@@ -151,13 +151,8 @@ void MidiServer::initialize()
151151 return ;
152152 }
153153
154- auto midiInputs = juce::MidiInput::getAvailableDevices ();
155- for (const auto & device : midiInputs)
156- {
157- deviceManager.setMidiInputDeviceEnabled (device.identifier , true );
158- deviceManager.addMidiInputDeviceCallback (device.identifier , this );
159- DBG (" [MidiServer] Enabled MIDI input: " + device.name );
160- }
154+ // MIDI inputs are now opened on-demand based on client subscriptions
155+ // See updateMidiDeviceSubscriptions()
161156
162157 startTimer (10 );
163158 initialized = true ;
@@ -179,14 +174,16 @@ void MidiServer::shutdown()
179174 for (juce::HashMap<juce::String, juce::MidiOutput*>::Iterator it (outputDevices); it.next ();)
180175 delete it.getValue ();
181176 outputDevices.clear ();
182- clients.clear ();
183- }
184177
185- auto midiInputs = juce::MidiInput::getAvailableDevices ();
186- for (const auto & device : midiInputs)
187- {
188- deviceManager.setMidiInputDeviceEnabled (device.identifier , false );
189- deviceManager.removeMidiInputDeviceCallback (device.identifier , this );
178+ // Disable all enabled MIDI inputs
179+ for (const auto & [name, identifier] : enabledInputDevices)
180+ {
181+ deviceManager.setMidiInputDeviceEnabled (identifier, false );
182+ deviceManager.removeMidiInputDeviceCallback (identifier, this );
183+ }
184+ enabledInputDevices.clear ();
185+
186+ clients.clear ();
190187 }
191188
192189 deviceManager.closeAudioDevice ();
@@ -391,23 +388,58 @@ void MidiServer::rebuildClientSnapshot()
391388
392389void MidiServer::updateMidiDeviceSubscriptions ()
393390{
394- juce::StringArray neededOutputs;
395- for (auto & [clientPtr, info] : clients)
391+ // Collect all needed devices from client subscriptions
392+ juce::StringArray neededInputs, neededOutputs;
393+ for (const auto & [clientPtr, info] : clients)
394+ {
395+ for (const auto & device : info.state .subscribedInputDevices )
396+ neededInputs.addIfNotAlreadyThere (device);
396397 for (const auto & device : info.state .subscribedOutputDevices )
397398 neededOutputs.addIfNotAlreadyThere (device);
399+ }
400+
401+ // Build name->identifier map for available inputs
402+ std::unordered_map<juce::String, juce::String> availableInputMap;
403+ for (const auto & device : juce::MidiInput::getAvailableDevices ())
404+ availableInputMap[device.name ] = device.identifier ;
405+
406+ // Enable newly needed input devices
407+ for (const auto & name : neededInputs)
408+ {
409+ if (enabledInputDevices.count (name) == 0 )
410+ {
411+ auto it = availableInputMap.find (name);
412+ if (it != availableInputMap.end ())
413+ {
414+ deviceManager.setMidiInputDeviceEnabled (it->second , true );
415+ deviceManager.addMidiInputDeviceCallback (it->second , this );
416+ enabledInputDevices[name] = it->second ;
417+ DBG (" [MidiServer] Enabled MIDI input: " + name);
418+ }
419+ }
420+ }
421+
422+ // Disable input devices no longer needed
423+ for (auto it = enabledInputDevices.begin (); it != enabledInputDevices.end ();)
424+ if (!neededInputs.contains (it->first ))
425+ {
426+ deviceManager.setMidiInputDeviceEnabled (it->second , false );
427+ deviceManager.removeMidiInputDeviceCallback (it->second , this );
428+ DBG (" [MidiServer] Disabled MIDI input: " + it->first );
429+ it = enabledInputDevices.erase (it);
430+ }
431+ else
432+ ++it;
398433
399- juce::Array<juce::String> devicesToRemove;
434+ // Close output devices no longer needed (they're opened lazily in timerCallback)
400435 for (juce::HashMap<juce::String, juce::MidiOutput*>::Iterator it (outputDevices); it.next ();)
401436 {
402437 if (!neededOutputs.contains (it.getKey ()))
403438 {
404439 delete it.getValue ();
405- devicesToRemove. add (it.getKey ());
440+ outputDevices. remove (it.getKey ());
406441 }
407442 }
408-
409- for (const auto & device : devicesToRemove)
410- outputDevices.remove (device);
411443}
412444
413445} // namespace atk
0 commit comments