diff options
| author | Tim E. Real <termtech@rogers.com> | 2011-02-24 17:27:04 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2011-02-24 17:27:04 +0000 | 
| commit | cc12a523f8f4065f133b1ec38ccba2e7be74d48b (patch) | |
| tree | ce42861856bbf2b23ae7f21f02aabbc775ad9a32 /muse2/muse | |
| parent | 8e4d18fdcc12c7202e287cc8a2ec2214667c8844 (diff) | |
Improved midi auto-connections. Fixed Organ synth crashing.
Diffstat (limited to 'muse2/muse')
| -rw-r--r-- | muse2/muse/app.cpp | 142 | ||||
| -rw-r--r-- | muse2/muse/app.h | 3 | ||||
| -rw-r--r-- | muse2/muse/arranger/tlist.cpp | 14 | ||||
| -rw-r--r-- | muse2/muse/conf.cpp | 34 | ||||
| -rw-r--r-- | muse2/muse/confmport.cpp | 456 | ||||
| -rw-r--r-- | muse2/muse/confmport.h | 5 | ||||
| -rw-r--r-- | muse2/muse/midiport.cpp | 30 | ||||
| -rw-r--r-- | muse2/muse/midiport.h | 5 | ||||
| -rw-r--r-- | muse2/muse/mixer/astrip.cpp | 6 | ||||
| -rw-r--r-- | muse2/muse/route.cpp | 11 | ||||
| -rw-r--r-- | muse2/muse/song.cpp | 49 | ||||
| -rw-r--r-- | muse2/muse/song.h | 3 | ||||
| -rw-r--r-- | muse2/muse/track.cpp | 17 | ||||
| -rw-r--r-- | muse2/muse/track.h | 7 | ||||
| -rw-r--r-- | muse2/muse/widgets/mtrackinfo.cpp | 22 | 
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; | 
