From aae64c142b4492c4613f483e0d961897deb06233 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Sat, 11 Dec 2010 08:46:41 +0000 Subject: Feature: Added default midi track in/out channels to midi ports list. See ChangeLog. --- muse2/ChangeLog | 9 +++++ muse2/muse/arranger/trackinfo.cpp | 11 +++--- muse2/muse/conf.cpp | 69 +++++++++++++++++++++++++++++------- muse2/muse/confmport.cpp | 53 ++++++++++++++++++++++++++- muse2/muse/midiport.cpp | 5 ++- muse2/muse/midiport.h | 7 ++++ muse2/muse/song.cpp | 61 +++++++++++++++++++++++++++---- muse2/muse/sync.cpp | 16 +++++++-- muse2/muse/sync.h | 1 + muse2/muse/widgets/mtrackinfobase.ui | 12 ++----- 10 files changed, 208 insertions(+), 36 deletions(-) diff --git a/muse2/ChangeLog b/muse2/ChangeLog index c51dd3b1..8a7579d8 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,12 @@ +11.12.2010: + * Feature: Added default midi track in/out channels to midi ports list. (Tim) + - For now, the boxes use the old text channel strings ("1 3 5", "1-5", "all, "none" etc.) + * Changed: Experimental: Mid ports now default to 'GM' instrument. (Tim) + - Was stopping new users from seeing instrument patches etc. + - TODO: Overhaul instrument type, instrument sysexes, and song type. + * Changed: Audio groups and inputs no longer default connect to first audio out. (Tim) + - Find it tedious, once a song grows with groups and inputs, to keep disconnecting them from output. + - TODO: Add a better audio default routing system. 10.12.2010: - More compiler and build warnings fixes. (Orcan) - Restored the scripts menu and fixed scripts handling. Tested OK. (Orcan) diff --git a/muse2/muse/arranger/trackinfo.cpp b/muse2/muse/arranger/trackinfo.cpp index 13197f50..20673b25 100644 --- a/muse2/muse/arranger/trackinfo.cpp +++ b/muse2/muse/arranger/trackinfo.cpp @@ -1192,10 +1192,12 @@ void Arranger::genMidiTrackInfo() //midiTrackInfo->iChanDetectLabel->setPixmap(*darkgreendotIcon); midiTrackInfo->iChanDetectLabel->setPixmap(*darkRedLedIcon); - QIcon recEchoIconSet; - recEchoIconSet.addPixmap(*recEchoIconOn, QIcon::Normal, QIcon::On); - recEchoIconSet.addPixmap(*recEchoIconOff, QIcon::Normal, QIcon::Off); - midiTrackInfo->recEchoButton->setIcon(recEchoIconSet); + //QIcon recEchoIconSet; + //recEchoIconSet.addPixmap(*recEchoIconOn, QIcon::Normal, QIcon::On); + //recEchoIconSet.addPixmap(*recEchoIconOff, QIcon::Normal, QIcon::Off); + //midiTrackInfo->recEchoButton->setIcon(recEchoIconSet); + midiTrackInfo->recEchoButton->setIcon(QIcon(*edit_midiIcon)); + midiTrackInfo->recEchoButton->setIconSize(edit_midiIcon->size()); // MusE-2: AlignCenter and WordBreak are set in the ui(3) file, but not supported by QLabel. Turn them on here. @@ -1258,6 +1260,7 @@ void Arranger::genMidiTrackInfo() // TODO: Works OK, but disabled for now, until we figure out what to do about multiple out routes and display values... midiTrackInfo->oRButton->setEnabled(false); + midiTrackInfo->oRButton->setVisible(false); connect(midiTrackInfo->oRButton, SIGNAL(pressed()), SLOT(outRoutesPressed())); connect(heartBeatTimer, SIGNAL(timeout()), SLOT(midiTrackInfoHeartBeat())); diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp index 9ab9e594..315ce9cd 100644 --- a/muse2/muse/conf.cpp +++ b/muse2/muse/conf.cpp @@ -200,9 +200,20 @@ static void readConfigMidiPort(Xml& xml) { int idx = 0; QString device; - QString instrument; + + //QString instrument; + // Changed by Tim. + //QString instrument("generic midi"); + // Let's be bold. New users have been confused by generic midi not enabling any patches and controllers. + // I had said this may cause HW problems by sending out GM sysEx when really the HW might not be GM. + // But this really needs to be done, one way or another. + // FIXME: TODO: Make this user-configurable! + QString instrument("GM"); + int openFlags = 1; bool thruFlag = false; + int dic = 0; + int doc = 0; MidiSyncInfo tmpSi; int type = MidiDevice::ALSA_MIDI; @@ -224,13 +235,18 @@ static void readConfigMidiPort(Xml& xml) } else if (tag == "openFlags") openFlags = xml.parseInt(); + else if (tag == "defaultInChans") + dic = xml.parseInt(); + else if (tag == "defaultOutChans") + doc = xml.parseInt(); else if (tag == "midiSyncInfo") tmpSi.read(xml); else if (tag == "instrument") { instrument = xml.parse1(); - midiPorts[idx].setInstrument( - registerMidiInstrument(instrument) - ); + // Moved by Tim. + //midiPorts[idx].setInstrument( + // registerMidiInstrument(instrument) + // ); } else if (tag == "midithru") thruFlag = xml.parseInt(); // obsolete @@ -271,6 +287,11 @@ static void readConfigMidiPort(Xml& xml) fprintf(stderr, "readConfigMidiPort: device not found %s\n", device.toLatin1().constData()); MidiPort* mp = &midiPorts[idx]; + + mp->setInstrument(registerMidiInstrument(instrument)); // By Tim. + mp->setDefaultInChannels(dic); + mp->setDefaultOutChannels(doc); + 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); @@ -946,20 +967,42 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo) // for (int i = 0; i < MIDI_PORTS; ++i) { bool used = false; - MidiTrackList* tl = song->midis(); - for (iMidiTrack it = tl->begin(); it != tl->end(); ++it) { - MidiTrack* t = *it; - if (t->outPort() == i) { - used = true; - break; - } - } MidiPort* mport = &midiPorts[i]; + // 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() || + (!mport->instrument()->iname().isEmpty() && mport->instrument()->iname() != "GM") || + !mport->syncInfo().isDefault()) + used = true; + else + { + MidiTrackList* tl = song->midis(); + for (iMidiTrack it = tl->begin(); it != tl->end(); ++it) + { + MidiTrack* t = *it; + if (t->outPort() == i) + { + used = true; + break; + } + } + } + MidiDevice* dev = mport->device(); if (!used && !dev) continue; xml.tag(level++, "midiport idx=\"%d\"", i); - xml.strTag(level, "instrument", mport->instrument()->iname()); + + if(mport->defaultInChannels()) + xml.intTag(level, "defaultInChans", mport->defaultInChannels()); + if(mport->defaultOutChannels()) + xml.intTag(level, "defaultOutChans", mport->defaultOutChannels()); + + if(!mport->instrument()->iname().isEmpty() && // Tim. + (mport->instrument()->iname() != "GM")) // FIXME: TODO: Make this user configurable. + xml.strTag(level, "instrument", mport->instrument()->iname()); + if (dev) { xml.strTag(level, "name", dev->name()); diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp index 203e0a63..30318f03 100644 --- a/muse2/muse/confmport.cpp +++ b/muse2/muse/confmport.cpp @@ -36,13 +36,15 @@ #include "driver/jackmidi.h" #include "audiodev.h" #include "menutitleitem.h" +#include "utils.h" extern std::vector 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_STATE }; // p3.3.55 + DEVCOL_INROUTES, DEVCOL_OUTROUTES, DEVCOL_DEF_IN_CHANS, DEVCOL_DEF_OUT_CHANS, DEVCOL_STATE }; //--------------------------------------------------------- // mdevViewItemRenamed @@ -57,6 +59,26 @@ void MPConfig::mdevViewItemRenamed(QTableWidgetItem* item) return; switch(col) { + 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(string2bitmap(s)); + song->update(); + } + break; + 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(string2bitmap(s)); + song->update(); + } + break; case DEVCOL_NAME: { QString id = item->tableWidget()->item(item->row(), DEVCOL_NO)->text(); @@ -358,6 +380,13 @@ void MPConfig::rbClicked(QTableWidgetItem* item) //break; return; + case DEVCOL_DEF_IN_CHANS: + case DEVCOL_DEF_OUT_CHANS: + { + } + //break; + return; + case DEVCOL_NAME: { //printf("MPConfig::rbClicked DEVCOL_NAME\n"); @@ -623,6 +652,8 @@ 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_STATE: item->setToolTip(tr("Device state")); break; default: return; } @@ -654,6 +685,18 @@ void MPConfig::setWhatsThis(QTableWidgetItem *item, int col) item->setWhatsThis(tr("Connections from Jack Midi output ports")); break; 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; + 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; case DEVCOL_STATE: item->setWhatsThis(tr("State: result of opening the device")); break; default: @@ -700,6 +743,8 @@ MPConfig::MPConfig(QWidget* parent) << tr("Device Name") << tr("In routes") << tr("Out routes") + << tr("Def in ch") + << tr("Def out ch") << tr("State"); mdevView->setColumnCount(columnnames.size()); @@ -804,6 +849,12 @@ 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())); + addItem(i, DEVCOL_DEF_IN_CHANS, itemdefin, mdevView); + itemdefin->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled); + QTableWidgetItem* itemdefout = new QTableWidgetItem(bitmap2String(port->defaultOutChannels())); + addItem(i, DEVCOL_DEF_OUT_CHANS, itemdefout, mdevView); + itemdefout->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled); mdevView->blockSignals(false); diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp index c6601591..0df08a59 100644 --- a/muse2/muse/midiport.cpp +++ b/muse2/muse/midiport.cpp @@ -37,7 +37,8 @@ void initMidiPorts() { for (int i = 0; i < MIDI_PORTS; ++i) { MidiPort* port = &midiPorts[i]; - port->setInstrument(genericMidiInstrument); + ///port->setInstrument(genericMidiInstrument); + port->setInstrument(registerMidiInstrument("GM")); // Changed by Tim. port->syncInfo().setPort(i); } } @@ -49,6 +50,8 @@ void initMidiPorts() MidiPort::MidiPort() : _state("not configured") { + _defaultInChannels = 0; + _defaultOutChannels = 0; _device = 0; _instrument = 0; _controller = new MidiCtrlValListList(); diff --git a/muse2/muse/midiport.h b/muse2/muse/midiport.h index 5ba08d67..7ee83cc9 100644 --- a/muse2/muse/midiport.h +++ b/muse2/muse/midiport.h @@ -36,6 +36,9 @@ class MidiPort { 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; + // When creating a new midi track, add these global default channel routes to/from this port. Ignored if 0. + int _defaultInChannels; // These are bit-wise channel masks. + int _defaultOutChannels; // RouteList _inRoutes, _outRoutes; @@ -84,6 +87,10 @@ class MidiPort { int nullSendValue(); void setNullSendValue(int v); + int defaultInChannels() const { return _defaultInChannels; } + int defaultOutChannels() const { return _defaultOutChannels; } + void setDefaultInChannels(int c) { _defaultInChannels = c; } + void setDefaultOutChannels(int c) { _defaultOutChannels = c; } RouteList* inRoutes() { return &_inRoutes; } RouteList* outRoutes() { return &_outRoutes; } bool noInRoute() const { return _inRoutes.empty(); } diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 64287e14..407b8dce 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -254,6 +254,52 @@ Track* Song::addTrack(int t) msgInsertTrack(track, -1, true); insertTrack3(track, -1); + // Add default track <-> midiport routes. + if(track->isMidiTrack()) + { + MidiTrack* mt = (MidiTrack*)track; + int c, cbi, ch; + bool defOutFound = false; /// TODO: Remove this when multiple out routes supported. + for(int i = 0; i < MIDI_PORTS; ++i) + { + MidiPort* mp = &midiPorts[i]; + + c = mp->defaultInChannels(); + if(c) + { + audio->msgAddRoute(Route(i, c), Route(track, c)); + updateFlags |= SC_ROUTE; + } + + if(!defOutFound) /// + { + c = mp->defaultOutChannels(); + if(c) + { + + /// TODO: Switch when multiple out routes supported. + #if 0 + audio->msgAddRoute(Route(track, c), Route(i, c)); + updateFlags |= SC_ROUTE; + #else + for(ch = 0; ch < MIDI_CHANNELS; ++ch) + { + cbi = 1 << ch; + if(c & cbi) + { + defOutFound = true; + mt->setOutPort(i); + mt->setOutChannel(ch); + updateFlags |= SC_ROUTE; + break; + } + } + #endif + } + } + } + } + // // add default route to master // @@ -261,14 +307,15 @@ Track* Song::addTrack(int t) if (!ol->empty()) { AudioOutput* ao = ol->front(); switch(type) { - case Track::MIDI: - case Track::DRUM: - case Track::AUDIO_OUTPUT: - break; + //case Track::MIDI: + //case Track::DRUM: + //case Track::AUDIO_OUTPUT: + // break; + case Track::WAVE: - case Track::AUDIO_GROUP: + //case Track::AUDIO_GROUP: // Removed by Tim. case Track::AUDIO_AUX: - case Track::AUDIO_INPUT: + //case Track::AUDIO_INPUT: // Removed by Tim. // p3.3.38 //case Track::AUDIO_SOFTSYNTH: audio->msgAddRoute(Route((AudioTrack*)track, -1), Route(ao, -1)); @@ -279,6 +326,8 @@ Track* Song::addTrack(int t) audio->msgAddRoute(Route((AudioTrack*)track, 0, ((AudioTrack*)track)->channels()), Route(ao, 0, ((AudioTrack*)track)->channels())); updateFlags |= SC_ROUTE; break; + default: + break; } } audio->msgUpdateSoloStates(); diff --git a/muse2/muse/sync.cpp b/muse2/muse/sync.cpp index c1056e82..9fe5f4d3 100644 --- a/muse2/muse/sync.cpp +++ b/muse2/muse/sync.cpp @@ -401,6 +401,16 @@ void MidiSyncInfo::trigActDetect(const int ch) _actTrig[ch] = true; } +//--------------------------------------------------------- +// isDefault +//--------------------------------------------------------- + +bool MidiSyncInfo::isDefault() const +{ + return(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMRT && !_sendMMC && !_sendMTC && + /* !_sendContNotStart && */ !_recMC && !_recMRT && !_recMMC && !_recMTC && _recRewOnStart); +} + //--------------------------------------------------------- // read //--------------------------------------------------------- @@ -462,8 +472,10 @@ void MidiSyncInfo::write(int level, Xml& xml) // return; // All defaults? Nothing to write. - if(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMRT && !_sendMMC && !_sendMTC && - /* !_sendContNotStart && */ !_recMC && !_recMRT && !_recMMC && !_recMTC && _recRewOnStart) + //if(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMRT && !_sendMMC && !_sendMTC && + // /* !_sendContNotStart && */ !_recMC && !_recMRT && !_recMMC && !_recMTC && _recRewOnStart) + // return; + if(isDefault()) return; xml.tag(level++, "midiSyncInfo"); diff --git a/muse2/muse/sync.h b/muse2/muse/sync.h index d6a08f0d..47acece8 100644 --- a/muse2/muse/sync.h +++ b/muse2/muse/sync.h @@ -120,6 +120,7 @@ class MidiSyncInfo bool actDetect(const int ch) const; void trigActDetect(const int ch); + bool isDefault() const; void read(Xml& xml); //void write(int level, Xml& xml, MidiDevice* md); void write(int level, Xml& xml); diff --git a/muse2/muse/widgets/mtrackinfobase.ui b/muse2/muse/widgets/mtrackinfobase.ui index 30b111c2..43cf6927 100644 --- a/muse2/muse/widgets/mtrackinfobase.ui +++ b/muse2/muse/widgets/mtrackinfobase.ui @@ -330,7 +330,7 @@ input routing - iR + Inputs @@ -389,17 +389,11 @@ 0 - - - 14 - 32767 - - - Echo + Midi thru - Echo recording events to output. + Pass input events through ('thru') to output. true -- cgit v1.2.3