diff options
-rw-r--r-- | muse/ChangeLog | 13 | ||||
-rw-r--r-- | muse/muse/app.cpp | 130 | ||||
-rw-r--r-- | muse/muse/app.h | 2 | ||||
-rw-r--r-- | muse/muse/arranger/trackinfo.cpp | 34 | ||||
-rw-r--r-- | muse/muse/conf.cpp | 3 | ||||
-rw-r--r-- | muse/muse/confmport.cpp | 3 | ||||
-rw-r--r-- | muse/muse/driver/alsamidi.cpp | 2 | ||||
-rw-r--r-- | muse/muse/driver/alsatimer.cpp | 9 | ||||
-rw-r--r-- | muse/muse/driver/audiodev.h | 4 | ||||
-rw-r--r-- | muse/muse/driver/dummyaudio.cpp | 11 | ||||
-rw-r--r-- | muse/muse/driver/jack.cpp | 2 | ||||
-rw-r--r-- | muse/muse/driver/jackaudio.h | 2 | ||||
-rw-r--r-- | muse/muse/driver/jackmidi.cpp | 57 | ||||
-rw-r--r-- | muse/muse/midi.cpp | 543 | ||||
-rw-r--r-- | muse/muse/midiport.cpp | 39 | ||||
-rw-r--r-- | muse/muse/midiport.h | 15 | ||||
-rw-r--r-- | muse/muse/mixer/astrip.cpp | 11 | ||||
-rw-r--r-- | muse/muse/mixer/astrip.h | 2 | ||||
-rw-r--r-- | muse/muse/mixer/mstrip.cpp | 6 | ||||
-rw-r--r-- | muse/muse/route.cpp | 769 | ||||
-rw-r--r-- | muse/muse/route.h | 45 | ||||
-rw-r--r-- | muse/muse/song.cpp | 113 | ||||
-rw-r--r-- | muse/muse/songfile.cpp | 7 | ||||
-rw-r--r-- | muse/muse/track.cpp | 84 |
24 files changed, 1203 insertions, 703 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog index b9a3c125..8f031aa9 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,16 @@ +16.09.2010 + * Fixed: Delete track(s) not disconnecting track routes, causing routes to hang around and store in song file. (T356) + - Fixed major regressions (my fault) in Song::insertTrack2() and ::removeTrack2(). + * Fixed: Dummy audio device: Crashes when Jack midi device created in device manager, or loaded from song. (T356) + - This allows to create Jack midi devices even when dummy audio driver is used. + - Tested OK loading complex Jack midi based songs with dummy audio driver. + * Fixed: AlsaTimer cannot start, with dummy audio device. (T356) + - Reverted: Back to default SND_TIMER_GLOBAL_SYSTEM in AlsaTimer, for now until a better fix. + - Also replaced pop-up warning in dummy loop with terminal output instead. + * Changed: MidiDevice <-> Track routes replaced with MidiPort <-> Track routes. (T356) + - This allows to change a port's device (even to <none> !) while keeping all the track channel routes. + * Changed: Single midi <-> track route with channel mask, instead of one route-per-channel. (T356) + - Potentially saving very many routes from memory and in song file. 10.09.2010 * Fixed: regression with oR routing for Aux strips (rj) 05.09.2010 diff --git a/muse/muse/app.cpp b/muse/muse/app.cpp index a4a2a417..b8aca409 100644 --- a/muse/muse/app.cpp +++ b/muse/muse/app.cpp @@ -2002,14 +2002,16 @@ PopupMenu* MusE::getRoutingPopupMenu() // updateRouteMenus //--------------------------------------------------------- -void MusE::updateRouteMenus(Track* track) +//void MusE::updateRouteMenus(Track* track) +void MusE::updateRouteMenus(Track* track, QObject* master) // p3.3.50 { //if(!track || track != gRoutingPopupMenuMaster || track->type() == Track::AUDIO_AUX) - if(!track || track->type() == Track::AUDIO_AUX) + //if(!track || track->type() == Track::AUDIO_AUX) + if(!track || gRoutingPopupMenuMaster != master) // p3.3.50 return; //QPopupMenu* pup = muse->getORoutesPopup(); - PopupMenu* pup = muse->getRoutingPopupMenu(); + PopupMenu* pup = getRoutingPopupMenu(); if(pup->count() == 0) return; @@ -2043,19 +2045,36 @@ void MusE::updateRouteMenus(Track* track) iRouteMenuMap imm = gRoutingMenuMap.begin(); for(; imm != gRoutingMenuMap.end(); ++imm) { - bool found = false; + // p3.3.50 Ignore the 'toggle' items. + if(imm->second.type == Route::MIDI_PORT_ROUTE && + imm->first >= (MIDI_PORTS * MIDI_CHANNELS) && imm->first < (MIDI_PORTS * MIDI_CHANNELS + MIDI_PORTS)) + continue; + + //bool found = false; iRoute irl = rl->begin(); for(; irl != rl->end(); ++irl) { + if(imm->second.type == Route::MIDI_PORT_ROUTE) // p3.3.50 Is the map route a midi port route? + { + if(irl->type == Route::MIDI_PORT_ROUTE && irl->midiPort == imm->second.midiPort // Is the track route a midi port route? + && (irl->channel & imm->second.channel) == imm->second.channel) // Is the exact channel mask bit(s) set? + { + //found = true; + break; + } + } + else if(*irl == imm->second) { - found = true; + //found = true; break; } } - pup->setItemChecked(imm->first, found); + //pup->setItemChecked(imm->first, found); + pup->setItemChecked(imm->first, irl != rl->end()); } + return; } @@ -2090,12 +2109,32 @@ void MusE::routingPopupMenuActivated(Track* track, int n) } else { - int mdidx = n / MIDI_CHANNELS; - int ch = n % MIDI_CHANNELS; + //int mdidx = n / MIDI_CHANNELS; + //int ch = n % MIDI_CHANNELS; + //int chbit = 1 << ch; // p3.3.50 + //int chmask = 0; + //if(n >= MIDI_PORTS * MIDI_CHANNELS) // p3.3.50 Toggle channels. + //{ + //for (int i = 0; i < MIDI_CHANNELS; i++) + //muse->routingPopupMenuActivated(selected, i + MIDI_CHANNELS * (n-1000)); + //muse->routingPopupMenuActivated(selected, i + MIDI_CHANNELS * (n - MIDI_PORTS * MIDI_CHANNELS)); // p3.3.50 + // chbit = (1 << MIDI_CHANNELS) - 1; + //} //if(debugMsg) //printf("MusE::routingPopupMenuActivated mdidx:%d ch:%d\n", mdidx, ch); + // p3.3.50 + iRouteMenuMap imm = gRoutingMenuMap.find(n); + if(imm == gRoutingMenuMap.end()) + return; + if(imm->second.type != Route::MIDI_PORT_ROUTE) + return; + Route &aRoute = imm->second; + int chbit = aRoute.channel; + Route bRoute(track, chbit); + int mdidx = aRoute.midiPort; + MidiPort* mp = &midiPorts[mdidx]; MidiDevice* md = mp->device(); if(!md) @@ -2115,21 +2154,33 @@ void MusE::routingPopupMenuActivated(Track* track, int n) //QT_TR_NOOP(md->name()) //Route srcRoute(s, false, -1); - Route aRoute(md, ch); + + //Route aRoute(md, ch); + //Route aRoute(mdidx, ch); // p3.3.49 + //Route aRoute(mdidx, chbit); // p3.3.50 In accordance with new channel mask, use the bit position. + //Route srcRoute(md, -1); //Route dstRoute(track, -1); - Route bRoute(track, ch); + //Route bRoute(track, ch); + //Route bRoute(track, chbit); // p3.3.50 //if (track->type() == Track::AUDIO_INPUT) // srcRoute.channel = dstRoute.channel = n & 0xf; + + int chmask = 0; iRoute iir = rl->begin(); for (; iir != rl->end(); ++iir) { //if(*iir == (dst ? bRoute : aRoute)) - if(*iir == aRoute) + //if(*iir == aRoute) + if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx) // p3.3.50 Is there already a route to this port? + { + chmask = iir->channel; // p3.3.50 Grab the channel mask. break; + } } - if (iir != rl->end()) + //if (iir != rl->end()) + if ((chmask & chbit) == chbit) // p3.3.50 Is the channel's bit(s) set? { // disconnect if(gIsOutRoutingPopupMenu) @@ -2425,7 +2476,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst) if(!track) return 0; - QPoint ppt = QCursor::pos(); + //QPoint ppt = QCursor::pos(); if(track->isMidiTrack()) { @@ -2467,7 +2518,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst) for(int i = 0; i < MIDI_PORTS; ++i) { //MidiInPort* track = *i; - // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports. + // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick with ports. MidiPort* mp = &midiPorts[i]; MidiDevice* md = mp->device(); if(!md) @@ -2485,6 +2536,19 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst) connect(subp, SIGNAL(activated(int)), pup, SIGNAL(activated(int))); //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide())); + int chanmask = 0; + // p3.3.50 To reduce number of routes required, from one per channel to just one containing a channel mask. + // Look for the first route to this midi port. There should always be only a single route for each midi port, now. + for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) + { + // We have a route to the midi port. Grab the channel mask. + chanmask = ir->channel; + break; + } + } + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) { //QAction* a = m->addAction(QString("Channel %1").arg(ch+1)); @@ -2493,26 +2557,40 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst) //printf("MusE::prepareRoutingPopupMenu inserting gid:%d\n", gid); - int id = subp->insertItem(QString("Channel %1").arg(ch+1), gid); + subp->insertItem(QString("Channel %1").arg(ch+1), gid); //a->setCheckable(true); //Route src(track, ch, RouteNode::TRACK); //Route src(md, ch); //Route r = Route(src, dst); //a->setData(QVariant::fromValue(r)); //a->setChecked(rl->indexOf(r) != -1); - Route srcRoute(md, ch); - gRoutingMenuMap.insert( pRouteMenuMap(id, srcRoute) ); - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { + + //Route srcRoute(md, ch); + //Route srcRoute(i, ch); // p3.3.49 New: Midi port route. + int chbit = 1 << ch; + Route srcRoute(i, chbit); // p3.3.50 In accordance with new channel mask, use the bit position. + + gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) ); + + //for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) // p3.3.50 Removed. + //{ //if(*ir == dst) - if(*ir == srcRoute) - { - subp->setItemChecked(id, true); - break; - } - } + // if(*ir == srcRoute) + // { + // subp->setItemChecked(id, true); + // break; + // } + //} + if(chanmask & chbit) // p3.3.50 Is the channel already set? Show item check mark. + subp->setItemChecked(gid, true); } - subp->insertItem(QString("Toggle all"), 1000+i); + //subp->insertItem(QString("Toggle all"), 1000+i); + // p3.3.50 One route with all channel bits set. + gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. + subp->insertItem(QString("Toggle all"), gid); + Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. + gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) ); + pup->insertItem(QT_TR_NOOP(md->name()), subp); } diff --git a/muse/muse/app.h b/muse/muse/app.h index b1128400..a3781945 100644 --- a/muse/muse/app.h +++ b/muse/muse/app.h @@ -282,7 +282,6 @@ class MusE : public QMainWindow void setUsedTool(int); void showDidYouKnowDialog(); - void updateRouteMenus(Track* track); void routingPopupMenuAboutToHide(); public: @@ -311,6 +310,7 @@ class MusE : public QMainWindow PopupMenu* getRoutingPopupMenu(); PopupMenu* prepareRoutingPopupMenu(Track* /*track*/, bool /*dst*/); void routingPopupMenuActivated(Track* /*track*/, int /*id*/); + void updateRouteMenus(Track* /*track*/, QObject* /*master*/); #ifdef HAVE_LASH void lash_idle_cb (); diff --git a/muse/muse/arranger/trackinfo.cpp b/muse/muse/arranger/trackinfo.cpp index 3c0f1cc4..39a30ca3 100644 --- a/muse/muse/arranger/trackinfo.cpp +++ b/muse/muse/arranger/trackinfo.cpp @@ -85,23 +85,27 @@ void Arranger::midiTrackInfoHeartBeat() for( ; r != rl->end(); ++r) { //if(!r->isValid() || ((r->type != Route::ALSA_MIDI_ROUTE) && (r->type != Route::JACK_MIDI_ROUTE))) - if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) + //if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) + if(!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49 continue; // NOTE: TODO: Code for channelless events like sysex, ** IF we end up using the 'special channel 17' method. - if(r->channel == -1) + //if(r->channel == -1) + if(r->channel == -1 || r->channel == 0) // p3.3.50 continue; // No port assigned to the device? - mpt = r->device->midiPort(); - if(mpt == -1) + //mpt = r->device->midiPort(); + mpt = r->midiPort; // p3.3.49 + if(mpt < 0 || mpt >= MIDI_PORTS) continue; //for(; mch < MIDI_CHANNELS; ++mch) //{ //if(midiPorts[mpt].syncInfo().actDetect(mch) && (iptMask & (1 << mpt)) && (ichMask & (1 << mch)) ) //if((iptMask & bitShiftLU[mpt]) && (midiPorts[mpt].syncInfo().actDetectBits() & ichMask) ) - if(midiPorts[mpt].syncInfo().actDetectBits() & bitShiftLU[r->channel]) + //if(midiPorts[mpt].syncInfo().actDetectBits() & bitShiftLU[r->channel]) + if(midiPorts[mpt].syncInfo().actDetectBits() & r->channel) // p3.3.50 Use new channel mask. { //if(midiTrackInfo->iChanTextLabel->paletteBackgroundColor() != green) // midiTrackInfo->iChanTextLabel->setPaletteBackgroundColor(green); @@ -572,13 +576,15 @@ void Arranger::routingPopupMenuActivated(int n) //if(gRoutingPopupMenuMaster != this || !track || !track->isMidiTrack()) if(!midiTrackInfo || gRoutingPopupMenuMaster != midiTrackInfo || !selected || !selected->isMidiTrack()) return; - if (n > 999) { - for (int i = 0; i < MIDI_CHANNELS; i++) - muse->routingPopupMenuActivated(selected, i + MIDI_CHANNELS * (n-1000)); - } - else { + //if (n > 999) { + //if (n >= MIDI_PORTS * MIDI_CHANNELS) { // p3.3.50 + // for (int i = 0; i < MIDI_CHANNELS; i++) + //muse->routingPopupMenuActivated(selected, i + MIDI_CHANNELS * (n-1000)); + // muse->routingPopupMenuActivated(selected, i + MIDI_CHANNELS * (n - MIDI_PORTS * MIDI_CHANNELS)); // p3.3.50 + //} + //else { muse->routingPopupMenuActivated(selected, n); - } + //} } //--------------------------------------------------------- @@ -1262,9 +1268,11 @@ void Arranger::updateMidiTrackInfo(int flags) return; // p3.3.47 Update the routing popup menu if anything relevant changes. - if(gRoutingPopupMenuMaster == midiTrackInfo && selected && (flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) + //if(gRoutingPopupMenuMaster == midiTrackInfo && selected && (flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) + if(flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) // p3.3.50 // Use this handy shared routine. - muse->updateRouteMenus(selected); + //muse->updateRouteMenus(selected); + muse->updateRouteMenus(selected, midiTrackInfo); // p3.3.50 // Added by Tim. p3.3.9 setTrackInfoLabelText(); diff --git a/muse/muse/conf.cpp b/muse/muse/conf.cpp index bb8f3cdd..d53b30b1 100644 --- a/muse/muse/conf.cpp +++ b/muse/muse/conf.cpp @@ -284,6 +284,9 @@ static void readConfigMidiPort(Xml& xml) MidiPort* mp = &midiPorts[idx]; mp->syncInfo().copyParams(tmpSi); + // p3.3.50 Indicate the port was found in the song file, even if no device is assigned to it. + mp->setFoundInSongFile(true); + if (dev) { dev->setOpenFlags(openFlags); midiSeq->msgSetMidiDevice(mp, dev); diff --git a/muse/muse/confmport.cpp b/muse/muse/confmport.cpp index 81c66c71..77766116 100644 --- a/muse/muse/confmport.cpp +++ b/muse/muse/confmport.cpp @@ -173,6 +173,9 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint& cpt, int col) if(!checkAudioDevice()) return; + if(audioDevice->deviceType() != AudioDevice::JACK_AUDIO) // p3.3.52 Only if Jack is running. + return; + if(!dev) return; diff --git a/muse/muse/driver/alsamidi.cpp b/muse/muse/driver/alsamidi.cpp index 5a057104..3b15fc6f 100644 --- a/muse/muse/driver/alsamidi.cpp +++ b/muse/muse/driver/alsamidi.cpp @@ -178,7 +178,7 @@ void MidiAlsaDevice::writeRouting(int level, Xml& xml) const { // p3.3.45 // If this device is not actually in use by the song, do not write any routes. - // This prevents bogus routes from being saved and propogated in the med file. + // This prevents bogus routes from being saved and propagated in the med file. if(midiPort() == -1) return; diff --git a/muse/muse/driver/alsatimer.cpp b/muse/muse/driver/alsatimer.cpp index f8294bec..d851410d 100644 --- a/muse/muse/driver/alsatimer.cpp +++ b/muse/muse/driver/alsatimer.cpp @@ -55,7 +55,8 @@ }; int max_ids = sizeof(test_ids) / sizeof(int); long best_res = LONG_MAX; - int best_dev = -1; // SND_TIMER_GLOBAL_SYSTEM; + //int best_dev = -1; // SND_TIMER_GLOBAL_SYSTEM; + int best_dev = SND_TIMER_GLOBAL_SYSTEM; // p3.3.51 int i; if (id || info || params) { @@ -89,12 +90,14 @@ device = best_dev; } - if(best_dev==-1) - return -1; // no working timer found + // p3.3.51 Removed. + //if(best_dev==-1) + // return -1; // no working timer found sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i", devclass, sclass, card, device, subdevice); if ((err = snd_timer_open(&handle, timername, SND_TIMER_OPEN_NONBLOCK))<0) { fprintf(stderr, "AlsaTimer::initTimer(): timer open %i (%s)\n", err, snd_strerror(err)); + return -1; // p3.3.51 } if ((err = snd_timer_info(handle, info)) < 0) { diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h index b28e381c..39ff822e 100644 --- a/muse/muse/driver/audiodev.h +++ b/muse/muse/driver/audiodev.h @@ -21,9 +21,13 @@ class MidiPlayEvent; class AudioDevice { public: + enum { DUMMY_AUDIO=0, JACK_AUDIO=1 }; // p3.3.52 + AudioDevice() {} virtual ~AudioDevice() {} + virtual int deviceType() = 0; // p3.3.52 + //virtual void start() = 0; virtual void start(int priority) = 0; diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp index 30da8197..a17a99e7 100644 --- a/muse/muse/driver/dummyaudio.cpp +++ b/muse/muse/driver/dummyaudio.cpp @@ -66,6 +66,8 @@ class DummyAudioDevice : public AudioDevice { free(buffer); } + virtual inline int deviceType() { return DUMMY_AUDIO; } // p3.3.52 + //virtual void start(); virtual void start(int); @@ -265,9 +267,12 @@ static void* dummyLoop(void* ptr) timer.setFindBestTimer(false); int fd = timer.initTimer(); if (fd==-1) { - QMessageBox::critical( 0, /*tr*/(QString("Failed to start timer for dummy audio driver!")), - /*tr*/(QString("No functional timer was available.\n" - "Alsa timer not available, check if module snd_timer is available and /dev/snd/timer is available"))); + // QMessageBox::critical( 0, /*tr*/(QString("Failed to start timer for dummy audio driver!")), + // /*tr*/(QString("No functional timer was available.\n" + // "Alsa timer not available, check if module snd_timer is available and /dev/snd/timer is available"))); + fprintf(stderr, "Failed to start timer for dummy audio driver! No functional timer was available.\n" + "Alsa timer not available, check if module snd_timer is available and /dev/snd/timer is available\n"); + pthread_exit(0); } /* Depending on nature of the timer, the requested tickRate might not diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp index c22a3252..2c5081fc 100644 --- a/muse/muse/driver/jack.cpp +++ b/muse/muse/driver/jack.cpp @@ -573,6 +573,7 @@ bool initJackAudio() if (status & JackVersionError) printf("jack server has wrong version\n"); printf("cannot create jack client\n"); + undoSetuid(); // p3.3.51 return true; } @@ -1412,6 +1413,7 @@ void JackAudioDevice::start(int /*priority*/) doSetuid(); if (jack_activate(_client)) { + undoSetuid(); // p3.3.51 fprintf (stderr, "JACK: cannot activate client\n"); exit(-1); } diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h index 2d30fe74..d3132efe 100644 --- a/muse/muse/driver/jackaudio.h +++ b/muse/muse/driver/jackaudio.h @@ -38,6 +38,8 @@ class JackAudioDevice : public AudioDevice { virtual ~JackAudioDevice(); virtual void nullify_client() { _client = 0; } + virtual inline int deviceType() { return JACK_AUDIO; } // p3.3.52 + void scanMidiPorts(); //virtual void start(); diff --git a/muse/muse/driver/jackmidi.cpp b/muse/muse/driver/jackmidi.cpp index 09b39f68..36d6a300 100644 --- a/muse/muse/driver/jackmidi.cpp +++ b/muse/muse/driver/jackmidi.cpp @@ -213,6 +213,7 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 jack_port_t* client_jackport = NULL; //char buf[80]; + // If Jack port can receive data from us and we actually want to... //if((pf & JackPortIsInput) && (_openFlags & 1)) if(rwflags & 1) @@ -231,9 +232,14 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 //if(!audioDevice->findPort(buf)) // break; //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); - client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); - if(client_jackport) - break; + if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52 + { + client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); + if(client_jackport) + break; + } + else + break; } if(i == 65535) @@ -246,12 +252,15 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 } else { - client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); - if(!client_jackport) + if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52 { - fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.latin1()); - return 0; - } + client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); + if(!client_jackport) + { + fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.latin1()); + return 0; + } + } } /* else @@ -309,9 +318,14 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 //if(!audioDevice->findPort(buf)) // break; //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true); - client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); - if(client_jackport) - break; + if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52 + { + client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); + if(client_jackport) + break; + } + else + break; } if(i == 65535) @@ -324,11 +338,14 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 } else { - client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); - if(!client_jackport) + if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52 { - fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.latin1()); - return 0; + client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); + if(!client_jackport) + { + fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.latin1()); + return 0; + } } } @@ -345,8 +362,9 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1 // _nextInIdNum++; } - if(client_jackport == NULL) - return 0; + + //if(client_jackport == NULL) // p3.3.52 Removed. Allow the device to be created even if Jack isn't running. + // return 0; MidiJackDevice* dev = new MidiJackDevice(client_jackport, name); dev->setrwFlags(rwflags); @@ -364,7 +382,8 @@ void MidiJackDevice::setName(const QString& s) printf("MidiJackDevice::setName %s new name:%s\n", name().latin1(), s.latin1()); #endif _name = s; - audioDevice->setPortName(clientPort(), s.latin1()); + if(clientPort()) // p3.3.52 Added check. + audioDevice->setPortName(clientPort(), s.latin1()); } //--------------------------------------------------------- @@ -513,7 +532,7 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const { // p3.3.45 // If this device is not actually in use by the song, do not write any routes. - // This prevents bogus routes from being saved and propogated in the med file. + // This prevents bogus routes from being saved and propagated in the med file. if(midiPort() == -1) return; diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index 5f919a45..3ec40065 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -1019,300 +1019,319 @@ void Audio::processMidi() for(ciRoute r = irl->begin(); r != irl->end(); ++r) { //if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE)) - if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) + //if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) + if(!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49 continue; + int devport = r->midiPort; // p3.3.49 + if (devport == -1) + continue; + //MidiDevice* dev = *id; - MidiDevice* dev = r->device; - int channel = r->channel; - + //MidiDevice* dev = r->device; + MidiDevice* dev = midiPorts[devport].device(); // p3.3.49 + if(!dev) + continue; + + + // p3.3.50 Removed + //int channel = r->channel; // NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **. // This would mean having a separate 'System' channel listed in the routing popups. // The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it, // this does not require a 'System' channel listed in the routing popups. - // But that requires more code below... Not added yet... - if(channel == -1) + // But that requires more code below... Done. + //if(channel == -1) //channel = MIDI_CHANNELS; // Special channel '17' - continue; + // continue; - int devport = dev->midiPort(); + //int devport = dev->midiPort(); // record only from ports marked in portMask: //if (devport == -1 || !(portMask & (1 << devport))) - if (devport == -1) - continue; + //if (devport == -1) + // continue; //MREventList* el = dev->recordEvents(); //MidiFifo& rf = dev->recordEvents(); - if(!dev->sysexFIFOProcessed()) + int channelMask = r->channel; // p3.3.50 + if(channelMask == -1 || channelMask == 0) + continue; + for(int channel = 0; channel < MIDI_CHANNELS; ++channel) // p3.3.50 { - // Set to the sysex fifo at first. - MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); - // Get the frozen snapshot of the size. - int count = dev->tmpRecordCount(MIDI_CHANNELS); + if(!(channelMask & (1 << channel))) + continue; - for(int i = 0; i < count; ++i) + if(!dev->sysexFIFOProcessed()) { - MidiPlayEvent event(rf.peek(i)); - - //unsigned time = event.time() + segmentSize*(segmentCount-1); - //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); - //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); - //event.setTime(time); - //if(!extsync) - // event.setTime(event.time() + segmentSize*(segmentCount-1)); - - event.setPort(port); - - // dont't echo controller changes back to software - // synthesizer: - if(!dev->isSynti() && md && track->recEcho()) - playEvents->add(event); - - // If syncing externally the event time is already in units of ticks, set above. - if(!extsync) - { - //time = tempomap.frame2tick(event.time()); - //event.setTime(time); // set tick time - event.setTime(tempomap.frame2tick(event.time())); // set tick time - } - - if(recording) - rl->add(event); - } + // Set to the sysex fifo at first. + MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); + // Get the frozen snapshot of the size. + int count = dev->tmpRecordCount(MIDI_CHANNELS); - dev->setSysexFIFOProcessed(true); - } - - // Set to the sysex fifo at first. - ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); - // Get the frozen snapshot of the size. - ///int count = dev->tmpRecordCount(MIDI_CHANNELS); - - // Iterate once for sysex fifo (if needed), once for channel fifos. - ///for(int sei = 0; sei < 2; ++sei) - { - // If on first pass, do sysex fifo. - /* - if(sei == 0) - { - // Ignore any further channel routes on this device if already done here. - if(dev->sysexFIFOProcessed()) - continue; - // Go ahead and set this now. + for(int i = 0; i < count; ++i) + { + MidiPlayEvent event(rf.peek(i)); + + //unsigned time = event.time() + segmentSize*(segmentCount-1); + //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); + //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); + //event.setTime(time); + //if(!extsync) + // event.setTime(event.time() + segmentSize*(segmentCount-1)); + + event.setPort(port); + + // dont't echo controller changes back to software + // synthesizer: + if(!dev->isSynti() && md && track->recEcho()) + playEvents->add(event); + + // If syncing externally the event time is already in units of ticks, set above. + if(!extsync) + { + //time = tempomap.frame2tick(event.time()); + //event.setTime(time); // set tick time + event.setTime(tempomap.frame2tick(event.time())); // set tick time + } + + if(recording) + rl->add(event); + } + dev->setSysexFIFOProcessed(true); - // Allow it to fall through with the sysex fifo and count... } - else - { - // We're on the second pass, do channel fifos. - rf = dev->recordEvents(channel); - // Get the frozen snapshot of the size. - count = dev->tmpRecordCount(channel); - } - */ - MidiFifo& rf = dev->recordEvents(channel); - int count = dev->tmpRecordCount(channel); + // Set to the sysex fifo at first. + ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); + // Get the frozen snapshot of the size. + ///int count = dev->tmpRecordCount(MIDI_CHANNELS); - //for (iMREvent ie = el->begin(); ie != el->end(); ++ie) - for(int i = 0; i < count; ++i) + // Iterate once for sysex fifo (if needed), once for channel fifos. + ///for(int sei = 0; sei < 2; ++sei) { - MidiPlayEvent event(rf.peek(i)); - - //int channel = ie->channel(); - ///int channel = event.channel(); - - int defaultPort = devport; - ///if (!(channelMask & (1 << channel))) - ///{ - /// continue; - ///} - - //MidiPlayEvent event(*ie); - int drumRecPitch=0; //prevent compiler warning: variable used without initialization - MidiController *mc = 0; - int ctl = 0; - - //Hmmm, hehhh... - // TODO: Clean up a bit around here when it comes to separate events for rec & for playback. - // But not before 0.7 (ml) - - int prePitch = 0, preVelo = 0; - - event.setChannel(track->outChannel()); - - if (event.isNote() || event.isNoteOff()) - { - // - // apply track values - // - - //Apply drum inkey: - if (track->type() == Track::DRUM) - { - int pitch = event.dataA(); - //Map note that is played according to drumInmap - drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote; - devport = drumMap[(unsigned int)drumInmap[pitch]].port; - event.setPort(devport); - channel = drumMap[(unsigned int)drumInmap[pitch]].channel; - event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote); - event.setChannel(channel); - } - else - { //Track transpose if non-drum - prePitch = event.dataA(); - int pitch = prePitch + track->transposition; - if (pitch > 127) - pitch = 127; - if (pitch < 0) - pitch = 0; - event.setA(pitch); - } - - if (!event.isNoteOff()) - { - preVelo = event.dataB(); - int velo = preVelo + track->velocity; - velo = (velo * track->compression) / 100; - if (velo > 127) - velo = 127; - if (velo < 1) - velo = 1; - event.setB(velo); - } - } - // Added by T356. - else - if(event.type() == ME_CONTROLLER) - { - if(track->type() == Track::DRUM) + // If on first pass, do sysex fifo. + /* + if(sei == 0) + { + // Ignore any further channel routes on this device if already done here. + if(dev->sysexFIFOProcessed()) + continue; + // Go ahead and set this now. + dev->setSysexFIFOProcessed(true); + // Allow it to fall through with the sysex fifo and count... + } + else + { + // We're on the second pass, do channel fifos. + rf = dev->recordEvents(channel); + // Get the frozen snapshot of the size. + count = dev->tmpRecordCount(channel); + } + */ + + MidiFifo& rf = dev->recordEvents(channel); + int count = dev->tmpRecordCount(channel); + + //for (iMREvent ie = el->begin(); ie != el->end(); ++ie) + for(int i = 0; i < count; ++i) + { + MidiPlayEvent event(rf.peek(i)); + + //int channel = ie->channel(); + ///int channel = event.channel(); + + int defaultPort = devport; + ///if (!(channelMask & (1 << channel))) + ///{ + /// continue; + ///} + + //MidiPlayEvent event(*ie); + int drumRecPitch=0; //prevent compiler warning: variable used without initialization + MidiController *mc = 0; + int ctl = 0; + + //Hmmm, hehhh... + // TODO: Clean up a bit around here when it comes to separate events for rec & for playback. + // But not before 0.7 (ml) + + int prePitch = 0, preVelo = 0; + + event.setChannel(track->outChannel()); + + if (event.isNote() || event.isNoteOff()) { - ctl = event.dataA(); - // Regardless of what port the event came from, is it a drum controller event - // according to the track port's instrument? - mc = tport->drumController(ctl); - if(mc) - { - int pitch = ctl & 0x7f; - ctl &= ~0xff; - int dmindex = drumInmap[pitch] & 0x7f; - //Map note that is played according to drumInmap - drumRecPitch = drumMap[dmindex].enote; - devport = drumMap[dmindex].port; - event.setPort(devport); - channel = drumMap[dmindex].channel; - event.setA(ctl | drumMap[dmindex].anote); - event.setChannel(channel); - } - } - } - - // p3.3.25 - // MusE uses a fixed clocks per quarternote of 24. - // At standard 384 ticks per quarternote for example, - // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks'). - // That is what we'll use if syncing externally. - //unsigned time = event.time() + segmentSize*(segmentCount-1); - //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); - // p3.3.34 - // Oops, use the current tick. - //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); - //event.setTime(time); - // p3.3.35 - // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). - // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. - // p3.3.36 - //if(!extsync) - // event.setTime(event.time() + segmentSize*(segmentCount-1)); - - // dont't echo controller changes back to software - // synthesizer: - - if (!dev->isSynti()) - { - //Check if we're outputting to another port than default: - if (devport == defaultPort) { - event.setPort(port); - if(md && track->recEcho()) - playEvents->add(event); + // + // apply track values + // + + //Apply drum inkey: + if (track->type() == Track::DRUM) + { + int pitch = event.dataA(); + //Map note that is played according to drumInmap + drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote; + devport = drumMap[(unsigned int)drumInmap[pitch]].port; + event.setPort(devport); + channel = drumMap[(unsigned int)drumInmap[pitch]].channel; + event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote); + event.setChannel(channel); } - else { - // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent?? - MidiDevice* mdAlt = midiPorts[devport].device(); - if(mdAlt && track->recEcho()) - mdAlt->playEvents()->add(event); + else + { //Track transpose if non-drum + prePitch = event.dataA(); + int pitch = prePitch + track->transposition; + if (pitch > 127) + pitch = 127; + if (pitch < 0) + pitch = 0; + event.setA(pitch); } - // Shall we activate meters even while rec echo is off? Sure, why not... - if(event.isNote() && event.dataB() > track->activity()) - track->setActivity(event.dataB()); - } - - // p3.3.25 - // If syncing externally the event time is already in units of ticks, set above. - if(!extsync) - { - // p3.3.35 - //time = tempomap.frame2tick(event.time()); - //event.setTime(time); // set tick time - event.setTime(tempomap.frame2tick(event.time())); // set tick time - } - - // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml) - if (recording) - { - // In these next steps, it is essential to set the recorded event's port - // to the track port so buildMidiEventList will accept it. Even though - // the port may have no device "<none>". - // - if (track->type() == Track::DRUM) + + if (!event.isNoteOff()) + { + preVelo = event.dataB(); + int velo = preVelo + track->velocity; + velo = (velo * track->compression) / 100; + if (velo > 127) + velo = 127; + if (velo < 1) + velo = 1; + event.setB(velo); + } + } + // Added by T356. + else + if(event.type() == ME_CONTROLLER) + { + if(track->type() == Track::DRUM) + { + ctl = event.dataA(); + // Regardless of what port the event came from, is it a drum controller event + // according to the track port's instrument? + mc = tport->drumController(ctl); + if(mc) { - // Is it a drum controller event? - if(mc) - { - MidiPlayEvent drumRecEvent = event; - drumRecEvent.setA(ctl | drumRecPitch); - // In this case, preVelo is simply the controller value. - drumRecEvent.setB(preVelo); - drumRecEvent.setPort(port); //rec-event to current port - drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel - rl->add(drumRecEvent); + int pitch = ctl & 0x7f; + ctl &= ~0xff; + int dmindex = drumInmap[pitch] & 0x7f; + //Map note that is played according to drumInmap + drumRecPitch = drumMap[dmindex].enote; + devport = drumMap[dmindex].port; + event.setPort(devport); + channel = drumMap[dmindex].channel; + event.setA(ctl | drumMap[dmindex].anote); + event.setChannel(channel); + } + } + } + + // p3.3.25 + // MusE uses a fixed clocks per quarternote of 24. + // At standard 384 ticks per quarternote for example, + // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks'). + // That is what we'll use if syncing externally. + //unsigned time = event.time() + segmentSize*(segmentCount-1); + //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); + // p3.3.34 + // Oops, use the current tick. + //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); + //event.setTime(time); + // p3.3.35 + // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). + // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. + // p3.3.36 + //if(!extsync) + // event.setTime(event.time() + segmentSize*(segmentCount-1)); + + // dont't echo controller changes back to software + // synthesizer: + + if (!dev->isSynti()) + { + //Check if we're outputting to another port than default: + if (devport == defaultPort) { + event.setPort(port); + if(md && track->recEcho()) + playEvents->add(event); + } + else { + // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent?? + MidiDevice* mdAlt = midiPorts[devport].device(); + if(mdAlt && track->recEcho()) + mdAlt->playEvents()->add(event); + } + // Shall we activate meters even while rec echo is off? Sure, why not... + if(event.isNote() && event.dataB() > track->activity()) + track->setActivity(event.dataB()); + } + + // p3.3.25 + // If syncing externally the event time is already in units of ticks, set above. + if(!extsync) + { + // p3.3.35 + //time = tempomap.frame2tick(event.time()); + //event.setTime(time); // set tick time + event.setTime(tempomap.frame2tick(event.time())); // set tick time + } + + // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml) + if (recording) + { + // In these next steps, it is essential to set the recorded event's port + // to the track port so buildMidiEventList will accept it. Even though + // the port may have no device "<none>". + // + if (track->type() == Track::DRUM) + { + // Is it a drum controller event? + if(mc) + { + MidiPlayEvent drumRecEvent = event; + drumRecEvent.setA(ctl | drumRecPitch); + // In this case, preVelo is simply the controller value. + drumRecEvent.setB(preVelo); + drumRecEvent.setPort(port); //rec-event to current port + drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel + rl->add(drumRecEvent); + } + else + { + + MidiPlayEvent drumRecEvent = event; + drumRecEvent.setA(drumRecPitch); + drumRecEvent.setB(preVelo); + // Changed by T356. + // Tested: Events were not being recorded for a drum map entry pointing to a + // different port. This must have been wrong - buildMidiEventList would ignore this. + //drumRecEvent.setPort(devport); + drumRecEvent.setPort(port); //rec-event to current port + + drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel + rl->add(drumRecEvent); + } } - else + else { - - MidiPlayEvent drumRecEvent = event; - drumRecEvent.setA(drumRecPitch); - drumRecEvent.setB(preVelo); - // Changed by T356. - // Tested: Events were not being recorded for a drum map entry pointing to a - // different port. This must have been wrong - buildMidiEventList would ignore this. - //drumRecEvent.setPort(devport); - drumRecEvent.setPort(port); //rec-event to current port - - drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel - rl->add(drumRecEvent); - } - } - else - { - // Restore record-pitch to non-transposed value since we don't want the note transposed twice next - MidiPlayEvent recEvent = event; - if (prePitch) - recEvent.setA(prePitch); - if (preVelo) - recEvent.setB(preVelo); - recEvent.setPort(port); - recEvent.setChannel(track->outChannel()); - - rl->add(recEvent); - } - } - } - } + // Restore record-pitch to non-transposed value since we don't want the note transposed twice next + MidiPlayEvent recEvent = event; + if (prePitch) + recEvent.setA(prePitch); + if (preVelo) + recEvent.setB(preVelo); + recEvent.setPort(port); + recEvent.setChannel(track->outChannel()); + + rl->add(recEvent); + } + } + } + } + } } } // Added by Tim. p3.3.8 diff --git a/muse/muse/midiport.cpp b/muse/muse/midiport.cpp index be310c4f..44ebf6ad 100644 --- a/muse/muse/midiport.cpp +++ b/muse/muse/midiport.cpp @@ -50,7 +50,8 @@ MidiPort::MidiPort() _device = 0; _instrument = 0; _controller = new MidiCtrlValListList(); - + _foundInSongFile = false; + // // create minimum set of managed controllers // to make midi mixer operational @@ -988,3 +989,39 @@ void MidiPort::setNullSendValue(int v) if(_instrument) _instrument->setNullSendValue(v); } + +//--------------------------------------------------------- +// writeRouting // p3.3.50 +//--------------------------------------------------------- + +void MidiPort::writeRouting(int level, Xml& xml) const +{ + // If this device is not actually in use by the song, do not write any routes. + // This prevents bogus routes from being saved and propagated in the med file. + if(!device()) + return; + + QString s; + + for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r) + { + if(r->type == Route::TRACK_ROUTE && !r->name().isEmpty()) + { + //xml.tag(level++, "Route"); + + s = QT_TR_NOOP("Route"); + if(r->channel != -1 && r->channel != 0) + s += QString(QT_TR_NOOP(" channelMask=\"%1\"")).arg(r->channel); // Use new channel mask. + xml.tag(level++, s); + + xml.tag(level, "source mport=\"%d\"/", portno()); + + s = QT_TR_NOOP("dest"); + s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name())); + xml.tag(level, s); + + xml.etag(level--, "Route"); + } + } +} + diff --git a/muse/muse/midiport.h b/muse/muse/midiport.h index 9da238fb..9bdca246 100644 --- a/muse/muse/midiport.h +++ b/muse/muse/midiport.h @@ -11,6 +11,7 @@ #include "globaldefs.h" #include "sync.h" +#include "route.h" class MidiDevice; class MidiInstrument; @@ -33,7 +34,11 @@ class MidiPort { AutomationType _automationType[MIDI_CHANNELS]; // Holds sync settings and detection monitors. MidiSyncInfo _syncInfo; - + // p3.3.50 Just a flag to say the port was found in the song file, even if it has no device right now. + bool _foundInSongFile; + + RouteList _inRoutes, _outRoutes; + void clearDevice(); public: @@ -60,6 +65,8 @@ class MidiPort { bool hasGui() const; int portno() const; + bool foundInSongFile() const { return _foundInSongFile; } + void setFoundInSongFile(bool b) { _foundInSongFile = b; } MidiDevice* device() const { return _device; } const QString& state() const { return _state; } @@ -77,6 +84,12 @@ class MidiPort { int nullSendValue(); void setNullSendValue(int v); + RouteList* inRoutes() { return &_inRoutes; } + RouteList* outRoutes() { return &_outRoutes; } + bool noInRoute() const { return _inRoutes.empty(); } + bool noOutRoute() const { return _outRoutes.empty(); } + void writeRouting(int, Xml&) const; + // send events to midi device and keep track of // device state: void sendGmOn(); diff --git a/muse/muse/mixer/astrip.cpp b/muse/muse/mixer/astrip.cpp index 9ed6f7b9..2a26669f 100644 --- a/muse/muse/mixer/astrip.cpp +++ b/muse/muse/mixer/astrip.cpp @@ -137,7 +137,7 @@ void AudioStrip::configChanged() void AudioStrip::songChanged(int val) { // Is it simply a midi controller value adjustment? Forget it. - if(val == SC_MIDI_CONTROLLER) + if (val == SC_MIDI_CONTROLLER) return; AudioTrack* src = (AudioTrack*)track; @@ -148,8 +148,11 @@ void AudioStrip::songChanged(int val) // p3.3.47 // Update the routing popup menu if anything relevant changed. - if (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) - updateRouteMenus(); + if (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) + { + //updateRouteMenus(); + muse->updateRouteMenus(track, this); // p3.3.50 Use this handy shared routine. + } // Catch when label font, or configuration min slider and meter values change. if (val & SC_CONFIG) @@ -2080,6 +2083,7 @@ void AudioStrip::iRoutePressed() } +#if 0 //--------------------------------------------------------- // updateRouteMenus //--------------------------------------------------------- @@ -2153,6 +2157,7 @@ void AudioStrip::updateRouteMenus() return; } +#endif //--------------------------------------------------------- // routingPopupMenuActivated diff --git a/muse/muse/mixer/astrip.h b/muse/muse/mixer/astrip.h index 29425fc4..82662b2b 100644 --- a/muse/muse/mixer/astrip.h +++ b/muse/muse/mixer/astrip.h @@ -58,7 +58,7 @@ class AudioStrip : public Strip { void updateVolume(); void updatePan(); void updateChannels(); - void updateRouteMenus(); + //void updateRouteMenus(); private slots: void stereoToggled(bool); diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp index eb656d4e..6915fc62 100644 --- a/muse/muse/mixer/mstrip.cpp +++ b/muse/muse/mixer/mstrip.cpp @@ -461,9 +461,11 @@ void MidiStrip::songChanged(int val) } // p3.3.47 Update the routing popup menu if anything relevant changes. - if(gRoutingPopupMenuMaster == this && track && (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) + //if(gRoutingPopupMenuMaster == this && track && (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) + if(val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) // p3.3.50 // Use this handy shared routine. - muse->updateRouteMenus(track); + //muse->updateRouteMenus(track); + muse->updateRouteMenus(track, this); // p3.3.50 } //--------------------------------------------------------- diff --git a/muse/muse/route.cpp b/muse/muse/route.cpp index 81838344..f0442547 100644 --- a/muse/muse/route.cpp +++ b/muse/muse/route.cpp @@ -16,11 +16,15 @@ #include "synth.h" #include "audiodev.h" #include "xml.h" +#include "midiport.h" #include "driver/jackmidi.h" #include "driver/alsamidi.h" //#define ROUTE_DEBUG +//#define ROUTE_MIDIPORT_NAME_PREFIX "MusE MidiPort " +const QString ROUTE_MIDIPORT_NAME_PREFIX = "MusE MidiPort "; + //--------------------------------------------------------- // Route //--------------------------------------------------------- @@ -28,6 +32,7 @@ Route::Route(void* t, int ch) { jackPort = t; + midiPort = -1; channel = ch; channels = -1; remoteChannel = -1; @@ -39,6 +44,7 @@ Route::Route(Track* t, int ch, int chans) //Route::Route(Track* t, int ch) { track = t; + midiPort = -1; channel = ch; channels = chans; remoteChannel = -1; @@ -48,7 +54,8 @@ Route::Route(Track* t, int ch, int chans) //Route::Route(MidiJackDevice* d) Route::Route(MidiDevice* d, int ch) { - device = d; + device = d; + midiPort = -1; channel = ch; channels = -1; remoteChannel = -1; @@ -61,12 +68,22 @@ Route::Route(MidiDevice* d, int ch) if(d->deviceType() == MidiDevice::ALSA_MIDI) type = ALSA_MIDI_ROUTE; */ - type = MIDI_DEVICE_ROUTE; + type = MIDI_DEVICE_ROUTE; +} + +Route::Route(int port, int ch) // p3.3.49 +{ + track = 0; + midiPort = port; + channel = ch; + channels = -1; + remoteChannel = -1; + type = MIDI_PORT_ROUTE; } //Route::Route(const QString& s, bool dst, int ch) Route::Route(const QString& s, bool dst, int ch, int rtype) - { + { //Route node(name2route(s, dst)); Route node(name2route(s, dst, rtype)); channel = node.channel; @@ -78,10 +95,16 @@ Route::Route(const QString& s, bool dst, int ch, int rtype) remoteChannel = node.remoteChannel; type = node.type; if(type == TRACK_ROUTE) + { track = node.track; + midiPort = -1; + } else if(type == JACK_ROUTE) + { jackPort = node.jackPort; + midiPort = -1; + } /* else if (type == JACK_MIDI_ROUTE) @@ -91,13 +114,23 @@ Route::Route(const QString& s, bool dst, int ch, int rtype) device = node.device; */ else - if (type == MIDI_DEVICE_ROUTE) - device = node.device; - } + if(type == MIDI_DEVICE_ROUTE) + { + device = node.device; + midiPort = -1; + } + else + if(type == MIDI_PORT_ROUTE) // p3.3.49 + { + track = 0; + midiPort = node.midiPort; // + } + } Route::Route() { track = 0; + midiPort = -1; channel = -1; channels = -1; remoteChannel = -1; @@ -143,6 +176,13 @@ void addRoute(Route src, Route dst) //exit(-1); return; } + if (dst.channel < 0) + { + fprintf(stderr, "addRoute: source is jack, dest:%s is track but invalid channel:%d\n", dst.track->name().latin1(), dst.channel); + //exit(-1); + return; + } + //src.channel = src.dstChannel = dst.channel; src.channel = dst.channel; //src.channels = dst.channels = 1; @@ -165,8 +205,18 @@ void addRoute(Route src, Route dst) else //if (dst.type == Route::JACK_MIDI_ROUTE) if (dst.type == Route::MIDI_DEVICE_ROUTE) + //if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { + //MidiDevice *md = midiPorts[dst.midiPort].device(); + //if(dst.device->deviceType() == MidiDevice::JACK_MIDI) + //if(!md) + //{ + // fprintf(stderr, "addRoute: source is Jack, but no destination port device\n"); + // return; + //} + if(dst.device->deviceType() == MidiDevice::JACK_MIDI) + //if(md->deviceType() == MidiDevice::JACK_MIDI) { src.channel = dst.channel; //src.channel = -1; @@ -222,6 +272,13 @@ void addRoute(Route src, Route dst) // exit(-1); return; } + if (src.channel < 0) + { + fprintf(stderr, "addRoute: destination is jack, source:%s is track but invalid channel:%d\n", src.track->name().latin1(), src.channel); + // exit(-1); + return; + } + RouteList* outRoutes = src.track->outRoutes(); //dst.channel = dst.dstChannel = src.channel; dst.channel = src.channel; @@ -284,8 +341,145 @@ void addRoute(Route src, Route dst) return; } } + else if(src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + if(dst.type != Route::TRACK_ROUTE) + { + fprintf(stderr, "addRoute: source is midi port:%d, but destination is not track\n", src.midiPort); + return; + } + if(dst.channel < 1 || dst.channel >= (1 << MIDI_CHANNELS)) + { + fprintf(stderr, "addRoute: source is midi port:%d, but destination channel mask:%d out of range\n", src.midiPort, dst.channel); + return; + } + + //MidiDevice *md = midiPorts[src.midiPort].device(); + //if(!md) + //{ + // fprintf(stderr, "addRoute: source is midi port, but no destination port device\n"); + // return; + //} + + MidiPort *mp = &midiPorts[src.midiPort]; + + src.channel = dst.channel; + RouteList* outRoutes = mp->outRoutes(); + //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + iRoute ir = outRoutes->begin(); // p3.3.50 + for ( ; ir != outRoutes->end(); ++ir) + { + //if (*i == dst) // route already there + if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // p3.3.50 Does a route to the track exist? + { + //#ifdef ROUTE_DEBUG + //fprintf(stderr, "addRoute: src midi port:%d dst track:%s route already exists.\n", src.midiPort, dst.track->name().latin1()); + //#endif + ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + break; + + //return; + } + } + #ifdef ROUTE_DEBUG + fprintf(stderr, "addRoute: src midi port:%d dst track name:%s pushing dst and src routes\n", src.midiPort, dst.track->name().latin1()); + #endif + + if(ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + outRoutes->push_back(dst); + + RouteList* inRoutes = dst.track->inRoutes(); + + // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. + ir = inRoutes->begin(); + for ( ; ir != inRoutes->end(); ++ir) + { + if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // p3.3.50 Does a route to the midi port exist? + { + ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + break; + } + } + + if(ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + inRoutes->push_back(src); + } + else if(dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + if(src.type != Route::TRACK_ROUTE) + { + fprintf(stderr, "addRoute: destination is midi port:%d, but source is not track\n", dst.midiPort); + return; + } + if(src.channel < 1 || src.channel >= (1 << MIDI_CHANNELS)) + { + fprintf(stderr, "addRoute: destination is midi port:%d, but source channel mask:%d out of range\n", dst.midiPort, src.channel); + return; + } + + + //MidiDevice *md = midiPorts[dst.midiPort].device(); + //if(!md) + //{ + // fprintf(stderr, "addRoute: dst is midi port, but no destination port device\n"); + // return; + //} + + dst.channel = src.channel; + RouteList* outRoutes = src.track->outRoutes(); + + //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + iRoute ir = outRoutes->begin(); // p3.3.50 + for ( ; ir != outRoutes->end(); ++ir) + { + //if (*i == dst) // route already there + if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort) // p3.3.50 Does a route to the midi port exist? + { + //#ifdef ROUTE_DEBUG + //fprintf(stderr, "addRoute: dst midi port:%d src track:%s route already exists.\n", dst.midiPort, src.track->name().latin1()); + //#endif + //return; + + ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + break; + } + } + + if(ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + outRoutes->push_back(dst); + + MidiPort *mp = &midiPorts[dst.midiPort]; + + #ifdef ROUTE_DEBUG + fprintf(stderr, "addRoute: src track:%s dst midi port:%d pushing dst and src routes\n", src.track->name().latin1(), dst.midiPort); + #endif + RouteList* inRoutes = mp->inRoutes(); + + // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. + ir = inRoutes->begin(); + for ( ; ir != inRoutes->end(); ++ir) + { + if (ir->type == Route::TRACK_ROUTE && ir->track == src.track) // p3.3.50 Does a route to the track exist? + { + ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + break; + } + } + + if(ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + inRoutes->push_back(src); + //inRoutes->insert(inRoutes->begin(), src); + } else { + if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 + { + fprintf(stderr, "addRoute: source and destination are not track routes\n"); + return; + } + + // Removed p3.3.49 + /* //if ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) if(src.type == Route::MIDI_DEVICE_ROUTE) { @@ -315,10 +509,12 @@ void addRoute(Route src, Route dst) inRoutes->push_back(src); } else + */ + { - if(dst.type == Route::MIDI_DEVICE_ROUTE) + ///if(dst.type == Route::MIDI_DEVICE_ROUTE) // Removed p3.3.49 //{ - dst.channel = src.channel; + /// dst.channel = src.channel; //src.channel = src.dstChannel = dst.dstChannel = dst.channel; //src.channels = dst.channels = 1; //} @@ -339,8 +535,8 @@ void addRoute(Route src, Route dst) src.channel = 0; if(src.channels == -1) src.channels = src.track->channels(); - if(dst.type == Route::TRACK_ROUTE) - { + //if(dst.type == Route::TRACK_ROUTE) // p3.3.49 Removed + //{ //if(dst.channel == -1) // dst.channel = 0; //if(dst.channels == -1) @@ -349,18 +545,16 @@ void addRoute(Route src, Route dst) dst.channel = src.channel; dst.channels = src.channels; dst.remoteChannel = src.remoteChannel; - } + //} } - /* - if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH) - { - if(dst.channel == -1) - dst.channel = 0; - if(dst.channels == -1) + //if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH) + //{ + // if(dst.channel == -1) + // dst.channel = 0; + // if(dst.channels == -1) // Yes, that's correct: dst channels = src track channels. - dst.channels = src.track->channels(); - } - */ + // dst.channels = src.track->channels(); + //} for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { @@ -389,6 +583,9 @@ void addRoute(Route src, Route dst) } outRoutes->push_back(dst); RouteList* inRoutes; + + // Removed p3.3.49 + /* //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) if(dst.type == Route::MIDI_DEVICE_ROUTE) { @@ -398,6 +595,8 @@ void addRoute(Route src, Route dst) inRoutes = dst.device->inRoutes(); } else + */ + { #ifdef ROUTE_DEBUG //fprintf(stderr, "addRoute: src track ch:%d chs:%d dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().latin1()); @@ -538,8 +737,114 @@ void removeRoute(Route src, Route dst) return; } } + else if(src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + if(dst.type != Route::TRACK_ROUTE) + { + fprintf(stderr, "removeRoute: source is midi port:%d, but destination is not track\n", src.midiPort); + return; + } + + if(src.isValid()) + { + MidiPort *mp = &midiPorts[src.midiPort]; + RouteList* outRoutes = mp->outRoutes(); + for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + { + //if (*i == dst) + if (i->type == Route::TRACK_ROUTE && i->track == dst.track) // p3.3.50 Is there a route to the track? + { + i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. + if(i->channel == 0) // Only if there are no channel bits set, erase the route. + outRoutes->erase(i); + + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... + } + } + } + else + printf("removeRoute: source is midi port:%d but invalid\n", src.midiPort); + + if(dst.isValid()) + { + RouteList* inRoutes = dst.track->inRoutes(); + for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) + { + //if (*i == src) + if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort) // p3.3.50 Is there a route to the midi port? + { + i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. + if(i->channel == 0) // Only if there are no channel bits set, erase the route. + inRoutes->erase(i); + + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... + } + } + } + else + printf("removeRoute: source is midi port:%d but destination track invalid\n", src.midiPort); + } + else if(dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + if(src.type != Route::TRACK_ROUTE) + { + fprintf(stderr, "removeRoute: destination is midi port:%d, but source is not track\n", dst.midiPort); + return; + } + + if(src.isValid()) + { + RouteList* outRoutes = src.track->outRoutes(); + for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + { + //if (*i == dst) + if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort) // p3.3.50 Is there a route to the midi port? + { + i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. + if(i->channel == 0) // Only if there are no channel bits set, erase the route. + outRoutes->erase(i); + + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... + } + } + } + else + printf("removeRoute: destination is midi port:%d but source track is invalid\n", dst.midiPort); + + if(dst.isValid()) + { + MidiPort *mp = &midiPorts[src.midiPort]; + RouteList* inRoutes = mp->inRoutes(); + for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) + { + //if (*i == src) + if (i->type == Route::TRACK_ROUTE && i->track == src.track) // p3.3.50 Is there a route to the track? + { + i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. + if(i->channel == 0) // Only if there are no channel bits set, erase the route. + inRoutes->erase(i); + + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... + } + } + } + else + printf("removeRoute: destination is midi port:%d but invalid\n", dst.midiPort); + } else { + if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 + { + fprintf(stderr, "removeRoute: source and destination are not tracks\n"); + return; + } + + // Removed p3.3.49 + /* //if((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) if(src.type == Route::MIDI_DEVICE_ROUTE) { @@ -572,6 +877,8 @@ void removeRoute(Route src, Route dst) printf("removeRoute: source is midi but destination invalid\n"); } else + */ + { if(src.isValid()) { @@ -590,10 +897,15 @@ void removeRoute(Route src, Route dst) if(dst.isValid()) { RouteList* inRoutes; + //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) + // Removed p3.3.49 + /* if (dst.type == Route::MIDI_DEVICE_ROUTE) inRoutes = dst.device->inRoutes(); else + */ + inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { @@ -639,36 +951,6 @@ QString Route::name() const } */ - /* - if (type == ALSA_MIDI_ROUTE) - { - if(device) - // TODO - //snd_seq_addr_t - return device->name(); - else - return QWidget::tr("None"); - } - else - if (type == JACK_MIDI_ROUTE) - { - if(device) - { - return audioDevice->portName(device->clientPort()); - //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(device); - //if(jmd) - // return audioDevice->portName(jmd->clientJackPort()); - //else - //{ - // fprintf(stderr, "Route::name Route is Jack midi but device is not a MidiJackDevice\n"); - // return QWidget::tr("None"); - //} - } - else - return QWidget::tr("None"); - } - */ - if(type == MIDI_DEVICE_ROUTE) { if(device) @@ -689,6 +971,11 @@ QString Route::name() const return audioDevice->portName(jackPort); } else + if(type == MIDI_PORT_ROUTE) // p3.3.49 + { + return ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort); + } + else //return s + track2name(track); return track2name(track); } @@ -730,99 +1017,29 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) MidiTrack* track = (MidiTrack*)*i; if(track->name() == s) return Route(track, channel); - //return Route(track, channel, 1); } else { AudioTrack* track = (AudioTrack*)*i; if(track->name() == s) return Route(track, channel); - //return Route(track, channel, 1); - //return Route(track, channel, track->channels()); } } for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) { if((*i)->name() == s) - //if (jmd->name() == rn) return Route(*i, channel); - - /* - MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); - if(jmd) - { - if(jmd->name() == s) - //if (jmd->name() == rn) - return Route(jmd); - } - MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); - if(amd) - { - // TODO - if(amd->name() == s) - //if (amd->name() == rn) - return Route(amd); - } - */ } - -/* - } - else - { - if(checkAudioDevice()) - { - void* p = audioDevice->findPort(s.latin1()); - if(p) - return Route(p, channel); - } - - TrackList* tl = song->tracks(); - for(iTrack i = tl->begin(); i != tl->end(); ++i) + // p3.3.49 + if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX) { - if((*i)->isMidiTrack()) - { - MidiTrack* track = (MidiTrack*)*i; - if(track->name() == s) - return Route(track, channel); - } - else - { - AudioTrack* track = (AudioTrack*)*i; - if(track->name() == s) - return Route(track, channel); - } + bool ok = false; + int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok); + if(ok) + return Route(port, channel); } - - for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) - { - if((*i)->name() == s) - //if (jmd->name() == rn) - return Route(*i, channel); -*/ - - /* - MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); - if(jmd) - { - if(jmd->name() == s) - //if (jmd->name() == rn) - return Route(jmd); - } - MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); - if(amd) - { - // TODO - if(amd->name() == s) - //if (amd->name() == rn) - return Route(amd); - } - */ -// } -// } - } else { @@ -889,75 +1106,17 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) return Route(p, channel); } } - - -/* - } - else - { - if(rtype == Route::TRACK_ROUTE) - { - TrackList* tl = song->tracks(); - for(iTrack i = tl->begin(); i != tl->end(); ++i) - { - if((*i)->isMidiTrack()) - { - MidiTrack* track = (MidiTrack*)*i; - if (track->name() == s) - return Route(track, channel); - } - else - { - AudioTrack* track = (AudioTrack*)*i; - if(track->name() == s) - return Route(track, channel); - } - } - } else - if((rtype == Route::JACK_MIDI_ROUTE) || (rtype == Route::ALSA_MIDI_ROUTE)) - { - for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) + if(rtype == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX) { - if((*i)->name() == s) - //if (jmd->name() == rn) - return Route(*i, channel); -*/ - - /* - MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); - if(jmd) - { - if(jmd->name() == s) - //if (jmd->name() == rn) - return Route(jmd); - } - MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); - if(amd) - { - // TODO - if(amd->name() == s) - //if (amd->name() == rn) - return Route(amd); - } - */ - -/* + bool ok = false; + int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok); + if(ok) + return Route(port, channel); } - } - else - if(rtype == JACK_ROUTE) - { - if(checkAudioDevice()) - { - void* p = audioDevice->findPort(s.latin1()); - if(p) - return Route(p, channel); - } } - } -*/ - } printf(" name2route: <%s> not found\n", rn.latin1()); @@ -1053,6 +1212,19 @@ bool checkRoute(const QString& s, const QString& d) else return false; } + else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + { + RouteList* outRoutes = midiPorts[src.midiPort].outRoutes(); + for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + { + if (*i == dst) { // route already there + return false; + } + } + } + //else if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + //{ + //} else { //RouteList* outRoutes = ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) ? @@ -1077,12 +1249,8 @@ void Route::read(Xml& xml) { QString s; int dtype = MidiDevice::ALSA_MIDI; - - //channel = -1; - //channels = -1; - //remoteChannel = -1; - type = Route::TRACK_ROUTE; - track = 0; + int port = -1; // p3.3.49 + unsigned char rtype = Route::TRACK_ROUTE; for (;;) { @@ -1101,79 +1269,92 @@ void Route::read(Xml& xml) printf("Route::read(): attribute:%s\n", tag.latin1()); #endif if(tag == "type") - type = xml.s2().toInt(); + rtype = xml.s2().toInt(); else if(tag == "devtype") { dtype = xml.s2().toInt(); - type = Route::MIDI_DEVICE_ROUTE; + rtype = Route::MIDI_DEVICE_ROUTE; } - //else - //if(tag == "channel") - // channel = xml.s2().toInt(); - //else - //if(tag == "channels") - // channels = xml.s2().toInt(); - //else - //if(tag == "remch") - // remoteChannel = xml.s2().toInt(); else if(tag == "name") s = xml.s2(); + else + if(tag == "mport") // p3.3.49 + { + port = xml.s2().toInt(); + rtype = Route::MIDI_PORT_ROUTE; + } else printf("Route::read(): unknown attribute:%s\n", tag.latin1()); break; case Xml::TagEnd: #ifdef ROUTE_DEBUG - printf("Route::read(): tag end type:%d channel:%d name:%s\n", type, channel, s.latin1()); + printf("Route::read(): tag end type:%d channel:%d name:%s\n", rtype, channel, s.latin1()); #endif + if(rtype == MIDI_PORT_ROUTE) // p3.3.49 + { + if(port >= 0 && port < MIDI_PORTS) + { + type = rtype; + midiPort = port; + } + else + printf("Route::read(): midi port <%d> out of range\n", port); + } + else if(!s.isEmpty()) { - if(type == TRACK_ROUTE) + if(rtype == TRACK_ROUTE) { - track = 0; TrackList* tl = song->tracks(); - for (iTrack i = tl->begin(); i != tl->end(); ++i) + iTrack i = tl->begin(); + for ( ; i != tl->end(); ++i) { Track* t = *i; if (t->name() == s) { track = t; + type = rtype; break; } } - if(track == 0) + if(i == tl->end()) printf("Route::read(): track <%s> not found\n", s.latin1()); } else - if(type == JACK_ROUTE) + if(rtype == JACK_ROUTE) { - jackPort = audioDevice->findPort(s); - if(jackPort == 0) + void* jport = audioDevice->findPort(s); + if(jport == 0) printf("Route::read(): jack port <%s> not found\n", s.latin1()); + else + { + jackPort = jport; + type = rtype; + } } else - //if((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE)) - if(type == MIDI_DEVICE_ROUTE) + if(rtype == MIDI_DEVICE_ROUTE) { - device = 0; - for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) + iMidiDevice imd = midiDevices.begin(); + for( ; imd != midiDevices.end(); ++imd) { MidiDevice* md = *imd; - //if(md->name() == s) if(md->name() == s && md->deviceType() == dtype) { // p3.3.45 // We found a device, but if it is not in use by the song (port is -1), ignore it. - // This prevents loading and propogation of bogus routes in the med file. + // This prevents loading and propagation of bogus routes in the med file. if(md->midiPort() == -1) break; device = md; + type = rtype; break; } } - if(device == 0) + if(imd == midiDevices.end()) printf("Route::read(): midi device <%s> not found\n", s.latin1()); } } @@ -1193,9 +1374,9 @@ void Song::readRoute(Xml& xml) { QString src; QString dst; - int ch = -1; - int chs = -1; - int remch = -1; + int ch = -1; + int chs = -1; + int remch = -1; Route sroute, droute; @@ -1244,7 +1425,10 @@ void Song::readRoute(Xml& xml) else if(tag == "remch") remch = xml.s2().toInt(); - else + else + if(tag == "channelMask") // p3.3.50 New channel mask for midi port-track routes. + ch = xml.s2().toInt(); + else printf("Song::readRoute(): unknown attribute:%s\n", tag.latin1()); break; case Xml::TagEnd: @@ -1261,8 +1445,48 @@ void Song::readRoute(Xml& xml) // Support new routes. if(sroute.isValid() && droute.isValid()) { - //printf("adding new route...\n"); - addRoute(sroute, droute); + // p3.3.49 Support pre- 1.1-RC2 midi-device-to-track routes. Obsolete. Replaced with midi port routes. + if(sroute.type == Route::MIDI_DEVICE_ROUTE && droute.type == Route::TRACK_ROUTE) + { + if(sroute.device->midiPort() >= 0 && sroute.device->midiPort() < MIDI_PORTS + && ch >= 0 && ch < MIDI_CHANNELS) // p3.3.50 + { + sroute.midiPort = sroute.device->midiPort(); + sroute.device = 0; + sroute.type = Route::MIDI_PORT_ROUTE; + + sroute.channel = 1 << ch; // p3.3.50 Convert to new bit-wise channel mask. + droute.channel = sroute.channel; + + addRoute(sroute, droute); + } + else + printf(" Warning - device:%s to track route, no device midi port or chan:%d out of range. Ignoring route!\n", + sroute.device->name().latin1(), ch); + } + else if(sroute.type == Route::TRACK_ROUTE && droute.type == Route::MIDI_DEVICE_ROUTE) + { + if(droute.device->midiPort() >= 0 && droute.device->midiPort() < MIDI_PORTS + && ch >= 0 && ch < MIDI_CHANNELS) // p3.3.50 + { + droute.midiPort = droute.device->midiPort(); + droute.device = 0; + droute.type = Route::MIDI_PORT_ROUTE; + + droute.channel = 1 << ch; // p3.3.50 Convert to new bit-wise channel mask. + sroute.channel = droute.channel; + + addRoute(sroute, droute); + } + else + printf(" Warning - track to device:%s route, no device midi port or chan:%d out of range. Ignoring route!\n", + droute.device->name().latin1(), ch); + } + else + { + //printf("adding new route...\n"); + addRoute(sroute, droute); + } } else printf(" Warning - route invalid. Ignoring route!\n"); @@ -1281,7 +1505,12 @@ void Song::readRoute(Xml& xml) void RouteList::removeRoute(const Route& r) { + //printf("RouteList::removeRoute:\n"); + //r.dump(); + //printf("Searching routes:\n"); + for (iRoute i = begin(); i != end(); ++i) { + //i->dump(); if (r == *i) { erase(i); return; @@ -1310,6 +1539,11 @@ void Route::dump() const if(checkAudioDevice()) printf("Route dump: jack audio port <%s> channel %d\n", audioDevice->portName(jackPort).latin1(), channel); } + else + if (type == MIDI_PORT_ROUTE) // p3.3.49 + { + printf("Route dump: midi port <%d> channel mask %d\n", midiPort, channel); + } else if (type == MIDI_DEVICE_ROUTE) { @@ -1335,24 +1569,6 @@ void Route::dump() const printf("channel:%d\n", channel); } - /* - else - if (type == JACK_MIDI_ROUTE) - { - if (!checkAudioDevice()) return; - printf("Route dump: jMidiPort <%s>\n", - audioDevice->portName(device->clientPort()).latin1()); - } - else - if (type == ALSA_MIDI_ROUTE) - { - // TODO - //if (!checkAudioDevice()) return; - //printf("Route dump: aMidiPort <%s>\n", - // audioDevice->portName(device->clientJackPort()).latin1()); - printf("Route dump: aMidiPort\n"); - } - */ else printf("Route dump: unknown route type:%d\n", type); } @@ -1363,40 +1579,20 @@ void Route::dump() const bool Route::operator==(const Route& a) const { + //if (type == MIDI_PORT_ROUTE) // p3.3.50 + //{ + // Use new channel mask. True if all the bits in a.channel are contained in this route's channel. + // Hmm, not commutative... Two such routes are equal if _____ what? ... Code-specific for now. + // return midiPort == a.midiPort && (channel & a.channel) == a.channel; + //} + //else + if ((type == a.type) && (channel == a.channel)) //if (type == a.type) { if (type == TRACK_ROUTE) { - //return track == a.track; - //return track == a.track && remoteChannel == a.remoteChannel; return track == a.track && channels == a.channels && remoteChannel == a.remoteChannel; - - /* - if(a.track == track && a.remoteChannel == remoteChannel) - { - int tcompch = rt.channel; - if(tcompch == -1) - tcompch = 0; - int tcompchs = rt.channels; - if(tcompchs == -1) - tcompchs = isOutput ? t->channels() : track->channels(); - - int compch = ir->channel; - if(compch == -1) - compch = 0; - int compchs = ir->channels; - if(compchs == -1) - compchs = isOutput ? t->channels() : ir->track->channels(); - - if(compch == tcompch && compchs == tcompchs) - { - chpup->setItemChecked(id, true); - break; - } - } - */ - } else if(channel == a.channel) @@ -1407,9 +1603,13 @@ bool Route::operator==(const Route& a) const return audioDevice->portName(jackPort) == audioDevice->portName(a.jackPort); } else + if (type == MIDI_PORT_ROUTE) // p3.3.49 + { + return midiPort == a.midiPort; + } + else if (type == MIDI_DEVICE_ROUTE) { - //if(device) if(device && a.device && device->deviceType() == a.device->deviceType()) { if(device->deviceType() == MidiDevice::JACK_MIDI) @@ -1426,23 +1626,6 @@ bool Route::operator==(const Route& a) const return device->name() == a.device->name(); } } - - /* - if (type == JACK_MIDI_ROUTE) - { - if (!checkAudioDevice()) return false; - return audioDevice->portName(device->clientPort()) == audioDevice->portName(a.device->clientPort()); - } - else - if (type == ALSA_MIDI_ROUTE) - { - // TODO - //if (!checkAudioDevice()) return false; - //return audioDevice->portName(device->clientJackPort()) == audioDevice->portName(a.device->clientJackPort()); - //return device->name() == a.device->name(); - return device->clientPort() == a.device->clientPort() && (channel == a.channel); - } - */ } } return false; diff --git a/muse/muse/route.h b/muse/muse/route.h index d8217207..4cacac88 100644 --- a/muse/muse/route.h +++ b/muse/muse/route.h @@ -9,14 +9,13 @@ #ifndef __ROUTE_H__ #define __ROUTE_H__ -//#include <alsa/asoundlib.h> #include <vector> #include <map> +#include "globaldefs.h" + class QString; -//class AudioTrack; class Track; -//class MidiJackDevice; class MidiDevice; class Xml; @@ -24,25 +23,27 @@ class Xml; // Route //--------------------------------------------------------- -//enum { TRACK_ROUTE=0, JACK_ROUTE=1 }; - struct Route { - //enum { TRACK_ROUTE=0, JACK_ROUTE=1, JACK_MIDI_ROUTE=2, ALSA_MIDI_ROUTE=3 }; - enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2 }; + enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2, MIDI_PORT_ROUTE=3 }; // p3.3.49 union { //AudioTrack* track; Track* track; //MidiJackDevice* device; - MidiDevice* device; + MidiDevice* device; void* jackPort; }; + int midiPort; // p3.3.49 Midi port number. Best not to put this in the union to avoid problems? + //snd_seq_addr_t alsaAdr; // Starting source channel (of the owner of this route). Normally zero for mono or stereo tracks, higher for multi-channel tracks. - int channel; - // Number of channels being routed. + // p3.3.50 NOTICE: channel is now a bit-wise channel mask, for MidiPort <-> MidiTrack routes. + // This saves many routes: Instead of one route per channel as before, there can now be only one single route with a channel mask, + // for each MidiPort <-> MidiTrack combination. + int channel; + // Number of (audio) channels being routed. int channels; // Allow for multi-channel syntis to feed to/from regular tracks, and to feed one to another. @@ -50,26 +51,21 @@ struct Route { // If a synti is feeding to/from another synti, this is not used and individual channels are routed using channel instead. int remoteChannel; - unsigned char type; // 0 - track, 1 - jackPort, 2 - jack midi device, 3 - alsa midi device + unsigned char type; // 0 - track, 1 - jackPort, 2 - midi device, 3 - midi port Route(void* t, int ch=-1); - //Route(AudioTrack* t, int ch); - //Route(Track* t, int ch); Route(Track* t, int ch = -1, int chans = -1); - //Route(Track* t, int ch = -1); - - //Route(MidiJackDevice* d); - Route(MidiDevice* d, int ch); - //Route(const QString&, bool dst, int ch); + Route(MidiDevice* d, int ch); + Route(int port, int ch); // p3.3.49 Route(const QString&, bool dst, int ch, int rtype = -1); Route(); + QString name() const; bool operator==(const Route& a) const; bool isValid() const { - //return ((type == 0) && (track != 0)) || ((type == 1) && (jackPort != 0)); return ((type == TRACK_ROUTE) && (track != 0)) || ((type == JACK_ROUTE) && (jackPort != 0)) || - //(((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE)) && (device != 0)); - ((type == MIDI_DEVICE_ROUTE) && (device != 0)); + ((type == MIDI_DEVICE_ROUTE) && (device != 0)) || + ((type == MIDI_PORT_ROUTE) && (midiPort >= 0) && (midiPort < MIDI_PORTS)); // p3.3.49 } void read(Xml& xml); void dump() const; @@ -89,7 +85,6 @@ typedef RouteList::const_iterator ciRoute; extern void addRoute(Route, Route); extern void removeRoute(Route, Route); -//extern Route name2route(const QString&, bool dst); extern Route name2route(const QString&, bool dst, int rtype = -1); extern bool checkRoute(const QString&, const QString&); @@ -97,12 +92,6 @@ extern bool checkRoute(const QString&, const QString&); // RouteMenuMap //--------------------------------------------------------- -//struct TRouteMenuMap{ -// Route r; -// }; -//typedef std::map<int, TRouteMenuMap, std::less<int> >::iterator iRouteMenuMap; -//typedef std::map<int, TRouteMenuMap, std::less<int> >::const_iterator ciRouteMenuMap; -//typedef std::map<int, TRouteMenuMap, std::less<int> > RouteMenuMap; typedef std::map<int, Route, std::less<int> >::iterator iRouteMenuMap; typedef std::map<int, Route, std::less<int> >::const_iterator ciRouteMenuMap; typedef std::map<int, Route, std::less<int> > RouteMenuMap; diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index 80099774..129306d6 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -1960,8 +1960,17 @@ void Song::clear(bool signal) // p3.3.45 Clear all midi port devices. for(int i = 0; i < MIDI_PORTS; ++i) + { + // p3.3.50 Since midi ports are not deleted, clear all midi port in/out routes. They point to non-existant tracks now. + midiPorts[i].inRoutes()->clear(); + midiPorts[i].outRoutes()->clear(); + + // p3.3.50 Reset this. + midiPorts[i].setFoundInSongFile(false); + // This will also close the device. midiPorts[i].setMidiDevice(0); + } _synthIs.clearDelete(); @@ -3162,8 +3171,12 @@ void Song::insertTrack2(Track* track, int idx) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->outRoutes()->push_back(*r); + //if(r->track == track) + // r->track->outRoutes()->push_back(*r); + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->outRoutes()->push_back(src); } } else if (track->type() == Track::AUDIO_INPUT) @@ -3171,8 +3184,29 @@ void Song::insertTrack2(Track* track, int idx) const RouteList* rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->inRoutes()->push_back(*r); + //if(r->track == track) + // r->track->inRoutes()->push_back(*r); + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->inRoutes()->push_back(src); + } + } + else if (track->isMidiTrack()) // p3.3.50 + { + const RouteList* rl = track->inRoutes(); + for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + //printf("Song::insertTrack2 %s in route port:%d\n", track->name().latin1(), r->midiPort); // p3.3.50 + Route src(track, r->channel); + midiPorts[r->midiPort].outRoutes()->push_back(src); + } + rl = track->outRoutes(); + for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + //printf("Song::insertTrack2 %s out route port:%d\n", track->name().latin1(), r->midiPort); // p3.3.50 + Route src(track, r->channel); + midiPorts[r->midiPort].inRoutes()->push_back(src); } } else @@ -3180,14 +3214,22 @@ void Song::insertTrack2(Track* track, int idx) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->outRoutes()->push_back(*r); + //if(r->track == track) + // r->track->outRoutes()->push_back(*r); + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->outRoutes()->push_back(src); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->inRoutes()->push_back(*r); + //if(r->track == track) + // r->track->inRoutes()->push_back(*r); + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->inRoutes()->push_back(src); } } @@ -3273,6 +3315,8 @@ void Song::removeTrack1(Track* track) void Song::removeTrack2(Track* track) { + //printf("Song::removeTrack2 track:%s\n", track->name().latin1()); // p3.3.50 + switch(track->type()) { case Track::MIDI: case Track::DRUM: @@ -3352,8 +3396,13 @@ void Song::removeTrack2(Track* track) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->outRoutes()->removeRoute(*r); + //if(r->track == track) + // r->track->outRoutes()->removeRoute(*r); + //printf("Song::removeTrack2 %s audio out track:%s\n", track->name().latin1(), r->track->name().latin1()); // p3.3.50 + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->outRoutes()->removeRoute(src); } } else if (track->type() == Track::AUDIO_INPUT) @@ -3361,8 +3410,30 @@ void Song::removeTrack2(Track* track) const RouteList* rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->inRoutes()->removeRoute(*r); + //if(r->track == track) + // r->track->inRoutes()->removeRoute(*r); + //printf("Song::removeTrack2 %s audio in track:%s\n", track->name().latin1(), r->track->name().latin1()); // p3.3.50 + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->inRoutes()->removeRoute(src); + } + } + else if (track->isMidiTrack()) // p3.3.50 + { + const RouteList* rl = track->inRoutes(); + for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + //printf("Song::removeTrack2 %s in route port:%d\n", track->name().latin1(), r->midiPort); // p3.3.50 + Route src(track, r->channel); + midiPorts[r->midiPort].outRoutes()->removeRoute(src); + } + rl = track->outRoutes(); + for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + //printf("Song::removeTrack2 %s out route port:%d\n", track->name().latin1(), r->midiPort); // p3.3.50 + Route src(track, r->channel); + midiPorts[r->midiPort].inRoutes()->removeRoute(src); } } else @@ -3370,14 +3441,24 @@ void Song::removeTrack2(Track* track) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->outRoutes()->removeRoute(*r); + //if(r->track == track) + // r->track->outRoutes()->removeRoute(*r); + //printf("Song::removeTrack2 %s in route track:%s\n", track->name().latin1(), r->track->name().latin1()); // p3.3.50 + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->outRoutes()->removeRoute(src); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(r->track == track) - r->track->inRoutes()->removeRoute(*r); + //if(r->track == track) + // r->track->inRoutes()->removeRoute(*r); + //printf("Song::removeTrack2 %s out route track:%s\n", track->name().latin1(), r->track->name().latin1()); // p3.3.50 + // p3.3.50 + Route src(track, r->channel, r->channels); + src.remoteChannel = r->remoteChannel; + r->track->inRoutes()->removeRoute(src); } } diff --git a/muse/muse/songfile.cpp b/muse/muse/songfile.cpp index 42b41a92..b13cb07a 100644 --- a/muse/muse/songfile.cpp +++ b/muse/muse/songfile.cpp @@ -1449,7 +1449,7 @@ void Song::write(int level, Xml& xml) const (*i)->writeRouting(level, xml); } - // Write Jack midi routing. + // Write midi device routing. for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) { //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i); //if (!mjd) @@ -1458,6 +1458,11 @@ void Song::write(int level, Xml& xml) const (*i)->writeRouting(level, xml); } + // p3.3.49 Write midi port routing. + for (int i = 0; i < MIDI_PORTS; ++i) { + midiPorts[i].writeRouting(level, xml); + } + tempomap.write(level, xml); sigmap.write(level, xml); _markerList->write(level, xml); diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp index 97fc23be..e2d23861 100644 --- a/muse/muse/track.cpp +++ b/muse/muse/track.cpp @@ -19,6 +19,7 @@ #include "drummap.h" #include "audio.h" #include "globaldefs.h" +#include "route.h" unsigned int Track::_soloRefCnt = 0; Track* Track::_tmpSoloChainTrack = 0; @@ -454,52 +455,63 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask) //if(!portmask || !chanmask) // return; - RouteList* rl = inRoutes(); + //RouteList* rl = inRoutes(); bool changed = false; for(int port = 0; port < 32; ++port) // 32 is the old maximum number of ports. { + // p3.3.50 If the port was not used in the song file to begin with, just ignore it. + // This saves from having all of the first 32 ports' channels connected. + if(!midiPorts[port].foundInSongFile()) + continue; + //if(!(portmask & (1 << port))) // continue; - MidiPort* mp = &midiPorts[port]; - MidiDevice* md = mp->device(); - if(!md) - continue; + // p3.3.50 Removed. Allow to connect to port with no device so user can change device later. + //MidiPort* mp = &midiPorts[port]; + //MidiDevice* md = mp->device(); + //if(!md) + // continue; - for(int ch = 0; ch < MIDI_CHANNELS; ++ch) - { + //for(int ch = 0; ch < MIDI_CHANNELS; ++ch) // p3.3.50 Removed. + //{ //if(!(chanmask & (1 << ch))) // continue; - Route aRoute(md, ch); - Route bRoute(this, ch); + //Route aRoute(md, ch); + //Route bRoute(this, ch); + Route aRoute(port, chanmask); // p3.3.50 + Route bRoute(this, chanmask); - iRoute iir = rl->begin(); - for(; iir != rl->end(); ++iir) - { - if(*iir == aRoute) - break; - } + // p3.3.50 Removed. + //iRoute iir = rl->begin(); + //for(; iir != rl->end(); ++iir) + //{ + //if(*iir == aRoute) + // if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == port) // p3.3.50 + // break; + //} // Route wanted? - if((portmask & (1 << port)) && (chanmask & (1 << ch))) + //if((portmask & (1 << port)) && (chanmask & (1 << ch))) + if(portmask & (1 << port)) // p3.3.50 { // Route already exists? - if(iir != rl->end()) - continue; + //if(iir != rl->end()) + // continue; audio->msgAddRoute(aRoute, bRoute); changed = true; } else { // Route does not exist? - if(iir == rl->end()) - continue; + //if(iir == rl->end()) + // continue; audio->msgRemoveRoute(aRoute, bRoute); changed = true; } - } + //} } if(changed) @@ -769,7 +781,8 @@ void Track::writeRouting(int level, Xml& xml) const const RouteList* rl = &_outRoutes; for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - if(!r->name().isEmpty()) + //if(!r->name().isEmpty()) + if(r->midiPort != -1 || !r->name().isEmpty()) // p3.3.49 { ///QString src(name()); ///if (type() == Track::AUDIO_OUTPUT) @@ -779,8 +792,16 @@ void Track::writeRouting(int level, Xml& xml) const ///} s = QT_TR_NOOP("Route"); - if(r->channel != -1) - s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); + if(r->type == Route::MIDI_PORT_ROUTE) // p3.3.50 + { + if(r->channel != -1 && r->channel != 0) + s += QString(QT_TR_NOOP(" channelMask=\"%1\"")).arg(r->channel); // Use new channel mask. + } + else + { + if(r->channel != -1) + s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); + } if(r->channels != -1) s += QString(QT_TR_NOOP(" channels=\"%1\"")).arg(r->channels); if(r->remoteChannel != -1) @@ -826,14 +847,19 @@ void Track::writeRouting(int level, Xml& xml) const // xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); s = QT_TR_NOOP("dest"); - if(r->type == Route::MIDI_DEVICE_ROUTE) - s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType()); - else - if(r->type != Route::TRACK_ROUTE) + + //if(r->type == Route::MIDI_DEVICE_ROUTE) // p3.3.49 Obsolete since 1.1-RC2 + // s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType()); // + //if(r->type != Route::TRACK_ROUTE) // + if(r->type != Route::TRACK_ROUTE && r->type != Route::MIDI_PORT_ROUTE) s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); //s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); - s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name())); + if(r->type == Route::MIDI_PORT_ROUTE) // p3.3.49 + s += QString(QT_TR_NOOP(" mport=\"%1\"/")).arg(r->midiPort); + else + s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name())); + xml.tag(level, s); xml.etag(level--, "Route"); |