1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: route.cpp,v 1.18.2.3 2008/05/21 00:28:52 terminator356 Exp $
5 //
6 // (C) Copyright 2003-2004 Werner Schweer (ws@seh.de)
7 // (C) Copyright 2011, 2015 Tim E. Real (terminator356 on sourceforge)
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 <QWidget>
26 #include <QPixmap>
27
28 #include "song.h"
29 #include "route.h"
30 #include "audio.h"
31 #include "track.h"
32 #include "synth.h"
33 #include "audiodev.h"
34 #include "xml.h"
35 #include "mididev.h"
36 #include "midiport.h"
37 #include "icons.h"
38 #include "driver/jackmidi.h"
39 #include "driver/alsamidi.h"
40 #include "strntcpy.h"
41 #include "globals.h"
42
43 //#define ROUTE_DEBUG
44
45 // Undefine if and when multiple output routes are added to midi tracks.
46 #define _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
47
48 namespace MusECore {
49
50 const QString ROUTE_MIDIPORT_NAME_PREFIX = "MusE MidiPort ";
51
52 //---------------------------------------------------------
53 // Route
54 //---------------------------------------------------------
55
Route(void * t,int ch)56 Route::Route(void* t, int ch)
57 {
58 jackPort = t;
59 persistentJackPortName[0] = 0;
60 if(MusEGlobal::checkAudioDevice())
61 MusEGlobal::audioDevice->portName(jackPort, persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
62
63 midiPort = -1;
64 channel = ch;
65 channels = -1;
66 remoteChannel = -1;
67 type = JACK_ROUTE;
68 }
69
Route(Track * t,int ch,int chans)70 Route::Route(Track* t, int ch, int chans)
71 {
72 track = t;
73 midiPort = -1;
74 channel = ch;
75 channels = chans;
76 remoteChannel = -1;
77 type = TRACK_ROUTE;
78 persistentJackPortName[0] = 0;
79 }
80
Route(MidiDevice * d,int ch)81 Route::Route(MidiDevice* d, int ch)
82 {
83 device = d;
84 midiPort = -1;
85 channel = ch;
86 channels = -1;
87 remoteChannel = -1;
88 type = MIDI_DEVICE_ROUTE;
89 persistentJackPortName[0] = 0;
90 }
91
Route(int port,int ch)92 Route::Route(int port, int ch)
93 {
94 track = 0;
95 midiPort = port;
96 channel = ch;
97 channels = -1;
98 remoteChannel = -1;
99 type = MIDI_PORT_ROUTE;
100 persistentJackPortName[0] = 0;
101 }
102
Route(const QString & s,bool dst,int ch,int rtype)103 Route::Route(const QString& s, bool dst, int ch, int rtype)
104 {
105 Route node(name2route(s, dst, rtype));
106 channel = node.channel;
107 if(channel == -1)
108 channel = ch;
109 channels = node.channels;
110 remoteChannel = node.remoteChannel;
111 type = node.type;
112 persistentJackPortName[0] = 0;
113 if(type == TRACK_ROUTE)
114 {
115 track = node.track;
116 midiPort = -1;
117 }
118 else
119 if(type == JACK_ROUTE)
120 {
121 jackPort = node.jackPort;
122 char* res = 0;
123 if(jackPort && MusEGlobal::checkAudioDevice())
124 res = MusEGlobal::audioDevice->portName(jackPort, persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
125 if(!res)
126 MusELib::strntcpy(persistentJackPortName, s.toLatin1().constData(), ROUTE_PERSISTENT_NAME_SIZE);
127 midiPort = -1;
128 }
129 else
130 if(type == MIDI_DEVICE_ROUTE)
131 {
132 device = node.device;
133 midiPort = -1;
134 }
135 else
136 if(type == MIDI_PORT_ROUTE)
137 {
138 track = 0;
139 midiPort = node.midiPort;
140 }
141 }
142
143
Route()144 Route::Route()
145 {
146 track = 0;
147 midiPort = -1;
148 channel = -1;
149 channels = -1;
150 remoteChannel = -1;
151 type = TRACK_ROUTE;
152 persistentJackPortName[0] = 0;
153 }
154
Route(RouteType type_,int midi_port_num_,void * void_pointer_,int channel_,int channels_,int remote_channel_,const char * name_)155 Route::Route(RouteType type_, int midi_port_num_, void* void_pointer_, int channel_, int channels_, int remote_channel_, const char* name_)
156 {
157 type = type_;
158 midiPort = midi_port_num_;
159 voidPointer = void_pointer_;
160 channel = channel_;
161 channels = channels_;
162 remoteChannel = remote_channel_;
163 persistentJackPortName[0] = 0;
164 MusELib::strntcpy(persistentJackPortName, name_, ROUTE_PERSISTENT_NAME_SIZE);
165 }
166
Route(const Route & a)167 Route::Route(const Route& a)
168 {
169 type = a.type;
170 midiPort = a.midiPort;
171 voidPointer = a.voidPointer;
172 channel = a.channel;
173 channels = a.channels;
174 remoteChannel = a.remoteChannel;
175 persistentJackPortName[0] = 0;
176 strcpy(persistentJackPortName, a.persistentJackPortName);
177 }
178
operator =(const Route & a)179 Route& Route::operator=(const Route& a)
180 {
181 type = a.type;
182 midiPort = a.midiPort;
183 voidPointer = a.voidPointer;
184 channel = a.channel;
185 channels = a.channels;
186 remoteChannel = a.remoteChannel;
187 persistentJackPortName[0] = 0;
188 strcpy(persistentJackPortName, a.persistentJackPortName);
189 return *this;
190 }
191
192 //---------------------------------------------------------
193 // addRoute
194 //---------------------------------------------------------
195
addRoute(Route src,Route dst)196 bool addRoute(Route src, Route dst)
197 {
198 #ifdef ROUTE_DEBUG
199 fprintf(stderr, "addRoute:\n");
200 #endif
201
202 if (!src.isValid() || !dst.isValid())
203 {
204 if(!src.isValid())
205 fprintf(stderr, "addRoute: invalid src\n");
206 if(!dst.isValid())
207 fprintf(stderr, "addRoute: invalid dst\n");
208 return false;
209 }
210
211 // fprintf(stderr, "addRoute %d.%d:<%s> %d.%d:<%s>\n",
212 // src.type, src.channel, src.name().toLatin1().constData(),
213 // dst.type, dst.channel, dst.name().toLatin1().constData());
214 if (src.type == Route::JACK_ROUTE)
215 {
216 if (dst.type == Route::TRACK_ROUTE)
217 {
218 if (dst.track->type() != Track::AUDIO_INPUT)
219 {
220 fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().toLatin1().constData());
221 return false;
222 }
223 if (dst.channel < 0)
224 {
225 fprintf(stderr, "addRoute: source is jack, dest:%s is track but invalid channel:%d\n", dst.track->name().toLatin1().constData(), dst.channel);
226 return false;
227 }
228
229 src.channel = dst.channel;
230
231 if(dst.track->inRoutes()->contains(src))
232 {
233 fprintf(stderr, "addRoute: src track route already exists.\n");
234 return false;
235 }
236
237 #ifdef ROUTE_DEBUG
238 fprintf(stderr, "addRoute: src Jack dst track name: %s pushing source route\n", dst.track->name().toLatin1().constData());
239 #endif
240
241 dst.track->inRoutes()->push_back(src);
242
243 return true;
244 }
245 else if (dst.type == Route::MIDI_DEVICE_ROUTE)
246 {
247 if(dst.device->deviceType() == MidiDevice::JACK_MIDI)
248 {
249 src.channel = dst.channel;
250
251 if(dst.device->inRoutes()->contains(src))
252 {
253 fprintf(stderr, "addRoute: src Jack midi route already exists.\n");
254 return false;
255 }
256
257 #ifdef ROUTE_DEBUG
258 fprintf(stderr, "addRoute: src Jack dst Jack midi name: %s pushing source route\n", dst.device->name().toLatin1().constData());
259 #endif
260
261 dst.device->inRoutes()->push_back(src);
262
263 return true;
264 }
265 else
266 {
267 fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType());
268 return false;
269 }
270 }
271 else if(dst.type == Route::JACK_ROUTE)
272 {
273 // Do nothing - it's a direct Jack connection!
274 return false;
275 }
276 else
277 {
278 fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type);
279 return false;
280 }
281
282 return false;
283 }
284 else if (dst.type == Route::JACK_ROUTE)
285 {
286 if (src.type == Route::TRACK_ROUTE)
287 {
288 if (src.track->type() != Track::AUDIO_OUTPUT)
289 {
290 fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n");
291 return false;
292 }
293 if (src.channel < 0)
294 {
295 fprintf(stderr, "addRoute: destination is jack, source:%s is track but invalid channel:%d\n", src.track->name().toLatin1().constData(), src.channel);
296 return false;
297 }
298
299 dst.channel = src.channel;
300
301 if(src.track->outRoutes()->contains(dst))
302 {
303 fprintf(stderr, "addRoute: dst track route already exists.\n");
304 return false;
305 }
306
307 #ifdef ROUTE_DEBUG
308 fprintf(stderr, "addRoute: dst Jack src track name: %s pushing destination route\n", src.track->name().toLatin1().constData());
309 #endif
310
311 src.track->outRoutes()->push_back(dst);
312
313 return true;
314 }
315 else if (src.type == Route::MIDI_DEVICE_ROUTE)
316 {
317 if(src.device->deviceType() == MidiDevice::JACK_MIDI)
318 {
319 dst.channel = src.channel;
320
321 if(src.device->outRoutes()->contains(dst))
322 {
323 fprintf(stderr, "addRoute: dst Jack midi route already exists.\n");
324 return false;
325 }
326
327 #ifdef ROUTE_DEBUG
328 fprintf(stderr, "addRoute: dst Jack src Jack midi name: %s pushing destination route\n", src.device->name().toLatin1().constData());
329 #endif
330
331 if(src.device->midiPort() != -1)
332 // Initializations sysex etc. need to be sent to the new connection.
333 MusEGlobal::midiPorts[src.device->midiPort()].clearInitSent();
334 src.device->outRoutes()->push_back(dst);
335
336 return true;
337 }
338 else
339 {
340 fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType());
341 return false;
342 }
343
344 return false;
345 }
346 else if(src.type == Route::JACK_ROUTE)
347 {
348 // Do nothing - it's a direct Jack connection!
349 return false;
350 }
351 else
352 {
353 fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type);
354 return false;
355 }
356
357 return false;
358 }
359 else if(src.type == Route::MIDI_PORT_ROUTE)
360 {
361 if(dst.type != Route::TRACK_ROUTE || !dst.track->isMidiTrack())
362 {
363 fprintf(stderr, "addRoute: source is midi port:%d, but destination is not midi track\n", src.midiPort);
364 return false;
365 }
366 if(dst.channel < -1 || dst.channel >= MusECore::MUSE_MIDI_CHANNELS)
367 {
368 fprintf(stderr, "addRoute: source is midi port:%d, but destination track channel:%d out of range\n", src.midiPort, dst.channel);
369 return false;
370 }
371
372 MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort];
373
374 // Do not allow synth ports to connect to any track. It may be useful in some cases,
375 // may be desired later, but for now it's just a routing hassle. p4.0.35
376 //if(mp->device() && mp->device()->isSynti())
377 // return false;
378
379 bool ret1 = false;
380 bool ret2 = false;
381 src.channel = dst.channel;
382 RouteList* rl;
383 rl = mp->outRoutes();
384 if(!rl->contains(dst))
385 {
386 rl->push_back(dst);
387 ret1 = true;
388 }
389 rl = dst.track->inRoutes();
390 if(!rl->contains(src))
391 {
392 rl->push_back(src);
393 ret2 = true;
394 }
395
396 return ret1 || ret2;
397 }
398 else if(dst.type == Route::MIDI_PORT_ROUTE)
399 {
400
401 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
402 fprintf(stderr, "addRoute: destination is midi port:%d, but source is not allowed\n", dst.midiPort);
403 return false;
404 #else
405
406 if(src.type != Route::TRACK_ROUTE || !src.track->isMidiTrack())
407 {
408 fprintf(stderr, "addRoute: destination is midi port:%d, but source is not midi track\n", dst.midiPort);
409 return false;
410 }
411 if(src.channel < -1 || src.channel >= MusECore::MUSE_MIDI_CHANNELS)
412 {
413 fprintf(stderr, "addRoute: destination is midi port:%d, but source track channel:%d out of range\n", dst.midiPort, src.channel);
414 return false;
415 }
416
417 bool ret1 = false;
418 bool ret2 = false;
419 dst.channel = src.channel;
420 RouteList* rl;
421 rl = src.track->outRoutes();
422 if(!rl->contains(dst))
423 {
424 rl->push_back(dst);
425 ret1 = true;
426 }
427 rl = MusEGlobal::midiPorts[dst.midiPort].inRoutes();
428 if(!rl->contains(src))
429 {
430 rl->push_back(src);
431 ret2 = true;
432 }
433
434 return ret1 || ret2;
435 #endif
436 }
437 else
438 {
439 if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)
440 {
441 fprintf(stderr, "addRoute: source or destination are not track routes\n");
442 return false;
443 }
444
445 RouteList* outRoutes = src.track->outRoutes();
446 if((src.channel == -1 && dst.channel != -1) || (dst.channel == -1 && src.channel != -1))
447 {
448 fprintf(stderr, "addRoute: source and destination are track routes but channels incompatible: src:%d dst:%d\n", src.channel, dst.channel);
449 return false;
450 }
451
452 // Don't bother checking valid channel ranges, to support persistent routes...
453
454 if(src.channels != dst.channels)
455 {
456 fprintf(stderr, "addRoute: source and destination are track routes but number of channels incompatible: src:%d dst:%d\n", src.channels, dst.channels);
457 return false;
458 }
459
460 // Ex. Params: src: TrackA, Channel 2, Remote Channel -1 dst: TrackB channel 4 Remote Channel -1
461 // After: src TrackA, Channel 4, Remote Channel 2 dst: TrackB channel 2 Remote Channel 4
462 //
463 // Ex. (Handled above, not used here. For example only.)
464 // Params: src: TrackA, Channel 2, Remote Channel -1 dst: JackAA channel -1 Remote Channel -1
465 // After: (src TrackA, Channel -1, Remote Channel 2) dst: JackAA channel 2 Remote Channel -1
466 src.remoteChannel = src.channel;
467 dst.remoteChannel = dst.channel;
468 const int src_chan = src.channel;
469 src.channel = dst.channel;
470 dst.channel = src_chan;
471
472 #ifdef ROUTE_DEBUG
473 fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n",
474 src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData());
475 #endif
476
477 const bool o_found = outRoutes->contains(dst);
478 if(o_found)
479 fprintf(stderr, "addRoute: dst track route already exists in src track out routes list. Ignoring.\n");
480 else
481 outRoutes->push_back(dst);
482
483 RouteList* inRoutes = dst.track->inRoutes();
484 const bool i_found = inRoutes->contains(src);
485 if(i_found)
486 fprintf(stderr, "addRoute: src track route already exists in dst track out routes list. Ignoring.\n");
487 else
488 {
489 // make sure AUDIO_AUX is processed last
490 if(src.track->type() == Track::AUDIO_AUX) // REMOVE Tim. Or not? This special aux code may not be useful or needed now. TBD
491 inRoutes->push_back(src);
492 else
493 inRoutes->insert(inRoutes->begin(), src);
494 }
495
496 // Only if a route was established:
497 if(!o_found || !i_found)
498 {
499 // Is the source an Aux Track or else does it have Aux Tracks routed to it?
500 // Update the destination track's aux ref count, and all tracks it is routed to.
501 if(src.track->auxRefCount())
502 src.track->updateAuxRoute( src.track->auxRefCount(), dst.track );
503 else
504 if(src.track->type() == Track::AUDIO_AUX)
505 src.track->updateAuxRoute( 1, dst.track );
506
507 return true;
508 }
509
510 return false;
511 }
512
513 return false;
514 }
515
516 //---------------------------------------------------------
517 // removeRoute
518 //---------------------------------------------------------
519
removeRoute(Route src,Route dst)520 bool removeRoute(Route src, Route dst)
521 {
522 if(src.type == Route::JACK_ROUTE)
523 {
524 if(dst.isValid())
525 {
526 switch(dst.type)
527 {
528 case Route::TRACK_ROUTE:
529 src.channel = dst.channel;
530 return dst.track->inRoutes()->removeRoute(src);
531 break;
532 case Route::MIDI_DEVICE_ROUTE:
533 return dst.device->inRoutes()->removeRoute(src);
534 break;
535 case Route::MIDI_PORT_ROUTE:
536 return MusEGlobal::midiPorts[dst.midiPort].inRoutes()->removeRoute(src);
537 break;
538 case Route::JACK_ROUTE:
539 // Do nothing - it's a direct Jack disconnection!
540 return false;
541 break;
542 }
543 }
544 return false;
545
546 }
547 else if(dst.type == Route::JACK_ROUTE)
548 {
549 if(src.isValid())
550 {
551 switch(src.type)
552 {
553 case Route::TRACK_ROUTE:
554 dst.channel = src.channel;
555 return src.track->outRoutes()->removeRoute(dst);
556 break;
557 case Route::MIDI_DEVICE_ROUTE:
558 return src.device->outRoutes()->removeRoute(dst);
559 break;
560 case Route::MIDI_PORT_ROUTE:
561 return MusEGlobal::midiPorts[src.midiPort].outRoutes()->removeRoute(dst);
562 break;
563 case Route::JACK_ROUTE:
564 // Do nothing - it's a direct Jack disconnection!
565 return false;
566 break;
567 }
568 }
569 return false;
570
571 }
572 else if(src.type == Route::MIDI_PORT_ROUTE)
573 {
574 bool ret1 = false;
575 bool ret2 = false;
576 if(src.isValid())
577 ret1 = MusEGlobal::midiPorts[src.midiPort].outRoutes()->removeRoute(dst);
578 if(dst.isValid())
579 {
580 switch(dst.type)
581 {
582 case Route::TRACK_ROUTE:
583 ret2 = dst.track->inRoutes()->removeRoute(src);
584 break;
585 case Route::MIDI_DEVICE_ROUTE:
586 ret2 = dst.device->inRoutes()->removeRoute(src);
587 break;
588 case Route::MIDI_PORT_ROUTE:
589 ret2 = MusEGlobal::midiPorts[dst.midiPort].inRoutes()->removeRoute(src);
590 break;
591 case Route::JACK_ROUTE:
592 ret2 = false;
593 break;
594 }
595 }
596 return ret1 || ret2;
597 }
598 else if(dst.type == Route::MIDI_PORT_ROUTE)
599 {
600 bool ret1 = false;
601 bool ret2 = false;
602 if(src.isValid())
603 {
604 switch(src.type)
605 {
606 case Route::TRACK_ROUTE:
607 ret2 = src.track->outRoutes()->removeRoute(dst);
608 break;
609 case Route::MIDI_DEVICE_ROUTE:
610 ret2 = src.device->outRoutes()->removeRoute(dst);
611 break;
612 case Route::MIDI_PORT_ROUTE:
613 ret2 = MusEGlobal::midiPorts[src.midiPort].outRoutes()->removeRoute(dst);
614 break;
615 case Route::JACK_ROUTE:
616 ret2 = false;
617 break;
618 }
619 }
620
621 if(dst.isValid())
622 ret1 = MusEGlobal::midiPorts[dst.midiPort].inRoutes()->removeRoute(src);
623
624 return ret1 || ret2;
625 }
626 else
627 {
628 if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)
629 {
630 fprintf(stderr, "removeRoute: source and destination are not tracks\n");
631 return false;
632 }
633
634 // Ex. Params: src: TrackA, Channel 2, Remote Channel -1 dst: TrackB channel 4 Remote Channel -1
635 // After: src TrackA, Channel 4, Remote Channel 2 dst: TrackB channel 2 Remote Channel 4
636 //
637 // Ex. (Handled above, not used here. For example only.)
638 // Params: src: TrackA, Channel 2, Remote Channel -1 dst: JackAA channel -1 Remote Channel -1
639 // After: (src TrackA, Channel -1, Remote Channel 2) dst: JackAA channel 2 Remote Channel -1
640 src.remoteChannel = src.channel;
641 dst.remoteChannel = dst.channel;
642 const int src_chan = src.channel;
643 src.channel = dst.channel;
644 dst.channel = src_chan;
645
646 // Is the source an Aux Track or else does it have Aux Tracks routed to it?
647 // Update the destination track's aux ref count, and all tracks it is routed to.
648 if(src.isValid() && dst.isValid() && src.track->outRoutes()->contains(dst) && dst.track->inRoutes()->contains(src))
649 {
650 if(src.track->auxRefCount())
651 src.track->updateAuxRoute( -src.track->auxRefCount(), dst.track );
652 else
653 if(src.track->type() == Track::AUDIO_AUX)
654 src.track->updateAuxRoute( -1, dst.track );
655 }
656
657 bool ret1 = false;
658 bool ret2 = false;
659
660 if(src.isValid())
661 {
662 RouteList* o_rl = src.track->outRoutes();
663 MusECore::iRoute o_ir = o_rl->find(dst);
664 if(o_ir != o_rl->end())
665 {
666 o_rl->erase(o_ir);
667 ret1 = true;
668 }
669 }
670 else
671 fprintf(stderr, "removeRoute: source is track but invalid\n");
672
673 if(dst.isValid())
674 {
675 RouteList* i_rl = dst.track->inRoutes();
676 MusECore::iRoute i_ir = i_rl->find(src);
677 if(i_ir != i_rl->end())
678 {
679 i_rl->erase(i_ir);
680 ret2 = true;
681 }
682 }
683 else
684 fprintf(stderr, "removeRoute: destination is track but invalid\n");
685
686 return ret1 || ret2;
687 }
688
689 return false;
690 }
691
692 //---------------------------------------------------------
693 // removeAllRoutes
694 // If src is valid, disconnects all output routes from it.
695 // If dst is valid, disconnects all input routes to it.
696 // src and dst Route are used SIMPLY because Route provides convenient way to
697 // specify the different pointer types (track, port, jack)
698 // This routine will ONLY look at the pointer, not the channel or port etc...
699 // So far it only works with MidiDevice <-> Jack.
700 //---------------------------------------------------------
701
removeAllRoutes(Route src,Route dst)702 void removeAllRoutes(Route src, Route dst)
703 {
704 // TODO: Is the source an Aux Track or else does it have Aux Tracks routed to it?
705 // Update the destination track's aux ref count, and all tracks it is routed to.
706 /* if(src.isValid() && dst.isValid()) DELETETHIS 8
707 {
708 if(src.track->auxRefCount())
709 dst.track->updateAuxStates( -src.track->auxRefCount() );
710 else
711 if(src.track->type() == Track::TrackType::AUDIO_AUX))
712 dst.track->updateAuxStates( -1 );
713 } */
714
715 if(src.isValid())
716 {
717 if(src.type == Route::MIDI_DEVICE_ROUTE)
718 src.device->outRoutes()->clear();
719 else
720 fprintf(stderr, "removeAllRoutes: source is not midi device\n");
721 }
722
723 if(dst.isValid())
724 {
725 if(dst.type == Route::MIDI_DEVICE_ROUTE)
726 dst.device->inRoutes()->clear();
727 else
728 fprintf(stderr, "removeAllRoutes: dest is not midi device\n");
729 }
730 }
731
732 //---------------------------------------------------------
733 // track2name
734 // create string name representation for audio node
735 //---------------------------------------------------------
736
track2name(const Track * n)737 static QString track2name(const Track* n)
738 {
739 if (n == nullptr)
740 return QWidget::tr("None");
741 return n->name();
742 }
743
744 //---------------------------------------------------------
745 // icon
746 //---------------------------------------------------------
747
748
icon(bool isSource,bool isMidi) const749 QIcon* Route::icon(bool isSource, bool isMidi) const
750 {
751 switch(type)
752 {
753 case TRACK_ROUTE:
754 if(track)
755 return track->icon();
756 break;
757
758 case JACK_ROUTE:
759 if(isMidi)
760 return isSource ? MusEGui::routeInMidiSVGIcon : MusEGui::routeOutMidiSVGIcon;
761 else
762 return isSource ? MusEGui::routeInSVGIcon : MusEGui::routeOutSVGIcon;
763
764 case MIDI_DEVICE_ROUTE:
765 return MusEGui::midiInSVGIcon;
766 // break;
767
768 case MIDI_PORT_ROUTE:
769 return MusEGui::midiPortSVGIcon;
770 }
771 return nullptr;
772 }
773
774 //---------------------------------------------------------
775 // name
776 // create string name representation for audio node
777 //---------------------------------------------------------
778
name(int preferred_name_or_alias) const779 QString Route::name(int preferred_name_or_alias) const
780 {
781 if(type == MIDI_DEVICE_ROUTE)
782 {
783 if(device)
784 return device->name();
785 return QWidget::tr("None");
786 }
787 else
788 if(type == JACK_ROUTE)
789 {
790 if(MusEGlobal::checkAudioDevice() && jackPort)
791 {
792 char s[ROUTE_PERSISTENT_NAME_SIZE];
793 return QString(MusEGlobal::audioDevice->portName(jackPort, s, ROUTE_PERSISTENT_NAME_SIZE, preferred_name_or_alias));
794 }
795 return QString(persistentJackPortName);
796
797 }
798 else
799 if(type == MIDI_PORT_ROUTE)
800 {
801 return ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort);
802 }
803 else
804 return track2name(track);
805 }
806
807 //---------------------------------------------------------
808 // name
809 // fill and return str char name representation for audio node
810 //---------------------------------------------------------
name(char * str,int str_size,int preferred_name_or_alias) const811 char* Route::name(char* str, int str_size, int preferred_name_or_alias) const
812 {
813 if(type == MIDI_DEVICE_ROUTE)
814 return MusELib::strntcpy(str, device ? device->name().toLatin1().constData() : 0, str_size);
815 else
816 if(type == JACK_ROUTE)
817 {
818 if(MusEGlobal::checkAudioDevice() && jackPort)
819 return MusEGlobal::audioDevice->portName(jackPort, str, str_size, preferred_name_or_alias);
820 return MusELib::strntcpy(str, persistentJackPortName, str_size);
821 }
822 else
823 if(type == MIDI_PORT_ROUTE)
824 {
825 return MusELib::strntcpy(str, (ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort)).toLatin1().constData(), str_size);
826 }
827 else
828 return MusELib::strntcpy(str, track ? track->name().toLatin1().constData() : 0, str_size);
829
830 }
831
832 //---------------------------------------------------------
833 // displayName
834 // create string name representation for audio node
835 //---------------------------------------------------------
836
displayName(int preferred_name_or_alias) const837 QString Route::displayName(int preferred_name_or_alias) const
838 {
839 if(type == MIDI_DEVICE_ROUTE)
840 {
841 if(device)
842 return device->name();
843 return QWidget::tr("None");
844 }
845 else
846 if(type == JACK_ROUTE)
847 {
848 if(MusEGlobal::checkAudioDevice() && jackPort)
849 {
850 char s[ROUTE_PERSISTENT_NAME_SIZE];
851 return QString(MusEGlobal::audioDevice->portName(jackPort, s, ROUTE_PERSISTENT_NAME_SIZE, preferred_name_or_alias));
852 }
853 return QString(persistentJackPortName);
854
855 }
856 else
857 if(type == MIDI_PORT_ROUTE)
858 {
859 return ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort);
860 }
861 else
862 return QString("%1:%2").arg(MusEGlobal::song->tracks()->index(track) + 1).arg(track2name(track));
863 }
864
865 //---------------------------------------------------------
866 // name2route
867 //---------------------------------------------------------
868
name2route(const QString & rn,bool,int rtype)869 Route name2route(const QString& rn, bool /*dst*/, int rtype)
870 {
871 int channel = -1;
872 QString s(rn);
873 // Support old route style in med files. Obsolete.
874 if (rn[0].isNumber() && rn[1]==':')
875 {
876 channel = rn[0].toLatin1() - int('1');
877 s = rn.mid(2);
878 }
879
880 if(rtype == -1)
881 {
882 if(MusEGlobal::checkAudioDevice())
883 {
884 void* p = MusEGlobal::audioDevice->findPort(s.toLatin1().constData());
885 if(p)
886 return Route(p, channel);
887 }
888
889 TrackList* tl = MusEGlobal::song->tracks();
890 for(iTrack i = tl->begin(); i != tl->end(); ++i)
891 {
892 if((*i)->isMidiTrack())
893 {
894 MidiTrack* track = (MidiTrack*)*i;
895 if(track->name() == s)
896 return Route(track, channel);
897 }
898 else
899 {
900 AudioTrack* track = (AudioTrack*)*i;
901 if(track->name() == s)
902 return Route(track, channel);
903 }
904 }
905
906 for(iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)
907 {
908 if((*i)->name() == s)
909 return Route(*i, channel);
910 }
911
912 if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)
913 {
914 bool ok = false;
915 int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok);
916 if(ok)
917 return Route(port, channel);
918 }
919 }
920 else
921 {
922 if(rtype == Route::TRACK_ROUTE)
923 {
924 TrackList* tl = MusEGlobal::song->tracks();
925 for(iTrack i = tl->begin(); i != tl->end(); ++i)
926 {
927 if((*i)->isMidiTrack())
928 {
929 MidiTrack* track = (MidiTrack*)*i;
930 if(track->name() == s)
931 return Route(track, channel);
932 }
933 else
934 {
935 AudioTrack* track = (AudioTrack*)*i;
936 if(track->name() == s)
937 return Route(track, channel);
938 }
939 }
940 return Route((Track*) 0, channel);
941 }
942 else
943 // TODO Distinguish the device types
944 if(rtype == Route::MIDI_DEVICE_ROUTE)
945 {
946 for(iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)
947 {
948 if((*i)->name() == s)
949 return Route(*i, channel);
950 }
951 return Route((MidiDevice*) 0, channel);
952 }
953 else
954 if(rtype == Route::JACK_ROUTE)
955 {
956 if(MusEGlobal::checkAudioDevice())
957 {
958 // REMOVE Tim. Persistent routes. TODO FIXME: Use new cached jack port names.
959 void* p = MusEGlobal::audioDevice->findPort(s.toLatin1().constData());
960 if(p)
961 return Route(p, channel);
962 }
963 return Route((void*) 0, channel);
964 }
965 else
966 if(rtype == Route::MIDI_PORT_ROUTE)
967 {
968 if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)
969 {
970 bool ok = false;
971 int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok);
972 if(ok)
973 return Route(port, channel);
974 }
975 return Route((int) 0, channel);
976 }
977 }
978
979 fprintf(stderr, " name2route: <%s> not found\n", rn.toLatin1().constData());
980 return Route((Track*) 0, channel);
981 }
982
983 //---------------------------------------------------------
984 // routeCanConnect
985 //---------------------------------------------------------
986
routeCanConnect(const Route & src,const Route & dst)987 bool routeCanConnect(const Route& src, const Route& dst)
988 {
989 if(!src.isValid() || !dst.isValid())
990 return false;
991
992 if(src.type == Route::JACK_ROUTE)
993 {
994 if(!MusEGlobal::checkAudioDevice() ||
995 !src.jackPort ||
996 MusEGlobal::audioDevice->portDirection(src.jackPort) != MusECore::AudioDevice::OutputPort)
997 return false;
998
999 if(dst.type == Route::TRACK_ROUTE)
1000 {
1001 if(MusEGlobal::audioDevice->portType(src.jackPort) != MusECore::AudioDevice::AudioPort ||
1002 dst.track->type() != Track::AUDIO_INPUT ||
1003 dst.channel < 0)
1004 return false;
1005 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, src.channel, src.persistentJackPortName);
1006 return !dst.track->inRoutes()->contains(v_src);
1007 }
1008 else if(dst.type == Route::MIDI_DEVICE_ROUTE)
1009 {
1010 if(MusEGlobal::audioDevice->portType(src.jackPort) != MusECore::AudioDevice::MidiPort ||
1011 dst.device->deviceType() != MidiDevice::JACK_MIDI)
1012 return false;
1013 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, src.channel, src.persistentJackPortName);
1014 return !dst.device->inRoutes()->contains(v_src);
1015 }
1016 else if(dst.type == Route::JACK_ROUTE)
1017 {
1018 // Allow direct Jack connections!
1019 return MusEGlobal::audioDevice && MusEGlobal::audioDevice->portsCanConnect(src.jackPort, dst.jackPort);
1020 }
1021 else
1022 return false;
1023 }
1024 else if(dst.type == Route::JACK_ROUTE)
1025 {
1026 if(!MusEGlobal::checkAudioDevice() ||
1027 !dst.jackPort ||
1028 MusEGlobal::audioDevice->portDirection(dst.jackPort) != MusECore::AudioDevice::InputPort)
1029 return false;
1030
1031 if(src.type == Route::TRACK_ROUTE)
1032 {
1033 if(MusEGlobal::audioDevice->portType(dst.jackPort) != MusECore::AudioDevice::AudioPort ||
1034 src.track->type() != Track::AUDIO_OUTPUT || src.channel < 0)
1035 return false;
1036 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, -1, dst.persistentJackPortName);
1037 return !src.track->outRoutes()->contains(v_dst);
1038 }
1039 else
1040 if(src.type == Route::MIDI_DEVICE_ROUTE)
1041 {
1042 if(MusEGlobal::audioDevice->portType(dst.jackPort) != MusECore::AudioDevice::MidiPort ||
1043 src.device->deviceType() != MidiDevice::JACK_MIDI)
1044 return false;
1045 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, -1, dst.persistentJackPortName);
1046 return !src.device->outRoutes()->contains(v_dst);
1047 }
1048 else if(src.type == Route::JACK_ROUTE)
1049 {
1050 // Allow direct Jack connections!
1051 return MusEGlobal::audioDevice && MusEGlobal::audioDevice->portsCanConnect(src.jackPort, dst.jackPort);
1052 }
1053 else
1054 return false;
1055 }
1056 else if(src.type == Route::MIDI_PORT_ROUTE)
1057 {
1058 if(dst.type != Route::TRACK_ROUTE || !dst.track->isMidiTrack() || dst.channel < -1 || dst.channel >= MusECore::MUSE_MIDI_CHANNELS)
1059 return false;
1060
1061 //MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort];
1062
1063 // Do not allow synth ports to connect to any track. It may be useful in some cases,
1064 // may be desired later, but for now it's just a routing hassle. p4.0.35
1065 //if(mp->device() && mp->device()->isSynti())
1066 // return false;
1067
1068 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, src.channel, src.persistentJackPortName);
1069 // If one route node exists and one is missing, it's OK to reconnect, addRoute will take care of it.
1070 if(!MusEGlobal::midiPorts[src.midiPort].outRoutes()->contains(dst) || !dst.track->inRoutes()->contains(v_src))
1071 return true;
1072
1073 return false;
1074 }
1075 else if(dst.type == Route::MIDI_PORT_ROUTE)
1076 {
1077
1078 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1079 return false;
1080 #else
1081
1082 if(src.type != Route::TRACK_ROUTE || !src.track->isMidiTrack() || src.channel < -1 || src.channel >= MusECore::MUSE_MIDI_CHANNELS)
1083 return false;
1084 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, dst.channel, dst.persistentJackPortName);
1085
1086 // If one route node exists and one is missing, it's OK to reconnect, addRoute will take care of it.
1087 if(!src.track->outRoutes()->contains(v_dst) || !MusEGlobal::midiPorts[dst.midiPort].inRoutes()->contains(src))
1088 return true;
1089
1090 return false;
1091 #endif
1092 }
1093 else
1094 {
1095 if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)
1096 return false;
1097 if(src.track && dst.track && src.track == dst.track)
1098 return false;
1099
1100 switch(src.track->type())
1101 {
1102 case Track::MIDI:
1103 case Track::DRUM:
1104 switch(dst.track->type())
1105 {
1106 case Track::MIDI:
1107 case Track::DRUM:
1108 case Track::WAVE:
1109 case Track::AUDIO_OUTPUT:
1110 case Track::AUDIO_GROUP:
1111 case Track::AUDIO_AUX:
1112 case Track::AUDIO_SOFTSYNTH:
1113 return false;
1114
1115 case Track::AUDIO_INPUT:
1116 if(src.channel >= 0)
1117 return false;
1118 break;
1119 }
1120 break;
1121
1122
1123 case Track::AUDIO_OUTPUT:
1124 switch(dst.track->type())
1125 {
1126 case Track::MIDI:
1127 case Track::DRUM:
1128 case Track::WAVE:
1129 case Track::AUDIO_OUTPUT:
1130 case Track::AUDIO_GROUP:
1131 case Track::AUDIO_AUX:
1132 case Track::AUDIO_SOFTSYNTH:
1133 return false;
1134
1135 case Track::AUDIO_INPUT:
1136 if(src.channel >= 0 || dst.channel >= 0)
1137 return false;
1138 break;
1139 }
1140 break;
1141
1142 case Track::AUDIO_INPUT:
1143 switch(dst.track->type())
1144 {
1145 case Track::MIDI:
1146 case Track::DRUM:
1147 case Track::AUDIO_INPUT:
1148 case Track::AUDIO_AUX:
1149 return false;
1150
1151 case Track::WAVE:
1152 case Track::AUDIO_OUTPUT:
1153 case Track::AUDIO_GROUP:
1154 case Track::AUDIO_SOFTSYNTH:
1155 break;
1156 }
1157 break;
1158
1159 case Track::WAVE:
1160 switch(dst.track->type())
1161 {
1162 case Track::MIDI:
1163 case Track::DRUM:
1164 case Track::AUDIO_INPUT:
1165 case Track::AUDIO_AUX:
1166 return false;
1167
1168 case Track::WAVE:
1169 case Track::AUDIO_OUTPUT:
1170 case Track::AUDIO_GROUP:
1171 case Track::AUDIO_SOFTSYNTH:
1172 break;
1173 }
1174 break;
1175
1176 case Track::AUDIO_GROUP:
1177 switch(dst.track->type())
1178 {
1179 case Track::MIDI:
1180 case Track::DRUM:
1181 case Track::AUDIO_INPUT:
1182 case Track::AUDIO_AUX:
1183 return false;
1184
1185 case Track::WAVE:
1186 case Track::AUDIO_OUTPUT:
1187 case Track::AUDIO_GROUP:
1188 case Track::AUDIO_SOFTSYNTH:
1189 break;
1190 }
1191 break;
1192
1193 case Track::AUDIO_AUX:
1194 switch(dst.track->type())
1195 {
1196 case Track::MIDI:
1197 case Track::DRUM:
1198 case Track::AUDIO_INPUT:
1199 case Track::AUDIO_AUX:
1200 return false;
1201
1202 case Track::AUDIO_GROUP:
1203 case Track::WAVE:
1204 case Track::AUDIO_OUTPUT:
1205 case Track::AUDIO_SOFTSYNTH:
1206 break;
1207 }
1208 break;
1209
1210 case Track::AUDIO_SOFTSYNTH:
1211 switch(dst.track->type())
1212 {
1213 case Track::MIDI:
1214 case Track::DRUM:
1215 case Track::AUDIO_INPUT:
1216 case Track::AUDIO_AUX:
1217 return false;
1218
1219 case Track::AUDIO_GROUP:
1220 case Track::WAVE:
1221 case Track::AUDIO_OUTPUT:
1222 case Track::AUDIO_SOFTSYNTH:
1223 break;
1224 }
1225 break;
1226
1227 }
1228
1229 if((src.channel == -1 && dst.channel != -1) || (dst.channel == -1 && src.channel != -1))
1230 return false;
1231
1232 if(src.channels != dst.channels)
1233 return false;
1234
1235 // Allow for -1 = omni route.
1236 if(src.channel >= src.track->routeCapabilities()._trackChannels._outChannels ||
1237 dst.channel >= dst.track->routeCapabilities()._trackChannels._inChannels)
1238 return false;
1239
1240 if(src.track->isCircularRoute(dst.track))
1241 return false;
1242
1243 // Ex. Params: src: TrackA, Channel 2, Remote Channel -1 dst: TrackB channel 4 Remote Channel -1
1244 // After: src TrackA, Channel 4, Remote Channel 2 dst: TrackB channel 2 Remote Channel 4
1245 //
1246 // Ex. (Handled above, not used here. For example only.)
1247 // Params: src: TrackA, Channel 2, Remote Channel -1 dst: JackAA channel -1 Remote Channel -1
1248 // After: (src TrackA, Channel -1, Remote Channel 2) dst: JackAA channel 2 Remote Channel -1
1249 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, src.channel, src.persistentJackPortName);
1250 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, dst.channel, dst.persistentJackPortName);
1251
1252 // Allow it to reconnect a partial route.
1253 if(!v_src.isValid() || !v_dst.isValid() || (src.track->outRoutes()->contains(v_dst) && dst.track->inRoutes()->contains(v_src)))
1254 return false;
1255
1256 return true;
1257 }
1258 return false;
1259 }
1260
1261 //---------------------------------------------------------
1262 // routeCanDisconnect
1263 //---------------------------------------------------------
1264
routeCanDisconnect(const Route & src,const Route & dst)1265 bool routeCanDisconnect(const Route& src, const Route& dst)
1266 {
1267 if(src.type == Route::JACK_ROUTE)
1268 {
1269 //if(!dst.isValid())
1270 if(!dst.exists())
1271 return false;
1272
1273 if(dst.type == Route::TRACK_ROUTE)
1274 {
1275 if(dst.track->type() != Track::AUDIO_INPUT)
1276 return false;
1277 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, -1, src.persistentJackPortName);
1278 return dst.track->inRoutes()->contains(v_src);
1279 }
1280 else if(dst.type == Route::MIDI_DEVICE_ROUTE)
1281 {
1282 return dst.device->inRoutes()->contains(src);
1283 }
1284 else if(dst.type == Route::JACK_ROUTE)
1285 {
1286 // Allow direct Jack connections! Pass the port names here instead of ports so that
1287 // persistent routes (where jackPort = NULL) can be removed.
1288 return MusEGlobal::audioDevice && MusEGlobal::audioDevice->portsCanDisconnect(src.persistentJackPortName, dst.persistentJackPortName);
1289 }
1290 else
1291 return false;
1292 }
1293 else if(dst.type == Route::JACK_ROUTE)
1294 {
1295 if(!src.exists())
1296 return false;
1297
1298 if(src.type == Route::TRACK_ROUTE)
1299 {
1300 if(src.track->type() != Track::AUDIO_OUTPUT)
1301 return false;
1302 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, -1, dst.persistentJackPortName);
1303 return src.track->outRoutes()->contains(v_dst);
1304 }
1305 else if(src.type == Route::MIDI_DEVICE_ROUTE)
1306 {
1307 return src.device->outRoutes()->contains(dst);
1308 }
1309 else if(src.type == Route::JACK_ROUTE)
1310 {
1311 // Allow direct Jack disconnections! Pass the port names here instead of ports so that
1312 // persistent routes (where jackPort = NULL) can be removed.
1313 return MusEGlobal::audioDevice && MusEGlobal::audioDevice->portsCanDisconnect(src.persistentJackPortName, dst.persistentJackPortName);
1314 }
1315 else
1316 return false;
1317 }
1318 else if(src.type == Route::MIDI_PORT_ROUTE)
1319 {
1320 if(!src.isValid() || src.channel < -1 || src.channel >= MusECore::MUSE_MIDI_CHANNELS ||
1321 dst.type != Route::TRACK_ROUTE || !dst.exists() || !dst.track->isMidiTrack() || dst.channel < -1 || dst.channel >= MusECore::MUSE_MIDI_CHANNELS)
1322 return false;
1323
1324 // Allow it to disconnect a partial route.
1325 if(MusEGlobal::midiPorts[src.midiPort].outRoutes()->contains(dst) || dst.track->inRoutes()->contains(src))
1326 return true;
1327
1328 return false;
1329 }
1330 else if(dst.type == Route::MIDI_PORT_ROUTE)
1331 {
1332
1333 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1334 return false;
1335 #else
1336
1337 if(!dst.isValid() || dst.channel < -1 || dst.channel >= MusECore::MUSE_MIDI_CHANNELS ||
1338 src.type != Route::TRACK_ROUTE || !src.exists() || !src.track->isMidiTrack() || src.channel < -1 || src.channel >= MusECore::MUSE_MIDI_CHANNELS)
1339 return false;
1340
1341 // Allow it to disconnect a partial route.
1342 if(src.track->outRoutes()->contains(dst) || MusEGlobal::midiPorts[dst.midiPort].inRoutes()->contains(src))
1343 return true;
1344
1345 return false;
1346 #endif
1347 }
1348 else
1349 {
1350 if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)
1351 return false;
1352 if(src.track && dst.track && src.track == dst.track)
1353 return false;
1354
1355 // Ex. Params: src: TrackA, Channel 2, Remote Channel -1 dst: TrackB channel 4 Remote Channel -1
1356 // After: src TrackA, Channel 4, Remote Channel 2 dst: TrackB channel 2 Remote Channel 4
1357 //
1358 // Ex. (Handled above, not used here. For example only.)
1359 // Params: src: TrackA, Channel 2, Remote Channel -1 dst: JackAA channel -1 Remote Channel -1
1360 // After: (src TrackA, Channel -1, Remote Channel 2) dst: JackAA channel 2 Remote Channel -1
1361 const Route v_src(src.type, src.midiPort, src.voidPointer, dst.channel, src.channels, src.channel, src.persistentJackPortName);
1362 const Route v_dst(dst.type, dst.midiPort, dst.voidPointer, src.channel, dst.channels, dst.channel, dst.persistentJackPortName);
1363
1364 // Allow it to disconnect a partial route.
1365 if((v_src.exists() && src.track->outRoutes()->contains(v_dst)) || (v_dst.exists() && dst.track->inRoutes()->contains(v_src)))
1366 return true;
1367
1368 return false;
1369 }
1370 return false;
1371 }
1372
1373 //---------------------------------------------------------
1374 // routeConnectionPossible
1375 //---------------------------------------------------------
1376
routesCompatible(const Route & src,const Route & dst,bool check_types_only)1377 bool routesCompatible(const Route& src, const Route& dst, bool check_types_only)
1378 {
1379 if(!src.isValid() || !dst.isValid())
1380 return false;
1381
1382 if(src.type == Route::JACK_ROUTE)
1383 {
1384 if(!MusEGlobal::checkAudioDevice() ||
1385 !src.jackPort ||
1386 MusEGlobal::audioDevice->portDirection(src.jackPort) != MusECore::AudioDevice::OutputPort)
1387 return false;
1388
1389 if(dst.type == Route::TRACK_ROUTE)
1390 {
1391 if(MusEGlobal::audioDevice->portType(src.jackPort) != MusECore::AudioDevice::AudioPort ||
1392 dst.track->type() != Track::AUDIO_INPUT ||
1393 (!check_types_only && dst.channel < 0))
1394 return false;
1395 return true;
1396 }
1397 else if(dst.type == Route::MIDI_DEVICE_ROUTE)
1398 {
1399 if(MusEGlobal::audioDevice->portType(src.jackPort) != MusECore::AudioDevice::MidiPort ||
1400 dst.device->deviceType() != MidiDevice::JACK_MIDI)
1401 return false;
1402 return true;
1403 }
1404 else if(dst.type == Route::JACK_ROUTE)
1405 // Allow direct Jack connections!
1406 return MusEGlobal::audioDevice->portsCompatible(src.jackPort, dst.jackPort);
1407 else
1408 return false;
1409 }
1410 else if(dst.type == Route::JACK_ROUTE)
1411 {
1412 if(!MusEGlobal::checkAudioDevice() ||
1413 !dst.jackPort ||
1414 MusEGlobal::audioDevice->portDirection(dst.jackPort) != MusECore::AudioDevice::InputPort)
1415 return false;
1416
1417 if(src.type == Route::TRACK_ROUTE)
1418 {
1419 if(MusEGlobal::audioDevice->portType(dst.jackPort) != MusECore::AudioDevice::AudioPort ||
1420 src.track->type() != Track::AUDIO_OUTPUT ||
1421 (!check_types_only && src.channel < 0))
1422 return false;
1423 return true;
1424 }
1425 else if(src.type == Route::MIDI_DEVICE_ROUTE)
1426 {
1427 if(MusEGlobal::audioDevice->portType(dst.jackPort) != MusECore::AudioDevice::MidiPort ||
1428 src.device->deviceType() != MidiDevice::JACK_MIDI)
1429 return false;
1430 return true;
1431 }
1432 // Unnecessary. This condition is handled above.
1433 //else if(src.type == Route::JACK_ROUTE)
1434 // // Allow direct Jack connections!
1435 // return MusEGlobal::audioDevice->portsCompatible(src.jackPort, dst.jackPort);
1436 else
1437 return false;
1438 }
1439 else if(src.type == Route::MIDI_PORT_ROUTE)
1440 {
1441 if(dst.type != Route::TRACK_ROUTE || !dst.track->isMidiTrack())
1442 return false;
1443
1444 //MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort];
1445
1446 // Do not allow synth ports to connect to any track. It may be useful in some cases,
1447 // may be desired later, but for now it's just a routing hassle. p4.0.35
1448 //if(mp->device() && mp->device()->isSynti())
1449 // return false;
1450
1451 if(check_types_only)
1452 return true;
1453
1454 if(dst.channel < -1 || dst.channel >= MusECore::MUSE_MIDI_CHANNELS)
1455 return false;
1456
1457 // If one route node exists and one is missing, it's OK to reconnect, addRoute will take care of it.
1458 return true;
1459 }
1460 else if(dst.type == Route::MIDI_PORT_ROUTE)
1461 {
1462
1463 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1464 return false;
1465 #else
1466
1467 if(src.type != Route::TRACK_ROUTE || !src.track->isMidiTrack())
1468 return false;
1469
1470 if(check_types_only)
1471 return true;
1472
1473 if(src.channel < -1 || src.channel >= MusECore::MUSE_MIDI_CHANNELS)
1474 return false;
1475
1476 // If one route node exists and one is missing, it's OK to reconnect, addRoute will take care of it.
1477 return true;
1478 #endif
1479 }
1480 else
1481 {
1482 if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)
1483 return false;
1484 if(src.track && dst.track && src.track == dst.track)
1485 return false;
1486
1487 switch(src.track->type())
1488 {
1489 case Track::MIDI:
1490 case Track::DRUM:
1491 switch(dst.track->type())
1492 {
1493 case Track::MIDI:
1494 case Track::DRUM:
1495 case Track::WAVE:
1496 case Track::AUDIO_OUTPUT:
1497 case Track::AUDIO_GROUP:
1498 case Track::AUDIO_AUX:
1499 case Track::AUDIO_SOFTSYNTH:
1500 return false;
1501
1502 case Track::AUDIO_INPUT:
1503 if(!check_types_only && src.channel >= 0)
1504 return false;
1505 break;
1506 }
1507 break;
1508
1509
1510 case Track::AUDIO_OUTPUT:
1511 switch(dst.track->type())
1512 {
1513 case Track::MIDI:
1514 case Track::DRUM:
1515 case Track::WAVE:
1516 case Track::AUDIO_OUTPUT:
1517 case Track::AUDIO_GROUP:
1518 case Track::AUDIO_AUX:
1519 case Track::AUDIO_SOFTSYNTH:
1520 return false;
1521
1522 case Track::AUDIO_INPUT:
1523 if(!check_types_only && (src.channel >= 0 || dst.channel >= 0))
1524 return false;
1525 break;
1526 }
1527 break;
1528
1529 case Track::AUDIO_INPUT:
1530 switch(dst.track->type())
1531 {
1532 case Track::MIDI:
1533 case Track::DRUM:
1534 case Track::AUDIO_INPUT:
1535 case Track::AUDIO_AUX:
1536 return false;
1537
1538 case Track::WAVE:
1539 case Track::AUDIO_OUTPUT:
1540 case Track::AUDIO_GROUP:
1541 case Track::AUDIO_SOFTSYNTH:
1542 break;
1543 }
1544 break;
1545
1546 case Track::WAVE:
1547 switch(dst.track->type())
1548 {
1549 case Track::MIDI:
1550 case Track::DRUM:
1551 case Track::AUDIO_INPUT:
1552 case Track::AUDIO_AUX:
1553 return false;
1554
1555 case Track::WAVE:
1556 case Track::AUDIO_OUTPUT:
1557 case Track::AUDIO_GROUP:
1558 case Track::AUDIO_SOFTSYNTH:
1559 break;
1560 }
1561 break;
1562
1563 case Track::AUDIO_GROUP:
1564 switch(dst.track->type())
1565 {
1566 case Track::MIDI:
1567 case Track::DRUM:
1568 case Track::AUDIO_INPUT:
1569 case Track::AUDIO_AUX:
1570 return false;
1571
1572 case Track::WAVE:
1573 case Track::AUDIO_OUTPUT:
1574 case Track::AUDIO_GROUP:
1575 case Track::AUDIO_SOFTSYNTH:
1576 break;
1577 }
1578 break;
1579
1580 case Track::AUDIO_AUX:
1581 switch(dst.track->type())
1582 {
1583 case Track::MIDI:
1584 case Track::DRUM:
1585 case Track::AUDIO_INPUT:
1586 case Track::AUDIO_AUX:
1587 return false;
1588
1589 case Track::AUDIO_GROUP:
1590 case Track::WAVE:
1591 case Track::AUDIO_OUTPUT:
1592 case Track::AUDIO_SOFTSYNTH:
1593 break;
1594 }
1595 break;
1596
1597 case Track::AUDIO_SOFTSYNTH:
1598 switch(dst.track->type())
1599 {
1600 case Track::MIDI:
1601 case Track::DRUM:
1602 case Track::AUDIO_INPUT:
1603 case Track::AUDIO_AUX:
1604 return false;
1605
1606 case Track::AUDIO_GROUP:
1607 case Track::WAVE:
1608 case Track::AUDIO_OUTPUT:
1609 case Track::AUDIO_SOFTSYNTH:
1610 break;
1611 }
1612 break;
1613
1614 }
1615
1616 // Don't bother with the circular route check, below.
1617 if(check_types_only)
1618 return true;
1619
1620 if((src.channel == -1 && dst.channel != -1) ||
1621 (dst.channel == -1 && src.channel != -1) ||
1622 (src.channels != dst.channels))
1623 return false;
1624
1625 // Allow for -1 = omni route.
1626 if(src.channel >= src.track->routeCapabilities()._trackChannels._outChannels ||
1627 dst.channel >= dst.track->routeCapabilities()._trackChannels._inChannels ||
1628 src.track->isCircularRoute(dst.track))
1629 return false;
1630
1631 return true;
1632 }
1633 return false;
1634 }
1635
1636
1637 //---------------------------------------------------------
1638 // read
1639 //---------------------------------------------------------
1640
read(Xml & xml)1641 void Route::read(Xml& xml)
1642 {
1643 QString s;
1644 int dtype = MidiDevice::ALSA_MIDI;
1645 int port = -1;
1646 int track_idx = -1;
1647 RouteType rtype = Route::TRACK_ROUTE;
1648
1649 for (;;)
1650 {
1651 const QString& tag = xml.s1();
1652 Xml::Token token = xml.parse();
1653 switch (token)
1654 {
1655 case Xml::Error:
1656 case Xml::End:
1657 return;
1658 case Xml::Attribut:
1659 #ifdef ROUTE_DEBUG
1660 fprintf(stderr, "Route::read(): attribute:%s\n", tag.toLatin1().constData());
1661 #endif
1662 if(tag == "type")
1663 rtype = RouteType(xml.s2().toInt());
1664 else
1665 if(tag == "devtype")
1666 {
1667 dtype = xml.s2().toInt();
1668 rtype = Route::MIDI_DEVICE_ROUTE;
1669 }
1670 else
1671 if(tag == "name")
1672 s = xml.s2();
1673 else
1674 if(tag == "track")
1675 track_idx = xml.s2().toInt();
1676 else
1677 if(tag == "mport")
1678 {
1679 port = xml.s2().toInt();
1680 rtype = Route::MIDI_PORT_ROUTE;
1681 }
1682 else
1683 fprintf(stderr, "Route::read(): unknown attribute:%s\n", tag.toLatin1().constData());
1684 break;
1685 case Xml::TagEnd:
1686 #ifdef ROUTE_DEBUG
1687 fprintf(stderr, "Route::read(): tag end type:%d channel:%d name:%s\n", rtype, channel, s.toLatin1().constData());
1688 #endif
1689 if(rtype == MIDI_PORT_ROUTE)
1690 {
1691 if(port >= 0 && port < MusECore::MIDI_PORTS)
1692 {
1693 type = rtype;
1694 midiPort = port;
1695 }
1696 else
1697 fprintf(stderr, "Route::read(): midi port <%d> out of range\n", port);
1698 }
1699 else
1700 // New track index method replaces obsolete track name method below.
1701 if(track_idx >= 0)
1702 {
1703 if(rtype == TRACK_ROUTE)
1704 {
1705 const TrackList* tl = MusEGlobal::song->tracks();
1706 Track* t = tl->index(track_idx);
1707 if(t)
1708 {
1709 track = t;
1710 type = rtype;
1711 }
1712 else
1713 fprintf(stderr, "Route::read(): track index <%d> not found\n", track_idx);
1714 }
1715 }
1716 else
1717 if(!s.isEmpty())
1718 {
1719 // OBSOLETE. Keep for backwards compatibility. Replaced by track index method above.
1720 if(rtype == TRACK_ROUTE)
1721 {
1722 TrackList* tl = MusEGlobal::song->tracks();
1723 iTrack i = tl->begin();
1724 for ( ; i != tl->end(); ++i)
1725 {
1726 Track* t = *i;
1727 if (t->name() == s)
1728 {
1729 track = t;
1730 type = rtype;
1731 break;
1732 }
1733 }
1734 if(i == tl->end())
1735 fprintf(stderr, "Route::read(): track <%s> not found\n", s.toLocal8Bit().constData());
1736 }
1737 else
1738 if(rtype == JACK_ROUTE)
1739 {
1740 type = rtype;
1741 jackPort = 0;
1742 if(MusEGlobal::audioDevice) // fix crash if jack is zombified at this point
1743 {
1744 jackPort = MusEGlobal::audioDevice->findPort(s.toLatin1().constData());
1745 if(jackPort)
1746 // Replace the name with a more appropriate one at this time.
1747 MusEGlobal::audioDevice->portName(jackPort, persistentJackPortName, ROUTE_PERSISTENT_NAME_SIZE);
1748 }
1749 // The graph change handler will replace persistentJackPortName with a more appropriate name if necessary.
1750 if(!jackPort)
1751 MusELib::strntcpy(persistentJackPortName, s.toLatin1().constData(), ROUTE_PERSISTENT_NAME_SIZE);
1752 }
1753 else
1754 if(rtype == MIDI_DEVICE_ROUTE)
1755 {
1756 iMidiDevice imd = MusEGlobal::midiDevices.begin();
1757 for( ; imd != MusEGlobal::midiDevices.end(); ++imd)
1758 {
1759 MidiDevice* md = *imd;
1760 if(md->name() == s && md->deviceType() == dtype)
1761 {
1762 // We found a device, but if it is not in use by the song (port is -1), ignore it.
1763 // This prevents loading and propagation of bogus routes in the med file.
1764 // We found a device, but if it is not a jack midi and in use by the song (port is -1), ignore it.
1765 // This prevents loading and propagation of bogus routes in the med file.
1766 if(md->midiPort() == -1 && md->deviceType() != MidiDevice::JACK_MIDI)
1767 break;
1768
1769 device = md;
1770 type = rtype;
1771 break;
1772 }
1773 }
1774 if(imd == MusEGlobal::midiDevices.end())
1775 fprintf(stderr, "Route::read(): midi device <%s> not found\n", s.toLatin1().constData());
1776 }
1777 }
1778 return;
1779 default:
1780 break;
1781 }
1782 }
1783 }
1784
1785
1786 //---------------------------------------------------------
1787 // read
1788 //---------------------------------------------------------
1789
readRoute(Xml & xml)1790 void Song::readRoute(Xml& xml)
1791 {
1792 QString src;
1793 QString dst;
1794 int ch = -1;
1795 int chmask = -1;
1796 int chs = -1;
1797 int remch = -1;
1798 bool midi_track_out_set = false;
1799
1800 Route sroute, droute;
1801
1802 for (;;)
1803 {
1804 const QString& tag = xml.s1();
1805 Xml::Token token = xml.parse();
1806 switch (token)
1807 {
1808 case Xml::Error:
1809 case Xml::End:
1810 return;
1811 case Xml::TagStart:
1812 // 2010/02/03 Support old routes in med files. Now obsolete!
1813 if (tag == "srcNode")
1814 src = xml.parse1();
1815 else if (tag == "dstNode")
1816 dst = xml.parse1();
1817 // Support new routes.
1818 else if (tag == "source")
1819 {
1820 sroute.read(xml);
1821 sroute.channel = ch;
1822 sroute.channels = chs;
1823 sroute.remoteChannel = remch;
1824 }
1825 else if (tag == "dest")
1826 {
1827 droute.read(xml);
1828 droute.channels = chs;
1829 // If channels was given, it should be a multi-channel audio route.
1830 // Convert to new scheme by switching them around for the destination route:
1831 if(chs > 0)
1832 {
1833 droute.channel = remch;
1834 droute.remoteChannel = ch;
1835 }
1836 else
1837 {
1838 droute.channel = ch;
1839 droute.remoteChannel = remch;
1840 }
1841 }
1842 else
1843 xml.unknown("readRoute");
1844 break;
1845 case Xml::Attribut:
1846 #ifdef ROUTE_DEBUG
1847 fprintf(stderr, "Song::readRoute(): attribute:%s\n", tag.toLatin1().constData());
1848 #endif
1849 if(tag == "channel")
1850 ch = xml.s2().toInt();
1851 else
1852 if(tag == "channels")
1853 chs = xml.s2().toInt();
1854 else
1855 if(tag == "remch")
1856 remch = xml.s2().toInt();
1857 else
1858 if(tag == "channelMask") // New channel mask for midi port-track routes.
1859 chmask = xml.s2().toInt();
1860 else
1861 fprintf(stderr, "Song::readRoute(): unknown attribute:%s\n", tag.toLatin1().constData());
1862 break;
1863 case Xml::TagEnd:
1864 if (xml.s1() == "Route")
1865 {
1866 // Support old routes in med files. Now obsolete!
1867 if(!src.isEmpty() && !dst.isEmpty())
1868 {
1869 Route s = name2route(src, false);
1870 Route d = name2route(dst, true);
1871 addRoute(s, d);
1872 }
1873 else
1874 // Support new routes.
1875 if(sroute.isValid() && droute.isValid())
1876 {
1877 // Support pre- 1.1-RC2 midi device to track routes. Obsolete. Replaced with midi port routes.
1878 if(sroute.type == Route::MIDI_DEVICE_ROUTE && droute.type == Route::TRACK_ROUTE)
1879 {
1880 if(sroute.device->midiPort() >= 0 && sroute.device->midiPort() < MusECore::MIDI_PORTS
1881 && ch >= 0 && ch < MusECore::MUSE_MIDI_CHANNELS)
1882 {
1883 sroute.midiPort = sroute.device->midiPort();
1884 sroute.device = 0;
1885 sroute.type = Route::MIDI_PORT_ROUTE;
1886
1887 sroute.channel = ch;
1888 droute.channel = sroute.channel;
1889
1890 addRoute(sroute, droute);
1891 }
1892 else
1893 fprintf(stderr, " Warning - device:%s to track route, no device midi port or chan:%d out of range. Ignoring route!\n",
1894 sroute.device->name().toLatin1().constData(), ch);
1895 }
1896 // Support pre- 1.1-RC2 track to midi device routes. Obsolete. Replaced with midi port routes.
1897 else if(sroute.type == Route::TRACK_ROUTE && droute.type == Route::MIDI_DEVICE_ROUTE)
1898 {
1899 // Device and track already validated in ::read().
1900 const int port = droute.device->midiPort();
1901 if(port >= 0 && port < MusECore::MIDI_PORTS
1902 && ch >= 0 && ch < MusECore::MUSE_MIDI_CHANNELS &&
1903 sroute.track->isMidiTrack())
1904 {
1905 MidiTrack* mt = static_cast<MidiTrack*>(sroute.track);
1906 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1907 if(!midi_track_out_set)
1908 {
1909 midi_track_out_set = true;
1910 MusECore::MidiTrack::ChangedType_t changed = MusECore::MidiTrack::NothingChanged;
1911 MusEGlobal::audio->msgIdle(true);
1912 changed |= mt->setOutPortAndChannelAndUpdate(port, ch, false);
1913 MusEGlobal::audio->msgIdle(false);
1914 MusEGlobal::audio->msgUpdateSoloStates();
1915 MusEGlobal::song->update(SC_ROUTE | ((changed & MusECore::MidiTrack::DrumMapChanged) ? SC_DRUMMAP : 0));
1916 }
1917 #else
1918 droute.midiPort = droute.device->midiPort();
1919 droute.device = 0;
1920 droute.type = Route::MIDI_PORT_ROUTE;
1921 droute.channel = ch;
1922 sroute.channel = droute.channel;
1923 addRoute(sroute, droute);
1924 #endif
1925 }
1926 else
1927 fprintf(stderr, " Warning - track to device:%s route, no device midi port or chan:%d out of range. Ignoring route!\n",
1928 droute.device->name().toLatin1().constData(), ch);
1929 }
1930 // Support old bit-wise channel mask for midi port to midi track routes and midi port to audio input soling chain routes. Obsolete!
1931 // Check for song file version 2.0 or below:
1932 else if(chmask > 0 && (xml.majorVersion() * 1000000 + xml.minorVersion()) <= 2000000) // Arbitrary shift, and add
1933 {
1934 fprintf(stderr, " Warning - Route: Converting old single-route bitwise channel mask:%d to individual routes\n", chmask);
1935
1936 if(sroute.type == Route::MIDI_PORT_ROUTE && droute.type == Route::TRACK_ROUTE)
1937 {
1938 if(droute.track->isMidiTrack())
1939 {
1940 // All channels set? Convert to new Omni route.
1941 if(chmask == ((1 << MusECore::MUSE_MIDI_CHANNELS) - 1))
1942 {
1943 sroute.channel = -1;
1944 droute.channel = -1;
1945 addRoute(sroute, droute);
1946 }
1947 else
1948 {
1949 // Check each channel bit:
1950 for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
1951 {
1952 const int chbit = 1 << i;
1953 // Is channel bit set?
1954 if(chmask & chbit)
1955 {
1956 // Convert to individual routes:
1957 sroute.channel = i;
1958 droute.channel = i;
1959 addRoute(sroute, droute);
1960 }
1961 }
1962 }
1963 }
1964 // Support old midi port to audio input soloing chain routes. Obsolete!
1965 else if(droute.track->type() == Track::AUDIO_INPUT)
1966 {
1967 const int port = sroute.midiPort;
1968 // Check each channel bit:
1969 for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
1970 {
1971 const int chbit = 1 << i;
1972 // Is channel bit set?
1973 if(chmask & chbit)
1974 {
1975 const MusECore::MidiTrackList* const mtl = MusEGlobal::song->midis();
1976 for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt)
1977 {
1978 MidiTrack* const mt = *imt;
1979 if(mt->outPort() == port && mt->outChannel() == i)
1980 {
1981 // Convert to a midi track to audio input route:
1982 sroute.type = Route::TRACK_ROUTE;
1983 sroute.track = mt;
1984 sroute.midiPort = -1;
1985 sroute.channel = sroute.channels = sroute.remoteChannel = droute.channel = droute.channels = droute.remoteChannel = -1;
1986 addRoute(sroute, droute);
1987 }
1988 }
1989 }
1990 }
1991 }
1992 }
1993 }
1994 // If channels was given, it must be a multi-channel audio route:
1995 else if(chs > 0)
1996 {
1997 // If EITHER the channel or the remote channel are zero but the other not given, convert to an Omni route:
1998 if((ch == -1 && remch == -1) || (ch == 0 && remch == -1) || (remch == 0 && ch == -1))
1999 {
2000 sroute.channel = sroute.remoteChannel = sroute.channels = droute.channel = droute.remoteChannel = droute.channels = -1;
2001 addRoute(sroute, droute);
2002 }
2003 // Otherwise convert to individual routes:
2004 else
2005 {
2006 sroute.channels = droute.channels = 1;
2007 if(sroute.channel == -1)
2008 sroute.channel = 0;
2009 if(sroute.remoteChannel == -1)
2010 sroute.remoteChannel = 0;
2011 if(droute.channel == -1)
2012 droute.channel = 0;
2013 if(droute.remoteChannel == -1)
2014 droute.remoteChannel = 0;
2015 for(int i = 0; i < chs; ++i)
2016 {
2017 addRoute(sroute, droute);
2018 ++sroute.channel;
2019 ++sroute.remoteChannel;
2020 ++droute.channel;
2021 ++droute.remoteChannel;
2022 }
2023 }
2024 }
2025 else
2026
2027 addRoute(sroute, droute);
2028 }
2029 else
2030 fprintf(stderr, " Warning - route invalid. Ignoring route!\n");
2031
2032 return;
2033 }
2034 default:
2035 break;
2036 }
2037 }
2038 }
2039
2040 //---------------------------------------------------------
2041 // dump
2042 //---------------------------------------------------------
2043
dump() const2044 void Route::dump() const
2045 {
2046 if (type == TRACK_ROUTE)
2047 {
2048 if(track)
2049 fprintf(stderr, "Route dump: track <%s> channel %d channels %d\n", track->name().toLocal8Bit().constData(), channel, channels);
2050 }
2051 else
2052 if (type == JACK_ROUTE)
2053 {
2054 if(MusEGlobal::checkAudioDevice())
2055 {
2056 if(jackPort)
2057 {
2058 char s[ROUTE_PERSISTENT_NAME_SIZE];
2059 fprintf(stderr, "Route dump: jack audio port %p <%s> persistent name <%s> channel %d\n", jackPort, MusEGlobal::audioDevice->portName(jackPort, s, ROUTE_PERSISTENT_NAME_SIZE), persistentJackPortName, channel);
2060 }
2061 else
2062 fprintf(stderr, "Route dump: jack audio port %p persistent name <%s> channel %d\n", jackPort, persistentJackPortName, channel);
2063 }
2064 }
2065 else
2066 if (type == MIDI_PORT_ROUTE)
2067 {
2068 fprintf(stderr, "Route dump: midi port <%d> channel mask %d\n", midiPort, channel);
2069 }
2070 else
2071 if (type == MIDI_DEVICE_ROUTE)
2072 {
2073 fprintf(stderr, "Route dump: ");
2074 if(device)
2075 {
2076 if(device->deviceType() == MidiDevice::JACK_MIDI)
2077 {
2078 if(MusEGlobal::checkAudioDevice())
2079 {
2080 fprintf(stderr, "jack midi device <%s> ", device->name().toLatin1().constData());
2081 if(device->inClientPort())
2082 {
2083 char s[ROUTE_PERSISTENT_NAME_SIZE];
2084 fprintf(stderr, "input port <%s> ",
2085 //MusEGlobal::audioDevice->portName(device->inClientPort()).toLatin1().constData());
2086 MusEGlobal::audioDevice->portName(device->inClientPort(), s, ROUTE_PERSISTENT_NAME_SIZE));
2087 }
2088 if(device->outClientPort())
2089 {
2090 char s[ROUTE_PERSISTENT_NAME_SIZE];
2091 fprintf(stderr, "output port <%s> ",
2092 //MusEGlobal::audioDevice->portName(device->outClientPort()).toLatin1().constData());
2093 MusEGlobal::audioDevice->portName(device->outClientPort(), s, ROUTE_PERSISTENT_NAME_SIZE));
2094 }
2095 }
2096 }
2097 else
2098 if(device->deviceType() == MidiDevice::ALSA_MIDI)
2099 fprintf(stderr, "alsa midi device <%s> ", device->name().toLatin1().constData());
2100 else
2101 if(device->deviceType() == MidiDevice::SYNTH_MIDI)
2102 fprintf(stderr, "synth midi device <%s> ", device->name().toLatin1().constData());
2103 else
2104 fprintf(stderr, "is midi but unknown device type:%d, ", device->deviceType());
2105 }
2106 else
2107 fprintf(stderr, "is midi but invalid device, ");
2108
2109 fprintf(stderr, "channel:%d\n", channel);
2110 }
2111 else
2112 fprintf(stderr, "Route dump: unknown route type:%d\n", type);
2113 }
2114
2115 //---------------------------------------------------------
2116 // operator==
2117 //---------------------------------------------------------
2118
operator ==(const Route & a) const2119 bool Route::operator==(const Route& a) const
2120 {
2121 if ((type == a.type) && (channel == a.channel))
2122 {
2123 if (type == TRACK_ROUTE)
2124 {
2125 return track == a.track && channels == a.channels && remoteChannel == a.remoteChannel;
2126 }
2127 else
2128 {
2129 if (type == JACK_ROUTE)
2130 {
2131 // If the ports are valid compare them, otherwise compare the persistent port names.
2132 if(jackPort && a.jackPort)
2133 return jackPort == a.jackPort; // Simplified.
2134 else
2135 return strcmp(persistentJackPortName, a.persistentJackPortName) == 0;
2136 }
2137 else
2138 if (type == MIDI_PORT_ROUTE)
2139 {
2140 return midiPort == a.midiPort;
2141 }
2142 else
2143 if (type == MIDI_DEVICE_ROUTE)
2144 {
2145 return device == a.device;
2146 }
2147 }
2148 }
2149 return false;
2150 }
2151
2152 //---------------------------------------------------------
2153 // exists
2154 //---------------------------------------------------------
2155
exists() const2156 bool Route::exists() const
2157 {
2158 switch(type)
2159 {
2160 case MusECore::Route::TRACK_ROUTE:
2161 return MusEGlobal::song->tracks()->contains(track);
2162 break;
2163
2164 case MusECore::Route::JACK_ROUTE:
2165 return MusEGlobal::checkAudioDevice() && MusEGlobal::audioDevice->findPort(persistentJackPortName);
2166 break;
2167
2168 case MusECore::Route::MIDI_DEVICE_ROUTE:
2169 return MusEGlobal::midiDevices.contains(device);
2170 break;
2171
2172 case MusECore::Route::MIDI_PORT_ROUTE:
2173 return isValid();
2174 break;
2175 }
2176 return false;
2177 }
2178
2179 //---------------------------------------------------------
2180 // compare
2181 //---------------------------------------------------------
2182
compare(const Route & a) const2183 bool Route::compare(const Route& a) const
2184 {
2185 //if ((type == a.type) && (channel == a.channel))
2186 if (type == a.type)
2187 {
2188 if (type == TRACK_ROUTE)
2189 {
2190 return track == a.track &&
2191 channels == a.channels &&
2192 ((a.channel == -1) ? (channel == -1) : (channel != -1)) &&
2193 //remoteChannel == a.remoteChannel;
2194 ((a.remoteChannel == -1) ? (remoteChannel == -1) : (remoteChannel != -1)); // TODO: Want this? Seems logical.
2195 }
2196 else
2197 //if(channel == a.channel)
2198 {
2199 if (type == JACK_ROUTE && channel == a.channel)
2200 {
2201 // If the ports are valid compare them, otherwise compare the persistent port names.
2202 if(jackPort && a.jackPort)
2203 return jackPort == a.jackPort; // Simplified.
2204 else
2205 return strcmp(persistentJackPortName, a.persistentJackPortName) == 0;
2206 }
2207 else
2208 if (type == MIDI_PORT_ROUTE)
2209 {
2210 return midiPort == a.midiPort;
2211 }
2212 else
2213 if (type == MIDI_DEVICE_ROUTE)
2214 {
2215 return device == a.device;
2216 }
2217 }
2218 }
2219 return false;
2220 }
2221
2222 /* Please keep this just in case...
2223 //---------------------------------------------------------
2224 // isCircularRoute
2225 // Recursive.
2226 // If dst is valid, start traversal from there, not from src.
2227 // Returns true if circular.
2228 //---------------------------------------------------------
2229
2230 bool isCircularRoutePath(Track* src, Track* dst)
2231 {
2232 bool rv = false;
2233
2234 if(dst)
2235 {
2236 src->setNodeTraversed(true);
2237 rv = isCircularRoutePath(dst, NULL);
2238 src->setNodeTraversed(false);
2239 return rv;
2240 }
2241
2242 if(src->nodeTraversed())
2243 return true;
2244
2245 src->setNodeTraversed(true);
2246
2247 RouteList* orl = src->outRoutes();
2248 for (iRoute i = orl->begin(); i != orl->end(); ++i)
2249 {
2250 if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE )
2251 continue;
2252 Track* t = (*i).track;
2253 //if(t->isMidiTrack())
2254 // continue;
2255 rv = isCircularRoutePath(src, NULL);
2256 if(rv)
2257 break;
2258 }
2259
2260 src->setNodeTraversed(false);
2261 return rv;
2262 }
2263 */
2264
2265
2266 } // namespace MusECore
2267