summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog13
-rw-r--r--muse/muse/app.cpp130
-rw-r--r--muse/muse/app.h2
-rw-r--r--muse/muse/arranger/trackinfo.cpp34
-rw-r--r--muse/muse/conf.cpp3
-rw-r--r--muse/muse/confmport.cpp3
-rw-r--r--muse/muse/driver/alsamidi.cpp2
-rw-r--r--muse/muse/driver/alsatimer.cpp9
-rw-r--r--muse/muse/driver/audiodev.h4
-rw-r--r--muse/muse/driver/dummyaudio.cpp11
-rw-r--r--muse/muse/driver/jack.cpp2
-rw-r--r--muse/muse/driver/jackaudio.h2
-rw-r--r--muse/muse/driver/jackmidi.cpp57
-rw-r--r--muse/muse/midi.cpp543
-rw-r--r--muse/muse/midiport.cpp39
-rw-r--r--muse/muse/midiport.h15
-rw-r--r--muse/muse/mixer/astrip.cpp11
-rw-r--r--muse/muse/mixer/astrip.h2
-rw-r--r--muse/muse/mixer/mstrip.cpp6
-rw-r--r--muse/muse/route.cpp769
-rw-r--r--muse/muse/route.h45
-rw-r--r--muse/muse/song.cpp113
-rw-r--r--muse/muse/songfile.cpp7
-rw-r--r--muse/muse/track.cpp84
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");