summaryrefslogtreecommitdiff
path: root/muse2/muse
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2011-02-24 17:27:04 +0000
committerTim E. Real <termtech@rogers.com>2011-02-24 17:27:04 +0000
commitcc12a523f8f4065f133b1ec38ccba2e7be74d48b (patch)
treece42861856bbf2b23ae7f21f02aabbc775ad9a32 /muse2/muse
parent8e4d18fdcc12c7202e287cc8a2ec2214667c8844 (diff)
Improved midi auto-connections. Fixed Organ synth crashing.
Diffstat (limited to 'muse2/muse')
-rw-r--r--muse2/muse/app.cpp142
-rw-r--r--muse2/muse/app.h3
-rw-r--r--muse2/muse/arranger/tlist.cpp14
-rw-r--r--muse2/muse/conf.cpp34
-rw-r--r--muse2/muse/confmport.cpp456
-rw-r--r--muse2/muse/confmport.h5
-rw-r--r--muse2/muse/midiport.cpp30
-rw-r--r--muse2/muse/midiport.h5
-rw-r--r--muse2/muse/mixer/astrip.cpp6
-rw-r--r--muse2/muse/route.cpp11
-rw-r--r--muse2/muse/song.cpp49
-rw-r--r--muse2/muse/song.h3
-rw-r--r--muse2/muse/track.cpp17
-rw-r--r--muse2/muse/track.h7
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp22
15 files changed, 674 insertions, 130 deletions
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp
index 42f003df..c483fcb5 100644
--- a/muse2/muse/app.cpp
+++ b/muse2/muse/app.cpp
@@ -1687,7 +1687,8 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll
if (mixer2)
mixer2->clear();
arranger->clear(); // clear track info
- if (clearSong())
+ //if (clearSong())
+ if (clearSong(loadAll)) // Allow not touching things like midi ports. p4.0.17 TESTING: Maybe some problems...
return;
QFileInfo fi(name);
@@ -1937,7 +1938,16 @@ void MusE::loadTemplate()
tr("MusE: load template"), 0, MFileDialog::GLOBAL_VIEW);
if (!fn.isEmpty()) {
// museProject = QFileInfo(fn).absolutePath();
+
loadProjectFile(fn, true, true);
+ // With templates, don't clear midi ports.
+ // Any named ports in the template file are useless since they likely
+ // would not be found on other users' machines.
+ // So keep whatever the user currently has set up for ports.
+ // Note that this will also keep the current window configurations etc.
+ // but actually that's also probably a good thing. p4.0.17 Tim. TESTING: Maybe some problems...
+ //loadProjectFile(fn, true, false);
+
setUntitledProject();
}
}
@@ -2210,13 +2220,9 @@ PopupMenu* MusE::getRoutingPopupMenu()
void MusE::updateRouteMenus(Track* track, QObject* master)
{
// NOTE: The purpose of this routine is to make sure the items actually reflect
- // the routing status. And with MusE-1 QT3, it was also required to actually
- // check the items since QT3 didn't do it for us.
- // But now with MusE-2 and QT4, QT4 checks an item when it is clicked.
- // So this routine is less important now, since 99% of the time, the items
- // will be in the right checked state.
- // But we still need this in case for some reason a route could not be
- // added (or removed). Then the item will be properly un-checked (or checked) here.
+ // the routing status.
+ // In case for some reason a route could not be added (or removed).
+ // Then the item will be properly un-checked (or checked) here.
//if(!track || track != gRoutingPopupMenuMaster || track->type() == Track::AUDIO_AUX)
//if(!track || track->type() == Track::AUDIO_AUX)
@@ -2371,6 +2377,12 @@ void MusE::routingPopupMenuActivated(Track* track, int n)
if(n == -1)
return;
+ if(n == 0) // p4.0.17
+ {
+ muse->configMidiPorts();
+ return;
+ }
+
iRouteMenuMap imm = gRoutingMenuMap.find(n);
if(imm == gRoutingMenuMap.end())
return;
@@ -2446,11 +2458,12 @@ void MusE::routingPopupMenuActivated(Track* track, int n)
MidiPort* mp = &midiPorts[mdidx];
MidiDevice* md = mp->device();
- if(!md)
- return;
+ //if(!md) // Removed p4.0.17 Allow connections to ports with no device.
+ // return;
//if(!(md->rwFlags() & 2))
- if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2)))
+ //if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2)))
+ if(md && !(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) // p4.0.17
return;
int chmask = 0;
@@ -2802,22 +2815,46 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)
}
else
{
+ // Warn if no devices available. Add an item to open midi config. p4.0.17
+ int pi = 0;
+ for( ; pi < MIDI_PORTS; ++pi)
+ {
+ MidiDevice* md = midiPorts[pi].device();
+ if(md && !md->isSynti() && (md->rwFlags() & 2))
+ break;
+ }
+ if(pi == MIDI_PORTS)
+ {
+ act = pup->addAction(tr("Warning: No midi input devices!"));
+ act->setCheckable(false);
+ act->setData(-1);
+ pup->addSeparator();
+ }
+ act = pup->addAction(QIcon(*settings_midiport_softsynthsIcon), tr("Open midi config..."));
+ act->setCheckable(false);
+ act->setData(gid);
+ pup->addSeparator();
+ ++gid;
+
+ pup->addAction(new MenuTitleItem("Midi input ports", pup));
+
for(int i = 0; i < MIDI_PORTS; ++i)
{
// 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)
- continue;
+ //if(!md)
+ // continue;
- if(!(md->rwFlags() & (dst ? 1 : 2)))
+ // p4.0.17 Do not list synth devices!
+ if(md && md->isSynti())
+ continue;
+
+ if(md && !(md->rwFlags() & 2))
continue;
//printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i);
- PopupMenu* subp = new PopupMenu(pup);
- subp->setTitle(md->name());
-
// MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers!
//connect(subp, SIGNAL(triggered(QAction*)), pup, SIGNAL(triggered(QAction*)));
//connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide()));
@@ -2825,7 +2862,8 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)
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)
+ iRoute ir = rl->begin();
+ for( ; ir != rl->end(); ++ir)
{
if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i)
{
@@ -2834,6 +2872,12 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)
break;
}
}
+ // p4.0.17 List ports with no device, but with routes to this track, in the main popup.
+ if(!md && ir == rl->end())
+ continue;
+
+ PopupMenu* subp = new PopupMenu(pup);
+ subp->setTitle(QString("%1:").arg(i+1) + (md ? md->name() : tr("<none>")));
for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
{
@@ -2852,7 +2896,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)
++gid;
}
//gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id.
- act = subp->addAction(QString("Toggle all"));
+ act = subp->addAction(tr("Toggle all"));
//act->setCheckable(true);
act->setData(gid);
Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits.
@@ -2860,6 +2904,61 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)
++gid;
pup->addMenu(subp);
}
+
+ #if 0
+ // p4.0.17 List ports with no device and no in routes, in a separate popup.
+ PopupMenu* morep = new PopupMenu(pup);
+ morep->setTitle(tr("More..."));
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ MidiPort* mp = &midiPorts[i];
+ if(mp->device())
+ continue;
+
+ PopupMenu* subp = new PopupMenu(morep);
+ subp->setTitle(QString("%1:").arg(i) + tr("<none>"));
+
+ // MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers!
+ //connect(subp, SIGNAL(triggered(QAction*)), pup, SIGNAL(triggered(QAction*)));
+ //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide()));
+
+ iRoute ir = rl->begin();
+ for( ; ir != rl->end(); ++ir)
+ {
+ if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i)
+ break;
+ }
+ if(ir != rl->end())
+ continue;
+
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ act = subp->addAction(QString("Channel %1").arg(ch+1));
+ act->setCheckable(true);
+ act->setData(gid);
+
+ int chbit = 1 << ch;
+ Route srcRoute(i, chbit); // In accordance with new channel mask, use the bit position.
+
+ gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) );
+
+ //if(chanmask & chbit) // Is the channel already set? Show item check mark.
+ // act->setChecked(true);
+
+ ++gid;
+ }
+ //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id.
+ act = subp->addAction(QString("Toggle all"));
+ //act->setCheckable(true);
+ act->setData(gid);
+ Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits.
+ gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) );
+ ++gid;
+ morep->addMenu(subp);
+ }
+ pup->addMenu(morep);
+ #endif
+
}
if(pup->actions().isEmpty())
@@ -4615,9 +4714,10 @@ MusE::lash_idle_cb ()
// clearSong
// return true if operation aborted
// called with sequencer stopped
+// If clear_all is false, it will not touch things like midi ports.
//---------------------------------------------------------
-bool MusE::clearSong()
+bool MusE::clearSong(bool clear_all)
{
if (song->dirty) {
int n = 0;
@@ -4665,7 +4765,7 @@ again:
}
}
microSleep(100000);
- song->clear(false);
+ song->clear(false, clear_all);
microSleep(100000);
return false;
}
diff --git a/muse2/muse/app.h b/muse2/muse/app.h
index 013f6efc..f3a3dc4c 100644
--- a/muse2/muse/app.h
+++ b/muse2/muse/app.h
@@ -190,7 +190,8 @@ class MusE : public QMainWindow
void processTrack(MidiTrack* track);
void write(Xml& xml) const;
- bool clearSong();
+ // If clear_all is false, it will not touch things like midi ports.
+ bool clearSong(bool clear_all = true);
bool save(const QString&, bool);
void setUntitledProject();
void setConfigDefaults();
diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp
index a76be9c2..4a9d3d32 100644
--- a/muse2/muse/arranger/tlist.cpp
+++ b/muse2/muse/arranger/tlist.cpp
@@ -545,6 +545,7 @@ void TList::portsPopupMenu(Track* t, int x, int y)
track->setOutPortAndUpdate(n);
}
audio->msgIdle(false);
+ audio->msgUpdateSoloStates(); // (p4.0.14) p4.0.17
song->update();
}
else
@@ -569,7 +570,9 @@ void TList::portsPopupMenu(Track* t, int x, int y)
//audio->msgSetTrackOutPort(track, n);
track->setOutPortAndUpdate(n);
audio->msgIdle(false);
- song->update();
+ //song->update();
+ audio->msgUpdateSoloStates(); // (p4.0.14) p4.0.17
+ song->update(SC_MIDI_TRACK_PROP); //
}
}
delete p;
@@ -1104,7 +1107,7 @@ void TList::mousePressEvent(QMouseEvent* ev)
//if(button == QMouseEvent::LeftButton)
// portsPopupMenu(t, x, t->y() - ypos);
- audio->msgUpdateSoloStates(); // p4.0.14
+ //audio->msgUpdateSoloStates(); // p4.0.14
//song->update(SC_ROUTE); //
break;
@@ -1459,7 +1462,9 @@ void TList::wheelEvent(QWheelEvent* ev)
mt->setOutPortAndUpdate(port);
audio->msgIdle(false);
- song->update(SC_ROUTE);
+ audio->msgUpdateSoloStates(); // p4.0.14
+ //song->update(SC_ROUTE);
+ song->update(SC_MIDI_TRACK_PROP); // p4.0.17
}
}
break;
@@ -1483,7 +1488,8 @@ void TList::wheelEvent(QWheelEvent* ev)
// may result in adding/removing mixer strip:
//song->update(-1);
- song->update(SC_MIDI_TRACK_PROP);
+ audio->msgUpdateSoloStates(); // p4.0.14
+ song->update(SC_MIDI_TRACK_PROP);
}
}
else {
diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp
index 5ddc058d..e4d57a3a 100644
--- a/muse2/muse/conf.cpp
+++ b/muse2/muse/conf.cpp
@@ -211,8 +211,11 @@ static void readConfigMidiPort(Xml& xml)
int openFlags = 1;
bool thruFlag = false;
- int dic = 0;
- int doc = 0;
+ //int dic = 0;
+ //int doc = 0;
+ int dic = -1; // p4.0.17
+ int doc = -1;
+
MidiSyncInfo tmpSi;
int type = MidiDevice::ALSA_MIDI;
@@ -288,9 +291,16 @@ static void readConfigMidiPort(Xml& xml)
MidiPort* mp = &midiPorts[idx];
mp->setInstrument(registerMidiInstrument(instrument)); // By Tim.
- mp->setDefaultInChannels(dic);
- mp->setDefaultOutChannels(doc);
-
+ if(dic != -1) // p4.0.17 Leave them alone unless set by song.
+ mp->setDefaultInChannels(dic);
+ if(doc != -1)
+ // p4.0.17 Turn on if and when multiple output routes supported.
+ #if 0
+ mp->setDefaultOutChannels(doc);
+ #else
+ setPortExclusiveDefOutChan(idx, doc);
+ #endif
+
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);
@@ -1037,10 +1047,18 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
for (int i = 0; i < MIDI_PORTS; ++i) {
bool used = false;
MidiPort* mport = &midiPorts[i];
+ MidiDevice* dev = mport->device();
// Route check by Tim. Port can now be used for routing even if no device.
// Also, check for other non-defaults and save port, to preserve settings even if no device.
if(!mport->noInRoute() || !mport->noOutRoute() ||
- mport->defaultInChannels() || mport->defaultOutChannels() ||
+ // p4.0.17 Since MidiPort:: and MidiDevice::writeRouting() ignore ports with no device, ignore them here, too.
+ // This prevents bogus routes from being saved and propagated in the med file.
+ // Hmm tough decision, should we save if no device? That would preserve routes in case user upgrades HW,
+ // or ALSA reorders or renames devices etc etc, then we have at least kept the track <-> port routes.
+ //if(((!mport->noInRoute() || !mport->noOutRoute()) && dev) ||
+ //mport->defaultInChannels() || mport->defaultOutChannels() ||
+ mport->defaultInChannels() != (1<<MIDI_CHANNELS)-1 || // p4.0.17 Default is now to connect to all channels.
+ mport->defaultOutChannels() ||
(!mport->instrument()->iname().isEmpty() && mport->instrument()->iname() != "GM") ||
!mport->syncInfo().isDefault())
used = true;
@@ -1058,12 +1076,12 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
}
}
- MidiDevice* dev = mport->device();
if (!used && !dev)
continue;
xml.tag(level++, "midiport idx=\"%d\"", i);
- if(mport->defaultInChannels())
+ //if(mport->defaultInChannels())
+ if(mport->defaultInChannels() != (1<<MIDI_CHANNELS)-1) // p4.0.17 Default is now to connect to all channels.
xml.intTag(level, "defaultInChans", mport->defaultInChannels());
if(mport->defaultOutChannels())
xml.intTag(level, "defaultOutChans", mport->defaultOutChannels());
diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp
index 77e6889c..2c72c9e3 100644
--- a/muse2/muse/confmport.cpp
+++ b/muse2/muse/confmport.cpp
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <QMenu>
+#include <QAction>
#include <QMessageBox>
#include <QPixmap>
#include <QTableWidget>
@@ -37,16 +38,185 @@
#include "audiodev.h"
#include "menutitleitem.h"
#include "utils.h"
+#include "popupmenu.h"
extern std::vector<Synth*> synthis;
enum { DEVCOL_NO = 0, DEVCOL_GUI, DEVCOL_REC, DEVCOL_PLAY, DEVCOL_INSTR, DEVCOL_NAME,
- //DEVCOL_STATE };
- //DEVCOL_ROUTES, DEVCOL_STATE };
- //DEVCOL_INROUTES, DEVCOL_OUTROUTES, DEVCOL_STATE }; // p3.3.55
DEVCOL_INROUTES, DEVCOL_OUTROUTES, DEVCOL_DEF_IN_CHANS, DEVCOL_DEF_OUT_CHANS, DEVCOL_STATE };
//---------------------------------------------------------
+// changeDefInputRoutes
+//---------------------------------------------------------
+
+void MPConfig::changeDefInputRoutes(QAction* act)
+{
+ QTableWidgetItem* item = mdevView->currentItem();
+ if(item == 0)
+ return;
+ QString id = mdevView->item(item->row(), DEVCOL_NO)->text();
+ int no = atoi(id.toLatin1().constData()) - 1;
+ if(no < 0 || no >= MIDI_PORTS)
+ return;
+ int actid = act->data().toInt();
+ int allch = (1 << MIDI_CHANNELS) - 1;
+ int defch = midiPorts[no].defaultInChannels();
+
+ if(actid == MIDI_CHANNELS + 1) // Apply to all tracks now.
+ {
+ // Are there tracks, and is there a port device?
+ // Tested: Hmm, allow ports with no device since that is a valid situation.
+ if(!song->midis()->empty()) // && midiPorts[no].device())
+ {
+ int ret = QMessageBox::question(this, tr("Default input connections"),
+ tr("Are you sure you want to apply to all existing midi tracks now?"),
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Cancel);
+ if(ret == QMessageBox::Ok)
+ {
+ MidiTrackList* mtl = song->midis();
+ for(iMidiTrack it = mtl->begin(); it != mtl->end(); ++it)
+ {
+ // Remove all routes from this port to the tracks first.
+ audio->msgRemoveRoute(Route(no, allch), Route(*it, allch));
+ if(defch)
+ audio->msgAddRoute(Route(no, defch), Route(*it, defch));
+ }
+ //audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ }
+ }
+ else
+ {
+ int chbits;
+ if(actid == MIDI_CHANNELS) // Toggle all.
+ {
+ chbits = (defch == allch) ? 0 : allch;
+ if(defpup)
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ {
+ QAction* act = defpup->findActionFromData(i);
+ if(act)
+ act->setChecked(chbits);
+ }
+ }
+ else
+ chbits = defch ^ (1 << actid);
+ midiPorts[no].setDefaultInChannels(chbits);
+ mdevView->item(item->row(), DEVCOL_DEF_IN_CHANS)->setText(bitmap2String(chbits));
+ }
+}
+
+//---------------------------------------------------------
+// changeDefOutputRoutes
+//---------------------------------------------------------
+
+void MPConfig::changeDefOutputRoutes(QAction* act)
+{
+ QTableWidgetItem* item = mdevView->currentItem();
+ if(item == 0)
+ return;
+ QString id = mdevView->item(item->row(), DEVCOL_NO)->text();
+ int no = atoi(id.toLatin1().constData()) - 1;
+ if(no < 0 || no >= MIDI_PORTS)
+ return;
+ int actid = act->data().toInt();
+ int defch = midiPorts[no].defaultOutChannels();
+ // Turn on if and when multiple output routes are supported.
+ #if 0
+ int allch = (1 << MIDI_CHANNELS) - 1;
+ #endif
+
+ if(actid == MIDI_CHANNELS + 1) // Apply to all tracks now.
+ {
+ // Are there tracks, and is there a port device?
+ // Tested: Hmm, allow ports with no device since that is a valid situation.
+ if(!song->midis()->empty()) // && midiPorts[no].device())
+ {
+ int ret = QMessageBox::question(this, tr("Default output connections"),
+ tr("Are you sure you want to apply to all existing midi tracks now?"),
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Cancel);
+ if(ret == QMessageBox::Ok)
+ {
+ MidiTrackList* mtl = song->midis();
+ // Turn on if and when multiple output routes are supported.
+ #if 0
+ for(iMidiTrack it = mtl->begin(); it != mtl->end(); ++it)
+ {
+ // Remove all routes from this port to the tracks first.
+ audio->msgRemoveRoute(Route(no, allch), Route(*it, allch));
+ if(defch)
+ audio->msgAddRoute(Route(no, defch), Route(*it, defch));
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ #else
+ int ch = 0;
+ for( ; ch < MIDI_CHANNELS; ++ch)
+ if(defch & (1 << ch)) break;
+
+ audio->msgIdle(true);
+ for(iMidiTrack it = mtl->begin(); it != mtl->end(); ++it)
+ {
+ // Leave drum track channel at current setting.
+ if((*it)->type() == Track::DRUM)
+ (*it)->setOutPortAndUpdate(no);
+ else
+ (*it)->setOutPortAndChannelAndUpdate(no, ch);
+ }
+ audio->msgIdle(false);
+ audio->msgUpdateSoloStates();
+ song->update(SC_MIDI_TRACK_PROP);
+ #endif
+ }
+ }
+ }
+ else
+ {
+ #if 0 // Turn on if and when multiple output routes are supported.
+ int chbits;
+ if(actid == MIDI_CHANNELS) // Toggle all.
+ {
+ chbits = (defch == allch) ? 0 : allch;
+ if(defpup)
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ {
+ QAction* act = defpup->findActionFromData(i);
+ if(act)
+ act->setChecked(chbits);
+ }
+ }
+ else
+ chbits = defch ^ (1 << actid);
+ midiPorts[no].setDefaultOutChannels(chbits);
+ mdevView->item(item->row(), DEVCOL_DEF_OUT_CHANS)->setText(bitmap2String(chbits));
+ #else
+ if(actid < MIDI_CHANNELS)
+ {
+ int chbits = 1 << actid;
+ // Multiple out routes not supported. Make the setting exclusive to this port - exclude all other ports.
+ setPortExclusiveDefOutChan(no, chbits);
+ int j = mdevView->rowCount();
+ for(int i = 0; i < j; ++i)
+ mdevView->item(i, DEVCOL_DEF_OUT_CHANS)->setText(bitmap2String(i == no ? chbits : 0));
+ if(defpup)
+ {
+ QAction* a;
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ {
+ a = defpup->findActionFromData(i);
+ if(a)
+ a->setChecked(i == actid);
+ }
+ }
+ }
+ #endif
+ }
+}
+
+//---------------------------------------------------------
// mdevViewItemRenamed
//---------------------------------------------------------
@@ -59,26 +229,81 @@ void MPConfig::mdevViewItemRenamed(QTableWidgetItem* item)
return;
switch(col)
{
+ // Enabled: Use editor (Not good - only responds if text changed. We need to respond always).
+ // Disabled: Use pop-up menu.
+ #if 0
case DEVCOL_DEF_IN_CHANS:
{
QString id = item->tableWidget()->item(item->row(), DEVCOL_NO)->text();
int no = atoi(id.toLatin1().constData()) - 1;
if(no < 0 || no >= MIDI_PORTS)
return;
- midiPorts[no].setDefaultInChannels(((1 << MIDI_CHANNELS) - 1) & string2bitmap(s));
+ int allch = (1 << MIDI_CHANNELS) - 1;
+ int ch = allch & string2bitmap(s);
+ midiPorts[no].setDefaultInChannels(ch);
+
+ if(!song->midis()->empty() && midiPorts[no].device()) // Only if there are tracks, and device is valid.
+ {
+ int ret = QMessageBox::question(this, tr("Default input connections"),
+ tr("Setting will apply to new midi tracks.\n"
+ "Do you want to apply to all existing midi tracks now?"),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if(ret == QMessageBox::Yes)
+ {
+ MidiTrackList* mtl = song->midis();
+ for(iMidiTrack it = mtl->begin(); it != mtl->end(); ++it)
+ {
+ // Remove all routes from this port to the tracks first.
+ audio->msgRemoveRoute(Route(no, allch), Route(*it, allch));
+ if(ch)
+ audio->msgAddRoute(Route(no, ch), Route(*it, ch));
+ }
+ }
+ }
song->update();
}
break;
+ #endif
+
+ // Enabled: Use editor (Not good - only responds if text changed. We need to respond always).
+ // Disabled: Use pop-up menu.
+ // Only turn on if and when multiple output routes are supported.
+ #if 0
case DEVCOL_DEF_OUT_CHANS:
{
QString id = item->tableWidget()->item(item->row(), DEVCOL_NO)->text();
int no = atoi(id.toLatin1().constData()) - 1;
if(no < 0 || no >= MIDI_PORTS)
return;
- midiPorts[no].setDefaultOutChannels(((1 << MIDI_CHANNELS) - 1) & string2bitmap(s));
+ int allch = (1 << MIDI_CHANNELS) - 1;
+ int ch = allch & string2bitmap(s);
+ midiPorts[no].setDefaultOutChannels(ch);
+
+ if(!song->midis()->empty() && midiPorts[no].device()) // Only if there are tracks, and device is valid.
+ {
+ int ret = QMessageBox::question(this, tr("Default output connections"),
+ tr("Setting will apply to new midi tracks.\n"
+ "Do you want to apply to all existing midi tracks now?"),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if(ret == QMessageBox::Yes)
+ {
+ MidiTrackList* mtl = song->midis();
+ for(iMidiTrack it = mtl->begin(); it != mtl->end(); ++it)
+ {
+ // Remove all routes from the tracks to this port first.
+ audio->msgRemoveRoute(Route(*it, allch), Route(no, allch));
+ if(ch)
+ audio->msgAddRoute(Route(*it, ch), Route(no, ch));
+ }
+ }
+ }
song->update();
}
break;
+ # endif
+
case DEVCOL_NAME:
{
QString id = item->tableWidget()->item(item->row(), DEVCOL_NO)->text();
@@ -134,93 +359,76 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
int rwFlags = dev ? dev->rwFlags() : 0;
int openFlags = dev ? dev->openFlags() : 0;
QTableWidget* listView = item->tableWidget();
- //printf("MPConfig::rbClicked cpt x:%d y:%d\n", cpt.x(), cpt.y());
- //printf("MPConfig::rbClicked new cpt x:%d y:%d\n", cpt.x(), cpt.y());
- //printf("MPConfig::rbClicked new mapped cpt x:%d y:%d\n", cpt.x(), cpt.y());
QPoint ppt = listView->visualItemRect(item).bottomLeft();
QPoint mousepos = QCursor::pos();
- //printf("MPConfig::rbClicked ppt x:%d y:%d\n", ppt.x(), ppt.y());
int col = item->column();
ppt += QPoint(0, listView->horizontalHeader()->height());
- //printf("MPConfig::rbClicked new ppt x:%d y:%d\n", ppt.x(), ppt.y());
ppt = listView->mapToGlobal(ppt);
- //printf("MPConfig::rbClicked new mapped ppt x:%d y:%d\n", ppt.x(), ppt.y());
switch (col) {
case DEVCOL_GUI:
if (dev == 0)
- //break;
return;
if (port->hasGui())
{
port->instrument()->showGui(!port->guiVisible());
item->setIcon(port->guiVisible() ? QIcon(*dotIcon) : QIcon(*dothIcon));
}
- //break;
return;
case DEVCOL_REC:
if (dev == 0 || !(rwFlags & 2))
- //break;
return;
openFlags ^= 0x2;
dev->setOpenFlags(openFlags);
midiSeq->msgSetMidiDevice(port, dev); // reopen device
item->setIcon(openFlags & 2 ? QIcon(*dotIcon) : QIcon(*dothIcon));
- // p3.3.55
if(dev->deviceType() == MidiDevice::JACK_MIDI)
{
if(dev->openFlags() & 2)
{
- //item->setPixmap(DEVCOL_INROUTES, *buttondownIcon);
+ item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setIcon(QIcon(*buttondownIcon));
item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setText(tr("in"));
}
else
{
- //item->setPixmap(DEVCOL_INROUTES, *buttondownIcon);
+ item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setIcon(QIcon());
item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setText("");
}
}
-
- //break;
return;
case DEVCOL_PLAY:
if (dev == 0 || !(rwFlags & 1))
- //break;
return;
openFlags ^= 0x1;
dev->setOpenFlags(openFlags);
midiSeq->msgSetMidiDevice(port, dev); // reopen device
item->setIcon(openFlags & 1 ? QIcon(*dotIcon) : QIcon(*dothIcon));
- // p3.3.55
if(dev->deviceType() == MidiDevice::JACK_MIDI)
{
if(dev->openFlags() & 1)
{
- //item->setPixmap(DEVCOL_OUTROUTES, *buttondownIcon);
+ item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setIcon(QIcon(*buttondownIcon));
item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setText(tr("out"));
}
else
{
- //item->setPixmap(DEVCOL_OUTROUTES, *buttondownIcon);
+ item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setIcon(QIcon());
item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setText("");
}
}
-
- //break;
return;
- //case DEVCOL_ROUTES:
- case DEVCOL_INROUTES: // p3.3.55
+ case DEVCOL_INROUTES:
case DEVCOL_OUTROUTES:
{
if(!checkAudioDevice())
return;
- if(audioDevice->deviceType() != AudioDevice::JACK_AUDIO) // p3.3.52 Only if Jack is running.
+ if(audioDevice->deviceType() != AudioDevice::JACK_AUDIO) // Only if Jack is running.
return;
if(!dev)
@@ -232,13 +440,12 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
if(dev->deviceType() != MidiDevice::JACK_MIDI)
return;
- //if(!(dev->rwFlags() & 3))
- //if(!(dev->rwFlags() & ((col == DEVCOL_OUTROUTES) ? 1 : 2))) // p3.3.55
+ //if(!(dev->rwFlags() & ((col == DEVCOL_OUTROUTES) ? 1 : 2)))
if(!(dev->openFlags() & ((col == DEVCOL_OUTROUTES) ? 1 : 2)))
return;
//RouteList* rl = (dev->rwFlags() & 1) ? dev->outRoutes() : dev->inRoutes();
- RouteList* rl = (col == DEVCOL_OUTROUTES) ? dev->outRoutes() : dev->inRoutes(); // p3.3.55
+ RouteList* rl = (col == DEVCOL_OUTROUTES) ? dev->outRoutes() : dev->inRoutes();
QMenu* pup = 0;
int gid = 0;
std::list<QString> sl;
@@ -250,7 +457,6 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
// Jack input ports if device is writable, and jack output ports if device is readable.
//sl = (dev->rwFlags() & 1) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases);
- // p3.3.55
sl = (col == DEVCOL_OUTROUTES) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases);
//for (int i = 0; i < channel; ++i)
@@ -283,7 +489,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
//Route dst(*ip, true, i);
//Route rt(*ip, (dev->rwFlags() & 1), -1, Route::JACK_ROUTE);
- Route rt(*ip, (col == DEVCOL_OUTROUTES), -1, Route::JACK_ROUTE); // p3.3.55
+ Route rt(*ip, (col == DEVCOL_OUTROUTES), -1, Route::JACK_ROUTE);
for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
{
if (*ir == rt)
@@ -324,8 +530,8 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
QString s(act->text());
- //if(dev->rwFlags() & 1) // Writable
- if(col == DEVCOL_OUTROUTES) // Writable p3.3.55
+ //if(dev->rwFlags() & 1) // Writeable
+ if(col == DEVCOL_OUTROUTES) // Writeable
{
Route srcRoute(dev, -1);
Route dstRoute(s, true, -1, Route::JACK_ROUTE);
@@ -345,7 +551,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
}
else
//if(dev->rwFlags() & 2) // Readable
- //if(col == DEVCOL_INROUTES) // Readable p3.3.55
+ //if(col == DEVCOL_INROUTES) // Readable
{
Route srcRoute(s, false, -1, Route::JACK_ROUTE);
Route dstRoute(dev, -1);
@@ -367,7 +573,6 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
- // p3.3.46
//delete pup;
// FIXME:
// Routes can't be re-read until the message sent from msgAddRoute1()
@@ -381,11 +586,86 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
return;
case DEVCOL_DEF_IN_CHANS:
+ // Enabled: Use editor (Not good - only responds if text changed. We need to respond always).
+ // Disabled: Use pop-up menu.
+ #if 0
+ return;
+ #else
+ {
+ defpup = new PopupMenu(this);
+ defpup->addAction(new MenuTitleItem("Channel", defpup));
+ QAction* act = 0;
+ int chbits = midiPorts[no].defaultInChannels();
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ {
+ act = defpup->addAction(QString().setNum(i + 1));
+ act->setData(i);
+ act->setCheckable(true);
+ act->setChecked((1 << i) & chbits);
+ }
+
+ act = defpup->addAction(tr("Toggle all"));
+ act->setData(MIDI_CHANNELS);
+
+ defpup->addSeparator();
+ act = defpup->addAction(tr("Change all tracks now"));
+ act->setData(MIDI_CHANNELS + 1);
+ // Enable only if there are tracks, and port has a device.
+ // Tested: Hmm, allow ports with no device since that is a valid situation.
+ act->setEnabled(!song->midis()->empty()); // && midiPorts[no].device());
+
+ connect(defpup, SIGNAL(triggered(QAction*)), SLOT(changeDefInputRoutes(QAction*)));
+ //connect(defpup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ //defpup->popup(QCursor::pos());
+ defpup->exec(QCursor::pos());
+ delete defpup;
+ defpup = 0;
+ }
+ return;
+ #endif
+
case DEVCOL_DEF_OUT_CHANS:
+ // Enabled: Use editor (Not good - only responds if text changed. We need to respond always).
+ // Disabled: Use pop-up menu.
+ // Only turn on if and when multiple output routes are supported.
+ #if 0
+ return;
+ #else
{
+ defpup = new PopupMenu(this);
+ defpup->addAction(new MenuTitleItem("Channel", defpup));
+ QAction* act = 0;
+ int chbits = midiPorts[no].defaultOutChannels();
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ {
+ act = defpup->addAction(QString().setNum(i + 1));
+ act->setData(i);
+ act->setCheckable(true);
+ act->setChecked((1 << i) & chbits);
+ }
+
+ // Turn on if and when multiple output routes are supported.
+ #if 0
+ act = defpup->addAction(tr("Toggle all"));
+ act->setData(MIDI_CHANNELS);
+ #endif
+
+ defpup->addSeparator();
+ act = defpup->addAction(tr("Change all tracks now"));
+ act->setData(MIDI_CHANNELS + 1);
+ // Enable only if there are tracks, and port has a device.
+ // Tested: Hmm, allow ports with no device since that is a valid situation.
+ act->setEnabled(!song->midis()->empty()); // && midiPorts[no].device());
+
+ connect(defpup, SIGNAL(triggered(QAction*)), SLOT(changeDefOutputRoutes(QAction*)));
+ //connect(defpup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ //defpup->popup(QCursor::pos());
+ defpup->exec(QCursor::pos());
+ delete defpup;
+ defpup = 0;
}
- //break;
return;
+ #endif
case DEVCOL_NAME:
{
@@ -550,7 +830,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
if(n < 0x10000000)
{
delete pup;
- if(n <= 2) // p3.3.55
+ if(n <= 2)
{
sdev = MidiJackDevice::createJackMidiDevice();
@@ -615,7 +895,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
instrPopup->addAction((*i)->iname());
}
- QAction* act = instrPopup->exec(ppt, 0);
+ QAction* act = instrPopup->exec(ppt);
if(!act)
//break;
return;
@@ -652,8 +932,13 @@ void MPConfig::setToolTip(QTableWidgetItem *item, int col)
//case DEVCOL_ROUTES: item->setToolTip(tr("Jack midi ports")); break;
case DEVCOL_INROUTES: item->setToolTip(tr("Connections from Jack Midi outputs")); break;
case DEVCOL_OUTROUTES: item->setToolTip(tr("Connections to Jack Midi inputs")); break;
- case DEVCOL_DEF_IN_CHANS: item->setToolTip(tr("Connect these to new midi tracks")); break;
- case DEVCOL_DEF_OUT_CHANS: item->setToolTip(tr("Connect new midi tracks to this (first listed only)")); break;
+ case DEVCOL_DEF_IN_CHANS: item->setToolTip(tr("Auto-connect these channels to new midi tracks")); break;
+ // Turn on if and when multiple output routes are supported.
+ #if 0
+ case DEVCOL_DEF_OUT_CHANS: item->setToolTip(tr("Auto-connect new midi tracks to these channels")); break;
+ #else
+ case DEVCOL_DEF_OUT_CHANS: item->setToolTip(tr("Auto-connect new midi tracks to this channel")); break;
+ #endif
case DEVCOL_STATE: item->setToolTip(tr("Device state")); break;
default: return;
}
@@ -686,17 +971,21 @@ void MPConfig::setWhatsThis(QTableWidgetItem *item, int col)
case DEVCOL_OUTROUTES:
item->setWhatsThis(tr("Connections to Jack Midi input ports")); break;
case DEVCOL_DEF_IN_CHANS:
- item->setWhatsThis(tr("Connect these channels, on this port, to new midi tracks.\n"
- "Example:\n"
- " 1 2 3 channel 1 2 and 3\n"
- " 1-3 same\n"
- " 1-3 5 channel 1 2 3 and 5\n"
- " all all channels\n"
- " none no channels")); break;
+ //item->setWhatsThis(tr("Auto-connect these channels, on this port, to new midi tracks.\n"
+ // "Example:\n"
+ // " 1 2 3 channel 1 2 and 3\n"
+ // " 1-3 same\n"
+ // " 1-3 5 channel 1 2 3 and 5\n"
+ // " all all channels\n"
+ // " none no channels")); break;
+ item->setWhatsThis(tr("Auto-connect these channels, on this port, to new midi tracks.")); break;
case DEVCOL_DEF_OUT_CHANS:
- item->setWhatsThis(tr("Connect new midi tracks to these channels, on this port.\n"
- "See default in channels.\n"
- "NOTE: Currently only one output port and channel supported (first found)")); break;
+ // Turn on if and when multiple output routes are supported.
+ #if 0
+ item->setWhatsThis(tr("Connect new midi tracks to these channels, on this port.")); break;
+ #else
+ item->setWhatsThis(tr("Connect new midi tracks to this channel, on this port.")); break;
+ #endif
case DEVCOL_STATE:
item->setWhatsThis(tr("State: result of opening the device")); break;
default:
@@ -732,6 +1021,7 @@ MPConfig::MPConfig(QWidget* parent)
//popup = 0;
instrPopup = 0;
+ defpup = 0;
_showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first.
QStringList columnnames;
@@ -768,7 +1058,8 @@ MPConfig::MPConfig(QWidget* parent)
connect(synthList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(addInstanceClicked()));
connect(removeInstance, SIGNAL(clicked()), SLOT(removeInstanceClicked()));
connect(instanceList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(removeInstanceClicked()));
- songChanged(0);
+ //songChanged(0);
+ songChanged(SC_CONFIG);
}
@@ -793,7 +1084,10 @@ void MPConfig::selectionChanged()
void MPConfig::songChanged(int flags)
{
// Is it simply a midi controller value adjustment? Forget it.
- if(flags == SC_MIDI_CONTROLLER)
+ //if(flags == SC_MIDI_CONTROLLER)
+ // return;
+ // No need for anything but this, yet.
+ if(!(flags & SC_CONFIG))
return;
// Get currently selected index...
@@ -809,6 +1103,7 @@ void MPConfig::songChanged(int flags)
sitem = 0;
mdevView->clearContents();
+ int defochs = 0;
for (int i = MIDI_PORTS-1; i >= 0; --i)
{
mdevView->blockSignals(true); // otherwise itemChanged() is triggered and bad things happen.
@@ -849,14 +1144,50 @@ void MPConfig::songChanged(int flags)
QTableWidgetItem* itemin = new QTableWidgetItem;
addItem(i, DEVCOL_INROUTES, itemin, mdevView);
itemin->setFlags(Qt::ItemIsEnabled);
- QTableWidgetItem* itemdefin = new QTableWidgetItem(bitmap2String(port->defaultInChannels()));
+ //QTableWidgetItem* itemdefin = new QTableWidgetItem(bitmap2String(port->defaultInChannels()));
+ // Ignore synth devices. Default input routes make no sense for them (right now).
+ QTableWidgetItem* itemdefin = new QTableWidgetItem((dev && dev->isSynti()) ?
+ QString() : bitmap2String(port->defaultInChannels()));
addItem(i, DEVCOL_DEF_IN_CHANS, itemdefin, mdevView);
- itemdefin->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled);
+ // Enabled: Use editor (not good). Disabled: Use pop-up menu.
+ #if 0
+ itemdefin->setFlags((dev && dev->isSynti()) ? Qt::NoItemFlags : Qt::ItemIsEditable | Qt::ItemIsEnabled);
+ # else
+ if(dev && dev->isSynti())
+ itemdefin->setFlags(Qt::NoItemFlags);
+ else
+ {
+ itemdefin->setFlags(Qt::ItemIsEnabled);
+ itemdefin->setIcon(QIcon(*buttondownIcon));
+ }
+ #endif
+
+ // Turn on if and when multiple output routes are supported.
+ #if 0
QTableWidgetItem* itemdefout = new QTableWidgetItem(bitmap2String(port->defaultOutChannels()));
addItem(i, DEVCOL_DEF_OUT_CHANS, itemdefout, mdevView);
itemdefout->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled);
- mdevView->blockSignals(false);
-
+ #else
+ //QTableWidgetItem* itemdefout = new QTableWidgetItem(QString("--"));
+ QTableWidgetItem* itemdefout = new QTableWidgetItem(bitmap2String(0));
+ defochs = port->defaultOutChannels();
+ if(defochs)
+ {
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ if(defochs & (1 << ch))
+ {
+ itemdefout->setText(QString().setNum(ch + 1));
+ break;
+ }
+ }
+ }
+ addItem(i, DEVCOL_DEF_OUT_CHANS, itemdefout, mdevView);
+ itemdefout->setFlags(Qt::ItemIsEnabled);
+ itemdefout->setIcon(QIcon(*buttondownIcon));
+ #endif
+
+ mdevView->blockSignals(false);
if (dev) {
itemname->setText(dev->name());
@@ -898,20 +1229,23 @@ void MPConfig::songChanged(int flags)
//item->setPixmap(DEVCOL_ROUTES, *buttondownIcon);
//item->setText(DEVCOL_ROUTES, tr("routes"));
- // p3.3.55
if(dev->rwFlags() & 1)
//if(dev->openFlags() & 1)
{
- itemout->setIcon(QIcon(*buttondownIcon));
if(dev->openFlags() & 1)
+ {
+ itemout->setIcon(QIcon(*buttondownIcon));
itemout->setText(tr("out"));
+ }
}
if(dev->rwFlags() & 2)
//if(dev->openFlags() & 2)
{
- itemin->setIcon(QIcon(*buttondownIcon));
if(dev->openFlags() & 2)
+ {
+ itemin->setIcon(QIcon(*buttondownIcon));
itemin->setText(tr("in"));
+ }
}
}
diff --git a/muse2/muse/confmport.h b/muse2/muse/confmport.h
index d8bd663b..f09c4d65 100644
--- a/muse2/muse/confmport.h
+++ b/muse2/muse/confmport.h
@@ -18,6 +18,8 @@ class QTreeWidget;
class QTableWidget;
class QPoint;
class QMenu;
+class QAction;
+class PopupMenu;
class Xml;
//---------------------------------------------------------
@@ -28,6 +30,7 @@ class Xml;
class MPConfig : public QDialog, Ui::SynthConfigBase {
QMenu* instrPopup;
//QMenu* popup;
+ PopupMenu* defpup;
int _showAliases; // -1: None. 0: First aliases. 1: Second aliases etc.
void setWhatsThis(QTableWidgetItem *item, int col);
void setToolTip(QTableWidgetItem *item, int col);
@@ -42,6 +45,8 @@ class MPConfig : public QDialog, Ui::SynthConfigBase {
void selectionChanged();
void addInstanceClicked();
void removeInstanceClicked();
+ void changeDefInputRoutes(QAction* act);
+ void changeDefOutputRoutes(QAction* act);
public:
MPConfig(QWidget* parent=0);
diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp
index 0220a353..6d04cff2 100644
--- a/muse2/muse/midiport.cpp
+++ b/muse2/muse/midiport.cpp
@@ -40,6 +40,9 @@ void initMidiPorts()
///port->setInstrument(genericMidiInstrument);
port->setInstrument(registerMidiInstrument("GM")); // Changed by Tim.
port->syncInfo().setPort(i);
+ // p4.0.17 Set the first channel on the first port to auto-connect to midi track outputs.
+ if(i == 0)
+ port->setDefaultOutChannels(1);
}
}
@@ -50,7 +53,8 @@ void initMidiPorts()
MidiPort::MidiPort()
: _state("not configured")
{
- _defaultInChannels = 0;
+ //_defaultInChannels = 0;
+ _defaultInChannels = (1 << MIDI_CHANNELS) -1; // p4.0.17 Default is now to connect to all channels.
_defaultOutChannels = 0;
_device = 0;
_instrument = 0;
@@ -1026,15 +1030,16 @@ void MidiPort::setNullSendValue(int v)
}
//---------------------------------------------------------
-// writeRouting // p3.3.50
+// writeRouting
//---------------------------------------------------------
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;
+ // p4.0.17 Reverted. Allow ports with no device to save.
+ //if(!device())
+ // return;
QString s;
@@ -1062,3 +1067,20 @@ void MidiPort::writeRouting(int level, Xml& xml) const
}
}
+// p4.0.17 Turn off if and when multiple output routes supported.
+#if 1
+//---------------------------------------------------------
+// setPortExclusiveDefOutChan
+//---------------------------------------------------------
+
+void setPortExclusiveDefOutChan(int port, int c)
+{
+ if(port < 0 || port >= MIDI_PORTS)
+ return;
+ midiPorts[port].setDefaultOutChannels(c);
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ if(i != port)
+ midiPorts[i].setDefaultOutChannels(0);
+}
+#endif
+
diff --git a/muse2/muse/midiport.h b/muse2/muse/midiport.h
index 0fa33a11..46107a8d 100644
--- a/muse2/muse/midiport.h
+++ b/muse2/muse/midiport.h
@@ -127,6 +127,11 @@ class MidiPort {
extern MidiPort midiPorts[MIDI_PORTS];
extern void initMidiPorts();
+// p4.0.17 Turn off if and when multiple output routes supported.
+#if 1
+extern void setPortExclusiveDefOutChan(int /*port*/, int /*chan*/);
+#endif
+
class QMenu;
class QWidget;
//extern QPopupMenu* midiPortsPopup(QWidget*);
diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp
index 1ed476ab..4e3fbe26 100644
--- a/muse2/muse/mixer/astrip.cpp
+++ b/muse2/muse/mixer/astrip.cpp
@@ -1568,7 +1568,11 @@ static int addMidiPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenuMap& mm,
//if(!(md->rwFlags() & (isOutput ? 1 : 2)))
// continue;
- RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
+ // p4.0.17 Do not list synth devices!
+ if(md->isSynti())
+ continue;
+
+ RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
PopupMenu* subp = new PopupMenu(pup);
subp->setTitle(md->name());
diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp
index c3df6517..6f42c1f2 100644
--- a/muse2/muse/route.cpp
+++ b/muse2/muse/route.cpp
@@ -401,6 +401,15 @@ void addRoute(Route src, Route dst)
}
*/
+ MidiPort *mp = &midiPorts[src.midiPort];
+
+ // p4.0.17 Do not allow ports with synth midi devices to connect to audio ins!
+ if(dst.track->type() == Track::AUDIO_INPUT && mp->device() && mp->device()->isSynti())
+ {
+ fprintf(stderr, "addRoute: destination is audio in, but source midi port:%d is synth device\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);
@@ -414,8 +423,6 @@ void addRoute(Route src, Route dst)
// return;
//}
- MidiPort *mp = &midiPorts[src.midiPort];
-
src.channel = dst.channel;
RouteList* outRoutes = mp->outRoutes();
//for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp
index 6b9c7e09..cf972b8c 100644
--- a/muse2/muse/song.cpp
+++ b/muse2/muse/song.cpp
@@ -260,17 +260,20 @@ Track* Song::addTrack(int t)
{
MidiTrack* mt = (MidiTrack*)track;
int c, cbi, ch;
- bool defOutFound = false; /// TODO: Remove this when multiple out routes supported.
+ bool defOutFound = false; /// TODO: Remove this if and when multiple output routes supported.
for(int i = 0; i < MIDI_PORTS; ++i)
{
MidiPort* mp = &midiPorts[i];
- c = mp->defaultInChannels();
- if(c)
+ if(mp->device()) // Only if device is valid. p4.0.17
{
- audio->msgAddRoute(Route(i, c), Route(track, c));
- updateFlags |= SC_ROUTE;
- }
+ c = mp->defaultInChannels();
+ if(c)
+ {
+ audio->msgAddRoute(Route(i, c), Route(track, c));
+ updateFlags |= SC_ROUTE;
+ }
+ }
if(!defOutFound) ///
{
@@ -278,7 +281,7 @@ Track* Song::addTrack(int t)
if(c)
{
- /// TODO: Switch when multiple out routes supported.
+ /// TODO: Switch if and when multiple output routes supported.
#if 0
audio->msgAddRoute(Route(track, c), Route(i, c));
updateFlags |= SC_ROUTE;
@@ -290,7 +293,8 @@ Track* Song::addTrack(int t)
{
defOutFound = true;
mt->setOutPort(i);
- mt->setOutChannel(ch);
+ if(type != Track::DRUM) // p4.0.17 Leave drum tracks at channel 10.
+ mt->setOutChannel(ch);
updateFlags |= SC_ROUTE;
break;
}
@@ -2019,9 +2023,10 @@ void Song::panic()
// signal - emit signals for changes if true
// called from constructor as clear(false) and
// from MusE::clearSong() as clear(false)
+// If clear_all is false, it will not touch things like midi ports.
//---------------------------------------------------------
-void Song::clear(bool signal)
+void Song::clear(bool signal, bool /*clear_all*/)
{
if(debugMsg)
printf("Song::clear\n");
@@ -2046,8 +2051,9 @@ void Song::clear(bool signal)
// p3.3.50 Reset this.
midiPorts[i].setFoundInSongFile(false);
- // This will also close the device.
- midiPorts[i].setMidiDevice(0);
+ //if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems...
+ // This will also close the device.
+ midiPorts[i].setMidiDevice(0);
}
_synthIs.clearDelete();
@@ -2064,15 +2070,18 @@ void Song::clear(bool signal)
//if((*imd)->deviceType() == MidiDevice::JACK_MIDI)
if(dynamic_cast< MidiJackDevice* >(*imd))
{
- // Remove the device from the list.
- midiDevices.erase(imd);
- // Since Jack midi devices are created dynamically, we must delete them.
- // The destructor unregisters the device from Jack, which also disconnects all device-to-jack routes.
- // This will also delete all midi-track-to-device routes, they point to non-existant midi tracks
- // which were all deleted above
- delete (*imd);
- loop = true;
- break;
+ //if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems...
+ {
+ // Remove the device from the list.
+ midiDevices.erase(imd);
+ // Since Jack midi devices are created dynamically, we must delete them.
+ // The destructor unregisters the device from Jack, which also disconnects all device-to-jack routes.
+ // This will also delete all midi-track-to-device routes, they point to non-existant midi tracks
+ // which were all deleted above
+ delete (*imd);
+ loop = true;
+ break;
+ }
}
else
//if((*imd)->deviceType() == MidiDevice::ALSA_MIDI)
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index 90dc3205..adcbc0ae 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -168,7 +168,8 @@ class Song : public QObject {
QString getSongInfo() { return songInfoStr; }
void setSongInfo(QString info) { songInfoStr = info; }
- void clear(bool signal);
+ // If clear_all is false, it will not touch things like midi ports.
+ void clear(bool signal, bool clear_all = true);
void update(int flags = -1);
void cleanupForQuit();
diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp
index 5038820e..bd3d7548 100644
--- a/muse2/muse/track.cpp
+++ b/muse2/muse/track.cpp
@@ -447,6 +447,23 @@ void MidiTrack::setOutPortAndUpdate(int i)
}
//---------------------------------------------------------
+// setOutPortAndChannelAndUpdate
+//---------------------------------------------------------
+
+void MidiTrack::setOutPortAndChannelAndUpdate(int port, int ch)
+{
+ if(_outPort == port && _outChannel == ch)
+ return;
+
+ //removePortCtrlEvents();
+ removePortCtrlEvents(this);
+ _outPort = port;
+ _outChannel = ch;
+ //addPortCtrlEvents();
+ addPortCtrlEvents(this);
+}
+
+//---------------------------------------------------------
// setInPortAndChannelMask
// For old song files with port mask (max 32 ports) and channel mask (16 channels),
// before midi routing was added (the iR button). p3.3.48
diff --git a/muse2/muse/track.h b/muse2/muse/track.h
index 48c9474e..531dd2d5 100644
--- a/muse2/muse/track.h
+++ b/muse2/muse/track.h
@@ -239,8 +239,11 @@ class MidiTrack : public Track {
void setOutChannel(int i) { _outChannel = i; }
void setOutPort(int i) { _outPort = i; }
- void setOutChanAndUpdate(int i);
- void setOutPortAndUpdate(int i);
+ // These will transfer controller data to the new selected port and/or channel.
+ void setOutChanAndUpdate(int /*chan*/);
+ void setOutPortAndUpdate(int /*port*/);
+ // Combines both port and channel operations.
+ void setOutPortAndChannelAndUpdate(int /*port*/, int /*chan*/);
//void setInPortMask(int i) { _inPortMask = i; }
///void setInPortMask(unsigned int i) { _inPortMask = i; } // Obsolete
diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp
index 04911b02..acdfb42f 100644
--- a/muse2/muse/widgets/mtrackinfo.cpp
+++ b/muse2/muse/widgets/mtrackinfo.cpp
@@ -614,18 +614,30 @@ void MidiTrackInfo::inRoutesPressed()
PopupMenu* pup = muse->prepareRoutingPopupMenu(selected, false);
//PopupView* pup = muse->prepareRoutingPopupView(selected, false);
- if(!pup) {
- int ret = QMessageBox::warning(this, tr("No inputs"),
- tr("There are no midi inputs.\n"
+ /*
+ QPoint ppt = QCursor::pos();
+
+ int i = 0;
+ for( ; i < MIDI_PORTS; ++i)
+ {
+ if(midiPorts[i].device() && !midiPorts[pi].device()->isSynti())
+ break;
+ }
+ if(!pup || i == MIDI_PORTS)
+ {
+ int ret = QMessageBox::warning(this, tr("No devices"),
+ tr("There are no midi port devices defined.\n"
"Do you want to open the midi configuration dialog?"),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok);
if (ret == QMessageBox::Ok) {
- printf("open config midi ports\n");
+ //printf("open config midi ports\n");
muse->configMidiPorts();
}
- return;
+ if(!pup)
+ return;
}
+ */
///gRoutingPopupMenuMaster = midiTrackInfo;
gRoutingPopupMenuMaster = this;