1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: jackmidi.cpp,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $
5 //  (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
6 //  (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; version 2 of
11 //  the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 //=========================================================
23 
24 #include <QByteArray>
25 
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include <jack/jack.h>
30 
31 #include "jackmidi.h"
32 #include "jackaudio.h"
33 #include "song.h"
34 #include "globals.h"
35 #include "midi_consts.h"
36 #include "mididev.h"
37 #include "../midiport.h"
38 #include "../midiseq.h"
39 #include "../midictrl.h"
40 #include "../audio.h"
41 #include "minstrument.h"
42 #include "mpevent.h"
43 #include "sync.h"
44 #include "audiodev.h"
45 #include "../mplugins/midiitransform.h"
46 #include "../mplugins/mitplugin.h"
47 #include "gconfig.h"
48 #include "track.h"
49 #include "route.h"
50 #include "helper.h"
51 
52 // Forwards from header:
53 #include "xml.h"
54 
55 // Turn on debug messages.
56 //#define JACK_MIDI_DEBUG
57 
58 // For debugging output: Uncomment the fprintf section.
59 #define DEBUG_PRST_ROUTES(dev, format, args...) // fprintf(dev, format, ##args);
60 
61 namespace MusECore {
62 
63 //---------------------------------------------------------
64 //   MidiJackDevice
65 //   in_jack_port or out_jack_port can be null
66 //---------------------------------------------------------
67 
MidiJackDevice(const QString & n)68 MidiJackDevice::MidiJackDevice(const QString& n)
69    : MidiDevice(n)
70 {
71   _in_client_jackport  = NULL;
72   _out_client_jackport = NULL;
73 }
74 
~MidiJackDevice()75 MidiJackDevice::~MidiJackDevice()
76 {
77   #ifdef JACK_MIDI_DEBUG
78     printf("MidiJackDevice::~MidiJackDevice()\n");
79   #endif
80 
81   if(MusEGlobal::audioDevice)
82   {
83     if(_in_client_jackport)
84       MusEGlobal::audioDevice->unregisterPort(_in_client_jackport);
85     if(_out_client_jackport)
86       MusEGlobal::audioDevice->unregisterPort(_out_client_jackport);
87   }
88 
89     //close();
90 }
91 
92 //---------------------------------------------------------
93 //   createJackMidiDevice
94 //   If name parameter is blank, creates a new (locally) unique one.
95 //---------------------------------------------------------
96 
createJackMidiDevice(QString name,int rwflags)97 MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable 3: Writable + Readable
98 {
99   int ni = 0;
100   if(name.isEmpty())
101   {
102     for( ; ni < 65536; ++ni)
103     {
104       name = QString("jack-midi-") + QString::number(ni);
105       if(!MusEGlobal::midiDevices.find(name, JACK_MIDI))
106         break;
107     }
108   }
109   if(ni >= 65536)
110   {
111     fprintf(stderr, "MusE: createJackMidiDevice failed! Can't find an unused midi device name 'jack-midi-[0-65535]'.\n");
112     return 0;
113   }
114 
115   MidiJackDevice* dev = new MidiJackDevice(name);
116   dev->setrwFlags(rwflags);
117   MusEGlobal::midiDevices.add(dev);
118   return dev;
119 }
120 
121 //---------------------------------------------------------
122 //   setName
123 //---------------------------------------------------------
124 
setName(const QString & s)125 void MidiJackDevice::setName(const QString& s)
126 {
127   #ifdef JACK_MIDI_DEBUG
128   printf("MidiJackDevice::setName %s new name:%s\n", name().toLatin1().constData(), s.toLatin1().constData());
129   #endif
130   _name = s;
131 
132   if(inClientPort())
133     MusEGlobal::audioDevice->setPortName(inClientPort(), (s + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData());
134   if(outClientPort())
135     MusEGlobal::audioDevice->setPortName(outClientPort(), (s + QString(JACK_MIDI_OUT_PORT_SUFFIX)).toLatin1().constData());
136 }
137 
138 //---------------------------------------------------------
139 //   open
140 //---------------------------------------------------------
141 
open()142 QString MidiJackDevice::open()
143 {
144   _openFlags &= _rwFlags; // restrict to available bits
145 
146   #ifdef JACK_MIDI_DEBUG
147   printf("MidiJackDevice::open %s\n", name().toLatin1().constData());
148   #endif
149 
150   // Start by disabling for now.
151   _writeEnable = _readEnable = false;
152   if(!MusEGlobal::checkAudioDevice())
153   {
154     fprintf(stderr, "MusE: MidiJackDevice::open failed: No audio device\n");
155     _state = QString("Not ready");
156     return _state;
157   }
158 
159   QString s;
160   bool out_fail = false, in_fail = false;
161   if(_openFlags & 1)
162   {
163     if(!_out_client_jackport)
164     {
165       if(MusEGlobal::audioDevice->deviceType() == AudioDevice::JACK_AUDIO)
166       {
167         s = name() + QString(JACK_MIDI_OUT_PORT_SUFFIX);
168         QByteArray ba = s.toLatin1();
169         const char* cs = ba.constData();
170         DEBUG_PRST_ROUTES(stderr, "MusE: MidiJackDevice::open creating output port name %s\n", cs);
171         _out_client_jackport = (jack_port_t*)MusEGlobal::audioDevice->registerOutPort(cs, true);
172         if(!_out_client_jackport)
173         {
174           fprintf(stderr, "MusE: MidiJackDevice::open failed creating output port name %s\n", cs);
175           _writeEnable = false;
176           out_fail = true;
177         }
178         else
179         {
180           _writeEnable = true;
181           const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(_out_client_jackport);
182           if(our_port_name)
183           {
184             // (We just registered the port. At this point, any existing persistent routes' jackPort SHOULD be 0.)
185             for(iRoute ir = _outRoutes.begin(); ir != _outRoutes.end(); ++ir)
186             {
187               if(ir->type != Route::JACK_ROUTE)
188                 continue;
189               const char* route_name = ir->persistentJackPortName;
190               if(!ir->jackPort)
191                 ir->jackPort = MusEGlobal::audioDevice->findPort(route_name);
192               //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
193               if(ir->jackPort)
194                 MusEGlobal::audioDevice->connect(our_port_name, route_name);
195             }
196           }
197         }
198       }
199     }
200   }
201   else
202   {
203     _writeEnable = false;
204     if(_out_client_jackport)
205     {
206       DEBUG_PRST_ROUTES(stderr, "MusE: MidiJackDevice::open unregistering output port\n");
207       // We want to unregister the port (which will also disconnect it), AND remove Routes, and then NULL-ify _out_client_jackport.
208       // We could let our graph change callback (the gui thread one) remove the Routes (which it would anyway).
209       // But that happens later (gui thread) and it needs a valid  _out_client_jackport,
210       //  so use of a registration callback would be required to finally NULL-ify _out_client_jackport,
211       //  and that would require some MidiDevice setter or re-scanner function.
212       // So instead, manually remove the Routes (in the audio thread), then unregister the port, then immediately NULL-ify _out_client_jackport.
213       // Our graph change callback (the gui thread one) will see a NULL  _out_client_jackport
214       //  so it cannot possibly remove the Routes, but that won't matter - we are removing them manually.
215       // This is the same technique that is used for audio elsewhere in the code, like Audio::msgSetChannels()
216       //  (but not Song::connectJackRoutes() which keeps the Routes for when undoing deletion of a track).
217       //
218       // NOTE: TESTED: Possibly a bug in QJackCtl, with Jack-1 (not Jack-2 !):
219       // After toggling the input/output green lights in the midi ports list (which gets us here), intermittently
220       //  qjackctl refuses to draw connections. It allows them to be made (MusE responds) but blanks them out immediately
221       //  and does not show 'disconnect', as if it is not properly aware of the connections.
222       // But ALL else is OK - the connection is fine in MusE, verbose Jack messages show all went OK.
223       // Yes, there's no doubt the connections are being made.
224       // When I toggle the lights again (which kills, then recreates the ports here), the problem can disappear or come back again.
225       // Also once observed a weird double connection from the port to two different Jack ports but one of
226       //  the connections should not have been there and kept toggling along with the other (like a 'ghost' connection).
227       for(iRoute ir = _outRoutes.begin(); ir != _outRoutes.end(); ++ir)
228       {
229         if(ir->type != Route::JACK_ROUTE)
230           continue;
231         if(ir->jackPort)
232         {
233           // Before we nullify the jackPort, grab the latest valid name of the port.
234           MusEGlobal::audioDevice->portName(ir->jackPort, ir->persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
235           ir->jackPort = 0;
236         }
237       }
238 
239       MusEGlobal::audioDevice->unregisterPort(_out_client_jackport);
240       _out_client_jackport = NULL;
241     }
242   }
243 
244   if(_openFlags & 2)
245   {
246     if(!_in_client_jackport)
247     {
248       if(MusEGlobal::audioDevice->deviceType() == AudioDevice::JACK_AUDIO)
249       {
250         s = name() + QString(JACK_MIDI_IN_PORT_SUFFIX);
251         QByteArray ba = s.toLatin1();
252         const char* cs = ba.constData();
253         DEBUG_PRST_ROUTES(stderr, "MusE: MidiJackDevice::open creating input port name %s\n", cs);
254         _in_client_jackport = (jack_port_t*)MusEGlobal::audioDevice->registerInPort(cs, true);
255         if(!_in_client_jackport)
256         {
257           fprintf(stderr, "MusE: MidiJackDevice::open failed creating input port name %s\n", cs);
258           _readEnable = false;
259           in_fail = true;
260         }
261         else
262         {
263           _readEnable = true;
264           const char* our_port_name = MusEGlobal::audioDevice->canonicalPortName(_in_client_jackport);
265           if(our_port_name)
266           {
267             // (We just registered the port. At this point, any existing persistent routes' jackPort SHOULD be 0.)
268             for(iRoute ir = _inRoutes.begin(); ir != _inRoutes.end(); ++ir)
269             {
270               if(ir->type != Route::JACK_ROUTE)
271                 continue;
272               const char* route_name = ir->persistentJackPortName;
273               if(!ir->jackPort)
274                 ir->jackPort = MusEGlobal::audioDevice->findPort(route_name);
275               //if(!MusEGlobal::audioDevice->portConnectedTo(our_port, route_name))
276               if(ir->jackPort)
277                 MusEGlobal::audioDevice->connect(route_name, our_port_name);
278             }
279           }
280         }
281       }
282     }
283   }
284   else
285   {
286     _readEnable = false;
287     if(_in_client_jackport)
288     {
289       DEBUG_PRST_ROUTES(stderr, "MusE: MidiJackDevice::open unregistering input port\n");
290       for(iRoute ir = _inRoutes.begin(); ir != _inRoutes.end(); ++ir)
291       {
292         if(ir->type != Route::JACK_ROUTE)
293           continue;
294         if(ir->jackPort)
295         {
296           // Before we nullify the jackPort, grab the latest valid name of the port.
297           MusEGlobal::audioDevice->portName(ir->jackPort, ir->persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
298           ir->jackPort = 0;
299         }
300       }
301 
302       MusEGlobal::audioDevice->unregisterPort(_in_client_jackport);
303       _in_client_jackport = NULL;
304     }
305   }
306 
307   if(out_fail && in_fail)
308     _state = QString("R+W Open fail");
309   else if(out_fail)
310     _state = QString("Write open fail");
311   else if(in_fail)
312     _state = QString("Read open fail");
313   else
314     _state = QString("OK");
315 
316   return _state;
317 }
318 
319 //---------------------------------------------------------
320 //   close
321 //---------------------------------------------------------
322 
close()323 void MidiJackDevice::close()
324 {
325   #ifdef JACK_MIDI_DEBUG
326   printf("MidiJackDevice::close %s\n", name().toLatin1().constData());
327   #endif
328 
329   DEBUG_PRST_ROUTES(stderr, "MidiJackDevice::close %s\n", name().toLatin1().constData());
330   // Disable immediately.
331   _writeEnable = _readEnable = false;
332   jack_port_t* i_jp = _in_client_jackport;
333   jack_port_t* o_jp = _out_client_jackport;
334   _in_client_jackport = 0;
335   _out_client_jackport = 0;
336 
337   DEBUG_PRST_ROUTES(stderr, "MidiJackDevice::close nullifying route jackPorts...\n");
338 
339   for(iRoute ir = _outRoutes.begin(); ir != _outRoutes.end(); ++ir)
340   {
341     if(ir->type != Route::JACK_ROUTE)
342       continue;
343     if(ir->jackPort)
344     {
345       // Before we nullify the jackPort, grab the latest valid name of the port.
346       if(MusEGlobal::checkAudioDevice())
347         MusEGlobal::audioDevice->portName(ir->jackPort, ir->persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
348       ir->jackPort = 0;
349     }
350   }
351   for(iRoute ir = _inRoutes.begin(); ir != _inRoutes.end(); ++ir)
352   {
353     if(ir->type != Route::JACK_ROUTE)
354       continue;
355     if(ir->jackPort)
356     {
357       // Before we nullify the jackPort, grab the latest valid name of the port.
358       if(MusEGlobal::checkAudioDevice())
359         MusEGlobal::audioDevice->portName(ir->jackPort, ir->persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
360       ir->jackPort = 0;
361     }
362   }
363 
364 //   if(_in_client_jackport)
365 //   {
366 //     if(MusEGlobal::checkAudioDevice())
367 //       MusEGlobal::audioDevice->unregisterPort(_in_client_jackport);
368 //     _in_client_jackport = 0;
369 //   }
370 //   if(_out_client_jackport)
371 //   {
372 //     if(MusEGlobal::checkAudioDevice())
373 //       MusEGlobal::audioDevice->unregisterPort(_out_client_jackport);
374 //     _out_client_jackport = 0;
375 //   }
376 
377   DEBUG_PRST_ROUTES(stderr, "MidiJackDevice::close unregistering our ports...\n");
378 
379   if(i_jp)
380   {
381     if(MusEGlobal::checkAudioDevice())
382       MusEGlobal::audioDevice->unregisterPort(i_jp);
383   }
384   if(o_jp)
385   {
386     if(MusEGlobal::checkAudioDevice())
387       MusEGlobal::audioDevice->unregisterPort(o_jp);
388   }
389   _state = QString("Closed");
390 }
391 
392 //---------------------------------------------------------
393 //   writeRouting
394 //---------------------------------------------------------
395 
writeRouting(int level,Xml & xml) const396 void MidiJackDevice::writeRouting(int level, Xml& xml) const
397 {
398       // If this device is not actually in use by the song, do not write any routes.
399       // This prevents bogus routes from being saved and propagated in the med file.
400       // Removed. Need to let routes be saved.
401       //if(midiPort() == -1)
402       //  return;
403 
404       QString s;
405       if(rwFlags() & 2)  // Readable
406       {
407         for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
408         {
409           if((r->type == Route::TRACK_ROUTE && r->track) || (r->type != Route::TRACK_ROUTE && !r->name().isEmpty()))
410           {
411             xml.tag(level++, "Route");
412             s = "source";
413             if(r->type == Route::TRACK_ROUTE)
414               s += QString(" track=\"%1\"/").arg(MusEGlobal::song->tracks()->index(r->track));
415             else
416               s += QString(" type=\"%1\" name=\"%2\"/").arg(r->type).arg(Xml::xmlString(r->name()));
417             xml.tag(level, s.toLatin1().constData());
418             xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());
419             xml.etag(level--, "Route");
420           }
421         }
422       }
423 
424       for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
425       {
426         if((r->type == Route::TRACK_ROUTE && r->track) || (r->type != Route::TRACK_ROUTE && !r->name().isEmpty()))
427         {
428           s = "Route";
429           if(r->channel != -1)
430             s += QString(" channel=\"%1\"").arg(r->channel);
431           xml.tag(level++, s.toLatin1().constData());
432           xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());
433           s = "dest";
434           if(r->type == Route::MIDI_DEVICE_ROUTE)
435             s += QString(" devtype=\"%1\" name=\"%2\"/").arg(r->device->deviceType()).arg(Xml::xmlString(r->name()));
436           else if(r->type == Route::TRACK_ROUTE)
437             s += QString(" track=\"%1\"/").arg(MusEGlobal::song->tracks()->index(r->track));
438           else
439             s += QString(" type=\"%1\" name=\"%2\"/").arg(r->type).arg(Xml::xmlString(r->name()));
440           xml.tag(level, s.toLatin1().constData());
441           xml.etag(level--, "Route");
442         }
443       }
444 }
445 
446 //---------------------------------------------------------
447 //   pbForwardShiftFrames
448 //---------------------------------------------------------
449 
pbForwardShiftFrames() const450 unsigned int MidiJackDevice::pbForwardShiftFrames() const
451 {
452   return MusEGlobal::segmentSize;
453 }
454 
455 //---------------------------------------------------------
456 //   recordEvent
457 //---------------------------------------------------------
458 
recordEvent(MidiRecordEvent & event)459 void MidiJackDevice::recordEvent(MidiRecordEvent& event)
460       {
461       // Set the loop number which the event came in at.
462       //if(MusEGlobal::audio->isRecording())
463       if(MusEGlobal::audio->isPlaying())
464         event.setLoopNum(MusEGlobal::audio->loopCount());
465 
466       if (MusEGlobal::midiInputTrace) {
467             fprintf(stderr, "MidiIn Jack: <%s>: ", name().toLatin1().constData());
468             dumpMPEvent(&event);
469             }
470 
471       int typ = event.type();
472 
473       if(_port != -1)
474       {
475         int idin = MusEGlobal::midiPorts[_port].syncInfo().idIn();
476 
477         //---------------------------------------------------
478         // filter some SYSEX events
479         //---------------------------------------------------
480 
481         if (typ == ME_SYSEX) {
482               const unsigned char* p = event.data();
483               int n = event.len();
484               if (n >= 4) {
485                     if ((p[0] == 0x7f)
486                       //&& ((p[1] == 0x7f) || (p[1] == rxDeviceId))) {
487                       && ((p[1] == 0x7f) || (idin == 0x7f) || (p[1] == idin))) {
488                           if (p[2] == 0x06) {
489                                 //mmcInput(p, n);
490                                 MusEGlobal::midiSyncContainer.mmcInput(_port, p, n);
491                                 return;
492                                 }
493                           if (p[2] == 0x01) {
494                                 //mtcInputFull(p, n);
495                                 MusEGlobal::midiSyncContainer.mtcInputFull(_port, p, n);
496                                 return;
497                                 }
498                           }
499                     else if (p[0] == 0x7e) {
500                           //nonRealtimeSystemSysex(p, n);
501                           MusEGlobal::midiSyncContainer.nonRealtimeSystemSysex(_port, p, n);
502                           return;
503                           }
504                     }
505               }
506           else
507             // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
508             MusEGlobal::midiPorts[_port].syncInfo().trigActDetect(event.channel());
509       }
510 
511       //
512       //  process midi event input filtering and
513       //    transformation
514       //
515 
516       processMidiInputTransformPlugins(event);
517 
518       if (filterEvent(event, MusEGlobal::midiRecordType, false))
519             return;
520 
521       if (!applyMidiInputTransformation(event)) {
522             if (MusEGlobal::midiInputTrace)
523                   printf("   midi input transformation: event filtered\n");
524             return;
525             }
526 
527       //
528       // transfer noteOn and Off events to gui for step recording and keyboard
529       // remote control (changed by flo93: added noteOff-events)
530       //
531       if (typ == ME_NOTEON) {
532             int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
533             MusEGlobal::song->putEvent(pv);
534             }
535       else if (typ == ME_NOTEOFF) {
536             int pv = ((event.dataA() & 0xff)<<8) + (0x00); //send an event with velo=0
537             MusEGlobal::song->putEvent(pv);
538             }
539       else if (MusEGlobal::rcEnableCC && typ == ME_CONTROLLER) {
540           char cc = static_cast<char>(event.dataA() & 0xff);
541           printf("*** Input CC: %d\n", cc);
542           MusEGlobal::song->putEventCC(cc);
543       }
544 
545       //if(_recordFifo.put(MidiPlayEvent(event)))
546       //  printf("MidiJackDevice::recordEvent: fifo overflow\n");
547 
548       // Do not bother recording if it is NOT actually being used by a port.
549       // Because from this point on, process handles things, by selected port.    p3.3.38
550       if(_port == -1)
551         return;
552 
553       // Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
554       unsigned int ch = (typ == ME_SYSEX)? MusECore::MUSE_MIDI_CHANNELS : event.channel();
555       if(_recordFifo[ch].put(event))
556         printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch);
557       }
558 
559 //---------------------------------------------------------
560 //   eventReceived
561 //---------------------------------------------------------
562 
eventReceived(jack_midi_event_t * ev)563 void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
564       {
565       if(ev->size == 0)
566         return;
567 
568       MidiRecordEvent event;
569       event.setB(0);
570       event.setPort(_port);
571       jack_nframes_t abs_ft = 0;
572 
573       // NOTE: From muse_qt4_evolution. Not done here in Muse-2 (yet).
574       // move all events 2*MusEGlobal::segmentSize into the future to get
575       // jitterfree playback
576       //
577       //  cycle   n-1         n          n+1
578       //          -+----------+----------+----------+-
579       //               ^          ^          ^
580       //               catch      process    play
581       //
582 
583       // These Jack events arrived in the previous period, and it may not have been at the audio position before this one (after a seek).
584       // This is how our ALSA driver works, events there are timestamped asynchronous of any process, referenced to the CURRENT audio
585       //  position, so that by the time of the NEXT process, THOSE events have also occurred in the previous period.
586       // So, technically this is correct. What MATTERS is how we adjust the times for storage, and/or simultaneous playback in THIS period,
587       //  and TEST: we'll need to make sure any non-contiguous previous period is handled correctly by process - will it work OK as is?
588       // If ALSA works OK than this should too...
589       // The events arrived in the previous cycle, not this one. Adjust.
590       abs_ft = MusEGlobal::audio->curSyncFrame() + ev->time;
591       if(abs_ft >= MusEGlobal::segmentSize)
592         abs_ft -= MusEGlobal::segmentSize;
593       event.setTime(abs_ft);
594       event.setTick(MusEGlobal::lastExtMidiSyncTick);
595 
596       event.setChannel(*(ev->buffer) & 0xf);
597       const int type = *(ev->buffer) & 0xf0;
598       event.setType(type);
599 
600       switch(type) {
601             case ME_NOTEON:
602             {
603                  if(ev->size < 3)
604                    return;
605                  // Convert zero-velocity note ons to note offs as per midi spec.
606                  if(*(ev->buffer + 2) == 0)
607                    event.setType(ME_NOTEOFF);
608             }
609             // Fall through.
610 
611             case ME_NOTEOFF:
612             case ME_CONTROLLER:
613             case ME_POLYAFTER:
614                   if(ev->size < 3)
615                     return;
616                   event.setA(*(ev->buffer + 1) & 0x7f);
617                   event.setB(*(ev->buffer + 2) & 0x7f);
618                   break;
619             case ME_PROGRAM:
620             case ME_AFTERTOUCH:
621                   if(ev->size < 2)
622                     return;
623                   event.setA(*(ev->buffer + 1) & 0x7f);
624                   break;
625 
626             case ME_PITCHBEND:
627                   if(ev->size < 3)
628                     return;
629                   event.setA(( ((*(ev->buffer + 2) & 0x7f) << 7) +
630                                 (*(ev->buffer + 1) & 0x7f) )
631                               - 8192);
632                   break;
633 
634             case ME_SYSEX:
635                   {
636                     const int type = *(ev->buffer) & 0xff;
637                     switch(type)
638                     {
639                           case ME_SYSEX:
640                               #ifdef JACK_MIDI_DEBUG
641                                 // ---Diagnostics---:
642                                 fprintf(stderr, "MidiJackDevice::eventReceived SYSEX len:%u data: ", (unsigned int)ev->size);
643                                 for(unsigned int i = 0; i < ev->size && i < 16; ++i)
644                                   fprintf(stderr, "%0x ", ((unsigned char*)ev->buffer)[i]);
645                                 if(ev->size >= 16)
646                                   fprintf(stderr, "...");
647                                 fprintf(stderr, "\n");
648                               #endif
649 
650                                 // TODO: Deal with large sysex, which are broken up into chunks!
651                                 // For now, do not accept if the last byte is not EOX, meaning it's a chunk with more chunks to follow.
652                                 if(*(((unsigned char*)ev->buffer) + ev->size - 1) != ME_SYSEX_END)
653                                 {
654                                   fprintf(stderr, "MidiJackDevice::eventReceived sysex chunks not supported!\n");
655                                   return;
656                                 }
657 
658                                 //event.setTime(0);      // mark as used
659                                 event.setType(ME_SYSEX);
660                                 event.setData((unsigned char*)(ev->buffer + 1), ev->size - 2);
661                                 break;
662                           case ME_MTC_QUARTER:
663                                 if(_port != -1)
664                                 {
665                                   MusEGlobal::midiSyncContainer.mtcInputQuarter(_port, *(ev->buffer + 1));
666                                 }
667                                 return;
668                           case ME_SONGPOS:
669                                 if(_port != -1)
670                                 {
671                                   MusEGlobal::midiSyncContainer.setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) << 7 )); // LSB then MSB
672                                 }
673                                 return;
674                           //case ME_SONGSEL:
675                           //case ME_TUNE_REQ:
676 
677                           // We don't use sensing. But suppress warning about this one since it is repetitive.
678                           case ME_SENSE:
679                                 return;
680 
681                           case ME_CLOCK:
682                           {
683                                 midiClockInput(abs_ft);
684                                 return;
685                           }
686                           case ME_START:
687                           {
688                             #ifdef JACK_MIDI_DEBUG
689                               fprintf(stderr, "MidiJackDevice::eventReceived: START port:%d time:%u\n", _port, abs_ft);
690                             #endif
691                           }
692                             // FALLTHROUGH
693 
694                           case ME_TICK:
695                           case ME_CONTINUE:
696                           case ME_STOP:
697                           {
698                                 MusEGlobal::midiSyncContainer.realtimeSystemInput(_port, type);
699                                 return;
700                           }
701                           //case ME_SYSEX_END:
702                                 //break;
703                           //      return;
704                           default:
705                                 if(MusEGlobal::debugMsg)
706                                   printf("MidiJackDevice::eventReceived unsupported system event 0x%02x\n", type);
707                                 return;
708                     }
709                   }
710                   break;
711             default:
712               if(MusEGlobal::debugMsg)
713                 printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type);
714               return;
715             }
716 
717       #ifdef JACK_MIDI_DEBUG
718       printf("MidiJackDevice::eventReceived time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
719       #endif
720 
721       // Let recordEvent handle it from here, with timestamps, filtering, gui triggering etc.
722       recordEvent(event);
723       }
724 
725 //---------------------------------------------------------
726 //   collectMidiEvents
727 //---------------------------------------------------------
728 
collectMidiEvents()729 void MidiJackDevice::collectMidiEvents()
730 {
731   if(!_readEnable)
732     return;
733 
734   if(!_in_client_jackport)
735     return;
736 
737   void* port_buf = jack_port_get_buffer(_in_client_jackport, MusEGlobal::segmentSize);
738   jack_midi_event_t event;
739   jack_nframes_t eventCount = jack_midi_get_event_count(port_buf);
740   for (jack_nframes_t i = 0; i < eventCount; ++i)
741   {
742     jack_midi_event_get(&event, port_buf, i);
743 
744     #ifdef JACK_MIDI_DEBUG
745     printf("MidiJackDevice::collectMidiEvents number:%d time:%d\n", i, event.time);
746     #endif
747 
748     eventReceived(&event);
749   }
750 }
751 
752 //---------------------------------------------------------
753 //   queueEvent
754 //   return true if successful
755 //---------------------------------------------------------
756 
queueEvent(const MidiPlayEvent & e,void * evBuffer)757 bool MidiJackDevice::queueEvent(const MidiPlayEvent& e, void* evBuffer)
758 {
759       // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
760       // No big deal if not. Not used for now.
761       //int port = e.port();
762 
763       if(!_writeEnable || !evBuffer)
764         return false;
765 
766       const unsigned int syncFrame = MusEGlobal::audio->curSyncFrame();
767       if(e.time() != 0 && e.time() < syncFrame)
768         fprintf(stderr, "MidiJackDevice::queueEvent() evTime:%u < syncFrame:%u!!\n", e.time(), syncFrame);
769       unsigned int ft = (e.time() < syncFrame) ? 0 : e.time() - syncFrame;
770       if (ft >= MusEGlobal::segmentSize) {
771             fprintf(stderr, "MidiJackDevice::queueEvent: Event time:%d out of range. syncFrame:%d ft:%d (seg=%d)\n",
772                     e.time(), syncFrame, ft, MusEGlobal::segmentSize);
773             ft = MusEGlobal::segmentSize - 1;
774             }
775 
776       #ifdef JACK_MIDI_DEBUG
777       fprintf(stderr, "MidiJackDevice::queueEvent pos:%d syncFrame:%d ft:%d time:%d type:%d ch:%d A:%d B:%d\n",
778               pos, syncFrame, ft, e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
779       #endif
780 
781       if (MusEGlobal::midiOutputTrace) {
782             fprintf(stderr, "MidiOut: Jack: <%s>: ", name().toLatin1().constData());
783             dumpMPEvent(&e);
784             }
785 
786       switch(e.type()) {
787 
788 
789             case ME_CONTROLLER:
790             case ME_NOTEON:
791             case ME_NOTEOFF:
792             case ME_POLYAFTER:
793             case ME_PITCHBEND:
794                   {
795                   #ifdef JACK_MIDI_DEBUG
796                   printf("MidiJackDevice::queueEvent note on/off polyafter controller or pitch\n");
797                   #endif
798 
799                   unsigned char* p = jack_midi_event_reserve(evBuffer, ft, 3);
800                   if (p == 0) {
801                         #ifdef JACK_MIDI_DEBUG
802                         fprintf(stderr, "MidiJackDevice::queueEvent NOTE CTL PAT or PB: buffer overflow, stopping until next cycle\n");
803                         #endif
804                         return false;
805                         }
806                   p[0] = e.type() | e.channel();
807                   p[1] = e.dataA();
808                   p[2] = e.dataB();
809                   }
810                   break;
811 
812             case ME_PROGRAM:
813             case ME_AFTERTOUCH:
814                   {
815                   #ifdef JACK_MIDI_DEBUG
816                   printf("MidiJackDevice::queueEvent program or aftertouch\n");
817                   #endif
818 
819                   unsigned char* p = jack_midi_event_reserve(evBuffer, ft, 2);
820                   if (p == 0) {
821                         #ifdef JACK_MIDI_DEBUG
822                         fprintf(stderr, "MidiJackDevice::queueEvent PROG or AT: buffer overflow, stopping until next cycle\n");
823                         #endif
824                         return false;
825                         }
826                   p[0] = e.type() | e.channel();
827                   p[1] = e.dataA();
828                   }
829                   break;
830             case ME_SYSEX:
831                   {
832                   #ifdef JACK_MIDI_DEBUG
833                   printf("MidiJackDevice::queueEvent sysex\n");
834                   #endif
835 
836                   const unsigned char* data = e.constData();
837                   int len = e.len();
838                   unsigned char* p = jack_midi_event_reserve(evBuffer, ft, len+2);
839                   if (p == 0) {
840                         fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n");
841 
842                         //return false;
843                         // Changed to true. Absorb the sysex if it is too big, to avoid attempting
844                         //  to resend repeatedly. If the sysex is too big, it would just stay in the
845                         //  list and never be processed, because Jack could never reserve enough space.
846                         // Other types of events should be OK since they are small and can be resent
847                         //  next cycle.     p4.0.15 Tim.
848                         // FIXME: We really need to chunk sysex events properly. It's tough. Investigating...
849                         return true;
850                         }
851                   p[0] = 0xf0;
852                   memcpy(p+1, data, len);
853                   p[len+1] = 0xf7;
854                   }
855                   break;
856             case ME_SONGPOS:
857                   {
858                   #ifdef JACK_MIDI_DEBUG
859                   printf("MidiJackDevice::queueEvent songpos %d\n", e.dataA());
860                   #endif
861 
862                   unsigned char* p = jack_midi_event_reserve(evBuffer, ft, 3);
863                   if (p == 0) {
864                         #ifdef JACK_MIDI_DEBUG
865                         fprintf(stderr, "MidiJackDevice::queueEvent songpos: buffer overflow, stopping until next cycle\n");
866                         #endif
867                         return false;
868                         }
869                   int pos = e.dataA();
870                   p[0] = e.type();
871                   p[1] = pos & 0x7f;         // LSB
872                   p[2] = (pos >> 7) & 0x7f;  // MSB
873                   }
874                   break;
875             case ME_CLOCK:
876             case ME_START:
877             case ME_CONTINUE:
878             case ME_STOP:
879                   {
880                   #ifdef JACK_MIDI_DEBUG
881                   printf("MidiJackDevice::queueEvent realtime %x\n", e.type());
882                   #endif
883 
884                   unsigned char* p = jack_midi_event_reserve(evBuffer, ft, 1);
885                   if (p == 0) {
886                         #ifdef JACK_MIDI_DEBUG
887                         fprintf(stderr, "MidiJackDevice::queueEvent realtime: buffer overflow, stopping until next cycle\n");
888                         #endif
889                         return false;
890                         }
891                   p[0] = e.type();
892                   }
893                   break;
894             default:
895                   if(MusEGlobal::debugMsg)
896                     printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
897                   return true;   // Absorb the event. Don't want it hanging around in the list.
898             }
899 
900             return true;
901 }
902 
903 //---------------------------------------------------------
904 //    processEvent
905 //    return true if successful
906 //---------------------------------------------------------
907 
processEvent(const MidiPlayEvent & event,void * evBuffer)908 bool MidiJackDevice::processEvent(const MidiPlayEvent& event, void* evBuffer)
909 {
910   int chn    = event.channel();
911   unsigned t = event.time();
912   int a      = event.dataA();
913   int b      = event.dataB();
914   // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
915   // No big deal if not. Not used for now.
916   int port   = event.port();
917 
918   #ifdef JACK_MIDI_DEBUG
919   //printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", t, event.type(), chn, a, b);
920   #endif
921 
922   MidiInstrument::NoteOffMode nom = MidiInstrument::NoteOffAll; // Default to NoteOffAll in case of no port.
923   const int mport = midiPort();
924   if(mport != -1)
925   {
926     if(MidiInstrument* mi = MusEGlobal::midiPorts[mport].instrument())
927       nom = mi->noteOffMode();
928   }
929 
930   // REMOVE Tim. Noteoff. Added.
931   if(event.type() == ME_NOTEON)
932   {
933     if(b == 0)
934     {
935       // Handle zero-velocity note ons. Technically this is an error because internal midi paths
936       //  are now all 'note-off' without zero-vel note ons - they're converted to note offs.
937       // Nothing should be setting a Note type Event's on velocity to zero.
938       // But just in case... If we get this warning, it means there is still code to change.
939       fprintf(stderr, "MidiJackDevice::processEvent: Warning: Zero-vel note on: time:%d type:%d (ME_NOTEON) ch:%d A:%d B:%d\n", t, event.type(), chn, a, b);
940       switch(nom)
941       {
942         // Instrument uses note offs. Convert to zero-vel note off.
943         case MidiInstrument::NoteOffAll:
944           return queueEvent(MidiPlayEvent(t, port, chn, ME_NOTEOFF, a, 0), evBuffer);
945         break;
946 
947         // Instrument uses no note offs at all. Send as-is.
948         case MidiInstrument::NoteOffNone:
949         // Instrument converts all note offs to zero-vel note ons. Send as-is.
950         case MidiInstrument::NoteOffConvertToZVNoteOn:
951           return queueEvent(event, evBuffer);
952         break;
953       }
954     }
955     return queueEvent(event, evBuffer);
956   }
957   else if(event.type() == ME_NOTEOFF)
958   {
959     switch(nom)
960     {
961       // Instrument uses note offs. Send as-is.
962       case MidiInstrument::NoteOffAll:
963         return queueEvent(event, evBuffer);
964       break;
965 
966       // Instrument uses no note offs at all. Send nothing. Eat up the event - return true.
967       case MidiInstrument::NoteOffNone:
968         return true;
969 
970       // Instrument converts all note offs to zero-vel note ons. Convert to zero-vel note on.
971       case MidiInstrument::NoteOffConvertToZVNoteOn:
972         return queueEvent(MidiPlayEvent(t, port, chn, ME_NOTEON, a, 0), evBuffer);
973       break;
974     }
975     return queueEvent(event, evBuffer);
976   }
977 
978   else if(event.type() == ME_PROGRAM)
979   {
980     //_curOutParamNums[chn].resetParamNums();  // Probably best to reset.
981     // don't output program changes for GM drum channel
982     //if (!(MusEGlobal::song->mtype() == MT_GM && chn == 9)) {
983           _curOutParamNums[chn].resetParamNums();  // Probably best to reset.
984           _curOutParamNums[chn].setPROG(a);
985           if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, a, 0), evBuffer))
986             return false;
987 
988     //      }
989   }
990   else if(event.type() == ME_PITCHBEND)
991   {
992       int v = a + 8192;
993       //printf("MidiJackDevice::processEvent ME_PITCHBEND v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
994       if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f), evBuffer))
995         return false;
996   }
997   else if(event.type() == ME_SYSEX)
998   {
999     resetCurOutParamNums();  // Probably best to reset all.
1000     if(!queueEvent(event, evBuffer))
1001       return false;
1002   }
1003   else if(event.type() == ME_CONTROLLER)
1004   {
1005     // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
1006     // No big deal if not. Not used for now.
1007     //int port   = event.port();
1008 
1009     if((a | 0xff) == CTRL_POLYAFTER)
1010     {
1011       //printf("MidiJackDevice::processEvent CTRL_POLYAFTER v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
1012       if(!queueEvent(MidiPlayEvent(t, port, chn, ME_POLYAFTER, a & 0x7f, b & 0x7f), evBuffer))
1013         return false;
1014     }
1015     else if(a == CTRL_AFTERTOUCH)
1016     {
1017       //printf("MidiJackDevice::processEvent CTRL_AFTERTOUCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
1018       if(!queueEvent(MidiPlayEvent(t, port, chn, ME_AFTERTOUCH, b & 0x7f, 0), evBuffer))
1019         return false;
1020     }
1021     else if(a == CTRL_PITCH)
1022     {
1023       int v = b + 8192;
1024       //printf("MidiJackDevice::processEvent CTRL_PITCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
1025       if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f), evBuffer))
1026         return false;
1027     }
1028     else if (a == CTRL_PROGRAM)
1029     {
1030       _curOutParamNums[chn].resetParamNums();  // Probably best to reset.
1031       // don't output program changes for GM drum channel
1032       //if (!(MusEGlobal::song->mtype() == MT_GM && chn == 9)) {
1033             int hb = (b >> 16) & 0xff;
1034             int lb = (b >> 8) & 0xff;
1035             int pr = b & 0xff;
1036             //printf("MidiJackDevice::processEvent CTRL_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n",
1037             //       event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
1038 
1039             _curOutParamNums[chn].setCurrentProg(pr, lb, hb);
1040             if (hb != 0xff)
1041             {
1042                   if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb), evBuffer))
1043                     return false;
1044             }
1045             if (lb != 0xff)
1046             {
1047                   if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb), evBuffer))
1048                     return false;
1049             }
1050             if (pr != 0xff)
1051             {
1052                   if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0), evBuffer))
1053                     return false;
1054             }
1055 
1056       //      }
1057     }
1058     else if (a == CTRL_MASTER_VOLUME)
1059     {
1060       unsigned char sysex[] = {
1061             0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00
1062             };
1063       //sysex[1] = deviceId(); TODO FIXME p4.0.15 Grab the ID from midi port sync info.
1064       sysex[4] = b & 0x7f;
1065       sysex[5] = (b >> 7) & 0x7f;
1066       if(!queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6), evBuffer))
1067         return false;
1068     }
1069     else if (a < CTRL_14_OFFSET)
1070     {              // 7 Bit Controller
1071       if(a == CTRL_HRPN)
1072         _curOutParamNums[chn].setRPNH(b);
1073       else if(a == CTRL_LRPN)
1074         _curOutParamNums[chn].setRPNL(b);
1075       else if(a == CTRL_HNRPN)
1076         _curOutParamNums[chn].setNRPNH(b);
1077       else if(a == CTRL_LNRPN)
1078         _curOutParamNums[chn].setNRPNL(b);
1079       else if(a == CTRL_HBANK)
1080       {
1081         _curOutParamNums[chn].setBANKH(b);
1082         _curOutParamNums[chn].resetParamNums();  // Probably best to reset.
1083       }
1084       else if(a == CTRL_LBANK)
1085       {
1086         _curOutParamNums[chn].setBANKL(b);
1087         _curOutParamNums[chn].resetParamNums();  // Probably best to reset.
1088       }
1089       else if(a == CTRL_RESET_ALL_CTRL)
1090         _curOutParamNums[chn].resetParamNums();  // Probably best to reset.
1091 
1092       //queueEvent(museport, MidiPlayEvent(t, port, chn, event));
1093       if(!queueEvent(event, evBuffer))
1094         return false;
1095     }
1096     else if (a < CTRL_RPN_OFFSET)
1097     {     // 14 bit high resolution controller
1098       int ctrlH = (a >> 8) & 0x7f;
1099       int ctrlL = a & 0x7f;
1100       int dataH = (b >> 7) & 0x7f;
1101       int dataL = b & 0x7f;
1102       if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, ctrlH, dataH), evBuffer))
1103         return false;
1104       if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlL, dataL), evBuffer))
1105         return false;
1106     }
1107     else if (a < CTRL_NRPN_OFFSET)
1108     {     // RPN 7-Bit Controller
1109       int ctrlH = (a >> 8) & 0x7f;
1110       int ctrlL = a & 0x7f;
1111       int data = b & 0x7f;
1112       if(ctrlH != _curOutParamNums[chn].RPNH || !MusEGlobal::config.midiOptimizeControllers)
1113       {
1114         _curOutParamNums[chn].setRPNH(ctrlH);
1115         if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH), evBuffer))
1116           return false;
1117       }
1118       if(ctrlL != _curOutParamNums[chn].RPNL || !MusEGlobal::config.midiOptimizeControllers)
1119       {
1120         _curOutParamNums[chn].setRPNL(ctrlL);
1121         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL), evBuffer))
1122           return false;
1123       }
1124       if(data != _curOutParamNums[chn].DATAH || !MusEGlobal::config.midiOptimizeControllers)
1125       {
1126         _curOutParamNums[chn].setDATAH(data);
1127         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, data), evBuffer))
1128           return false;
1129       }
1130 
1131       // Select null parameters so that subsequent data controller events do not upset the last *RPN controller.
1132       if(MusEGlobal::config.midiSendNullParameters)
1133       {
1134         _curOutParamNums[chn].setRPNH(0x7f);
1135         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, 0x7f), evBuffer))
1136           return false;
1137 
1138         _curOutParamNums[chn].setRPNL(0x7f);
1139         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, 0x7f), evBuffer))
1140           return false;
1141       }
1142     }
1143     else if (a < CTRL_INTERNAL_OFFSET)
1144     {     // NRPN 7-Bit Controller
1145       int ctrlH = (a >> 8) & 0x7f;
1146       int ctrlL = a & 0x7f;
1147       int data = b & 0x7f;
1148       if(ctrlH != _curOutParamNums[chn].NRPNH || !MusEGlobal::config.midiOptimizeControllers)
1149       {
1150         _curOutParamNums[chn].setNRPNH(ctrlH);
1151         if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH), evBuffer))
1152           return false;
1153       }
1154       if(ctrlL != _curOutParamNums[chn].NRPNL || !MusEGlobal::config.midiOptimizeControllers)
1155       {
1156         _curOutParamNums[chn].setNRPNL(ctrlL);
1157         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL), evBuffer))
1158           return false;
1159       }
1160       if(data != _curOutParamNums[chn].DATAH || !MusEGlobal::config.midiOptimizeControllers)
1161       {
1162         _curOutParamNums[chn].setDATAH(data);
1163         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, data), evBuffer))
1164           return false;
1165       }
1166 
1167       if(MusEGlobal::config.midiSendNullParameters)
1168       {
1169         _curOutParamNums[chn].setNRPNH(0x7f);
1170         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, 0x7f), evBuffer))
1171           return false;
1172 
1173         _curOutParamNums[chn].setNRPNL(0x7f);
1174         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, 0x7f), evBuffer))
1175           return false;
1176       }
1177     }
1178     else if (a < CTRL_RPN14_OFFSET)      // Unaccounted for internal controller
1179       return false;
1180     else if (a < CTRL_NRPN14_OFFSET)
1181     {     // RPN14 Controller
1182       int ctrlH = (a >> 8) & 0x7f;
1183       int ctrlL = a & 0x7f;
1184       int dataH = (b >> 7) & 0x7f;
1185       int dataL = b & 0x7f;
1186       if(ctrlH != _curOutParamNums[chn].RPNH || !MusEGlobal::config.midiOptimizeControllers)
1187       {
1188         _curOutParamNums[chn].setRPNH(ctrlH);
1189         if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH), evBuffer))
1190           return false;
1191       }
1192       if(ctrlL != _curOutParamNums[chn].RPNL || !MusEGlobal::config.midiOptimizeControllers)
1193       {
1194         _curOutParamNums[chn].setRPNL(ctrlL);
1195         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL), evBuffer))
1196           return false;
1197       }
1198       if(dataH != _curOutParamNums[chn].DATAH || !MusEGlobal::config.midiOptimizeControllers)
1199       {
1200         _curOutParamNums[chn].setDATAH(dataH);
1201         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH), evBuffer))
1202           return false;
1203       }
1204       if(dataL != _curOutParamNums[chn].DATAL || !MusEGlobal::config.midiOptimizeControllers)
1205       {
1206         _curOutParamNums[chn].setDATAL(dataL);
1207         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL), evBuffer))
1208           return false;
1209       }
1210 
1211       if(MusEGlobal::config.midiSendNullParameters)
1212       {
1213         _curOutParamNums[chn].setRPNH(0x7f);
1214         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, 0x7f), evBuffer))
1215           return false;
1216 
1217         _curOutParamNums[chn].setRPNL(0x7f);
1218         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, 0x7f), evBuffer))
1219           return false;
1220       }
1221     }
1222     else if (a < CTRL_NONE_OFFSET)
1223     {     // NRPN14 Controller
1224       int ctrlH = (a >> 8) & 0x7f;
1225       int ctrlL = a & 0x7f;
1226       int dataH = (b >> 7) & 0x7f;
1227       int dataL = b & 0x7f;
1228       if(ctrlH != _curOutParamNums[chn].NRPNH || !MusEGlobal::config.midiOptimizeControllers)
1229       {
1230         _curOutParamNums[chn].setNRPNH(ctrlH);
1231         if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH), evBuffer))
1232           return false;
1233       }
1234       if(ctrlL != _curOutParamNums[chn].NRPNL || !MusEGlobal::config.midiOptimizeControllers)
1235       {
1236         _curOutParamNums[chn].setNRPNL(ctrlL);
1237         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL), evBuffer))
1238           return false;
1239       }
1240       if(dataH != _curOutParamNums[chn].DATAH || !MusEGlobal::config.midiOptimizeControllers)
1241       {
1242         _curOutParamNums[chn].setDATAH(dataH);
1243         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH), evBuffer))
1244           return false;
1245       }
1246       if(dataL != _curOutParamNums[chn].DATAL || !MusEGlobal::config.midiOptimizeControllers)
1247       {
1248         _curOutParamNums[chn].setDATAL(dataL);
1249         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL), evBuffer))
1250           return false;
1251       }
1252 
1253       if(MusEGlobal::config.midiSendNullParameters)
1254       {
1255         _curOutParamNums[chn].setNRPNH(0x7f);
1256         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, 0x7f), evBuffer))
1257           return false;
1258 
1259         _curOutParamNums[chn].setNRPNL(0x7f);
1260         if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, 0x7f), evBuffer))
1261          return false;
1262       }
1263     }
1264     else
1265     {
1266       if(MusEGlobal::debugMsg)
1267         printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a);
1268       //return false;  // Just ignore it.
1269     }
1270   }
1271   else
1272   {
1273     //queueEvent(MidiPlayEvent(t, port, chn, event));
1274     if(!queueEvent(event, evBuffer))
1275       return false;
1276   }
1277 
1278   return true;
1279 }
1280 
1281 //---------------------------------------------------------
1282 //    processMidi
1283 //    Called from audio thread only.
1284 //---------------------------------------------------------
1285 
processMidi(unsigned int curFrame)1286 void MidiJackDevice::processMidi(unsigned int curFrame)
1287 {
1288   void* port_buf = 0;
1289   if(_out_client_jackport && _writeEnable)
1290   {
1291     port_buf = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);
1292     jack_midi_clear_buffer(port_buf);
1293   }
1294 
1295   // Get the state of the stop flag.
1296   const bool do_stop = stopFlag();
1297 
1298   MidiPlayEvent buf_ev;
1299 
1300   // Transfer the user lock-free buffer events to the user sorted multi-set.
1301   // False = don't use the size snapshot, but update it.
1302   const unsigned int usr_buf_sz = eventBuffers(UserBuffer)->getSize(false);
1303   for(unsigned int i = 0; i < usr_buf_sz; ++i)
1304   {
1305     if(eventBuffers(UserBuffer)->get(buf_ev))
1306       _outUserEvents.insert(buf_ev);
1307   }
1308 
1309   // Transfer the playback lock-free buffer events to the playback sorted multi-set.
1310   const unsigned int pb_buf_sz = eventBuffers(PlaybackBuffer)->getSize(false);
1311   for(unsigned int i = 0; i < pb_buf_sz; ++i)
1312   {
1313     // Are we stopping? Just remove the item.
1314     if(do_stop)
1315       eventBuffers(PlaybackBuffer)->remove();
1316     // Otherwise get the item.
1317     else if(eventBuffers(PlaybackBuffer)->get(buf_ev))
1318       _outPlaybackEvents.insert(buf_ev);
1319   }
1320 
1321   // Are we stopping?
1322   if(do_stop)
1323   {
1324     // Transport has stopped, purge ALL further scheduled playback events now.
1325     _outPlaybackEvents.clear();
1326     // Reset the flag.
1327     setStopFlag(false);
1328   }
1329 
1330   iMPEvent impe_pb = _outPlaybackEvents.begin();
1331   iMPEvent impe_us = _outUserEvents.begin();
1332   bool using_pb;
1333 
1334   while(1)
1335   {
1336     if(impe_pb != _outPlaybackEvents.end() && impe_us != _outUserEvents.end())
1337       using_pb = *impe_pb < *impe_us;
1338     else if(impe_pb != _outPlaybackEvents.end())
1339       using_pb = true;
1340     else if(impe_us != _outUserEvents.end())
1341       using_pb = false;
1342     else break;
1343 
1344     const MidiPlayEvent& ev = using_pb ? *impe_pb : *impe_us;
1345 
1346     if(ev.time() >= (curFrame + MusEGlobal::segmentSize))
1347     {
1348       #ifdef JACK_MIDI_DEBUG
1349       fprintf(stderr, "MusE: Jack midi: putted event is for future:%lu, breaking loop now\n", ev.time() - curFrame);
1350       #endif
1351       break;
1352     }
1353 
1354     // If processEvent fails, although we would like to not miss events by keeping them
1355     //  until next cycle and trying again, that can lead to a large backup of events
1356     //  over a long time. So we'll just... miss them.
1357     processEvent(ev, port_buf);
1358 
1359     // Successfully processed event. Remove it from FIFO.
1360     // C++11.
1361     if(using_pb)
1362       impe_pb = _outPlaybackEvents.erase(impe_pb);
1363     else
1364       impe_us = _outUserEvents.erase(impe_us);
1365   }
1366 }
1367 
1368 //---------------------------------------------------------
1369 //   portLatency
1370 //   If capture is true get the capture latency,
1371 //    otherwise get the playback latency.
1372 //---------------------------------------------------------
1373 
portLatency(void *,bool capture) const1374 unsigned int MidiJackDevice::portLatency(void* /*port*/, bool capture) const
1375 {
1376 //   jack_latency_range_t c_range;
1377 //   jack_port_get_latency_range((jack_port_t*)port, JackCaptureLatency, &c_range);
1378 //   jack_latency_range_t p_range;
1379 //   jack_port_get_latency_range((jack_port_t*)port, JackPlaybackLatency, &p_range);
1380 
1381   // TODO FIXME: Tests on both Jack-1 Midi and Jack-2 Midi show the returned values are always zero.
1382   //             Spent a few days trying to diagnose, it appears Jack does not initialize any ALSA
1383   //              midi port latency values as it does with the audio ports. Thus right from the start,
1384   //              right from the backend physical port, the values passed throughout the system and
1385   //              to the app are always zero!
1386 
1387   // NOTICE: For at least the ALSA seq driver (tested), the input latency is
1388   //          always 1 period while the output latency is always 2 periods
1389   //          regardless of Jack command line -p (period size).
1390   //         (Also there is the user latency from command line or QJackCtl.)
1391   //         In other words, the Jack command line -p (number of periods) ONLY applies to audio output ports.
1392 
1393   //fprintf(stderr, "MidiJackDevice::portLatency port:%p capture:%d c_range.min:%d c_range.max:%d p_range.min:%d p_range.max:%d\n",
1394   //        port, capture, c_range.min, c_range.max, p_range.min, p_range.max);
1395 
1396   if(capture)
1397   {
1398 //     jack_latency_range_t c_range;
1399 //     jack_port_get_latency_range((jack_port_t*)port, JackCaptureLatency, &c_range);
1400 
1401 // REMOVE Tim. latency. TESTING Reinstate. For simulating non-functional jack midi latency. This seems to work well.
1402 //     return c_range.max;
1403     return MusEGlobal::segmentSize;
1404   }
1405   else
1406   {
1407 //     jack_latency_range_t p_range;
1408 //     jack_port_get_latency_range((jack_port_t*)port, JackPlaybackLatency, &p_range);
1409 
1410 // REMOVE Tim. latency. TESTING Reinstate. For simulating non-functional jack midi latency. This seems to work well.
1411 //     return p_range.max;
1412     return MusEGlobal::segmentSize * 2;
1413   }
1414 }
1415 
1416 //---------------------------------------------------------
1417 //   selfLatencyMidi
1418 //---------------------------------------------------------
1419 
selfLatencyMidi(int channel,bool capture) const1420 float MidiJackDevice::selfLatencyMidi(int channel, bool capture) const
1421 {
1422   float l = MidiDevice::selfLatencyMidi(channel, capture);
1423 
1424   //if(!MusEGlobal::checkAudioDevice())
1425   //  return l;
1426 
1427   if(capture)
1428   {
1429     if(_in_client_jackport)
1430       l += portLatency(_in_client_jackport, capture);
1431   }
1432   else
1433   {
1434     if(_out_client_jackport)
1435       l += portLatency(_out_client_jackport, capture);
1436   }
1437   return l;
1438 }
1439 
1440 //---------------------------------------------------------
1441 //   initMidiJack
1442 //    return true on error
1443 //---------------------------------------------------------
1444 
initMidiJack()1445 bool initMidiJack()
1446 {
1447   return false;
1448 }
1449 
1450 } // namespace MusECore
1451