1212class MidiDeviceManager : public ChangeListener
1313 , public AsyncUpdater
1414 , public MidiInputCallback
15- , public Timer
1615{
1716
1817public:
@@ -31,7 +30,7 @@ class MidiDeviceManager : public ChangeListener
3130
3231 updateMidiDevices ();
3332 midiBufferIn.ensureSize (2048 );
34- startTimer ( 2 );
33+ midiBufferOut. ensureSize ( 2048 );
3534 }
3635
3736 ~MidiDeviceManager ()
@@ -252,29 +251,59 @@ class MidiDeviceManager : public ChangeListener
252251 auto & outputPort = outputPorts[port + 1 ];
253252 if (outputPort.enabled )
254253 {
255- outputPort.queue .addEvent ( message, samplePosition);
254+ outputPort.queue .enqueue ({ message, samplePosition} );
256255 }
257256 }
258257
259258 // Read output buffer for a port. Used to pass back into the DAW or into the internal GM synth
260259 void dequeueMidiOutput (int port, MidiBuffer& buffer, int numSamples)
261260 {
262- if (outputPorts[port + 1 ].enabled ) {
263- buffer.addEvents (outputPorts[port].queue , 0 , numSamples, 0 );
261+ auto & outputPort = outputPorts[port + 1 ];
262+ if (outputPort.enabled ) {
263+ std::pair<MidiMessage, int > message;
264+ while (outputPort.queue .try_dequeue (message))
265+ {
266+ auto & [midiMessage, samplePosition] = message;
267+ outputPort.buffer .addEvent (midiMessage, samplePosition);
268+ }
269+ buffer.addEvents (buffer, 0 , numSamples, 0 );
264270 }
265271 }
266272
267- void sendMidiOutput ()
273+ // Sends pending MIDI output messages, and return a block with all messages
274+ void sendAndCollectMidiOutput (MidiBuffer& allOutputBuffer)
268275 {
269- for (auto & port : outputPorts) {
270- if (!port.enabled || port.queue .isEmpty ()) continue ;
271- for (auto * device : port.devices ) {
272- device->sendBlockOfMessages (port.queue , Time::getMillisecondCounterHiRes (), currentSampleRate);
276+ for (auto & outputPort : outputPorts) {
277+ if (outputPort.enabled )
278+ {
279+ std::pair<MidiMessage, int > message;
280+ while (outputPort.queue .try_dequeue (message))
281+ {
282+ auto & [midiMessage, samplePosition] = message;
283+ outputPort.buffer .addEvent (midiMessage, samplePosition);
284+ allOutputBuffer.addEvent (midiMessage, samplePosition);
285+ }
286+
287+ if (!outputPort.buffer .isEmpty ()) {
288+ for (auto * device : outputPort.devices ) {
289+ device->sendBlockOfMessages (outputPort.buffer , Time::getMillisecondCounterHiRes (), currentSampleRate);
290+ }
291+ outputPort.buffer .clear ();
292+ }
273293 }
274- port.queue .clear ();
275294 }
276295 }
277-
296+
297+ void clearMidiOutputBuffers ()
298+ {
299+ for (auto & outputPort : outputPorts) {
300+ if (outputPort.enabled && !outputPort.buffer .isEmpty ())
301+ {
302+ outputPort.buffer .clear ();
303+ }
304+ }
305+ }
306+
278307 // Load last MIDI settings from our settings file
279308 void loadMidiSettings ()
280309 {
@@ -343,17 +372,12 @@ class MidiDeviceManager : public ChangeListener
343372 {
344373 for (auto & port : outputPorts) {
345374 if (!port.enabled ) continue ;
346- buffer.addEvents (port.queue , 0 , numSamples, 0 );
375+ buffer.addEvents (port.buffer , 0 , numSamples, 0 );
347376 }
348377 }
349378
350379private:
351380
352- void timerCallback () override
353- {
354- sendMidiOutput ();
355- }
356-
357381 void handleIncomingMidiMessage (MidiInput* input, MidiMessage const & message) override
358382 {
359383 auto port = [this , input]() -> int {
@@ -396,10 +420,12 @@ class MidiDeviceManager : public ChangeListener
396420 {
397421 std::atomic<bool > enabled = false ;
398422 OwnedArray<MidiOutput> devices;
399- MidiBuffer queue;
423+ moodycamel::ConcurrentQueue<std::pair<MidiMessage, int >> queue;
424+ MidiBuffer buffer;
400425 };
401426
402427 MidiBuffer midiBufferIn;
428+ MidiBuffer midiBufferOut;
403429
404430 MidiInput* toPlugdata = nullptr ;
405431 MidiOutput* fromPlugdata = nullptr ;
0 commit comments