diff options
| author | Tim E. Real <termtech@rogers.com> | 2011-09-09 10:04:11 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2011-09-09 10:04:11 +0000 | 
| commit | 2120ea4f083228dde0d7307203391a4ec8f57e2d (patch) | |
| tree | 3f8b5c3aeb6691c962d42fb4e3a01bcf511f023f /muse2/muse/driver | |
| parent | ad72332d2cbd0d22e5d49d9fd60c985e563b17d0 (diff) | |
Mostly engine fixes/corrections. Please see ChangeLog.
Diffstat (limited to 'muse2/muse/driver')
| -rw-r--r-- | muse2/muse/driver/alsamidi.cpp | 369 | ||||
| -rw-r--r-- | muse2/muse/driver/alsamidi.h | 20 | ||||
| -rw-r--r-- | muse2/muse/driver/jackmidi.cpp | 851 | ||||
| -rw-r--r-- | muse2/muse/driver/jackmidi.h | 89 | 
4 files changed, 304 insertions, 1025 deletions
| diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp index 07688a33..9a62dbdd 100644 --- a/muse2/muse/driver/alsamidi.cpp +++ b/muse2/muse/driver/alsamidi.cpp @@ -3,6 +3,7 @@  //  Linux Music Editor  //  $Id: alsamidi.cpp,v 1.8.2.7 2009/11/19 04:20:33 terminator356 Exp $  //  (C) Copyright 2000-2001 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -25,16 +26,18 @@  #include "alsamidi.h"  #include "globals.h"  #include "midi.h" -#include "mididev.h" +//#include "mididev.h"  #include "../midiport.h"  #include "../midiseq.h"  #include "../midictrl.h"  #include "../audio.h" -#include "mpevent.h" +//#include "mpevent.h"  //#include "sync.h"  #include "utils.h"  #include "audiodev.h"  #include "xml.h" +#include "part.h" +#include "gconfig.h"  static int alsaSeqFdi = -1;  static int alsaSeqFdo = -1; @@ -50,6 +53,8 @@ MidiAlsaDevice::MidiAlsaDevice(const snd_seq_addr_t& a, const QString& n)     : MidiDevice(n)        {        adr = a; +      stopPending = false;          +      seekPending = false;        init();        } @@ -132,7 +137,7 @@ void MidiAlsaDevice::close()        // Allocated on stack, no need to call snd_seq_port_subscribe_free() later.        snd_seq_port_subscribe_alloca(&subs); -      // Changed by T356. This function appears to be called only by MidiPort::setMidiDevice(),  +      // This function appears to be called only by MidiPort::setMidiDevice(),         //  which closes then opens the device.        // Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags.        // @@ -146,7 +151,7 @@ void MidiAlsaDevice::close()        //                 dst 16:0        //                only sometimes (not when playing notes), but with jack midi turned on,         //                we don't get the messages. With jack stopped we get the messages -      //                no matter if jack midi is turned on or not. +      //                no matter if jack midi is turned on or not.   Tim.        //if (_openFlags & 1) {        //if (!(_openFlags & 1))  @@ -191,95 +196,27 @@ void MidiAlsaDevice::close()  void MidiAlsaDevice::writeRouting(int level, Xml& xml) const  { -      // p3.3.45        // If this device is not actually in use by the song, do not write any routes. -      // This prevents bogus routes from being saved and propagated in the med file. +      // This prevents bogus routes from being saved and propagated in the med file.  Tim.        if(midiPort() == -1)          return;        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().toLatin1().constData()); -             -            //xml.strTag(level, "dstNode", name()); -            xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().toLatin1().constData()); -             -            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_TRANSLATE_NOOP("@default", "Route");            if(r->channel != -1)              s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel);            xml.tag(level++, s.toLatin1().constData()); -           -          /* -          //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().toLatin1().constData()); -            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().toLatin1().constData()); -            xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, r->channel, name().toLatin1().constData()); -          else   -            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().toLatin1().constData()); -            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData()); -          */   -            //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, name().toLatin1().constData()); -            xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData()); -           -          /* -          //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().toLatin1().constData()); -            else   -              xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().toLatin1().constData()); -          } -          else   -          { -            if(r->type == Route::MIDI_DEVICE_ROUTE)   -              xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().toLatin1().constData()); -            else   -              xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData()); -          } -          */ -           +          xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData());            s = QT_TRANSLATE_NOOP("@default", "dest");            if(r->type == Route::MIDI_DEVICE_ROUTE)              s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType());            else            if(r->type != Route::TRACK_ROUTE)              s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); -          //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());            s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));            xml.tag(level, s.toLatin1().constData()); @@ -326,12 +263,9 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                    int a   = e.dataA();                    int b   = e.dataB();                    int chn = e.channel(); -                  // p3.3.37 -                  //if (a < 0x1000) {          // 7 Bit Controller                    if (a < CTRL_14_OFFSET) {          // 7 Bit Controller                          snd_seq_ev_set_controller(&event, chn, a, b);                          } -                  //else if (a < 0x20000) {     // 14 bit high resolution controller                    else if (a < CTRL_RPN_OFFSET) {     // 14 bit high resolution controller                          int ctrlH = (a >> 8) & 0x7f;                          int ctrlL = a & 0x7f; @@ -339,7 +273,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                          snd_seq_ev_set_controller(&event, chn, a, b);                          event.type = SND_SEQ_EVENT_CONTROL14;                          } -                  //else if (a < 0x30000) {     // RPN 7-Bit Controller                    else if (a < CTRL_NRPN_OFFSET) {     // RPN 7-Bit Controller                          int ctrlH = (a >> 8) & 0x7f;                          int ctrlL = a & 0x7f; @@ -348,7 +281,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                          snd_seq_ev_set_controller(&event, chn, a, b);                          event.type = SND_SEQ_EVENT_REGPARAM;                          } -                  //else if (a < 0x40000) {     // NRPN 7-Bit Controller                    else if (a < CTRL_INTERNAL_OFFSET) {     // NRPN 7-Bit Controller                          int ctrlH = (a >> 8) & 0x7f;                          int ctrlL = a & 0x7f; @@ -357,7 +289,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                          snd_seq_ev_set_controller(&event, chn, a, b);                          event.type = SND_SEQ_EVENT_NONREGPARAM;                          } -                  //else if (a < 0x60000) {     // RPN14 Controller                    else if (a < CTRL_NRPN14_OFFSET) {     // RPN14 Controller                          int ctrlH = (a >> 8) & 0x7f;                          int ctrlL = a & 0x7f; @@ -365,7 +296,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                          snd_seq_ev_set_controller(&event, chn, a, b);                          event.type = SND_SEQ_EVENT_REGPARAM;                          } -                  //else if (a < 0x70000) {     // NRPN14 Controller                    else if (a < CTRL_NONE_OFFSET) {     // NRPN14 Controller                          int ctrlH = (a >> 8) & 0x7f;                          int ctrlL = a & 0x7f; @@ -466,6 +396,250 @@ bool MidiAlsaDevice::putEvent(snd_seq_event_t* event)        }  //--------------------------------------------------------- +//   processMidi +//   Called from ALSA midi sequencer thread only. +//--------------------------------------------------------- + +void MidiAlsaDevice::processMidi() +{ +  bool stop = stopPending;  // Snapshots +  bool seek = seekPending;  // +  seekPending = stopPending = false; +  // Transfer the stuck notes FIFO to the play events list. +  // FIXME It would be faster to have MidiAlsaDevice automatically add the stuck note so that only +  //  one FIFO would be needed. But that requires passing an extra 'tick' and 'off velocity' in +  //  addScheduledEvent, which felt too weird. +  while(!stuckNotesFifo.isEmpty()) +    _stuckNotes.add(stuckNotesFifo.get()); +     +  bool extsync = extSyncFlag.value(); +  //int frameOffset = getFrameOffset(); +  //int nextTick = audio->nextTick(); +   +  // We're in the ALSA midi thread. audio->isPlaying() might not be true during seek right now. +  //if(stop || (seek && audio->isPlaying())) +  if(stop || seek) +  { +    //--------------------------------------------------- +    //    Clear all notes and handle stuck notes +    //--------------------------------------------------- +    playEventFifo.clear(); +    _playEvents.clear(); +    //printf("transferring stuck notes\n");   +    for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)  +    { +      //printf(" stuck note\n");   +      MidiPlayEvent ev = *i; +      ev.setTime(0); +      _playEvents.add(ev); +    } +    _stuckNotes.clear(); +  } +  else +  { +    // Transfer the play events FIFO to the play events list. +    while(!playEventFifo.isEmpty()) +      _playEvents.add(playEventFifo.get()); +       +    /*  TODO Handle these more directly than putting them into play events list. +    //if(audio->isPlaying())   +    { +      iMPEvent k; +      for (k = _stuckNotes.begin(); k != _stuckNotes.end(); ++k) { +            if (k->time() >= nextTick)   +                  break; +            MidiPlayEvent ev(*k); +            if(extsync)              // p3.3.25 +              ev.setTime(k->time()); +            else  +              ev.setTime(tempomap.tick2frame(k->time()) + frameOffset); +            _playEvents.add(ev); +            } +      _stuckNotes.erase(_stuckNotes.begin(), k); +    } +    */ +    processStuckNotes();   +  } +   +  /* Instead, done immediately in handleStop and handleSeek using putEvent. +  if(stop) +  { +    // reset sustain... +    MidiPort* mp = &midiPorts[_port]; +    for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +    { +      if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +      { +        //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch); +        MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); +        _playEvents.add(ev); +      } +    } +  } +  if(seek) +  { +    // Send new contoller values... +    for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)  +    { +      MidiCtrlValList* vl = ivl->second; +      iMidiCtrlVal imcv = vl->iValue(pos); +      if(imcv != vl->end()) { +        Part* p = imcv->second.part; +        unsigned t = (unsigned)imcv->first; +        // Do not add values that are outside of the part. +        if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) ) +          _playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val)); +      } +    } +  }    */ +   +  if (_playEvents.empty()) +        return; +   +  int port = midiPort(); +  MidiPort* mp = port != -1 ? &midiPorts[port] : 0; +  unsigned curFrame = audio->curFrame(); +  int tickpos = audio->tickPos(); +   +  // Play all events up to current frame. +  iMPEvent i = _playEvents.begin();             +  for (; i != _playEvents.end(); ++i) { +        if (i->time() > (extsync ? tickpos : curFrame))  // p3.3.25  Check: Should be nextTickPos? p4.0.34 +          break;  +        if(mp){ +          if (mp->sendEvent(*i)) +            break; +              } +        else  +          if(putMidiEvent(*i)) +            break; +        } +  _playEvents.erase(_playEvents.begin(), i); +} + +//--------------------------------------------------------- +//   handleStop +//--------------------------------------------------------- + +void MidiAlsaDevice::handleStop() +{ +  // If the device is not in use by a port, don't bother it. +  if(_port == -1) +    return; +     +  stopPending = true;  // Trigger stop handling in processMidi. +   +  //--------------------------------------------------- +  //    reset sustain +  //--------------------------------------------------- +   +  MidiPort* mp = &midiPorts[_port]; +  for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +  { +    if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +    { +      //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch); +      MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); +      putMidiEvent(ev); +    } +  } +   +  //--------------------------------------------------- +  //    send midi stop +  //--------------------------------------------------- +   +  // Don't send if external sync is on. The master, and our sync routing system will take care of that.    +  if(!extSyncFlag.value()) +  { +    // Shall we check open flags? +    //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) +    //if(!(dev->openFlags() & 1)) +    //  return; +           +    MidiSyncInfo& si = mp->syncInfo(); +    if(si.MMCOut()) +      mp->sendMMCStop(); +     +    if(si.MRTOut())  +    { +      // Send STOP  +      mp->sendStop(); +       +      // Added check of option send continue not start.    p3.3.31 +      // Hmm, is this required? Seems to make other devices unhappy. +      // (Could try now that this is in MidiDevice. p4.0.22 ) +      //if(!si.sendContNotStart()) +      //  mp->sendSongpos(audio->tickPos() * 4 / config.division); +    } +  }   +} + +//--------------------------------------------------------- +//   handleSeek +//--------------------------------------------------------- + +void MidiAlsaDevice::handleSeek() +{ +  // If the device is not in use by a port, don't bother it. +  if(_port == -1) +    return; +   +  seekPending = true;  // Trigger seek handling in processMidi. +   +  MidiPort* mp = &midiPorts[_port]; +  MidiCtrlValListList* cll = mp->controller(); +  int pos = audio->tickPos(); +   +  //--------------------------------------------------- +  //    Send new contoller values +  //--------------------------------------------------- +     +  for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)  +  { +    MidiCtrlValList* vl = ivl->second; +    iMidiCtrlVal imcv = vl->iValue(pos); +    if(imcv != vl->end())  +    { +      Part* p = imcv->second.part; +      unsigned t = (unsigned)imcv->first; +      // Do not add values that are outside of the part. +      if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) ) +        //_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val)); +        // Hmm, play event list for immediate playback? Try putEvent instead.  p4.0.34  +        putMidiEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val)); +    } +  } +   +  //--------------------------------------------------- +  //    Send STOP and "set song position pointer" +  //--------------------------------------------------- +     +  // Don't send if external sync is on. The master, and our sync routing system will take care of that.  p3.3.31 +  if(!extSyncFlag.value()) +  { +    if(mp->syncInfo().MRTOut()) +    { +      // Shall we check for device write open flag to see if it's ok to send?... +      // This means obey what the user has chosen for read/write in the midi port config dialog, +      //  which already takes into account whether the device is writable or not. +      //if(!(rwFlags() & 0x1) || !(openFlags() & 1)) +      //if(!(openFlags() & 1)) +      //  continue; +       +      int beat = (pos * 4) / MusEConfig::config.division; +         +      //bool isPlaying = (state == PLAY); +      bool isPlaying = audio->isPlaying();  // TODO Check this it includes LOOP1 and LOOP2 besides PLAY.  p4.0.22 +         +      mp->sendStop(); +      mp->sendSongpos(beat); +      if(isPlaying) +        mp->sendContinue(); +    }     +  } +} + +//---------------------------------------------------------  //   initMidiAlsa  //    return true on error  //--------------------------------------------------------- @@ -539,7 +713,6 @@ bool initMidiAlsa()                    }              } -      // p3.3.38        //snd_seq_set_client_name(alsaSeq, "MusE Sequencer");        snd_seq_set_client_name(alsaSeq, audioDevice->clientName()); @@ -773,31 +946,6 @@ void alsaProcessMidiInput()                    return;                    } -            /* -            if(curPort == -1)  -            { -                if(mdev == 0) -                {   -                  if (MusEGlobal::debugMsg)  -                  { -                    fprintf(stderr, "no port %d:%d found for received alsa event\n", -                      ev->source.client, ev->source.port); -                  } -                } -                else -                { -                  // Allow the sync detect mechanisms to work, even if device is not assigned to a port. -                  if(ev->type == SND_SEQ_EVENT_CLOCK) -                    mdev->syncInfo().trigMCSyncDetect(); -                  else   -                  if(ev->type == SND_SEQ_EVENT_TICK) -                    mdev->syncInfo().trigTickDetect(); -                } -                snd_seq_free_event(ev); -                return; -            } -            */       -                                event.setType(0);      // mark as unused              event.setPort(curPort);              event.setB(0); @@ -867,7 +1015,6 @@ void alsaProcessMidiInput()                          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. @@ -916,13 +1063,7 @@ void alsaProcessMidiInput()                          break;              }              if(event.type()) -            {                mdev->recordEvent(event); -              // p3.3.26 1/23/10 Moved to MidiDevice now. Anticipating Jack midi support, so don't make it ALSA specific. Tim. -              //if(ev->type != SND_SEQ_EVENT_SYSEX) -                // Trigger general activity indicator detector. Sysex has no channel, don't trigger. -              //  midiPorts[curPort].syncInfo().trigActDetect(event.channel()); -            }              snd_seq_free_event(ev);              if (rv == 0) diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h index 01894f8c..13e07ca4 100644 --- a/muse2/muse/driver/alsamidi.h +++ b/muse2/muse/driver/alsamidi.h @@ -3,6 +3,7 @@  //  Linux Music Editor  //  $Id: alsamidi.h,v 1.2 2004/01/14 09:06:43 wschweer Exp $  //  (C) Copyright 2001 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -26,6 +27,7 @@  #include <config.h>  #include <alsa/asoundlib.h> +#include "mpevent.h"  #include "mididev.h"  class Xml; @@ -39,6 +41,13 @@ class MidiAlsaDevice : public MidiDevice {        snd_seq_addr_t adr;     private: +      // Special for ALSA midi device: Play event list is processed in the ALSA midi sequencer thread. +      // Need this FIFO, to decouple from audio thread which adds events to the list.        +      MidiFifo playEventFifo;   +      MidiFifo stuckNotesFifo;   +      volatile bool stopPending;          +      volatile bool seekPending; +              virtual QString open();        virtual void close();        virtual void processInput()  {} @@ -49,17 +58,22 @@ class MidiAlsaDevice : public MidiDevice {        virtual bool putMidiEvent(const MidiPlayEvent&);     public: -      //MidiAlsaDevice() {}  // p3.3.55 Removed        MidiAlsaDevice(const snd_seq_addr_t&, const QString& name);        virtual ~MidiAlsaDevice() {} -      //virtual void* clientPort() { return (void*)&adr; } -      // p3.3.55        virtual void* inClientPort() { return (void*)&adr; }     // For ALSA midi, in/out client ports are the same.        virtual void* outClientPort() { return (void*)&adr; }    // That is, ALSA midi client ports can be both r/w.        virtual void writeRouting(int, Xml&) const;        virtual inline int deviceType() const { return ALSA_MIDI; }  +      // Schedule an event for playback. Returns false if event cannot be delivered. +      virtual bool addScheduledEvent(const MidiPlayEvent& ev) { return !playEventFifo.put(ev); } +      // Add a stuck note. Returns false if event cannot be delivered. +      virtual bool addStuckNote(const MidiPlayEvent& ev) { return !stuckNotesFifo.put(ev); } +      // Play all events up to current frame. +      virtual void processMidi(); +      virtual void handleStop(); +      virtual void handleSeek();        };  extern bool initMidiAlsa(); diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp index 2e790a10..a4577f0b 100644 --- a/muse2/muse/driver/jackmidi.cpp +++ b/muse2/muse/driver/jackmidi.cpp @@ -3,6 +3,7 @@  //  Linux Music Editor  //  $Id: jackmidi.cpp,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $  //  (C) Copyright 1999-2010 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -48,128 +49,16 @@  extern unsigned int volatile lastExtMidiSyncTick; -///int jackmidi_pi[2]; -///int jackmidi_po[2]; - -//extern muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; -//extern muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; -///extern jack_port_t *midi_port_in[JACK_MIDI_CHANNELS]; -///extern jack_port_t *midi_port_out[JACK_MIDI_CHANNELS]; - -///MidiJackDevice* gmdev = NULL; - -///int* jackSeq; -//static snd_seq_addr_t musePort; - -//int MidiJackDevice::_nextOutIdNum = 0; -//int MidiJackDevice::_nextInIdNum = 0; - -//int JackMidiPortList::_nextOutIdNum = 0; -//int JackMidiPortList::_nextInIdNum = 0; - -//JackMidiPortList jackMidiClientPorts; - - -/* -//--------------------------------------------------------- -//   JackMidiPortList -//--------------------------------------------------------- - -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  //   in_jack_port or out_jack_port can be null  //--------------------------------------------------------- -//MidiJackDevice::MidiJackDevice(const int& a, const QString& n) -//MidiJackDevice::MidiJackDevice(jack_port_t* jack_port, const QString& n) -// p3.3.55 -//MidiJackDevice::MidiJackDevice(jack_port_t* in_jack_port, jack_port_t* out_jack_port, const QString& n)  MidiJackDevice::MidiJackDevice(const QString& n)     : MidiDevice(n)  { -  //_client_jackport = 0; -   -  //_client_jackport = jack_port; -  // p3.3.55 -  //_in_client_jackport  = in_jack_port; -  //_out_client_jackport = out_jack_port;    _in_client_jackport  = NULL;    _out_client_jackport = NULL; -   -  //adr = a;    init();  } @@ -179,10 +68,6 @@ MidiJackDevice::~MidiJackDevice()      printf("MidiJackDevice::~MidiJackDevice()\n");    #endif   -  //if(_client_jackport) -  //  audioDevice->unregisterPort(_client_jackport); -  // p3.3.55 -      if(audioDevice)    {       if(_in_client_jackport) @@ -194,69 +79,13 @@ MidiJackDevice::~MidiJackDevice()      //close();  } -/* -//--------------------------------------------------------- -//   select[RW]fd -//--------------------------------------------------------- - -int MidiJackDevice::selectRfd() -{ -  return jackmidi_pi[0]; -} - -int MidiJackDevice::selectWfd() -{ -  return jackmidi_po[0]; -} -*/ -  //---------------------------------------------------------  //   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. -MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // p3.3.55 1:Writable 2: Readable 3: Writable + Readable +MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable 3: Writable + Readable  { -///  _openFlags &= _rwFlags; // restrict to available bits -   -///  #ifdef JACK_MIDI_DEBUG -///  printf("MidiJackDevice::open %s\n", name.toLatin1().constData()); -///  #endif   -   -  //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData()); -///  jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData()); -   -///  if(!jp) -///  { -///    printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().toLatin1().constData()); -///    _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.toLatin1().constData())) -  //  { -  //    fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Given port name %s already exists!\n", name.toLatin1().constData()); -  //    return 0;   -  //  }   -  //} -   -  //jack_port_t* client_jackport = NULL; -  // p3.3.55 -  ///jack_port_t* in_client_jackport = NULL; -  ///jack_port_t* out_client_jackport = NULL; -   -  //char buf[80]; -     -     -  // p3.3.55    int ni = 0;    if(name.isEmpty())    { @@ -273,188 +102,7 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // p      return 0;    } -  // If Jack port can receive data from us and we actually want to... -  //if((pf & JackPortIsInput) && (_openFlags & 1)) -  ///if(rwflags & 1) -  ///{ -    /*  p3.3.55 Removed. -    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); -         -        if(!midiDevices.find(name)) -        { -          // Does not work. -          //if(!audioDevice->findPort(buf)) -          //  break; -          //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); -          if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO)   // p3.3.52 -          { -            //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true); -            out_client_jackport = (jack_port_t*)audioDevice->registerOutPort((name + QString("_out")).toLatin1().constData(), true);  // p3.3.55 -            //if(client_jackport) -            if(out_client_jackport)  // p3.3.55 -              break; -          } -          else -            break;     -        }     -           -        if(i == 65535) -        { -          fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n"); -          return 0; -        } -      } -      //name = QString(buf); -    } -    else -    */ -     -    /* -    { -      if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO)       // p3.3.52 -      { -        //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true); -        out_client_jackport = (jack_port_t*)audioDevice->registerOutPort((name + QString(JACK_MIDI_OUT_PORT_SUFFIX)).toLatin1().constData(), true);  // p3.3.55 -        //if(!client_jackport) -        if(!out_client_jackport)   // p3.3.55 -        { -          //fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.toLatin1().constData()); -          fprintf(stderr, "MusE: createJackMidiDevice failed creating output port name %s\n", (name + QString(JACK_MIDI_OUT_PORT_SUFFIX)).toLatin1().constData()); // p3.3.55 -           -          //return 0; -          rwflags &= ~1; // p3.3.55 Remove the output r/w flag, but continue on... -        } -      }   -    } -    */ -     -    /* -    else -    { -      client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), 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.toLatin1().constData(), true); -    //if(client_jackport == NULL) -    //{ -    //  fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client output port %s\n", name.toLatin1().constData()); -    //  return 0; -    //} -    //else -    //  _nextOutIdNum++; -     -  ///} -  //else // Note docs say it can't be both input and output.  // p3.3.55 Removed -   -  // If Jack port can send data to us and we actually want it... -  //if((pf & JackPortIsOutput) && (_openFlags & 2)) -  ///if(rwflags & 2) -  ///{   -    /*  p3.3.55 Removed. -    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);  -         -        if(!midiDevices.find(name)) -        { -          // Does not work. -          //if(!audioDevice->findPort(buf)) -          //  break; -          //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true); -          if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO)       // p3.3.52 -          { -            //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true); -            in_client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true);  // p3.3.55 -            //if(client_jackport) -            if(in_client_jackport)   // p3.3.55 -              break; -          } -          else -            break;     -        }     -           -        if(i == 65535) -        { -          fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused input port name!\n"); -          return 0; -        } -      } -      //name = QString(buf); -    } -    else -    */ -     -    /* -    { -      if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO)       // p3.3.52 -      { -        //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true); -        in_client_jackport = (jack_port_t*)audioDevice->registerInPort((name + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData(), true);   // p3.3.55 -        //if(!client_jackport) -        if(!in_client_jackport)    // p3.3.55 -        { -          //fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.toLatin1().constData()); -          fprintf(stderr, "MusE: createJackMidiDevice failed creating input port name %s\n", (name + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData()); -           -          //return 0; -          rwflags &= ~2; // p3.3.55 Remove the input r/w flag, but continue on... -        }   -      } -    } -    */   -       -    //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true); -     -    //if(client_jackport == NULL) -    //{ -    //  fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client input port %s\n", name.toLatin1().constData()); -      //_readEnable = false; -      //return QString("Could not register jack-midi-in client port"); -    //  return 0; -    //} -    //else -    //  _nextInIdNum++; -     -  ///} -     -  //if(client_jackport == NULL)  // p3.3.52 Removed. Allow the device to be created even if Jack isn't running. -  //  return 0; -     -  //MidiJackDevice* dev = new MidiJackDevice(client_jackport, name); -  //MidiJackDevice* dev = new MidiJackDevice(in_client_jackport, out_client_jackport, name);  // p3.3.55 -  //MidiJackDevice* dev = new MidiJackDevice(NULL, NULL, name);  // p3.3.55 -  MidiJackDevice* dev = new MidiJackDevice(name);  // p3.3.55 +  MidiJackDevice* dev = new MidiJackDevice(name);      dev->setrwFlags(rwflags);    midiDevices.add(dev);    return dev; @@ -471,9 +119,6 @@ void MidiJackDevice::setName(const QString& s)    #endif      _name = s;  -  //if(clientPort())  // p3.3.52 Added check. -  //  audioDevice->setPortName(clientPort(), s.toLatin1().constData()); -  // p3.3.55    if(inClientPort())        audioDevice->setPortName(inClientPort(), (s + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData());    if(outClientPort())   @@ -492,65 +137,7 @@ QString MidiJackDevice::open()    printf("MidiJackDevice::open %s\n", name().toLatin1().constData());    #endif   -  /* -  //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData()); -  jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData()); -   -  if(!jp) -  { -    printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().toLatin1().constData()); -    _writeEnable = false; -    _readEnable = false; -    return QString("Jack midi port not found"); -  } -     -  int pf = jack_port_flags(jp); -   -  // If Jack port can receive data from us and we actually want to... -  if((pf & JackPortIsInput) && (_openFlags & 1)) -  { -    char buf[80]; -    snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum); -    _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true); -    if(_client_jackport == NULL) -    { -      fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-out\n"); -      _writeEnable = false; -      return QString("Could not register jack-midi-out client port"); -    } -    else -    { -      _nextOutIdNum++; -      // src, dest -      ///audioDevice->connect(_client_jackport, jp); -      _writeEnable = true; -    } -  } -  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)) -  {   -    char buf[80]; -    snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum); -    _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true); -    if(_client_jackport == NULL) -    { -      fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-in\n"); -      _readEnable = false; -      return QString("Could not register jack-midi-in client port"); -    } -    else -    { -      _nextInIdNum++; -      ///audioDevice->connect(jp, _client_jackport); -      _readEnable = true; -    } -  } -  */ -   -      QString s; -  // p3.3.55 Moved from createJackMidiDevice()    if(_openFlags & 1)    {      if(!_out_client_jackport) @@ -623,9 +210,6 @@ QString MidiJackDevice::open()      _in_client_jackport = NULL;      } -  //if(client_jackport == NULL)  // p3.3.52 Removed. Allow the device to be created even if Jack isn't running. -  //  return 0; -        _writeEnable = bool(_openFlags & 1);    _readEnable = bool(_openFlags & 2); @@ -642,10 +226,10 @@ void MidiJackDevice::close()    printf("MidiJackDevice::close %s\n", name().toLatin1().constData());    #endif   -  // p3.3.55 TODO: I don't really want to unregister the +  // TODO: I don't really want to unregister the    //  Jack midi ports because then we lose the connections    //  to Jack every time we click the read/write lights -  //  or change a port's device. +  //  or change a port's device.   p3.3.55     /*    if(_client_jackport) @@ -667,38 +251,6 @@ void MidiJackDevice::close()    _writeEnable = false;    _readEnable = false; -   -  /* -  //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData()); -  jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData()); -   -  if(!jp) -  { -    printf("MidiJackDevice::close: Jack midi port %s not found!\n", name().toLatin1().constData()); -    _writeEnable = false; -    _readEnable = false; -    return; -  } -     -  //int pf = jack_port_flags(jp); -   -  // If Jack port can receive data from us and we actually want to... -  //if((pf & JackPortIsInput) && (_openFlags & 1)) -  if(jack_port_connected_to(midi_port_out[0], name().toLatin1().constData())) -  { -    // src, dest -///    audioDevice->disconnect(midi_port_out[0], jp); -    _writeEnable = false; -  } -  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(jack_port_connected_to(midi_port_in[0], name().toLatin1().constData())) -  {   -///    audioDevice->disconnect(jp, midi_port_in[0]); -    _readEnable = false; -  } -  */  }  //--------------------------------------------------------- @@ -707,7 +259,6 @@ void MidiJackDevice::close()  void MidiJackDevice::writeRouting(int level, Xml& xml) const  { -      // p3.3.45        // If this device is not actually in use by the song, do not write any routes.        // This prevents bogus routes from being saved and propagated in the med file.        if(midiPort() == -1) @@ -716,30 +267,17 @@ 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().toLatin1().constData());              s = QT_TRANSLATE_NOOP("@default", "source");              if(r->type != Route::TRACK_ROUTE)                s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - -            //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());              s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));              xml.tag(level, s.toLatin1().constData()); -             -            //xml.strTag(level, "dstNode", name()); -            //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData()); -            //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData()); -            //xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().toLatin1().constData());              xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData()); -                          xml.etag(level--, "Route");            }          }   @@ -752,49 +290,14 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const            s = QT_TRANSLATE_NOOP("@default", "Route");            if(r->channel != -1)              s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); -           -          //xml.tag(level++, "Route");            xml.tag(level++, s.toLatin1().constData()); -           -          /* -          //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().toLatin1().constData()); -            //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().toLatin1().constData()); -            xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, r->channel, name().toLatin1().constData()); -          else   -            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData()); -            //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData()); -          */   -            //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().toLatin1().constData()); -            xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData()); -           -          /* -          //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().toLatin1().constData()); -            else   -              xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().toLatin1().constData()); -          } -          else   -          { -            if(r->type == Route::MIDI_DEVICE_ROUTE) -              xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().toLatin1().constData()); -            else   -              xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData()); -          } -          */ -           +          xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());            s = QT_TRANSLATE_NOOP("@default", "dest");            if(r->type == Route::MIDI_DEVICE_ROUTE)              s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType());            else            if(r->type != Route::TRACK_ROUTE)              s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - -          //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());            s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));            xml.tag(level, s.toLatin1().constData()); @@ -802,33 +305,6 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const            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().toLatin1().constData()); -            //else   -              xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData()); -             -            //xml.strTag(level, "dstNode", r->name()); -            xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData()); -             -            xml.etag(level--, "Route"); -          } -        }   -      } -      */        }  //--------------------------------------------------------- @@ -841,80 +317,8 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const   */  bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& /*event*/)  { -  /* -  int give, channel = event.channel(); -  int x; - -  if(channel >= JACK_MIDI_CHANNELS) return false; - -  // buffer up events, because jack eats them in chunks, if -   // the buffer is full, there isn't so much to do, than -   // drop the event -    -  give = jack_midi_out_data[channel].give; -  if(jack_midi_out_data[channel].buffer[give*4+3]){ -    fprintf(stderr, "WARNING: muse-to-jack midi-buffer is full, channel=%u\n", channel); -    return false; -  } -  // copy event(note-on etc..), pitch and volume  -  // see http://www.midi.org/techspecs/midimessages.php  -  switch(event.type()){ -    case ME_NOTEOFF: -      jack_midi_out_data[channel].buffer[give*4+0] = 0x80; -      jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f; -      jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f; -      break; -    case ME_NOTEON: -      jack_midi_out_data[channel].buffer[give*4+0] = 0x90; -      jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f; -      jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f; -      break; -    case ME_CONTROLLER: -      jack_midi_out_data[channel].buffer[give*4+0] = 0xb0; -      jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f; -      jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f; -      break; -    case ME_PROGRAM: -      jack_midi_out_data[channel].buffer[give*4+0] = 0xc0; -      jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f; -      jack_midi_out_data[channel].buffer[give*4+2] = 0; -      break; -    case ME_PITCHBEND: -      jack_midi_out_data[channel].buffer[give*4+0] = 0xE0; -      // convert muse pitch-bend to midi standard  -      x = 0x2000 + event.dataA(); -      jack_midi_out_data[channel].buffer[give*4+1] = x & 0x7f; -      jack_midi_out_data[channel].buffer[give*4+2] = (x >> 8) & 0x7f; -      break; -    default: -      fprintf(stderr, "jack-midi-out %u WARNING: unknown event %x\n", channel, event.type()); -      return false; -  } -  jack_midi_out_data[channel].buffer[give*4+3] = 1; // mark state of this slot  -  // finally increase give position  -  give++; -  if(give >= JACK_MIDI_BUFFER_SIZE){ -    give = 0; -  } -  jack_midi_out_data[channel].give = give; -  return false; -  */ -   -  return false; -} - -/* -//--------------------------------------------------------- -//   putEvent -//    return false if event is delivered -//--------------------------------------------------------- - -bool MidiJackDevice::putEvent(int* event) -{ -  int *y; y = event;    return false;  } -*/  //---------------------------------------------------------  //   recordEvent @@ -1004,9 +408,8 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)        //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. +      // Because from this point on, process handles things, by selected port.    p3.3.38        if(_port == -1)          return; @@ -1025,7 +428,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)        MidiRecordEvent event;        event.setB(0); -      // NOTE: From MusE-2. Not done here in Muse-1 (yet). +      // NOTE: From muse_qt4_evolution. Not done here in Muse-2 (yet).        // move all events 2*MusEGlobal::segmentSize into the future to get        // jitterfree playback        // @@ -1034,15 +437,11 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)        //               ^          ^          ^        //               catch      process    play        // -//      const SeqTime* st = audio->seqTime(); - -      //unsigned curFrame = st->startFrame() + MusEGlobal::segmentSize; -//      unsigned curFrame = st->lastFrameTime; +              //int frameOffset = audio->getFrameOffset();        unsigned pos = audio->pos().frame(); -      //event.setTime(pos + ev->time); -      event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time)); +      event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time));      // p3.3.25        event.setChannel(*(ev->buffer) & 0xf);        int type = *(ev->buffer) & 0xf0; @@ -1144,13 +543,10 @@ void MidiJackDevice::collectMidiEvents()    if(!_readEnable)      return; -  //if(!_client_jackport) -  if(!_in_client_jackport)  // p3.3.55 +  if(!_in_client_jackport)        return; -  //void* port_buf = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize); -  void* port_buf = jack_port_get_buffer(_in_client_jackport, MusEGlobal::segmentSize);   // p3.3.55 -   +  void* port_buf = jack_port_get_buffer(_in_client_jackport, MusEGlobal::segmentSize);       jack_midi_event_t event;    jack_nframes_t eventCount = jack_midi_get_event_count(port_buf);    for (jack_nframes_t i = 0; i < eventCount; ++i)  @@ -1172,9 +568,7 @@ void MidiJackDevice::collectMidiEvents()  bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)  { -  //if(!_writeEnable) -  if(!_writeEnable || !_out_client_jackport)  // p4.0.15 -    //return true; +  if(!_writeEnable || !_out_client_jackport)        return false;    #ifdef JACK_MIDI_DEBUG @@ -1193,9 +587,7 @@ bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)  //   return true if successful  //--------------------------------------------------------- -//void JackAudioDevice::putEvent(Port port, const MidiEvent& e)  bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) -//bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)  {        // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).        // No big deal if not. Not used for now. @@ -1212,11 +604,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)        //if(MusEGlobal::debugMsg)        //  printf("MidiJackDevice::queueEvent\n"); -      //if(!_client_jackport)   -      if(!_out_client_jackport)   // p3.3.55 +      if(!_out_client_jackport)             return false; -      //void* pb = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize); -      void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);  // p3.3.55 +      void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);          //unsigned frameCounter = ->frameTime();        int frameOffset = audio->getFrameOffset(); @@ -1340,7 +730,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)    // Just do this 'standard midi 64T timing thing' for now until we figure out more precise external timings.     // Does require relatively short audio buffers, in order to catch the resolution, but buffer <= 256 should be OK...     // Tested OK so far with 128.  -  ///if(extSyncFlag.value())  +  //if(extSyncFlag.value())     // p4.0.15 Or, is the event marked to be played immediately?    // Nothing to do but stamp the event to be queued for frame 0+.    if(t == 0 || extSyncFlag.value())     @@ -1377,17 +767,13 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)    if(event.type() == ME_PITCHBEND)     {        int v = a + 8192; -      // p3.3.44        //printf("MidiJackDevice::processEvent ME_PITCHBEND v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); -              if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))          return false;    }    else    if(event.type() == ME_CONTROLLER)     { -    //int a      = event.dataA(); -    //int b      = event.dataB();      // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).      // No big deal if not. Not used for now.      //int port   = event.port(); @@ -1407,9 +793,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)      if(a == CTRL_PITCH)       {        int v = b + 8192; -      // p3.3.44        //printf("MidiJackDevice::processEvent CTRL_PITCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); -              if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))          return false;      } @@ -1420,8 +804,6 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)              int hb = (b >> 16) & 0xff;              int lb = (b >> 8) & 0xff;              int pr = b & 0x7f; -           -            // p3.3.44              //printf("MidiJackDevice::processEvent CTRL_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n",               //       event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr); @@ -1440,7 +822,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        //      }      } -    else if (a == CTRL_MASTER_VOLUME) // Enabled p4.0.15 Tim. +    else if (a == CTRL_MASTER_VOLUME)       {        unsigned char sysex[] = {              0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 @@ -1596,19 +978,16 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)  }  //--------------------------------------------------------- -//    processMidi called from audio process only. +//    processMidi  +//    Called from audio thread only.  //---------------------------------------------------------  void MidiJackDevice::processMidi()  { -  //if(!_client_jackport) -  //if(!_out_client_jackport)  // p3.3.55 -  //  return; +  processStuckNotes();        -  //void* port_buf = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize); -  //void* port_buf = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);   // p3.3.55    void* port_buf = 0; -  if(_out_client_jackport && _writeEnable)  // p4.0.15 +  if(_out_client_jackport && _writeEnable)      {      port_buf = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);      jack_midi_clear_buffer(port_buf); @@ -1616,45 +995,24 @@ void MidiJackDevice::processMidi()    while(!eventFifo.isEmpty())    { -    ///MidiPlayEvent e(eventFifo.get()); -    MidiPlayEvent e(eventFifo.peek()); // p4.0.15 -     -    ///int evTime = e.time();  -    // Is event marked to be played immediately? p4.0.15 Moved into processEvent(). -    ///if(evTime == 0)  -    ///{ -      // Nothing to do but stamp the event to be queued for frame 0+. -      //e.setTime(frameOffset + pos); -    ///  e.setTime(audio->getFrameOffset() + audio->pos().frame()); -    ///} -     -    //#ifdef JACK_MIDI_DEBUG -    //printf("MidiJackDevice::processMidi eventFifo time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());   -    //#endif   -     -    //el->insert(eventFifo.get()); -    //el->insert(e); -    ///processEvent(e); -    // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. +    MidiPlayEvent e(eventFifo.peek());  +    // Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events.  p4.0.15       if(port_buf && !processEvent(e))          return;            // Give up. The Jack buffer is full. Nothing left to do.        eventFifo.remove();  // Successfully processed event. Remove it from FIFO.    } -  MPEventList* el = playEvents(); -  if(el->empty()) +  if(_playEvents.empty())    {      //printf("MidiJackDevice::processMidi play events empty\n");       return;    } -  //printf("MidiJackDevice::processMidi play events:\n");  -  ///iMPEvent i = nextPlayEvent(); -  iMPEvent i = el->begin();     // p4.0.15 -  for(; i != el->end(); ++i)  +  iMPEvent i = _playEvents.begin();      +  for(; i != _playEvents.end(); ++i)     {      //printf("MidiJackDevice::processMidi playEvent time:%d type:%d ch:%d A:%d B:%d\n", i->time(), i->type(), i->channel(), i->dataA(), i->dataB());  -    // p3.3.39 Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values. +    // Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.         // Same code as in MidiPort::sendEvent()      if(_port != -1)      { @@ -1672,12 +1030,10 @@ void MidiJackDevice::processMidi()        if(i->type() == ME_PITCHBEND)         {          //printf("MidiJackDevice::processMidi playEvents ME_PITCHBEND time:%d type:%d ch:%d A:%d B:%d\n", (*i).time(), (*i).type(), (*i).channel(), (*i).dataA(), (*i).dataB()); -                  int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA());          if(!mp->setHwCtrlState(i->channel(), CTRL_PITCH, da))            continue;          //mp->setHwCtrlState(i->channel(), CTRL_PITCH, da); -                  //(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));        }        else @@ -1689,25 +1045,11 @@ void MidiJackDevice::processMidi()        }      } -    ///processEvent(*i); -    // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. -    if(port_buf && !processEvent(*i)) -    { -      //setNextPlayEvent(i); -      //return; +    // Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events.  p4.0.15  +    if(port_buf && !processEvent(*i))         break; -    }      } -   -  ///setNextPlayEvent(i); -  // p4.0.15 We are done with these events. Let us erase them here instead of Audio::processMidi. -  // That way we can simply set the next play event to the beginning. -  // This also allows other events to be inserted without the problems caused by the next play event  -  //  being at the 'end' iterator and not being *easily* set to some new place beginning of the newer insertions.  -  // The way that MPEventList sorts made it difficult to predict where the iterator of the first newly inserted items was. -  // The erasure in Audio::processMidi was missing some events because of that. -  el->erase(el->begin(), i); -  // setNextPlayEvent(el->begin());  // Removed p4.0.15 Tim. +  _playEvents.erase(_playEvents.begin(), i);  } @@ -1718,139 +1060,6 @@ void MidiJackDevice::processMidi()  bool initMidiJack()  { -  /* -  int adr = 0; - -  memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); -  memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); - -  MidiJackDevice* dev = new MidiJackDevice(adr, QString("jack-midi")); -  dev->setrwFlags(3); // set read and write flags  - -  if(pipe(jackmidi_pi) < 0){ -    fprintf(stderr, "cant create midi-jack input pipe\n"); -  } -  if(pipe(jackmidi_po) < 0){ -    fprintf(stderr, "cant create midi-jack output pipe\n"); -  } -   -  midiDevices.add(dev); -   -  gmdev = dev; // proclaim the global jack-midi instance  - -  //jackScanMidiPorts(); -  */ -      return false;  } -/* -struct JackPort { -      int adr; -      //char* name; -      QString name; -      int flags; -      //JackPort(int a, const char* s, int f) { -      JackPort(int a, const QString& s, int f) { -            adr = a; -            //name = strdup(s); -            name = QString(s); -            flags = f; -            } -      }; - - -static std::list<JackPort> portList; - -//--------------------------------------------------------- -//   jackScanMidiPorts -//--------------------------------------------------------- - -void jackScanMidiPorts() -{ -  int adr; -  const char* name; - -  portList.clear(); -  adr  = 0; -  name = strdup("namex"); -  portList.push_back(JackPort(adr, name, 0)); -  // -  //  check for devices to add -  // -  for (std::list<JackPort>::iterator k = portList.begin(); k != portList.end(); ++k) { -    iMidiDevice i = midiDevices.begin(); -    for (;i != midiDevices.end(); ++i) { -      //MidiJackDevice* d = dynamic_cast<MidiJackDevice*>(*i); -      break; -      //if (d == 0) continue; -      //if ((k->adr.client == d->adr.client) && (k->adr.port == d->adr.port)) { -      //  break; -      //} -    } -    if (i == midiDevices.end()) { -      // add device -      MidiJackDevice* dev = new MidiJackDevice(k->adr, QString(k->name)); -      dev->setrwFlags(k->flags); -      midiDevices.add(dev); -    } -  } -} -*/ - -/* -//--------------------------------------------------------- -//   processInput -//--------------------------------------------------------- -static void handle_jack_midi_in(int channel) -{ -  MidiRecordEvent event; -  int t,n,v; -  t = jack_midi_in_data[channel].buffer[0]; -  n = jack_midi_in_data[channel].buffer[1]; -  v = jack_midi_in_data[channel].buffer[2]; - -  event.setType(0);      // mark as unused -  event.setPort(gmdev->midiPort()); -  event.setB(0); - -  if(t == 0x90){ // note on  -    fprintf(stderr, "jackProcessMidiInput note-on\n"); -    event.setChannel(channel); -    event.setType(ME_NOTEON); -    event.setA(n); -    event.setB(v); -  }else if (t == 0x80){ // note off  -    fprintf(stderr, "jackProcessMidiInput note-off\n"); -    event.setChannel(channel); -    event.setType(ME_NOTEOFF); -    event.setA(n); -    event.setB(v); -  }else{ -    fprintf(stderr, "WARNING: unknown midi-in on channel %d: %x,%x,%x\n", -            channel, t, n, v); -    return; -  } -  if(event.type()){ -    gmdev->recordEvent(event); -    midiPorts[gmdev->midiPort()].syncInfo().trigActDetect(event.channel()); -  } -} - -void MidiJackDevice::processInput() -{ -  char buf; -  int i,s; -  read(gmdev->selectRfd(), &buf, 1); - -  s = 1; -  for(i = 0; i < JACK_MIDI_CHANNELS; i++){ -    if(jack_midi_in_data[i].buffer[3]){ -      s = 0; -      handle_jack_midi_in(i); -      jack_midi_in_data[i].buffer[3] = 0; -    } -  } -} - -*/ diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h index 2c027c00..e79e9288 100644 --- a/muse2/muse/driver/jackmidi.h +++ b/muse2/muse/driver/jackmidi.h @@ -3,6 +3,7 @@  //  Linux Music Editor  //  $Id: jackmidi.h,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $  //  (C) Copyright 1999-2010 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -40,81 +41,17 @@ class MidiPlayEvent;  //class RouteList;  class Xml; -// Turn on to show multiple devices, work in progress,  -//  not working fully yet, can't seem to connect... -//#define JACK_MIDI_SHOW_MULTIPLE_DEVICES -  // It appears one client port per remote port will be necessary.  // Jack doesn't seem to like manipulation of non-local ports buffers.  //#define JACK_MIDI_USE_MULTIPLE_CLIENT_PORTS -/* jack-midi channels */ -//#define JACK_MIDI_CHANNELS 32 - -/* jack-midi buffer size */ -//#define JACK_MIDI_BUFFER_SIZE 32 - -/* -typedef struct { -  int  give; -  int  take; -  // 32 parallel midi events, where each event contains three -  //  midi-bytes and one busy-byte  -  char buffer[4 * JACK_MIDI_BUFFER_SIZE]; -} 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; -     private: -      // fifo for midi events sent from gui -      // direct to midi port: -      //MidiFifo eventFifo;  // Moved into MidiDevice p4.0.15 - -      //static int _nextOutIdNum; -      //static int _nextInIdNum; -      //jack_port_t* _client_jackport; -      // p3.3.55        jack_port_t* _in_client_jackport;        jack_port_t* _out_client_jackport; @@ -134,49 +71,27 @@ class MidiJackDevice : public MidiDevice {        void eventReceived(jack_midi_event_t*);     public: -      //MidiJackDevice() {}  // p3.3.55  Removed. -      //MidiJackDevice(const int&, const QString& name); -       -      //MidiJackDevice(jack_port_t* jack_port, const QString& name); -      //MidiJackDevice(jack_port_t* in_jack_port, jack_port_t* out_jack_port, const QString& name); // p3.3.55 In or out port can be null.        MidiJackDevice(const QString& name);  -      //static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix. -      static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // p3.3.55 1:Writable 2: Readable 3: Writable + Readable -       +      static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // 1:Writable 2: Readable 3: Writable + Readable        virtual inline int deviceType() const { return JACK_MIDI; }  -              virtual void setName(const QString&);        virtual void processMidi();        virtual ~MidiJackDevice();  -      //virtual int selectRfd(); -      //virtual int selectWfd(); -      //virtual void processInput();        virtual void recordEvent(MidiRecordEvent&);        virtual bool putEvent(const MidiPlayEvent&);        virtual void collectMidiEvents(); -      //virtual jack_port_t* jackPort() { return _jackport; } -      //virtual jack_port_t* clientJackPort() { return _client_jackport; } -       -      //virtual void* clientPort() { return (void*)_client_jackport; } -      // p3.3.55        virtual void* inClientPort()  { return (void*)  _in_client_jackport; }        virtual void* outClientPort() { return (void*) _out_client_jackport; } -      //RouteList* routes()   { return &_routes; } -      //bool noRoute() const   { return _routes.empty();  }        virtual void writeRouting(int, Xml&) const;        };  extern bool initMidiJack(); -//extern int jackSelectRfd(); -//extern int jackSelectWfd(); -//extern void jackProcessMidiInput(); -//extern void jackScanMidiPorts();  #endif | 
