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