1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: midiport.cpp,v 1.21.2.15 2009/12/07 20:11:51 terminator356 Exp $
5 //
6 // (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
7 // (C) Copyright 2012, 2017 Tim E. Real (terminator356 on users dot sourceforge dot net)
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; version 2 of
12 // the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=========================================================
24
25 #include <set>
26
27 #include <QString>
28
29 #include "midiport.h"
30 #include "midi_consts.h"
31 #include "midiseq.h"
32 #include "gconfig.h"
33 #include "globals.h"
34 #include "synth.h"
35 #include "app.h"
36 #include "song.h"
37 #include "menutitleitem.h"
38 #include "icons.h"
39 #include "track.h"
40 #include "drummap.h"
41 #include "audio.h"
42 #include "muse_math.h"
43 #include "sysex_helper.h"
44
45 // Forwards from header:
46 #include "mididev.h"
47 #include "instruments/minstrument.h"
48 #include "part.h"
49 #include "midi_controller.h"
50 #include "midictrl.h"
51 #include "mpevent.h"
52 #include "xml.h"
53
54 namespace MusEGlobal {
55 MusECore::MidiPort midiPorts[MusECore::MIDI_PORTS];
56 }
57
58 namespace MusECore {
59
60 MidiControllerList defaultManagedMidiController;
61
62 //---------------------------------------------------------
63 // initMidiPorts
64 //---------------------------------------------------------
65
initMidiPorts()66 void initMidiPorts()
67 {
68 defaultManagedMidiController.add(&pitchCtrl);
69 defaultManagedMidiController.add(&programCtrl);
70 defaultManagedMidiController.add(&volumeCtrl);
71 defaultManagedMidiController.add(&panCtrl);
72 defaultManagedMidiController.add(&reverbSendCtrl);
73 defaultManagedMidiController.add(&chorusSendCtrl);
74 defaultManagedMidiController.add(&variationSendCtrl);
75
76 for (int i = 0; i < MusECore::MIDI_PORTS; ++i) {
77 MidiPort* port = &MusEGlobal::midiPorts[i];
78
79 //
80 // create minimum set of managed controllers
81 // to make midi mixer operational
82 //
83 port->addDefaultControllers();
84
85 port->changeInstrument(registerMidiInstrument("GM"));
86 port->syncInfo().setPort(i);
87 // Set the first channel on the first port to auto-connect to midi track outputs.
88 if(i == 0)
89 {
90
91 // robert: removing the default init on several places to allow for the case
92 // where you rather want the midi track to default to the last created port
93 // this can only happen if there is _no_ default set
94 //
95 // port->setDefaultOutChannels(1);
96
97 port->setDefaultInChannels(1);
98 }
99 }
100 }
101
102 //---------------------------------------------------------
103 // MidiPort
104 //---------------------------------------------------------
105
MidiPort()106 MidiPort::MidiPort()
107 : _state("not configured")
108 {
109 _initializationsSent = false;
110 _defaultInChannels = 0;
111 _defaultOutChannels = 0;
112 _device = 0;
113 _instrument = 0;
114 _tmpTrackIdx = -1;
115 _controller = new MidiCtrlValListList();
116 _foundInSongFile = false;
117 }
118
119 //---------------------------------------------------------
120 // MidiPort
121 //---------------------------------------------------------
122
~MidiPort()123 MidiPort::~MidiPort()
124 {
125 delete _controller;
126 }
127
128 //---------------------------------------------------------
129 // guiVisible
130 //---------------------------------------------------------
131
guiVisible() const132 bool MidiPort::guiVisible() const
133 {
134 if(!_device)
135 return false;
136 SynthI* synth = 0;
137 if(_device->isSynti())
138 synth = static_cast<SynthI*>(_device);
139 if(!synth)
140 return false;
141 return synth->guiVisible();
142 }
143
144 //---------------------------------------------------------
145 // showGui
146 //---------------------------------------------------------
147
showGui(bool v)148 void MidiPort::showGui(bool v)
149 {
150 if(!_device)
151 return;
152 SynthI* synth = 0;
153 if(_device->isSynti())
154 synth = static_cast<SynthI*>(_device);
155 if(!synth)
156 return;
157 synth->showGui(v);
158 }
159
160 //---------------------------------------------------------
161 // hasGui
162 //---------------------------------------------------------
163
hasGui() const164 bool MidiPort::hasGui() const
165 {
166 if(!_device)
167 return false;
168 SynthI* synth = 0;
169 if(_device->isSynti())
170 synth = static_cast<SynthI*>(_device);
171 if(!synth)
172 return false;
173 return synth->hasGui();
174 }
175
176 //---------------------------------------------------------
177 // nativeGuiVisible
178 //---------------------------------------------------------
179
nativeGuiVisible() const180 bool MidiPort::nativeGuiVisible() const
181 {
182 if(!_device)
183 return false;
184 SynthI* synth = 0;
185 if(_device->isSynti())
186 synth = static_cast<SynthI*>(_device);
187 if(!synth)
188 return false;
189 return synth->nativeGuiVisible();
190 }
191
192 //---------------------------------------------------------
193 // showNativeGui
194 //---------------------------------------------------------
195
showNativeGui(bool v)196 void MidiPort::showNativeGui(bool v)
197 {
198 if(!_device)
199 return;
200 SynthI* synth = 0;
201 if(_device->isSynti())
202 synth = static_cast<SynthI*>(_device);
203 if(!synth)
204 return;
205 synth->showNativeGui(v);
206 }
207
208 //---------------------------------------------------------
209 // hasNativeGui
210 //---------------------------------------------------------
211
hasNativeGui() const212 bool MidiPort::hasNativeGui() const
213 {
214 if(!_device)
215 return false;
216 SynthI* synth = 0;
217 if(_device->isSynti())
218 synth = static_cast<SynthI*>(_device);
219 if(!synth)
220 return false;
221 return synth->hasNativeGui();
222 }
223
224 //---------------------------------------------------------
225 // setDevice
226 //---------------------------------------------------------
227
setMidiDevice(MidiDevice * dev,MidiInstrument * instrument)228 void MidiPort::setMidiDevice(MidiDevice* dev, MidiInstrument* instrument)
229 {
230 if (_device) {
231 if (_device->isSynti())
232 _instrument = genericMidiInstrument;
233 _device->setPort(-1);
234 _device->close();
235 _initializationsSent = false;
236 // Wait until upcoming process call has finished. Otherwise Jack may crash!
237 MusEGlobal::audio->msgAudioWait();
238 }
239 if (dev) {
240 for (int i = 0; i < MusECore::MIDI_PORTS; ++i) {
241 MidiPort* mp = &MusEGlobal::midiPorts[i];
242 if (mp->device() == dev) {
243 if(dev->isSynti())
244 mp->changeInstrument(genericMidiInstrument);
245 // move device
246 _state = mp->state();
247 mp->clearDevice();
248 break;
249 }
250 }
251 _device = dev;
252 // If an instrument was given, use it. Otherwise don't touch the instrument.
253 if(instrument)
254 _instrument = instrument;
255 _state = _device->open();
256 _device->setPort(portno());
257 _initializationsSent = false;
258 }
259
260 else
261 clearDevice();
262 }
263
264 //---------------------------------------------------------
265 // sendPendingInitializations
266 // Return true if success.
267 // To be called from realtime audio thread only.
268 //---------------------------------------------------------
269
sendPendingInitializations(bool force)270 bool MidiPort::sendPendingInitializations(bool force)
271 {
272 if(!_device || !(_device->openFlags() & 1)) // Not writable?
273 return false;
274
275 bool rv = true;
276 int port = portno();
277
278 //
279 // test for explicit instrument initialization
280 //
281
282 // unsigned last_tick = 0;
283 unsigned last_frame = 0;
284 MusECore::MidiInstrument* instr = instrument();
285 if(instr && MusEGlobal::config.midiSendInit && (force || !_initializationsSent))
286 {
287 // Send the Instrument Init sequences.
288 EventList* events = instr->midiInit();
289 if(!events->empty())
290 {
291 for(iEvent ie = events->begin(); ie != events->end(); ++ie)
292 {
293 if(ie->second.type() == Sysex)
294 last_frame += sysexDuration(ie->second.dataLen(), MusEGlobal::sampleRate);
295 MusECore::MidiPlayEvent ev = ie->second.asMidiPlayEvent(last_frame + MusEGlobal::audio->curSyncFrame(), port, 0);
296 _device->putEvent(ev, MidiDevice::NotLate);
297 }
298 // Give a bit of time for the last Init sysex to settle?
299 last_frame += 100;
300 }
301 _initializationsSent = true; // Mark as having been sent.
302 }
303
304 // Send the Instrument controller default values.
305 sendInitialControllers(last_frame);
306
307 return rv;
308 }
309
310 //---------------------------------------------------------
311 // sendInitialControllers
312 // Return true if success.
313 //---------------------------------------------------------
314
sendInitialControllers(unsigned start_time)315 bool MidiPort::sendInitialControllers(unsigned start_time)
316 {
317 MusECore::MetronomeSettings* metro_settings =
318 MusEGlobal::metroUseSongSettings ? &MusEGlobal::metroSongSettings : &MusEGlobal::metroGlobalSettings;
319
320 bool rv = true;
321 int port = portno();
322
323 // Find all channels of this port used in the song...
324 bool usedChans[MusECore::MUSE_MIDI_CHANNELS];
325 int usedChanCount = 0;
326 for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
327 usedChans[i] = false;
328 if(MusEGlobal::song->click() && metro_settings->clickPort == port)
329 {
330 usedChans[metro_settings->clickChan] = true;
331 ++usedChanCount;
332 }
333 for(ciMidiTrack imt = MusEGlobal::song->midis()->begin(); imt != MusEGlobal::song->midis()->end(); ++imt)
334 {
335 if((*imt)->type() == MusECore::Track::DRUM)
336 {
337 for(int i = 0; i < DRUM_MAPSIZE; ++i)
338 {
339 // Default to track port if -1 and track channel if -1.
340 int mport = (*imt)->drummap()[i].port;
341 if(mport == -1)
342 mport = (*imt)->outPort();
343 int mchan = (*imt)->drummap()[i].channel;
344 if(mchan == -1)
345 mchan = (*imt)->outChannel();
346 if(mport != port || usedChans[mchan])
347 continue;
348 usedChans[mchan] = true;
349 ++usedChanCount;
350 if(usedChanCount >= MusECore::MUSE_MIDI_CHANNELS)
351 break; // All are used, done searching.
352 }
353 }
354 else
355 {
356 if((*imt)->outPort() != port || usedChans[(*imt)->outChannel()])
357 continue;
358 usedChans[(*imt)->outChannel()] = true;
359 ++usedChanCount;
360 }
361
362 if(usedChanCount >= MusECore::MUSE_MIDI_CHANNELS)
363 break; // All are used, done searching.
364 }
365
366 // NOT for syntis. Use midiState and/or initParams for that.
367 if(MusEGlobal::config.midiSendInit && MusEGlobal::config.midiSendCtlDefaults && _instrument && !_device->isSynti())
368 {
369 MusECore::MidiControllerList* cl = new MusECore::MidiControllerList();
370
371 MidiController* mc;
372
373 for(int chan = 0; chan < MusECore::MUSE_MIDI_CHANNELS; ++chan)
374 {
375 if(!usedChans[chan])
376 continue; // This channel on this port is not used in the song.
377
378 const int patch = hwCtrlState(chan, CTRL_PROGRAM);
379 cl->clear();
380 instrument()->getControllers(cl, chan, patch);
381
382 for(ciMidiController imc = cl->begin(); imc != cl->end(); ++imc)
383 {
384 mc = imc->second;
385 ciMidiCtrlValList i;
386
387 // Look for an initial value for this midi controller, on this midi channel, in the song...
388 for(i = _controller->begin(); i != _controller->end(); ++i)
389 {
390 int channel = i->first >> 24;
391 int cntrl = i->first & 0xffffff;
392 int val = i->second->hwVal();
393 if(channel == chan && cntrl == mc->num() && val != CTRL_VAL_UNKNOWN)
394 break;
395 }
396 // If no initial value was found for this midi controller, on this midi channel, in the song...
397 if(i == _controller->end())
398 {
399 // If the instrument's midi controller has an initial value, send it now.
400 if(mc->initVal() != CTRL_VAL_UNKNOWN)
401 {
402 int ctl = mc->num();
403 // Note the addition of bias!
404 _device->putEvent(MidiPlayEvent(start_time, port, chan,
405 ME_CONTROLLER, ctl, mc->initVal() + mc->bias()), MidiDevice::NotLate);
406 // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
407 // Set it again so that control labels show 'off'...
408 setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, mc->initVal() + mc->bias());
409 }
410 }
411 }
412 }
413 delete cl;
414 }
415
416 // init HW controller state
417 for (iMidiCtrlValList i = _controller->begin(); i != _controller->end(); ++i)
418 {
419 int channel = i->first >> 24;
420 if(!usedChans[channel])
421 continue; // This channel on this port is not used in the song.
422 int cntrl = i->first & 0xffffff;
423 int val = i->second->hwVal();
424 if (val != CTRL_VAL_UNKNOWN)
425 {
426 _device->putEvent(MidiPlayEvent(start_time, port, channel,
427 ME_CONTROLLER, cntrl, val), MidiDevice::NotLate);
428 // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
429 setHwCtrlState(channel, cntrl, val);
430 }
431 }
432
433 return rv;
434 }
435
436 //---------------------------------------------------------
437 // changeInstrument
438 // If audio is running (and not idle) this should only be called by the rt audio thread.
439 //---------------------------------------------------------
440
changeInstrument(MidiInstrument * i)441 void MidiPort::changeInstrument(MidiInstrument* i)
442 {
443 if(_instrument == i)
444 return;
445 _instrument = i;
446 _initializationsSent = false;
447 updateDrumMaps();
448 }
449
450 //---------------------------------------------------------
451 // clearDevice
452 //---------------------------------------------------------
453
clearDevice()454 void MidiPort::clearDevice()
455 {
456 _device = 0;
457 _initializationsSent = false;
458 _state = "not configured";
459 }
460
461 //---------------------------------------------------------
462 // portno
463 //---------------------------------------------------------
464
portno() const465 int MidiPort::portno() const
466 {
467 for (int i = 0; i < MusECore::MIDI_PORTS; ++i) {
468 if (&MusEGlobal::midiPorts[i] == this)
469 return i;
470 }
471 return -1;
472 }
473
474 //---------------------------------------------------------
475 // portname
476 //---------------------------------------------------------
477
portname() const478 const QString& MidiPort::portname() const
479 {
480 static const QString none(QT_TRANSLATE_NOOP("@default", "<none>"));
481 if (_device)
482 return _device->name();
483 else
484 return none;
485 }
486
487 //---------------------------------------------------------
488 // tryCtrlInitVal
489 // To be called from realtime audio thread only.
490 //---------------------------------------------------------
491
tryCtrlInitVal(int chan,int ctl,int val)492 void MidiPort::tryCtrlInitVal(int chan, int ctl, int val)
493 {
494 // Look for an initial value in the song for this midi controller, on this midi channel... (p4.0.27)
495 iMidiCtrlValList i = _controller->find(chan, ctl);
496 if(i != _controller->end())
497 {
498 int v = i->second->value(0); // Value at tick 0.
499 if(v != CTRL_VAL_UNKNOWN)
500 {
501 if(_device)
502 _device->putEvent(MidiPlayEvent(0, portno(), chan, ME_CONTROLLER, ctl, v), MidiDevice::NotLate);
503
504 // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
505 setHwCtrlState(chan, ctl, v);
506
507 return;
508 }
509 }
510
511 // No initial value was found in the song for this midi controller on this midi channel. Try the instrument...
512 if(_instrument)
513 {
514 const int patch = hwCtrlState(chan, CTRL_PROGRAM);
515 const MidiController* mc = instrument()->findController(ctl, chan, patch);
516
517 int initval = mc->initVal();
518
519 // Initialize from either the instrument controller's initial value, or the supplied value.
520 if(initval != CTRL_VAL_UNKNOWN)
521 {
522 if(_device)
523 {
524 MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, initval + mc->bias());
525 _device->putEvent(ev, MidiDevice::NotLate);
526 }
527 setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, initval + mc->bias());
528
529 return;
530 }
531 }
532
533 // No initial value was found in the song or instrument for this midi controller. Just send the given value.
534 if(_device)
535 {
536 MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, val);
537 _device->putEvent(ev, MidiDevice::NotLate);
538 }
539 setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, val);
540 }
541
542 //---------------------------------------------------------
543 // sendGmInitValues
544 //---------------------------------------------------------
545
sendGmInitValues()546 void MidiPort::sendGmInitValues()
547 {
548 for (int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i) {
549 // By T356. Initialize from instrument controller if it has an initial value, otherwise use the specified value.
550 // Tested: Ultimately, a track's controller stored values take priority by sending any 'zero time' value
551 // AFTER these GM/GS/XG init routines are called via initDevices().
552 tryCtrlInitVal(i, CTRL_PROGRAM, 0);
553 tryCtrlInitVal(i, CTRL_PITCH, 0);
554 tryCtrlInitVal(i, CTRL_VOLUME, 100);
555 tryCtrlInitVal(i, CTRL_PANPOT, 64);
556 tryCtrlInitVal(i, CTRL_REVERB_SEND, 40);
557 tryCtrlInitVal(i, CTRL_CHORUS_SEND, 0);
558 }
559 }
560
561 //---------------------------------------------------------
562 // sendGsInitValues
563 //---------------------------------------------------------
564
sendGsInitValues()565 void MidiPort::sendGsInitValues()
566 {
567 sendGmInitValues();
568 }
569
570 //---------------------------------------------------------
571 // sendXgInitValues
572 //---------------------------------------------------------
573
sendXgInitValues()574 void MidiPort::sendXgInitValues()
575 {
576 for (int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i) {
577 // By T356. Initialize from instrument controller if it has an initial value, otherwise use the specified value.
578 tryCtrlInitVal(i, CTRL_PROGRAM, 0);
579 tryCtrlInitVal(i, CTRL_MODULATION, 0);
580 tryCtrlInitVal(i, CTRL_PORTAMENTO_TIME, 0);
581 tryCtrlInitVal(i, CTRL_VOLUME, 0x64);
582 tryCtrlInitVal(i, CTRL_PANPOT, 0x40);
583 tryCtrlInitVal(i, CTRL_EXPRESSION, 0x7f);
584 tryCtrlInitVal(i, CTRL_SUSTAIN, 0x0);
585 tryCtrlInitVal(i, CTRL_PORTAMENTO, 0x0);
586 tryCtrlInitVal(i, CTRL_SOSTENUTO, 0x0);
587 tryCtrlInitVal(i, CTRL_SOFT_PEDAL, 0x0);
588 tryCtrlInitVal(i, CTRL_HARMONIC_CONTENT, 0x40);
589 tryCtrlInitVal(i, CTRL_RELEASE_TIME, 0x40);
590 tryCtrlInitVal(i, CTRL_ATTACK_TIME, 0x40);
591 tryCtrlInitVal(i, CTRL_BRIGHTNESS, 0x40);
592 tryCtrlInitVal(i, CTRL_REVERB_SEND, 0x28);
593 tryCtrlInitVal(i, CTRL_CHORUS_SEND, 0x0);
594 tryCtrlInitVal(i, CTRL_VARIATION_SEND, 0x0);
595 }
596 }
597
598 //---------------------------------------------------------
599 // sendGmOn
600 // send GM-On message to midi device and keep track
601 // of device state
602 //---------------------------------------------------------
603
sendGmOn()604 void MidiPort::sendGmOn()
605 {
606 sendSysex(gmOnMsg, gmOnMsgLen);
607 }
608
609 //---------------------------------------------------------
610 // sendGsOn
611 // send Roland GS-On message to midi device and keep track
612 // of device state
613 //---------------------------------------------------------
614
sendGsOn()615 void MidiPort::sendGsOn()
616 {
617 sendSysex(gsOnMsg2, gsOnMsg2Len);
618 sendSysex(gsOnMsg3, gsOnMsg3Len);
619 }
620
621 //---------------------------------------------------------
622 // sendXgOn
623 // send Yamaha XG-On message to midi device and keep track
624 // of device state
625 //---------------------------------------------------------
626
sendXgOn()627 void MidiPort::sendXgOn()
628 {
629 sendSysex(xgOnMsg, xgOnMsgLen);
630 }
631
632 //---------------------------------------------------------
633 // sendSysex
634 // send SYSEX message to midi device
635 //---------------------------------------------------------
636
sendSysex(const unsigned char * p,int n)637 void MidiPort::sendSysex(const unsigned char* p, int n)
638 {
639 if (_device) {
640 MidiPlayEvent event(0, 0, ME_SYSEX, p, n);
641 _device->putEvent(event, MidiDevice::NotLate);
642 }
643 }
644
645 //---------------------------------------------------------
646 // sendMMCLocate
647 //---------------------------------------------------------
648
sendMMCLocate(unsigned char ht,unsigned char m,unsigned char s,unsigned char f,unsigned char sf,int devid)649 void MidiPort::sendMMCLocate(unsigned char ht, unsigned char m, unsigned char s, unsigned char f, unsigned char sf, int devid)
650 {
651 unsigned char msg[mmcLocateMsgLen];
652 memcpy(msg, mmcLocateMsg, mmcLocateMsgLen);
653 if(devid != -1)
654 msg[1] = devid;
655 else
656 msg[1] = _syncInfo.idOut();
657 msg[6] = ht;
658 msg[7] = m;
659 msg[8] = s;
660 msg[9] = f;
661 msg[10] = sf;
662 sendSysex(msg, mmcLocateMsgLen);
663 }
664
665 //---------------------------------------------------------
666 // sendMMCStop
667 //---------------------------------------------------------
668
sendMMCStop(int devid)669 void MidiPort::sendMMCStop(int devid)
670 {
671 unsigned char msg[mmcStopMsgLen];
672 memcpy(msg, mmcStopMsg, mmcStopMsgLen);
673 if(devid != -1)
674 msg[1] = devid;
675 else
676 msg[1] = _syncInfo.idOut();
677 sendSysex(msg, mmcStopMsgLen);
678 }
679
680 //---------------------------------------------------------
681 // sendMMCDeferredPlay
682 //---------------------------------------------------------
683
sendMMCDeferredPlay(int devid)684 void MidiPort::sendMMCDeferredPlay(int devid)
685 {
686 unsigned char msg[mmcDeferredPlayMsgLen];
687 memcpy(msg, mmcDeferredPlayMsg, mmcDeferredPlayMsgLen);
688 if(devid != -1)
689 msg[1] = devid;
690 else
691 msg[1] = _syncInfo.idOut();
692 sendSysex(msg, mmcDeferredPlayMsgLen);
693 }
694
695 //---------------------------------------------------------
696 // sendStart
697 //---------------------------------------------------------
698
sendStart()699 void MidiPort::sendStart()
700 {
701 if (_device) {
702 MidiPlayEvent event(0, 0, 0, ME_START, 0, 0);
703 _device->putEvent(event, MidiDevice::NotLate);
704 }
705 }
706
707 //---------------------------------------------------------
708 // sendStop
709 //---------------------------------------------------------
710
sendStop()711 void MidiPort::sendStop()
712 {
713 if (_device) {
714 MidiPlayEvent event(0, 0, 0, ME_STOP, 0, 0);
715 _device->putEvent(event, MidiDevice::NotLate);
716 }
717 }
718
719 //---------------------------------------------------------
720 // sendClock
721 //---------------------------------------------------------
722
sendClock()723 void MidiPort::sendClock()
724 {
725 if (_device) {
726 MidiPlayEvent event(0, 0, 0, ME_CLOCK, 0, 0);
727 _device->putEvent(event, MidiDevice::NotLate);
728 }
729 }
730
731 //---------------------------------------------------------
732 // sendContinue
733 //---------------------------------------------------------
734
sendContinue()735 void MidiPort::sendContinue()
736 {
737 if (_device) {
738 MidiPlayEvent event(0, 0, 0, ME_CONTINUE, 0, 0);
739 _device->putEvent(event, MidiDevice::NotLate);
740 }
741 }
742
743 //---------------------------------------------------------
744 // sendSongpos
745 //---------------------------------------------------------
746
sendSongpos(int pos)747 void MidiPort::sendSongpos(int pos)
748 {
749 if (_device) {
750 MidiPlayEvent event(0, 0, 0, ME_SONGPOS, pos, 0);
751 _device->putEvent(event, MidiDevice::NotLate);
752 }
753 }
754
755 //---------------------------------------------------------
756 // addManagedController
757 //---------------------------------------------------------
758
addManagedController(int channel,int ctrl)759 MidiCtrlValList* MidiPort::addManagedController(int channel, int ctrl)
760 {
761 iMidiCtrlValList cl = _controller->find(channel, ctrl);
762 if (cl == _controller->end()) {
763 MidiCtrlValList* pvl = new MidiCtrlValList(ctrl);
764 _controller->add(channel, pvl);
765 return pvl;
766 }
767 else
768 return cl->second;
769 }
770
771 //---------------------------------------------------------
772 // addDefaultControllers
773 //---------------------------------------------------------
774
addDefaultControllers()775 void MidiPort::addDefaultControllers()
776 {
777 for (int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i) {
778 for(ciMidiController imc = defaultManagedMidiController.begin(); imc != defaultManagedMidiController.end(); ++imc)
779 addManagedController(i, imc->second->num());
780 _automationType[i] = AUTO_READ;
781 }
782 }
783
784 //---------------------------------------------------------
785 // limitValToInstrCtlRange
786 //---------------------------------------------------------
787
limitValToInstrCtlRange(const MidiController * mc,int val)788 int MidiPort::limitValToInstrCtlRange(const MidiController* mc, int val)
789 {
790 if(!_instrument || !mc || val == CTRL_VAL_UNKNOWN)
791 return val;
792
793 //MidiController* mc = imc->second;
794 int mn = mc->minVal();
795 int mx = mc->maxVal();
796 int bias = mc->bias();
797
798 // Subtract controller bias from value.
799 val -= bias;
800
801 // Limit value to controller range.
802 if(val < mn)
803 val = mn;
804 else
805 if(val > mx)
806 val = mx;
807
808 // Re-add controller bias to value.
809 val += bias;
810
811 return val;
812 }
813
limitValToInstrCtlRange(int ctl,int val,int chan)814 int MidiPort::limitValToInstrCtlRange(int ctl, int val, int chan)
815 {
816 if(!_instrument || val == CTRL_VAL_UNKNOWN)
817 return val;
818
819 // FIXME: This might be optimized by calling midiController instead,
820 // and simply asking if it's a drum controller. Saves one list iteration.
821 // Is it a drum controller?
822 // Note: Midnam apparently has no concept of drum controllers, so the fact
823 // that this only asks in the instrument's controllers and not the midnam is OK.
824 const MidiController *mc = drumController(ctl);
825 if(!mc)
826 {
827 // It's not a drum controller. Find it as a regular controller instead.
828 const int patch = hwCtrlState(chan, CTRL_PROGRAM);
829 mc = _instrument->findController(ctl, chan, patch);
830 }
831
832 // If it's a valid controller, limit the value to the instrument controller range.
833 if(mc)
834 return limitValToInstrCtlRange(mc, val);
835
836 return val;
837 }
838
limitValToInstrCtlRange(const MidiController * mc,double val)839 double MidiPort::limitValToInstrCtlRange(const MidiController* mc, double val)
840 {
841 if(!_instrument || !mc || int(val) == CTRL_VAL_UNKNOWN)
842 return val;
843
844 const double mn = double(mc->minVal());
845 const double mx = double(mc->maxVal());
846 const double bias = double(mc->bias());
847
848 // Subtract controller bias from value.
849 val -= double(bias);
850
851 // Limit value to controller range.
852 if(val < mn)
853 val = mn;
854 else
855 if(val > mx)
856 val = mx;
857
858 // Re-add controller bias to value.
859 val += bias;
860
861 return val;
862 }
863
limitValToInstrCtlRange(int ctl,double val,int chan)864 double MidiPort::limitValToInstrCtlRange(int ctl, double val, int chan)
865 {
866 if(!_instrument || int(val) == CTRL_VAL_UNKNOWN)
867 return val;
868
869 // FIXME: This might be optimized by calling midiController instead,
870 // and simply asking if it's a drum controller. Saves one list iteration.
871 // Is it a drum controller?
872 // Note: Midnam apparently has no concept of drum controllers, so the fact
873 // that this only asks in the instrument's controllers and not the midnam is OK.
874 const MidiController *mc = drumController(ctl);
875 if(!mc)
876 {
877 // It's not a drum controller. Find it as a regular controller instead.
878 const int patch = hwCtrlState(chan, CTRL_PROGRAM);
879 mc = _instrument->findController(ctl, chan, patch);
880 }
881
882 // If it's a valid controller, limit the value to the instrument controller range.
883 if(mc)
884 return limitValToInstrCtlRange(mc, val);
885
886 return val;
887 }
888
889 //---------------------------------------------------------
890 // createController
891 // Creates a controller in this port's controller list.
892 // Returns true if the controller was created.
893 // To be called by gui thread only.
894 //---------------------------------------------------------
895
createController(int chan,int ctrl)896 bool MidiPort::createController(int chan, int ctrl)
897 {
898 if(ctrl < 0 || chan < 0 || chan >= MusECore::MUSE_MIDI_CHANNELS)
899 return false;
900
901 PendingOperationList operations;
902
903 // Make sure the controller exists, create it if not.
904 iMidiCtrlValList cl = _controller->find(chan, ctrl);
905 if(cl != _controller->end())
906 return false;
907
908 PendingOperationItem poi(_controller, 0, chan, ctrl, PendingOperationItem::AddMidiCtrlValList);
909
910 // This step is intended in case we ever pass an operations list to this function.
911 if(operations.findAllocationOp(poi) != operations.end())
912 return false;
913
914 MidiCtrlValList* mcvl = new MidiCtrlValList(ctrl);
915 poi._mcvl = mcvl;
916 operations.add(poi);
917 // This waits for audio process thread to execute it.
918 MusEGlobal::audio->msgExecutePendingOperations(operations, true);
919
920 return true;
921 }
922
923 //---------------------------------------------------------
924 // putHwCtrlEvent
925 // To be called from gui thread only.
926 // Returns true if event cannot be delivered.
927 //---------------------------------------------------------
928
putHwCtrlEvent(const MidiPlayEvent & ev)929 bool MidiPort::putHwCtrlEvent(const MidiPlayEvent& ev)
930 {
931 const int ctrl = ev.translateCtrlNum();
932
933 // Event not translatable to a controller?
934 if(ctrl < 0)
935 return true;
936
937 // Make sure to create the controller if necessary.
938 //createController(chan, ctrl);
939
940 // Make sure the controller exists, create it if not.
941 const int chan = ev.channel();
942 ciMidiCtrlValList cl = _controller->find(chan, ctrl);
943 // Controller does not exist?
944 if(cl == _controller->end())
945 {
946 // Tell the gui thread to create and add a new controller.
947 // It will store and re-deliver the events directly to the buffers
948 // after the controller is created.
949 MusEGlobal::song->putIpcInEvent(ev);
950 // Technically the event is being delivered.
951 return false;
952 }
953
954 if(!MusEGlobal::song->putIpcOutEvent(ev))
955 {
956 fprintf(stderr, "MidiPort::putHwCtrlEvent: Error: gui2AudioFifo fifo overflow\n");
957 return true;
958 }
959
960 return false;
961 }
962
963 //---------------------------------------------------------
964 // putEvent
965 // To be called from gui thread only.
966 // Returns true if event cannot be delivered.
967 //---------------------------------------------------------
968
putEvent(const MidiPlayEvent & ev)969 bool MidiPort::putEvent(const MidiPlayEvent& ev)
970 {
971 // Send the event to the device first so that current parameters could be updated on process.
972 bool res = false;
973 if(_device)
974 {
975 res = !_device->putEvent(ev, MidiDevice::Late);
976 }
977 putHwCtrlEvent(ev);
978 return res;
979 }
980
981 //---------------------------------------------------------
982 // putControllerValue
983 // To be called from gui thread only.
984 // Returns true if event cannot be delivered.
985 //---------------------------------------------------------
986
putControllerValue(int port,int chan,int ctlnum,double val,bool isDb)987 bool MidiPort::putControllerValue(int port, int chan, int ctlnum, double val, bool isDb)
988 {
989 iMidiCtrlValList imcvl = _controller->find(chan, ctlnum);
990 if(imcvl == _controller->end())
991 return true;
992
993 // Don't create if not found.
994 MusECore::MidiController* mc = midiController(ctlnum, chan, false);
995 if(!mc)
996 return true;
997 const int max = mc->maxVal();
998
999 if(isDb)
1000 val = double(max) * muse_db2val(val / 2.0);
1001
1002 const int i_new_val = MidiController::dValToInt(val);
1003
1004 // Time-stamp the event.
1005 MidiPlayEvent ev(MusEGlobal::audio->curFrame(), port, chan, MusECore::ME_CONTROLLER, ctlnum, i_new_val);
1006 bool res = false;
1007 if(_device)
1008 {
1009 res = !_device->putEvent(ev, MidiDevice::Late);
1010 }
1011
1012 putHwCtrlEvent(ev);
1013 return res;
1014 }
1015
1016 //---------------------------------------------------------
1017 // handleGui2AudioEvent
1018 // To be called from audio thread only.
1019 // Returns true on success.
1020 // If createAsNeeded is true, automatically send a message to the gui thread to
1021 // create items such as controllers, and cache the events sent to it and re-put
1022 // them after the controller has been created.
1023 //---------------------------------------------------------
1024
handleGui2AudioEvent(const MidiPlayEvent & ev,bool createAsNeeded)1025 bool MidiPort::handleGui2AudioEvent(const MidiPlayEvent& ev, bool createAsNeeded)
1026 {
1027 const int chn = ev.channel();
1028 const int type = ev.type();
1029 const int i_dataA = ev.dataA();
1030 const double d_dataB = ev.dataB();
1031 const int i_dataB = MidiController::dValToInt(d_dataB);
1032
1033 int fin_db = i_dataB;
1034 switch(type)
1035 {
1036 case ME_CONTROLLER:
1037 switch(i_dataA)
1038 {
1039 case CTRL_HBANK:
1040 {
1041 // Does the CTRL_PROGRAM controller exist?
1042 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_PROGRAM);
1043 if(imcvl == _controller->end())
1044 {
1045 // Tell the gui to create the controller and add the value.
1046 if(createAsNeeded)
1047 return MusEGlobal::song->putIpcInEvent(ev);
1048 return false;
1049 }
1050
1051 int hb = 0xff;
1052 if(!MidiController::iValIsUnknown(i_dataB))
1053 hb = i_dataB & 0xff;
1054 if(hb != 0xff)
1055 hb = limitValToInstrCtlRange(i_dataA, hb, chn);
1056 int lb = 0xff;
1057 int pr = 0xff;
1058
1059 MidiCtrlValList* mcvl = imcvl->second;
1060 if(!mcvl->hwValIsUnknown())
1061 {
1062 const int hw_val = mcvl->hwVal();
1063 lb = (hw_val >> 8) & 0xff;
1064 pr = hw_val & 0xff;
1065 }
1066
1067 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1068 pr = 0x01;
1069 if(hb == 0xff && lb == 0xff && pr == 0xff)
1070 fin_db = CTRL_VAL_UNKNOWN;
1071 else
1072 fin_db = (hb << 16) | (lb << 8) | pr;
1073
1074 // Set the value. Be sure to update drum maps (and inform the gui).
1075 if(mcvl->setHwVal(fin_db))
1076 updateDrumMaps(chn, fin_db);
1077
1078 return true;
1079 }
1080 break;
1081
1082 case CTRL_LBANK:
1083 {
1084 // Does the CTRL_PROGRAM controller exist?
1085 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_PROGRAM);
1086 if(imcvl == _controller->end())
1087 {
1088 // Tell the gui to create the controller and add the value.
1089 if(createAsNeeded)
1090 return MusEGlobal::song->putIpcInEvent(ev);
1091 return false;
1092 }
1093
1094 int hb = 0xff;
1095 int lb = 0xff;
1096 if(!MidiController::iValIsUnknown(i_dataB))
1097 lb = i_dataB & 0xff;
1098 if(lb != 0xff)
1099 lb = limitValToInstrCtlRange(i_dataA, lb, chn);
1100 int pr = 0xff;
1101
1102 MidiCtrlValList* mcvl = imcvl->second;
1103 if(!mcvl->hwValIsUnknown())
1104 {
1105 const int hw_val = mcvl->hwVal();
1106 hb = (hw_val >> 16) & 0xff;
1107 pr = hw_val & 0xff;
1108 }
1109
1110 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1111 pr = 0x01;
1112 if(hb == 0xff && lb == 0xff && pr == 0xff)
1113 fin_db = CTRL_VAL_UNKNOWN;
1114 else
1115 fin_db = (hb << 16) | (lb << 8) | pr;
1116
1117 // Set the value. Be sure to update drum maps (and inform the gui).
1118 if(mcvl->setHwVal(fin_db))
1119 updateDrumMaps(chn, fin_db);
1120
1121 return true;
1122 }
1123 break;
1124
1125 case CTRL_PROGRAM:
1126 {
1127 // TODO: Maybe update CTRL_HBANK/CTRL_LBANK - but ONLY if they are specifically
1128 // defined by the user in the controller list.
1129
1130 // Does the CTRL_PROGRAM controller exist?
1131 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_PROGRAM);
1132 if(imcvl == _controller->end())
1133 {
1134 // Tell the gui to create the controller and add the value.
1135 if(createAsNeeded)
1136 return MusEGlobal::song->putIpcInEvent(ev);
1137 return false;
1138 }
1139
1140 // Set the value. Be sure to update drum maps (and inform the gui).
1141 if(imcvl->second->setHwVal(fin_db))
1142 updateDrumMaps(chn, fin_db);
1143
1144 return true;
1145 }
1146 break;
1147
1148 default:
1149 {
1150 // Does the controller exist?
1151 iMidiCtrlValList imcvl = _controller->find(chn, i_dataA);
1152 if(imcvl == _controller->end())
1153 {
1154 // Tell the gui to create the controller and add the value.
1155 if(createAsNeeded)
1156 return MusEGlobal::song->putIpcInEvent(ev);
1157 return false;
1158 }
1159
1160 fin_db = limitValToInstrCtlRange(i_dataA, i_dataB, chn);
1161 // Set the value.
1162 imcvl->second->setHwVal(fin_db);
1163
1164 return true;
1165 }
1166 break;
1167 }
1168 break;
1169
1170 case ME_POLYAFTER:
1171 {
1172 const int pitch = i_dataA & 0x7f;
1173 const int fin_da = (CTRL_POLYAFTER & ~0xff) | pitch;
1174
1175 // Does the controller exist?
1176 iMidiCtrlValList imcvl = _controller->find(chn, fin_da);
1177 if(imcvl == _controller->end())
1178 {
1179 // Tell the gui to create the controller and add the value.
1180 if(createAsNeeded)
1181 return MusEGlobal::song->putIpcInEvent(ev);
1182 return false;
1183 }
1184
1185 fin_db = limitValToInstrCtlRange(fin_da, i_dataB, chn);
1186 // Set the value.
1187 imcvl->second->setHwVal(fin_db);
1188
1189 return true;
1190 }
1191 break;
1192
1193 case ME_AFTERTOUCH:
1194 {
1195 // Does the controller exist?
1196 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_AFTERTOUCH);
1197 if(imcvl == _controller->end())
1198 {
1199 // Tell the gui to create the controller and add the value.
1200 if(createAsNeeded)
1201 return MusEGlobal::song->putIpcInEvent(ev);
1202 return false;
1203 }
1204
1205 fin_db = limitValToInstrCtlRange(CTRL_AFTERTOUCH, i_dataA, chn);
1206 // Set the value.
1207 imcvl->second->setHwVal(fin_db);
1208
1209 return true;
1210 }
1211 break;
1212
1213 case ME_PITCHBEND:
1214 {
1215 // Does the controller exist?
1216 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_PITCH);
1217 if(imcvl == _controller->end())
1218 {
1219 // Tell the gui to create the controller and add the value.
1220 if(createAsNeeded)
1221 return MusEGlobal::song->putIpcInEvent(ev);
1222 return false;
1223 }
1224
1225 fin_db = limitValToInstrCtlRange(CTRL_PITCH, i_dataA, chn);
1226 // Set the value.
1227 imcvl->second->setHwVal(fin_db);
1228
1229 return true;
1230 }
1231 break;
1232
1233 case ME_PROGRAM:
1234 {
1235 // Does the controller exist?
1236 iMidiCtrlValList imcvl = _controller->find(chn, CTRL_PROGRAM);
1237 if(imcvl == _controller->end())
1238 {
1239 // Tell the gui to create the controller and add the value.
1240 if(createAsNeeded)
1241 return MusEGlobal::song->putIpcInEvent(ev);
1242 return false;
1243 }
1244
1245 int hb = 0xff;
1246 int lb = 0xff;
1247 int pr = 0xff;
1248 if(!MidiController::iValIsUnknown(i_dataA))
1249 pr = i_dataA & 0xff;
1250 //if(pr != 0xff)
1251 // pr = limitValToInstrCtlRange(da, pr, chn);
1252
1253 MidiCtrlValList* mcvl = imcvl->second;
1254 if(!mcvl->hwValIsUnknown())
1255 {
1256 const int hw_val = mcvl->hwVal();
1257 hb = (hw_val >> 16) & 0xff;
1258 lb = (hw_val >> 8) & 0xff;
1259 }
1260
1261 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1262 pr = 0x01;
1263 if(hb == 0xff && lb == 0xff && pr == 0xff)
1264 fin_db = CTRL_VAL_UNKNOWN;
1265 else
1266 fin_db = (hb << 16) | (lb << 8) | pr;
1267
1268 // Set the value. Be sure to update drum maps (and inform the gui).
1269 if(mcvl->setHwVal(fin_db))
1270 updateDrumMaps(chn, fin_db);
1271
1272 return true;
1273 }
1274 break;
1275
1276 default:
1277 break;
1278 }
1279
1280 return false;
1281 }
1282
1283 //---------------------------------------------------------
1284 // sendHwCtrlState
1285 // Return true if it is OK to go ahead and deliver the event.
1286 //---------------------------------------------------------
1287
sendHwCtrlState(const MidiPlayEvent & ev,bool forceSend)1288 bool MidiPort::sendHwCtrlState(const MidiPlayEvent& ev, bool forceSend)
1289 {
1290 const int type = ev.type();
1291 const int chn = ev.channel();
1292 const int da = ev.dataA();
1293 int fin_da = da;
1294 const int db = ev.dataB();
1295
1296 switch(type)
1297 {
1298 case ME_CONTROLLER:
1299 switch(da)
1300 {
1301 case CTRL_HBANK:
1302 {
1303 int hb = 0xff;
1304 if(!MidiController::iValIsUnknown(db))
1305 hb = db & 0xff;
1306 if(hb != 0xff)
1307 hb = limitValToInstrCtlRange(da, hb, chn);
1308 int lb = 0xff;
1309 int pr = 0xff;
1310
1311 fin_da = CTRL_PROGRAM;
1312 // This will create a new value list if necessary, otherwise it returns the existing list.
1313 // FIXME: This is not realtime safe because it may allocate.
1314 MidiCtrlValList* mcvl = addManagedController(chn, fin_da);
1315 if(!mcvl->hwValIsUnknown())
1316 {
1317 const int hw_val = mcvl->hwVal();
1318 lb = (hw_val >> 8) & 0xff;
1319 pr = hw_val & 0xff;
1320 }
1321
1322 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1323 pr = 0x01;
1324 }
1325 break;
1326
1327 case CTRL_LBANK:
1328 {
1329 int hb = 0xff;
1330 int lb = 0xff;
1331 if(!MidiController::iValIsUnknown(db))
1332 lb = db & 0xff;
1333 if(lb != 0xff)
1334 lb = limitValToInstrCtlRange(da, lb, chn);
1335 int pr = 0xff;
1336
1337 fin_da = CTRL_PROGRAM;
1338 // This will create a new value list if necessary, otherwise it returns the existing list.
1339 // FIXME: This is not realtime safe because it may allocate.
1340 MidiCtrlValList* mcvl = addManagedController(chn, fin_da);
1341 if(!mcvl->hwValIsUnknown())
1342 {
1343 const int hw_val = mcvl->hwVal();
1344 hb = (hw_val >> 16) & 0xff;
1345 pr = hw_val & 0xff;
1346 }
1347
1348 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1349 pr = 0x01;
1350 }
1351 break;
1352
1353 case CTRL_PROGRAM:
1354 // This will create a new value list if necessary, otherwise it returns the existing list.
1355 // FIXME: This is not realtime safe because it may allocate.
1356 addManagedController(chn, da);
1357 // TODO: Maybe update CTRL_HBANK/CTRL_LBANK - but ONLY if they are specifically
1358 // defined by the user in the controller list.
1359 break;
1360
1361 default:
1362 // This will create a new value list if necessary, otherwise it returns the existing list.
1363 // FIXME: This is not realtime safe because it may allocate.
1364 addManagedController(chn, da);
1365 break;
1366 }
1367 break;
1368
1369 case ME_POLYAFTER:
1370 {
1371 const int pitch = da & 0x7f;
1372 fin_da = (CTRL_POLYAFTER & ~0xff) | pitch;
1373 // This will create a new value list if necessary, otherwise it returns the existing list.
1374 // FIXME: This is not realtime safe because it may allocate.
1375 addManagedController(chn, fin_da);
1376 }
1377 break;
1378
1379 case ME_AFTERTOUCH:
1380 {
1381 fin_da = CTRL_AFTERTOUCH;
1382 // This will create a new value list if necessary, otherwise it returns the existing list.
1383 // FIXME: This is not realtime safe because it may allocate.
1384 addManagedController(chn, fin_da);
1385 }
1386 break;
1387
1388 case ME_PITCHBEND:
1389 {
1390 fin_da = CTRL_PITCH;
1391 // This will create a new value list if necessary, otherwise it returns the existing list.
1392 // FIXME: This is not realtime safe because it may allocate.
1393 addManagedController(chn, fin_da);
1394 }
1395 break;
1396
1397 case ME_PROGRAM:
1398 {
1399 int hb = 0xff;
1400 int lb = 0xff;
1401 int pr = 0xff;
1402 if(!MidiController::iValIsUnknown(da))
1403 pr = da & 0xff;
1404 //if(pr != 0xff)
1405 // pr = limitValToInstrCtlRange(da, pr, chn);
1406
1407 fin_da = CTRL_PROGRAM;
1408 // This will create a new value list if necessary, otherwise it returns the existing list.
1409 // FIXME: This is not realtime safe because it may allocate.
1410 MidiCtrlValList* mcvl = addManagedController(chn, fin_da);
1411 if(!mcvl->hwValIsUnknown())
1412 {
1413 const int hw_val = mcvl->hwVal();
1414 hb = (hw_val >> 16) & 0xff;
1415 lb = (hw_val >> 8) & 0xff;
1416 }
1417
1418 if((hb != 0xff || lb != 0xff) && pr == 0xff)
1419 pr = 0x01;
1420 }
1421 break;
1422
1423 default:
1424 // For all other event types, just return true.
1425 return true;
1426 break;
1427 }
1428
1429 if(!setHwCtrlState(chn, da, db)) {
1430 if (MusEGlobal::debugMsg && forceSend)
1431 printf("sendHwCtrlState: State already set. Forcing anyway...\n");
1432 if (!forceSend)
1433 return false;
1434 }
1435
1436 return true;
1437 }
1438
1439 //---------------------------------------------------------
1440 // lastValidHWCtrlState
1441 //---------------------------------------------------------
1442
lastValidHWCtrlState(int ch,int ctrl) const1443 int MidiPort::lastValidHWCtrlState(int ch, int ctrl) const
1444 {
1445 ch &= 0xff;
1446 ciMidiCtrlValList cl = ((const MidiCtrlValListList*)_controller)->find(ch, ctrl);
1447 if (cl == _controller->end()) {
1448 return CTRL_VAL_UNKNOWN;
1449 }
1450 MidiCtrlValList* vl = cl->second;
1451 return vl->lastValidHWVal();
1452 }
1453
1454 //---------------------------------------------------------
1455 // lastValidHWCtrlState
1456 //---------------------------------------------------------
1457
lastValidHWDCtrlState(int ch,int ctrl) const1458 double MidiPort::lastValidHWDCtrlState(int ch, int ctrl) const
1459 {
1460 ch &= 0xff;
1461 ciMidiCtrlValList cl = ((const MidiCtrlValListList*)_controller)->find(ch, ctrl);
1462 if (cl == _controller->end()) {
1463 return CTRL_VAL_UNKNOWN;
1464 }
1465 MidiCtrlValList* vl = cl->second;
1466 return vl->lastValidHWDVal();
1467 }
1468
1469 //---------------------------------------------------------
1470 // hwCtrlState
1471 //---------------------------------------------------------
1472
hwCtrlState(int ch,int ctrl) const1473 int MidiPort::hwCtrlState(int ch, int ctrl) const
1474 {
1475 ch &= 0xff;
1476 ciMidiCtrlValList cl = ((const MidiCtrlValListList*)_controller)->find(ch, ctrl);
1477 if (cl == _controller->end())
1478 return CTRL_VAL_UNKNOWN;
1479 MidiCtrlValList* vl = cl->second;
1480 return vl->hwVal();
1481 }
1482
1483 //---------------------------------------------------------
1484 // hwDCtrlState
1485 //---------------------------------------------------------
1486
hwDCtrlState(int ch,int ctrl) const1487 double MidiPort::hwDCtrlState(int ch, int ctrl) const
1488 {
1489 ch &= 0xff;
1490 ciMidiCtrlValList cl = ((const MidiCtrlValListList*)_controller)->find(ch, ctrl);
1491 if (cl == _controller->end())
1492 return CTRL_VAL_UNKNOWN;
1493 MidiCtrlValList* vl = cl->second;
1494 return vl->hwDVal();
1495 }
1496
1497 //---------------------------------------------------------
1498 // setHwCtrlState
1499 // If audio is running (and not idle) this should only be called by the rt audio thread.
1500 // Returns false if value is already equal, true if value is set.
1501 //---------------------------------------------------------
1502
setHwCtrlState(const MidiPlayEvent & ev)1503 bool MidiPort::setHwCtrlState(const MidiPlayEvent& ev)
1504 {
1505 const int port = ev.port();
1506 if(port < 0 || port >= MusECore::MIDI_PORTS)
1507 return false;
1508
1509 // Handle the event. Tell the gui to create controllers as needed.
1510 return MusEGlobal::midiPorts[port].handleGui2AudioEvent(ev, true);
1511 }
1512
setHwCtrlState(int ch,int ctrl,int val)1513 bool MidiPort::setHwCtrlState(int ch, int ctrl, int val)
1514 {
1515 // This will create a new value list if necessary, otherwise it returns the existing list.
1516 MidiCtrlValList* vl = addManagedController(ch, ctrl);
1517
1518 bool res = vl->setHwVal(val);
1519 // If program controller be sure to update drum maps (and inform the gui).
1520 if(res && ctrl == CTRL_PROGRAM)
1521 updateDrumMaps(ch, val);
1522
1523 return res;
1524 }
1525
setHwCtrlState(int ch,int ctrl,double val)1526 bool MidiPort::setHwCtrlState(int ch, int ctrl, double val)
1527 {
1528 // This will create a new value list if necessary, otherwise it returns the existing list.
1529 MidiCtrlValList* vl = addManagedController(ch, ctrl);
1530
1531 bool res = vl->setHwVal(val);
1532 // If program controller be sure to update drum maps (and inform the gui).
1533 if(res && ctrl == CTRL_PROGRAM)
1534 updateDrumMaps(ch, val);
1535
1536 return res;
1537 }
1538
1539 //---------------------------------------------------------
1540 // setHwCtrlStates
1541 // If audio is running (and not idle) this should only be called by the rt audio thread.
1542 // Sets current and last HW values.
1543 // Handy for forcing labels to show 'off' and knobs to show specific values
1544 // without having to send two messages.
1545 // Returns false if both values are already set, true if either value is changed.
1546 //---------------------------------------------------------
1547
setHwCtrlStates(int ch,int ctrl,int val,int lastval)1548 bool MidiPort::setHwCtrlStates(int ch, int ctrl, int val, int lastval)
1549 {
1550 // This will create a new value list if necessary, otherwise it returns the existing list.
1551 MidiCtrlValList* vl = addManagedController(ch, ctrl);
1552
1553 // This is not perfectly ideal, drum maps should not have to (check) change if last hw val changed.
1554 bool res = vl->setHwVals(val, lastval);
1555 // If program controller be sure to update drum maps (and inform the gui).
1556 if(res && ctrl == CTRL_PROGRAM)
1557 updateDrumMaps(ch, val);
1558
1559 return res;
1560 }
1561
setHwCtrlStates(int ch,int ctrl,double val,double lastval)1562 bool MidiPort::setHwCtrlStates(int ch, int ctrl, double val, double lastval)
1563 {
1564 // This will create a new value list if necessary, otherwise it returns the existing list.
1565 MidiCtrlValList* vl = addManagedController(ch, ctrl);
1566
1567 // This is not perfectly ideal, drum maps should not have to (check) change if last hw val changed.
1568 bool res = vl->setHwVals(val, lastval);
1569 // If program controller be sure to update drum maps (and inform the gui).
1570 if(res && ctrl == CTRL_PROGRAM)
1571 updateDrumMaps(ch, val);
1572
1573 return res;
1574 }
1575
1576 //---------------------------------------------------------
1577 // setControllerVal
1578 // This function sets a controller value,
1579 // creating the controller if necessary.
1580 // Returns true if a value was actually added.
1581 //---------------------------------------------------------
1582
setControllerVal(int ch,unsigned int tick,int ctrl,int val,Part * part)1583 bool MidiPort::setControllerVal(int ch, unsigned int tick, int ctrl, int val, Part* part)
1584 {
1585 MidiCtrlValList* pvl;
1586 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1587 if (cl == _controller->end())
1588 {
1589 pvl = new MidiCtrlValList(ctrl);
1590 _controller->add(ch, pvl);
1591 }
1592 else
1593 pvl = cl->second;
1594
1595 return pvl->addMCtlVal(tick, val, part);
1596 }
1597
1598 //---------------------------------------------------------
1599 // updateDrumMaps
1600 // If audio is running (and not idle) this should only be called by the rt audio thread.
1601 // Returns true if maps were changed.
1602 //---------------------------------------------------------
1603
updateDrumMaps(int chan,int patch)1604 bool MidiPort::updateDrumMaps(int chan, int patch)
1605 {
1606 int port;
1607 int tpatch;
1608 int tchan;
1609 bool map_changed = false;
1610 MidiTrack* mt;
1611 for(iMidiTrack t = MusEGlobal::song->midis()->begin(); t != MusEGlobal::song->midis()->end(); ++t)
1612 {
1613 mt = *t;
1614 if(mt->type() != Track::DRUM)
1615 continue;
1616 port = mt->outPort();
1617 if(port < 0 || port >= MusECore::MIDI_PORTS || &MusEGlobal::midiPorts[port] != this)
1618 continue;
1619 tchan = mt->outChannel();
1620 if(tchan != chan)
1621 continue;
1622 tpatch = hwCtrlState(tchan, CTRL_PROGRAM);
1623 if(tpatch != patch)
1624 continue;
1625 if(mt->updateDrummap(false)) // false = don't signal gui thread, we'll do that here.
1626 map_changed = true;
1627 }
1628
1629 if(map_changed)
1630 {
1631 // It is possible we are being called from gui thread already, in audio idle mode.
1632 // Will this still work, and not conflict with audio sending the same message?
1633 // Are we are not supposed to write to an fd from different threads?
1634 if(!MusEGlobal::audio || MusEGlobal::audio->isIdle())
1635 // Directly emit SC_DRUMMAP song changed signal.
1636 MusEGlobal::song->update(SC_DRUMMAP);
1637 else
1638 // Tell the gui to emit SC_DRUMMAP song changed signal.
1639 MusEGlobal::audio->sendMsgToGui('D'); // Drum map changed.
1640
1641 return true;
1642 }
1643
1644 return false;
1645 }
1646
1647 //---------------------------------------------------------
1648 // updateDrumMaps
1649 // If audio is running (and not idle) this should only be called by the rt audio thread.
1650 // Returns true if maps were changed.
1651 //---------------------------------------------------------
1652
updateDrumMaps()1653 bool MidiPort::updateDrumMaps()
1654 {
1655 int port;
1656 bool map_changed = false;
1657 MidiTrack* mt;
1658 for(iMidiTrack t = MusEGlobal::song->midis()->begin(); t != MusEGlobal::song->midis()->end(); ++t)
1659 {
1660 mt = *t;
1661 if(mt->type() != Track::DRUM)
1662 continue;
1663 port = mt->outPort();
1664 if(port < 0 || port >= MusECore::MIDI_PORTS || &MusEGlobal::midiPorts[port] != this)
1665 continue;
1666 if(mt->updateDrummap(false)) // false = don't signal gui thread, we'll do that here.
1667 map_changed = true;
1668 }
1669
1670 if(map_changed)
1671 {
1672 // It is possible we are being called from gui thread already, in audio idle mode.
1673 // Will this still work, and not conflict with audio sending the same message?
1674 // Are we are not supposed to write to an fd from different threads?
1675 //if(MusEGlobal::audio && MusEGlobal::audio->isIdle() && MusEGlobal::midiSeq && MusEGlobal::midiSeq->isIdle())
1676 if(!MusEGlobal::audio || MusEGlobal::audio->isIdle())
1677 // Directly emit SC_DRUMMAP song changed signal.
1678 //MusEGlobal::song->update(SC_DRUMMAP, true);
1679 MusEGlobal::song->update(SC_DRUMMAP);
1680 else
1681 // Tell the gui to emit SC_DRUMMAP song changed signal.
1682 MusEGlobal::audio->sendMsgToGui('D'); // Drum map changed.
1683
1684 return true;
1685 }
1686
1687 return false;
1688 }
1689
1690 //---------------------------------------------------------
1691 // getCtrl
1692 //---------------------------------------------------------
1693
getCtrl(int ch,unsigned int tick,int ctrl) const1694 int MidiPort::getCtrl(int ch, unsigned int tick, int ctrl) const
1695 {
1696 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1697 if (cl == _controller->end())
1698 return CTRL_VAL_UNKNOWN;
1699
1700 return cl->second->value(tick);
1701 }
1702
getCtrl(int ch,unsigned int tick,int ctrl,Part * part) const1703 int MidiPort::getCtrl(int ch, unsigned int tick, int ctrl, Part* part) const
1704 {
1705 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1706 if (cl == _controller->end())
1707 return CTRL_VAL_UNKNOWN;
1708
1709 return cl->second->value(tick, part);
1710 }
1711
getVisibleCtrl(int ch,unsigned int tick,int ctrl,bool inclMutedParts,bool inclMutedTracks,bool inclOffTracks) const1712 int MidiPort::getVisibleCtrl(int ch, unsigned int tick, int ctrl, bool inclMutedParts, bool inclMutedTracks, bool inclOffTracks) const
1713 {
1714 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1715 if (cl == _controller->end())
1716 return CTRL_VAL_UNKNOWN;
1717
1718 return cl->second->visibleValue(tick, inclMutedParts, inclMutedTracks, inclOffTracks);
1719 }
1720
getVisibleCtrl(int ch,unsigned int tick,int ctrl,Part * part,bool inclMutedParts,bool inclMutedTracks,bool inclOffTracks) const1721 int MidiPort::getVisibleCtrl(int ch, unsigned int tick, int ctrl, Part* part, bool inclMutedParts, bool inclMutedTracks, bool inclOffTracks) const
1722 {
1723 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1724 if (cl == _controller->end())
1725 return CTRL_VAL_UNKNOWN;
1726
1727 return cl->second->visibleValue(tick, part, inclMutedParts, inclMutedTracks, inclOffTracks);
1728 }
1729
1730 //---------------------------------------------------------
1731 // deleteController
1732 //---------------------------------------------------------
1733
deleteController(int ch,unsigned int tick,int ctrl,int val,Part * part)1734 void MidiPort::deleteController(int ch, unsigned int tick, int ctrl, int val, Part* part)
1735 {
1736 iMidiCtrlValList cl = _controller->find(ch, ctrl);
1737 if (cl == _controller->end()) {
1738 if (MusEGlobal::debugMsg)
1739 printf("deleteController: controller %d(0x%x) for channel %d not found size %zd\n",
1740 ctrl, ctrl, ch, _controller->size());
1741 return;
1742 }
1743
1744 cl->second->delMCtlVal(tick, part, val);
1745 }
1746
1747 //---------------------------------------------------------
1748 // midiController
1749 //---------------------------------------------------------
1750
midiController(int num,int chan,bool createIfNotFound) const1751 MidiController* MidiPort::midiController(int num, int chan, bool createIfNotFound) const
1752 {
1753 MidiController* mc = nullptr;
1754
1755 // Search the instrument's controller lists (including midnam controllers).
1756 if (_instrument) {
1757 const int patch = hwCtrlState(chan, CTRL_PROGRAM);
1758 mc = _instrument->findController(num, chan, patch);
1759 if(mc)
1760 return mc;
1761 }
1762
1763 // Search the global default controller list.
1764 mc = defaultMidiController.findController(num);
1765 if(mc)
1766 return mc;
1767
1768 if(!createIfNotFound)
1769 return nullptr;
1770
1771 const QString name = midiCtrlName(num);
1772 int min = 0;
1773 int max = 127;
1774
1775 MidiController::ControllerType t = midiControllerType(num);
1776 switch (t) {
1777 case MidiController::RPN:
1778 case MidiController::NRPN:
1779 case MidiController::Controller7:
1780 case MidiController::PolyAftertouch:
1781 case MidiController::Aftertouch:
1782 max = 127;
1783 break;
1784 case MidiController::Controller14:
1785 case MidiController::RPN14:
1786 case MidiController::NRPN14:
1787 max = 16383;
1788 break;
1789 case MidiController::Program:
1790 max = 0xffffff;
1791 break;
1792 case MidiController::Pitch:
1793 max = 8191;
1794 min = -8192;
1795 break;
1796 case MidiController::Velo: // cannot happen
1797 return nullptr;
1798 break;
1799 }
1800 mc = new MidiController(name, num, min, max, 0, 0);
1801 defaultMidiController.add(mc);
1802 return mc;
1803 }
1804
1805 //---------------------------------------------------------
1806 // drumController
1807 // Returns instrument drum controller if ctl is a drum controller number.
1808 // Otherwise returns zero.
1809 // NOTE: Midnam apparently has no concept of drum controllers, so the fact
1810 // that this only asks in the instrument's controllers and not the midnam is OK.
1811 //---------------------------------------------------------
1812
drumController(int ctl)1813 MidiController* MidiPort::drumController(int ctl)
1814 {
1815 if(!_instrument)
1816 return nullptr;
1817 MidiControllerList* cl = _instrument->controller();
1818 if(!cl)
1819 return nullptr;
1820 return cl->perNoteController(ctl);
1821 }
1822
1823 //---------------------------------------------------------
1824 // writeRouting
1825 //---------------------------------------------------------
1826
writeRouting(int level,Xml & xml) const1827 void MidiPort::writeRouting(int level, Xml& xml) const
1828 {
1829 // If this device is not actually in use by the song, do not write any routes.
1830 // This prevents bogus routes from being saved and propagated in the med file.
1831 // p4.0.17 Reverted. Allow ports with no device to save.
1832 //if(!device())
1833 // return;
1834
1835 QString s;
1836
1837 for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
1838 {
1839 if(r->type == Route::TRACK_ROUTE && r->track)
1840 {
1841 // Ignore Midi Port to Audio Input routes. Handled by Track route writer. p4.0.14 Tim.
1842 if(r->track->type() == Track::AUDIO_INPUT)
1843 continue;
1844
1845 s = "Route";
1846 if(r->channel != -1)
1847 s += QString(" channel=\"%1\"").arg(r->channel);
1848 xml.tag(level++, s.toLatin1().constData());
1849
1850 xml.tag(level, "source mport=\"%d\"/", portno());
1851
1852 s = "dest";
1853 s += QString(" track=\"%1\"/").arg(MusEGlobal::song->tracks()->index(r->track));
1854 xml.tag(level, s.toLatin1().constData());
1855
1856 xml.etag(level--, "Route");
1857 }
1858 }
1859 }
1860
1861 // p4.0.17 Turn off if and when multiple output routes supported.
1862 #if 1
1863 //---------------------------------------------------------
1864 // setPortExclusiveDefOutChan
1865 //---------------------------------------------------------
1866
setPortExclusiveDefOutChan(int port,int c)1867 void setPortExclusiveDefOutChan(int port, int c)
1868 {
1869 if(port < 0 || port >= MusECore::MIDI_PORTS)
1870 return;
1871 MusEGlobal::midiPorts[port].setDefaultOutChannels(c);
1872 for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
1873 if(i != port)
1874 MusEGlobal::midiPorts[i].setDefaultOutChannels(0);
1875 }
1876 #endif
1877
1878 } // namespace MusECore
1879