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