diff options
| author | Tim E. Real <termtech@rogers.com> | 2010-03-31 04:29:35 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2010-03-31 04:29:35 +0000 | 
| commit | 877df47f6c8021a4377e76720e7f13943404f20b (patch) | |
| tree | ee93dcbcc70178350571249f6df04ee5996b47b6 | |
| parent | a278b34a6c2a47d6cf0c9b5ebfc696f5bf2c984d (diff) | |
See ChangeLog
45 files changed, 6219 insertions, 1060 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog index a9505d58..cdf4928f 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,24 @@ +30.03.2010 +      * Major reworks: Jack midi, routing system, multichannel synth ins/outs, midi strips and trackinfo pane. (T356) +        - WORK IN PROGRESS. Should be usable for current projects. +        - ADVISORY: If opening current projects you are advised to "save as" or back up your med files (waves should be OK) +           until all is deemed to be working OK. It is possible more changes to .med file structure are needed later. +        - Some .med project file structures have CHANGED (like routing). I have tested opening large existing projects,  +           then re-saving them. OK so far. +          However, I have not added importing code for the old midi trackinfo panel 'input port' and 'input channel' boxes (gone now). +          If you want to wait, I am planning to do that, but later... Otherwise you must re-enter them with the new midi input routing. +        - ** Multichannel synth inputs and outputs: Fairly satisfied with popup menus, hopefully no major reworks...  +          Routing system fully supports multichannel synth mono/stero paths but is NOT COMPLETE yet.  +          When changing a connected track from stereo to mono, there is no coding yet to ensure the existing stereo routes are  +           changed from stereo to mono (just like the audio input and output tracks have always done with Jack routes). +          Also coding must be added to avoid simultaneous mono and stereo routes - make them mutually exclusive - although +           there's nothing technically wrong with it, it's just not desirable.  +        - ** Jack midi: You now create your own Jack midi ports. I have not added any means to delete them yet, but I believe +           if you 'unselect' them in the midi ports list so that they are not used, then the saved .med file will ignore them. +        - Multi-instances of MusE should work OK now - all ports should hopefully have unique names.     +        - Number of midi ports increased from 32 to 128. It's a bit much for the ports list, was planning "create your own +           midi port as needed" (like RG). Obstacles seem to have been cleared now, but it would be a big job (lots of places to change). +        - Along the way various tweaks and fixes when I spotted them.  18.02.2010        * Added: Separate Jack midi client ports per MusE port. (T356)          - For now, you will have to manually add further connections to those ports if desired, each session. diff --git a/muse/muse/app.cpp b/muse/muse/app.cpp index 6bc52319..219f59bd 100644 --- a/muse/muse/app.cpp +++ b/muse/muse/app.cpp @@ -95,7 +95,8 @@  #include "didyouknow.h"  #include <qtextedit.h> -extern void cacheJackRouteNames(); +//extern void cacheJackRouteNames(); +  static pthread_t watchdogThread;  //ErrorHandler *error;  static const char* fileOpenText = @@ -1698,7 +1699,9 @@ bool MusE::save(const QString& name, bool overwriteWarn)        // By T356. Cache the jack in/out route names BEFORE saving.         // Because jack often shuts down during save, causing the routes to be lost in the file. -      cacheJackRouteNames(); +      // Not required any more... +      //cacheJackRouteNames(); +              if (QFile::exists(name)) {              backupCommand.sprintf("cp \"%s\" \"%s.backup\"", name.latin1(), name.latin1());              } @@ -2659,7 +2662,9 @@ int main(int argc, char* argv[])            lash_client = lash_init (lash_args, muse_name, lash_flags, LASH_PROTOCOL(2,0));            lash_alsa_client_id (lash_client, snd_seq_client_id (alsaSeq));            if (!noAudio) { -                char *jack_name = ((JackAudioDevice*)audioDevice)->getJackName(); +                // p3.3.38 +                //char *jack_name = ((JackAudioDevice*)audioDevice)->getJackName(); +                const char *jack_name = audioDevice->clientName();                  lash_jack_client_name (lash_client, jack_name);            }                } diff --git a/muse/muse/arranger/arranger.h b/muse/muse/arranger/arranger.h index 5a402585..c43320cb 100644 --- a/muse/muse/arranger/arranger.h +++ b/muse/muse/arranger/arranger.h @@ -132,9 +132,9 @@ class Arranger : public QWidget {        void trackInfoScroll(int);        //void iNameChanged(); -      void iInputChannelChanged(const QString&); +      ///void iInputChannelChanged(const QString&);        void iOutputChannelChanged(int); -      void iInputPortChanged(const QString&); +      ///void iInputPortChanged(const QString&);        void iOutputPortChanged(int);        void iProgHBankChanged();        void iProgLBankChanged(); @@ -166,6 +166,8 @@ class Arranger : public QWidget {        void panRecClicked();        void recEchoToggled(bool);        void verticalScrollSetYpos(unsigned); +      void inRoutesPressed(); +      void outRoutesPressed();     signals:        void redirectWheelEvent(QWheelEvent*); diff --git a/muse/muse/arranger/trackinfo.cpp b/muse/muse/arranger/trackinfo.cpp index 914d98e6..bc1cf939 100644 --- a/muse/muse/arranger/trackinfo.cpp +++ b/muse/muse/arranger/trackinfo.cpp @@ -40,6 +40,7 @@  #include "mixer/astrip.h"  #include "icons.h"  #include "app.h" +#include "route.h"  //--------------------------------------------------------- @@ -59,9 +60,9 @@ void Arranger::midiTrackInfoHeartBeat()        int outChannel = track->outChannel();        int outPort    = track->outPort(); -      int ichMask    = track->inChannelMask(); +      ///int ichMask    = track->inChannelMask();        //int iptMask    = track->inPortMask(); -      unsigned int iptMask    = track->inPortMask(); +      ///unsigned int iptMask    = track->inPortMask();        MidiPort* mp = &midiPorts[outPort]; @@ -76,19 +77,36 @@ void Arranger::midiTrackInfoHeartBeat()        // Check for detection of midi general activity on chosen channels...        int mpt = 0;        //int mch = 0; -      for(; mpt < MIDI_PORTS; ++mpt) +      RouteList* rl = track->inRoutes(); +       +      ciRoute r = rl->begin(); +      //for( ; mpt < MIDI_PORTS; ++mpt) +      for( ; r != rl->end(); ++r)        { +        //if(!r->isValid() || ((r->type != Route::ALSA_MIDI_ROUTE) && (r->type != Route::JACK_MIDI_ROUTE))) +        if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) +          continue; +         +        // NOTE: TODO: Code for channelless events like sysex, ** IF we end up using the 'special channel 17' method. +        if(r->channel == -1) +          continue; +         +        // No port assigned to the device? +        mpt = r->device->midiPort(); +        if(mpt == -1) +          continue; +                  //for(; mch < MIDI_CHANNELS; ++mch)          //{            //if(midiPorts[mpt].syncInfo().actDetect(mch) && (iptMask & (1 << mpt)) && (ichMask & (1 << mch)) ) -          if((iptMask & bitShiftLU[mpt]) && (midiPorts[mpt].syncInfo().actDetectBits() & ichMask) ) +          //if((iptMask & bitShiftLU[mpt]) && (midiPorts[mpt].syncInfo().actDetectBits() & ichMask) ) +          if(midiPorts[mpt].syncInfo().actDetectBits() & bitShiftLU[r->channel])             {              //if(midiTrackInfo->iChanTextLabel->paletteBackgroundColor() != green)              //  midiTrackInfo->iChanTextLabel->setPaletteBackgroundColor(green);              //if(midiTrackInfo->iChanDetectLabel->pixmap() != greendotIcon)              if(!midiTrackInfo->_midiDetect)              { -              // Added by Tim. p3.3.6                //printf("Arranger::midiTrackInfoHeartBeat setting green icon\n");                midiTrackInfo->_midiDetect = true; @@ -101,14 +119,14 @@ void Arranger::midiTrackInfoHeartBeat()        }        // No activity detected?        //if(mch == MIDI_CHANNELS) -      if(mpt == MIDI_PORTS) +      //if(mpt == MIDI_PORTS) +      if(r == rl->end())        {          //if(midiTrackInfo->iChanTextLabel->paletteBackgroundColor() != darkGreen)          //  midiTrackInfo->iChanTextLabel->setPaletteBackgroundColor(darkGreen);          //if(midiTrackInfo->iChanDetectLabel->pixmap() != darkgreendotIcon)          if(midiTrackInfo->_midiDetect)          { -          // Added by Tim. p3.3.6            //printf("Arranger::midiTrackInfoHeartBeat setting darkgreen icon\n");            midiTrackInfo->_midiDetect = false; @@ -122,7 +140,6 @@ void Arranger::midiTrackInfoHeartBeat()        {          if(program != CTRL_VAL_UNKNOWN)          { -          // Added by Tim. p3.3.6            //printf("Arranger::midiTrackInfoHeartBeat setting program to unknown\n");            program = CTRL_VAL_UNKNOWN; @@ -154,7 +171,6 @@ void Arranger::midiTrackInfoHeartBeat()            //if(strcmp(midiTrackInfo->iPatch->text().latin1(), n) != 0)            if(midiTrackInfo->iPatch->text() != n)            { -            // Added by Tim. p3.3.6              //printf("Arranger::midiTrackInfoHeartBeat setting patch <unknown>\n");              midiTrackInfo->iPatch->setText(n); @@ -172,7 +188,6 @@ void Arranger::midiTrackInfoHeartBeat()            else            if(strcmp(midiTrackInfo->iPatch->text().latin1(), name) != 0)            { -            // Added by Tim. p3.3.6              //printf("Arranger::midiTrackInfoHeartBeat setting patch name\n");              midiTrackInfo->iPatch->setText(name); @@ -207,7 +222,6 @@ void Arranger::midiTrackInfoHeartBeat()                          pr = 0;              //} -            // Added by Tim. p3.3.6              //printf("Arranger::midiTrackInfoHeartBeat setting program\n");              if(midiTrackInfo->iHBank->value() != hb) @@ -249,7 +263,6 @@ void Arranger::midiTrackInfoHeartBeat()          volume = v;          if(midiTrackInfo->iLautst->value() != v)          { -          // Added by Tim. p3.3.6            //printf("Arranger::midiTrackInfoHeartBeat setting volume\n");            midiTrackInfo->iLautst->blockSignals(true); @@ -277,7 +290,6 @@ void Arranger::midiTrackInfoHeartBeat()          pan = v;          if(midiTrackInfo->iPan->value() != v)          { -          // Added by Tim. p3.3.6            //printf("Arranger::midiTrackInfoHeartBeat setting pan\n");            midiTrackInfo->iPan->blockSignals(true); @@ -405,7 +417,6 @@ void Arranger::switchInfo(int n)  //---------------------------------------------------------  //   setTrackInfoLabelText  //--------------------------------------------------------- -// Added by Tim. p3.3.9  void Arranger::setTrackInfoLabelText()  { @@ -419,7 +430,6 @@ void Arranger::setTrackInfoLabelText()  //---------------------------------------------------------  //   setTrackInfoLabelFont  //--------------------------------------------------------- -// Added by Tim. p3.3.9  void Arranger::setTrackInfoLabelFont()  { @@ -498,6 +508,7 @@ void Arranger::iOutputChannelChanged(int channel)              }        } +/*  //---------------------------------------------------------  //   iKanalChanged  //--------------------------------------------------------- @@ -511,6 +522,7 @@ void Arranger::iInputChannelChanged(const QString& s)              list->redraw();              }        } +*/  //---------------------------------------------------------  //   iOutputPortChanged @@ -531,6 +543,7 @@ void Arranger::iOutputPortChanged(int index)        list->redraw();        } +/*  //---------------------------------------------------------  //   iInputPortChanged  //--------------------------------------------------------- @@ -547,6 +560,31 @@ void Arranger::iInputPortChanged(const QString& s)        track->setInPortMask(val);        list->redraw();        } +*/ + +//--------------------------------------------------------- +//   inRoutesPressed +//--------------------------------------------------------- + +void Arranger::inRoutesPressed() +{ +  if(!selected) +    return; +     +  song->chooseMidiRoutes(midiTrackInfo->iRButton, (MidiTrack*)selected, false); +} + +//--------------------------------------------------------- +//   outRoutesPressed +//--------------------------------------------------------- + +void Arranger::outRoutesPressed() +{ +  if(!selected) +    return; +     +  song->chooseMidiRoutes(midiTrackInfo->oRButton, (MidiTrack*)selected, true); +}  //---------------------------------------------------------  //   iProgHBankChanged @@ -1124,7 +1162,7 @@ void Arranger::genMidiTrackInfo()        //connect(midiTrackInfo->iName, SIGNAL(returnPressed()), SLOT(iNameChanged()));        connect(midiTrackInfo->iOutputChannel, SIGNAL(valueChanged(int)), SLOT(iOutputChannelChanged(int))); -      connect(midiTrackInfo->iInputChannel, SIGNAL(textChanged(const QString&)), SLOT(iInputChannelChanged(const QString&))); +      ///connect(midiTrackInfo->iInputChannel, SIGNAL(textChanged(const QString&)), SLOT(iInputChannelChanged(const QString&)));        connect(midiTrackInfo->iHBank, SIGNAL(valueChanged(int)), SLOT(iProgHBankChanged()));        connect(midiTrackInfo->iLBank, SIGNAL(valueChanged(int)), SLOT(iProgLBankChanged()));        connect(midiTrackInfo->iProgram, SIGNAL(valueChanged(int)), SLOT(iProgramChanged())); @@ -1141,12 +1179,17 @@ void Arranger::genMidiTrackInfo()        connect(midiTrackInfo->iPan, SIGNAL(valueChanged(int)), SLOT(iPanChanged(int)));        connect(midiTrackInfo->iPan, SIGNAL(doubleClicked()), SLOT(iPanDoubleClicked()));        connect(midiTrackInfo->iOutput, SIGNAL(activated(int)), SLOT(iOutputPortChanged(int))); -      connect(midiTrackInfo->iInput, SIGNAL(textChanged(const QString&)), SLOT(iInputPortChanged(const QString&))); +      ///connect(midiTrackInfo->iInput, SIGNAL(textChanged(const QString&)), SLOT(iInputPortChanged(const QString&)));        connect(midiTrackInfo->recordButton, SIGNAL(clicked()), SLOT(recordClicked()));        connect(midiTrackInfo->progRecButton, SIGNAL(clicked()), SLOT(progRecClicked()));        connect(midiTrackInfo->volRecButton, SIGNAL(clicked()), SLOT(volRecClicked()));        connect(midiTrackInfo->panRecButton, SIGNAL(clicked()), SLOT(panRecClicked()));        connect(midiTrackInfo->recEchoButton, SIGNAL(toggled(bool)), SLOT(recEchoToggled(bool))); +      connect(midiTrackInfo->iRButton, SIGNAL(pressed()), SLOT(inRoutesPressed())); +       +      // 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); +      connect(midiTrackInfo->oRButton, SIGNAL(pressed()), SLOT(outRoutesPressed()));        connect(heartBeatTimer, SIGNAL(timeout()), SLOT(midiTrackInfoHeartBeat()));        } @@ -1169,12 +1212,12 @@ void Arranger::updateMidiTrackInfo(int flags)        //{          int outChannel = track->outChannel(); -        int inChannel  = track->inChannelMask(); +        ///int inChannel  = track->inChannelMask();          int outPort    = track->outPort();          //int inPort     = track->inPortMask(); -        unsigned int inPort     = track->inPortMask(); +        ///unsigned int inPort     = track->inPortMask(); -        midiTrackInfo->iInput->clear(); +        //midiTrackInfo->iInput->clear();          midiTrackInfo->iOutput->clear();          for (int i = 0; i < MIDI_PORTS; ++i) { @@ -1185,7 +1228,8 @@ void Arranger::updateMidiTrackInfo(int flags)                      midiTrackInfo->iOutput->setCurrentItem(i);                }          //midiTrackInfo->iInput->setText(bitmap2String(inPort)); -        midiTrackInfo->iInput->setText(u32bitmap2String(inPort)); +        ///midiTrackInfo->iInput->setText(u32bitmap2String(inPort)); +                  //midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel));          // Removed by Tim. p3.3.9 @@ -1195,7 +1239,7 @@ void Arranger::updateMidiTrackInfo(int flags)          //      }          midiTrackInfo->iOutputChannel->setValue(outChannel+1); -        midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel)); +        ///midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel));          // Set record echo.          if(midiTrackInfo->recEchoButton->isOn() != track->recEcho()) diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index d8c12331..5172447e 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -596,7 +596,9 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)            // Added by Tim. p3.3.13            //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().latin1()); -          track->copyData(samplePos, channels, frames, buffer); +          // p3.3.38 +          //track->copyData(samplePos, channels, frames, buffer); +          track->copyData(samplePos, channels, -1, -1, frames, buffer);          }        }            } diff --git a/muse/muse/audiotrack.cpp b/muse/muse/audiotrack.cpp index ece9bed6..fd6ba76a 100644 --- a/muse/muse/audiotrack.cpp +++ b/muse/muse/audiotrack.cpp @@ -22,6 +22,8 @@  // By T356. For caching jack in/out routing names BEFORE file save.   // Jack often shuts down during file save, causing the routes to be lost in the file.  // cacheJackRouteNames() is ONLY called from MusE::save() in app.cpp +// Update: Not required any more because the real problem was Jack RT priority, which has been fixed. +/*  typedef std::multimap <const int, QString> jackRouteNameMap;  std::map <const AudioTrack*, jackRouteNameMap > jackRouteNameCache;  typedef std::multimap <const int, QString>::const_iterator ciJackRouteNameMap; @@ -54,13 +56,17 @@ void cacheJackRouteNames()        }                                  }  } +*/ +  //---------------------------------------------------------  //   AudioTrack  //---------------------------------------------------------  AudioTrack::AudioTrack(TrackType t) +//AudioTrack::AudioTrack(TrackType t, int num_out_bufs)     : Track(t)        { +      //_totalOutChannels = num_out_bufs; // Is either parameter-default MAX_CHANNELS, or custom value passed (used by syntis).        _processed = false;        _haveData = false;        _sendMetronome = false; @@ -79,8 +85,9 @@ AudioTrack::AudioTrack(TrackType t)        //outBuffers = new float*[MAX_CHANNELS];        //for (int i = 0; i < MAX_CHANNELS; ++i)        //      outBuffers[i] = new float[segmentSize]; -      for (int i = 0; i < MAX_CHANNELS; ++i) -            posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize); +      //for (int i = 0; i < MAX_CHANNELS; ++i) +      //      posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize); +              // Let's allocate it all in one block, and just point the remaining buffer pointers into the block        //  which allows faster one-shot buffer copying.        // Nope. Nice but interferes with possibility we don't know if other buffers are contiguous (jack buffers, local stack buffers etc.). @@ -88,6 +95,18 @@ AudioTrack::AudioTrack(TrackType t)        //for (int i = 0; i < MAX_CHANNELS; ++i)        //  *(outBuffers + i) = sizeof(float) * segmentSize * i; +      // p3.3.38 +      // Easy way, less desirable... Start out with enough for MAX_CHANNELS. Then multi-channel syntis can re-allocate,  +      //  via a call to (a modified!) setChannels(). +      // Hard way, more desirable... Creating a synti instance passes the total channels to this constructor, overriding MAX_CHANNELS. +      _totalOutChannels = MAX_CHANNELS; +      outBuffers = new float*[_totalOutChannels]; +      for (int i = 0; i < _totalOutChannels; ++i) +            posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * segmentSize); +       +      // This is only set by multi-channel syntis... +      _totalInChannels = 0; +              bufferPos = MAXINT;        setVolume(1.0); @@ -98,6 +117,7 @@ AudioTrack::AudioTrack(TrackType t)  AudioTrack::AudioTrack(const AudioTrack& t, bool cloneParts)    : Track(t, cloneParts)        { +      _totalOutChannels = t._totalOutChannels; // Is either MAX_CHANNELS, or custom value (used by syntis).        _processed      = false;        _haveData       = false;        _sendMetronome  = t._sendMetronome; @@ -112,8 +132,18 @@ AudioTrack::AudioTrack(const AudioTrack& t, bool cloneParts)        //outBuffers = new float*[MAX_CHANNELS];        //for (int i = 0; i < MAX_CHANNELS; ++i)        //      outBuffers[i] = new float[segmentSize]; -      for (int i = 0; i < MAX_CHANNELS; ++i) -            posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize); +      //for (int i = 0; i < MAX_CHANNELS; ++i) +      //      posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize); +       +      // p3.3.38 +      int chans = _totalOutChannels; +      // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.  +      if(chans < MAX_CHANNELS) +        chans = MAX_CHANNELS; +      outBuffers = new float*[chans]; +      for (int i = 0; i < chans; ++i) +            posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * segmentSize); +              bufferPos = MAXINT;        _recFile  = t._recFile;        } @@ -124,11 +154,26 @@ AudioTrack::~AudioTrack()        //for (int i = 0; i < MAX_CHANNELS; ++i)        //      delete[] outBuffers[i];        //delete[] outBuffers; -      for(int i = 0; i < MAX_CHANNELS; ++i)  +       +      // p3.3.15 +      //for(int i = 0; i < MAX_CHANNELS; ++i)  +      //{ +      //  if(outBuffers[i]) +      //    free(outBuffers[i]); +      //} +       +      // p3.3.38 +      int chans = _totalOutChannels; +      // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.  +      if(chans < MAX_CHANNELS) +        chans = MAX_CHANNELS; +      for(int i = 0; i < chans; ++i)         {          if(outBuffers[i])            free(outBuffers[i]);        } +      delete[] outBuffers; +        }  //--------------------------------------------------------- @@ -1109,12 +1154,13 @@ void AudioTrack::mapRackPluginsToControllers()      */  } +/*  //---------------------------------------------------------  //   writeRouting  //---------------------------------------------------------  void AudioTrack::writeRouting(int level, Xml& xml) const -      { +{        QString n;        if (type() == Track::AUDIO_INPUT) {                  ciJackRouteNameCache circ = jackRouteNameCache.find(this); @@ -1168,7 +1214,9 @@ void AudioTrack::writeRouting(int level, Xml& xml) const              }          }          }   -    } +} +*/        +         //---------------------------------------------------------  //   AudioInput  //--------------------------------------------------------- diff --git a/muse/muse/conf.cpp b/muse/muse/conf.cpp index 57d6f4f0..8af9994b 100644 --- a/muse/muse/conf.cpp +++ b/muse/muse/conf.cpp @@ -40,6 +40,7 @@  #include "midiport.h"  #include "mididev.h"  #include "driver/audiodev.h" +#include "driver/jackmidi.h"  #include "xml.h"  #include "waveedit.h"  #include "midi.h" @@ -216,6 +217,7 @@ static void readConfigMidiPort(Xml& xml)        int openFlags = 1;        bool thruFlag = false;        MidiSyncInfo tmpSi; +      int type = MidiDevice::ALSA_MIDI;        for (;;) {              Xml::Token token = xml.parse(); @@ -226,6 +228,8 @@ static void readConfigMidiPort(Xml& xml)                    case Xml::TagStart:                          if (tag == "name")                                device = xml.parse1(); +                        else if (tag == "type") +                              type = xml.parseInt();                          else if (tag == "record") {         // old                                bool f = xml.parseInt();                                if (f) @@ -262,7 +266,19 @@ static void readConfigMidiPort(Xml& xml)                                         idx, MIDI_PORTS);                                      idx = 0;                                      } +                                                              MidiDevice* dev = midiDevices.find(device); +                               +                              if(debugMsg && !dev) +                                fprintf(stderr, "readConfigMidiPort: device not found %s\n", device.latin1()); +                                 +                              if(!dev && type == MidiDevice::JACK_MIDI) +                              { +                                if(debugMsg) +                                  fprintf(stderr, "readConfigMidiPort: creating jack midi device %s\n", device.latin1()); +                                dev = MidiJackDevice::createJackMidiDevice(device, openFlags); +                              } +                                                              MidiPort* mp = &midiPorts[idx];                                mp->syncInfo().copyParams(tmpSi);                                if (dev) { @@ -942,6 +958,13 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)                    xml.strTag(level, "instrument", mport->instrument()->iname());                    if (dev) {                          xml.strTag(level, "name",   dev->name()); +                         +                        // p3.3.38 +                        //if(dynamic_cast<MidiJackDevice*>(dev)) +                        if(dev->deviceType() != MidiDevice::ALSA_MIDI) +                          //xml.intTag(level, "type", MidiDevice::JACK_MIDI); +                          xml.intTag(level, "type", dev->deviceType()); +                                                  // Changed by T356. "record" is old and by mistake written as rwFlags here.                           // openFlags was read before, but never written here.                          //xml.intTag(level, "record", dev->rwFlags() & 0x2 ? 1 : 0); diff --git a/muse/muse/confmport.cpp b/muse/muse/confmport.cpp index a3761439..61960910 100644 --- a/muse/muse/confmport.cpp +++ b/muse/muse/confmport.cpp @@ -44,11 +44,16 @@  #include "synth.h"  #include "audio.h"  #include "midiseq.h" +#include "driver/alsamidi.h" +#include "driver/jackmidi.h" +#include "audiodev.h" +#include "menutitleitem.h"  extern std::vector<Synth*> synthis;  enum { DEVCOL_NO = 0, DEVCOL_GUI, DEVCOL_REC, DEVCOL_PLAY, DEVCOL_INSTR, DEVCOL_NAME, -       DEVCOL_STATE }; +       //DEVCOL_STATE }; +       DEVCOL_ROUTES, DEVCOL_STATE };  //---------------------------------------------------------  //   rbClicked @@ -95,36 +100,343 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint&, int col)                    dev->setOpenFlags(openFlags);                    midiSeq->msgSetMidiDevice(port, dev);       // reopen device                    break; -            case DEVCOL_NAME: +            case DEVCOL_ROUTES:                    { -                  if (popup == 0) -                        popup = new QPopupMenu(this); -                  popup->clear(); -                  popup->insertItem(tr("<none>"), 0); -                  int id = 1; -                  for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) { -                        const QString s = (*i)->name(); -                        popup->insertItem(s, id); -                        for (int k = 0; k < MIDI_PORTS; ++k) { -                              MidiDevice* dev = midiPorts[k].device(); -                              if (dev && s == dev->name()) { -                                    popup->setItemEnabled(id, false); -                                    break; -                                    } -                              } -                        ++id; +                    if(!checkAudioDevice()) +                      return; +                       +                    if(!dev) +                      return; +                     +                    // Only Jack midi devices. +                    //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(dev); +                    //if(!mjd) +                    if(dev->deviceType() != MidiDevice::JACK_MIDI)   +                      return; +                     +                    if(!dev->rwFlags() & 3) +                      return; +                       +                    RouteList* rl = (dev->rwFlags() & 1) ? dev->outRoutes() : dev->inRoutes(); +               +                    QPopupMenu* pup = 0; +                    int gid = 0; +                    std::list<QString> sl; +         +        _redisplay: +                    // 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); +                     +                    pup = new QPopupMenu(this); +                    pup->setCheckable(true); +                     +                    gid = 0; +                    //for (int i = 0; i < channel; ++i)  +                    //{ +                      //char buffer[128]; +                      //snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +                      //MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +                      //pup->insertItem(titel); +   +                      pup->insertItem(tr("Show first aliases"), gid); +                      pup->setItemChecked(gid, (_showAliases == 0)); +                      ++gid; +                      pup->insertItem(tr("Show second aliases"), gid); +                      pup->setItemChecked(gid, (_showAliases == 1)); +                      ++gid; +                      pup->insertSeparator(); +                       +                      for(std::list<QString>::iterator ip = sl.begin(); ip != sl.end(); ++ip)  +                      { +                        //int id = pup->insertItem(*ip, gid); +                        pup->insertItem(*ip, gid); +                        //Route dst(*ip, true, i); +                        Route rt(*ip, (dev->rwFlags() & 1), -1, Route::JACK_ROUTE); +                        for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +                        { +                          if (*ir == rt)  +                          { +                            //pup->setItemChecked(id, true); +                            pup->setItemChecked(gid, true); +                            break; +                          }                          } -                  n = popup->exec(ppt, 0); -                  if (n == -1) -                        break; - -                  QString s = popup->text(n); -                  MidiDevice* dev = 0; -                  if (n > 0) -                        dev = midiDevices.find(s); -                  midiSeq->msgSetMidiDevice(port, dev); -                  muse->changeConfig(true);     // save configuration file -                  song->update(); +                        ++gid; +                      } +                      //if (i+1 != channel) +                      //      pup->insertSeparator(); +                    //} +                     +                    n = pup->exec(ppt, 0); +                    if (n != -1)  +                    { +                      if(n == 0) // Show first aliases +                      { +                        delete pup; +                        if(_showAliases == 0) +                          _showAliases = -1; +                        else   +                          _showAliases = 0; +                        goto _redisplay;   // Go back +                      } +                      else +                      if(n == 1) // Show second aliases +                      { +                        delete pup; +                        if(_showAliases == 1) +                          _showAliases = -1; +                        else   +                          _showAliases = 1; +                        goto _redisplay;   // Go back +                      } +                       +                      QString s(pup->text(n)); +                       +                      if(dev->rwFlags() & 1) // Writable +                      { +                        Route srcRoute(dev, -1); +                        Route dstRoute(s, true, -1, Route::JACK_ROUTE); +             +                        iRoute iir = rl->begin(); +                        for(; iir != rl->end(); ++iir)  +                        { +                          if(*iir == dstRoute) +                            break; +                        } +                        if(iir != rl->end())  +                          // disconnect +                          audio->msgRemoveRoute(srcRoute, dstRoute); +                        else  +                          // connect +                          audio->msgAddRoute(srcRoute, dstRoute); +                      } +                      else +                      if(dev->rwFlags() & 2) // Readable +                      { +                        Route srcRoute(s, false, -1, Route::JACK_ROUTE); +                        Route dstRoute(dev, -1); +             +                        iRoute iir = rl->begin(); +                        for(; iir != rl->end(); ++iir)  +                        { +                          if(*iir == srcRoute) +                            break; +                        } +                        if(iir != rl->end())  +                          // disconnect +                          audio->msgRemoveRoute(srcRoute, dstRoute); +                        else  +                          // connect +                          audio->msgAddRoute(srcRoute, dstRoute); +                      }   +                       +                      audio->msgUpdateSoloStates(); +                      song->update(SC_ROUTE); +                    } +                    delete pup; +                    //iR->setDown(false);     // pup->exec() catches mouse release event +                   +                   +                   +                  } +                  break; +            case DEVCOL_NAME: +                  { +                    QPopupMenu* pup = new QPopupMenu(this); +                     +                    pup->setCheckable(true); +                     +                    pup->insertItem(tr("Create") + QT_TR_NOOP(" Jack") + tr(" input"), 0); +                    pup->insertItem(tr("Create") + QT_TR_NOOP(" Jack") + tr(" output"), 1); +                     +                    typedef std::map<std::string, int > asmap; +                    typedef std::map<std::string, int >::iterator imap; +                     +                    asmap mapALSA; +                    asmap mapJACK; +                    asmap mapSYNTH; +                     +                    int aix = 2; +                    int jix = 0x10000000; +                    int six = 0x20000000; +                    for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +                    { +                      //devALSA = dynamic_cast<MidiAlsaDevice*>(*i); +                      //if(devALSA) +                      if((*i)->deviceType() == MidiDevice::ALSA_MIDI) +                      { +                        //mapALSA.insert( std::pair<std::string, int> (std::string(devALSA->name().lower().latin1()), ii) ); +                        mapALSA.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), aix) ); +                        ++aix; +                      }   +                      else +                      if((*i)->deviceType() == MidiDevice::JACK_MIDI) +                      {   +                        //devJACK = dynamic_cast<MidiJackDevice*>(*i); +                        //if(devJACK) +                          //mapJACK.insert( std::pair<std::string, int> (std::string(devJACK->name().lower().latin1()), ii) ); +                        mapJACK.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), jix) ); +                        ++jix; +                      } +                      else +                      if((*i)->deviceType() == MidiDevice::SYNTH_MIDI) +                      { +                        mapSYNTH.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), six) ); +                        ++six;   +                      } +                      else +                        printf("MPConfig::rbClicked unknown midi device: %s\n", (*i)->name().latin1()); +                    } +                     +                    //int sz = midiDevices.size(); +                    if(!mapALSA.empty()) +                    { +                      pup->insertSeparator(); +                      pup->insertItem(new MenuTitleItem(QT_TR_NOOP("ALSA:"))); +                       +                      for(imap i = mapALSA.begin(); i != mapALSA.end(); ++i)  +                      { +                        int idx = i->second; +                        //if(idx > sz)           // Sanity check +                        //  continue; +                        QString s(i->first.c_str()); +                        MidiDevice* md = midiDevices.find(s, MidiDevice::ALSA_MIDI); +                        if(md) +                        { +                          //if(!dynamic_cast<MidiAlsaDevice*>(md)) +                          if(md->deviceType() != MidiDevice::ALSA_MIDI)   +                            continue; +                             +                          //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3); +                          pup->insertItem(QT_TR_NOOP(md->name()), idx); +                           +                          //for(int k = 0; k < MIDI_PORTS; ++k)  +                          //{ +                            //MidiDevice* dev = midiPorts[k].device(); +                            //if(dev && s == dev->name())  +                            if(md == dev)  +                            { +                              //pup->setItemEnabled(idx + 3, false); +                              //pup->setItemChecked(idx + 3, true); +                              pup->setItemChecked(idx, true); +                              //break; +                            }       +                          //} +                        }   +                      } +                    }   +                     +                    if(!mapJACK.empty()) +                    { +                      pup->insertSeparator(); +                      pup->insertItem(new MenuTitleItem(QT_TR_NOOP("JACK:"))); +                       +                      for(imap i = mapJACK.begin(); i != mapJACK.end(); ++i)  +                      { +                        int idx = i->second; +                        //if(idx > sz)            +                        //  continue; +                        QString s(i->first.c_str()); +                        MidiDevice* md = midiDevices.find(s, MidiDevice::JACK_MIDI); +                        if(md) +                        { +                          //if(!dynamic_cast<MidiJackDevice*>(md)) +                          if(md->deviceType() != MidiDevice::JACK_MIDI)   +                            continue; +                             +                          //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3); +                          pup->insertItem(QT_TR_NOOP(md->name()), idx); +                           +                          //for(int k = 0; k < MIDI_PORTS; ++k)  +                          //{ +                            //MidiDevice* dev = midiPorts[k].device(); +                            //if(dev && s == dev->name())  +                            if(md == dev)  +                            { +                              //pup->setItemEnabled(idx + 3, false); +                              //pup->setItemChecked(idx + 3, true); +                              pup->setItemChecked(idx, true); +                              //break; +                            }       +                          //} +                        }   +                      } +                    }   +                     +                    if(!mapSYNTH.empty()) +                    { +                      pup->insertSeparator(); +                      pup->insertItem(new MenuTitleItem(QT_TR_NOOP("SYNTH:"))); +                       +                      for(imap i = mapSYNTH.begin(); i != mapSYNTH.end(); ++i)  +                      { +                        int idx = i->second; +                        //if(idx > sz)            +                        //  continue; +                        QString s(i->first.c_str()); +                        MidiDevice* md = midiDevices.find(s, MidiDevice::SYNTH_MIDI); +                        if(md) +                        { +                          //if(!dynamic_cast<MidiJackDevice*>(md)) +                          if(md->deviceType() != MidiDevice::SYNTH_MIDI)   +                            continue; +                             +                          //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3); +                          pup->insertItem(QT_TR_NOOP(md->name()), idx); +                           +                          //for(int k = 0; k < MIDI_PORTS; ++k)  +                          //{ +                            //MidiDevice* dev = midiPorts[k].device(); +                            //if(dev && s == dev->name())  +                            if(md == dev)  +                            { +                              //pup->setItemEnabled(idx + 3, false); +                              //pup->setItemChecked(idx + 3, true); +                              pup->setItemChecked(idx, true); +                              //break; +                            }       +                          //} +                        }   +                      } +                    } +                     +                    n = pup->exec(ppt, 0); +                    if(n == -1) +                    {       +                      delete pup; +                      break; +                    } +                     +                    //printf("MPConfig::rbClicked n:%d\n", n); +                     +                    MidiDevice* sdev = 0; +                    if(n < 2) +                    { +                      delete pup; +                      if(n == 0) +                        sdev = MidiJackDevice::createJackMidiDevice(QString(), 2); // 2: Readable. +                      else +                      if(n == 1) +                        sdev = MidiJackDevice::createJackMidiDevice(QString(), 1); // 1:Writable. +                    }   +                    else +                    { +                      int typ = MidiDevice::ALSA_MIDI; +                      if(n >= 0x10000000) +                        typ = MidiDevice::JACK_MIDI; +                      if(n >= 0x20000000) +                        typ = MidiDevice::SYNTH_MIDI; +                       +                      sdev = midiDevices.find(pup->text(n), typ); +                      delete pup; +                      // Is it the current device? Reset it to <none>. +                      if(sdev == dev) +                        sdev = 0; +                    }     +                     +                    midiSeq->msgSetMidiDevice(port, sdev); +                    muse->changeConfig(true);     // save configuration file +                    song->update();                    }                    break; @@ -189,6 +501,8 @@ QString MPWhatsThis::text(const QPoint& pos)                         " this port number");              case DEVCOL_INSTR:                    return QHeader::tr("Instrument connected to port"); +            case DEVCOL_ROUTES: +                  return QHeader::tr("Jack midi ports");              case DEVCOL_STATE:                    return QHeader::tr("State: result of opening the device");              default: @@ -207,7 +521,8 @@ MPConfig::MPConfig(QWidget* parent, char* name)        {        popup      = 0;        instrPopup = 0; - +      _showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first. +              mdevView->setSorting(-1);        mdevView->setAllColumnsShowFocus(true);        mdevView->addColumn(tr("Port")); @@ -216,6 +531,7 @@ MPConfig::MPConfig(QWidget* parent, char* name)        mdevView->addColumn(tr("O"));        mdevView->addColumn(tr("Instrument"), 120);        mdevView->addColumn(tr("Device Name"), 120); +      mdevView->addColumn(tr("Routing"), 80);        mdevView->addColumn(tr("State"));        mdevView->setFocusPolicy(NoFocus); @@ -279,6 +595,11 @@ void MPConfig::songChanged(int flags)                    item->setText(DEVCOL_INSTR, tr("<unknown>"));              if (dev) {                    item->setText(DEVCOL_NAME, dev->name()); +                  // Is it a Jack midi device? Allow renaming. +                  //if(dynamic_cast<MidiJackDevice*>(dev)) +                  if(dev->deviceType() == MidiDevice::JACK_MIDI) +                    item->setRenameEnabled(DEVCOL_NAME, true); +                                        if (dev->rwFlags() & 0x2)                          item->setPixmap(DEVCOL_REC, dev->openFlags() & 2 ? *dotIcon : *dothIcon);                    else @@ -303,6 +624,14 @@ void MPConfig::songChanged(int flags)              if (!(dev && dev->isSynti()))                    item->setPixmap(DEVCOL_INSTR, *buttondownIcon);              item->setPixmap(DEVCOL_NAME, *buttondownIcon); +             +            //if(dev && dynamic_cast<MidiJackDevice*>(dev)) +            if(dev && dev->deviceType() == MidiDevice::JACK_MIDI) +            { +              item->setPixmap(DEVCOL_ROUTES, *buttondownIcon); +              item->setText(DEVCOL_ROUTES, tr("routes")); +            } +                          mdevView->insertItem(item);              } diff --git a/muse/muse/confmport.h b/muse/muse/confmport.h index b98a2189..577c0afd 100644 --- a/muse/muse/confmport.h +++ b/muse/muse/confmport.h @@ -45,7 +45,9 @@ class MPWhatsThis : public QWhatsThis {  class MPConfig : public SynthConfigBase {        QPopupMenu* popup;        QPopupMenu* instrPopup; - +       +      int _showAliases; // -1: None. 0: First aliases. 1: Second aliases etc. +              Q_OBJECT     private slots: diff --git a/muse/muse/driver/alsamidi.cpp b/muse/muse/driver/alsamidi.cpp index c9e14bbc..bcd1bd75 100644 --- a/muse/muse/driver/alsamidi.cpp +++ b/muse/muse/driver/alsamidi.cpp @@ -18,6 +18,8 @@  #include "mpevent.h"  //#include "sync.h"  #include "utils.h" +#include "audiodev.h" +#include "xml.h"  static int alsaSeqFdi = -1;  static int alsaSeqFdo = -1; @@ -169,6 +171,101 @@ void MidiAlsaDevice::close()  }  //--------------------------------------------------------- +//   writeRouting +//--------------------------------------------------------- + +void MidiAlsaDevice::writeRouting(int level, Xml& xml) const +{ +      QString s; +      /* +      //if(rwFlags() & 2)  // Readable +      { +        //RouteList* rl = _inRoutes; +        //for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)  +        { +          // Since an ALSA midi device supports read + write, this is the only way we can tell if this route is using the device as input.   +          if(r->type == Route::TRACK_ROUTE) +            continue; +             +          if(!r->name().isEmpty()) +          { +            xml.tag(level++, "Route"); +             +            //xml.strTag(level, "srcNode", r->name()); +            xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +             +            //xml.strTag(level, "dstNode", name()); +            xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1()); +             +            xml.etag(level--, "Route"); +          } +        }   +      }  +      */ +       +      for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)  +      { +        //if(r->type != Route::TRACK_ROUTE) +        //{   +        //  printf("MidiAlsaDevice::writeRouting Warning out route is not TRACK_ROUTE type\n"); +        //  continue; +        //} +           +        if(!r->name().isEmpty()) +        { +          //xml.tag(level++, "Route"); +           +          s = QT_TR_NOOP("Route"); +          if(r->channel != -1) +            s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); +          xml.tag(level++, s); +           +          /* +          //xml.strTag(level, "srcNode", name()); +          if(r->channel != -1)   +            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, r->channel, name().latin1()); +            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1()); +            xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, r->channel, name().latin1()); +          else   +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1()); +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1()); +          */   +            xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, name().latin1()); +           +          /* +          //xml.strTag(level, "dstNode", r->name()); +          if(r->channel != -1)   +          { +            if(r->type == Route::MIDI_DEVICE_ROUTE)   +              xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1()); +            else   +              xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1()); +          } +          else   +          { +            if(r->type == Route::MIDI_DEVICE_ROUTE)   +              xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1()); +            else   +              xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +          } +          */ +           +          s = QT_TR_NOOP("dest"); +          if(r->type == Route::MIDI_DEVICE_ROUTE) +            s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType()); +          else +          if(r->type != Route::TRACK_ROUTE) +            s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); +          s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); +          xml.tag(level, s); +           +          xml.etag(level--, "Route"); +        } +      } +} +     +//---------------------------------------------------------  //   putEvent  //--------------------------------------------------------- @@ -418,7 +515,11 @@ bool initMidiAlsa()                    }              } -      snd_seq_set_client_name(alsaSeq, "MusE Sequencer"); +       +      // p3.3.38 +      //snd_seq_set_client_name(alsaSeq, "MusE Sequencer"); +      snd_seq_set_client_name(alsaSeq, audioDevice->clientName()); +              int ci = snd_seq_poll_descriptors_count(alsaSeq, POLLIN);        int co = snd_seq_poll_descriptors_count(alsaSeq, POLLOUT); @@ -721,28 +822,39 @@ void alsaProcessMidiInput()                          break;                    case SND_SEQ_EVENT_CLOCK: -                        midiSeq->realtimeSystemInput(curPort, 0xf8); +                        midiSeq->realtimeSystemInput(curPort, ME_CLOCK);                          //mdev->syncInfo().trigMCSyncDetect();                          break;                    case SND_SEQ_EVENT_START: -                        midiSeq->realtimeSystemInput(curPort, 0xfa); +                        midiSeq->realtimeSystemInput(curPort, ME_START);                          break;                    case SND_SEQ_EVENT_CONTINUE: -                        midiSeq->realtimeSystemInput(curPort, 0xfb); +                        midiSeq->realtimeSystemInput(curPort, ME_CONTINUE);                          break;                    case SND_SEQ_EVENT_STOP: -                        midiSeq->realtimeSystemInput(curPort, 0xfc); +                        midiSeq->realtimeSystemInput(curPort, ME_STOP);                          break;                    case SND_SEQ_EVENT_TICK: -                        midiSeq->realtimeSystemInput(curPort, 0xf9); +                        midiSeq->realtimeSystemInput(curPort, ME_TICK);                          //mdev->syncInfo().trigTickDetect();                          break;                    case SND_SEQ_EVENT_SYSEX: +                         +                        // TODO: Deal with large sysex, which are broken up into chunks! +                        // For now, do not accept if the first byte is not SYSEX or the last byte is not EOX,  +                        //  meaning it's a chunk, possibly with more chunks to follow. +                        if((*((unsigned char*)ev->data.ext.ptr) != ME_SYSEX) || +                           (*(((unsigned char*)ev->data.ext.ptr) + ev->data.ext.len - 1) != ME_SYSEX_END)) +                        { +                          printf("MusE: alsaProcessMidiInput sysex chunks not supported!\n"); +                          break; +                        } +                                                  event.setTime(0);      // mark as used                          event.setType(ME_SYSEX);                          event.setData((unsigned char*)(ev->data.ext.ptr)+1, diff --git a/muse/muse/driver/alsamidi.h b/muse/muse/driver/alsamidi.h index 48645706..6c19ff0d 100644 --- a/muse/muse/driver/alsamidi.h +++ b/muse/muse/driver/alsamidi.h @@ -13,6 +13,8 @@  #include "mididev.h" +class Xml; +  //---------------------------------------------------------  //   MidiAlsaDevice  //--------------------------------------------------------- @@ -35,6 +37,9 @@ class MidiAlsaDevice : public MidiDevice {        MidiAlsaDevice() {}        MidiAlsaDevice(const snd_seq_addr_t&, const QString& name);        virtual ~MidiAlsaDevice() {} +      virtual void* clientPort() { return (void*)&adr; } +      virtual void writeRouting(int, Xml&) const; +      virtual inline int deviceType() { return ALSA_MIDI; }         };  extern bool initMidiAlsa(); diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h index f66627b8..b888f6eb 100644 --- a/muse/muse/driver/audiodev.h +++ b/muse/muse/driver/audiodev.h @@ -33,11 +33,13 @@ class AudioDevice {        virtual float* getBuffer(void* port, unsigned long nframes) = 0; -      virtual std::list<QString> outputPorts() = 0; -      virtual std::list<QString> inputPorts() = 0; +      virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1) = 0; +      virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1) = 0;        virtual void registerClient() = 0; +      virtual const char* clientName() = 0; +              //virtual void* registerOutPort(const char* name) = 0;        //virtual void* registerInPort(const char* name) = 0;        virtual void* registerOutPort(const char* /*name*/, bool /*midi*/) = 0; diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp index 2695f705..0bca9890 100644 --- a/muse/muse/driver/dummyaudio.cpp +++ b/muse/muse/driver/dummyaudio.cpp @@ -88,11 +88,13 @@ class DummyAudioDevice : public AudioDevice {              return buffer;              } -      virtual std::list<QString> outputPorts(); -      virtual std::list<QString> inputPorts(); +      virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1); +      virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);        virtual void registerClient() {} +      virtual const char* clientName() { return "MusE"; } +              //virtual void* registerOutPort(const char*) {        virtual void* registerOutPort(const char*, bool) {              return (void*)1; @@ -214,11 +216,14 @@ bool initDummyAudio()  //   outputPorts  //--------------------------------------------------------- -std::list<QString> DummyAudioDevice::outputPorts() +std::list<QString> DummyAudioDevice::outputPorts(bool midi, int /*aliases*/)        {        std::list<QString> clientList; -      clientList.push_back(QString("output1")); -      clientList.push_back(QString("output2")); +      if(!midi) +      { +        clientList.push_back(QString("output1")); +        clientList.push_back(QString("output2")); +      }          return clientList;        } @@ -226,11 +231,14 @@ std::list<QString> DummyAudioDevice::outputPorts()  //   inputPorts  //--------------------------------------------------------- -std::list<QString> DummyAudioDevice::inputPorts() +std::list<QString> DummyAudioDevice::inputPorts(bool midi, int /*aliases*/)        {        std::list<QString> clientList; -      clientList.push_back(QString("input1")); -      clientList.push_back(QString("input2")); +      if(!midi) +      { +        clientList.push_back(QString("input1")); +        clientList.push_back(QString("input2")); +      }          return clientList;        } diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp index 3329b73f..2926e281 100644 --- a/muse/muse/driver/jack.cpp +++ b/muse/muse/driver/jack.cpp @@ -6,6 +6,8 @@  //=========================================================  #include "config.h" +#include <string> +#include <set>  #include <stdio.h>  #include <stdlib.h>  #include <errno.h> @@ -123,6 +125,7 @@ static void jack_thread_init (void* )  // data        undoSetuid();        } +/*  //---------------------------------------------------------  //   processAudio + Midi  //    JACK callback @@ -137,6 +140,7 @@ print_triplet(unsigned char *data)    memcpy(&c, data+2, 1);    fprintf(stderr, "%x,%x,%x", a, b, c);  } +*/  /*  void handle_jack_midi_in_events(jack_nframes_t frames) @@ -430,7 +434,7 @@ static void noJackError(const char* /* s */)  //   JackAudioDevice  //--------------------------------------------------------- -JackAudioDevice::JackAudioDevice(jack_client_t* cl, char * name) +JackAudioDevice::JackAudioDevice(jack_client_t* cl, char* name)     : AudioDevice()        {        _frameCounter = 0; @@ -496,6 +500,7 @@ int JackAudioDevice::realtimePriority() const        return param.sched_priority;        } +/*  //---------------------------------------------------------  //   getJackName()  //--------------------------------------------------------- @@ -504,6 +509,22 @@ char* JackAudioDevice::getJackName()        {        return jackRegisteredName;        } +*/ + +/* +//--------------------------------------------------------- +//   clientName() +//--------------------------------------------------------- + +const char* JackAudioDevice::clientName() +{ +  //if(_client) +  //  return jack_get_client_name(_client); +  //else +  //  return "MusE";   +  return jackRegisteredName; +} +*/  //---------------------------------------------------------  //   initJackAudio @@ -531,25 +552,41 @@ bool initJackAudio()              jack_set_error_function(noJackError);        doSetuid(); -      jack_client_t* client = 0; -      int i = 0; -      char jackIdString[8]; -      for (i = 0; i < 5; ++i) { -            sprintf(jackIdString, "MusE-%d", i+1); +      //jack_client_t* client = 0; +      //int i = 0; +      //char jackIdString[8]; +      //for (i = 0; i < 5; ++i) { +      //      sprintf(jackIdString, "MusE-%d", i+1);              //client = jack_client_new(jackIdString); -            client = jack_client_open(jackIdString, JackNoStartServer, 0); -            if (client) -                  break; -            } - -      if (i == 5) +      //      client = jack_client_open(jackIdString, JackNoStartServer, 0); +      //      if (client) +      //            break; +      //      } +      //if (i == 5) +      //      return true; +      jack_status_t status; +      jack_client_t* client = jack_client_open("MusE", JackNoStartServer, &status); +      if (!client) { +            if (status & JackServerStarted) +                  printf("jack server started...\n"); +            if (status & JackServerFailed) +                  printf("cannot connect to jack server\n"); +            if (status & JackServerError) +                  printf("communication with jack server failed\n"); +            if (status & JackShmFailure) +                  printf("jack cannot access shared memory\n"); +            if (status & JackVersionError) +                  printf("jack server has wrong version\n"); +            printf("cannot create jack client\n");              return true; +            }        if (debugMsg) -            fprintf(stderr, "initJackAudio(): client %s opened.\n", jackIdString); +            fprintf(stderr, "initJackAudio(): client %s opened.\n", jack_get_client_name(client));        if (client) {              jack_set_error_function(jackError); -            jackAudio = new JackAudioDevice(client, jackIdString); +            //jackAudio = new JackAudioDevice(client, jackIdString); +            jackAudio = new JackAudioDevice(client, jack_get_client_name(client));              if (debugMsg)                    fprintf(stderr, "initJackAudio(): registering client...\n");              jackAudio->registerClient(); @@ -648,8 +685,10 @@ void JackAudioDevice::registrationChanged()    if(JACK_DEBUG)      printf("JackAudioDevice::registrationChanged()\n"); +  // Rescan. +  scanMidiPorts();    // Connect the Jack midi client ports to the device ports. -  connectJackMidiPorts(); +  //connectJackMidiPorts();  }  //--------------------------------------------------------- @@ -661,6 +700,32 @@ void JackAudioDevice::connectJackMidiPorts()    if(JACK_DEBUG)      printf("JackAudioDevice::connectJackMidiPorts()\n"); +  for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +  { +    //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i); +    //if(!mjd) +    MidiDevice* md = *i; +    if(md->deviceType() != MidiDevice::JACK_MIDI) +      continue; +     +    void* port = md->clientPort(); +    if(md->rwFlags() & 1) +    { +      RouteList* rl = md->outRoutes(); +      for (iRoute r = rl->begin(); r != rl->end(); ++r)  +        connect(port, r->jackPort); +    } +    else +    if(md->rwFlags() & 2) +    {   +      RouteList* rl = md->inRoutes(); +      for (iRoute r = rl->begin(); r != rl->end(); ++r)  +        connect(r->jackPort, port); +    }     +  } +   +   +  /*    const char* type = JACK_DEFAULT_MIDI_TYPE;    const char** ports = jack_get_ports(_client, 0, type, 0);    for (const char** p = ports; p && *p; ++p)  @@ -668,6 +733,13 @@ void JackAudioDevice::connectJackMidiPorts()      jack_port_t* port = jack_port_by_name(_client, *p);      if(!port)        continue; +    // Ignore our own client ports. +    if(jack_port_is_mine(_client, port)) +    { +      if(debugMsg) +        printf(" ignoring own port: %s\n", *p); +      continue;          +    }      int nsz = jack_port_name_size();      char buffer[nsz];      strncpy(buffer, *p, nsz); @@ -675,6 +747,9 @@ void JackAudioDevice::connectJackMidiPorts()      //if(strncmp(buffer, "MusE", 4) == 0)      //  continue; +    if(debugMsg) +      printf(" found port: %s  ", buffer); +          // If there are aliases for this port, use the first one - much better for identifying.       //char a1[nsz];       char a2[nsz];  @@ -688,6 +763,9 @@ void JackAudioDevice::connectJackMidiPorts()      //char* namep = (na >= 1) ? aliases[0] : buffer;      char* namep = aliases[0]; +    if(debugMsg) +      printf("alias: %s\n", aliases[0]); +          //int flags = 0;      int pf = jack_port_flags(port);      // If Jack port can send data to us... @@ -753,6 +831,8 @@ void JackAudioDevice::connectJackMidiPorts()    if(ports)      free(ports);       +     +  */    }  //---------------------------------------------------------  //   client_registration_callback @@ -846,7 +926,8 @@ void JackAudioDevice::graphChanged()                                      }                                if (!found) {                                      audio->msgRemoveRoute1( -                                       Route(portName, false, channel), +                                       //Route(portName, false, channel), +                                       Route(portName, false, channel, Route::JACK_ROUTE),                                         Route(it, channel)                                         );                                      erased = true; @@ -877,7 +958,8 @@ void JackAudioDevice::graphChanged()                                      }                                if (!found) {                                      audio->msgAddRoute1( -                                       Route(*pn, false, channel), +                                       //Route(*pn, false, channel), +                                       Route(*pn, false, channel, Route::JACK_ROUTE),                                         Route(it, channel)                                         );                                      } @@ -929,7 +1011,8 @@ void JackAudioDevice::graphChanged()                                if (!found) {                                      audio->msgRemoveRoute1(                                         Route(it, channel), -                                       Route(portName, false, channel) +                                       //Route(portName, false, channel) +                                       Route(portName, false, channel, Route::JACK_ROUTE)                                         );                                      erased = true;                                      break; @@ -960,7 +1043,8 @@ void JackAudioDevice::graphChanged()                                if (!found) {                                      audio->msgAddRoute1(                                         Route(it, channel), -                                       Route(*pn, false, channel) +                                       //Route(*pn, false, channel) +                                       Route(*pn, false, channel, Route::JACK_ROUTE)                                         );                                      }                                ++pn; @@ -975,6 +1059,201 @@ void JackAudioDevice::graphChanged()                    }              } +      for (iMidiDevice ii = midiDevices.begin(); ii != midiDevices.end(); ++ii)  +      { +            MidiDevice* md = *ii; +            if(md->deviceType() != MidiDevice::JACK_MIDI) +              continue; +             +            //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*ii); +            //if(!mjd) +            //  continue; +            //for (int channel = 0; channel < channels; ++channel)  +            //{ +                  jack_port_t* port = (jack_port_t*)md->clientPort(); +                  if (port == 0) +                        continue; +                  const char** ports = jack_port_get_all_connections(_client, port); +                   +                  //--------------------------------------- +                  // outputs +                  //--------------------------------------- +                   +                  if(md->rwFlags() & 1) // Writable +                  { +                    RouteList* rl      = md->outRoutes(); +   +                    //--------------------------------------- +                    // check for disconnects +                    //--------------------------------------- +   +                    bool erased; +                    // limit set to 20 iterations for disconnects, don't know how to make it go +                    // the "right" amount +                    for (int i = 0; i < 20 ; i++)  +                    { +                          erased = false; +                          for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                //if (irl->channel != channel) +                                //      continue; +                                QString name = irl->name(); +                                const char* portName = name.latin1(); +                                bool found = false; +                                const char** pn = ports; +                                while (pn && *pn) { +                                      if (strcmp(*pn, portName) == 0) { +                                            found = true; +                                            break; +                                            } +                                      ++pn; +                                      } +                                if (!found) { +                                      audio->msgRemoveRoute1( +                                        //Route(it, channel), +                                        //Route(mjd), +                                        Route(md, -1), +                                        //Route(portName, false, channel) +                                        //Route(portName, false, -1) +                                        Route(portName, false, -1, Route::JACK_ROUTE) +                                        ); +                                      erased = true; +                                      break; +                                      } +                                } +                          if (!erased) +                                break; +                    } +   +                    //--------------------------------------- +                    // check for connects +                    //--------------------------------------- +   +                    if (ports)  +                    { +                          const char** pn = ports; +                          while (*pn) { +                                bool found = false; +                                for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                      //if (irl->channel != channel) +                                      //      continue; +                                      QString name = irl->name(); +                                      const char* portName = name.latin1(); +                                      if (strcmp(*pn, portName) == 0) { +                                            found = true; +                                            break; +                                            } +                                      } +                                if (!found) { +                                      audio->msgAddRoute1( +                                        //Route(it, channel), +                                        //Route(mjd), +                                        Route(md, -1), +                                        //Route(*pn, false, channel) +                                        //Route(*pn, false, -1) +                                        Route(*pn, false, -1, Route::JACK_ROUTE) +                                        ); +                                      } +                                ++pn; +                                } +   +                          // p3.3.37 +                          //delete ports; +                          //free(ports); +                           +                          //ports = NULL; +                    } +                  }   +                   +                   +                  //------------------------ +                  // Inputs +                  //------------------------ +                   +                  if(md->rwFlags() & 2) // Readable +                  { +                    RouteList* rl = md->inRoutes(); +   +                    //--------------------------------------- +                    // check for disconnects +                    //--------------------------------------- +   +                    bool erased; +                    // limit set to 20 iterations for disconnects, don't know how to make it go +                    // the "right" amount +                    for (int i = 0; i < 20 ; i++)  +                    { +                          erased = false; +                          for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                //if (irl->channel != channel) +                                //      continue; +                                QString name = irl->name(); +                                const char* portName = name.latin1(); +                                bool found = false; +                                const char** pn = ports; +                                while (pn && *pn) { +                                      if (strcmp(*pn, portName) == 0) { +                                            found = true; +                                            break; +                                            } +                                      ++pn; +                                      } +                                if (!found) { +                                      audio->msgRemoveRoute1( +                                        //Route(portName, false, channel), +                                        //Route(portName, false, -1), +                                        Route(portName, false, -1, Route::JACK_ROUTE), +                                        //Route(it, channel) +                                        //Route(mjd) +                                        Route(md, -1) +                                        ); +                                      erased = true; +                                      break; +                                      } +                                } +                          if (!erased) +                                break; +                    } +   +                    //--------------------------------------- +                    // check for connects +                    //--------------------------------------- +   +                    if (ports)  +                    { +                          const char** pn = ports; +                          while (*pn) { +                                bool found = false; +                                for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                      //if (irl->channel != channel) +                                      //      continue; +                                      QString name = irl->name(); +                                      const char* portName = name.latin1(); +                                      if (strcmp(*pn, portName) == 0) { +                                            found = true; +                                            break; +                                            } +                                      } +                                if (!found) { +                                      audio->msgAddRoute1( +                                        //Route(*pn, false, channel), +                                        //Route(*pn, false, -1), +                                        Route(*pn, false, -1, Route::JACK_ROUTE), +                                        //Route(it, channel) +                                        //Route(mjd) +                                        Route(md, -1) +                                        ); +                                      } +                                ++pn; +                                } +                    } +                  }   +                  if(ports)  +                    // Done with ports. Free them. +                    //delete ports; +                    free(ports); +                     +                  ports = NULL; +      }  }  //static int xrun_callback(void*) @@ -1279,24 +1558,67 @@ int JackAudioDevice::frameDelay() const  //   outputPorts  //--------------------------------------------------------- -std::list<QString> JackAudioDevice::outputPorts() +std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)        {        if (JACK_DEBUG)              printf("JackAudioDevice::outputPorts()\n");        std::list<QString> clientList;        if(!checkJackClient(_client)) return clientList; -      const char** ports = jack_get_ports(_client, 0, JACK_DEFAULT_AUDIO_TYPE, 0); +      QString qname; +      const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; +      const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput);        for (const char** p = ports; p && *p; ++p) {              jack_port_t* port = jack_port_by_name(_client, *p); -            int flags = jack_port_flags(port); -            if (!(flags & JackPortIsOutput)) -                  continue; -            char buffer[128]; -            strncpy(buffer, *p, 128); -            if (strncmp(buffer, "MusE", 4) == 0) -                  continue; -            clientList.push_back(QString(buffer)); +            //int flags = jack_port_flags(port); +            //if (!(flags & JackPortIsOutput)) +            //      continue; +            //char buffer[128]; +             +            int nsz = jack_port_name_size(); +            char buffer[nsz]; +             +            strncpy(buffer, *p, nsz); +            //if (strncmp(buffer, "MusE", 4) == 0) +            //{ +            //  if(debugMsg) +            //    printf("JackAudioDevice::outputPorts ignoring own MusE port: %s\n", *p); +            //  continue;          +            //} +             +            // Ignore our own client ports. +            if(jack_port_is_mine(_client, port)) +            { +              if(debugMsg) +                printf("JackAudioDevice::outputPorts ignoring own port: %s\n", *p); +              continue;                       } +             +            // p3.3.38 +            if((aliases == 0) || (aliases == 1))  +            { +              //char a1[nsz];  +              char a2[nsz];  +              char* al[2]; +              //aliases[0] = a1; +              al[0] = buffer; +              al[1] = a2; +              int na = jack_port_get_aliases(port, al); +              int a = aliases; +              if(a >= na) +              { +                a = na; +                if(a > 0) +                  a--; +              }     +              qname = QString(al[a]); +            } +            else +              qname = QString(buffer); +             +            //clientList.push_back(QString(buffer)); +            clientList.push_back(qname); +            } +                    // p3.3.37        if(ports)          free(ports);       @@ -1308,24 +1630,67 @@ std::list<QString> JackAudioDevice::outputPorts()  //   inputPorts  //--------------------------------------------------------- -std::list<QString> JackAudioDevice::inputPorts() +std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)        {        if (JACK_DEBUG)              printf("JackAudioDevice::inputPorts()\n");        std::list<QString> clientList;        if(!checkJackClient(_client)) return clientList; -      const char** ports = jack_get_ports(_client, 0, JACK_DEFAULT_AUDIO_TYPE, 0); +      QString qname; +      const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; +      const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput);        for (const char** p = ports; p && *p; ++p) {              jack_port_t* port = jack_port_by_name(_client, *p); -            int flags = jack_port_flags(port); -            if (!(flags & JackPortIsInput)) -                  continue; -            char buffer[128]; -            strncpy(buffer, *p, 128); -            if (strncmp(buffer, "MusE", 4) == 0) -                  continue; -            clientList.push_back(QString(buffer)); +            //int flags = jack_port_flags(port); +            //if (!(flags & JackPortIsInput)) +            //      continue; +            //char buffer[128]; +             +            int nsz = jack_port_name_size(); +            char buffer[nsz]; +             +            strncpy(buffer, *p, nsz); +            //if (strncmp(buffer, "MusE", 4) == 0) +            //{ +            //  if(debugMsg) +            //    printf("JackAudioDevice::inputPorts ignoring own MusE port: %s\n", *p); +            //  continue;          +            //} +             +            // Ignore our own client ports. +            if(jack_port_is_mine(_client, port)) +            { +              if(debugMsg) +                printf("JackAudioDevice::inputPorts ignoring own port: %s\n", *p); +              continue;          +            } +             +            // p3.3.38 +            if((aliases == 0) || (aliases == 1))  +            { +              //char a1[nsz];  +              char a2[nsz];  +              char* al[2]; +              //aliases[0] = a1; +              al[0] = buffer; +              al[1] = a2; +              int na = jack_port_get_aliases(port, al); +              int a = aliases; +              if(a >= na) +              { +                a = na; +                if(a > 0) +                  a--; +              }     +              qname = QString(al[a]); +            } +            else +              qname = QString(buffer); +             +            //clientList.push_back(QString(buffer)); +            clientList.push_back(qname);              } +                    // p3.3.37        if(ports)          free(ports);       @@ -1678,22 +2043,34 @@ void JackAudioDevice::scanMidiPorts()  {    if(debugMsg)      printf("JackAudioDevice::scanMidiPorts:\n"); +   +/*      const char* type = JACK_DEFAULT_MIDI_TYPE;    const char** ports = jack_get_ports(_client, 0, type, 0); +   +  std::set<std::string> names;    for (const char** p = ports; p && *p; ++p)     {      jack_port_t* port = jack_port_by_name(_client, *p);      if(!port)        continue; +    // Ignore our own client ports. +    if(jack_port_is_mine(_client, port)) +    { +      if(debugMsg) +        printf(" ignoring own port: %s\n", *p); +      continue;          +    } +          int nsz = jack_port_name_size();      char buffer[nsz];      strncpy(buffer, *p, nsz);      // Ignore the MusE Jack port. -    if(strncmp(buffer, "MusE", 4) == 0) -      continue; +    //if(strncmp(buffer, "MusE", 4) == 0) +    //  continue;      if(debugMsg) -      printf(" found port:%s\n", buffer); +      printf(" found port: %s  ", buffer);      // If there are aliases for this port, use the first one - much better for identifying.       //char a1[nsz];  @@ -1706,8 +2083,75 @@ void JackAudioDevice::scanMidiPorts()      jack_port_get_aliases(port, aliases);      //int na = jack_port_get_aliases(port, aliases);      //char* namep = (na >= 1) ? aliases[0] : buffer; -    char* namep = aliases[0]; +    //char* namep = aliases[0]; +    //names.insert(std::string(*p)); +    if(debugMsg) +      printf("alias: %s\n", aliases[0]); +     +    names.insert(std::string(aliases[0])); +  } +  if(ports) +    free(ports);       +  std::list<MidiDevice*> to_del; +  for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) +  { +    // Only Jack midi devices. +    if(dynamic_cast<MidiJackDevice*>(*imd) == 0) +      continue; +    if(names.find(std::string((*imd)->name().latin1())) == names.end()) +      to_del.push_back(*imd); +  } +   +  for(std::list<MidiDevice*>::iterator imd = to_del.begin(); imd != to_del.end(); ++imd) +  { +    if(debugMsg) +      printf(" removing port device:%s\n", (*imd)->name().latin1()); +    midiDevices.remove(*imd); +    // This will close (and unregister) the client port. +    delete (*imd); +  } +   +  //for (const char** p = ports; p && *p; ++p)  +  for(std::set<std::string>::iterator is = names.begin(); is != names.end(); ++is) +  { +    //jack_port_t* port = jack_port_by_name(_client, *p); +    jack_port_t* port = jack_port_by_name(_client, is->c_str()); +    if(!port) +      continue; +*/     +     +    /* +    int nsz = jack_port_name_size(); +    char buffer[nsz]; +    //strncpy(buffer, *p, nsz); +    strncpy(buffer, is->c_str(), nsz); +    // Ignore the MusE Jack port. +    //if(strncmp(buffer, "MusE", 4) == 0) +    //  continue; +     +    // If there are aliases for this port, use the first one - much better for identifying.  +    //char a1[nsz];  +    char a2[nsz];  +    char* aliases[2]; +    //aliases[0] = a1; +    aliases[0] = buffer; +    aliases[1] = a2; +    // To disable aliases, just rem this line. +    jack_port_get_aliases(port, aliases); +    //int na = jack_port_get_aliases(port, aliases); +    //char* namep = (na >= 1) ? aliases[0] : buffer; +    char* namep = aliases[0]; +    QString qname(namep); +    */ +     +/* +    QString qname(is->c_str()); +     +    // Port already exists? +    if(midiDevices.find(qname)) +      continue; +          int flags = 0;      int pf = jack_port_flags(port);      // If Jack port can send data to us... @@ -1722,12 +2166,13 @@ void JackAudioDevice::scanMidiPorts()      //JackPort jp(0, QString(buffer), flags);      //portList.append(jp); -    MidiJackDevice* dev = new MidiJackDevice(0, QString(namep)); +    if(debugMsg) +      printf(" adding port device:%s\n", qname.latin1()); +     +    MidiJackDevice* dev = new MidiJackDevice(0, qname);      dev->setrwFlags(flags);      midiDevices.add(dev);    } -  // p3.3.37 -  if(ports) -    free(ports);       +*/  } diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h index 086e36db..242e762d 100644 --- a/muse/muse/driver/jackaudio.h +++ b/muse/muse/driver/jackaudio.h @@ -25,7 +25,7 @@ class JackAudioDevice : public AudioDevice {        int samplePos;        jack_transport_state_t transportState;        jack_position_t pos; -      char jackRegisteredName[8]; +      char jackRegisteredName[16];        int dummyState;        int dummyPos;        // Free-running frame counter incremented always in process. @@ -52,17 +52,18 @@ class JackAudioDevice : public AudioDevice {              return (float*)jack_port_get_buffer((jack_port_t*)port, nframes);              } -      virtual std::list<QString> outputPorts(); -      virtual std::list<QString> inputPorts(); +      virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1); +      virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);        virtual void registerClient(); +      virtual const char* clientName() { return jackRegisteredName; }        //virtual void* registerOutPort(const char* name);        //virtual void* registerInPort(const char* name);        virtual void* registerOutPort(const char* /*name*/, bool /*midi*/);        virtual void* registerInPort(const char* /*name*/, bool /*midi*/); -      virtual char* getJackName(); +      //virtual char* getJackName();        virtual void unregisterPort(void*);        virtual void connect(void*, void*); diff --git a/muse/muse/driver/jackmidi.cpp b/muse/muse/driver/jackmidi.cpp index efc70602..d27d83d6 100644 --- a/muse/muse/driver/jackmidi.cpp +++ b/muse/muse/driver/jackmidi.cpp @@ -5,6 +5,7 @@  //  (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)  //========================================================= +#include <qt.h>  #include <qstring.h>  #include <stdio.h> @@ -25,6 +26,9 @@  #include "audiodev.h"  #include "../mplugins/midiitransform.h"  #include "../mplugins/mitplugin.h" +#include "xml.h" + +extern unsigned int volatile lastExtMidiSyncTick;  // Turn on debug messages.  //#define JACK_MIDI_DEBUG @@ -42,28 +46,115 @@  ///int* jackSeq;  //static snd_seq_addr_t musePort; -int MidiJackDevice::_nextOutIdNum = 0; -int MidiJackDevice::_nextInIdNum = 0; +//int MidiJackDevice::_nextOutIdNum = 0; +//int MidiJackDevice::_nextInIdNum = 0; + +//int JackMidiPortList::_nextOutIdNum = 0; +//int JackMidiPortList::_nextInIdNum = 0; + +//JackMidiPortList jackMidiClientPorts; + +/*  //--------------------------------------------------------- -//   MidiAlsaDevice +//   JackMidiPortList  //--------------------------------------------------------- -MidiJackDevice::MidiJackDevice(const int& a, const QString& n) +JackMidiPortList::JackMidiPortList() +{ + +} + +JackMidiPortList::~JackMidiPortList() +{ + +} + +iJackMidiPort JackMidiPortList::createClientPort(int flags) // 1 = writable, 2 = readable - do not mix +{ +  if(flags & 1) +  { +    char buf[80]; +    snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum); +    jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); +    if(_client_jackport == NULL) +    { +      fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-out\n"); +      //return QString("Could not register jack-midi-out client port"); +      return end(); +    } +    else +    { +      JackMidiPort jmp(_client_jackport, QString(buf), flags); +      _nextOutIdNum++; +      return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp)); +    } +  } +  else  +  if(flags & 2) +  {   +    char buf[80]; +    snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum); +    jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true); +    if(_client_jackport == NULL) +    { +      fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-in\n"); +      return end(); +    } +    else +    { +      JackMidiPort jmp(_client_jackport, QString(buf), flags); +      _nextInIdNum++; +      return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp)); +    } +  } +  return end(); +} + +// Return true if removed. +bool JackMidiPortList::removeClientPort(jack_port_t* port)  +{ +  iJackMidiPort ijp = find(port); +  if(ijp == end()) +    return false; +     +  // Is output? +  if(ijp->second._flags & 1) +    _nextOutIdNum--; +  // Is input? +  if(ijp->second._flags & 2) +    _nextInIdNum--; +   +  erase(ijp); +   +  audioDevice->unregisterPort(port); +   +  return true; +} +*/ + +//--------------------------------------------------------- +//   MidiJackDevice +//--------------------------------------------------------- + +//MidiJackDevice::MidiJackDevice(const int& a, const QString& n) +MidiJackDevice::MidiJackDevice(jack_port_t* jack_port, const QString& n)     : MidiDevice(n)  { -  _client_jackport = 0; -  adr = a; +  //_client_jackport = 0; +  _client_jackport = jack_port; +  //adr = a;    init();  }  MidiJackDevice::~MidiJackDevice()  { -  #ifdef JACK_MIDI_USE_MULTIPLE_CLIENT_PORTS     +  #ifdef JACK_MIDI_DEBUG +    printf("MidiJackDevice::~MidiJackDevice()\n"); +  #endif      if(_client_jackport) -    //audioDevice->unregisterPort(_client_jackport); -    close(); -  #endif +    audioDevice->unregisterPort(_client_jackport); +    //close();  }  /* @@ -83,6 +174,181 @@ int MidiJackDevice::selectWfd()  */  //--------------------------------------------------------- +//   createJackMidiDevice +//   If name parameter is blank, creates a new (locally) unique one. +//--------------------------------------------------------- + +//QString MidiJackDevice::createJackMidiDevice(int rwflags) // 1:Writable 2: Readable. Do not mix. +MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable. Do not mix. +{ +///  _openFlags &= _rwFlags; // restrict to available bits +   +///  #ifdef JACK_MIDI_DEBUG +///  printf("MidiJackDevice::open %s\n", name.latin1()); +///  #endif   +   +  //jack_port_t* jp = jack_port_by_name(_client, name().latin1()); +///  jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); +   +///  if(!jp) +///  { +///    printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().latin1()); +///    _writeEnable = false; +///    _readEnable = false; +///    return QString("Jack midi port not found"); +///  } +     +///  int pf = jack_port_flags(jp); +   +  //if(!name.isEmpty()) +  //{ +  //  Does not work. +  //  if(audioDevice->findPort(name.latin1())) +  //  { +  //    fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Given port name %s already exists!\n", name.latin1()); +  //    return 0;   +  //  }   +  //} +   +  jack_port_t* client_jackport = NULL; +  //char buf[80]; +     +  // If Jack port can receive data from us and we actually want to... +  //if((pf & JackPortIsInput) && (_openFlags & 1)) +  if(rwflags & 1) +  { +    if(name.isEmpty()) +    { +      //snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum); +      for(int i = 0; ; ++i) +      { +        //snprintf(buf, 80, "midi-out-%d", i); +        name.sprintf("midi-out-%d", i); +         +        // Does not work. +        //if(!audioDevice->findPort(buf)) +        //  break; +        //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); +        client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); +        if(client_jackport) +          break; +           +        if(i == 65535) +        { +          fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n"); +          return 0; +        } +      } +      //name = QString(buf); +    } +    else +    { +      client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); +      if(!client_jackport) +      { +        fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.latin1()); +        return 0; +      } +    } +    /* +    else +    { +      client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); +      if(!client_jackport) +      { +        for(int i = 0; ; ++i) +        { +          snprintf(buf, 80, "midi-out-%d", i); +          // Does not work! +          //if(!audioDevice->findPort(buf)) +          //  break; +          client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); +          if(client_jackport) +            break; +             +          if(i == 65535) +          { +            fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n"); +            return 0; +          } +        } +        name = QString(buf); +      }     +    } +    */ +     +    //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true); +    //if(client_jackport == NULL) +    //{ +    //  fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client output port %s\n", name.latin1()); +    //  return 0; +    //} +    //else +    //  _nextOutIdNum++; +     +  } +  else // Note docs say it can't be both input and output. +  // If Jack port can send data to us and we actually want it... +  //if((pf & JackPortIsOutput) && (_openFlags & 2)) +  if(rwflags & 2) +  {   +    if(name.isEmpty()) +    { +      //snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum); +      for(int i = 0; ; ++i) +      { +        //snprintf(buf, 80, "midi-in-%d", i); +        name.sprintf("midi-in-%d", i);  +         +        // Does not work. +        //if(!audioDevice->findPort(buf)) +        //  break; +        //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true); +        client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); +        if(client_jackport) +          break; +           +        if(i == 65535) +        { +          fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused input port name!\n"); +          return 0; +        } +      } +      //name = QString(buf); +    } +    else +    { +      client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); +      if(!client_jackport) +      { +        fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.latin1()); +        return 0; +      } +    } +       +    //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true); +     +    //if(client_jackport == NULL) +    //{ +    //  fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client input port %s\n", name.latin1()); +      //_readEnable = false; +      //return QString("Could not register jack-midi-in client port"); +    //  return 0; +    //} +    //else +    //  _nextInIdNum++; +     +  } +  if(client_jackport == NULL) +    return 0; +     +  MidiJackDevice* dev = new MidiJackDevice(client_jackport, name); +  dev->setrwFlags(rwflags); +  midiDevices.add(dev); +  return dev; +} + +//---------------------------------------------------------  //   open  //--------------------------------------------------------- @@ -91,9 +357,10 @@ QString MidiJackDevice::open()    _openFlags &= _rwFlags; // restrict to available bits    #ifdef JACK_MIDI_DEBUG -  printf("MidiJackDevice::open %s\n", name.latin1()); +  printf("MidiJackDevice::open %s\n", name().latin1());    #endif   +  /*    //jack_port_t* jp = jack_port_by_name(_client, name().latin1());    jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); @@ -147,6 +414,11 @@ QString MidiJackDevice::open()        _readEnable = true;      }    } +  */ +   +  _writeEnable = bool(_openFlags & 1); +  _readEnable = bool(_openFlags & 2); +      return QString("OK");  } @@ -157,9 +429,10 @@ QString MidiJackDevice::open()  void MidiJackDevice::close()  {    #ifdef JACK_MIDI_DEBUG -  printf("MidiJackDevice::close %s\n", name.latin1()); +  printf("MidiJackDevice::close %s\n", name().latin1());    #endif   +  /*    if(_client_jackport)    {      int pf = jack_port_flags(_client_jackport); @@ -175,7 +448,11 @@ void MidiJackDevice::close()      _readEnable = false;      return;    }   +  */ +  _writeEnable = false; +  _readEnable = false; +      /*    //jack_port_t* jp = jack_port_by_name(_client, name().latin1());    jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); @@ -210,6 +487,124 @@ void MidiJackDevice::close()  }  //--------------------------------------------------------- +//   writeRouting +//--------------------------------------------------------- + +void MidiJackDevice::writeRouting(int level, Xml& xml) const +{ +      QString s; +      if(rwFlags() & 2)  // Readable +      { +        //RouteList* rl = _inRoutes; +        //for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)  +        { +          if(!r->name().isEmpty()) +          { +            xml.tag(level++, "Route"); +             +            //xml.strTag(level, "srcNode", r->name()); +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +            s = QT_TR_NOOP("source"); +            if(r->type != Route::TRACK_ROUTE) +              s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); +            s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); +            xml.tag(level, s); +             +            //xml.strTag(level, "dstNode", name()); +            //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1()); +            //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1()); +            xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1()); +             +            xml.etag(level--, "Route"); +          } +        }   +      }  +       +      for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)  +      { +        if(!r->name().isEmpty()) +        { +          s = QT_TR_NOOP("Route"); +          if(r->channel != -1) +            s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); +           +          //xml.tag(level++, "Route"); +          xml.tag(level++, s); +           +          /* +          //xml.strTag(level, "srcNode", name()); +          if(r->channel != -1)   +            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, r->channel, name().latin1()); +            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1()); +            xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, r->channel, name().latin1()); +          else   +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1()); +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1()); +          */   +            xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1()); +           +          /* +          //xml.strTag(level, "dstNode", r->name()); +          if(r->channel != -1) +          {   +            if(r->type == Route::MIDI_DEVICE_ROUTE) +              xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1()); +            else   +              xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1()); +          } +          else   +          { +            if(r->type == Route::MIDI_DEVICE_ROUTE) +              xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1()); +            else   +              xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +          } +          */ +           +          s = QT_TR_NOOP("dest"); +          if(r->type == Route::MIDI_DEVICE_ROUTE) +            s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType()); +          else +          if(r->type != Route::TRACK_ROUTE) +            s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); +          s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); +          xml.tag(level, s); +           +           +          xml.etag(level--, "Route"); +        } +      } +       +      /* +      else +      if(rwFlags() & 1)  // Writable +      { +        //RouteList* rl = _outRoutes; +        //for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)  +        { +          if(!r->name().isEmpty()) +          { +            xml.tag(level++, "Route"); +             +            //xml.strTag(level, "srcNode", name()); +            //if(r->channel != -1)   +            //  xml.tag(level, "srcNode type=\"%d\" channel=\"%d\" name=\"%s\"", Route::JACK_MIDI_ROUTE, r->channel, name().latin1()); +            //else   +              xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1()); +             +            //xml.strTag(level, "dstNode", r->name()); +            xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +             +            xml.etag(level--, "Route"); +          } +        }   +      } +      */       +} +     +//---------------------------------------------------------  //   putEvent  //--------------------------------------------------------- @@ -310,12 +705,12 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)              event.dump();              } +      int typ = event.type(); +              if(_port != -1)        {          int idin = midiPorts[_port].syncInfo().idIn(); -        int typ = event.type(); -            //---------------------------------------------------          // filter some SYSEX events          //--------------------------------------------------- @@ -370,13 +765,24 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)        // transfer noteOn events to gui for step recording and keyboard        // remote control        // -      if (event.type() == ME_NOTEON) { +      if (typ == ME_NOTEON) {              int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);              song->putEvent(pv);              } -      if(_recordFifo.put(MidiPlayEvent(event))) -        printf("MidiJackDevice::recordEvent: fifo overflow\n"); +      //if(_recordFifo.put(MidiPlayEvent(event))) +      //  printf("MidiJackDevice::recordEvent: fifo overflow\n"); +       +      // p3.3.38 +      // Do not bother recording if it is NOT actually being used by a port. +      // Because from this point on, process handles things, by selected port. +      if(_port == -1) +        return; +       +      // Split the events up into channel fifos. Special 'channel' number 17 for sysex events. +      unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel(); +      if(_recordFifo[ch].put(MidiPlayEvent(event))) +        printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch);        }  //--------------------------------------------------------- @@ -403,7 +809,9 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)  //      unsigned curFrame = st->lastFrameTime;        //int frameOffset = audio->getFrameOffset();        unsigned pos = audio->pos().frame(); -      event.setTime(pos + ev->time); +       +      //event.setTime(pos + ev->time); +      event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time));        event.setChannel(*(ev->buffer) & 0xf);        int type = *(ev->buffer) & 0xf0; @@ -428,23 +836,56 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)              case ME_SYSEX:                    { -                  int type = *(ev->buffer) & 0xff; -                  switch(type) { -                        case ME_SYSEX: -                              event.setTime(0);      // mark as used -                              event.setType(ME_SYSEX); -                              event.setData((unsigned char*)(ev->buffer + 1), -                                 ev->size - 2); -                              break; -                        case ME_CLOCK: -                        case ME_SENSE: -                              break; -                        default: -                              printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type); -                              return; -                        } +                    int type = *(ev->buffer) & 0xff; +                    switch(type)  +                    { +                          case ME_SYSEX: +                                 +                                // TODO: Deal with large sysex, which are broken up into chunks! +                                // For now, do not accept if the last byte is not EOX, meaning it's a chunk with more chunks to follow. +                                if(*(((unsigned char*)ev->buffer) + ev->size - 1) != ME_SYSEX_END) +                                { +                                  printf("MidiJackDevice::eventReceived sysex chunks not supported!\n"); +                                  return; +                                } +                                 +                                //event.setTime(0);      // mark as used +                                event.setType(ME_SYSEX); +                                event.setData((unsigned char*)(ev->buffer + 1), ev->size - 2); +                                break; +                          case ME_MTC_QUARTER: +                                if(_port != -1) +                                  midiSeq->mtcInputQuarter(_port, *(ev->buffer + 1));  +                                return; +                          case ME_SONGPOS:     +                                if(_port != -1) +                                  midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) >> 2 )); // LSB then MSB +                                return; +                          //case ME_SONGSEL:     +                          //case ME_TUNE_REQ:    +                          //case ME_SENSE: +                          case ME_CLOCK:       +                          case ME_TICK:        +                          case ME_START:       +                          case ME_CONTINUE:    +                          case ME_STOP:        +                                if(_port != -1) +                                  midiSeq->realtimeSystemInput(_port, type); +                                return; +                          //case ME_SYSEX_END:   +                                //break; +                          //      return; +                          default: +                                printf("MidiJackDevice::eventReceived unsupported system event 0x%02x\n", type); +                                return; +                    }                    } -                  return; +                  //return; +                  break; +            default: +              printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type); +              //printf("MidiJackDevice::eventReceived unknown event 0x%02x size:%d buf:0x%02x 0x%02x 0x%02x ...0x%02x\n", type, ev->size, *(ev->buffer), *(ev->buffer + 1), *(ev->buffer + 2), *(ev->buffer + (ev->size - 1))); +              return;              }        if (midiInputTrace) { diff --git a/muse/muse/driver/jackmidi.h b/muse/muse/driver/jackmidi.h index d260163c..a143b7ff 100644 --- a/muse/muse/driver/jackmidi.h +++ b/muse/muse/driver/jackmidi.h @@ -10,15 +10,20 @@  //#include <config.h> +#include <map> +  #include <jack/jack.h>  #include <jack/midiport.h>  #include "mididev.h" +#include "route.h"  class QString;  class MidiFifo;  class MidiRecordEvent;  class MidiPlayEvent; +//class RouteList; +class Xml;  // Turn on to show multiple devices, work in progress,   //  not working fully yet, can't seem to connect... @@ -44,23 +49,57 @@ typedef struct {  } muse_jack_midi_buffer;  */ +/* +struct JackMidiPort  +{ +  jack_port_t* _jackPort; +  QString _name; +  int _flags; // 1 = writable, 2 = readable - do not mix +  JackMidiPort(jack_port_t* jp, const QString& s, int f)  +  { +    _jackPort = jp; +    _name = QString(s); +    _flags = f; +  } +}; + +typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::iterator iJackMidiPort; +typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::const_iterator ciJackMidiPort; + +class JackMidiPortList : public std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >  +{ +   private:    +      static int _nextOutIdNum; +      static int _nextInIdNum; +       +   public: +      JackMidiPortList(); +      ~JackMidiPortList(); +      iJackMidiPort createClientPort(int flags); +      bool removeClientPort(jack_port_t* port); +}; + +extern JackMidiPortList jackMidiClientPorts; +*/ +  //---------------------------------------------------------  //   MidiJackDevice  //---------------------------------------------------------  class MidiJackDevice : public MidiDevice {     public: -      int adr; +      //int adr;     private:        // fifo for midi events sent from gui        // direct to midi port:        MidiFifo eventFifo; -      static int _nextOutIdNum; -      static int _nextInIdNum; +      //static int _nextOutIdNum; +      //static int _nextInIdNum;        jack_port_t* _client_jackport; +      //RouteList _routes;        virtual QString open();        virtual void close(); @@ -77,8 +116,14 @@ class MidiJackDevice : public MidiDevice {     public:        MidiJackDevice() {} -      MidiJackDevice(const int&, const QString& name); -      void processMidi(); +      //MidiJackDevice(const int&, const QString& name); +      MidiJackDevice(jack_port_t* jack_port, const QString& name); +       +      static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix. +       +      virtual inline int deviceType() { return JACK_MIDI; }  +       +      virtual void processMidi();        virtual ~MidiJackDevice();         //virtual int selectRfd();        //virtual int selectWfd(); @@ -90,7 +135,12 @@ class MidiJackDevice : public MidiDevice {        virtual void collectMidiEvents();        //virtual jack_port_t* jackPort() { return _jackport; } -      virtual jack_port_t* clientJackPort() { return _client_jackport; } +      //virtual jack_port_t* clientJackPort() { return _client_jackport; } +      virtual void* clientPort() { return (void*)_client_jackport; } +       +      //RouteList* routes()   { return &_routes; } +      //bool noRoute() const   { return _routes.empty();  } +      virtual void writeRouting(int, Xml&) const;        };  extern bool initMidiJack(); diff --git a/muse/muse/dssihost.cpp b/muse/muse/dssihost.cpp index b9825a83..eb07b1d1 100644 --- a/muse/muse/dssihost.cpp +++ b/muse/muse/dssihost.cpp @@ -360,6 +360,28 @@ static void scanDSSILib(const QFileInfo& fi)              //DssiSynth* s = new DssiSynth(fi, label);              DssiSynth* s = new DssiSynth(fi, label, QString(descr->LADSPA_Plugin->Name), QString(descr->LADSPA_Plugin->Maker), QString()); +            if(debugMsg) +            { +              fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n", label.ascii(), s->name().ascii(), fi.baseName(true).ascii(), s->baseName().ascii()); +              int ai = 0, ao = 0, ci = 0, co = 0; +              for(int pt = 0; pt < descr->LADSPA_Plugin->PortCount; ++pt) +              { +                LADSPA_PortDescriptor pd = descr->LADSPA_Plugin->PortDescriptors[pt]; +                if(LADSPA_IS_PORT_INPUT(pd) && LADSPA_IS_PORT_AUDIO(pd)) +                  ai++; +                else   +                if(LADSPA_IS_PORT_OUTPUT(pd) && LADSPA_IS_PORT_AUDIO(pd)) +                  ao++; +                else   +                if(LADSPA_IS_PORT_INPUT(pd) && LADSPA_IS_PORT_CONTROL(pd)) +                  ci++; +                else   +                if(LADSPA_IS_PORT_OUTPUT(pd) && LADSPA_IS_PORT_CONTROL(pd)) +                  co++; +              }   +              fprintf(stderr, "audio ins:%d outs:%d control ins:%d outs:%d\n", ai, ao, ci, co); +            } +                          synthis.push_back(s);            }            else @@ -545,7 +567,8 @@ bool DssiSynthIF::init(DssiSynth* s)          for(int k = 0; k < inports; ++k)          {            //audioInBuffers[k] = new LADSPA_Data[segmentSize]; -          posix_memalign((void**)(audioInBuffers + k), 16, sizeof(float) * segmentSize); +          //posix_memalign((void**)(audioInBuffers + k), 16, sizeof(float) * segmentSize); +          posix_memalign((void**)&audioInBuffers[k], 16, sizeof(float) * segmentSize);            memset(audioInBuffers[k], 0, sizeof(float) * segmentSize);            ld->connect_port(handle, synth->iIdx[k], audioInBuffers[k]);          }   @@ -558,9 +581,11 @@ bool DssiSynthIF::init(DssiSynth* s)          for(int k = 0; k < outports; ++k)          {            //audioOutBuffers[k] = new LADSPA_Data[segmentSize]; -          posix_memalign((void**)(audioOutBuffers + k), 16, sizeof(float) * segmentSize); +          //posix_memalign((void**)(audioOutBuffers + k), 16, sizeof(float) * segmentSize); +          posix_memalign((void**)&audioOutBuffers[k], 16, sizeof(float) * segmentSize);            memset(audioOutBuffers[k], 0, sizeof(float) * segmentSize);            ld->connect_port(handle, synth->oIdx[k], audioOutBuffers[k]); +          //printf("DssiSynthIF::init output port name: %s\n", ld->PortNames[synth->oIdx[k]]); // out1, out2, out3 etc          }          } @@ -1995,6 +2020,16 @@ int DssiSynthIF::channels() const    return synth->_outports > MAX_CHANNELS ? MAX_CHANNELS : synth->_outports;   } +int DssiSynthIF::totalOutChannels() const  +{  +  return synth->_outports;  +} + +int DssiSynthIF::totalInChannels() const  +{  +  return synth->_inports;  +} +  #else //DSSI_SUPPORT  void initDSSI() {}  #endif diff --git a/muse/muse/dssihost.h b/muse/muse/dssihost.h index f2609dca..eb3637f0 100644 --- a/muse/muse/dssihost.h +++ b/muse/muse/dssihost.h @@ -139,6 +139,8 @@ class DssiSynthIF : public SynthIF        //virtual int channels() const { return synth->_outports; }        virtual int channels() const; +      virtual int totalOutChannels() const; +      virtual int totalInChannels() const;        virtual void deactivate3() {} diff --git a/muse/muse/globaldefs.h b/muse/muse/globaldefs.h index d842a3f0..06661771 100644 --- a/muse/muse/globaldefs.h +++ b/muse/muse/globaldefs.h @@ -23,7 +23,8 @@ enum AutomationType {  const int MAX_CHANNELS = 2;   // max audio channels  const int MAX_PLUGINS  = 4;   // plugins in mixer rack -const int MIDI_PORTS   = 32;  // max Number of Midi Ports +//const int MIDI_PORTS   = 32;  // max Number of Midi Ports +const int MIDI_PORTS   = 128;  // max Number of Midi Ports  #ifndef MIDI_CHANNELS  #define MIDI_CHANNELS 16       // Channels per Port diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index 04f802be..5f919a45 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -955,10 +955,11 @@ void Audio::processMidi()                }              } -            // Is it a Jack midi device? -            MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); -            if(mjd) -              mjd->collectMidiEvents(); +            // Is it a Jack midi device?  +            //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); +            //if(mjd) +            //  mjd->collectMidiEvents(); +            md->collectMidiEvents();              // Take snapshots of the current sizes of the recording fifos,               //  because they may change while here in process, asynchronously. @@ -1004,220 +1005,314 @@ void Audio::processMidi()              if (track->recordFlag())               {                    //int portMask    = track->inPortMask(); -                  unsigned int portMask = track->inPortMask(); -                  int channelMask = track->inChannelMask(); +                  // p3.3.38 Removed +                  //unsigned int portMask = track->inPortMask(); +                  //int channelMask = track->inChannelMask(); +                                      MPEventList* rl = track->mpevents();                    MidiPort* tport = &midiPorts[port]; -                  for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)  +                  // p3.3.38 +                  //for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)  +                  //{ +                  RouteList* irl = track->inRoutes(); +                  for(ciRoute r = irl->begin(); r != irl->end(); ++r)                    { -                        MidiDevice* dev = *id; - +                        //if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE)) +                        if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) +                          continue; +                            +                        //MidiDevice* dev = *id; +                        MidiDevice* dev = r->device; +                        int channel = r->channel; + +                        // NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **. +                        // This would mean having a separate 'System' channel listed in the routing popups. +                        // The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it,  +                        //  this does not require a 'System' channel listed in the routing popups. +                        // But that requires more code below... Not added yet... +                        if(channel == -1) +                          //channel = MIDI_CHANNELS; // Special channel '17' +                          continue; +                                                    int devport = dev->midiPort();                          // record only from ports marked in portMask: -                        if (devport == -1 || !(portMask & (1 << devport))) +                        //if (devport == -1 || !(portMask & (1 << devport))) +                        if (devport == -1)                                continue;                          //MREventList* el = dev->recordEvents(); -                        MidiFifo& rf = dev->recordEvents(); +                        //MidiFifo& rf = dev->recordEvents(); +                         +                         +                        if(!dev->sysexFIFOProcessed()) +                        { +                          // Set to the sysex fifo at first. +                          MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); +                          // Get the frozen snapshot of the size. +                          int count = dev->tmpRecordCount(MIDI_CHANNELS); +                         +                          for(int i = 0; i < count; ++i)  +                          { +                            MidiPlayEvent event(rf.peek(i)); +                             +                            //unsigned time = event.time() + segmentSize*(segmentCount-1); +                            //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); +                            //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); +                            //event.setTime(time); +                            //if(!extsync) +                            //  event.setTime(event.time() + segmentSize*(segmentCount-1)); + +                            event.setPort(port); +                             +                            // dont't echo controller changes back to software +                            // synthesizer: +                            if(!dev->isSynti() && md && track->recEcho()) +                              playEvents->add(event); +                             +                            // If syncing externally the event time is already in units of ticks, set above. +                            if(!extsync) +                            { +                              //time = tempomap.frame2tick(event.time()); +                              //event.setTime(time);  // set tick time +                              event.setTime(tempomap.frame2tick(event.time()));  // set tick time +                            }   + +                            if(recording)  +                              rl->add(event); +                          }       +                           +                          dev->setSysexFIFOProcessed(true); +                        } +                         +                        // Set to the sysex fifo at first. +                        ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);                          // Get the frozen snapshot of the size. -                        int count = dev->tmpRecordCount(); +                        ///int count = dev->tmpRecordCount(MIDI_CHANNELS); -                        //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)  -                        for(int i = 0; i < count; ++i)  +                        // Iterate once for sysex fifo (if needed), once for channel fifos. +                        ///for(int sei = 0; sei < 2; ++sei)                          { -                              MidiPlayEvent event(rf.peek(i)); -                               -                              //int channel = ie->channel(); -                              int channel = event.channel(); -                              int defaultPort = devport; -                              if (!(channelMask & (1 << channel))) -                              { -                                    continue; -                              }       - -                              //MidiPlayEvent event(*ie); -                              int drumRecPitch=0; //prevent compiler warning: variable used without initialization -                              MidiController *mc = 0; -                              int ctl = 0; -                               -                              //Hmmm, hehhh...  -                              // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.  -                              // But not before 0.7 (ml) - -                              int prePitch = 0, preVelo = 0; - -                              event.setChannel(track->outChannel()); -                               -                              if (event.isNote() || event.isNoteOff())  -                              { -                                    // -                                    // apply track values -                                    // - -                                    //Apply drum inkey: -                                    if (track->type() == Track::DRUM)  -                                    { -                                          int pitch = event.dataA(); -                                          //Map note that is played according to drumInmap -                                          drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote; -                                          devport = drumMap[(unsigned int)drumInmap[pitch]].port; -                                          event.setPort(devport); -                                          channel = drumMap[(unsigned int)drumInmap[pitch]].channel; -                                          event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote); -                                          event.setChannel(channel); -                                    } -                                    else  -                                    { //Track transpose if non-drum -                                          prePitch = event.dataA(); -                                          int pitch = prePitch + track->transposition; -                                          if (pitch > 127) -                                                pitch = 127; -                                          if (pitch < 0) -                                                pitch = 0; -                                          event.setA(pitch); -                                    } - -                                    if (!event.isNoteOff())  -                                    { -                                          preVelo = event.dataB(); -                                          int velo = preVelo + track->velocity; -                                          velo = (velo * track->compression) / 100; -                                          if (velo > 127) -                                                velo = 127; -                                          if (velo < 1) -                                                velo = 1; -                                          event.setB(velo); -                                    } -                              } -                              // Added by T356. -                              else -                              if(event.type() == ME_CONTROLLER) -                              { -                                if(track->type() == Track::DRUM)  +                          // If on first pass, do sysex fifo.   +                          /* +                          if(sei == 0) +                          {   +                            // Ignore any further channel routes on this device if already done here. +                            if(dev->sysexFIFOProcessed()) +                              continue; +                            // Go ahead and set this now. +                            dev->setSysexFIFOProcessed(true); +                            // Allow it to fall through with the sysex fifo and count... +                          } +                          else +                          { +                            // We're on the second pass, do channel fifos. +                            rf = dev->recordEvents(channel); +                            // Get the frozen snapshot of the size. +                            count = dev->tmpRecordCount(channel); +                          } +                          */ +                           +                          MidiFifo& rf = dev->recordEvents(channel); +                          int count = dev->tmpRecordCount(channel); +                           +                          //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)  +                          for(int i = 0; i < count; ++i)  +                          { +                                MidiPlayEvent event(rf.peek(i)); +                                 +                                //int channel = ie->channel(); +                                ///int channel = event.channel(); +                                 +                                int defaultPort = devport; +                                ///if (!(channelMask & (1 << channel))) +                                ///{ +                                ///      continue; +                                ///}       +   +                                //MidiPlayEvent event(*ie); +                                int drumRecPitch=0; //prevent compiler warning: variable used without initialization +                                MidiController *mc = 0; +                                int ctl = 0; +                                 +                                //Hmmm, hehhh...  +                                // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.  +                                // But not before 0.7 (ml) +   +                                int prePitch = 0, preVelo = 0; +   +                                event.setChannel(track->outChannel()); +                                 +                                if (event.isNote() || event.isNoteOff())                                   { -                                  ctl = event.dataA(); -                                  // Regardless of what port the event came from, is it a drum controller event  -                                  //  according to the track port's instrument? -                                  mc = tport->drumController(ctl); -                                  if(mc) -                                  { -                                    int pitch = ctl & 0x7f; -                                    ctl &= ~0xff; -                                    int dmindex = drumInmap[pitch] & 0x7f; -                                    //Map note that is played according to drumInmap -                                    drumRecPitch = drumMap[dmindex].enote; -                                    devport = drumMap[dmindex].port; -                                    event.setPort(devport); -                                    channel = drumMap[dmindex].channel; -                                    event.setA(ctl | drumMap[dmindex].anote); -                                    event.setChannel(channel); -                                  }   -                                } -                              } -                               -                              // p3.3.25  -                              // MusE uses a fixed clocks per quarternote of 24.  -                              // At standard 384 ticks per quarternote for example,  -                              // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks'). -                              // That is what we'll use if syncing externally. -                              //unsigned time = event.time() + segmentSize*(segmentCount-1); -                              //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); -                              // p3.3.34 -                              // Oops, use the current tick.  -                              //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); -                              //event.setTime(time); -                              // p3.3.35 -                              // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). -                              // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. -                              // p3.3.36 -                              //if(!extsync) -                              //  event.setTime(event.time() + segmentSize*(segmentCount-1)); - -                              // dont't echo controller changes back to software -                              // synthesizer: - -                              if (!dev->isSynti())  -                              { -                                //Check if we're outputting to another port than default: -                                if (devport == defaultPort) { -                                      event.setPort(port); -                                      if(md && track->recEcho()) -                                        playEvents->add(event); +                                      // +                                      // apply track values +                                      // +   +                                      //Apply drum inkey: +                                      if (track->type() == Track::DRUM)  +                                      { +                                            int pitch = event.dataA(); +                                            //Map note that is played according to drumInmap +                                            drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote; +                                            devport = drumMap[(unsigned int)drumInmap[pitch]].port; +                                            event.setPort(devport); +                                            channel = drumMap[(unsigned int)drumInmap[pitch]].channel; +                                            event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote); +                                            event.setChannel(channel);                                        } -                                else { -                                      // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent?? -                                      MidiDevice* mdAlt = midiPorts[devport].device(); -                                      if(mdAlt && track->recEcho()) -                                        mdAlt->playEvents()->add(event); +                                      else  +                                      { //Track transpose if non-drum +                                            prePitch = event.dataA(); +                                            int pitch = prePitch + track->transposition; +                                            if (pitch > 127) +                                                  pitch = 127; +                                            if (pitch < 0) +                                                  pitch = 0; +                                            event.setA(pitch);                                        } -                                // Shall we activate meters even while rec echo is off? Sure, why not... -                                if(event.isNote() && event.dataB() > track->activity()) -                                  track->setActivity(event.dataB()); -                              } -                               -                              // p3.3.25 -                              // If syncing externally the event time is already in units of ticks, set above. -                              if(!extsync) -                              { -                                // p3.3.35 -                                //time = tempomap.frame2tick(event.time()); -                                //event.setTime(time);  // set tick time -                                event.setTime(tempomap.frame2tick(event.time()));  // set tick time -                              }   - -                              // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml) -                              if (recording)  -                              { -                                    // In these next steps, it is essential to set the recorded event's port  -                                    //  to the track port so buildMidiEventList will accept it. Even though  -                                    //  the port may have no device "<none>". -                                    // -                                    if (track->type() == Track::DRUM)  +   +                                      if (!event.isNoteOff())  +                                      { +                                            preVelo = event.dataB(); +                                            int velo = preVelo + track->velocity; +                                            velo = (velo * track->compression) / 100; +                                            if (velo > 127) +                                                  velo = 127; +                                            if (velo < 1) +                                                  velo = 1; +                                            event.setB(velo); +                                      } +                                } +                                // Added by T356. +                                else +                                if(event.type() == ME_CONTROLLER) +                                { +                                  if(track->type() == Track::DRUM)  +                                  { +                                    ctl = event.dataA(); +                                    // Regardless of what port the event came from, is it a drum controller event  +                                    //  according to the track port's instrument? +                                    mc = tport->drumController(ctl); +                                    if(mc)                                      { -                                      // Is it a drum controller event? -                                      if(mc) -                                      {     -                                          MidiPlayEvent drumRecEvent = event; -                                          drumRecEvent.setA(ctl | drumRecPitch); -                                          // In this case, preVelo is simply the controller value. -                                          drumRecEvent.setB(preVelo); -                                          drumRecEvent.setPort(port); //rec-event to current port -                                          drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel -                                          rl->add(drumRecEvent); +                                      int pitch = ctl & 0x7f; +                                      ctl &= ~0xff; +                                      int dmindex = drumInmap[pitch] & 0x7f; +                                      //Map note that is played according to drumInmap +                                      drumRecPitch = drumMap[dmindex].enote; +                                      devport = drumMap[dmindex].port; +                                      event.setPort(devport); +                                      channel = drumMap[dmindex].channel; +                                      event.setA(ctl | drumMap[dmindex].anote); +                                      event.setChannel(channel); +                                    }   +                                  } +                                } +                                 +                                // p3.3.25  +                                // MusE uses a fixed clocks per quarternote of 24.  +                                // At standard 384 ticks per quarternote for example,  +                                // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks'). +                                // That is what we'll use if syncing externally. +                                //unsigned time = event.time() + segmentSize*(segmentCount-1); +                                //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); +                                // p3.3.34 +                                // Oops, use the current tick.  +                                //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); +                                //event.setTime(time); +                                // p3.3.35 +                                // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). +                                // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. +                                // p3.3.36 +                                //if(!extsync) +                                //  event.setTime(event.time() + segmentSize*(segmentCount-1)); +   +                                // dont't echo controller changes back to software +                                // synthesizer: +   +                                if (!dev->isSynti())  +                                { +                                  //Check if we're outputting to another port than default: +                                  if (devport == defaultPort) { +                                        event.setPort(port); +                                        if(md && track->recEcho()) +                                          playEvents->add(event); +                                        } +                                  else { +                                        // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent?? +                                        MidiDevice* mdAlt = midiPorts[devport].device(); +                                        if(mdAlt && track->recEcho()) +                                          mdAlt->playEvents()->add(event); +                                        } +                                  // Shall we activate meters even while rec echo is off? Sure, why not... +                                  if(event.isNote() && event.dataB() > track->activity()) +                                    track->setActivity(event.dataB()); +                                } +                                 +                                // p3.3.25 +                                // If syncing externally the event time is already in units of ticks, set above. +                                if(!extsync) +                                { +                                  // p3.3.35 +                                  //time = tempomap.frame2tick(event.time()); +                                  //event.setTime(time);  // set tick time +                                  event.setTime(tempomap.frame2tick(event.time()));  // set tick time +                                }   +   +                                // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml) +                                if (recording)  +                                { +                                      // In these next steps, it is essential to set the recorded event's port  +                                      //  to the track port so buildMidiEventList will accept it. Even though  +                                      //  the port may have no device "<none>". +                                      // +                                      if (track->type() == Track::DRUM)  +                                      { +                                        // Is it a drum controller event? +                                        if(mc) +                                        {     +                                            MidiPlayEvent drumRecEvent = event; +                                            drumRecEvent.setA(ctl | drumRecPitch); +                                            // In this case, preVelo is simply the controller value. +                                            drumRecEvent.setB(preVelo); +                                            drumRecEvent.setPort(port); //rec-event to current port +                                            drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel +                                            rl->add(drumRecEvent); +                                        } +                                        else +                                        { +                                         +                                            MidiPlayEvent drumRecEvent = event; +                                            drumRecEvent.setA(drumRecPitch); +                                            drumRecEvent.setB(preVelo); +                                            // Changed by T356.  +                                            // Tested: Events were not being recorded for a drum map entry pointing to a  +                                            //  different port. This must have been wrong - buildMidiEventList would ignore this. +                                            //drumRecEvent.setPort(devport); +                                            drumRecEvent.setPort(port);  //rec-event to current port +                                             +                                            drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel +                                            rl->add(drumRecEvent); +                                        }                                            } -                                      else +                                      else                                         { -                                       -                                          MidiPlayEvent drumRecEvent = event; -                                          drumRecEvent.setA(drumRecPitch); -                                          drumRecEvent.setB(preVelo); -                                          // Changed by T356.  -                                          // Tested: Events were not being recorded for a drum map entry pointing to a  -                                          //  different port. This must have been wrong - buildMidiEventList would ignore this. -                                          //drumRecEvent.setPort(devport); -                                          drumRecEvent.setPort(port);  //rec-event to current port -                                           -                                          drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel -                                          rl->add(drumRecEvent); -                                      }     -                                    } -                                    else  -                                    { -                                          // Restore record-pitch to non-transposed value since we don't want the note transposed twice next -                                          MidiPlayEvent recEvent = event; -                                          if (prePitch) -                                                recEvent.setA(prePitch); -                                          if (preVelo) -                                                recEvent.setB(preVelo); -                                          recEvent.setPort(port); -                                          recEvent.setChannel(track->outChannel()); -                                                 -                                          rl->add(recEvent); -                                    } -                              } -                        } +                                            // Restore record-pitch to non-transposed value since we don't want the note transposed twice next +                                            MidiPlayEvent recEvent = event; +                                            if (prePitch) +                                                  recEvent.setA(prePitch); +                                            if (preVelo) +                                                  recEvent.setB(preVelo); +                                            recEvent.setPort(port); +                                            recEvent.setChannel(track->outChannel()); +                                                   +                                            rl->add(recEvent); +                                      } +                                } +                          } +                        }                      }              }              // Added by Tim. p3.3.8 @@ -1382,13 +1477,13 @@ void Audio::processMidi()        //        for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)         { -        MidiDevice* md = *id; +        //MidiDevice* md = *id;          // Is it a Jack midi device? -        MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); -        if(!mjd) -          continue; -         -        mjd->processMidi(); +        //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); +        //if(!mjd) +        //  continue; +        //mjd->processMidi(); +        (*id)->processMidi();          /*          int port = md->midiPort(); diff --git a/muse/muse/mididev.cpp b/muse/muse/mididev.cpp index 28acd541..7f52fc2e 100644 --- a/muse/muse/mididev.cpp +++ b/muse/muse/mididev.cpp @@ -83,7 +83,14 @@ void MidiDevice::init()  MidiDevice::MidiDevice()        {        ///_recBufFlipped = false; -      _tmpRecordCount = 0; +      //_tmpRecordCount = 0; +      for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i) +        _tmpRecordCount[i] = 0; +       +      _sysexFIFOProcessed = false; +      //_sysexWritingChunks = false; +      _sysexReadingChunks = false; +              init();        } @@ -91,7 +98,14 @@ MidiDevice::MidiDevice(const QString& n)     : _name(n)        {        ///_recBufFlipped = false; -      _tmpRecordCount = 0; +      //_tmpRecordCount = 0; +      for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i) +        _tmpRecordCount[i] = 0; +       +      _sysexFIFOProcessed = false; +      //_sysexWritingChunks = false; +      _sysexReadingChunks = false; +              init();        } @@ -151,10 +165,16 @@ bool filterEvent(const MEvent& event, int type, bool thru)  //---------------------------------------------------------  void MidiDevice::afterProcess() -      { -      while (_tmpRecordCount--) -            _recordFifo.remove(); -      } +{ +  //while (_tmpRecordCount--) +  //  _recordFifo.remove(); +   +  for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i) +  { +    while (_tmpRecordCount[i]--) +      _recordFifo[i].remove(); +  }  +}  //---------------------------------------------------------  //   beforeProcess @@ -162,11 +182,17 @@ void MidiDevice::afterProcess()  //---------------------------------------------------------  void MidiDevice::beforeProcess() -      { -      //if (!jackPort(0).isZero()) -      //      audioDriver->collectMidiEvents(this, jackPort(0)); -      _tmpRecordCount = _recordFifo.getSize(); -      } +{ +  //if (!jackPort(0).isZero()) +  //      audioDriver->collectMidiEvents(this, jackPort(0)); +   +  //_tmpRecordCount = _recordFifo.getSize(); +  for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i) +    _tmpRecordCount[i] = _recordFifo[i].getSize(); +   +  // Reset this. +  _sysexFIFOProcessed = false; +}  /*  //--------------------------------------------------------- @@ -230,13 +256,14 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)              event.dump();              } +      int typ = event.type(); +              if(_port != -1)        {          int idin = midiPorts[_port].syncInfo().idIn();  // p3.3.26 1/23/10 Section was disabled, enabled by Tim.  //#if 0 -        int typ = event.type();          //---------------------------------------------------          // filter some SYSEX events @@ -296,7 +323,7 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)        // transfer noteOn events to gui for step recording and keyboard        // remote control        // -      if (event.type() == ME_NOTEON) { +      if (typ == ME_NOTEON) {              int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);              song->putEvent(pv);              } @@ -305,18 +332,30 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)        ///  _recordEvents2.add(event);     // add event to secondary list of recorded events        ///else        ///  _recordEvents.add(event);     // add event to primary list of recorded events -      if(_recordFifo.put(MidiPlayEvent(event))) -        printf("MidiDevice::recordEvent: fifo overflow\n"); +       +      //if(_recordFifo.put(MidiPlayEvent(event))) +      //  printf("MidiDevice::recordEvent: fifo overflow\n"); +       +      // p3.3.38 +      // Do not bother recording if it is NOT actually being used by a port. +      // Because from this point on, process handles things, by selected port. +      if(_port == -1) +        return; +       +      // Split the events up into channel fifos. Special 'channel' number 17 for sysex events. +      unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel(); +      if(_recordFifo[ch].put(MidiPlayEvent(event))) +        printf("MidiDevice::recordEvent: fifo channel %d overflow\n", ch);        }  //---------------------------------------------------------  //   find  //--------------------------------------------------------- -MidiDevice* MidiDeviceList::find(const QString& s) +MidiDevice* MidiDeviceList::find(const QString& s, int typeHint)        {        for (iMidiDevice i = begin(); i != end(); ++i) -            if ((*i)->name() == s) +            if( (typeHint == -1 || typeHint == (*i)->deviceType()) && ((*i)->name() == s) )                    return *i;        return 0;        } diff --git a/muse/muse/mididev.h b/muse/muse/mididev.h index a0744923..36b33c27 100644 --- a/muse/muse/mididev.h +++ b/muse/muse/mididev.h @@ -14,6 +14,11 @@  #include "mpevent.h"  //#include "sync.h" +#include "route.h" +#include "globaldefs.h" + +//class RouteList; +class Xml;  //---------------------------------------------------------  //   MidiDevice @@ -26,8 +31,10 @@ class MidiDevice {        ///MREventList _recordEvents;        ///MREventList _recordEvents2; -      // Used for multiple reads of fifo during process. -      int _tmpRecordCount; +      // Used for multiple reads of fifos during process. +      //int _tmpRecordCount; +      int _tmpRecordCount[MIDI_CHANNELS + 1]; +      bool _sysexFIFOProcessed;        ///bool _recBufFlipped;        // Holds sync settings and detection monitors. @@ -40,22 +47,43 @@ class MidiDevice {        int _openFlags;    // configured open flags        bool _readEnable;  // set when opened/closed.        bool _writeEnable; // +      //int _sysexWriteChunk; +      //int _sysexReadChunk; +      //bool _sysexWritingChunks; +      bool _sysexReadingChunks; +              // Recording fifo.  -      MidiFifo _recordFifo; +      //MidiFifo _recordFifo; +      // Recording fifos. To speed up processing, one per channel plus one special system 'channel' for channel-less events like sysex. +      MidiFifo _recordFifo[MIDI_CHANNELS + 1]; +       +      RouteList _inRoutes, _outRoutes; +              void init();        virtual bool putMidiEvent(const MidiPlayEvent&) = 0;     public: +      enum { ALSA_MIDI=0, JACK_MIDI=1, SYNTH_MIDI=2 }; +              MidiDevice();        MidiDevice(const QString& name);        virtual ~MidiDevice() {} +      virtual int deviceType() = 0; +       +      virtual void* clientPort() { return 0; }        virtual QString open() = 0;        virtual void close() = 0; +      virtual void writeRouting(int, Xml&) const {  }; +      RouteList* inRoutes()   { return &_inRoutes; } +      RouteList* outRoutes()   { return &_outRoutes; } +      bool noInRoute() const   { return _inRoutes.empty();  } +      bool noOutRoute() const  { return _outRoutes.empty(); } +              const QString& name() const      { return _name; }        void setName(const QString& s)   { _name = s; } - +              int midiPort() const             { return _port; }        void setPort(int p)              { _port = p; } @@ -76,6 +104,10 @@ class MidiDevice {        virtual void recordEvent(MidiRecordEvent&);        virtual bool putEvent(const MidiPlayEvent&); +       +      // For Jack-based devices - called in Jack audio process callback +      virtual void collectMidiEvents() {}    +      virtual void processMidi() {}        MPEventList* stuckNotes()          { return &_stuckNotes; }        MPEventList* playEvents()          { return &_playEvents; } @@ -85,8 +117,16 @@ class MidiDevice {        ///bool recBufFlipped()               { return _recBufFlipped; }        void beforeProcess();        void afterProcess(); -      int tmpRecordCount() { return _tmpRecordCount; } -      MidiFifo& recordEvents() { return _recordFifo; } +      //int tmpRecordCount() { return _tmpRecordCount; } +      int tmpRecordCount(const unsigned int ch)     { return _tmpRecordCount[ch]; } +      //MidiFifo& recordEvents() { return _recordFifo; } +      MidiFifo& recordEvents(const unsigned int ch) { return _recordFifo[ch]; } +      bool sysexFIFOProcessed()                     { return _sysexFIFOProcessed; } +      void setSysexFIFOProcessed(bool v)            { _sysexFIFOProcessed = v; } +      //bool sysexWritingChunks() { return _sysexWritingChunks; } +      //void setSysexWritingChunks(bool v) { _sysexWritingChunks = v; } +      bool sysexReadingChunks() { return _sysexReadingChunks; } +      void setSysexReadingChunks(bool v) { _sysexReadingChunks = v; }        //virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MPEventList* /*dst*/);        iMPEvent nextPlayEvent()           { return _nextPlayEvent; } @@ -100,13 +140,14 @@ class MidiDevice {  typedef std::list<MidiDevice*>::iterator iMidiDevice; -class MidiDeviceList : public std::list<MidiDevice*> { +class MidiDeviceList : public std::list<MidiDevice*>  +{     public:        void add(MidiDevice* dev);        void remove(MidiDevice* dev); -      MidiDevice* find(const QString& name); +      MidiDevice* find(const QString& name, int typeHint = -1);        iMidiDevice find(const MidiDevice* dev); -      }; +};  extern MidiDeviceList midiDevices;  extern void initMidiDevices(); diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp index bd079c5a..e5692a6a 100644 --- a/muse/muse/midiseq.cpp +++ b/muse/muse/midiseq.cpp @@ -685,10 +685,11 @@ void MidiSeq::processTimerTick()        for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {              MidiDevice* md = *id;              // Is it a Jack midi device? p3.3.36  -            MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); -            if(mjd) +            //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); +            //if(mjd) +            if(md->deviceType() == MidiDevice::JACK_MIDI)                continue; -            if (md->isSynti())      // syntis are handled by audio thread +            if(md->isSynti())      // syntis are handled by audio thread                    continue;              int port = md->midiPort();              MidiPort* mp = port != -1 ? &midiPorts[port] : 0; diff --git a/muse/muse/mixer/astrip.cpp b/muse/muse/mixer/astrip.cpp index 6a31bc82..da06ad63 100644 --- a/muse/muse/mixer/astrip.cpp +++ b/muse/muse/mixer/astrip.cpp @@ -21,6 +21,7 @@  #include <qcursor.h>  #include <qmenudata.h>  #include <qpainter.h> +#include <qstring.h>  #include "globals.h"  #include "audio.h" @@ -122,9 +123,6 @@ void AudioStrip::heartBeat()  void AudioStrip::configChanged()      {  -  // Added by Tim. p3.3.6 -  //printf("AudioStrip::configChanged\n"); -          songChanged(SC_CONFIG);   } @@ -962,137 +960,1399 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)        }  //--------------------------------------------------------- +//   addMenuItem +//--------------------------------------------------------- + +static int addMenuItem(QButton* /*parent*/, AudioTrack* track, Track* route_track, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput) +{ +  // totalInChannels is only used by syntis. +  //int channels = (!isOutput || route_track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)route_track)->totalOutChannels() : ((AudioTrack*)route_track)->totalInChannels(); +  //int channels = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels(); +  int toch = ((AudioTrack*)track)->totalOutChannels(); +  // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. +  if(track->channels() == 1) +    toch = 1; +   +  // totalInChannels is only used by syntis. +  int chans = (isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels(); +   +  // Don't add the last stray mono route if the track is stereo. +  //if(route_track->channels() > 1 && (channel+1 == chans)) +  //  return id; +     +  RouteList* rl = isOutput ? track->outRoutes() : track->inRoutes(); +   +  QString s(route_track->name()); +  //int trackchans = track->channels(); +  //QString ns; +   +  //if(track->channels() > 1 && (channel+1 < channels)) +  //if(track->channels() > 1) +  //if(route_track->type() == Track::AUDIO_SOFTSYNTH && channels > 2 && track->channels() > 1) +  ///if(track->type() == Track::AUDIO_SOFTSYNTH && chans > 2 && route_track->channels() > 1) +  ///  s += QString(" < [%1,%2]").arg(channel+1).arg(channel+2); +   +  //int it = lb->insertItem(s); +  lb->insertItem(s, id); +   +  int ach = channel; +  int bch = -1; +   +  Route r(route_track, isOutput ? ach : bch, channels); +  //Route r(route_track, channel); +   +  r.remoteChannel = isOutput ? bch : ach; +   +  mm.insert( pRouteMenuMap(id, r) ); +   +  for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +  { +    //if (ir->type == 0 && ir->track == track) { +    //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channels == channels)  +    //if(ir->type == Route::TRACK_ROUTE && ir->track == track &&  +    //   (channel != -1 && ir->channel == channel) && (channels != -1 && ir->channels == channels))  +    //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel)  +    //printf("addMenuItem: ir->type:%d ir->track:%s track:%s ir->channel:%d channel:%d ir->channels:%d channels:%d\n", +    //       ir->type, ir->track->name().latin1(), track->name().latin1(), ir->channel, channel, ir->channels, channels); +    //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == channel && ir->remoteChannel == r.remoteChannel)  +    //if(*ir == r) +    //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == channel && ir->channels == channels && ir->remoteChannel == r.remoteChannel)  +     +    if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->remoteChannel == r.remoteChannel) +    { +      int tcompch = r.channel; +      if(tcompch == -1) +        tcompch = 0; +      int tcompchs = r.channels; +      if(tcompchs == -1) +        tcompchs = isOutput ? track->channels() : route_track->channels(); +       +      int compch = ir->channel; +      if(compch == -1) +        compch = 0; +      int compchs = ir->channels; +      if(compchs == -1) +        compchs = isOutput ? track->channels() : ir->track->channels(); +       +      //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == r.channel && ir->channels == r.channels && ir->remoteChannel == r.remoteChannel)  +      if(compch == tcompch && compchs == tcompchs)  +      { +        //lb->setItemChecked(it, true); +        lb->setItemChecked(id, true); +        break; +      } +    }   +  } +  return ++id;       +} + +//---------------------------------------------------------  //   addAuxPorts  //--------------------------------------------------------- -static void addAuxPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addAuxPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addAuxPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)        {        AuxList* al = song->auxs();        for (iAudioAux i = al->begin(); i != al->end(); ++i) {              Track* track = *i;              if (t == track)                    continue; +            id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */       +                          } +      return id;              }  //---------------------------------------------------------  //   addInPorts  //--------------------------------------------------------- -static void addInPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addInPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addInPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)        {        InputList* al = song->inputs();        for (iAudioInput i = al->begin(); i != al->end(); ++i) {              Track* track = *i;              if (t == track)                    continue; +            id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */ +                          } +      return id;              }  //---------------------------------------------------------  //   addOutPorts  //--------------------------------------------------------- -static void addOutPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addOutPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addOutPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)        {        OutputList* al = song->outputs();        for (iAudioOutput i = al->begin(); i != al->end(); ++i) {              Track* track = *i;              if (t == track)                    continue; +            id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */ +                          } +      return id;              }  //---------------------------------------------------------  //   addGroupPorts  //--------------------------------------------------------- -static void addGroupPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addGroupPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addGroupPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)        {        GroupList* al = song->groups();        for (iAudioGroup i = al->begin(); i != al->end(); ++i) {              Track* track = *i;              if (t == track)                    continue; +            id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */ +                          } +      return id;              }  //---------------------------------------------------------  //   addWavePorts  //--------------------------------------------------------- -static void addWavePorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addWavePorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addWavePorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)        {        WaveTrackList* al = song->waves();        for (iWaveTrack i = al->begin(); i != al->end(); ++i) {              Track* track = *i;              if (t == track)                    continue; +            id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */ +                          } +      return id;              }  //---------------------------------------------------------  //   addSyntiPorts  //--------------------------------------------------------- -static void addSyntiPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +//static void addSyntiPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r) +static int addSyntiPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput) +{ +      RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); +       +      SynthIList* al = song->syntis(); +      for (iSynthI i = al->begin(); i != al->end(); ++i)  +      { +            Track* track = *i; +            if (t == track) +                  continue; +            //id = addMenuItem(parent, track, lb, r, id, mm, channel, channels); +             +            /* +            QString s(track->name()); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id); +            for (iRoute ir = r->begin(); ir != r->end(); ++ir) { +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true); +                        break; +                        } +                  } +            ++id;       +            */ +             +            //SynthI* synti = (SynthI*)track; +             +            int toch = ((AudioTrack*)track)->totalOutChannels(); +            // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. +            if(track->channels() == 1) +              toch = 1; +             +            //int chans = synti->totalOutChannels(); +            //int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels(); +            // totalInChannels is only used by syntis. +            int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels(); +             +            //int schans = synti->channels(); +            //if(schans < chans) +            //  chans = schans; +            int tchans = (channels != -1) ? channels: t->channels(); +            if(tchans == 2) +            { +              // Ignore odd numbered left-over mono channel. +              //chans = chans & ~1; +              //if(chans != 0) +                chans -= 1; +            } +             +            if(chans > 0) +            { +              QPopupMenu* chpup = new QPopupMenu(parent); +              chpup->setCheckable(true); +              for(int ch = 0; ch < chans; ++ch) +              { +                char buffer[128]; +                if(tchans == 2) +                  snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2); +                else   +                  snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1); +                chpup->insertItem(QString(buffer), id); +                 +                int ach = (channel == -1) ? ch : channel; +                int bch = (channel == -1) ? -1 : ch; +                 +                Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans); +                //Route rt(track, ch); +                //rt.remoteChannel = -1; +                rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach; +                 +                mm.insert( pRouteMenuMap(id, rt) ); +                 +                for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +                { +                  //if (ir->type == 0 && ir->track == track) { +                  //if(ir->type == 0 && ir->track == track && ir->channels == channels)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&  +                  //   ir->channels == channels && ir->remoteChannel == r.remoteChannel)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&  +                  //   ir->remoteChannel == rt.remoteChannel)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&  +                  //   ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)  +                   +                  if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel) +                  { +                    int tcompch = rt.channel; +                    if(tcompch == -1) +                      tcompch = 0; +                    int tcompchs = rt.channels; +                    if(tcompchs == -1) +                      tcompchs = isOutput ? t->channels() : track->channels(); +                     +                    int compch = ir->channel; +                    if(compch == -1) +                      compch = 0; +                    int compchs = ir->channels; +                    if(compchs == -1) +                      compchs = isOutput ? t->channels() : ir->track->channels(); +                     +                    if(compch == tcompch && compchs == tcompchs)  +                    { +                      chpup->setItemChecked(id, true); +                      break; +                    } +                  } +                }   +                ++id; +              } +             +              lb->insertItem(track->name(), chpup); +            } +      } +      return id;       +} + +//--------------------------------------------------------- +//   addMultiChannelOutPorts +//--------------------------------------------------------- + +static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup, int id, RouteMenuMap& mm, bool isOutput) +{ +  int toch = t->totalOutChannels(); +  // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. +  if(t->channels() == 1) +    toch = 1; +   +  // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.  +  //int chans = t->totalOutChannels();   +  // totalInChannels is only used by syntis. +  //int chans = isOutput ? t->totalOutChannels() : t->totalInChannels(); +  //int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? t->totalOutChannels() : t->totalInChannels(); +  int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? toch : t->totalInChannels(); + +  // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. +  //if(t->channels() == 1) +  //  chans = 1; +   +  if(chans > 1) +  { +    pup->insertItem(new MenuTitleItem("<Mono>")); +    //pup->insertSeparator(); +  } +   +  // +  // If it's more than one channel, create a sub-menu. If it's just one channel, don't bother with a sub-menu... +  // + +  QPopupMenu* chpup = pup; +   +  for(int ch = 0; ch < chans; ++ch) +  { +    // If more than one channel, create the sub-menu. +    if(chans > 1) +    { +      chpup = new QPopupMenu(parent); +      chpup->setCheckable(true); +    } +     +    if(isOutput) +    { +      switch(t->type())  +      { +         +        case Track::AUDIO_INPUT: +              id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput); +        case Track::WAVE: +        case Track::AUDIO_GROUP: +        case Track::AUDIO_SOFTSYNTH: +              id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              break; +        case Track::AUDIO_AUX: +              id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              break; +        default: +              break; +         +        /* +        case Track::AUDIO_INPUT: +               id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput); +        case Track::WAVE: +        case Track::AUDIO_GROUP: +        case Track::AUDIO_SOFTSYNTH: +              id = addOutPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput); +              break; +        case Track::AUDIO_AUX: +              id = addOutPorts(parent, t, chpup, id, mm, ch, isOutput); +              break; +        default: +              break; +        */       +      } +    } +    else +    { +      switch(t->type())  +      { +         +        case Track::AUDIO_OUTPUT: +              id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addAuxPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              break; +        case Track::WAVE: +              id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              break; +        case Track::AUDIO_SOFTSYNTH: +        case Track::AUDIO_GROUP: +              id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput); +              break; +        default: +              break; +         +        /* +        case Track::AUDIO_OUTPUT: +              id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addInPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addAuxPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput); +              break; +        case Track::WAVE: +              id = addInPorts(parent, t, chpup, id, mm, ch, isOutput); +              break; +        case Track::AUDIO_SOFTSYNTH: +        case Track::AUDIO_GROUP: +              id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addInPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput); +              id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput); +              break; +        default: +              break; +       */        +      } +    } +       +    // If more than one channel, add the created sub-menu. +    if(chans > 1) +    { +      char buffer[128]; +      snprintf(buffer, 128, "%s %d", pup->tr("Channel").latin1(), ch+1); +      pup->insertItem(QString(buffer), chpup); +    }   +  }  +        +  // For stereo listing, ignore odd numbered left-over channels. +  chans -= 1; +  if(chans > 0) +  { +    // Ignore odd numbered left-over channels. +    //int schans = (chans & ~1) - 1; +     +    pup->insertSeparator(); +    pup->insertItem(new MenuTitleItem("<Stereo>")); +    //pup->insertSeparator(); +   +    // +    // If it's more than two channels, create a sub-menu. If it's just two channels, don't bother with a sub-menu... +    // +     +    //QPopupMenu* chpup = pup; +    chpup = pup; +    if(chans <= 2) +      // Just do one iteration. +      chans = 1; +     +    //for(int ch = 0; ch < schans; ++ch) +    for(int ch = 0; ch < chans; ++ch) +    { +      // If more than two channels, create the sub-menu. +      if(chans > 2)        { +        chpup = new QPopupMenu(parent); +        chpup->setCheckable(true); +      } +       +      if(isOutput) +      { +        switch(t->type())  +        { +          case Track::AUDIO_INPUT: +                id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput); +          case Track::WAVE: +          case Track::AUDIO_GROUP: +          case Track::AUDIO_SOFTSYNTH: +                id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                break; +          case Track::AUDIO_AUX: +                id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                break; +          default: +                break; +        } +      }     +      else +      { +        switch(t->type())  +        { +          case Track::AUDIO_OUTPUT: +                id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addAuxPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                break; +          case Track::WAVE: +                id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                break; +          case Track::AUDIO_SOFTSYNTH: +          case Track::AUDIO_GROUP: +                id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput); +                break; +          default: +                break; +        } +      } +       +      // If more than two channels, add the created sub-menu. +      if(chans > 2) +      { +        char buffer[128]; +        snprintf(buffer, 128, "%s %d,%d", pup->tr("Channel").latin1(), ch+1, ch+2); +        pup->insertItem(QString(buffer), chpup); +      }   +    }  +  } +   +  return id; +} + +//--------------------------------------------------------- +//   nonSyntiTrackAddSyntis +//--------------------------------------------------------- + +//static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput) +static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, bool isOutput) +{ +      RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); +              SynthIList* al = song->syntis(); -      for (iSynthI i = al->begin(); i != al->end(); ++i) { +      for (iSynthI i = al->begin(); i != al->end(); ++i)  +      {              Track* track = *i;              if (t == track)                    continue; +            //id = addMenuItem(parent, track, lb, r, id, mm, channel, channels); +             +            /*              QString s(track->name()); -            int it = lb->insertItem(s); +            //int it = lb->insertItem(s); +            lb->insertItem(s, id);              for (iRoute ir = r->begin(); ir != r->end(); ++ir) { -                  if (ir->type == 0 && ir->track == track) { -                        lb->setItemChecked(it, true); +                  //if (ir->type == 0 && ir->track == track) { +                  if (ir->type == 0 && ir->track == track && ir->channels == channels) { +                        //lb->setItemChecked(it, true); +                        lb->setItemChecked(id, true);                          break;                          }                    } +            ++id;       +            */ +             +            //SynthI* synti = (SynthI*)track; +             +            int toch = ((AudioTrack*)track)->totalOutChannels(); +            // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. +            if(track->channels() == 1) +              toch = 1; +             +            //int chans = synti->totalOutChannels(); +            //int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels(); +            // totalInChannels is only used by syntis. +            int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels(); +             +            //int schans = synti->channels(); +            //if(schans < chans) +            //  chans = schans; +//            int tchans = (channels != -1) ? channels: t->channels(); +//            if(tchans == 2) +//            { +              // Ignore odd numbered left-over mono channel. +              //chans = chans & ~1; +              //if(chans != 0) +//                chans -= 1; +//            } +            //int tchans = (channels != -1) ? channels: t->channels(); +             +            if(chans > 0) +            { +              QPopupMenu* chpup = new QPopupMenu(parent); +              chpup->setCheckable(true); +               +              if(chans > 1) +              { +                chpup->insertItem(new MenuTitleItem("<Mono>")); +                //pup->insertSeparator(); +              } +               +              for(int ch = 0; ch < chans; ++ch) +              { +                char buffer[128]; +                //if(tchans == 2) +                //  snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2); +                //else   +                  snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1); +                chpup->insertItem(QString(buffer), id); +                 +                //int ach = (channel == -1) ? ch : channel; +                //int bch = (channel == -1) ? -1 : ch; +                int ach = ch; +                int bch = -1; +                 +                //Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans); +                Route rt(track, isOutput ? bch : ach, 1); +                //Route rt(track, ch); +                 +                //rt.remoteChannel = -1; +                //rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach; +                rt.remoteChannel = isOutput ? ach : bch; +                 +                mm.insert( pRouteMenuMap(id, rt) ); +                 +                for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +                { +                  //if (ir->type == 0 && ir->track == track) { +                  //if(ir->type == 0 && ir->track == track && ir->channels == channels)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&  +                  //   ir->channels == channels && ir->remoteChannel == r.remoteChannel)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&  +                  //   ir->remoteChannel == rt.remoteChannel)  +                  //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&  +                  //   ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)  +                   +                  if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel) +                  { +                    int tcompch = rt.channel; +                    if(tcompch == -1) +                      tcompch = 0; +                    int tcompchs = rt.channels; +                    if(tcompchs == -1) +                      tcompchs = isOutput ? t->channels() : track->channels(); +                     +                    int compch = ir->channel; +                    if(compch == -1) +                      compch = 0; +                    int compchs = ir->channels; +                    if(compchs == -1) +                      compchs = isOutput ? t->channels() : ir->track->channels(); +                     +                    if(compch == tcompch && compchs == tcompchs)  +                    { +                      chpup->setItemChecked(id, true); +                      break; +                    } +                  } +                } +                ++id; +              } +             +              chans -= 1; +              if(chans > 0) +              { +                // Ignore odd numbered left-over channels. +                //int schans = (chans & ~1) - 1; +                 +                chpup->insertSeparator(); +                chpup->insertItem(new MenuTitleItem("<Stereo>")); +                //pup->insertSeparator(); +               +                for(int ch = 0; ch < chans; ++ch) +                { +                  char buffer[128]; +                  //if(tchans == 2) +                    snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2); +                  //else   +                  //  snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1); +                  chpup->insertItem(QString(buffer), id); +                   +                  //int ach = (channel == -1) ? ch : channel; +                  //int bch = (channel == -1) ? -1 : ch; +                  int ach = ch; +                  int bch = -1; +                   +                  //Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans); +                  Route rt(track, isOutput ? bch : ach, 2); +                  //Route rt(track, ch); +                   +                  //rt.remoteChannel = -1; +                  //rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach; +                  rt.remoteChannel = isOutput ? ach : bch; +                   +                  mm.insert( pRouteMenuMap(id, rt) ); +                   +                  for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +                  { +                    //if (ir->type == 0 && ir->track == track) { +                    //if(ir->type == 0 && ir->track == track && ir->channels == channels)  +                    //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&  +                    //   ir->channels == channels && ir->remoteChannel == r.remoteChannel)  +                    //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&  +                    //   ir->remoteChannel == rt.remoteChannel)  +                    //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&  +                    //  ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)  +                     +                     +                    if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel) +                    { +                      int tcompch = rt.channel; +                      if(tcompch == -1) +                        tcompch = 0; +                      int tcompchs = rt.channels; +                      if(tcompchs == -1) +                        tcompchs = isOutput ? t->channels() : track->channels(); +                       +                      int compch = ir->channel; +                      if(compch == -1) +                        compch = 0; +                      int compchs = ir->channels; +                      if(compchs == -1) +                        compchs = isOutput ? t->channels() : ir->track->channels(); +                       +                      if(compch == tcompch && compchs == tcompchs)  +                      { +                        chpup->setItemChecked(id, true); +                        break; +                      } +                    }   +                  } +                  ++id; +                } +              } +               +              lb->insertItem(track->name(), chpup); +            } +      } +      return id;       +} + +//--------------------------------------------------------- +//   iRoutePressed +//--------------------------------------------------------- + +void AudioStrip::iRoutePressed() +      { +      //if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH)) +      if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX)) +        return; +         +      QPopupMenu* pup = new QPopupMenu(iR); +      //pup->setCheckable(true); +      AudioTrack* t = (AudioTrack*)track; +      RouteList* irl = t->inRoutes(); + +      int gid = 0; +      RouteMenuMap mm; +       +      switch(track->type())  +      { +        case Track::AUDIO_INPUT: +        { +          pup->setCheckable(true); +          //int gid = 0; +          for(int i = 0; i < channel; ++i)  +          { +            char buffer[128]; +            snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +            MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +            pup->insertItem(titel); +   +            if(!checkAudioDevice()) +            {  +              delete pup; +              return; +            } +            std::list<QString> ol = audioDevice->outputPorts(); +            for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)  +            { +              int id = pup->insertItem(*ip, (gid * 16) + i); +              //Route dst(*ip, true, i); +              Route dst(*ip, true, i, Route::JACK_ROUTE); +              ++gid; +              for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)  +              { +                if(*ir == dst)  +                { +                  pup->setItemChecked(id, true); +                  break; +                } +              } +            } +            if(i+1 != channel) +              pup->insertSeparator(); +          } +        } +        break; +        /* +        case Track::AUDIO_OUTPUT: +        case Track::WAVE: +        case Track::AUDIO_GROUP: +        */ +         +        case Track::AUDIO_OUTPUT: +              gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false); +              gid = addInPorts(   iR, t, pup, gid, mm, -1, -1, false); +              gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false); +              gid = addAuxPorts(  iR, t, pup, gid, mm, -1, -1, false); +              //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false); +              gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false); +              break; +        case Track::WAVE: +              gid = addInPorts(   iR, t, pup, gid, mm, -1, -1, false); +              break; +        case Track::AUDIO_GROUP: +              gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false); +              gid = addInPorts(   iR, t, pup, gid, mm, -1, -1, false); +              gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false); +              //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false); +              gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false); +              break; +         +        case Track::AUDIO_SOFTSYNTH: +              gid = addMultiChannelPorts(iR, t, pup, gid, mm, false); +              break; +        default: +              delete pup; +              return; +      }   +       +      if(pup->count() == 0) +      { +        delete pup; +        return; +      } +       +      int n = pup->exec(QCursor::pos()); +      if(n != -1)  +      { +            QString s(pup->text(n)); +             +            if(track->type() == Track::AUDIO_INPUT) +            { +              delete pup; +              int chan = n & 0xf; +               +              Route srcRoute(s, false, -1, Route::JACK_ROUTE); +              Route dstRoute(t, chan); +               +              srcRoute.channel = chan; +               +              iRoute iir = irl->begin(); +              for(; iir != irl->end(); ++iir)  +              { +                if(*iir == srcRoute) +                  break; +              } +              if(iir != irl->end())  +                // disconnect +                audio->msgRemoveRoute(srcRoute, dstRoute); +              else  +                // connect +                audio->msgAddRoute(srcRoute, dstRoute); +               +              audio->msgUpdateSoloStates(); +              song->update(SC_ROUTE); +              iR->setDown(false);     // pup->exec() catches mouse release event +              return; +            } +             +            iRouteMenuMap imm = mm.find(n); +            if(imm == mm.end()) +            {   +              delete pup; +              iR->setDown(false);     // pup->exec() catches mouse release event +              return; +            }   +             +            //int chan = n >> 16; +            //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo. +            //chan &= 0xffff; +            //int chan = imm->second.channel; +            //int chans = imm->second.channels;  +             +            //Route srcRoute(s, false, -1); +            //Route srcRoute(s, false, -1, Route::TRACK_ROUTE); +            Route &srcRoute = imm->second; +             +            //Route dstRoute(t, -1); +            //Route dstRoute(t, chan, chans); +            Route dstRoute(t, imm->second.channel, imm->second.channels); +            //Route dstRoute(t, imm->second.channel); +            dstRoute.remoteChannel = imm->second.remoteChannel; + +            iRoute iir = irl->begin(); +            for (; iir != irl->end(); ++iir) { +                  if (*iir == srcRoute) +                        break; +                  } +            if (iir != irl->end()) { +                  // disconnect +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            audio->msgUpdateSoloStates(); +            song->update(SC_ROUTE); +            } +      delete pup; +      iR->setDown(false);     // pup->exec() catches mouse release event +      } + +//--------------------------------------------------------- +//   oRoutePressed +//--------------------------------------------------------- + +void AudioStrip::oRoutePressed() +{ +      if(track->isMidiTrack()) +        return; +         +      QPopupMenu* pup = new QPopupMenu(oR); +      //pup->setCheckable(true); +      AudioTrack* t = (AudioTrack*)track; +      RouteList* orl = t->outRoutes(); + +      int gid = 0; +      RouteMenuMap mm; +       +      switch(track->type())  +      { +        case Track::AUDIO_OUTPUT: +        { +          pup->setCheckable(true); +          //int gid = 0; +          for(int i = 0; i < channel; ++i)  +          { +            char buffer[128]; +            snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +            MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +            pup->insertItem(titel); +   +            if(!checkAudioDevice()) +            {  +              delete pup; +              return; +            } +            std::list<QString> ol = audioDevice->inputPorts(); +            for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)  +            { +              int id = pup->insertItem(*ip, (gid * 16) + i); +              //Route dst(*ip, true, i); +              Route dst(*ip, true, i, Route::JACK_ROUTE); +              ++gid; +              for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)  +              { +                if(*ir == dst)  +                { +                  pup->setItemChecked(id, true); +                  break; +                } +              } +            } +            if(i+1 != channel) +              pup->insertSeparator(); +          }       +        } +        break; +        /* +        case Track::AUDIO_INPUT: +        case Track::WAVE: +        case Track::AUDIO_GROUP: +        case Track::AUDIO_AUX: +        */ +         +        case Track::AUDIO_SOFTSYNTH: +              //addOutPorts(t, pup, orl); +              //addGroupPorts(t, pup, orl); +              gid = addMultiChannelPorts(oR, t, pup, gid, mm, true); +        break; +         +        case Track::AUDIO_INPUT: +              gid = addWavePorts(        oR, t, pup, gid, mm, -1, -1, true); +        case Track::WAVE: +        case Track::AUDIO_GROUP: +        //case Track::AUDIO_SOFTSYNTH: +              gid = addOutPorts(         oR, t, pup, gid, mm, -1, -1, true); +              gid = addGroupPorts(       oR, t, pup, gid, mm, -1, -1, true); +              //gid = addSyntiPorts(       oR, t, pup, gid, mm, -1, -1, true); +              gid = nonSyntiTrackAddSyntis(oR, t, pup, gid, mm, true); +        break; +        case Track::AUDIO_AUX: +              gid = addOutPorts(         oR, t, pup, gid, mm, -1, -1, true); +        break; +         +        default: +              delete pup; +              return; +      } +       +      if(pup->count() == 0) +      { +        delete pup; +        return; +      } +       +      int n = pup->exec(QCursor::pos()); +      if (n != -1) { +            QString s(pup->text(n)); +             +            if(track->type() == Track::AUDIO_OUTPUT) +            { +              delete pup; +              int chan = n & 0xf; +               +              //Route srcRoute(t, -1); +              //Route srcRoute(t, chan, chans); +              //Route srcRoute(t, chan, 1); +              Route srcRoute(t, chan); +               +              //Route dstRoute(s, true, -1); +              Route dstRoute(s, true, -1, Route::JACK_ROUTE); +              //Route dstRoute(s, true, 0, Route::JACK_ROUTE); +   +              //srcRoute.channel = dstRoute.channel = chan; +              dstRoute.channel = chan; +              //dstRoute.channels = 1; +   +              // check if route src->dst exists: +              iRoute iorl = orl->begin(); +              for (; iorl != orl->end(); ++iorl) { +                    if (*iorl == dstRoute) +                          break; +                    } +              if (iorl != orl->end()) { +                    // disconnect if route exists +                    audio->msgRemoveRoute(srcRoute, dstRoute); +                    } +              else { +                    // connect if route does not exist +                    audio->msgAddRoute(srcRoute, dstRoute); +                    } +              audio->msgUpdateSoloStates(); +              song->update(SC_ROUTE); +              oR->setDown(false);     // pup->exec() catches mouse release event +              return; +            } +             +            iRouteMenuMap imm = mm.find(n); +            if(imm == mm.end()) +            {   +              delete pup; +              oR->setDown(false);     // pup->exec() catches mouse release event +              return; +            }   +             +            //int chan = n >> 16; +            //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo. +            //chan &= 0xffff; +            //int chan = imm->second.channel; +            //int chans = imm->second.channels;  +             +            //Route srcRoute(t, -1); +            //srcRoute.remoteChannel = chan; +            //Route srcRoute(t, chan, chans); +            Route srcRoute(t, imm->second.channel, imm->second.channels); +            //Route srcRoute(t, imm->second.channel); +            srcRoute.remoteChannel = imm->second.remoteChannel; +             +            //Route dstRoute(s, true, -1); +            //Route dstRoute(s, true, -1, Route::TRACK_ROUTE); +            Route &dstRoute = imm->second; + +            // check if route src->dst exists: +            iRoute iorl = orl->begin(); +            for (; iorl != orl->end(); ++iorl) { +                  if (*iorl == dstRoute) +                        break; +                  } +            if (iorl != orl->end()) { +                  // disconnect if route exists +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect if route does not exist +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            audio->msgUpdateSoloStates(); +            song->update(SC_ROUTE); +            } +      delete pup; +      oR->setDown(false);     // pup->exec() catches mouse release event +} + +/* +//--------------------------------------------------------- +//   iRoutePressed +//--------------------------------------------------------- + +void AudioStrip::iRoutePressed() +      { +      if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH)) +        return; +         +      QPopupMenu* pup = new QPopupMenu(iR); +      //pup->setCheckable(true); +      AudioTrack* t = (AudioTrack*)track; +      RouteList* irl = t->inRoutes(); + +      RouteMenuMap mm; +       +      if(track->type() == Track::AUDIO_INPUT) +      { +        pup->setCheckable(true); +        int gid = 0; +        for(int i = 0; i < channel; ++i)  +        { +          char buffer[128]; +          snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +          MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +          pup->insertItem(titel); + +          if(!checkAudioDevice()) +          {  +            delete pup; +            return; +          } +          std::list<QString> ol = audioDevice->outputPorts(); +          for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)  +          { +            int id = pup->insertItem(*ip, (gid * 16) + i); +            //Route dst(*ip, true, i); +            Route dst(*ip, true, i, Route::JACK_ROUTE); +            ++gid; +            for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)  +            { +              if(*ir == dst)  +              { +                pup->setItemChecked(id, true); +                break; +              }              } +          } +          if(i+1 != channel) +            pup->insertSeparator(); +        }        } +      else +        addMultiChannelOutPorts(iR, t, pup, irl, mm, false); +       +      int n = pup->exec(QCursor::pos()); +      if (n != -1) { +            QString s(pup->text(n)); +             +            //Route srcRoute(s, false, -1); +            Route srcRoute(s, false, -1, (track->type() == Track::AUDIO_INPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE); +            Route dstRoute(t, -1); + +            if (track->type() == Track::AUDIO_INPUT) +                  srcRoute.channel = dstRoute.channel = n & 0xf; +            iRoute iir = irl->begin(); +            for (; iir != irl->end(); ++iir) { +                  if (*iir == srcRoute) +                        break; +                  } +            if (iir != irl->end()) { +                  // disconnect +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            audio->msgUpdateSoloStates(); +            song->update(SC_ROUTE); +            } +      delete pup; +      iR->setDown(false);     // pup->exec() catches mouse release event +      } +*/ +/* +//--------------------------------------------------------- +//   oRoutePressed +//--------------------------------------------------------- + +void AudioStrip::oRoutePressed() +{ +      if(track->isMidiTrack()) +        return; +         +      QPopupMenu* pup = new QPopupMenu(oR); +      //pup->setCheckable(true); +      AudioTrack* t = (AudioTrack*)track; +      RouteList* orl = t->outRoutes(); + +      RouteMenuMap mm; +       +      if(track->type() == Track::AUDIO_OUTPUT) +      { +        pup->setCheckable(true); +        int gid = 0; +        for(int i = 0; i < channel; ++i)  +        { +          char buffer[128]; +          snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +          MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +          pup->insertItem(titel); + +          if(!checkAudioDevice()) +          {  +            delete pup; +            return; +          } +          std::list<QString> ol = audioDevice->inputPorts(); +          for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)  +          { +            int id = pup->insertItem(*ip, (gid * 16) + i); +            //Route dst(*ip, true, i); +            Route dst(*ip, true, i, Route::JACK_ROUTE); +            ++gid; +            for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)  +            { +              if(*ir == dst)  +              { +                pup->setItemChecked(id, true); +                break; +              } +            } +          } +          if(i+1 != channel) +            pup->insertSeparator(); +        }       +      } +      else +        addMultiChannelOutPorts(oR, t, pup, orl, mm, true); +       +      int n = pup->exec(QCursor::pos()); +      if (n != -1) { +            QString s(pup->text(n)); +             +            if(track->type() == Track::AUDIO_OUTPUT) +            { +              delete pup; +              int chan = n & 0xf; +               +              //Route srcRoute(t, -1); +              //Route srcRoute(t, chan, chans); +              Route srcRoute(t, chan, 1); +               +              //Route dstRoute(s, true, -1); +              Route dstRoute(s, true, -1, Route::JACK_ROUTE); +              //Route dstRoute(s, true, 0, Route::JACK_ROUTE); +   +              //srcRoute.channel = dstRoute.channel = chan; +              dstRoute.channel = chan; +              dstRoute.channels = 1; +   +              // check if route src->dst exists: +              iRoute iorl = orl->begin(); +              for (; iorl != orl->end(); ++iorl) { +                    if (*iorl == dstRoute) +                          break; +                    } +              if (iorl != orl->end()) { +                    // disconnect if route exists +                    audio->msgRemoveRoute(srcRoute, dstRoute); +                    } +              else { +                    // connect if route does not exist +                    audio->msgAddRoute(srcRoute, dstRoute); +                    } +              audio->msgUpdateSoloStates(); +              song->update(SC_ROUTE); +              oR->setDown(false);     // pup->exec() catches mouse release event +              return; +            } +             +            iRouteMenuMap imm = mm.find(n); +            if(imm == mm.end()) +            {   +              delete pup; +              oR->setDown(false);     // pup->exec() catches mouse release event +              return; +            }   +             +            //int chan = n >> 16; +            //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo. +            //chan &= 0xffff; +            int chan = imm->second.channel; +            int chans = imm->second.channels;  +              +            //Route srcRoute(t, -1); +            Route srcRoute(t, chan, chans); +             +            //Route dstRoute(s, true, -1); +            Route dstRoute(s, true, -1, Route::TRACK_ROUTE); + +            // check if route src->dst exists: +            iRoute iorl = orl->begin(); +            for (; iorl != orl->end(); ++iorl) { +                  if (*iorl == dstRoute) +                        break; +                  } +            if (iorl != orl->end()) { +                  // disconnect if route exists +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect if route does not exist +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            audio->msgUpdateSoloStates(); +            song->update(SC_ROUTE); +            } +      delete pup; +      oR->setDown(false);     // pup->exec() catches mouse release event +} +*/ + +/*  //---------------------------------------------------------  //   iRoutePressed  //--------------------------------------------------------- @@ -1124,7 +2384,8 @@ void AudioStrip::iRoutePressed()                          std::list<QString> ol = audioDevice->outputPorts();                          for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {                                int id = pup->insertItem(*ip, (gid * 16) + i); -                              Route dst(*ip, true, i); +                              //Route dst(*ip, true, i); +                              Route dst(*ip, true, i, Route::JACK_ROUTE);                                ++gid;                                for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) {                                      if (*ir == dst) { @@ -1138,7 +2399,6 @@ void AudioStrip::iRoutePressed()                          }                    }                    break; -                  break;              case Track::AUDIO_OUTPUT:                    addWavePorts(t, pup, irl);                    addInPorts(t, pup, irl); @@ -1159,7 +2419,9 @@ void AudioStrip::iRoutePressed()        int n = pup->exec(QCursor::pos());        if (n != -1) {              QString s(pup->text(n)); -            Route srcRoute(s, false, -1); +             +            //Route srcRoute(s, false, -1); +            Route srcRoute(s, false, -1, (track->type() == Track::AUDIO_INPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);              Route dstRoute(t, -1);              if (track->type() == Track::AUDIO_INPUT) @@ -1183,7 +2445,9 @@ void AudioStrip::iRoutePressed()        delete pup;        iR->setDown(false);     // pup->exec() catches mouse release event        } +*/ +/*  //---------------------------------------------------------  //   oRoutePressed  //--------------------------------------------------------- @@ -1213,7 +2477,8 @@ void AudioStrip::oRoutePressed()                          std::list<QString> ol = audioDevice->inputPorts();                          for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {                                int id = pup->insertItem(*ip, (gid * 16) + i); -                              Route dst(*ip, true, i); +                              //Route dst(*ip, true, i); +                              Route dst(*ip, true, i, Route::JACK_ROUTE);                                ++gid;                                for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) {                                      if (*ir == dst) { @@ -1243,7 +2508,8 @@ void AudioStrip::oRoutePressed()        if (n != -1) {              QString s(pup->text(n));              Route srcRoute(t, -1); -            Route dstRoute(s, true, -1); +            //Route dstRoute(s, true, -1); +            Route dstRoute(s, true, -1, (track->type() == Track::AUDIO_OUTPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);              if (track->type() == Track::AUDIO_OUTPUT)                    srcRoute.channel = dstRoute.channel = n & 0xf; @@ -1268,4 +2534,4 @@ void AudioStrip::oRoutePressed()        delete pup;        oR->setDown(false);     // pup->exec() catches mouse release event        } - +*/ diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp index cd9cea86..a2cd26dd 100644 --- a/muse/muse/mixer/mstrip.cpp +++ b/muse/muse/mixer/mstrip.cpp @@ -17,11 +17,14 @@  #include <qcombobox.h>  #include <qtooltip.h>  #include <qtimer.h> +#include <qpopupmenu.h> +#include <qcursor.h>  #include <math.h>  #include "midi.h"  #include "midictrl.h"  #include "mstrip.h" +#include "midiport.h"  #include "globals.h"  #include "audio.h"  #include "song.h" @@ -343,7 +346,7 @@ MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t)        dev_ch_label->setFont(config.fonts[1]);        // Dealing with a horizontally constrained label. Ignore vertical. Use a minimum readable point size.        //autoAdjustFontSize(dev_ch_label, dev_ch_label->text(), false, true, config.fonts[6].pointSize(), 5); -      QToolTip::add(dev_ch_label, tr("output: device - channel")); +      QToolTip::add(dev_ch_label, tr("output port and channel"));        smBox1->addWidget(dev_ch_label);        smBox1->addWidget(record); @@ -351,15 +354,36 @@ MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t)        layout->addLayout(smBox2);        //--------------------------------------------------- -      //    output routing +      //    routing        //--------------------------------------------------- -      route = new QToolButton(this); -      route->setFont(config.fonts[1]); -      route->setFixedWidth(STRIP_WIDTH); -      route->setText(tr("Route")); -      QToolTip::add(route, tr("set routing")); -      layout->addWidget(route); +      // p3.3.38 +      //route = new QToolButton(this); +      //route->setFont(config.fonts[1]); +      //route->setFixedWidth(STRIP_WIDTH); +      //route->setText(tr("Route")); +      //QToolTip::add(route, tr("set routing")); +      //layout->addWidget(route); +      QHBoxLayout* rBox = new QHBoxLayout(0); +      iR = new QToolButton(this); +      iR->setFont(config.fonts[1]); +      iR->setFixedWidth((STRIP_WIDTH-4)/2); +      iR->setText(tr("iR")); +      iR->setToggleButton(false); +      QToolTip::add(iR, tr("input routing")); +      rBox->addWidget(iR); +      connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed())); +      oR = new QToolButton(this); +      oR->setFont(config.fonts[1]); +      oR->setFixedWidth((STRIP_WIDTH-4)/2); +      oR->setText(tr("oR")); +      oR->setToggleButton(false); +      // TODO: Works OK, but disabled for now, until we figure out what to do about multiple out routes and display values... +      oR->setEnabled(false); +      QToolTip::add(oR, tr("output routing")); +      rBox->addWidget(oR); +      connect(oR, SIGNAL(pressed()), SLOT(oRoutePressed())); +      layout->addLayout(rBox);        //---------------------------------------------------        //    automation mode @@ -518,6 +542,7 @@ void MidiStrip::labelDoubleClicked(int idx)  } +/*  //---------------------------------------------------------  //   routeClicked  //--------------------------------------------------------- @@ -525,6 +550,7 @@ void MidiStrip::labelDoubleClicked(int idx)  void MidiStrip::routeClicked()        {        } +*/  //---------------------------------------------------------  //   heartBeat @@ -929,3 +955,224 @@ void MidiStrip::updateOffState() // Ripped from AudioStrip, hehh(mg)        if (mute)              mute->setEnabled(val);        } + +//--------------------------------------------------------- +//   iRoutePressed +//--------------------------------------------------------- + +void MidiStrip::iRoutePressed() +{ +  if(!track->isMidiTrack()) +    return; +   +  song->chooseMidiRoutes(iR, (MidiTrack*)track, false); +   +  /* +  RouteList* irl = track->inRoutes(); +  //Route dst(track, -1); + +  QPopupMenu* pup = new QPopupMenu(iR); +  pup->setCheckable(true); +   +  int gid = 0; +   +  //MidiInPortList* tl = song->midiInPorts(); +  //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)  +  for(int i = 0; i < MIDI_PORTS; ++i) +  { +    //MidiInPort* track = *i; +    // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports. +    MidiPort* mp = &midiPorts[i]; +    MidiDevice* md = mp->device(); +    if(!md) +      continue; +     +    if(!(md->rwFlags() & 2)) +      continue; +       +    //printf("MidiStrip::iRoutePressed adding submenu portnum:%d\n", i); +     +    //QMenu* m = menu->addMenu(track->name()); +    QPopupMenu* subp = new QPopupMenu(iR); +     +    for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +    { +      //QAction* a = m->addAction(QString("Channel %1").arg(ch+1)); +      //subp->insertItem(QT_TR_NOOP(QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch); +      gid = i * MIDI_CHANNELS + ch; +       +      //printf("MidiStrip::iRoutePressed inserting gid:%d\n", gid); +       +      subp->insertItem(QString("Channel %1").arg(ch+1), gid); +      //a->setCheckable(true); +      //Route src(track, ch, RouteNode::TRACK); +      //Route src(md, ch); +      //Route r = Route(src, dst); +      //a->setData(QVariant::fromValue(r)); +      //a->setChecked(rl->indexOf(r) != -1); +      Route srcRoute(md, ch); +      for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)  +      { +        //if(*ir == dst)  +        if(*ir == srcRoute)  +        { +          subp->setItemChecked(gid, true); +          break; +        } +      } +    } +    pup->insertItem(QT_TR_NOOP(md->name()), subp); +  } +       +      int n = pup->exec(QCursor::pos()); +      delete pup; +      if (n != -1)  +      { +            int mdidx = n / MIDI_CHANNELS; +            int ch = n % MIDI_CHANNELS; +             +            //if(debugMsg) +              printf("MidiStrip::iRoutePressed mdidx:%d ch:%d\n", mdidx, ch); +               +            MidiPort* mp = &midiPorts[mdidx]; +            MidiDevice* md = mp->device(); +            if(!md) +              return; +             +            if(!(md->rwFlags() & 2)) +              return; +               +             +            //QString s(pup->text(n)); +            //QT_TR_NOOP(md->name()) +             +            //Route srcRoute(s, false, -1); +            Route srcRoute(md, ch); +            //Route srcRoute(md, -1); +            //Route dstRoute(track, -1); +            Route dstRoute(track, ch); + +            //if (track->type() == Track::AUDIO_INPUT) +            //      srcRoute.channel = dstRoute.channel = n & 0xf; +            iRoute iir = irl->begin(); +            for (; iir != irl->end(); ++iir) { +                  if (*iir == srcRoute) +                        break; +                  } +            if (iir != irl->end()) { +                  // disconnect +                  printf("MidiStrip::iRoutePressed removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1()); +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect +                  printf("MidiStrip::iRoutePressed adding route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1()); +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            printf("MidiStrip::iRoutePressed calling msgUpdateSoloStates\n"); +            audio->msgUpdateSoloStates(); +            printf("MidiStrip::iRoutePressed calling song->update\n"); +            song->update(SC_ROUTE); +      } +      //delete pup; +      iR->setDown(false);     // pup->exec() catches mouse release event +      printf("MidiStrip::iRoutePressed end\n"); +      */ +       +} + +//--------------------------------------------------------- +//   oRoutePressed +//--------------------------------------------------------- + +void MidiStrip::oRoutePressed() +      { +  if(!track->isMidiTrack()) +    return; +   +  song->chooseMidiRoutes(oR, (MidiTrack*)track, true); +       +      /* +      QPopupMenu* pup = new QPopupMenu(oR); +      pup->setCheckable(true); +      AudioTrack* t = (AudioTrack*)track; +      RouteList* orl = t->outRoutes(); + +      switch(track->type()) { +            case Track::MIDI: +            case Track::DRUM: +                  delete pup; +                  return; +            case Track::AUDIO_OUTPUT: +                  { +                  int gid = 0; +                  for (int i = 0; i < channel; ++i) { +                        char buffer[128]; +                        snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +                        MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +                        pup->insertItem(titel); + +                        if (!checkAudioDevice()) return; +                        std::list<QString> ol = audioDevice->inputPorts(); +                        for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) { +                              int id = pup->insertItem(*ip, (gid * 16) + i); +                              Route dst(*ip, true, i); +                              ++gid; +                              for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { +                                    if (*ir == dst) { +                                          pup->setItemChecked(id, true); +                                          break; +                                          } +                                    } +                              } +                        if (i+1 != channel) +                              pup->insertSeparator(); +                        } +                  } +                  break; +            case Track::AUDIO_INPUT: +                  addWavePorts(t, pup, orl); +            case Track::WAVE: +            case Track::AUDIO_GROUP: +            case Track::AUDIO_SOFTSYNTH: +                  addOutPorts(t, pup, orl); +                  addGroupPorts(t, pup, orl); +                  break; +            case Track::AUDIO_AUX: +                  addOutPorts(t, pup, orl); +                  break; +            } +      int n = pup->exec(QCursor::pos()); +      if (n != -1) { +            QString s(pup->text(n)); +            Route srcRoute(t, -1); +            Route dstRoute(s, true, -1); + +            if (track->type() == Track::AUDIO_OUTPUT) +                  srcRoute.channel = dstRoute.channel = n & 0xf; + +            // check if route src->dst exists: +            iRoute iorl = orl->begin(); +            for (; iorl != orl->end(); ++iorl) { +                  if (*iorl == dstRoute) +                        break; +                  } +            if (iorl != orl->end()) { +                  // disconnect if route exists +                  audio->msgRemoveRoute(srcRoute, dstRoute); +                  } +            else { +                  // connect if route does not exist +                  audio->msgAddRoute(srcRoute, dstRoute); +                  } +            audio->msgUpdateSoloStates(); +            song->update(SC_ROUTE); +            } +      delete pup; +      oR->setDown(false);     // pup->exec() catches mouse release event +      */ +       +       +      } + + diff --git a/muse/muse/mixer/mstrip.h b/muse/muse/mixer/mstrip.h index e32b4310..460a7d65 100644 --- a/muse/muse/mixer/mstrip.h +++ b/muse/muse/mixer/mstrip.h @@ -28,7 +28,9 @@ class MidiStrip : public Strip {        Slider* slider;        DoubleLabel* sl; -      QToolButton* route; +      //QToolButton* route; +      QToolButton* iR; +      QToolButton* oR;        struct KNOB {              Knob* knob; @@ -49,7 +51,9 @@ class MidiStrip : public Strip {        void updateOffState();     private slots: -      void routeClicked(); +      //void routeClicked(); +      void iRoutePressed(); +      void oRoutePressed();        void setVolume(double);        void setPan(double);        void setChorusSend(double); diff --git a/muse/muse/mixer/routedialog.cpp b/muse/muse/mixer/routedialog.cpp index 595305c0..e3b1f211 100644 --- a/muse/muse/mixer/routedialog.cpp +++ b/muse/muse/mixer/routedialog.cpp @@ -49,13 +49,16 @@ void RouteDialog::routingChanged()        for (ciTrack i = tl->begin(); i != tl->end(); ++i) {              if ((*i)->isMidiTrack())                    continue; -            WaveTrack* track = (WaveTrack*)(*i); +            // p3.3.38 +            //WaveTrack* track = (WaveTrack*)(*i); +            AudioTrack* track = (AudioTrack*)(*i);              if (track->type() == Track::AUDIO_INPUT) {                    for (int channel = 0; channel < track->channels(); ++channel)                          newDstList->insertItem(Route(track, channel).name());                    const RouteList* rl = track->inRoutes();                    for (ciRoute r = rl->begin(); r != rl->end(); ++r) { -                        Route dst(track->name(), true, r->channel); +                        //Route dst(track->name(), true, r->channel); +                        Route dst(track->name(), true, r->channel, Route::TRACK_ROUTE);                          new QListViewItem(routeList, r->name(), dst.name());                          }                    } diff --git a/muse/muse/node.cpp b/muse/muse/node.cpp index 4928420f..178c87cc 100644 --- a/muse/muse/node.cpp +++ b/muse/muse/node.cpp @@ -177,7 +177,7 @@ void AudioTrack::updateInternalSoloStates()          const RouteList* rl = inRoutes();          for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)          { -          if(ir->type == TRACK_ROUTE) +          if(ir->type == Route::TRACK_ROUTE)              ir->track->updateInternalSoloStates();          }        } @@ -186,7 +186,7 @@ void AudioTrack::updateInternalSoloStates()          const RouteList* rl = outRoutes();          for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)          { -          if(ir->type == TRACK_ROUTE) +          if(ir->type == Route::TRACK_ROUTE)              ir->track->updateInternalSoloStates();          }        }   @@ -243,7 +243,7 @@ void AudioTrack::updateSoloStates(bool noDec)      const RouteList* rl = inRoutes();      for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)      { -      if(ir->type == TRACK_ROUTE) +      if(ir->type == Route::TRACK_ROUTE)          ir->track->updateInternalSoloStates();      }    }   @@ -252,7 +252,7 @@ void AudioTrack::updateSoloStates(bool noDec)      const RouteList* rl = outRoutes();      for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)      { -      if(ir->type == TRACK_ROUTE) +      if(ir->type == Route::TRACK_ROUTE)          ir->track->updateInternalSoloStates();      }    }   @@ -280,7 +280,8 @@ void Track::setOff(bool val)  //   copyData  //--------------------------------------------------------- -void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) +//void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) +void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)  {    //Changed by T356. 12/12/09.     // Overhaul and streamline to eliminate multiple processing during one process loop.  @@ -288,9 +289,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float    // Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing.    // Previously only WaveTrack used them. (Changed WaveTrack as well). -  int srcChannels = channels(); +  if(srcStartChan == -1) +    srcStartChan = 0; +     +  int srcChans = (srcChannels == -1) ? channels() : srcChannels; +  int srcTotalOutChans = totalOutChannels(); +  if(channels() == 1) +    srcTotalOutChans = 1; -  //Added by Tim. p3.3.16    #ifdef NODE_DEBUG    printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().latin1(), processed());    #endif @@ -304,7 +310,11 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float    int i; -  float* buffer[srcChannels]; +  // p3.3.38 +  //float* buffer[srcChannels]; +  float* buffer[srcTotalOutChans]; +   +      //float data[nframes * srcChannels];    //for(i = 0; i < srcChannels; ++i)    //      buffer[i] = data + i * nframes; @@ -315,7 +325,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float    double _pan = pan();    vol[0] = _volume * (1.0 - _pan);    vol[1] = _volume * (1.0 + _pan); -  float meter[srcChannels]; +  float meter[srcChans];    // Have we been here already during this process cycle?    if(processed()) @@ -330,7 +340,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      if(_haveData)      {        // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. -      for(i = 0; i < srcChannels; ++i) +      //for(i = 0; i < srcChannels; ++i) +      //  buffer[i] = outBuffers[i]; +      // p3.3.38 +      for(i = 0; i < srcTotalOutChans; ++i)          buffer[i] = outBuffers[i];      }      else @@ -354,8 +367,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      // First time here during this process cycle.       // Point the input buffers at a temporary stack buffer. -    float data[nframes * srcChannels]; -    for(i = 0; i < srcChannels; ++i) +    //float data[nframes * srcChannels]; +    //for(i = 0; i < srcChannels; ++i) +    //    buffer[i] = data + i * nframes; +    // p3.3.38 +    float data[nframes * srcTotalOutChans]; +    for(i = 0; i < srcTotalOutChans; ++i)          buffer[i] = data + i * nframes;      // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.  @@ -363,9 +380,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      // p3.3.29 1/27/10 Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times,      //  so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is !      //if(!getData(pos, srcChannels, nframes, buffer) || off() || (isMute() && !_prefader))  -    if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader))  +    //if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader))  +    // p3.3.38 +    if(off() || !getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader))       { -      //Added by Tim. p3.3.16        #ifdef NODE_DEBUG        printf("MusE: AudioTrack::copyData name:%s dstChannels:%d zeroing buffers\n", name().latin1(), dstChannels);        #endif @@ -383,7 +401,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float            memset(dstBuffer[i], 0, sizeof(float) * nframes);        }   -      for(i = 0; i < srcChannels; ++i)  +      for(i = 0; i < srcChans; ++i)         {          //_meter[i] = 0;          _meter[i] = 0.0; @@ -411,7 +429,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      // apply plugin chain      //--------------------------------------------------- -    _efxPipe->apply(srcChannels, nframes, buffer); +    _efxPipe->apply(srcChans, nframes, buffer);      //---------------------------------------------------      // aux sends @@ -429,9 +447,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float          AudioAux* a = (AudioAux*)((*al)[k]);          float** dst = a->sendBuffer();          int auxChannels = a->channels(); -        if((srcChannels ==1 && auxChannels==1) || srcChannels == 2)  +        if((srcChans ==1 && auxChannels==1) || srcChans == 2)           { -          for(int ch = 0; ch < srcChannels; ++ch)  +          for(int ch = 0; ch < srcChans; ++ch)             {              float* db = dst[ch % a->channels()]; // no matter whether there's one or two dst buffers              float* sb = buffer[ch]; @@ -439,7 +457,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float                *db++ += (*sb++ * m * vol[ch]);   // add to mix            }          } -        else if(srcChannels==1 && auxChannels==2)  // copy mono to both channels +        else if(srcChans==1 && auxChannels==2)  // copy mono to both channels          {              for(int ch = 0; ch < auxChannels; ++ch)             { @@ -458,7 +476,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      if(_prefader)       { -      for(i = 0; i < srcChannels; ++i)  +      for(i = 0; i < srcChans; ++i)         {          float* p = buffer[i];          meter[i] = 0.0; @@ -514,7 +532,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them.       if(!usedirectbuf)      { -      for(i = 0; i < srcChannels; ++i) +      //for(i = 0; i < srcChannels; ++i) +      //  AL::dsp->cpy(outBuffers[i], buffer[i], nframes); +      // p3.3.38 +      for(i = 0; i < srcTotalOutChans; ++i)          AL::dsp->cpy(outBuffers[i], buffer[i], nframes);      } @@ -522,18 +543,43 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float      _haveData = true;    } +  // Sanity check. Is source starting channel out of range? Just zero and return. +  if(srcStartChan >= srcTotalOutChans)  +  { +    unsigned int q; +    for(i = 0; i < dstChannels; ++i) +    { +      if(config.useDenormalBias)  +      { +        for(q = 0; q < nframes; q++) +          dstBuffer[i][q] = denormalBias; +      }  +      else  +        memset(dstBuffer[i], 0, sizeof(float) * nframes); +    }         +    _processed = true; +    return; +  } +  // Force a source range to fit actual available total out channels. +  if((srcStartChan + srcChans) > srcTotalOutChans)  +    srcChans = srcTotalOutChans - srcStartChan; +      //---------------------------------------------------    // apply volume    //    postfader metering    //--------------------------------------------------- -  if(srcChannels == dstChannels)  +     +  if(srcChans == dstChannels)     {      if(_prefader)       {        for(int c = 0; c < dstChannels; ++c)         { -        float* sp = buffer[c]; +        // p3.3.38 +        //float* sp = buffer[c]; +        float* sp = buffer[c + srcStartChan]; +                  float* dp = dstBuffer[c];          for(unsigned k = 0; k < nframes; ++k)            *dp++ = (*sp++ * vol[c]); @@ -544,7 +590,11 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float        for(int c = 0; c < dstChannels; ++c)         {          meter[c] = 0.0; -        float* sp = buffer[c]; +         +        // p3.3.38 +        //float* sp = buffer[c]; +        float* sp = buffer[c + srcStartChan]; +                  float* dp = dstBuffer[c];          //printf("2 dstBuffer[c]=%d\n",long(dstBuffer[c]));          for(unsigned k = 0; k < nframes; ++k)  @@ -562,9 +612,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float        }      }    } -  else if(srcChannels == 1 && dstChannels == 2)  +  else if(srcChans == 1 && dstChannels == 2)     { -    float* sp = buffer[0]; +    // p3.3.38 +    //float* sp = buffer[0]; +    float* sp = buffer[srcStartChan]; +          if(_prefader)       {        for(int c = 0; c < dstChannels; ++c)  @@ -592,10 +645,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float          _peak[0] = _meter[0];      }    } -  else if(srcChannels == 2 && dstChannels == 1)  +  else if(srcChans == 2 && dstChannels == 1)     { -    float* sp1 = buffer[0]; -    float* sp2 = buffer[1]; +    // p3.3.38 +    //float* sp1 = buffer[0]; +    //float* sp2 = buffer[1]; +    float* sp1 = buffer[srcStartChan]; +    float* sp2 = buffer[srcStartChan + 1]; +          if(_prefader)       {        float* dp = dstBuffer[0]; @@ -637,7 +694,8 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float  //   addData  //--------------------------------------------------------- -void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) +//void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) +void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)  {    //Changed by T356. 12/12/09.     // Overhaul and streamline to eliminate multiple processing during one process loop. @@ -656,7 +714,13 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      return;    }  -  int srcChannels = channels(); +  if(srcStartChan == -1) +    srcStartChan = 0; +     +  int srcChans = (srcChannels == -1) ? channels() : srcChannels; +  int srcTotalOutChans = totalOutChannels(); +  if(channels() == 1) +    srcTotalOutChans = 1;    // Special consideration for metronome: It is not part of the track list,    //  and it has no in or out routes, yet multiple output tracks may call addData on it ! @@ -666,7 +730,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*    int i; -  float* buffer[srcChannels]; +  // p3.3.38 +  //float* buffer[srcChannels]; +  float* buffer[srcTotalOutChans]; +      //float data[nframes * srcChannels];    //for (i = 0; i < srcChannels; ++i)    //      buffer[i] = data + i * nframes; @@ -677,7 +744,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*    double _pan = pan();    vol[0] = _volume * (1.0 - _pan);    vol[1] = _volume * (1.0 + _pan); -  float meter[srcChannels]; +  float meter[srcChans];    // Have we been here already during this process cycle?    if(processed()) @@ -692,7 +759,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      if(_haveData)      {        // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. -      for(i = 0; i < srcChannels; ++i) +      //for(i = 0; i < srcChannels; ++i) +      //  buffer[i] = outBuffers[i]; +      // p3.3.38 +      for(i = 0; i < srcTotalOutChans; ++i)          buffer[i] = outBuffers[i];      }      else @@ -704,16 +774,23 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      // First time here during this process cycle.       // Point the input buffers at a temporary stack buffer. -    float data[nframes * srcChannels]; -    for(i = 0; i < srcChannels; ++i) -      buffer[i] = data + i * nframes; +    //float data[nframes * srcChannels]; +    //for(i = 0; i < srcChannels; ++i) +    //  buffer[i] = data + i * nframes; +    // p3.3.38 +    float data[nframes * srcTotalOutChans]; +    for(i = 0; i < srcTotalOutChans; ++i) +        buffer[i] = data + i * nframes; +        // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.       // For ex. if this is an audio input, Jack will set the pointers for us. -    if(!getData(pos, srcChannels, nframes, buffer))  +    //if(!getData(pos, srcChannels, nframes, buffer))  +    // p3.3.38 +    if(!getData(pos, srcTotalOutChans, nframes, buffer))       {        // No data was available. Nothing to add, but zero our local buffers and the meters. -      for(i = 0; i < srcChannels; ++i) +      for(i = 0; i < srcChans; ++i)        {          // If we're using local buffers, we must zero them so that the next thing requiring them           //  during this process cycle will see zeros. @@ -743,7 +820,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      // apply plugin chain      //--------------------------------------------------- -    _efxPipe->apply(srcChannels, nframes, buffer); +    _efxPipe->apply(srcChans, nframes, buffer);      //---------------------------------------------------      // aux sends @@ -761,9 +838,9 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*          AudioAux* a = (AudioAux*)((*al)[k]);          float** dst = a->sendBuffer();          int auxChannels = a->channels(); -        if((srcChannels ==1 && auxChannels==1) || srcChannels==2)  +        if((srcChans ==1 && auxChannels==1) || srcChans==2)           { -          for(int ch = 0; ch < srcChannels; ++ch)  +          for(int ch = 0; ch < srcChans; ++ch)             {              float* db = dst[ch % a->channels()];              float* sb = buffer[ch]; @@ -771,7 +848,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*                *db++ += (*sb++ * m * vol[ch]);   // add to mix            }          } -        else if(srcChannels == 1 && auxChannels == 2)  +        else if(srcChans == 1 && auxChannels == 2)           {            for(int ch = 0; ch < auxChannels; ++ch)             { @@ -790,7 +867,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      if(_prefader)       { -      for(i = 0; i < srcChannels; ++i)  +      for(i = 0; i < srcChans; ++i)         {          float* p = buffer[i];          meter[i] = 0.0; @@ -835,7 +912,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them.       if(!usedirectbuf)      { -      for(i = 0; i < srcChannels; ++i) +      //for(i = 0; i < srcChannels; ++i) +      //  AL::dsp->cpy(outBuffers[i], buffer[i], nframes); +      // p3.3.38 +      for(i = 0; i < srcTotalOutChans; ++i)          AL::dsp->cpy(outBuffers[i], buffer[i], nframes);      } @@ -843,18 +923,42 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*      _haveData = true;    }   +  // Sanity check. Is source starting channel out of range? Just zero and return. +  if(srcStartChan >= srcTotalOutChans)  +  { +    unsigned int q; +    for(i = 0; i < dstChannels; ++i) +    { +      if(config.useDenormalBias)  +      { +        for(q = 0; q < nframes; q++) +          dstBuffer[i][q] = denormalBias; +      }  +      else  +        memset(dstBuffer[i], 0, sizeof(float) * nframes); +    }         +    _processed = true; +    return; +  } +  // Force a source range to fit actual available total out channels. +  if((srcStartChan + srcChans) > srcTotalOutChans)  +    srcChans = srcTotalOutChans - srcStartChan; +      //---------------------------------------------------    // apply volume    //    postfader metering    //--------------------------------------------------- -  if(srcChannels == dstChannels)  +  if(srcChans == dstChannels)     {      if(_prefader)       {        for(int c = 0; c < dstChannels; ++c)         { -        float* sp = buffer[c]; +        // p3.3.38 +        //float* sp = buffer[c]; +        float* sp = buffer[c + srcStartChan]; +                  float* dp = dstBuffer[c];          for(unsigned k = 0; k < nframes; ++k)            *dp++ += (*sp++ * vol[c]); @@ -865,7 +969,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*        for(int c = 0; c < dstChannels; ++c)         {          meter[c] = 0.0; -        float* sp = buffer[c]; +        // p3.3.38 +        //float* sp = buffer[c]; +        float* sp = buffer[c + srcStartChan]; +                  float* dp = dstBuffer[c];          for(unsigned k = 0; k < nframes; ++k)           { @@ -882,21 +989,24 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*        }      }    } -  else if(srcChannels == 1 && dstChannels == 2)  +  else if(srcChans == 1 && dstChannels == 2)     { +    // p3.3.38 +    float* sp = buffer[srcStartChan]; +          if(_prefader)       {        for(int c = 0; c < dstChannels; ++c)         {          float* dp = dstBuffer[c]; -        float* sp = buffer[0]; +        //float* sp = buffer[0];          for(unsigned k = 0; k < nframes; ++k)            *dp++ += (*sp++ * vol[c]);        }      }      else       { -      float* sp = buffer[0]; +      //float* sp = buffer[0];        meter[0]  = 0.0;        for(unsigned k = 0; k < nframes; ++k)         { @@ -913,10 +1023,14 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*          _peak[0] = _meter[0];      }    } -  else if(srcChannels == 2 && dstChannels == 1)  +  else if(srcChans == 2 && dstChannels == 1)     { -    float* sp1 = buffer[0]; -    float* sp2 = buffer[1]; +    // p3.3.38 +    //float* sp1 = buffer[0]; +    //float* sp2 = buffer[1]; +    float* sp1 = buffer[srcStartChan]; +    float* sp2 = buffer[srcStartChan + 1]; +          if(_prefader)       {        float* dp = dstBuffer[0]; @@ -1096,7 +1210,6 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b        RouteList* rl = inRoutes(); -      // Added by Tim. p3.3.16        #ifdef NODE_DEBUG        printf("AudioTrack::getData name:%s inRoutes:%d\n", name().latin1(), rl->size());        #endif @@ -1105,20 +1218,37 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b        if (ir == rl->end())              return false; -      // Added by Tim. p3.3.16 +      if(ir->track->isMidiTrack()) +        return false; +                #ifdef NODE_DEBUG        printf("    calling copyData on %s...\n", ir->track->name().latin1());        #endif -      ir->track->copyData(pos, channels, nframes, buffer); +      // p3.3.38 +      //((AudioTrack*)ir->track)->copyData(pos, channels, nframes, buffer); +      ((AudioTrack*)ir->track)->copyData(pos, channels,  +                                         //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0, +                                         ir->channel, +                                         ir->channels, +                                         nframes, buffer); +              ++ir;        for (; ir != rl->end(); ++ir) { -            // Added by Tim. p3.3.16              #ifdef NODE_DEBUG              printf("    calling addData on %s...\n", ir->track->name().latin1());              #endif -            ir->track->addData(pos, channels, nframes, buffer); +            if(ir->track->isMidiTrack()) +              continue; +               +            // p3.3.38 +            //((AudioTrack*)ir->track)->addData(pos, channels, nframes, buffer); +            ((AudioTrack*)ir->track)->addData(pos, channels,  +                                              //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0, +                                              ir->channel, +                                              ir->channels, +                                              nframes, buffer);              }        return true;        } @@ -1368,7 +1498,7 @@ void AudioOutput::processInit(unsigned nframes)  //---------------------------------------------------------  void AudioOutput::process(unsigned pos, unsigned offset, unsigned n) -      { +{        //Added by Tim. p3.3.16        #ifdef NODE_DEBUG        printf("MusE: AudioOutput::process name:%s processed:%d\n", name().latin1(), processed()); @@ -1377,8 +1507,11 @@ void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)        for (int i = 0; i < _channels; ++i) {              buffer1[i] = buffer[i] + offset;        } -      copyData(pos, _channels, n, buffer1); -      } +       +      // p3.3.38 +      //copyData(pos, _channels, n, buffer1); +      copyData(pos, _channels, -1, -1, n, buffer1); +}  //---------------------------------------------------------  //   silence @@ -1427,7 +1560,9 @@ void AudioOutput::processWrite()              printf("MusE: AudioOutput::processWrite Calling metronome->addData frame:%u channels:%d frames:%lu\n", audio->pos().frame(), _channels, _nframes);              #endif -            metronome->addData(audio->pos().frame(), _channels, _nframes, buffer); +            // p3.3.38 +            //metronome->addData(audio->pos().frame(), _channels, _nframes, buffer); +            metronome->addData(audio->pos().frame(), _channels, -1, -1, _nframes, buffer);              }        }  //--------------------------------------------------------- @@ -1606,3 +1741,53 @@ void AudioTrack::setChannels(int n)              _efxPipe->setChannels(n);        } +//--------------------------------------------------------- +//   setTotalOutChannels +//--------------------------------------------------------- + +void AudioTrack::setTotalOutChannels(int num) +{ +      if(num == _totalOutChannels) +        return; +         +      int chans = _totalOutChannels; +      // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.  +      if(chans < MAX_CHANNELS) +        chans = MAX_CHANNELS; +      for(int i = 0; i < chans; ++i)  +      { +        if(outBuffers[i]) +          free(outBuffers[i]); +      } +      delete[] outBuffers; +       +      _totalOutChannels = num; +      chans = num; +      // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.  +      if(chans < MAX_CHANNELS) +        chans = MAX_CHANNELS; +         +      outBuffers = new float*[chans]; +      for (int i = 0; i < chans; ++i) +            posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * segmentSize); +       +      chans = num; +      // Limit the actual track (meters, copying etc, all 'normal' operation) to two-channel stereo. +      if(chans > MAX_CHANNELS) +        chans = MAX_CHANNELS; +       +      setChannels(chans); +} + +//--------------------------------------------------------- +//   setTotalInChannels +//--------------------------------------------------------- + +void AudioTrack::setTotalInChannels(int num) +{ +      if(num == _totalInChannels) +        return; +         +      _totalInChannels = num; +} + diff --git a/muse/muse/route.cpp b/muse/muse/route.cpp index ace53252..0b45fdf2 100644 --- a/muse/muse/route.cpp +++ b/muse/muse/route.cpp @@ -16,6 +16,10 @@  #include "synth.h"  #include "audiodev.h"  #include "xml.h" +#include "driver/jackmidi.h" +#include "driver/alsamidi.h" + +//#define ROUTE_DEBUG   //---------------------------------------------------------  //   Route @@ -25,34 +29,79 @@ Route::Route(void* t, int ch)        {        jackPort = t;        channel  = ch; +      channels = -1; +      remoteChannel = -1;        type     = JACK_ROUTE;        } -Route::Route(AudioTrack* t, int ch) +//Route::Route(AudioTrack* t, int ch) +Route::Route(Track* t, int ch, int chans) +//Route::Route(Track* t, int ch)        { -      channel = ch; -      track   = t; -      type    = TRACK_ROUTE; +      track    = t; +      channel  = ch; +      channels = chans; +      remoteChannel = -1; +      type     = TRACK_ROUTE;        } -Route::Route(const QString& s, bool dst, int ch) +//Route::Route(MidiJackDevice* d) +Route::Route(MidiDevice* d, int ch) +{ +      device   = d; +      channel  = ch; +      channels = -1; +      remoteChannel = -1; +      /* +      //if(dynamic_cast<MidiJackDevice*>(d)) +      if(d->deviceType() == MidiDevice::JACK_MIDI) +        type    = JACK_MIDI_ROUTE; +      else   +      //if(dynamic_cast<MidiAlsaDevice*>(d)) +      if(d->deviceType() == MidiDevice::ALSA_MIDI) +        type    = ALSA_MIDI_ROUTE; +      */   +      type    = MIDI_DEVICE_ROUTE; +} + +//Route::Route(const QString& s, bool dst, int ch) +Route::Route(const QString& s, bool dst, int ch, int rtype)        { -      Route node(name2route(s, dst)); -      channel = node.channel; -      if (channel == -1) -            channel = ch; +      //Route node(name2route(s, dst)); +      Route node(name2route(s, dst, rtype)); +      channel  = node.channel; +      if(channel == -1) +        channel = ch; +      //if(channels == -1) +      //  channels = chans; +      channels = node.channels; +      remoteChannel = node.remoteChannel;        type = node.type; -      if (type == TRACK_ROUTE) -            track = node.track; +      if(type == TRACK_ROUTE) +        track = node.track; +      else +      if(type == JACK_ROUTE) +        jackPort = node.jackPort; +      /* +      else +      if (type == JACK_MIDI_ROUTE) +            device = node.device;        else -            jackPort = node.jackPort; +      if (type == ALSA_MIDI_ROUTE) +            device = node.device; +      */ +      else +      if (type == MIDI_DEVICE_ROUTE) +            device = node.device;        }  Route::Route()        { -      track   = 0; -      channel = -1; -      type    = TRACK_ROUTE; +      track    = 0; +      channel  = -1; +      channels = -1; +      remoteChannel = -1; +      type     = TRACK_ROUTE;        }  //--------------------------------------------------------- @@ -60,58 +109,306 @@ Route::Route()  //---------------------------------------------------------  void addRoute(Route src, Route dst) -      { +{ +      #ifdef ROUTE_DEBUG +      fprintf(stderr, "addRoute:\n"); +      #endif +              if (!src.isValid() || !dst.isValid()) +      { +            if(!src.isValid()) +              fprintf(stderr, "addRoute: invalid src\n"); +            if(!dst.isValid()) +              fprintf(stderr, "addRoute: invalid dst\n");              return; - +      } +        //      printf("addRoute %d.%d:<%s> %d.%d:<%s>\n",  //         src.type, src.channel, src.name().latin1(),  //         dst.type, dst.channel, dst.name().latin1()); -      if (src.type == JACK_ROUTE) { -            if (dst.type != TRACK_ROUTE) { -                  fprintf(stderr, "addRoute: bad route 1\n"); +      if (src.type == Route::JACK_ROUTE)  +      {            +            //if (dst.type != TRACK_ROUTE)  +            //{ +            //      fprintf(stderr, "addRoute: bad route 1\n");                    // exit(-1); +            //      return; +            //} +             +            if (dst.type == Route::TRACK_ROUTE)  +            { +              if (dst.track->type() != Track::AUDIO_INPUT)  +              { +                  fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().latin1()); +                  //exit(-1);                    return; -                  } -            if (dst.track->type() != Track::AUDIO_INPUT) { -                  fprintf(stderr, "addRoute: bad route 2\n"); -                  exit(-1); -                  } -            src.channel = dst.channel; -            RouteList* inRoutes = dst.track->inRoutes(); -            for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { +              } +              //src.channel = src.dstChannel = dst.channel; +              src.channel = dst.channel; +              //src.channels = dst.channels = 1; +              RouteList* inRoutes = dst.track->inRoutes(); +              for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  +              { +                if (*i == src)    // route already there +                { +                  //#ifdef ROUTE_DEBUG +                  fprintf(stderr, "addRoute: src track route already exists.\n"); +                  //#endif +                  return; +                }   +              } +              #ifdef ROUTE_DEBUG +              fprintf(stderr, "addRoute: src Jack dst track name: %s pushing source route\n", dst.track->name().latin1()); +              #endif +              inRoutes->push_back(src); +            }   +            else +            //if (dst.type == Route::JACK_MIDI_ROUTE)  +            if (dst.type == Route::MIDI_DEVICE_ROUTE)  +            { +              if(dst.device->deviceType() == MidiDevice::JACK_MIDI) +              { +                src.channel = dst.channel; +                //src.channel = -1; +                //src.channel = 0; +                //src.channel = src.dstChannel = dst.channel; +                //src.channels = dst.channels = 1; +                //dst.channel = -1; +                 +                RouteList* routes = dst.device->inRoutes(); +                for (iRoute i = routes->begin(); i != routes->end(); ++i)  +                {                    if (*i == src)    // route already there -                        return; -                  } -            inRoutes->push_back(src); +                  { +                    //#ifdef ROUTE_DEBUG +                    fprintf(stderr, "addRoute: src Jack midi route already exists.\n"); +                    //#endif +                    return; +                  }   +                } +                #ifdef ROUTE_DEBUG +                fprintf(stderr, "addRoute: src Jack dst Jack midi name: %s pushing source route\n", dst.device->name().latin1()); +                #endif +                routes->push_back(src); +              }   +              else +              { +                fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType()); +                // exit(-1); +                return; +              } +            }   +            else +            { +              fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type); +              // exit(-1); +              return;              } -      else if (dst.type == JACK_ROUTE) { -            if (src.type != TRACK_ROUTE) { -                  fprintf(stderr, "addRoute: bad route 3\n"); -                  // exit(-1); -                  return; -                  } -            if (src.track->type() != Track::AUDIO_OUTPUT) { -                  fprintf(stderr, "addRoute: bad route 4\n"); +      } +      else if (dst.type == Route::JACK_ROUTE)  +      { +            //if (src.type != TRACK_ROUTE)  +            //{ +            //      fprintf(stderr, "addRoute: bad route 3\n");                    // exit(-1); -                  return; -                  } -            RouteList* outRoutes = src.track->outRoutes(); -            dst.channel = src.channel; -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { +            //      return; +            //} +             +            if (src.type == Route::TRACK_ROUTE)  +            { +              if (src.track->type() != Track::AUDIO_OUTPUT)  +              { +                    fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n"); +                    // exit(-1); +                    return; +              } +              RouteList* outRoutes = src.track->outRoutes(); +              //dst.channel = dst.dstChannel = src.channel; +              dst.channel = src.channel; +              //dst.channels = src.channels = 1; +               +              for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +              { +                    if (*i == dst)    // route already there +                    { +                          #ifdef ROUTE_DEBUG +                          fprintf(stderr, "addRoute: dst track route already exists.\n"); +                          #endif +                          return; +                    }       +              } +              #ifdef ROUTE_DEBUG +              fprintf(stderr, "addRoute: dst Jack src track name: %s pushing destination route\n", src.track->name().latin1()); +              #endif +              outRoutes->push_back(dst); +            } +            else +            //if (src.type == Route::JACK_MIDI_ROUTE)  +            if (src.type == Route::MIDI_DEVICE_ROUTE)  +            { +              if(src.device->deviceType() == MidiDevice::JACK_MIDI) +              { +                dst.channel = src.channel; +                //dst.channel = -1; +                //src.channel = -1; +                //dst.channel = dst.dstChannel = src.channel; +                //dst.channels = src.channels = 1; +                 +                RouteList* routes = src.device->outRoutes(); +                for (iRoute i = routes->begin(); i != routes->end(); ++i)  +                {                    if (*i == dst)    // route already there -                        return; -                  } -            outRoutes->push_back(dst); +                  { +                    //#ifdef ROUTE_DEBUG +                    fprintf(stderr, "addRoute: dst Jack midi route already exists.\n"); +                    //#endif +                    return; +                  }   +                } +                #ifdef ROUTE_DEBUG +                fprintf(stderr, "addRoute: dst Jack src Jack midi name: %s pushing destination route\n", src.device->name().latin1()); +                #endif +                routes->push_back(dst); +              } +              else   +              { +                fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType()); +                // exit(-1); +                return; +              }              } -      else { -            RouteList* outRoutes = src.track->outRoutes(); -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { +            else +            { +              fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type); +              // exit(-1); +              return; +            } +      } +      else  +      { +        //if ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) +        if(src.type == Route::MIDI_DEVICE_ROUTE) +        {            +            //src.channel = src.dstChannel = dst.dstChannel = dst.channel; +            src.channel = dst.channel; +            //src.channels = dst.channels = 1; +            RouteList* outRoutes = src.device->outRoutes(); +            #ifdef ROUTE_DEBUG +            fprintf(stderr, "addRoute: src name: %s looking for existing dest in out routes...\n", src.device->name().latin1()); +            #endif +            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +            {                    if (*i == dst)    // route already there +                  { +                        //#ifdef ROUTE_DEBUG +                        fprintf(stderr, "addRoute: src Jack or ALSA midi route already exists.\n"); +                        //#endif                          return; -                  } +                  }       +            } +            #ifdef ROUTE_DEBUG +            fprintf(stderr, "addRoute: src midi dst name: %s pushing destination and source routes\n", dst.track->name().latin1()); +            #endif +                          outRoutes->push_back(dst);              RouteList* inRoutes = dst.track->inRoutes(); +            inRoutes->push_back(src); +        }           +        else +        {            +            if(dst.type == Route::MIDI_DEVICE_ROUTE) +            //{ +              dst.channel = src.channel; +              //src.channel = src.dstChannel = dst.dstChannel = dst.channel; +              //src.channels = dst.channels = 1; +            //} +            //else +            //{ +              //src.channel = src.dstChannel = dst.dstChannel = dst.channel; +              //src.channels = dst.channels = 1; +            //} +               +            RouteList* outRoutes = src.track->outRoutes(); +             +            // +            // Must enforce to ensure channel and channels are valid if defaults of -1 passed. +            // +            if(src.track->type() == Track::AUDIO_SOFTSYNTH) +            { +              if(src.channel == -1) +                src.channel = 0; +              if(src.channels == -1) +                src.channels = src.track->channels();   +              if(dst.type == Route::TRACK_ROUTE) +              { +                //if(dst.channel == -1) +                //  dst.channel = 0; +                //if(dst.channels == -1) +                  // Yes, that's correct: dst channels = src track channels. +                //  dst.channels = src.track->channels();   +                dst.channel = src.channel; +                dst.channels = src.channels; +                dst.remoteChannel = src.remoteChannel; +              } +            } +            /* +            if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH) +            { +              if(dst.channel == -1) +                dst.channel = 0; +              if(dst.channels == -1) +                // Yes, that's correct: dst channels = src track channels. +                dst.channels = src.track->channels();   +            } +            */ +             +            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +            { +                  if (*i == dst)    // route already there +                  // TODO: +                  //if (i->type == dst.type && i->channel == dst.channel)     +                  { +                    //if(i->type == Route::TRACK_ROUTE) +                    { +                      //if(i->track == dst.track) +                      { +                        //if(i->channels == dst.channels) +                        { +                          //#ifdef ROUTE_DEBUG +                          fprintf(stderr, "addRoute: src track route already exists.\n"); +                          //#endif +                          return; +                        } +                        //else +                        //{ +                         +                        //} +                      } +                    } +                  }       +            } +            outRoutes->push_back(dst); +            RouteList* inRoutes; +            //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) +            if(dst.type == Route::MIDI_DEVICE_ROUTE) +            { +              #ifdef ROUTE_DEBUG +              fprintf(stderr, "addRoute: src track dst midi name: %s pushing destination and source routes\n", dst.device->name().latin1()); +              #endif +              inRoutes = dst.device->inRoutes(); +            }   +            else   +            { +              #ifdef ROUTE_DEBUG +              //fprintf(stderr, "addRoute: src track ch:%d chs:%d  dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().latin1()); +              fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d  dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n",  +                src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().latin1()); +              //fprintf(stderr, "addRoute: src track ch:%d  dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().latin1()); +              #endif +              inRoutes = dst.track->inRoutes(); +            }   +               +                          //              // make sure AUDIO_AUX is processed last              // @@ -119,76 +416,198 @@ void addRoute(Route src, Route dst)                    inRoutes->push_back(src);              else                    inRoutes->insert(inRoutes->begin(), src); -            } +        }                  } +}  //---------------------------------------------------------  //   removeRoute  //---------------------------------------------------------  void removeRoute(Route src, Route dst) -      { +{      //printf("removeRoute %d.%d:<%s> %d.%d:<%s>\n",      //     src.type, src.channel, src.name().latin1(),      //     dst.type, dst.channel, dst.name().latin1()); -      if (src.type == JACK_ROUTE) { -            if (dst.type != TRACK_ROUTE) { -                  fprintf(stderr, "removeRoute: bad route 1\n"); +      if (src.type == Route::JACK_ROUTE)  +      { +            //if (dst.type != TRACK_ROUTE)  +            //{ +            //      fprintf(stderr, "removeRoute: bad route 1\n");                    // exit(-1); -                  return; -                  } -            if (dst.track->type() != Track::AUDIO_INPUT) { -                  fprintf(stderr, "removeRoute: bad route 2\n"); +            //      return; +            //} +            if(!dst.isValid()) +            { +              printf("removeRoute: source is jack, invalid destination\n"); +              return; +            } +             +            if (dst.type == Route::TRACK_ROUTE)  +            { +              if (dst.track->type() != Track::AUDIO_INPUT)  +              { +                    fprintf(stderr, "removeRoute: source is jack, destination is track but not audio input\n"); +                    // exit(-1); +                    return; +              } +              RouteList* inRoutes = dst.track->inRoutes(); +              iRoute i; +              for (i = inRoutes->begin(); i != inRoutes->end(); ++i)  +              { +                    if (*i == src)  +                    { +                          inRoutes->erase(i); +                          break; +                    } +              } +            }   +            else +            //if (dst.type == Route::JACK_MIDI_ROUTE)  +            if (dst.type == Route::MIDI_DEVICE_ROUTE)  +            { +              RouteList* routes = dst.device->inRoutes(); +              iRoute i; +              for (i = routes->begin(); i != routes->end(); ++i)  +              { +                    if (*i == src)  +                    { +                          routes->erase(i); +                          break; +                    } +              } +            }   +            else +            { +                  fprintf(stderr, "removeRoute: source is jack, destination unknown\n");                    // exit(-1);                    return; -                  } -            RouteList* inRoutes = dst.track->inRoutes(); -            iRoute i; -            for (i = inRoutes->begin(); i != inRoutes->end(); ++i) { -                  if (*i == src) { -                        inRoutes->erase(i); -                        break; -                        } -                  }              } -      else if (dst.type == JACK_ROUTE) { -            if (src.type != TRACK_ROUTE) { -                  fprintf(stderr, "removeRoute: bad route 3\n"); +      } +      else if (dst.type == Route::JACK_ROUTE)  +      { +            //if (src.type != TRACK_ROUTE)  +            //{ +            //      fprintf(stderr, "removeRoute: bad route 3\n");                    // exit(-1); -                  return; -                  } -            if (src.track->type() != Track::AUDIO_OUTPUT) { -                  fprintf(stderr, "removeRoute: bad route 4\n"); +            //      return; +            //} +            if(!src.isValid()) +            { +              printf("removeRoute: destination is jack, invalid source\n"); +              return; +            } +             +            if (src.type == Route::TRACK_ROUTE)  +            { +              if (src.track->type() != Track::AUDIO_OUTPUT)  +              { +                    fprintf(stderr, "removeRoute: destination is jack, source is track but not audio output\n"); +                    // exit(-1); +                    return; +              } +              RouteList* outRoutes = src.track->outRoutes(); +              iRoute i; +              for (i = outRoutes->begin(); i != outRoutes->end(); ++i)  +              { +                    if (*i == dst) { +                          outRoutes->erase(i); +                          break; +                          } +              } +            }   +            else +            //if (src.type == Route::JACK_MIDI_ROUTE)  +            if (src.type == Route::MIDI_DEVICE_ROUTE)  +            { +              RouteList* routes = src.device->outRoutes(); +              iRoute i; +              for (i = routes->begin(); i != routes->end(); ++i)  +              { +                    if (*i == dst) { +                          routes->erase(i); +                          break; +                          } +              } +            }   +            else +            { +                  fprintf(stderr, "removeRoute: destination is jack, source unknown\n");                    // exit(-1);                    return; -                  } -            RouteList* outRoutes = src.track->outRoutes(); -            iRoute i; -            for (i = outRoutes->begin(); i != outRoutes->end(); ++i) { -                  if (*i == dst) { -                        outRoutes->erase(i); -                        break; -                        } -                  }              } -      else { -            RouteList* outRoutes = src.track->outRoutes(); -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { -                  if (*i == dst) { -                        outRoutes->erase(i); -                        break; -                        } -                  } -            RouteList* inRoutes = dst.track->inRoutes(); -            for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { -                  if (*i == src) { -                        inRoutes->erase(i); -                        break; -                        } -                  } +      } +      else  +      { +            //if((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) +            if(src.type == Route::MIDI_DEVICE_ROUTE) +            { +              if(src.isValid()) +              { +                RouteList* outRoutes = src.device->outRoutes(); +                for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +                { +                      if (*i == dst) { +                            outRoutes->erase(i); +                            break; +                            } +                } +              } +              else +                printf("removeRoute: source is midi but invalid\n"); +               +              if(dst.isValid()) +              { +                RouteList* inRoutes = dst.track->inRoutes(); +                for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  +                { +                      if (*i == src) { +                            inRoutes->erase(i); +                            break; +                            } +                } +              } +              else +                printf("removeRoute: source is midi but destination invalid\n");              } +            else +            { +              if(src.isValid()) +              { +                RouteList* outRoutes = src.track->outRoutes(); +                for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +                { +                      if (*i == dst) { +                            outRoutes->erase(i); +                            break; +                            } +                } +              }   +              else +                printf("removeRoute: source is track but invalid\n"); +               +              if(dst.isValid()) +              { +                RouteList* inRoutes; +                //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) +                if (dst.type == Route::MIDI_DEVICE_ROUTE) +                  inRoutes = dst.device->inRoutes(); +                else   +                  inRoutes = dst.track->inRoutes(); +                for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  +                { +                      if (*i == src) { +                            inRoutes->erase(i); +                            break; +                            } +                } +              }   +              else +                printf("removeRoute: source is track but destination invalid\n"); +            }              } +}  //---------------------------------------------------------  //   track2name @@ -208,7 +627,9 @@ static QString track2name(const Track* n)  //---------------------------------------------------------  QString Route::name() const -      { +{ +      // p3.3.38 Removed +      /*        QString s;        if ((type == TRACK_ROUTE) && (channel != -1)) {  //      if (channel != -1) { @@ -216,58 +637,333 @@ QString Route::name() const              c.setNum(channel+1);              s = c + ":";              } -      if (type == JACK_ROUTE) { -            if (!checkAudioDevice()) return ""; -            return s + audioDevice->portName(jackPort); +      */ +       +      /* +      if (type == ALSA_MIDI_ROUTE)  +      { +            if(device) +              // TODO +              //snd_seq_addr_t +              return device->name(); +            else +              return QWidget::tr("None"); +      } +      else +      if (type == JACK_MIDI_ROUTE)  +      { +            if(device) +            { +              return audioDevice->portName(device->clientPort()); +              //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(device); +              //if(jmd) +              //  return audioDevice->portName(jmd->clientJackPort()); +              //else +              //{ +              //  fprintf(stderr, "Route::name Route is Jack midi but device is not a MidiJackDevice\n"); +              //  return QWidget::tr("None"); +              //}                } +            else +              return QWidget::tr("None"); +      } +      */ +       +      if(type == MIDI_DEVICE_ROUTE)  +      { +        if(device) +        { +          if(device->deviceType() == MidiDevice::JACK_MIDI) +            return audioDevice->portName(device->clientPort()); +          else +          //if(device->deviceType() == MidiDevice::ALSA_MIDI) +            return device->name(); +        } +        return QWidget::tr("None"); +      }        else -            return s + track2name(track); +      if(type == JACK_ROUTE)  +      { +        if (!checkAudioDevice()) return ""; +        //return s + audioDevice->portName(jackPort); +        return audioDevice->portName(jackPort);        } +      else +        //return s + track2name(track); +        return track2name(track); +}  //---------------------------------------------------------  //   name2route  //--------------------------------------------------------- -Route name2route(const QString& rn, bool dst) -      { +//Route name2route(const QString& rn, bool dst) +Route name2route(const QString& rn, bool /*dst*/, int rtype) +{  // printf("name2route %s\n", rn.latin1()); -      int channel = -1; -      QString s(rn); -      if (rn[0].isNumber() && rn[1]==':') { -            channel = rn[0] - '1'; -            s = rn.mid(2); -            } -      if (dst) { -            TrackList* tl = song->tracks(); -            for (iTrack i = tl->begin(); i != tl->end(); ++i) { -                  if ((*i)->isMidiTrack()) -                        continue; -                  AudioTrack* track = (AudioTrack*)*i; -                  if (track->name() == s) -                        return Route(track, channel); -                  } -            if (!checkAudioDevice()) return Route((AudioTrack*)NULL,0); -            void* p = audioDevice->findPort(s.latin1()); -            if (p) -                  return Route(p, channel); -            } -      else { -            if (!checkAudioDevice()) return Route((AudioTrack*)NULL,0); -            void* p = audioDevice->findPort(s.latin1()); -            if (p) -                  return Route(p, channel); -            TrackList* tl = song->tracks(); -            for (iTrack i = tl->begin(); i != tl->end(); ++i) { -                  if ((*i)->isMidiTrack()) -                        continue; -                  AudioTrack* track = (AudioTrack*)*i; -                  if (track->name() == s) -                        return Route(track, channel); -                  } -            } -      printf("  name2route: <%s> not found\n", rn.latin1()); -      return Route((Track*) 0, channel); +  int channel = -1; +  //int channel = 0; +  QString s(rn); +  // Support old route style in med files. Obsolete. +  if (rn[0].isNumber() && rn[1]==':')  +  { +    channel = rn[0] - '1'; +    s = rn.mid(2); +  } +   +  if(rtype == -1) +  {   +    //if(dst)  +    //{ +      if(checkAudioDevice()) +      { +        void* p = audioDevice->findPort(s.latin1()); +        if(p) +          return Route(p, channel); +      } +       +      TrackList* tl = song->tracks(); +      for(iTrack i = tl->begin(); i != tl->end(); ++i)  +      { +        if((*i)->isMidiTrack()) +        { +          MidiTrack* track = (MidiTrack*)*i; +          if(track->name() == s) +            return Route(track, channel); +            //return Route(track, channel, 1); +        } +        else +        {   +          AudioTrack* track = (AudioTrack*)*i; +          if(track->name() == s) +            return Route(track, channel); +            //return Route(track, channel, 1); +            //return Route(track, channel, track->channels()); +        }              } +       +      for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +      { +        if((*i)->name() == s) +        //if (jmd->name() == rn) +            return Route(*i, channel); +         +        /* +        MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); +        if(jmd) +        {      +          if(jmd->name() == s) +          //if (jmd->name() == rn) +              return Route(jmd); +        }       +        MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); +        if(amd) +        {      +          // TODO +          if(amd->name() == s) +          //if (amd->name() == rn) +              return Route(amd); +        }       +        */ +      } +     + +/*     +    } +    else  +    { +      if(checkAudioDevice())  +      { +        void* p = audioDevice->findPort(s.latin1()); +        if(p) +          return Route(p, channel); +      } +       +      TrackList* tl = song->tracks(); +      for(iTrack i = tl->begin(); i != tl->end(); ++i)  +      { +        if((*i)->isMidiTrack()) +        { +          MidiTrack* track = (MidiTrack*)*i; +          if(track->name() == s) +            return Route(track, channel); +        } +        else +        { +          AudioTrack* track = (AudioTrack*)*i; +          if(track->name() == s) +            return Route(track, channel); +        }       +      } +       +      for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +      { +        if((*i)->name() == s) +        //if (jmd->name() == rn) +            return Route(*i, channel); +*/ +         +        /* +        MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); +        if(jmd) +        {      +          if(jmd->name() == s) +          //if (jmd->name() == rn) +              return Route(jmd); +        }       +        MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); +        if(amd) +        {      +          // TODO +          if(amd->name() == s) +          //if (amd->name() == rn) +              return Route(amd); +        }       +        */ +//      } +//    } +     +  } +  else +  { +    //if(dst)  +    //{ +      if(rtype == Route::TRACK_ROUTE) +      {   +        TrackList* tl = song->tracks(); +        for(iTrack i = tl->begin(); i != tl->end(); ++i)  +        { +          if((*i)->isMidiTrack()) +          { +            MidiTrack* track = (MidiTrack*)*i; +            if(track->name() == s) +              return Route(track, channel); +          } +          else +          {   +            AudioTrack* track = (AudioTrack*)*i; +            if(track->name() == s) +              return Route(track, channel); +              //return Route(track, channel, 1); +              //return Route(track, channel, track->channels()); +          }       +        } +      } +      else +      //if((rtype == Route::JACK_MIDI_ROUTE) || (rtype == Route::ALSA_MIDI_ROUTE)) +      // TODO Distinguish the device types +      if(rtype == Route::MIDI_DEVICE_ROUTE) +      {   +        for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +        { +          if((*i)->name() == s) +          //if (jmd->name() == rn) +            return Route(*i, channel); +           +          /* +          MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); +          if(jmd) +          {      +            if(jmd->name() == s) +            //if (jmd->name() == rn) +                return Route(jmd); +          }       +          MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); +          if(amd) +          {      +            // TODO +            if(amd->name() == s) +            //if (amd->name() == rn) +                return Route(amd); +          }       +          */ +        } +      } +      else +      if(rtype == Route::JACK_ROUTE) +      {   +        if(checkAudioDevice()) +        { +          void* p = audioDevice->findPort(s.latin1()); +          if(p) +            return Route(p, channel); +        }       +      } +     + +/*     +    } +    else  +    { +      if(rtype == Route::TRACK_ROUTE) +      { +        TrackList* tl = song->tracks(); +        for(iTrack i = tl->begin(); i != tl->end(); ++i)  +        { +          if((*i)->isMidiTrack()) +          { +            MidiTrack* track = (MidiTrack*)*i; +            if (track->name() == s) +              return Route(track, channel); +          } +          else +          { +            AudioTrack* track = (AudioTrack*)*i; +            if(track->name() == s) +              return Route(track, channel); +          }       +        } +      } +      else +      if((rtype == Route::JACK_MIDI_ROUTE) || (rtype == Route::ALSA_MIDI_ROUTE)) +      { +        for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)  +        { +          if((*i)->name() == s) +          //if (jmd->name() == rn) +            return Route(*i, channel); +*/ +           +          /* +          MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i); +          if(jmd) +          {      +            if(jmd->name() == s) +            //if (jmd->name() == rn) +                return Route(jmd); +          }       +          MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i); +          if(amd) +          {      +            // TODO +            if(amd->name() == s) +            //if (amd->name() == rn) +                return Route(amd); +          }       +          */ + +/*         +        } +      }  +      else  +      if(rtype == JACK_ROUTE) +      { +        if(checkAudioDevice())  +        { +          void* p = audioDevice->findPort(s.latin1()); +          if(p) +            return Route(p, channel); +        }       +      } +    } +*/     +     +  } +   +  printf("  name2route: <%s> not found\n", rn.latin1()); +  return Route((Track*) 0, channel); +  //return Route((Track*) 0, channel, 1); +}  //---------------------------------------------------------  //   checkRoute @@ -281,44 +977,95 @@ bool checkRoute(const QString& s, const QString& d)        if (!(src.isValid() && dst.isValid()) || (src == dst))              return false; -      if (src.type == JACK_ROUTE) { -            if (dst.type != TRACK_ROUTE) { -                  return false; -                  } -            if (dst.track->type() != Track::AUDIO_INPUT) { -                  return false; -                  } -            src.channel = dst.channel; -            RouteList* inRoutes = dst.track->inRoutes(); -            for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { -                  if (*i == src) {   // route already there -                        return false; -                        } -                  } +      if (src.type == Route::JACK_ROUTE)  +      { +            //if (dst.type != TRACK_ROUTE) { +            //      return false; +            //      } +             +            if (dst.type == Route::TRACK_ROUTE)  +            { +              if (dst.track->type() != Track::AUDIO_INPUT) { +                    return false; +                    } +              src.channel = dst.channel; +              RouteList* inRoutes = dst.track->inRoutes(); +              for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  +              { +                    if (*i == src) {   // route already there +                          return false; +                          } +              }              } -      else if (dst.type == JACK_ROUTE) { -            if (src.type != TRACK_ROUTE) { -                  return false; -                  } -            if (src.track->type() != Track::AUDIO_OUTPUT) { -                  return false; -                  } -            RouteList* outRoutes = src.track->outRoutes(); -            dst.channel = src.channel; -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { -                  if (*i == dst) {   // route already there -                        return false; -                        } -                  } +            else +            //if (dst.type == Route::JACK_MIDI_ROUTE)  +            if (dst.type == Route::MIDI_DEVICE_ROUTE)  +            { +              //src.channel = dst.channel; +              src.channel = -1; +              //dst.channel = -1; +              RouteList* routes = dst.device->inRoutes(); +              for (iRoute i = routes->begin(); i != routes->end(); ++i)  +              { +                    if (*i == src) {   // route already there +                          return false; +                          } +              }              } -      else { -            RouteList* outRoutes = src.track->outRoutes(); -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { +            else +              return false; +      }   +      else if (dst.type == Route::JACK_ROUTE)  +      { +            //if (src.type != TRACK_ROUTE) { +            //      return false; +            //      } +             +            if (src.type == Route::TRACK_ROUTE)  +            { +              if (src.track->type() != Track::AUDIO_OUTPUT) { +                    return false; +                    } +              RouteList* outRoutes = src.track->outRoutes(); +              dst.channel = src.channel; +              for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +              { +                    if (*i == dst) {   // route already there +                          return false; +                          } +              } +            } +            else +            //if (src.type == Route::JACK_MIDI_ROUTE)  +            if (src.type == Route::MIDI_DEVICE_ROUTE)  +            { +              RouteList* routes = src.device->outRoutes(); +              //dst.channel = src.channel; +              dst.channel = -1; +              //src.channel = -1; +              for (iRoute i = routes->begin(); i != routes->end(); ++i)  +              { +                    if (*i == dst) {   // route already there +                          return false; +                          } +              } +            } +            else +              return false; +      }   +      else  +      { +            //RouteList* outRoutes = ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) ?  +            //                       src.device->outRoutes() : src.track->outRoutes(); +            RouteList* outRoutes = (src.type == Route::MIDI_DEVICE_ROUTE) ? src.device->outRoutes() : src.track->outRoutes(); +             +            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +            {                    if (*i == dst) {   // route already there                          return false;                          } -                  }              } +      }        return true;        } @@ -326,47 +1073,201 @@ bool checkRoute(const QString& s, const QString& d)  //   read  //--------------------------------------------------------- -void Song::readRoute(Xml& xml) +void Route::read(Xml& xml) +{ +      QString s; +      int dtype = MidiDevice::ALSA_MIDI; +       +      //channel        = -1; +      //channels       = -1; +      //remoteChannel  = -1; +      type = Route::TRACK_ROUTE; +      track = 0; +       +      for (;;)         { +            const QString& tag = xml.s1(); +            Xml::Token token = xml.parse(); +            switch (token)  +            { +                  case Xml::Error: +                  case Xml::End: +                        return; +                  //case Xml::TagStart: +                  //        xml.unknown("Route"); +                  //      break; +                  case Xml::Attribut: +                        #ifdef ROUTE_DEBUG +                        printf("Route::read(): attribute:%s\n", tag.latin1()); +                        #endif +                        if(tag == "type") +                          type = xml.s2().toInt(); +                        else +                        if(tag == "devtype") +                        { +                          dtype = xml.s2().toInt(); +                          type = Route::MIDI_DEVICE_ROUTE; +                        } +                        //else +                        //if(tag == "channel") +                        //  channel = xml.s2().toInt(); +                        //else +                        //if(tag == "channels") +                        //  channels = xml.s2().toInt(); +                        //else +                        //if(tag == "remch") +                        //  remoteChannel = xml.s2().toInt(); +                        else +                        if(tag == "name") +                          s = xml.s2(); +                        else   +                          printf("Route::read(): unknown attribute:%s\n", tag.latin1()); +                        break; +                  case Xml::TagEnd: +                        #ifdef ROUTE_DEBUG +                        printf("Route::read(): tag end type:%d channel:%d name:%s\n", type, channel, s.latin1()); +                        #endif +                        if(!s.isEmpty()) +                        { +                          if(type == TRACK_ROUTE)  +                          { +                            track = 0; +                            TrackList* tl = song->tracks(); +                            for (iTrack i = tl->begin(); i != tl->end(); ++i)  +                            { +                              Track* t = *i; +                              if (t->name() == s)  +                              { +                                track = t; +                                break; +                              } +                            } +                            if(track == 0) +                              printf("Route::read(): track <%s> not found\n", s.latin1()); +                          } +                          else +                          if(type == JACK_ROUTE)  +                          { +                            jackPort = audioDevice->findPort(s); +                            if(jackPort == 0) +                              printf("Route::read(): jack port <%s> not found\n", s.latin1()); +                          } +                          else +                          //if((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE)) +                          if(type == MIDI_DEVICE_ROUTE) +                          { +                            device = 0; +                            for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)  +                            { +                              MidiDevice* md = *imd; +                              //if(md->name() == s)  +                              if(md->name() == s && md->deviceType() == dtype)  +                              { +                                device = md; +                                break; +                              } +                            } +                            if(device == 0) +                              printf("Route::read(): midi device <%s> not found\n", s.latin1()); +                          } +                        } +                        return; +                  default: +                        break; +            } +      } +} + + +//--------------------------------------------------------- +//   read +//--------------------------------------------------------- + +void Song::readRoute(Xml& xml) +{        QString src;        QString dst; +      int ch        = -1; +      int chs       = -1; +      int remch     = -1; -      for (;;) { +      Route sroute, droute; +       +      for (;;)  +      {              const QString& tag = xml.s1();              Xml::Token token = xml.parse(); -            switch (token) { +            switch (token)  +            {                    case Xml::Error:                    case Xml::End:                          return;                    case Xml::TagStart: +                        // p3.3.38 2010/02/03 Support old routes in med files. Now obsolete!                          if (tag == "srcNode")                                src = xml.parse1();                          else if (tag == "dstNode")                                dst = xml.parse1(); +                        // Support new routes. +                        else if (tag == "source") +                        { +                              sroute.read(xml); +                              sroute.channel       = ch; +                              sroute.channels      = chs; +                              sroute.remoteChannel = remch; +                        } +                        else if (tag == "dest") +                        { +                              droute.read(xml); +                              droute.channel       = ch; +                              droute.channels      = chs; +                              droute.remoteChannel = remch; +                        }                                else                                xml.unknown("readRoute");                          break; +                  case Xml::Attribut: +                        #ifdef ROUTE_DEBUG +                        printf("Song::readRoute(): attribute:%s\n", tag.latin1()); +                        #endif +                        if(tag == "channel") +                          ch = xml.s2().toInt(); +                        else +                        if(tag == "channels") +                          chs = xml.s2().toInt(); +                        else +                        if(tag == "remch") +                          remch = xml.s2().toInt(); +                        else   +                          printf("Song::readRoute(): unknown attribute:%s\n", tag.latin1()); +                        break;                    case Xml::TagEnd: -                        if (xml.s1() == "Route") { -                               -                              if(!src.isEmpty() && !dst.isEmpty()) -                              { -                                 -                                Route s = name2route(src, false); -                                Route d = name2route(dst, true); -                                addRoute(s, d); -                               -                              }   -                              else -                                printf("  Warning - route name missing. Ignoring route!\n"); -                               -                              return; -                              } +                        if (xml.s1() == "Route")  +                        { +                          // Support old routes in med files. Now obsolete! +                          if(!src.isEmpty() && !dst.isEmpty()) +                          { +                            Route s = name2route(src, false); +                            Route d = name2route(dst, true); +                            addRoute(s, d); +                          }   +                          else +                          // Support new routes. +                          if(sroute.isValid() && droute.isValid()) +                          {     +                            //printf("adding new route...\n"); +                            addRoute(sroute, droute); +                          } +                          else +                            printf("  Warning - route invalid. Ignoring route!\n"); +                           +                          return; +                        }                    default:                          break; -                  } -            } +             }        } +}  //---------------------------------------------------------  //   removeRoute @@ -388,30 +1289,156 @@ void RouteList::removeRoute(const Route& r)  //---------------------------------------------------------  void Route::dump() const +{ +      if (type == TRACK_ROUTE) +      { +        if(track) +          printf("Route dump: track <%s> channel %d channels %d\n", track->name().latin1(), channel, channels); +          //printf("Route dump: track <%s> channel %d\n", track->name().latin1(), channel); +        //else   +        //  printf("Route dump: invalid track, channel %d\n", channel); +      }       +      else  +      if (type == JACK_ROUTE) +      { +        if(checkAudioDevice()) +          printf("Route dump: jack audio port <%s> channel %d\n", audioDevice->portName(jackPort).latin1(), channel); +      } +      else +      if (type == MIDI_DEVICE_ROUTE) +      { +        printf("Route dump: "); +        if(device) +        { +          if(device->deviceType() == MidiDevice::JACK_MIDI) +          { +            if(checkAudioDevice()) +              printf("jack midi port device <%s> ", audioDevice->portName(device->clientPort()).latin1()); +          } +          else +          if(device->deviceType() == MidiDevice::ALSA_MIDI) +            printf("alsa midi device <%s> ", device->name().latin1()); +          else +          if(device->deviceType() == MidiDevice::SYNTH_MIDI) +            printf("synth midi device <%s> ", device->name().latin1()); +          else +            printf("is midi but unknown device type:%d, ", device->deviceType()); +        } +        else +          printf("is midi but invalid device, "); +           +        printf("channel:%d\n", channel); +      } +      /* +      else  +      if (type == JACK_MIDI_ROUTE)        { -      if (type == 0) -            printf("Route dump: track <%s> channel %d\n", track->name().latin1(), channel); -      else {              if (!checkAudioDevice()) return; -            printf("Route dump: jPort <%s> channel %d\n", -               audioDevice->portName(jackPort).latin1(), channel); -            } +            printf("Route dump: jMidiPort <%s>\n", +               audioDevice->portName(device->clientPort()).latin1());        } +      else  +      if (type == ALSA_MIDI_ROUTE) +      { +            // TODO +            //if (!checkAudioDevice()) return; +            //printf("Route dump: aMidiPort <%s>\n", +            //   audioDevice->portName(device->clientJackPort()).latin1()); +            printf("Route dump: aMidiPort\n"); +      } +      */ +      else +        printf("Route dump: unknown route type:%d\n", type); +}  //---------------------------------------------------------  //   operator==  //---------------------------------------------------------  bool Route::operator==(const Route& a) const +{ +      if ((type == a.type) && (channel == a.channel))  +      //if (type == a.type)         { -      if ((type == a.type) && (channel == a.channel)) { -            if (type == 0) -                  return track == a.track; -            else { -                  if (!checkAudioDevice()) return false; -                  return audioDevice->portName(jackPort) == audioDevice->portName(a.jackPort); -                  } +            if (type == TRACK_ROUTE) +            { +                  //return track == a.track; +                  //return track == a.track && remoteChannel == a.remoteChannel; +                  return track == a.track && channels == a.channels && remoteChannel == a.remoteChannel; +                   +                  /* +                  if(a.track == track && a.remoteChannel == remoteChannel) +                  { +                    int tcompch = rt.channel; +                    if(tcompch == -1) +                      tcompch = 0; +                    int tcompchs = rt.channels; +                    if(tcompchs == -1) +                      tcompchs = isOutput ? t->channels() : track->channels(); +                     +                    int compch = ir->channel; +                    if(compch == -1) +                      compch = 0; +                    int compchs = ir->channels; +                    if(compchs == -1) +                      compchs = isOutput ? t->channels() : ir->track->channels(); +                     +                    if(compch == tcompch && compchs == tcompchs)  +                    { +                      chpup->setItemChecked(id, true); +                      break; +                    } +                  }   +                  */ +                                } -      return false; +            else  +            if(channel == a.channel) +            { +              if (type == JACK_ROUTE) +              { +                    if (!checkAudioDevice()) return false; +                    return audioDevice->portName(jackPort) == audioDevice->portName(a.jackPort); +              } +              else  +              if (type == MIDI_DEVICE_ROUTE) +              { +                //if(device) +                if(device && a.device && device->deviceType() == a.device->deviceType()) +                { +                  if(device->deviceType() == MidiDevice::JACK_MIDI) +                  { +                    if (!checkAudioDevice()) return false; +                    return audioDevice->portName(device->clientPort()) == audioDevice->portName(a.device->clientPort()); +                  } +                  else +                  if(device->deviceType() == MidiDevice::ALSA_MIDI) +                    // TODO: OK ??  +                    return device->clientPort() == a.device->clientPort() && (channel == a.channel); +                  else +                  if(device->deviceType() == MidiDevice::SYNTH_MIDI) +                    return device->name() == a.device->name(); +                }     +              } +               +              /* +              if (type == JACK_MIDI_ROUTE) +              { +                if (!checkAudioDevice()) return false; +                return audioDevice->portName(device->clientPort()) == audioDevice->portName(a.device->clientPort()); +              } +              else +              if (type == ALSA_MIDI_ROUTE) +              { +                    // TODO +                    //if (!checkAudioDevice()) return false; +                    //return audioDevice->portName(device->clientJackPort()) == audioDevice->portName(a.device->clientJackPort()); +                    //return device->name() == a.device->name(); +                    return device->clientPort() == a.device->clientPort() && (channel == a.channel); +              } +              */ +            }            } +      return false; +} diff --git a/muse/muse/route.h b/muse/muse/route.h index ba40bb06..d8217207 100644 --- a/muse/muse/route.h +++ b/muse/muse/route.h @@ -9,34 +9,69 @@  #ifndef __ROUTE_H__  #define __ROUTE_H__ +//#include <alsa/asoundlib.h>  #include <vector> +#include <map>  class QString; -class AudioTrack; +//class AudioTrack; +class Track; +//class MidiJackDevice; +class MidiDevice; +class Xml;  //---------------------------------------------------------  //   Route  //--------------------------------------------------------- -enum { TRACK_ROUTE=0, JACK_ROUTE=1 }; +//enum { TRACK_ROUTE=0, JACK_ROUTE=1 };  struct Route { +      //enum { TRACK_ROUTE=0, JACK_ROUTE=1, JACK_MIDI_ROUTE=2, ALSA_MIDI_ROUTE=3 }; +      enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2 }; +              union { -            AudioTrack* track; +            //AudioTrack* track; +            Track* track; +            //MidiJackDevice* device; +            MidiDevice* device;              void* jackPort;              }; +       +      //snd_seq_addr_t alsaAdr; +       +      // Starting source channel (of the owner of this route). Normally zero for mono or stereo tracks, higher for multi-channel tracks.         int channel; -      unsigned char type;     // 0 - track, 1 - jackPort +      // Number of channels being routed.  +      int channels; +       +      // Allow for multi-channel syntis to feed to/from regular tracks, and to feed one to another.  +      // If a synti is feeding to/from a regular track, remoteChannel is the 'starting' channel of this multi-channel synti. +      // If a synti is feeding to/from another synti, this is not used and individual channels are routed using channel instead. +      int remoteChannel; +       +      unsigned char type;     // 0 - track, 1 - jackPort, 2 - jack midi device, 3 - alsa midi device        Route(void* t, int ch=-1); -      Route(AudioTrack* t, int ch); -      Route(const QString&, bool dst, int ch); +      //Route(AudioTrack* t, int ch); +      //Route(Track* t, int ch); +      Route(Track* t, int ch = -1, int chans = -1); +      //Route(Track* t, int ch = -1); +       +      //Route(MidiJackDevice* d); +      Route(MidiDevice* d, int ch); +      //Route(const QString&, bool dst, int ch); +      Route(const QString&, bool dst, int ch, int rtype = -1);        Route();        QString name() const;        bool operator==(const Route& a) const;        bool isValid() const { -            return ((type == 0) && (track != 0)) || ((type == 1) && (jackPort != 0)); +            //return ((type == 0) && (track != 0)) || ((type == 1) && (jackPort != 0)); +            return ((type == TRACK_ROUTE) && (track != 0)) || ((type == JACK_ROUTE) && (jackPort != 0)) ||  +                   //(((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE)) && (device != 0)); +                   ((type == MIDI_DEVICE_ROUTE) && (device != 0));              } +      void read(Xml& xml);        void dump() const;        }; @@ -54,8 +89,25 @@ typedef RouteList::const_iterator ciRoute;  extern void addRoute(Route, Route);  extern void removeRoute(Route, Route); -extern Route name2route(const QString&, bool dst); +//extern Route name2route(const QString&, bool dst); +extern Route name2route(const QString&, bool dst, int rtype = -1);  extern bool checkRoute(const QString&, const QString&); +//--------------------------------------------------------- +//   RouteMenuMap +//--------------------------------------------------------- + +//struct TRouteMenuMap{ +//       Route r; +//       }; +//typedef std::map<int, TRouteMenuMap, std::less<int> >::iterator iRouteMenuMap; +//typedef std::map<int, TRouteMenuMap, std::less<int> >::const_iterator ciRouteMenuMap; +//typedef std::map<int, TRouteMenuMap, std::less<int> > RouteMenuMap; +typedef std::map<int, Route, std::less<int> >::iterator iRouteMenuMap; +typedef std::map<int, Route, std::less<int> >::const_iterator ciRouteMenuMap; +typedef std::map<int, Route, std::less<int> > RouteMenuMap; +typedef std::pair<int, Route> pRouteMenuMap; +typedef std::pair<iRouteMenuMap, bool > rpRouteMenuMap; +  #endif diff --git a/muse/muse/seqmsg.cpp b/muse/muse/seqmsg.cpp index 42227305..02fbdf01 100644 --- a/muse/muse/seqmsg.cpp +++ b/muse/muse/seqmsg.cpp @@ -21,6 +21,7 @@  #include "alsamidi.h"  #include "audio.h"  #include "arranger.h" +#include "driver/jackmidi.h"  //---------------------------------------------------------  //   sendMsg @@ -72,14 +73,58 @@ bool Audio::sendMessage(AudioMsg* m, bool doUndo)  //---------------------------------------------------------  void Audio::msgRemoveRoute(Route src, Route dst) -      { +{        msgRemoveRoute1(src, dst); -      if (!checkAudioDevice()) return; -      if (src.type == JACK_ROUTE) +      //if (!checkAudioDevice()) return; +      if (src.type == Route::JACK_ROUTE) +      { +          if (!checkAudioDevice()) return; +           +          //if(dst.type == Route::JACK_MIDI_ROUTE)   +          if(dst.type == Route::MIDI_DEVICE_ROUTE)   +          { +            //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(dst.device); +            //if(jmd) +            if(dst.device) +            { +              if(dst.device->deviceType() == MidiDevice::JACK_MIDI) +                audioDevice->disconnect(src.jackPort, dst.device->clientPort()); +              //else +              //{ +                // TODO... +                //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(dst.device); +                //if(amd) +              //}   +            } +          } +          else                audioDevice->disconnect(src.jackPort, ((AudioInput*)dst.track)->jackPort(dst.channel)); -      else if (dst.type == JACK_ROUTE) +      } +      else if (dst.type == Route::JACK_ROUTE) +      { +          if (!checkAudioDevice()) return; +           +          //if(src.type == Route::JACK_MIDI_ROUTE)   +          if(src.type == Route::MIDI_DEVICE_ROUTE)   +          { +            //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(src.device); +            //if(jmd) +            if(src.device) +            { +              if(src.device->deviceType() == MidiDevice::JACK_MIDI) +                audioDevice->disconnect(src.device->clientPort(), dst.jackPort); +              //else +              //{ +                // TODO... +                //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(src.device); +                //if(amd) +              //} +            }   +          } +          else                audioDevice->disconnect(((AudioOutput*)src.track)->jackPort(src.channel), dst.jackPort);        } +}  //---------------------------------------------------------  //   msgRemoveRoute1 @@ -100,16 +145,58 @@ void Audio::msgRemoveRoute1(Route src, Route dst)  void Audio::msgAddRoute(Route src, Route dst)        { -      if (src.type == JACK_ROUTE) { +      if (src.type == Route::JACK_ROUTE)  +      {              if (!checkAudioDevice()) return;              if (isRunning()) +            { +                //if(dst.type == Route::JACK_MIDI_ROUTE)   +                if(dst.type == Route::MIDI_DEVICE_ROUTE)   +                { +                  //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(dst.device); +                  //if(jmd) +                  if(dst.device) +                  { +                    if(dst.device->deviceType() == MidiDevice::JACK_MIDI)   +                      audioDevice->connect(src.jackPort, dst.device->clientPort()); +                    //else +                    //{ +                      // TODO... +                      //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(dst.device); +                      //if(amd) +                    //} +                  }   +                } +                else                      audioDevice->connect(src.jackPort, ((AudioInput*)dst.track)->jackPort(dst.channel)); -            } -      else if (dst.type == JACK_ROUTE) { +            }       +      } +      else if (dst.type == Route::JACK_ROUTE)  +      {              if (!checkAudioDevice()) return;              if (audio->isRunning()) +            { +                //if(src.type == Route::JACK_MIDI_ROUTE)   +                if(src.type == Route::MIDI_DEVICE_ROUTE)   +                { +                  //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(src.device); +                  //if(jmd) +                  if(src.device) +                  { +                    if(src.device->deviceType() == MidiDevice::JACK_MIDI)   +                      audioDevice->connect(src.device->clientPort(), dst.jackPort); +                    //else +                    //{ +                      // TODO... +                      //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(src.device); +                      //if(amd) +                    //} +                  }   +                } +                else                      audioDevice->connect(((AudioOutput*)src.track)->jackPort(dst.channel), dst.jackPort); -            } +            }       +      }        msgAddRoute1(src, dst);        } @@ -203,57 +290,117 @@ void Audio::msgSetChannels(AudioTrack* node, int n)        QString name = node->name();        int mc       = std::max(n, node->channels()); -      if (!name.isEmpty()) { -            if (node->type() == Track::AUDIO_INPUT) { -                  if (!checkAudioDevice()) return; -                  AudioInput* ai = (AudioInput*)node; -                  for (int i = 0; i < mc; ++i) { -                        if (i < n && ai->jackPort(i) == 0) { -                              char buffer[128]; -                              snprintf(buffer, 128, "%s-%d", name.latin1(), i); -                              //ai->setJackPort(i, audioDevice->registerInPort(buffer)); -                              ai->setJackPort(i, audioDevice->registerInPort(buffer, false)); -                              } -                        else if ((i >= n) && ai->jackPort(i)) { -                              RouteList* ir = node->inRoutes(); -                              for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) { -                                    Route r = *ii; -                                    if ((r.type == JACK_ROUTE) && (r.channel == i)) { -                                          msgRemoveRoute(r, Route(node,i)); -                                          break; -                                          } -                                    } -                              audioDevice->unregisterPort(ai->jackPort(i)); -                              ai->setJackPort(i, 0); -                              } -                        } +      if (!name.isEmpty())  +      { +            if (node->type() == Track::AUDIO_INPUT)  +            { +              if (!checkAudioDevice()) return; +              AudioInput* ai = (AudioInput*)node; +              for (int i = 0; i < mc; ++i)  +              { +                if (i < n && ai->jackPort(i) == 0)  +                { +                  char buffer[128]; +                  snprintf(buffer, 128, "%s-%d", name.latin1(), i); +                  //ai->setJackPort(i, audioDevice->registerInPort(buffer)); +                  ai->setJackPort(i, audioDevice->registerInPort(buffer, false)); +                } +                else if ((i >= n) && ai->jackPort(i))  +                { +                  RouteList* ir = node->inRoutes(); +                  for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)  +                  { +                    Route r = *ii; +                    if ((r.type == Route::JACK_ROUTE) && (r.channel == i))  +                    { +                      msgRemoveRoute(r, Route(node,i)); +                      break; +                    }                    } -            else if (node->type() == Track::AUDIO_OUTPUT) { +                  audioDevice->unregisterPort(ai->jackPort(i)); +                  ai->setJackPort(i, 0); +                } +              }       +            } +            else if (node->type() == Track::AUDIO_OUTPUT)  +            {                    if (!checkAudioDevice()) return;                    AudioOutput* ao = (AudioOutput*)node; -                  for (int i = 0; i < mc; ++i) { +                  for (int i = 0; i < mc; ++i)  +                  {                          void* jp = ao->jackPort(i); -                        if (i < n && jp == 0) { +                        if (i < n && jp == 0)  +                        {                                char buffer[128];                                snprintf(buffer, 128, "%s-%d", name.latin1(), i);                                //ao->setJackPort(i, audioDevice->registerOutPort(buffer));                                ao->setJackPort(i, audioDevice->registerOutPort(buffer, false)); -                              } -                        else if (i >= n && jp) { +                        } +                        else if (i >= n && jp)  +                        {                                RouteList* ir = node->outRoutes(); -                              for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) { +                              for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)  +                              {                                      Route r = *ii; -                                    if ((r.type == JACK_ROUTE) && (r.channel == i)) { +                                    if ((r.type == Route::JACK_ROUTE) && (r.channel == i))  +                                    {                                            msgRemoveRoute(Route(node,i), r);                                            break; -                                          }                                      } +                              }                                audioDevice->unregisterPort(jp);                                ao->setJackPort(i, 0); -                              }                          }                    }              } +      }       +       +      /* TODO TODO: Change all stereo routes to mono.  +      // If we are going from stereo to mono we need to disconnect any stray synti 'mono last channel'... +      if(n == 1 && node->channels() > 1) +      { +        // This should always happen - syntis are fixed channels, user cannot change them. But to be safe... +        if(node->type() != Track::AUDIO_SOFTSYNTH)  +        { +          if(node->type() != Track::AUDIO_INPUT)  +          { +            RouteList* rl = node->inRoutes(); +            for(iRoute r = rl->begin(); r != rl->end(); ++r) +            { +              // Only interested in synth tracks. +              if(r->type != Route::TRACK_ROUTE || r->track->type() != Track::AUDIO_SOFTSYNTH) +                continue;   +              // If it's the last channel... +              if(r->channel + 1 == ((AudioTrack*)r->track)->totalOutChannels()) +              { +                msgRemoveRoute(*r, Route(node, r->channel)); +                //msgRemoveRoute(r, Route(node, r->remoteChannel)); +                break; +              } +            } +          }   +         +          if(node->type() != Track::AUDIO_OUTPUT)  +          { +            RouteList* rl = node->outRoutes(); +            for(iRoute r = rl->begin(); r != rl->end(); ++r) +            { +              // Only interested in synth tracks. +              if(r->type != Route::TRACK_ROUTE || r->track->type() != Track::AUDIO_SOFTSYNTH) +                continue;   +              // If it's the last channel... +              if(r->channel + 1 == ((AudioTrack*)r->track)->totalOutChannels()) +              { +                msgRemoveRoute(Route(node, r->channel), *r); +                //msgRemoveRoute(Route(node, r->remoteChannel), r); +                break; +              } +            } +          }   +        }    +      } +      */         +                      AudioMsg msg;        msg.id    = AUDIO_SET_CHANNELS;        msg.snode = node; diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index 7b1e46bb..fa08f27f 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -14,6 +14,8 @@  #include <qpopupmenu.h>  #include <qdir.h>  #include <qaction.h> +#include <qcursor.h> +#include <qbutton.h>  #include "app.h"  #include "song.h" @@ -42,6 +44,26 @@ extern void clearMidiTransforms();  extern void clearMidiInputTransforms();  Song* song; +/* +//--------------------------------------------------------- +//   RoutingMenuItem +//--------------------------------------------------------- + +class RoutingMenuItem : public QCustomMenuItem  +{ +      Route route; +      //virtual QSize sizeHint() { return QSize(80, h); } +      virtual void paint(QPainter* p, const QColorGroup&, bool, bool, int x, int y, int w, int h) +      { +        p->fillRect(x, y, w, h, QBrush(lightGray)); +        p->drawText(x, y, w, h, AlignCenter, route.name()); +      } + +   public: +      RoutingMenuItem(const Route& r) : route(r) { } +}; +*/ +  //---------------------------------------------------------  //   Song  //--------------------------------------------------------- @@ -235,10 +257,16 @@ Track* Song::addTrack(int t)                    case Track::AUDIO_GROUP:                    case Track::AUDIO_AUX:                    case Track::AUDIO_INPUT: -                  case Track::AUDIO_SOFTSYNTH: +                  // p3.3.38 +                  //case Track::AUDIO_SOFTSYNTH:                          audio->msgAddRoute(Route((AudioTrack*)track, -1), Route(ao, -1));                          updateFlags |= SC_ROUTE;                          break; +                  // p3.3.38 It should actually never get here now, but just in case. +                  case Track::AUDIO_SOFTSYNTH: +                        audio->msgAddRoute(Route((AudioTrack*)track, 0, ((AudioTrack*)track)->channels()), Route(ao, 0, ((AudioTrack*)track)->channels())); +                        updateFlags |= SC_ROUTE; +                        break;                    }              }        audio->msgUpdateSoloStates(); @@ -853,7 +881,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start                    }              newPart->setLenTick(endTick); // endTick - part->tick() -            // Added by Tim. p3.3.6              //printf("Song::cmdAddRecordedEvents before changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());              // Change the part. @@ -866,7 +893,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start              // Now add all of the new part's port controller values, and do all clone parts.              addPortCtrlEvents(newPart, true); -            // Added by Tim. p3.3.6              //printf("Song::cmdAddRecordedEvents after changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());              //undoOp(UndoOp::ModifyPart, part, newPart); @@ -877,7 +903,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start              //part->events()->incARef(-1);              updateFlags |= SC_PART_MODIFIED; -            // Added by Tim. p3.3.6              //printf("Song::cmdAddRecordedEvents final part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());              */ @@ -1123,7 +1148,7 @@ void Song::setPlay(bool f)        {        if (extSyncFlag.value()) {            if (debugMsg) -          printf("not allowed while using external sync"); +            printf("not allowed while using external sync");            return;        }        // only allow the user to set the button "on" @@ -1137,7 +1162,7 @@ void Song::setStop(bool f)        {        if (extSyncFlag.value()) {            if (debugMsg) -          printf("not allowed while using external sync"); +            printf("not allowed while using external sync");            return;        }        // only allow the user to set the button "on" @@ -1857,7 +1882,6 @@ void Song::cmdRemovePart(Part* part)  //void Song::cmdChangePart(Part* oldPart, Part* newPart)  void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClones)        { -      // Added by Tim. p3.3.6        //printf("Song::cmdChangePart before changePart oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());        if(doCtrls) @@ -1875,7 +1899,6 @@ void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClon        //oldPart->replaceClone(newPart); -      // Added by Tim. p3.3.6        //printf("Song::cmdChangePart before repl/unchClone oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());        replaceClone(oldPart, newPart); @@ -1883,7 +1906,6 @@ void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClon        if(doCtrls)          addPortCtrlEvents(newPart, doClones); -      // Added by Tim. p3.3.6        //printf("Song::cmdChangePart after repl/unchClone oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());        updateFlags = SC_PART_MODIFIED; @@ -2028,6 +2050,20 @@ void Song::cleanupForQuit()          // Remove the controllers and the values.          midiPorts[i].controller()->clearDelete(true); +      // Can't do this here. Jack isn't running. +      /* +      if(debugMsg) +        printf("deleting midi devices\n"); +      for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) +      { +        // Since Syntis are midi devices, there's no need to delete them below. +        if((*imd)->isSynti()) +          continue; +        delete (*imd); +      } +      midiDevices.clear();     // midi devices +      */ +              if(debugMsg)          printf("deleting synths\n");        // Delete all synths. @@ -2385,7 +2421,6 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo      dctl |= drumMap[note].anote;    } -  // Added by Tim. p3.3.6    //printf("Song::execMidiAutomationCtlPopup ctlnum:%d dctl:%d anote:%d\n", ctlnum, dctl, drumMap[ctlnum & 0x7f].anote);    unsigned tick = cpos(); @@ -2428,7 +2463,6 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo          ev = i->second;          if(ev.type() == Controller)          { -          // Added by Tim. p3.3.6            //printf("Song::execMidiAutomationCtlPopup ev.dataA:%d\n", ev.dataA());            //if(ev.dataA() == dctl) @@ -2651,7 +2685,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)                          for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)                          {                              Route r = *ii; -                            if ((r.type == JACK_ROUTE) && (r.channel == ch)) +                            if ((r.type == Route::JACK_ROUTE) && (r.channel == ch))                              {                                      if(disconnect)                                      audioDevice->disconnect(ao->jackPort(ch), r.jackPort); @@ -2684,7 +2718,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)                              for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)                              {                                  Route r = *ii; -                                if ((r.type == JACK_ROUTE) && (r.channel == ch)) +                                if ((r.type == Route::JACK_ROUTE) && (r.channel == ch))                                  {                                          if(disconnect)                                          audioDevice->disconnect(r.jackPort, ai->jackPort(ch)); @@ -2708,6 +2742,199 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)  }  //--------------------------------------------------------- +//   chooseMidiRoutes +//--------------------------------------------------------- + +void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst) +{ +  if(!track) +    return; +     +  //if(!track->isMidiTrack()) +  //  return; +   +  //if(dst) +  //{ +    // TODO +     +  //} +  //else +  //{ +    RouteList* rl = dst ? track->outRoutes() : track->inRoutes(); +    //Route dst(track, -1); +   +    QPopupMenu* pup = new QPopupMenu(parent); +    pup->setCheckable(true); +     +    int gid = 0; +     +    //MidiInPortList* tl = song->midiInPorts(); +    //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)  +    for(int i = 0; i < MIDI_PORTS; ++i) +    { +      //MidiInPort* track = *i; +      // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports. +      MidiPort* mp = &midiPorts[i]; +      MidiDevice* md = mp->device(); +      if(!md) +        continue; +       +      if(!(md->rwFlags() & (dst ? 1 : 2))) +        continue; +         +      //printf("MidiStrip::iRoutePressed adding submenu portnum:%d\n", i); +       +      //QMenu* m = menu->addMenu(track->name()); +      QPopupMenu* subp = new QPopupMenu(parent); +       +      for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +      { +        //QAction* a = m->addAction(QString("Channel %1").arg(ch+1)); +        //subp->insertItem(QT_TR_NOOP(QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch); +        gid = i * MIDI_CHANNELS + ch; +         +        //printf("MidiStrip::iRoutePressed inserting gid:%d\n", gid); +         +        subp->insertItem(QString("Channel %1").arg(ch+1), gid); +        //a->setCheckable(true); +        //Route src(track, ch, RouteNode::TRACK); +        //Route src(md, ch); +        //Route r = Route(src, dst); +        //a->setData(QVariant::fromValue(r)); +        //a->setChecked(rl->indexOf(r) != -1); +        Route srcRoute(md, ch); +        for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)  +        { +          //if(*ir == dst)  +          if(*ir == srcRoute)  +          { +            subp->setItemChecked(gid, true); +            break; +          } +        } +      } +      pup->insertItem(QT_TR_NOOP(md->name()), subp); +    } +         +    /* +    QPopupMenu* pup = new QPopupMenu(iR); +    pup->setCheckable(true); +    //MidiTrack* t = (MidiTrack*)track; +    RouteList* irl = track->inRoutes(); + +    MidiTrack* t = (MidiTrack*)track; +    int gid = 0; +    for (int i = 0; i < channel; ++i)  +    { +          char buffer[128]; +          snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1); +          MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); +          pup->insertItem(titel); + +          if (!checkAudioDevice()) return; +          std::list<QString> ol = audioDevice->outputPorts(); +          for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) { +                int id = pup->insertItem(*ip, (gid * 16) + i); +                Route dst(*ip, true, i); +                ++gid; +                for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) { +                      if (*ir == dst) { +                            pup->setItemChecked(id, true); +                            break; +                            } +                      } +                } +          if (i+1 != channel) +                pup->insertSeparator(); +    } +    */ +     +    if(pup->count() == 0) +    { +      delete pup; +      return; +    } +     +    int n = pup->exec(QCursor::pos()); +    delete pup; +    if (n != -1)  +    { +          int mdidx = n / MIDI_CHANNELS; +          int ch = n % MIDI_CHANNELS; +           +          //if(debugMsg) +            //printf("Song::chooseMidiRoutes mdidx:%d ch:%d\n", mdidx, ch); +             +          MidiPort* mp = &midiPorts[mdidx]; +          MidiDevice* md = mp->device(); +          if(!md) +            return; +           +          //if(!(md->rwFlags() & 2)) +          if(!(md->rwFlags() & (dst ? 1 : 2))) +            return; +             +           +          //QString s(pup->text(n)); +          //QT_TR_NOOP(md->name()) +           +          //Route srcRoute(s, false, -1); +          Route aRoute(md, ch); +          //Route srcRoute(md, -1); +          //Route dstRoute(track, -1); +          Route bRoute(track, ch); + +          //if (track->type() == Track::AUDIO_INPUT) +          //      srcRoute.channel = dstRoute.channel = n & 0xf; +          iRoute iir = rl->begin(); +          for (; iir != rl->end(); ++iir)  +          { +            //if(*iir == (dst ? bRoute : aRoute)) +            if(*iir == aRoute) +                  break; +          } +          if (iir != rl->end())  +          { +                // disconnect +                if(dst) +                { +                  //printf("Song::chooseMidiRoutes removing route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1()); +                  audio->msgRemoveRoute(bRoute, aRoute); +                } +                else +                { +                  //printf("Song::chooseMidiRoutes removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1()); +                  audio->msgRemoveRoute(aRoute, bRoute); +                } +          } +          else  +          { +            // connect +            if(dst) +            { +              //printf("Song::chooseMidiRoutes adding route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1()); +              audio->msgAddRoute(bRoute, aRoute); +            } +            else +            { +              //printf("Song::chooseMidiRoutes adding route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1()); +              audio->msgAddRoute(aRoute, bRoute); +            }   +          } +           +          //printf("Song::chooseMidiRoutes calling msgUpdateSoloStates\n"); +          audio->msgUpdateSoloStates(); +          //printf("Song::chooseMidiRoutes calling song->update\n"); +          song->update(SC_ROUTE); +    } +    //delete pup; +    parent->setDown(false);     // pup->exec() catches mouse release event +    //printf("Song::chooseMidiRoutes end\n"); +     +  //}   +} + +//---------------------------------------------------------  //   insertTrack0  //--------------------------------------------------------- @@ -2725,7 +2952,6 @@ void Song::insertTrack0(Track* track, int idx)  void Song::insertTrack1(Track* track, int /*idx*/)        { -      // Added by Tim. p3.3.13        //printf("Song::insertTrack1 track:%lx\n", track);        switch(track->type()) { @@ -2742,7 +2968,6 @@ void Song::insertTrack1(Track* track, int /*idx*/)                    break;              } -      // Added by Tim. p3.3.13        //printf("Song::insertTrack1 end of function\n");        } @@ -2753,8 +2978,7 @@ void Song::insertTrack1(Track* track, int /*idx*/)  //---------------------------------------------------------  void Song::insertTrack2(Track* track, int idx) -      { -      // Added by Tim. p3.3.13 +{        //printf("Song::insertTrack2 track:%lx\n", track);        int n; @@ -2805,11 +3029,9 @@ void Song::insertTrack2(Track* track, int idx)        // initialize missing aux send        //        iTrack i = _tracks.index2iterator(idx); -      // Added by Tim. p3.3.13        //printf("Song::insertTrack2 inserting into _tracks...\n");        _tracks.insert(i, track); -      // Added by Tim. p3.3.13        //printf("Song::insertTrack2 inserted\n");        n = _auxs.size(); @@ -2822,6 +3044,7 @@ void Song::insertTrack2(Track* track, int idx)                    }              } +      /*        //        //  add routes        // @@ -2848,11 +3071,51 @@ void Song::insertTrack2(Track* track, int idx)              for (ciRoute r = rl->begin(); r != rl->end(); ++r)                    r->track->inRoutes()->push_back(src);              } +      */ -      // Added by Tim. p3.3.13 -      //printf("Song::insertTrack2 end of function\n"); +      // p3.3.38 +      // +      //  add routes +      // + +      if (track->type() == Track::AUDIO_OUTPUT)  +      { +            const RouteList* rl = track->inRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->outRoutes()->push_back(*r); +            }       +      } +      else if (track->type() == Track::AUDIO_INPUT)  +      { +            const RouteList* rl = track->outRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->inRoutes()->push_back(*r); +            }              } +      else  +      { +            const RouteList* rl = track->inRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->outRoutes()->push_back(*r); +            } +            rl = track->outRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->inRoutes()->push_back(*r); +            }       +      } +       +      //printf("Song::insertTrack2 end of function\n"); +       +}  //---------------------------------------------------------  //   insertTrack3 @@ -2861,7 +3124,6 @@ void Song::insertTrack2(Track* track, int idx)  void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning: unused parameter        { -      // Added by Tim. p3.3.13        //printf("Song::insertTrack3\n");        /* @@ -2932,7 +3194,7 @@ void Song::removeTrack1(Track* track)  //---------------------------------------------------------  void Song::removeTrack2(Track* track) -      { +{        switch(track->type()) {              case Track::MIDI:              case Track::DRUM: @@ -2970,6 +3232,9 @@ void Song::removeTrack2(Track* track)                    break;              }        _tracks.erase(track); +       +       +      /*        if (track->isMidiTrack())              return;        // @@ -2996,7 +3261,49 @@ void Song::removeTrack2(Track* track)              for (ciRoute r = rl->begin(); r != rl->end(); ++r)                    r->track->inRoutes()->removeRoute(src);              } +      */       +       +      // p3.3.38 +       +      // +      //  remove routes +      // + +      if (track->type() == Track::AUDIO_OUTPUT)  +      { +            const RouteList* rl = track->inRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->outRoutes()->removeRoute(*r); +            }              } +      else if (track->type() == Track::AUDIO_INPUT)  +      { +            const RouteList* rl = track->outRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->inRoutes()->removeRoute(*r); +            }       +      } +      else  +      { +            const RouteList* rl = track->inRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->outRoutes()->removeRoute(*r); +            } +            rl = track->outRoutes(); +            for (ciRoute r = rl->begin(); r != rl->end(); ++r) +            { +                  if(r->track == track) +                    r->track->inRoutes()->removeRoute(*r); +            }       +      } +       +}  //---------------------------------------------------------  //   removeTrack3 diff --git a/muse/muse/song.h b/muse/muse/song.h index 0e08d8ab..6c76362b 100644 --- a/muse/muse/song.h +++ b/muse/muse/song.h @@ -36,6 +36,7 @@ class MarkerList;  class Marker;  class SNode;  class QPopupMenu; +class QButton;  class MidiPort;  class MidiDevice; @@ -301,6 +302,7 @@ class Song : public QObject {        int execMidiAutomationCtlPopup(MidiTrack*, MidiPart*, const QPoint&, int);        void connectJackRoutes(AudioTrack* track, bool disconnect);        void updateSoloStates(); +      void chooseMidiRoutes(QButton* /*parent*/, MidiTrack* /*track*/, bool /*dst*/);        //-----------------------------------------        //   undo, redo diff --git a/muse/muse/songfile.cpp b/muse/muse/songfile.cpp index 2e4a5395..07bf1e31 100644 --- a/muse/muse/songfile.cpp +++ b/muse/muse/songfile.cpp @@ -29,6 +29,7 @@  #include "midictrl.h"  #include "amixer.h"  #include "conf.h" +#include "driver/jackmidi.h"  //struct ClonePart {        //const EventList* el; @@ -1428,12 +1429,25 @@ void Song::write(int level, Xml& xml) const        // write routing        for (ciTrack i = _tracks.begin(); i != _tracks.end(); ++i) { -            if ((*i)->isMidiTrack()) -                  continue; -            WaveTrack* track = (WaveTrack*)(*i); -            track->writeRouting(level, xml); +             +            // p3.3.38 Changed +            //if ((*i)->isMidiTrack()) +            //      continue; +            //WaveTrack* track = (WaveTrack*)(*i); +            //track->writeRouting(level, xml); +             +            (*i)->writeRouting(level, xml);              } +      // Write Jack midi routing. +      for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) { +            //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i); +            //if (!mjd) +            //  continue; +            //mjd->writeRouting(level, xml); +            (*i)->writeRouting(level, xml); +            } +              tempomap.write(level, xml);        sigmap.write(level, xml);        _markerList->write(level, xml); diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp index 6b8e959c..0fbfa144 100644 --- a/muse/muse/sync.cpp +++ b/muse/muse/sync.cpp @@ -18,6 +18,7 @@  #include "audiodev.h"  #include "gconfig.h"  #include "xml.h" +#include "midi.h"  //int rxSyncPort = -1;         // receive from all ports  //int txSyncPort = 1; @@ -26,7 +27,7 @@  //MidiSyncPort midiSyncPorts[MIDI_PORTS];  int volatile curMidiSyncInPort = -1; -bool debugSync = false; +bool debugSync = true;  int mtcType     = 1;  MTC mtcOffset; @@ -880,10 +881,10 @@ void MidiSeq::realtimeSystemInput(int port, int c)        MidiPort* mp = &midiPorts[port];        // Trigger on any tick, clock, or realtime command.  -      if(c == 0xf9) // Tick +      if(c == ME_TICK) // Tick          mp->syncInfo().trigTickDetect();        else -      if(c == 0xf8) // Clock +      if(c == ME_CLOCK) // Clock          mp->syncInfo().trigMCSyncDetect();        else            mp->syncInfo().trigMRTDetect(); // Other @@ -891,7 +892,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)        // External sync not on? Clock in not turned on? Otherwise realtime in not turned on?        if(!extSyncFlag.value())          return; -      if(c == 0xf8) +      if(c == ME_CLOCK)        {           if(!mp->syncInfo().MCIn())            return;  @@ -902,7 +903,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)        switch(c) { -            case 0xf8:  // midi clock (24 ticks / quarter note) +            case ME_CLOCK:  // midi clock (24 ticks / quarter note)                    {                    // Not for the current in port? Forget it.                    if(port != curMidiSyncInPort) @@ -1194,7 +1195,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                    }                    break; -            case 0xf9:  // midi tick  (every 10 msec) +            case ME_TICK:  // midi tick  (every 10 msec)                    // FIXME: Unfinished? mcStartTick is uninitialized and Song::setPos doesn't set it either. Dangerous to allow this.                    //if (mcStart) {                    //      song->setPos(0, mcStartTick); @@ -1202,7 +1203,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                    //      return;                    //      }                    break; -            case 0xfa:  // start +            case ME_START:  // start                    // Re-transmit start to other devices if clock out turned on.                    for(int p = 0; p < MIDI_PORTS; ++p)                      //if(p != port && midiPorts[p].syncInfo().MCOut()) @@ -1259,7 +1260,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          playStateExt = true;                          }                    break; -            case 0xfb:  // continue +            case ME_CONTINUE:  // continue                    // Re-transmit continue to other devices if clock out turned on.                    for(int p = 0; p < MIDI_PORTS; ++p)                      //if(p != port && midiPorts[p].syncInfo().MCOut()) @@ -1286,7 +1287,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          playStateExt = true;                          }                    break; -            case 0xfc:  // stop +            case ME_STOP:  // stop                    {                      // p3.3.35                      // Stop the increment right away. @@ -1326,10 +1327,11 @@ void MidiSeq::realtimeSystemInput(int port, int c)                    }                    break; -            case 0xfd:  // unknown -            case 0xfe:  // active sensing -            case 0xff:  // system reset -                  break; +            //case 0xfd:  // unknown +            //case ME_SENSE:  // active sensing +            //case ME_META:  // system reset (reset is 0xff same enumeration as file meta event) +            default: +                  break;                    }        } diff --git a/muse/muse/synth.cpp b/muse/muse/synth.cpp index e3bf1582..24780a52 100644 --- a/muse/muse/synth.cpp +++ b/muse/muse/synth.cpp @@ -126,12 +126,12 @@ static Synth* findSynth(const QString& sclass, const QString& label)        }  //--------------------------------------------------------- -//   createSynthI +//   createSynthInstance  //    create a synthesizer instance of class "label"  //---------------------------------------------------------  //static SynthI* createSynthI(const QString& sclass) -static SynthI* createSynthI(const QString& sclass, const QString& label) +static SynthI* createSynthInstance(const QString& sclass, const QString& label)        {        //Synth* s = findSynth(sclass);        Synth* s = findSynth(sclass, label); @@ -149,7 +149,7 @@ static SynthI* createSynthI(const QString& sclass, const QString& label)                    }              }        else -            printf("synthi class:%s label:%s not found\n", sclass.latin1(), label.latin1()); +            printf("createSynthInstance: synthi class:%s label:%s not found\n", sclass.latin1(), label.latin1());        return si;        } @@ -300,6 +300,16 @@ int MessSynthIF::channels() const        return _mess->channels();        } +int MessSynthIF::totalOutChannels() const +      { +      return _mess->channels(); +      } + +int MessSynthIF::totalInChannels() const +      { +      return 0; +      } +  //SynthIF* MessSynth::createSIF() const  SynthIF* MessSynth::createSIF(SynthI* si)        { @@ -327,8 +337,11 @@ bool SynthI::initInstance(Synth* s, const QString& instanceName)        setIName(instanceName);   // set instrument name        _sif        = s->createSIF(this); -      AudioTrack::setChannels(_sif->channels()); - +      // p3.3.38 +      //AudioTrack::setChannels(_sif->channels()); +      AudioTrack::setTotalOutChannels(_sif->totalOutChannels()); +      AudioTrack::setTotalInChannels(_sif->totalInChannels()); +              //---------------------------------------------------        //  read available controller from synti        //--------------------------------------------------- @@ -531,36 +544,38 @@ void initMidiSynth()  //SynthI* Song::createSynthI(const QString& sclass)  SynthI* Song::createSynthI(const QString& sclass, const QString& label)        { -      // Added by Tim. p3.3.13        //printf("Song::createSynthI calling ::createSynthI class:%s\n", sclass.latin1());        //SynthI* si = ::createSynthI(sclass); -      SynthI* si = ::createSynthI(sclass, label); +      //SynthI* si = ::createSynthI(sclass, label); +      SynthI* si = createSynthInstance(sclass, label);        if(!si)          return 0; -      // Added by Tim. p3.3.13        //printf("Song::createSynthI created SynthI. Before insertTrack1...\n");        insertTrack1(si, -1); -      // Added by Tim. p3.3.13        //printf("Song::createSynthI after insertTrack1. Before msgInsertTrack...\n");        msgInsertTrack(si, -1, true);       // add to instance list -      // Added by Tim. p3.3.13        //printf("Song::createSynthI after msgInsertTrack. Before insertTrack3...\n");        insertTrack3(si, -1); -      // Added by Tim. p3.3.13        //printf("Song::createSynthI after insertTrack3. Adding default routes...\n");        OutputList* ol = song->outputs();        // add default route to master (first audio output)        if (!ol->empty()) {              AudioOutput* ao = ol->front(); -            audio->msgAddRoute(Route(si, -1), Route(ao, -1)); +            // p3.3.38 +            //audio->msgAddRoute(Route(si, -1), Route(ao, -1)); +            //audio->msgAddRoute(Route((AudioTrack*)si, -1), Route(ao, -1)); +            // Make sure the route channel and channels are valid. +            audio->msgAddRoute(Route((AudioTrack*)si, 0, ((AudioTrack*)si)->channels()), Route(ao, 0, ((AudioTrack*)si)->channels())); +                          audio->msgUpdateSoloStates();              } +              return si;        } diff --git a/muse/muse/synth.h b/muse/muse/synth.h index 7132e227..87584a53 100644 --- a/muse/muse/synth.h +++ b/muse/muse/synth.h @@ -118,6 +118,8 @@ class SynthIF {        //virtual bool init(Synth* s) = 0;        virtual int channels() const = 0; +      virtual int totalOutChannels() const = 0; +      virtual int totalInChannels() const = 0;        virtual void deactivate3() = 0;        virtual const char* getPatchName(int, int, int, bool) const = 0;        virtual const char* getPatchName(int, int, MType, bool) = 0; @@ -169,6 +171,8 @@ class SynthI : public AudioTrack, public MidiDevice,        //SynthI* clone() const { return new SynthI(*this); }        SynthI* clone(bool /*cloneParts*/) const { return new SynthI(*this); } +      virtual inline int deviceType() { return SYNTH_MIDI; }  +              SynthIF* sif() const { return _sif; }        bool initInstance(Synth* s, const QString& instanceName); @@ -237,6 +241,8 @@ class MessSynthIF : public SynthIF {        bool init(Synth* s, SynthI* si);        virtual int channels() const; +      virtual int totalOutChannels() const; +      virtual int totalInChannels() const;        virtual void deactivate3();        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool); diff --git a/muse/muse/ticksynth.cpp b/muse/muse/ticksynth.cpp index acbdfb3e..2cd0ae82 100644 --- a/muse/muse/ticksynth.cpp +++ b/muse/muse/ticksynth.cpp @@ -74,6 +74,8 @@ class MetronomeSynthIF : public SynthIF        //virtual bool init(Synth*) { return true; }        virtual int channels() const { return 1; } +      virtual int totalOutChannels() const { return 1; } +      virtual int totalInChannels() const { return 0; }        virtual void deactivate3() {}        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool) { return ""; } diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp index 1580f180..6f6f11a8 100644 --- a/muse/muse/track.cpp +++ b/muse/muse/track.cpp @@ -6,6 +6,9 @@  //  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)  //========================================================= +#include <qt.h> +#include <qstring.h> +  #include "track.h"  #include "event.h"  #include "mididev.h" @@ -367,8 +370,8 @@ MidiTrack::MidiTrack(const MidiTrack& mt, bool cloneParts)        {        _outPort       = mt.outPort();        _outChannel    = mt.outChannel(); -      _inPortMask    = mt.inPortMask(); -      _inChannelMask = mt.inChannelMask(); +      ///_inPortMask    = mt.inPortMask(); +      ///_inChannelMask = mt.inChannelMask();        _events        = new EventList;        _mpevents      = new MPEventList;        transposition  = mt.transposition; @@ -395,9 +398,9 @@ void MidiTrack::init()        _outChannel    = 0;        // Changed by Tim. p3.3.8        //_inPortMask    = 0xffff; -      _inPortMask    = 0xffffffff; +      ///_inPortMask    = 0xffffffff; -      _inChannelMask = 0xffff;      // "ALL" +      ///_inChannelMask = 0xffff;      // "ALL"        transposition  = 0;        velocity       = 0;        delay          = 0; @@ -648,6 +651,123 @@ bool Track::readProperties(Xml& xml, const QString& tag)        }  //--------------------------------------------------------- +//   writeRouting +//--------------------------------------------------------- + +void Track::writeRouting(int level, Xml& xml) const +{ +      QString s; +       +      if (type() == Track::AUDIO_INPUT)  +      { +        const RouteList* rl = &_inRoutes; +        for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        { +          if(!r->name().isEmpty()) +          { +            s = QT_TR_NOOP("Route"); +            if(r->channel != -1) +              s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); +             +            ///Route dst(name(), true, r->channel); +            //xml.tag(level++, "Route"); +            xml.tag(level++, s); +             +            // p3.3.38 New routing scheme. +            ///xml.strTag(level, "srcNode", r->name()); +            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +            s = QT_TR_NOOP("source"); +            if(r->type != Route::TRACK_ROUTE) +              s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); +            s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); +            xml.tag(level, s); +             +            ///xml.strTag(level, "dstNode", dst.name()); +             +            //if(r->channel != -1) +            //  xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1()); +            //else   +            //  xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, name().latin1()); +            xml.tag(level, "dest name=\"%s\"/", name().latin1()); +             +            xml.etag(level--, "Route"); +          } +        } +      } +       +      const RouteList* rl = &_outRoutes; +      for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +      { +        if(!r->name().isEmpty()) +        { +          ///QString src(name()); +          ///if (type() == Track::AUDIO_OUTPUT)  +          ///{  +                ///Route s(src, false, r->channel); +                ///src = s.name(); +          ///} +           +          s = QT_TR_NOOP("Route"); +          if(r->channel != -1) +            s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel); +          if(r->channels != -1) +            s += QString(QT_TR_NOOP(" channels=\"%1\"")).arg(r->channels); +          if(r->remoteChannel != -1) +            s += QString(QT_TR_NOOP(" remch=\"%1\"")).arg(r->remoteChannel); +           +          //xml.tag(level++, "Route"); +          xml.tag(level++, s); +           +          ///xml.strTag(level, "srcNode", src); +          //if(r->channel != -1) +           +          // Allow for a regular mono or stereo track to feed a multi-channel synti.  +          // thisChannel is the 'starting' channel of this source if feeding a regular track. +          //if(r->type == Route::TRACK_ROUTE && r->track->isSynti() && r->channel != -1) +          //if(isSynti() && r->thisChannel != -1) +            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1()); +          //  xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->thisChannel, name().latin1()); +          //else +           +          //if(r->channel != -1) +          //  xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1()); +          //else   +          //  xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, name().latin1()); +          xml.tag(level, "source name=\"%s\"/", name().latin1()); +           +          ///xml.strTag(level, "dstNode", r->name()); +          //if(r->channel != -1) +          //  xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1()); +          //else   +          //  xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +           +          // Allow for a regular mono or stereo track to feed a multi-channel synti.  +          // Channel is the 'starting' channel of the destination. +          //if(r->type == Route::TRACK_ROUTE && r->track->isSynti() && r->channel != -1) +           +          //if(r->type == Route::TRACK_ROUTE && r->track->type() == Track::AUDIO_SOFTSYNTH && r->remoteChannel != -1) +          //  xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->remoteChannel, r->name().latin1()); +          //else   +          //if(r->type == Route::MIDI_DEVICE_ROUTE) +          //  xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1()); +          //else   +          //  xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1()); +           +          s = QT_TR_NOOP("dest"); +          if(r->type == Route::MIDI_DEVICE_ROUTE) +            s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType()); +          else +          if(r->type != Route::TRACK_ROUTE) +            s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type); +          s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name()); +          xml.tag(level, s); +           +          xml.etag(level--, "Route"); +        } +      } +} +        +//---------------------------------------------------------  //   MidiTrack::write  //--------------------------------------------------------- @@ -665,8 +785,8 @@ void MidiTrack::write(int level, Xml& xml) const        xml.intTag(level, "device", outPort());        xml.intTag(level, "channel", outChannel());        //xml.intTag(level, "inportMap", inPortMask()); -      xml.uintTag(level, "inportMap", inPortMask()); -      xml.intTag(level, "inchannelMap", inChannelMask()); +      ///xml.uintTag(level, "inportMap", inPortMask());       // Obsolete +      ///xml.intTag(level, "inchannelMap", inChannelMask());  // Obsolete        xml.intTag(level, "locked", _locked);        xml.intTag(level, "echo", _recEcho); @@ -721,9 +841,11 @@ void MidiTrack::read(Xml& xml)                                setOutChannel(xml.parseInt());                          else if (tag == "inportMap")                                //setInPortMask(xml.parseInt()); -                              setInPortMask(xml.parseUInt()); +                              ///setInPortMask(xml.parseUInt()); +                              xml.skip(tag);                      // Obsolete                          else if (tag == "inchannelMap") -                              setInChannelMask(xml.parseInt()); +                              ///setInChannelMask(xml.parseInt()); +                              xml.skip(tag);                      // Obsolete                          else if (tag == "locked")                                _locked = xml.parseInt();                          else if (tag == "echo") diff --git a/muse/muse/track.h b/muse/muse/track.h index 6f06c923..9449fd1b 100644 --- a/muse/muse/track.h +++ b/muse/muse/track.h @@ -51,6 +51,9 @@ class Track {        static bool _tmpSoloChainDoIns;        static bool _tmpSoloChainNoDec; +      // p3.3.38 +      RouteList _inRoutes; +      RouteList _outRoutes;        QString _name;        bool _recordFlag; @@ -115,6 +118,13 @@ class Track {        TrackType type() const          { return _type; }        void setType(TrackType t)       { _type = t; } +      // routing +      RouteList* inRoutes()    { return &_inRoutes; } +      RouteList* outRoutes()   { return &_outRoutes; } +      bool noInRoute() const   { return _inRoutes.empty();  } +      bool noOutRoute() const  { return _outRoutes.empty(); } +      void writeRouting(int, Xml&) const; +        PartList* parts()               { return &_parts; }        const PartList* cparts() const  { return &_parts; }        Part* findPart(unsigned tick); @@ -184,8 +194,8 @@ class MidiTrack : public Track {        int _outPort;        int _outChannel;        //int _inPortMask;         -      unsigned int _inPortMask; // bitmask of accepted record ports -      int _inChannelMask;     // bitmask of accepted record channels +      ///unsigned int _inPortMask; // bitmask of accepted record ports +      ///int _inChannelMask;     // bitmask of accepted record channels        bool _recEcho;          // For midi (and audio). Whether to echo incoming record events to output device.        EventList* _events;     // tmp Events during midi import @@ -227,14 +237,14 @@ class MidiTrack : public Track {        void setOutChanAndUpdate(int i);        void setOutPortAndUpdate(int i);        //void setInPortMask(int i)       { _inPortMask = i; } -      void setInPortMask(unsigned int i) { _inPortMask = i; } -      void setInChannelMask(int i)    { _inChannelMask = i; } +      ///void setInPortMask(unsigned int i) { _inPortMask = i; } +      ///void setInChannelMask(int i)    { _inChannelMask = i; }        void setRecEcho(bool b)         { _recEcho = b; }        int outPort() const             { return _outPort;     }        //int inPortMask() const          { return _inPortMask;  } -      unsigned int inPortMask() const { return _inPortMask;  } +      ///unsigned int inPortMask() const { return _inPortMask;  }        int outChannel() const          { return _outChannel;  } -      int inChannelMask() const       { return _inChannelMask; } +      ///int inChannelMask() const       { return _inChannelMask; }        bool recEcho() const            { return _recEcho; }        virtual bool isMute() const; @@ -269,8 +279,8 @@ class AudioTrack : public Track {        AutomationType _automationType; -      RouteList _inRoutes; -      RouteList _outRoutes; +      //RouteList _inRoutes; +      //RouteList _outRoutes;        bool _sendMetronome; @@ -278,8 +288,11 @@ class AudioTrack : public Track {        void readAuxSend(Xml& xml);     protected: -      //float** outBuffers; -      float* outBuffers[MAX_CHANNELS];   +      float** outBuffers; +      //float* outBuffers[MAX_CHANNELS];   +      int _totalOutChannels; +      int _totalInChannels; +              unsigned bufferPos;        virtual bool getData(unsigned, int, unsigned, float**);        SndFile* _recFile; @@ -288,6 +301,8 @@ class AudioTrack : public Track {     public:        AudioTrack(TrackType t); +      //AudioTrack(TrackType t, int num_out_bufs = MAX_CHANNELS);  +              //AudioTrack(const AudioTrack&);        AudioTrack(const AudioTrack&, bool cloneParts);        virtual ~AudioTrack(); @@ -317,6 +332,10 @@ class AudioTrack : public Track {        CtrlListList* controller()         { return &_controller; }        virtual void setChannels(int n); +      virtual void setTotalOutChannels(int num); +      virtual int totalOutChannels() { return _totalOutChannels; } +      virtual void setTotalInChannels(int num); +      virtual int totalInChannels() { return _totalInChannels; }        virtual bool isMute() const;        virtual void setSolo(bool val); @@ -355,19 +374,19 @@ class AudioTrack : public Track {        void setPluginCtrlVal(int param, double val);        void readVolume(Xml& xml); -      void writeRouting(int, Xml&) const; +      //void writeRouting(int, Xml&) const;        // routing -      RouteList* inRoutes()    { return &_inRoutes; } -      RouteList* outRoutes()   { return &_outRoutes; } -      bool noInRoute() const   { return _inRoutes.empty();  } -      bool noOutRoute() const  { return _outRoutes.empty(); } +      //RouteList* inRoutes()    { return &_inRoutes; } +      //RouteList* outRoutes()   { return &_outRoutes; } +      //bool noInRoute() const   { return _inRoutes.empty();  } +      //bool noOutRoute() const  { return _outRoutes.empty(); }        virtual void preProcessAlways() { _processed = false; } -      virtual void addData(unsigned, int, unsigned, float**); -      virtual void copyData(unsigned, int, unsigned, float**); +      virtual void  addData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/); +      virtual void copyData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/);        virtual bool hasAuxSend() const { return false; } - +              // automation        virtual AutomationType automationType() const    { return _automationType; }        virtual void setAutomationType(AutomationType t); diff --git a/muse/muse/vst.cpp b/muse/muse/vst.cpp index 945bc2e9..194e1993 100644 --- a/muse/muse/vst.cpp +++ b/muse/muse/vst.cpp @@ -473,6 +473,18 @@ int VstSynthIF::channels() const        return plugin->numOutputs;        } +int VstSynthIF::totalOutChannels() const +      { +      AEffect* plugin = _fst->plugin; +      return plugin->numOutputs; +      } + +int VstSynthIF::totalInChannels() const +      { +      AEffect* plugin = _fst->plugin; +      return plugin->numInputs; +      } +  //---------------------------------------------------------  //   createSIF  //--------------------------------------------------------- diff --git a/muse/muse/vst.h b/muse/muse/vst.h index 1caef0fc..33eaaab3 100644 --- a/muse/muse/vst.h +++ b/muse/muse/vst.h @@ -61,6 +61,8 @@ class VstSynthIF : public SynthIF        virtual int eventsPending() const { return 0; }        virtual bool init(Synth*);        virtual int channels() const; +      virtual int totalOutChannels() const; +      virtual int totalInChannels() const;        virtual void deactivate3();        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool) { return ""; } diff --git a/muse/muse/wavetrack.cpp b/muse/muse/wavetrack.cpp index fbf7b965..c4fe7071 100644 --- a/muse/muse/wavetrack.cpp +++ b/muse/muse/wavetrack.cpp @@ -197,10 +197,39 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float*        if ((song->bounceTrack != this) && !noInRoute()) {              RouteList* irl = inRoutes();              iRoute i = irl->begin(); -            i->track->copyData(framePos, channels, nframe, bp); +            if(i->track->isMidiTrack()) +            { +              if(debugMsg) +                printf("WaveTrack::getData: Error: First route is a midi track route!\n"); +              return false; +            } +            // p3.3.38 +            //((AudioTrack*)i->track)->copyData(framePos, channels, nframe, bp); +            ((AudioTrack*)i->track)->copyData(framePos, channels,  +                                              //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,  +                                              i->channel,  +                                              i->channels, +                                              nframe, bp); +                          ++i;              for (; i != irl->end(); ++i) -                  i->track->addData(framePos, channels, nframe, bp); +            { +              if(i->track->isMidiTrack()) +              { +                if(debugMsg) +                  printf("WaveTrack::getData: Error: Route is a midi track route!\n"); +                //return false; +                continue; +              } +              // p3.3.38 +              //((AudioTrack*)i->track)->addData(framePos, channels, nframe, bp); +              ((AudioTrack*)i->track)->addData(framePos, channels,  +                                               //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,  +                                               i->channel,  +                                               i->channels, +                                               nframe, bp); +               +            }              if (recordFlag()) {                    if (audio->isRecording() && recFile()) {                          if (audio->freewheel()) { diff --git a/muse/muse/widgets/mtrackinfobase.ui b/muse/muse/widgets/mtrackinfobase.ui index cf753252..3d2b274a 100644 --- a/muse/muse/widgets/mtrackinfobase.ui +++ b/muse/muse/widgets/mtrackinfobase.ui @@ -95,7 +95,7 @@                  <set>AlignCenter | WordBreak</set>              </property>          </widget> -        <widget class="SpinBox" row="8" column="0"> +        <widget class="SpinBox" row="7" column="0">              <property name="name">                  <cstring>iLen</cstring>              </property> @@ -136,81 +136,29 @@                  <string>output port</string>              </property>          </widget> -        <widget class="QLayoutWidget" row="2" column="1"> +        <widget class="QLabel" row="2" column="1">            <property name="name"> -            <cstring>oPortsLayout</cstring> +            <cstring>TextLabel2</cstring> +          </property> +          <property name="sizePolicy"> +            <sizepolicy> +              <hsizetype>5</hsizetype> +              <vsizetype>0</vsizetype> +              <horstretch>0</horstretch> +              <verstretch>0</verstretch> +            </sizepolicy> +          </property> +          <property name="margin"> +            <number>0</number> +          </property> +          <property name="indent"> +            <number>1</number> +          </property> +          <property name="text"> +            <string>Out ch</string>            </property> -          <hbox> -            <widget class="QLabel"> -                <property name="name"> -                    <cstring>TextLabel2</cstring> -                </property> -                <property name="sizePolicy"> -                    <sizepolicy> -                        <hsizetype>5</hsizetype> -                        <vsizetype>0</vsizetype> -                        <horstretch>0</horstretch> -                        <verstretch>0</verstretch> -                    </sizepolicy> -                </property> -                <property name="margin"> -                    <number>0</number> -                </property> -                <property name="indent"> -                  <number>1</number> -                </property> -                <property name="text"> -                    <string>OCh</string> -                </property> -            </widget> -            <widget class="QToolButton"> -              <property name="name"> -                <cstring>recEchoButton</cstring> -              </property> -              <property name="maximumSize"> -                <size> -                  <width>14</width> -                  <height>32767</height> -                </size> -              </property> -              <property name="sizePolicy"> -                <sizepolicy> -                  <hsizetype>1</hsizetype> -                  <vsizetype>1</vsizetype> -                  <horstretch>0</horstretch> -                  <verstretch>0</verstretch> -                </sizepolicy> -              </property> -              <property name="toggleButton"> -                <string>true</string> -              </property> -              <property name="whatsThis" stdset="0"> -                <string>Echo recording events to output.</string> -              </property> -              <property name="toolTip" stdset="0"> -                <string>Echo</string> -              </property> -            </widget> -            <spacer> -              <property name="name"> -                <cstring>recEchoSpacer</cstring> -              </property> -              <property name="orientation"> -                <enum>Horizontal</enum> -              </property> -              <property name="sizeType"> -                <enum>Minimum</enum> -              </property> -              <property name="sizeHint"> -                <size> -                  <width>2</width> -                  <height>2</height> -                </size> -              </property> -            </spacer> -          </hbox>          </widget> -        <widget class="SpinBox" row="7" column="0"> +        <widget class="SpinBox" row="6" column="0">              <property name="name">                  <cstring>iVerz</cstring>              </property> @@ -232,7 +180,7 @@                  <number>-1000</number>              </property>          </widget> -        <widget class="SpinBox" row="9" column="0"> +        <widget class="SpinBox" row="8" column="0">              <property name="name">                  <cstring>iAnschl</cstring>              </property> @@ -254,7 +202,7 @@                  <number>0</number>              </property>          </widget> -        <widget class="SpinBox" row="10" column="0"> +        <widget class="SpinBox" row="9" column="0">              <property name="name">                  <cstring>iKompr</cstring>              </property> @@ -282,7 +230,7 @@                  <number>100</number>              </property>          </widget> -        <widget class="SpinBox" row="6" column="0"> +        <widget class="SpinBox" row="5" column="0">              <property name="name">                  <cstring>iTransp</cstring>              </property> @@ -307,7 +255,7 @@                  <number>1</number>              </property>          </widget> -        <widget class="QLabel" row="6" column="1"> +        <widget class="QLabel" row="5" column="1">              <property name="name">                  <cstring>TextLabel9</cstring>              </property> @@ -326,7 +274,7 @@                <number>2</number>              </property>          </widget> -        <widget class="QLabel" row="7" column="1"> +        <widget class="QLabel" row="6" column="1">              <property name="name">                  <cstring>TextLabel10</cstring>              </property> @@ -345,7 +293,7 @@                <number>2</number>              </property>          </widget> -        <widget class="QLabel" row="10" column="1"> +        <widget class="QLabel" row="9" column="1">              <property name="name">                  <cstring>TextLabel13</cstring>              </property> @@ -364,7 +312,7 @@                <number>2</number>              </property>          </widget> -        <widget class="QLabel" row="9" column="1"> +        <widget class="QLabel" row="8" column="1">              <property name="name">                  <cstring>TextLabel12</cstring>              </property> @@ -383,7 +331,7 @@                <number>0</number>              </property>          </widget> -        <widget class="QLabel" row="8" column="1"> +        <widget class="QLabel" row="7" column="1">              <property name="name">                  <cstring>TextLabel11</cstring>              </property> @@ -402,135 +350,131 @@                <number>2</number>              </property>          </widget> -        <widget class="QLineEdit" row="3" column="0"> +        <widget class="QLayoutWidget" row="3" column="0">              <property name="name"> -                <cstring>iInput</cstring> +                <cstring>routingLayout</cstring>              </property> -            <property name="sizePolicy"> -                <sizepolicy> -                    <hsizetype>7</hsizetype> -                    <vsizetype>0</vsizetype> +            <hbox> +              <widget class="QToolButton"> +                <property name="name"> +                  <cstring>iRButton</cstring> +                </property> +                <property name="sizePolicy"> +                  <sizepolicy> +                    <hsizetype>1</hsizetype> +                    <vsizetype>1</vsizetype>                      <horstretch>0</horstretch>                      <verstretch>0</verstretch> -                </sizepolicy> -            </property> -            <property name="whatsThis" stdset="0"> -              <string>Events from all configured ports are -recorded to this track. -You can specify more than one port for -recording: -   1 2 3    record from port 1 2 and 3 -   1-3      same -   1-3 5    record from port 1 2 3 and 5</string> -            </property> -            <property name="toolTip" stdset="0"> -                <string>input ports</string> -            </property> -        </widget> -        <widget class="QLabel" row="3" column="1"> -          <property name="name"> -            <cstring>iPortsTextLabel</cstring> -          </property> -          <property name="sizePolicy"> -            <sizepolicy> -              <hsizetype>0</hsizetype> -              <vsizetype>0</vsizetype> -              <horstretch>0</horstretch> -              <verstretch>0</verstretch> -            </sizepolicy> -          </property> -          <property name="margin"> -            <number>0</number> -          </property> -          <property name="indent"> -            <number>2</number> -          </property> -          <property name="text"> -            <string>IPorts</string> -          </property> -        </widget> -        <widget class="QLayoutWidget" row="4" column="1"> -            <property name="name"> -                <cstring>iChLayout</cstring> -            </property> -            <hbox> -              <widget class="QLabel"> -                  <property name="name"> -                      <cstring>iChanTextLabel</cstring> -                  </property> -                  <property name="sizePolicy"> -                      <sizepolicy> -                          <hsizetype>0</hsizetype> -                          <vsizetype>0</vsizetype> -                          <horstretch>0</horstretch> -                          <verstretch>0</verstretch> -                      </sizepolicy> -                  </property> -                  <property name="margin"> -                      <number>0</number> -                  </property> -                  <property name="indent"> -                    <number>2</number> -                  </property> -                  <property name="text"> -                      <string>ICh</string> -                  </property> +                  </sizepolicy> +                </property> +                <property name="text"> +                  <string>iR</string> +                </property> +                <property name="toolTip" stdset="0"> +                  <string>input routing</string> +                </property>                </widget> -              <widget class="QLabel"> +              <widget class="QToolButton">                  <property name="name"> -                  <cstring>iChanDetectLabel</cstring> +                  <cstring>oRButton</cstring>                  </property>                  <property name="sizePolicy">                    <sizepolicy> -                    <hsizetype>5</hsizetype> -                    <vsizetype>0</vsizetype> +                    <hsizetype>1</hsizetype> +                    <vsizetype>1</vsizetype>                      <horstretch>0</horstretch>                      <verstretch>0</verstretch>                    </sizepolicy>                  </property>                  <property name="text"> -                  <string>W</string> -                </property> -                <property name="alignment"> -                  <set>AlignCenter</set> +                  <string>oR</string>                  </property>                  <property name="toolTip" stdset="0"> -                  <string>input detect</string> -                </property> -                <property name="whatsThis" stdset="0"> -                  <string>Input detect indicator. Detects all note on-off, controller, aftertouch,  -                    program change, and pitchbend (but not sysex or realtime) events  -                    on the selected channels, on the selected midi ports.</string> +                  <string>output routing</string>                  </property>                </widget>              </hbox>          </widget> -        <widget class="QLineEdit" row="4" column="0"> -            <property name="name"> -                <cstring>iInputChannel</cstring> -            </property> -            <property name="sizePolicy"> +        <widget class="QLayoutWidget" row="3" column="1"> +          <property name="name"> +            <cstring>routingLayout2</cstring> +          </property> +          <hbox> +            <widget class="QLabel"> +              <property name="name"> +                <cstring>iChanDetectLabel</cstring> +              </property> +              <property name="sizePolicy">                  <sizepolicy> -                    <hsizetype>5</hsizetype> -                    <vsizetype>0</vsizetype> -                    <horstretch>0</horstretch> -                    <verstretch>0</verstretch> +                  <hsizetype>5</hsizetype> +                  <vsizetype>0</vsizetype> +                  <horstretch>0</horstretch> +                  <verstretch>0</verstretch>                  </sizepolicy> -            </property> -            <property name="toolTip" stdset="0"> -                <string>input channels</string> -            </property> -            <property name="whatsThis" stdset="0"> -                <string>Events from all configured channels are -recorded to this track. -You can specify more than one channel for -recording: -   1 2 3    record from channel 1 2 and 3 -   1-3      same -   1-3 5    record from channel 1 2 3 and 5</string> -            </property> +              </property> +              <property name="text"> +                <string>W</string> +              </property> +              <property name="alignment"> +                <set>AlignCenter</set> +              </property> +              <property name="toolTip" stdset="0"> +                <string>input detect</string> +              </property> +              <property name="whatsThis" stdset="0"> +                <string>Input detect indicator. Detects all note on-off, controller, aftertouch,  +                  program change, and pitchbend (but not sysex or realtime) events  +                  on the selected channels, on the selected midi ports.</string> +              </property> +            </widget> +            <widget class="QToolButton"> +              <property name="name"> +                <cstring>recEchoButton</cstring> +              </property> +              <property name="maximumSize"> +                <size> +                  <width>14</width> +                  <height>32767</height> +                </size> +              </property> +              <property name="sizePolicy"> +                <sizepolicy> +                  <hsizetype>1</hsizetype> +                  <vsizetype>1</vsizetype> +                  <horstretch>0</horstretch> +                  <verstretch>0</verstretch> +                </sizepolicy> +              </property> +              <property name="toggleButton"> +                <string>true</string> +              </property> +              <property name="whatsThis" stdset="0"> +                <string>Echo recording events to output.</string> +              </property> +              <property name="toolTip" stdset="0"> +                <string>Echo</string> +              </property> +            </widget> +            <spacer> +              <property name="name"> +                <cstring>echoSpacer</cstring> +              </property> +              <property name="orientation"> +                <enum>Horizontal</enum> +              </property> +              <property name="sizeType"> +                <enum>Maximum</enum> +              </property> +              <property name="sizeHint"> +                <size> +                  <width>4</width> +                  <height>2</height> +                </size> +              </property> +            </spacer> +          </hbox>          </widget> -        <widget class="QLabel" row="11" column="0" rowspan="1" colspan="2"> +        <widget class="QLabel" row="10" column="0" rowspan="1" colspan="2">              <property name="name">                  <cstring>TextLabel1_2</cstring>              </property> @@ -561,7 +505,7 @@ recording:                  <set>AlignCenter</set>              </property>          </widget> -        <widget class="QPushButton" row="12" column="0" rowspan="1" colspan="2"> +        <widget class="QPushButton" row="11" column="0" rowspan="1" colspan="2">              <property name="name">                  <cstring>iPatch</cstring>              </property> @@ -580,7 +524,7 @@ recording:                  <string>Select instrument patch</string>              </property>          </widget> -        <widget class="QLabel" row="13" column="0"> +        <widget class="QLabel" row="12" column="0">              <property name="name">                  <cstring>textLabel1</cstring>              </property> @@ -599,7 +543,7 @@ recording:                  <set>AlignVCenter|AlignRight</set>              </property>          </widget> -        <widget class="QLayoutWidget" row="13" column="1"> +        <widget class="QLayoutWidget" row="12" column="1">              <property name="name">                <cstring>recLayout</cstring>              </property> @@ -662,7 +606,7 @@ recording:                  </spacer>              </hbox>          </widget> -        <widget class="SpinBox" row="14" column="0"> +        <widget class="SpinBox" row="13" column="0">              <property name="name">                  <cstring>iHBank</cstring>              </property> @@ -690,7 +634,7 @@ recording:                  <string>Bank Select MSB. Double-click on/off.</string>              </property>          </widget> -        <widget class="QLabel" row="14" column="1"> +        <widget class="QLabel" row="13" column="1">              <property name="name">                  <cstring>TextLabel4</cstring>              </property> @@ -715,7 +659,7 @@ recording:                  <number>2</number>              </property>          </widget> -        <widget class="SpinBox" row="15" column="0"> +        <widget class="SpinBox" row="14" column="0">              <property name="name">                  <cstring>iLBank</cstring>              </property> @@ -743,7 +687,7 @@ recording:                  <string>Bank Select LSB. Double-click on/off.</string>              </property>          </widget> -        <widget class="QLabel" row="15" column="1"> +        <widget class="QLabel" row="14" column="1">              <property name="name">                  <cstring>TextLabel5</cstring>              </property> @@ -768,7 +712,7 @@ recording:                  <number>2</number>              </property>          </widget> -        <widget class="SpinBox" row="16" column="0"> +        <widget class="SpinBox" row="15" column="0">              <property name="name">                  <cstring>iProgram</cstring>              </property> @@ -796,7 +740,7 @@ recording:                  <string>Program. Double-click on/off.</string>              </property>          </widget> -        <widget class="QLayoutWidget" row="16" column="1"> +        <widget class="QLayoutWidget" row="15" column="1">              <property name="name">                  <cstring>progLayout</cstring>              </property> @@ -865,7 +809,7 @@ recording:                </spacer>              </hbox>          </widget> -        <widget class="SpinBox" row="17" column="0"> +        <widget class="SpinBox" row="16" column="0">              <property name="name">                  <cstring>iLautst</cstring>              </property> @@ -893,7 +837,7 @@ recording:                  <string>Volume. Double-click on/off.</string>              </property>          </widget> -        <widget class="QLayoutWidget" row="17" column="1"> +        <widget class="QLayoutWidget" row="16" column="1">              <property name="name">                  <cstring>volLayout</cstring>              </property> @@ -962,7 +906,7 @@ recording:                </spacer>              </hbox>          </widget> -        <widget class="SpinBox" row="18" column="0"> +        <widget class="SpinBox" row="17" column="0">              <property name="name">                  <cstring>iPan</cstring>              </property> @@ -993,7 +937,7 @@ recording:                  <string>Change stereo position. Double-click on/off.</string>              </property>          </widget> -        <widget class="QLayoutWidget" row="18" column="1"> +        <widget class="QLayoutWidget" row="17" column="1">              <property name="name">                  <cstring>panLayout</cstring>              </property> @@ -1062,7 +1006,7 @@ recording:                </spacer>              </hbox>          </widget> -        <spacer row="19" column="0" rowspan="1" colspan="2"> +        <spacer row="18" column="0" rowspan="1" colspan="2">              <property name="name">                  <cstring>spacer5</cstring>              </property> @@ -1107,8 +1051,6 @@ recording:  <tabstops>      <tabstop>iOutput</tabstop>      <tabstop>iOutputChannel</tabstop> -    <tabstop>iInput</tabstop> -    <tabstop>iInputChannel</tabstop>      <tabstop>iTransp</tabstop>      <tabstop>iVerz</tabstop>      <tabstop>iLen</tabstop>  | 
