diff options
| author | Florian Jung <flo@windfisch.org> | 2012-03-15 18:21:23 +0000 | 
|---|---|---|
| committer | Florian Jung <flo@windfisch.org> | 2012-03-15 18:21:23 +0000 | 
| commit | 27b7bf6815cda7abb67026c37b3e44daee1803cb (patch) | |
| tree | 0b9d1c0bc84ac7ff8032e707f2b5fb4e0aaabb5c /muse2/muse/driver | |
| parent | 2d6f113a10eb485694e20a78500f650776d701e3 (diff) | |
merged with trunk
Diffstat (limited to 'muse2/muse/driver')
| -rw-r--r-- | muse2/muse/driver/alsamidi.cpp | 373 | ||||
| -rw-r--r-- | muse2/muse/driver/alsamidi.h | 14 | ||||
| -rw-r--r-- | muse2/muse/driver/alsatimer.cpp | 2 | ||||
| -rw-r--r-- | muse2/muse/driver/jack.cpp | 720 | ||||
| -rw-r--r-- | muse2/muse/driver/jackaudio.h | 12 | ||||
| -rw-r--r-- | muse2/muse/driver/jackmidi.cpp | 444 | ||||
| -rw-r--r-- | muse2/muse/driver/jackmidi.h | 4 | ||||
| -rw-r--r-- | muse2/muse/driver/rtctimer.cpp | 4 | ||||
| -rw-r--r-- | muse2/muse/driver/rtctimer.h | 22 | 
9 files changed, 729 insertions, 866 deletions
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp index 740de1fb..08f5345f 100644 --- a/muse2/muse/driver/alsamidi.cpp +++ b/muse2/muse/driver/alsamidi.cpp @@ -38,6 +38,7 @@  #include "xml.h"  #include "part.h"  #include "gconfig.h" +#include "track.h"  #include <QApplication> @@ -58,8 +59,6 @@ MidiAlsaDevice::MidiAlsaDevice(const snd_seq_addr_t& a, const QString& n)     : MidiDevice(n)        {        adr = a; -      stopPending = false;          -      seekPending = false;        init();        } @@ -285,7 +284,7 @@ void MidiAlsaDevice::writeRouting(int level, Xml& xml) const  bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)        {        if (MusEGlobal::midiOutputTrace) { -            printf("MidiOut: midiAlsa: "); +            printf("MidiOut: Alsa: <%s>: ", name().toLatin1().constData());              e.dump();              }        int chn = e.channel(); @@ -309,6 +308,19 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)                    snd_seq_ev_set_pgmchange(&event, chn, a);                    break;              case ME_CONTROLLER: +                  { +                    if(a == CTRL_PROGRAM) +                    { +                      snd_seq_ev_set_pgmchange(&event, chn, b); +                      break; +                    } +                    else if(a == CTRL_PITCH) +                    { +                      snd_seq_ev_set_pitchbend(&event, chn, b); +                      break; +                    } +                  } +                    #if 1                    snd_seq_ev_set_controller(&event, chn, a, b);  #else @@ -453,77 +465,160 @@ bool MidiAlsaDevice::putEvent(snd_seq_event_t* event)  //   Called from ALSA midi sequencer thread only.  //--------------------------------------------------------- -#if 0 -void MidiAlsaDevice::processMidi() -{ -  processStuckNotes();   -  if (_playEvents.empty()) -        return; -  int port = midiPort(); -  MidiPort* mp = port != -1 ? &MusEGlobal::midiPorts[port] : 0; -  unsigned curFrame = MusEGlobal::audio->curFrame(); -  int tickpos = MusEGlobal::audio->tickPos(); -  bool extsync = MusEGlobal::extSyncFlag.value(); -  //int frameOffset = getFrameOffset(); -  //int nextTick = MusEGlobal::audio->nextTick(); -   -  // 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); -} - -#else  void MidiAlsaDevice::processMidi()  { -  bool stop = stopPending;  // Snapshots -  bool seek = seekPending;  // -  seekPending = stopPending = false; +  //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()); +  //while(!stuckNotesFifo.isEmpty()) +  //  _stuckNotes.add(stuckNotesFifo.get()); -  bool extsync = MusEGlobal::extSyncFlag.value();    //int frameOffset = getFrameOffset();    //int nextTick = MusEGlobal::audio->nextTick(); -  // We're in the ALSA midi thread. MusEGlobal::audio->isPlaying() might not be true during seek right now. -  //if(stop || (seek && MusEGlobal::audio->isPlaying())) -  if(stop || seek) +  //bool is_playing = MusEGlobal::audio->isPlaying();   +  // We're in the ALSA midi thread. audio->isPlaying() might not be true during seek right now. Include START_PLAY state... +  //bool is_playing = MusEGlobal::audio->isPlaying() || MusEGlobal::audio->isStarting(); // TODO Check this. It includes LOOP1 and LOOP2 besides PLAY. +  int pos = MusEGlobal::audio->tickPos(); +  int port = midiPort(); +  MidiPort* mp = port == -1 ? 0 : &MusEGlobal::midiPorts[port]; +  bool ext_sync = MusEGlobal::extSyncFlag.value(); + +  /* +  if(mp)    { -    //--------------------------------------------------- -    //    Clear all notes and handle stuck notes -    //--------------------------------------------------- -    playEventFifo.clear(); +    MidiSyncInfo& si = mp->syncInfo(); +    if(stop) +    { +      // Don't send if external sync is on. The master, and our sync routing system will take care of that.    +      if(!ext_sync) +      { +        // Shall we check open flags? +        //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) +        //if(!(dev->openFlags() & 1)) +        //  return; +               +        // Send MMC stop... +        if(si.MMCOut()) +        { +          unsigned char msg[mmcStopMsgLen]; +          memcpy(msg, mmcStopMsg, mmcStopMsgLen); +          msg[1] = si.idOut(); +          putMidiEvent(MidiPlayEvent(0, 0, ME_SYSEX, msg, mmcStopMsgLen)); +        } +         +        // Send midi stop... +        if(si.MRTOut())  +        { +          putMidiEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0)); +          // 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(MusEGlobal::audio->tickPos() * 4 / config.division); +        } +      }   +    } +     +    if(seek) +    { +      // Don't send if external sync is on. The master, and our sync routing system will take care of that.   +      if(!ext_sync) +      { +        // Send midi stop and song position pointer... +        if(si.MRTOut()) +        { +          // Shall we check for device write open flag to see if it's ok to send?... +          //if(!(rwFlags() & 0x1) || !(openFlags() & 1)) +          //if(!(openFlags() & 1)) +          //  continue; +          putMidiEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0)); +          // Hm, try sending these after stuck notes below... +          //putMidiEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0)); +          //if(is_playing) +          //  putMidiEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0)); +        }     +      } +    }     +  } +  */ +   +  /* +  if(stop || (seek && is_playing))   +  { +    // 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); +      //_playEvents.add(ev); +      putMidiEvent(ev);  // Play immediately.      }      _stuckNotes.clear();    } -  else +  */ +   +  /* +  if(mp) +  { +    MidiSyncInfo& si = mp->syncInfo(); +    // Try sending these now after stuck notes above... +    if(stop || seek) +    { +      // Reset sustain. +      for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +        if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +          putMidiEvent(MidiPlayEvent(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0)); +    } +    if(seek) +    { +      // Send new song position. +      if(!ext_sync && si.MRTOut()) +      { +        int beat = (pos * 4) / MusEGlobal::config.division; +        putMidiEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0)); +      } +      // Send new controller values. +      MidiCtrlValListList* cll = mp->controller(); +      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; +          // Don't send if part or track is muted or off. +          if(!p || p->mute()) +            continue; +          Track* track = p->track(); +          if(track && (track->isMute() || track->off()))    +            continue; +          unsigned t = (unsigned)imcv->first; +          // Do not add values that are outside of the part. +          if(t >= p->tick() && t < (p->tick() + p->lenTick())) +            // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position. +            mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos); +        } +      } +       +      // Send continue. +      // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready. +      //if(is_playing && !ext_sync && si.MRTOut()) +      //  putMidiEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0)); +    } +  } +  */ +   +  //if(!(stop || (seek && is_playing)))    {      // Transfer the play events FIFO to the play events list. -    while(!playEventFifo.isEmpty()) -      _playEvents.add(playEventFifo.get()); +    //while(!playEventFifo.isEmpty()) +    //  _playEvents.add(playEventFifo.get());      /*  TODO Handle these more directly than putting them into play events list.      //if(MusEGlobal::audio->isPlaying())   @@ -545,53 +640,18 @@ void MidiAlsaDevice::processMidi()      processStuckNotes();      } -  /* Instead, done immediately in handleStop and handleSeek using putEvent. -  if(stop) -  { -    // reset sustain... -    MidiPort* mp = &MusEGlobal::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; +  if(_playEvents.empty()) +    return; -  int port = midiPort(); -  MidiPort* mp = port != -1 ? &MusEGlobal::midiPorts[port] : 0;    unsigned curFrame = MusEGlobal::audio->curFrame(); -  int tickpos = MusEGlobal::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 +        if (i->time() > (ext_sync ? pos : curFrame))  // p3.3.25  Check: Should be nextTickPos? p4.0.34            break;           if(mp){ -          if (mp->sendEvent(*i)) +          if (mp->sendEvent(*i, true))  // Force the event to be sent.              break;                }          else  @@ -601,6 +661,7 @@ void MidiAlsaDevice::processMidi()    _playEvents.erase(_playEvents.begin(), i);  } +/*  //---------------------------------------------------------  //   handleStop  //--------------------------------------------------------- @@ -614,21 +675,6 @@ void MidiAlsaDevice::handleStop()    stopPending = true;  // Trigger stop handling in processMidi.    //--------------------------------------------------- -  //    reset sustain -  //--------------------------------------------------- -   -  MidiPort* mp = &MusEGlobal::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    //--------------------------------------------------- @@ -646,18 +692,61 @@ void MidiAlsaDevice::handleStop()      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 ) +      // Added check of option send continue not start. Hmm, is this required? Seems to make other devices unhappy. +      // (Could try now that this is in MidiDevice.)        //if(!si.sendContNotStart())        //  mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);      }    }   + +  //--------------------------------------------------- +  //    reset sustain +  //--------------------------------------------------- +   +  MidiPort* mp = &MusEGlobal::midiPorts[_port]; +  for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +  { +    if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +    { +      MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); +      //putMidiEvent(ev); +      putEvent(ev); +      // Do sendEvent to get the optimizations - send only on a change of value. +      //mp->sendEvent(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(!MusEGlobal::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. Hmm, is this required? Seems to make other devices unhappy. +//       // (Could try now that this is in MidiDevice.) +//       //if(!si.sendContNotStart()) +//       //  mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division); +//     } +//   }    } +*/ +/*  //---------------------------------------------------------  //   handleSeek  //--------------------------------------------------------- @@ -675,7 +764,41 @@ void MidiAlsaDevice::handleSeek()    int pos = MusEGlobal::audio->tickPos();    //--------------------------------------------------- -  //    Send new contoller values +  //    Send STOP  +  //--------------------------------------------------- +     +  // Don't send if external sync is on. The master, and our sync routing system will take care of that.   +  if(!MusEGlobal::extSyncFlag.value()) +  { +    if(mp->syncInfo().MRTOut()) +    { +      // Shall we check for device write open flag to see if it's ok to send?... +      //if(!(rwFlags() & 0x1) || !(openFlags() & 1)) +      //if(!(openFlags() & 1)) +      //  continue; +      mp->sendStop(); +    }     +  } +   +  //--------------------------------------------------- +  //    reset sustain +  //--------------------------------------------------- +   +  MidiPort* mp = &MusEGlobal::midiPorts[_port]; +  for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +  { +    if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +    { +      MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); +      putEvent(ev); +      //putMidiEvent(ev); +      // Do sendEvent to get the optimizations - send only on a change of value. +      //mp->sendEvent(ev); +    } +  } +   +  //--------------------------------------------------- +  //    Send new controller values    //---------------------------------------------------    for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)  @@ -685,12 +808,18 @@ void MidiAlsaDevice::handleSeek()      if(imcv != vl->end())       {        Part* p = imcv->second.part; +      // Don't send if part or track is muted or off. +      if(!p || p->mute()) +        continue; +      Track* track = p->track(); +      if(track && (track->isMute() || track->off()))    +        continue;        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)); +        // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position. +        mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos);      }    } @@ -698,31 +827,23 @@ void MidiAlsaDevice::handleSeek()    //    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 +  // Don't send if external sync is on. The master, and our sync routing system will take care of that.      if(!MusEGlobal::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; +      //mp->sendStop(); // Moved above.        int beat = (pos * 4) / MusEGlobal::config.division; -         -      //bool isPlaying = (state == PLAY); -      bool isPlaying = MusEGlobal::audio->isPlaying();  // TODO Check this it includes LOOP1 and LOOP2 besides PLAY.  p4.0.22 -         -      mp->sendStop();        mp->sendSongpos(beat); -      if(isPlaying) -        mp->sendContinue();      }        }  } -#endif +*/  //---------------------------------------------------------  //   initMidiAlsa diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h index 2054a7d3..7a1ac1c2 100644 --- a/muse2/muse/driver/alsamidi.h +++ b/muse2/muse/driver/alsamidi.h @@ -45,10 +45,8 @@ class MidiAlsaDevice : public MidiDevice {     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; +      //MidiFifo playEventFifo;   +      //MidiFifo stuckNotesFifo;          virtual QString open();        virtual void close(); @@ -69,13 +67,13 @@ class MidiAlsaDevice : public MidiDevice {        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); } +      //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); } +      //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(); +      //virtual void handleStop(); +      //virtual void handleSeek();        };  extern bool initMidiAlsa(); diff --git a/muse2/muse/driver/alsatimer.cpp b/muse2/muse/driver/alsatimer.cpp index ee72d679..20f7ab88 100644 --- a/muse2/muse/driver/alsatimer.cpp +++ b/muse2/muse/driver/alsatimer.cpp @@ -173,7 +173,7 @@ namespace MusECore {            (long int)((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params)));        } -      return 0; +      return (long int)((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params));      }      actFreq = (1000000000 / snd_timer_info_get_resolution(info)) / setTick;      if (actFreq != freq) { diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index 421152a7..a52410e9 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -3,6 +3,7 @@  //  Linux Music Editor  //    $Id: jack.cpp,v 1.30.2.17 2009/12/20 05:00:35 terminator356 Exp $  //  (C) Copyright 2002 Werner Schweer (ws@seh.de) +//  (C) Copyright 2012 Tim E. Real (terminator356 on sourceforge.net)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -82,15 +83,6 @@ bool checkAudioDevice()  namespace MusECore { -//extern int jackmidi_pi[2]; -//extern int jackmidi_po[2]; - -//jack_port_t *midi_port_in[JACK_MIDI_CHANNELS]; -//jack_port_t *midi_port_out[JACK_MIDI_CHANNELS]; - -//muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; -//muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; -  JackAudioDevice* jackAudio;  //--------------------------------------------------------- @@ -109,38 +101,9 @@ inline bool checkJackClient(jack_client_t* _client)  //   jack_thread_init  //--------------------------------------------------------- -static void jack_thread_init (void* )  // data +static void jack_thread_init (void* )          {        MusEGlobal::doSetuid(); -      /* -      if (jackAudio->isRealtime()) { -            struct sched_param rt_param; -            int rv; -            memset(&rt_param, 0, sizeof(sched_param)); -            int type; -            rv = pthread_getschedparam(pthread_self(), &type, &rt_param); -            if (rv != 0) -                  perror("get scheduler parameter"); -            if (type != SCHED_FIFO) { -                  fprintf(stderr, "JACK thread not running SCHED_FIFO, try to set...\n"); - -                  memset(&rt_param, 0, sizeof(sched_param)); -                  rt_param.sched_priority = 1; -                  rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param); -                  if (rv != 0) -                        perror("set realtime scheduler"); -                  memset(&rt_param, 0, sizeof(sched_param)); -                  rv = pthread_getschedparam(pthread_self(), &type, &rt_param); -                  if (rv != 0) -                        perror("get scheduler parameter"); -                  if (type != SCHED_FIFO) -                        fprintf(stderr, "JACK still not running FIFO !?!\n" -                        "======reliable RT operation not possible!!======\n"); -                  else -                        fprintf(stderr, "JACK thread succesfully set to SCHED_FIFO\n"); -                  }  -            } -            */  #ifdef VST_SUPPORT        if (loadVST)              fst_adopt_thread(); @@ -148,161 +111,78 @@ static void jack_thread_init (void* )  // data        MusEGlobal::undoSetuid();        } -/* -//--------------------------------------------------------- -//   processAudio + Midi -//    JACK callback -//--------------------------------------------------------- -void -print_triplet(unsigned char *data) -{ -  int a,b,c; -  a = b = c = 0; -  memcpy(&a, data, 1); -  memcpy(&b, data+1, 1); -  memcpy(&c, data+2, 1); -  fprintf(stderr, "%x,%x,%x", a, b, c); -} -*/ - -/* -void handle_jack_midi_in_events(jack_nframes_t frames) -{ -  char buf = 0; -  int i,j; -  jack_midi_event_t midi_event; -  unsigned char t,n,v; - -  for(j = 0; j < JACK_MIDI_CHANNELS; j++){ -    void *midi_buffer_in = jack_port_get_buffer(midi_port_in[j], frames); -    int event_count = jack_midi_get_event_count(midi_buffer_in); - -    for(i = 0; i < event_count; i++){ -      jack_midi_event_get(&midi_event, midi_buffer_in, i); -      t = midi_event.buffer[0]; -      n = midi_event.buffer[1]; -      v = midi_event.buffer[2]; -      if(((*(midi_event.buffer) & 0xf0)) == 0x90){ -        fprintf(stderr, "jack-midi-in-event: ON_ time=%d %u ", midi_event.time, -                midi_event.size); -        print_triplet(midi_event.buffer); -        fprintf(stderr, "\n"); -      }else if(((*(midi_event.buffer)) & 0xf0) == 0x80){ -        fprintf(stderr, "jack-midi-in-event: OFF time=%d %u ", midi_event.time, -                midi_event.size); -        print_triplet(midi_event.buffer); -        fprintf(stderr, "\n"); -      }else{ -        fprintf(stderr, "jack-midi-in-event: ??? time=%d %u ", midi_event.time, -                midi_event.size); -        print_triplet(midi_event.buffer); -        fprintf(stderr, "\n"); -      } -      jack_midi_in_data[j].buffer[0] = t; -      jack_midi_in_data[j].buffer[1] = n; -      jack_midi_in_data[j].buffer[2] = v; -      jack_midi_in_data[j].buffer[3] = 1; -      fprintf(stderr, "handle_jack_midi_in_events() w\n"); -      write(jackmidi_pi[1], &buf, 1); -      fprintf(stderr, "handle_jack_midi_in_events() wd\n"); -    } -  } -} - -void handle_jack_midi_out_events(jack_nframes_t frames) -{ -  unsigned char *data; -  void *port_buf; -  int i,j,n,x; - -  //for(i = 0; i < JACK_MIDI_CHANNELS; i++){ -  for(i = 0; i < JACK_MIDI_CHANNELS; ++i){ -    // jack-midi-clear any old events  -    while(jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] == 2){ -      port_buf = jack_port_get_buffer(midi_port_out[i], frames); -      jack_midi_clear_buffer(port_buf); -      jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] = 0; -      // point the take to the next slot  -      jack_midi_out_data[i].take++; -      if(jack_midi_out_data[i].take >= JACK_MIDI_BUFFER_SIZE){ -        jack_midi_out_data[i].take = 0; -      } -    } -    // check if any incoming midi-events from muse  -    if(jack_midi_out_data[i].give != jack_midi_out_data[i].take){ - -      if(jack_midi_out_data[i].give > jack_midi_out_data[i].take){ -        n = jack_midi_out_data[i].give - jack_midi_out_data[i].take; -      }else{ -        n = jack_midi_out_data[i].give + -            (JACK_MIDI_BUFFER_SIZE - jack_midi_out_data[i].take); -      } -      port_buf = jack_port_get_buffer(midi_port_out[i], frames); -      jack_midi_clear_buffer(port_buf); -      // FIX: midi events has different sizes, compare note-on to -      //        program-change. We should first walk over the events -      //        counting the size.  -      //data = jack_midi_event_reserve(port_buf, 0, n*3); -      //x = jack_midi_out_data[i].take; -      //for(j = 0; j < n; j++){ -      //  data[j*3+0] = jack_midi_out_data[i].buffer[x*4+0]; -      //  data[j*3+1] = jack_midi_out_data[i].buffer[x*4+1]; -      //  data[j*3+2] = jack_midi_out_data[i].buffer[x*4+2]; -        // after having copied the buffer over to the jack-buffer,  -        // mark the muses midi-out buffer as 'need-cleaning'  -      //  jack_midi_out_data[i].buffer[x*4+3] = 2; -      //  x++; -      //  if(x >= JACK_MIDI_BUFFER_SIZE){ -      //    x = 0; -      //  } -      //} -       -      x = jack_midi_out_data[i].take; -      for(j = 0; j < n; ++j) -      { -        data = jack_midi_event_reserve(port_buf, 0, 3); -        if(data == 0)  -        { -          fprintf(stderr, "handle_jack_midi_out_events: buffer overflow, event lost\n"); -          // Can do no more processing. Just return. -          return; -        } -        data[0] = jack_midi_out_data[i].buffer[x*4+0]; -        data[1] = jack_midi_out_data[i].buffer[x*4+1]; -        data[2] = jack_midi_out_data[i].buffer[x*4+2]; -        // after having copied the buffer over to the jack-buffer,  -        //  mark the muses midi-out buffer as 'need-cleaning'  -        jack_midi_out_data[i].buffer[x*4+3] = 2; -        x++; -        if(x >= JACK_MIDI_BUFFER_SIZE){ -          x = 0; -        } -      } -       -    } -  } -} -*/ - -//static int processAudio(jack_nframes_t frames, void*)  int JackAudioDevice::processAudio(jack_nframes_t frames, void*)  { -  jackAudio->_frameCounter += frames; -   -///  handle_jack_midi_in_events(frames); -///  handle_jack_midi_out_events(frames); -   -//      if (JACK_DEBUG) -//            printf("processAudio - >>>>\n"); +      int state_pending = jackAudio->_dummyStatePending;  // Snapshots. +      int pos_pending   = jackAudio->_dummyPosPending;    // +      jackAudio->_dummyStatePending = -1;                 // Reset. +      jackAudio->_dummyPosPending = -1;                   // +       +      jackAudio->_frameCounter += frames;        MusEGlobal::segmentSize = frames; +        if (MusEGlobal::audio->isRunning()) -            MusEGlobal::audio->process((unsigned long)frames); +      { +            // Are we not using Jack transport? +            if(!MusEGlobal::useJackTransport.value()) +            { +              // STOP -> STOP, STOP -> START_PLAY, PLAY -> START_PLAY all count as 'syncing'. +              if(((jackAudio->dummyState == Audio::STOP || jackAudio->dummyState == Audio::PLAY) && state_pending == Audio::START_PLAY)  +                 || (jackAudio->dummyState == Audio::STOP && state_pending == Audio::STOP) ) +              { +                jackAudio->_syncTimeout = (float)frames / (float)MusEGlobal::sampleRate;  // (Re)start the timeout counter... +                if(pos_pending != -1) +                  jackAudio->dummyPos = pos_pending; // Set the new dummy position. +                if((jackAudio->dummyState == Audio::STOP || jackAudio->dummyState == Audio::PLAY) && state_pending == Audio::START_PLAY) +                  jackAudio->dummyState = Audio::START_PLAY; +              } +              else // All other states such as START_PLAY -> STOP, PLAY -> STOP. +              if(state_pending != -1 && state_pending != jackAudio->dummyState) +              { +                jackAudio->_syncTimeout = 0.0;  // Reset. +                jackAudio->dummyState = state_pending;                 +              } +               +              // Is the sync timeout counter running? +              if(jackAudio->_syncTimeout > 0.0) +              { +                //printf("Jack processAudio dummy sync: state:%d pending:%d\n", jackAudio->dummyState, state_pending);   +                // Is MusE audio ready to roll? +                if(MusEGlobal::audio->sync(jackAudio->dummyState, jackAudio->dummyPos)) +                { +                  jackAudio->_syncTimeout = 0.0;  // Reset. +                  // We're ready. Switch to PLAY state. +                  if(jackAudio->dummyState == Audio::START_PLAY) +                    jackAudio->dummyState = Audio::PLAY; +                } +                else +                {   +                  jackAudio->_syncTimeout += (float)frames / (float)MusEGlobal::sampleRate; +                  if(jackAudio->_syncTimeout > 5.0)  // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here. +                  { +                    if (MusEGlobal::debugMsg) +                      puts("Jack dummy sync timeout! Starting anyway...\n"); +                    jackAudio->_syncTimeout = 0.0;  // Reset. +                    // We're not ready, but no time left - gotta roll anyway. Switch to PLAY state, similar to how Jack is supposed to work. +                    if(jackAudio->dummyState == Audio::START_PLAY) +                    { +                      jackAudio->dummyState = Audio::PLAY; +                      // Docs say sync will be called with Rolling state when timeout expires. +                      MusEGlobal::audio->sync(jackAudio->dummyState, jackAudio->dummyPos); +                    } +                  } +                } +              } +            } +         +            //if(jackAudio->getState() != Audio::START_PLAY)  // Don't process while we're syncing. TODO: May need to deliver silence in process! +              MusEGlobal::audio->process((unsigned long)frames); +      }        else {              if (MusEGlobal::debugMsg)                   puts("jack calling when audio is disconnected!\n");              } -//      if (JACK_DEBUG) -//            printf("processAudio - <<<<\n"); +                return 0;  } @@ -344,13 +224,9 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void*              }        unsigned frame = pos->frame; -      //printf("processSync valid:%d frame:%d\n", pos->valid, frame); -       -            // p3.3.23 -            //printf("Jack processSync() before MusEGlobal::audio->sync frame:%d\n", frame);        //return MusEGlobal::audio->sync(audioState, frame);        int rv = MusEGlobal::audio->sync(audioState, frame); -            //printf("Jack processSync() after MusEGlobal::audio->sync frame:%d\n", frame); +      //printf("Jack processSync() after MusEGlobal::audio->sync frame:%d\n", frame);        return rv;              } @@ -366,7 +242,6 @@ static void timebase_callback(jack_transport_state_t /* state */,    {        //printf("Jack timebase_callback pos->frame:%u MusEGlobal::audio->tickPos:%d MusEGlobal::song->cpos:%d\n", pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos()); -      // p3.3.27        //Pos p(pos->frame, false);        Pos p(MusEGlobal::extSyncFlag.value() ? MusEGlobal::audio->tickPos() : pos->frame, MusEGlobal::extSyncFlag.value() ? true : false);        // Can't use song pos - it is only updated every (slow) GUI heartbeat ! @@ -382,7 +257,6 @@ static void timebase_callback(jack_transport_state_t /* state */,        //  dummy:        // -      // p3.3.26        //pos->beats_per_bar = 4;        //pos->beat_type = 4;        //pos->ticks_per_beat = 384; @@ -472,20 +346,7 @@ JackAudioDevice::~JackAudioDevice()        if (JACK_DEBUG)              printf("~JackAudioDevice()\n");        if (_client) { -             -            /* -            // p3.3.35 -            for(int i = 0; i < JACK_MIDI_CHANNELS; i++) -            { -              if(midi_port_in[i]) -                jack_port_unregister(_client, midi_port_in[i]); -              if(midi_port_out[i]) -                jack_port_unregister(_client, midi_port_out[i]); -            } -            */ -                          if (jack_client_close(_client)) { -                  //error->logError("jack_client_close() failed: %s\n", strerror(errno));                    fprintf(stderr,"jack_client_close() failed: %s\n", strerror(errno));                    }              } @@ -518,32 +379,6 @@ int JackAudioDevice::realtimePriority() const        return param.sched_priority;        } -/* -//--------------------------------------------------------- -//   getJackName() -//--------------------------------------------------------- - -char* JackAudioDevice::getJackName() -      { -      return jackRegisteredName; -      } -*/ - -/* -//--------------------------------------------------------- -//   clientName() -//--------------------------------------------------------- - -const char* JackAudioDevice::clientName() -{ -  //if(_client) -  //  return jack_get_client_name(_client); -  //else -  //  return "MusE";   -  return jackRegisteredName; -} -*/ -  //---------------------------------------------------------  //   initJackAudio  //    return true if JACK not found @@ -551,15 +386,6 @@ const char* JackAudioDevice::clientName()  bool initJackAudio()        { -      /* -      // p3.3.35 -      for(int i = 0; i < JACK_MIDI_CHANNELS; i++) -      { -        midi_port_in[i] = 0; -        midi_port_out[i] = 0; -      } -      */ -              if (JACK_DEBUG)              printf("initJackAudio()\n");        if (MusEGlobal::debugMsg) { @@ -596,7 +422,7 @@ bool initJackAudio()              if (status & JackVersionError)                    printf("jack server has wrong version\n");              printf("cannot create jack client\n"); -	    MusEGlobal::undoSetuid();   // p3.3.51 +	    MusEGlobal::undoSetuid();                 return true;              } @@ -616,39 +442,6 @@ bool initJackAudio()              }        MusEGlobal::undoSetuid(); -      /* -      // setup midi input/output  -      //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)); -      if(client){ -        for(i = 0; i < JACK_MIDI_CHANNELS; i++) -        { -          char buf[80]; -          snprintf(buf, 80, "muse-jack-midi-in-%d", i+1); -          midi_port_in[i] = jack_port_register(client, buf, -                                              JACK_DEFAULT_MIDI_TYPE, -                                              JackPortIsInput, 0); -          if(midi_port_in[i] == NULL){ -            fprintf(stderr, "failed to register jack-midi-in\n"); -            exit(-1); -          } -          snprintf(buf, 80, "muse-jack-midi-out-%d", i+1); -          midi_port_out[i] = jack_port_register(client, buf, -                                                JACK_DEFAULT_MIDI_TYPE, -                                                JackPortIsOutput, 0); -          if(midi_port_out == NULL) -          { -            fprintf(stderr, "failed to register jack-midi-out\n"); -            exit(-1); -          } -        } -      } -      else -      { -        fprintf(stderr, "WARNING NO muse-jack midi connection\n"); -      } -      */     -                  if (client) {              MusEGlobal::audioDevice = jackAudio;              jackAudio->scanMidiPorts(); @@ -730,8 +523,8 @@ void JackAudioDevice::connectJackMidiPorts()      //void* port = md->clientPort();      if(md->rwFlags() & 1)      { -      void* port = md->outClientPort(); // p3.3.55 -      if(port)                          //  +      void* port = md->outClientPort();  +      if(port)                                   {          RouteList* rl = md->outRoutes();          for (ciRoute r = rl->begin(); r != rl->end(); ++r)  @@ -743,12 +536,10 @@ void JackAudioDevice::connectJackMidiPorts()        }          } -    // else  // p3.3.55 Removed -          if(md->rwFlags() & 2)      {   -      void* port = md->inClientPort();  // p3.3.55 -      if(port)                          // +      void* port = md->inClientPort();   +      if(port)                                  {          RouteList* rl = md->inRoutes();          for (ciRoute r = rl->begin(); r != rl->end(); ++r)  @@ -760,117 +551,8 @@ void JackAudioDevice::connectJackMidiPorts()        }          }        } -   -   -  /* -  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)  -  { -    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(MusEGlobal::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(MusEGlobal::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];  -    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]; -   -    if(MusEGlobal::debugMsg) -      printf("alias: %s\n", aliases[0]); -     -    //int flags = 0; -    int pf = jack_port_flags(port); -    // If Jack port can send data to us... -    //if(pf & JackPortIsOutput) -      // Mark as input capable. -    //  flags |= 2; -    // If Jack port can receive data from us... -    //if(pf & JackPortIsInput) -      // Mark as output capable. -    //  flags |= 1; -     -    //JackPort jp(0, QString(buffer), flags); -    //portList.append(jp); -     -    QString name(namep); -     -    if(JACK_DEBUG) -      printf("JackAudioDevice::graphChanged %s\n", name.toLatin1()); -       -    for(iMidiDevice imd = MusEGlobal::midiDevices.begin(); imd != MusEGlobal::midiDevices.end(); ++imd) -    { -      // Is it a Jack midi device?  -      MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*imd); -      if(!mjd) -        continue; -         -      //if(dev->name() != name) -      //  continue; -       -      // Is this port the one created for the Jack midi device? -      if(!mjd->clientJackPort() || (mjd->clientJackPort() != port)) -        continue; -       -      jack_port_t* devport = jack_port_by_name(_client, mjd->name().toLatin1()); -      if(!devport) -        continue; -       -      int ofl = mjd->openFlags(); -     -      if(JACK_DEBUG) -        printf("JackAudioDevice::graphChanged found MidiJackDevice:%s\n", mjd->name().toLatin1()); -       -      // Note docs say it can't be both input and output. src, dest -      // If Jack port can receive data from us and we actually want to... -      if((pf & JackPortIsOutput) && (ofl & 1)) -      { -        if(JACK_DEBUG) -          printf("JackAudioDevice::graphChanged connecting MusE output\n"); -        MusEGlobal::audioDevice->connect(port, devport); -      } -      else  -      // If Jack port can send data to us and we actually want it... -      if((pf & JackPortIsInput) && (ofl & 2)) -      { -        if(JACK_DEBUG) -          printf("JackAudioDevice::graphChanged connecting MusE input\n"); -        MusEGlobal::audioDevice->connect(devport, port); -      } -       -      break;   -    } -  } -   -  if(ports) -    free(ports);       -     -  */    } +  //---------------------------------------------------------  //   client_registration_callback  //--------------------------------------------------------- @@ -1009,9 +691,6 @@ void JackAudioDevice::graphChanged()                                ++pn;                                } -                        // p3.3.37 -                        //delete ports; -                        //free(ports);                          jack_free(ports);  // p4.0.29                          ports = NULL; @@ -1100,9 +779,6 @@ void JackAudioDevice::graphChanged()                                ++pn;                                } -                        // p3.3.37 -                        //delete ports; -                        //free(ports);                          jack_free(ports);  // p4.0.29                          ports = NULL; @@ -1134,12 +810,9 @@ void JackAudioDevice::graphChanged()                    if(md->rwFlags() & 1) // Writable                    { -                    // p3.3.55                      jack_port_t* port = (jack_port_t*)md->outClientPort();                      if(port != 0)                      { -                      //printf("graphChanged() valid out client port\n"); // p3.3.55 -                                              const char** ports = jack_port_get_all_connections(_client, port);                        RouteList* rl      = md->outRoutes(); @@ -1160,7 +833,7 @@ void JackAudioDevice::graphChanged()                                    //if (irl->channel != channel)                                    //      continue;                                    QString name = irl->name(); -                                  //name += QString(JACK_MIDI_OUT_PORT_SUFFIX);    // p3.3.55 +                                  //name += QString(JACK_MIDI_OUT_PORT_SUFFIX);                                        QByteArray ba = name.toLatin1();                                    const char* portName = ba.constData();                                    bool found = false; @@ -1224,9 +897,6 @@ void JackAudioDevice::graphChanged()                                    ++pn;                                    } -                            // p3.3.55 -                            // Done with ports. Free them. -                            //free(ports);                              jack_free(ports);  // p4.0.29                        }                      }   @@ -1239,11 +909,9 @@ void JackAudioDevice::graphChanged()                    if(md->rwFlags() & 2) // Readable                    { -                    // p3.3.55                      jack_port_t* port = (jack_port_t*)md->inClientPort();                      if(port != 0)                      { -                      //printf("graphChanged() valid in client port\n"); // p3.3.55                        const char** ports = jack_port_get_all_connections(_client, port);                        RouteList* rl = md->inRoutes(); @@ -1326,20 +994,11 @@ void JackAudioDevice::graphChanged()                                          }                                    ++pn;                                    } -                            // p3.3.55 -                            // Done with ports. Free them. -                            //free(ports); +                                                                jack_free(ports);  // p4.0.29                        }                      }                      }   -                   -                  // p3.3.55 Removed. -                  //if(ports)  -                    // Done with ports. Free them. -                    //delete ports; -                  //  free(ports); -                  //ports = NULL;        }  } @@ -1360,18 +1019,12 @@ void JackAudioDevice::registerClient()        if(!checkJackClient(_client)) return;        jack_set_process_callback(_client, processAudio, 0);        jack_set_sync_callback(_client, processSync, 0); -      // FIXME: FIXME: -      // Added by Tim. p3.3.20 -      // Did not help. Seek during play: Jack keeps switching to STOP state after about 1-2 seconds timeout if sync is holding it up. -      // Nothing in MusE seems to be telling it to stop. -      // NOTE: Update: It was a bug in QJackCtl. Fixed now.        //jack_set_sync_timeout(_client, 5000000); // Change default 2 to 5 second sync timeout because prefetch may be very slow esp. with resampling !        jack_on_shutdown(_client, processShutdown, 0);        jack_set_buffer_size_callback(_client, bufsize_callback, 0);        jack_set_sample_rate_callback(_client, srate_callback, 0);        jack_set_port_registration_callback(_client, registration_callback, 0); -      // p3.3.37        jack_set_client_registration_callback(_client, client_registration_callback, 0);        jack_set_port_connect_callback(_client, port_connect_callback, 0); @@ -1384,7 +1037,6 @@ void JackAudioDevice::registerClient()  //   registerInPort  //--------------------------------------------------------- -//void* JackAudioDevice::registerInPort(const char* name)  void* JackAudioDevice::registerInPort(const char* name, bool midi)        {        if (JACK_DEBUG) @@ -1401,7 +1053,6 @@ void* JackAudioDevice::registerInPort(const char* name, bool midi)  //   registerOutPort  //--------------------------------------------------------- -//void* JackAudioDevice::registerOutPort(const char* name)  void* JackAudioDevice::registerOutPort(const char* name, bool midi)        {        if (JACK_DEBUG) @@ -1452,7 +1103,7 @@ void JackAudioDevice::disconnect(void* src, void* dst)        if (JACK_DEBUG)              printf("JackAudioDevice::disconnect()\n");        if(!checkJackClient(_client)) return; -      if(!src || !dst)  // p3.3.55 +      if(!src || !dst)            return;        const char* sn = jack_port_name((jack_port_t*) src);        const char* dn = jack_port_name((jack_port_t*) dst); @@ -1478,7 +1129,6 @@ void JackAudioDevice::disconnect(void* src, void* dst)  //   start  //--------------------------------------------------------- -//void JackAudioDevice::start()  void JackAudioDevice::start(int /*priority*/)        {        if (JACK_DEBUG) @@ -1488,7 +1138,7 @@ void JackAudioDevice::start(int /*priority*/)        MusEGlobal::doSetuid();        if (jack_activate(_client)) { -            MusEGlobal::undoSetuid();   // p3.3.51 +            MusEGlobal::undoSetuid();                 fprintf (stderr, "JACK: cannot activate client\n");              exit(-1);              } @@ -1530,7 +1180,6 @@ void JackAudioDevice::start(int /*priority*/)                    }              } -      // p3.3.37        // Connect the Jack midi client ports to device ports.        connectJackMidiPorts(); @@ -1723,9 +1372,6 @@ void JackAudioDevice::getJackPorts(const char** ports, std::list<QString>& name_              name_list.push_back(qname);              } -      // p3.3.37 -      //if(ports) -        //free(ports);              //  jack_free(ports);  // p4.0.29        //return clientList; @@ -1744,61 +1390,6 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)        const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;        const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput); -      /* -      QString qname; -      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]; -             -            int nsz = jack_port_name_size(); -            char buffer[nsz]; -             -            strncpy(buffer, *p, nsz); -            //if (strncmp(buffer, "MusE", 4) == 0) -            //{ -            //  if(MusEGlobal::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(MusEGlobal::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); -            } -      */ -              if(ports)        {          getJackPorts(ports, clientList, midi, true, aliases);   // Get physical ports first. @@ -1823,61 +1414,6 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)        const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;        const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); -      /* -      QString qname; -      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]; -             -            int nsz = jack_port_name_size(); -            char buffer[nsz]; -             -            strncpy(buffer, *p, nsz); -            //if (strncmp(buffer, "MusE", 4) == 0) -            //{ -            //  if(MusEGlobal::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(MusEGlobal::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); -            } -      */ -              if(ports)        {          getJackPorts(ports, clientList, midi, true, aliases);   // Get physical ports first. @@ -1979,37 +1515,6 @@ void JackAudioDevice::setFreewheel(bool f)        }  //--------------------------------------------------------- -//   dummySync -//--------------------------------------------------------- - -bool JackAudioDevice::dummySync(int state) -{ -  // Roughly segment time length. -  //timespec ts = { 0, (1000000000 * MusEGlobal::segmentSize) / MusEGlobal::sampleRate };     // In nanoseconds. -  unsigned int sl = (1000000 * MusEGlobal::segmentSize) / MusEGlobal::sampleRate;            // In microseconds. -   -  double ct = curTime(); -  // Wait for a default maximum of 5 seconds.  -  // Similar to how Jack is supposed to wait a default of 2 seconds for slow clients. -  // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here. -  while((curTime() - ct) < 5.0)   -  { -    // Is MusE audio ready to roll? -    if(MusEGlobal::audio->sync(state, dummyPos)) -      return true; -     -    // Not ready. Wait a 'segment', try again... -    //nanosleep(&ts, NULL);   -    usleep(sl);              // usleep is supposed to be obsolete! -  } -     -  //if(JACK_DEBUG) -    printf("JackAudioDevice::dummySync Sync timeout - audio not ready!\n"); -   -  return false; -} - -//---------------------------------------------------------  //   startTransport  //--------------------------------------------------------- @@ -2022,19 +1527,7 @@ void JackAudioDevice::startTransport()        //  as if processSync was called.         if(!MusEGlobal::useJackTransport.value())        { -        //dummyState = Audio::START_PLAY; -         -        // Is MusE audio ready to roll? -        //if(dummySync(dummyState)) -        if(dummySync(Audio::START_PLAY)) -        { -          // MusE audio is ready to roll. Let's play. -          dummyState = Audio::PLAY; -          return; -        } -           -        // Ready or not, we gotta roll. Similar to how Jack is supposed to roll anyway. -        dummyState = Audio::PLAY; +        _dummyStatePending = Audio::START_PLAY;          return;        } @@ -2052,11 +1545,9 @@ void JackAudioDevice::stopTransport()        if (JACK_DEBUG)              printf("JackAudioDevice::stopTransport()\n"); -      dummyState = Audio::STOP; -              if(!MusEGlobal::useJackTransport.value())        { -        //dummyState = Audio::STOP; +        _dummyStatePending = Audio::STOP;          return;        } @@ -2077,32 +1568,11 @@ void JackAudioDevice::seekTransport(unsigned frame)        if (JACK_DEBUG)              printf("JackAudioDevice::seekTransport() frame:%d\n", frame); -      dummyPos = frame;        if(!MusEGlobal::useJackTransport.value())        { -        // If we're not using Jack's transport, just pass the current state and new frame along -        //  as if processSync was called.  -        //dummyPos = frame; -        int tempState = dummyState; -        //dummyState = Audio::START_PLAY; -         -        // Is MusE audio ready yet? -        //MusEGlobal::audio->sync(dummyState, dummyPos); -        //if(dummySync(dummyState)) -        if(dummySync(Audio::START_PLAY)) -        { -          dummyState = tempState; -          return; -        } -         -        // Not ready, resume previous state anyway. -        // FIXME: Observed: Seek during play: Jack transport STOPs on timeout.  -        // Docs say when starting play, transport will roll anyway, ready or not (observed), -        //  but don't mention what should happen on seek during play.  -        // And setting the slow-sync timeout doesn't seem to do anything! -        // NOTE: Update: It was a bug with QJackCtl. Fixed now. -        //dummyState = tempState; -        dummyState = Audio::STOP; +        _dummyPosPending   = frame; +        // STOP -> STOP means seek in stop mode. PLAY -> START_PLAY means seek in play mode. +        _dummyStatePending = (dummyState == Audio::STOP ? Audio::STOP : Audio::START_PLAY);          return;        } @@ -2120,28 +1590,11 @@ void JackAudioDevice::seekTransport(const Pos &p)        if (JACK_DEBUG)              printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame()); -      dummyPos = p.frame();        if(!MusEGlobal::useJackTransport.value())        { -        // If we're not using Jack's transport, just pass the current state and new frame along -        //  as if processSync was called.  -        //dummyPos = p.frame(); -        int tempState = dummyState; -        //dummyState = Audio::START_PLAY; -         -        // Is MusE audio ready yet? -        //MusEGlobal::audio->sync(dummyState, dummyPos); -        //if(dummySync(dummyState)) -        if(dummySync(Audio::START_PLAY)) -        { -          dummyState = tempState; -          return; -        } -         -        // Not ready, resume previous state anyway. -        // FIXME: See fixme in other seekTransport... -        //dummyState = tempState; -        dummyState = Audio::STOP; +        _dummyPosPending   = p.frame(); +        // STOP -> STOP means seek in stop mode. PLAY -> START_PLAY means seek in play mode. +        _dummyStatePending = (dummyState == Audio::STOP ? Audio::STOP : Audio::START_PLAY);          return;        } @@ -2380,8 +1833,7 @@ void exitJackAudio()        if (JACK_DEBUG)              printf("exitJackAudio() after delete jackAudio\n"); -      // Added by Tim. p3.3.14 -      MusEGlobal::audioDevice = NULL;       +      MusEGlobal::audioDevice = NULL;      // By Tim        }  } // namespace MusECore diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h index c4d37db9..838a20df 100644 --- a/muse2/muse/driver/jackaudio.h +++ b/muse2/muse/driver/jackaudio.h @@ -40,13 +40,16 @@ class MidiPlayEvent;  class JackAudioDevice : public AudioDevice {        jack_client_t* _client; -      double sampleTime; -      int samplePos; +      //double sampleTime; +      //int samplePos; +      float _syncTimeout;        jack_transport_state_t transportState;        jack_position_t pos;        char jackRegisteredName[16];        int dummyState;        int dummyPos; +      volatile int _dummyStatePending; +      volatile int _dummyPosPending;        // Free-running frame counter incremented always in process.        jack_nframes_t _frameCounter;  @@ -58,14 +61,13 @@ class JackAudioDevice : public AudioDevice {        virtual ~JackAudioDevice();        virtual void nullify_client() { _client = 0; } -      virtual inline int deviceType() const { return JACK_AUDIO; }   // p3.3.52 +      virtual inline int deviceType() const { return JACK_AUDIO; }           void scanMidiPorts();        //virtual void start();        virtual void start(int);        virtual void stop (); -      virtual bool dummySync(int state); // Artificial sync when not using Jack transport.        virtual int framePos() const;        virtual unsigned frameTime() const     { return _frameCounter; }   @@ -80,8 +82,6 @@ class JackAudioDevice : public AudioDevice {        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*/); diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp index 7a12b92d..706fa269 100644 --- a/muse2/muse/driver/jackmidi.cpp +++ b/muse2/muse/driver/jackmidi.cpp @@ -24,6 +24,7 @@  #include <QString>  #include <stdio.h> +#include <string.h>  #include <jack/jack.h>  //#include <jack/midiport.h> @@ -43,6 +44,8 @@  #include "../mplugins/midiitransform.h"  #include "../mplugins/mitplugin.h"  #include "xml.h" +#include "gconfig.h" +#include "track.h"  // Turn on debug messages.  //#define JACK_MIDI_DEBUG @@ -336,10 +339,10 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)          event.setLoopNum(MusEGlobal::audio->loopCount());        if (MusEGlobal::midiInputTrace) { -            printf("Jack MidiInput: "); +            printf("MidiIn Jack: <%s>: ", name().toLatin1().constData());              event.dump();              } - +                    int typ = event.type();        if(_port != -1) @@ -431,7 +434,8 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)        {        MidiRecordEvent event;        event.setB(0); - +      event.setPort(_port); +              // 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 @@ -452,6 +456,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)        int a    = *(ev->buffer + 1) & 0x7f;        int b    = *(ev->buffer + 2) & 0x7f;        event.setType(type); +        switch(type) {              case ME_NOTEON:              case ME_NOTEOFF: @@ -494,7 +499,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)                                  return;                            case ME_SONGPOS:                                      if(_port != -1) -                                  MusEGlobal::midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) >> 2 )); // LSB then MSB +                                  MusEGlobal::midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) << 7 )); // LSB then MSB                                  return;                            //case ME_SONGSEL:                                //case ME_TUNE_REQ:    @@ -525,11 +530,6 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)                return;              } -      if (MusEGlobal::midiInputTrace) { -            printf("MidiInput<%s>: ", name().toLatin1().constData()); -            event.dump(); -            } -                    #ifdef JACK_MIDI_DEBUG        printf("MidiJackDevice::eventReceived time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());        #endif   @@ -600,14 +600,6 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)        //if(port >= JACK_MIDI_CHANNELS)        //  return false; -      //if (midiOutputTrace) { -      //      printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().constData()); -      //      e.dump(); -      //      } -       -      //if(MusEGlobal::debugMsg) -      //  printf("MidiJackDevice::queueEvent\n"); -            if(!_out_client_jackport)             return false;        void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);   @@ -626,9 +618,14 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)              }        #ifdef JACK_MIDI_DEBUG -      printf("MidiJackDevice::queueEvent time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB()); +      printf("MidiJackDevice::queueEvent pos:%d fo:%d ft:%d time:%d type:%d ch:%d A:%d B:%d\n", pos, frameOffset, ft, e.time(), e.type(), e.channel(), e.dataA(), e.dataB());        #endif   +      if (MusEGlobal::midiOutputTrace) { +            printf("MidiOut: Jack: <%s>: ", name().toLatin1().constData()); +            e.dump(); +            } +                    switch(e.type()) {              case ME_NOTEON:              case ME_NOTEOFF: @@ -698,14 +695,47 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)                    }                    break;              case ME_SONGPOS: +                  { +                  #ifdef JACK_MIDI_DEBUG +                  printf("MidiJackDevice::queueEvent songpos %d\n", e.dataA()); +                  #endif   +                     +                  unsigned char* p = jack_midi_event_reserve(pb, ft, 3); +                  if (p == 0) { +                        #ifdef JACK_MIDI_DEBUG +                        fprintf(stderr, "MidiJackDevice::queueEvent songpos: buffer overflow, stopping until next cycle\n");   +                        #endif   +                        return false; +                        } +                  int pos = e.dataA();       +                  p[0] = e.type(); +                  p[1] = pos & 0x7f;         // LSB +                  p[2] = (pos >> 7) & 0x7f;  // MSB +                  } +                  break;              case ME_CLOCK:              case ME_START:              case ME_CONTINUE:              case ME_STOP: +                  { +                  #ifdef JACK_MIDI_DEBUG +                  printf("MidiJackDevice::queueEvent realtime %x\n", e.type()); +                  #endif   +                     +                  unsigned char* p = jack_midi_event_reserve(pb, ft, 1); +                  if (p == 0) { +                        #ifdef JACK_MIDI_DEBUG +                        fprintf(stderr, "MidiJackDevice::queueEvent realtime: buffer overflow, stopping until next cycle\n");   +                        #endif   +                        return false; +                        } +                  p[0] = e.type(); +                  } +                  break; +            default:                    if(MusEGlobal::debugMsg)                      printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); -                  //return false; -                  return true;   // Absorb the event. Don't want it hanging around in the list. FIXME: Support these?   p4.0.15 Tim. +                  return true;   // Absorb the event. Don't want it hanging around in the list.                     break;              } @@ -757,12 +787,18 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)            //       event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);            if (hb != 0xff) +          {                    if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))                    return false;  // p4.0.15 Inform that processing the event in general failed. Ditto all below...  +///            t += 1;       +          }            if (lb != 0xff) -                if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb))) +          { +                if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))                    return false; -          if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0))) +///            t += 1;       +          } +          if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0)))              return false;      //      } @@ -815,13 +851,15 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)              {                    if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))                      return false; +///                  t += 1;                    }              if (lb != 0xff)              { -                  if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb))) +                  if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))                      return false; +///                  t += 1;                    } -            if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0))) +            if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0)))                return false;        //      } @@ -851,7 +889,8 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        int dataL = b & 0x7f;        if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, ctrlH, dataH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlL, dataL)))          return false;      }      else if (a < CTRL_NRPN_OFFSET)  @@ -860,19 +899,22 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        int ctrlL = a & 0x7f;        if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))          return false; -      if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))          return false; +///     t += 1;       -      t += 3;   +      //t += 3;          // Select null parameters so that subsequent data controller events do not upset the last *RPN controller.        //sendNullRPNParams(chn, false);        if(nvh != 0xff)        {          if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))            return false; -        t += 1;   +///        t += 1;          }        if(nvl != 0xff)        { @@ -887,18 +929,21 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        int ctrlL = a & 0x7f;        if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))          return false; -      if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))          return false; +///     t += 1;       -      t += 3;   +      //t += 3;          //sendNullRPNParams(chn, true);        if(nvh != 0xff)        {          if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))            return false; -        t += 1;   +///        t += 1;          }        if(nvl != 0xff)        { @@ -914,20 +959,24 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        int dataL = b & 0x7f;        if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))          return false; -      if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))          return false; +///     t += 1;       -      t += 4;   +      //t += 4;          //sendNullRPNParams(chn, false);        if(nvh != 0xff)        {          if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))            return false; -        t += 1;   +///        t += 1;          }        if(nvl != 0xff)        { @@ -943,20 +992,24 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)        int dataL = b & 0x7f;        if(!queueEvent(MidiPlayEvent(t,   port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))          return false; -      if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))          return false; -      if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL))) +///     t += 1;       +      if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))          return false; +///     t += 1;       -      t += 4;   +      //t += 4;          //sendNullRPNParams(chn, true);        if(nvh != 0xff)        {          if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))            return false; -        t += 1;   +///        t += 1;          }        if(nvl != 0xff)        { @@ -988,8 +1041,16 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)  void MidiJackDevice::processMidi()  { +  //bool stop = stopPending;  // Snapshots +  //bool seek = seekPending;  // +  //seekPending = stopPending = false; +    processStuckNotes();        +  // Don't process if the device is not assigned to a port. +  //if(_port == -1) +  //  return; +        void* port_buf = 0;    if(_out_client_jackport && _writeEnable)      { @@ -997,65 +1058,294 @@ void MidiJackDevice::processMidi()      jack_midi_clear_buffer(port_buf);    }   +  int port = midiPort(); +  MidiPort* mp = port == -1 ? 0 : &MusEGlobal::midiPorts[port]; + +  /* +  bool is_playing = MusEGlobal::audio->isPlaying();  // TODO Check this. It includes LOOP1 and LOOP2 besides PLAY. +  //bool is_playing = MusEGlobal::audio->isPlaying() || MusEGlobal::audio->isStarting();  +  int pos = MusEGlobal::audio->tickPos(); +  bool ext_sync = MusEGlobal::extSyncFlag.value(); + +  if(mp) +  { +    MidiSyncInfo& si = mp->syncInfo(); +    if(stop) +    { +      // Don't send if external sync is on. The master, and our sync routing system will take care of that.    +      if(!ext_sync) +      { +        // Shall we check open flags? +        //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) +        //if(!(dev->openFlags() & 1)) +        //  return; +               +        // Send MMC stop... +        if(si.MMCOut()) +        { +          unsigned char msg[mmcStopMsgLen]; +          memcpy(msg, mmcStopMsg, mmcStopMsgLen); +          msg[1] = si.idOut(); +          putEvent(MidiPlayEvent(0, 0, ME_SYSEX, msg, mmcStopMsgLen)); +        } +         +        // Send midi stop... +        if(si.MRTOut())  +        { +          putEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0)); +          // 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(MusEGlobal::audio->tickPos() * 4 / config.division); +        } +      }   +    } +     +    if(seek) +    { +      // Don't send if external sync is on. The master, and our sync routing system will take care of that.   +      if(!ext_sync) +      { +        // Send midi stop and song position pointer... +        if(si.MRTOut()) +        { +          // Shall we check for device write open flag to see if it's ok to send?... +          //if(!(rwFlags() & 0x1) || !(openFlags() & 1)) +          //if(!(openFlags() & 1)) +          //  continue; +          putEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0)); +          // Hm, try scheduling these for after stuck notes scheduled below... +          //putEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0)); +          //if(is_playing) +          //  putEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0)); +        }     +      } +    }     +  } +   +  if(stop || (seek && is_playing)) +  { +    // Clear all notes and handle stuck notes... +    _playEvents.clear(); +    for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)  +    { +      MidiPlayEvent ev = *i; +      ev.setTime(0);  // Schedule immediately. +      putEvent(ev); +    } +    _stuckNotes.clear(); +  } + +  if(mp) +  { +    MidiSyncInfo& si = mp->syncInfo(); +    // Try scheduling these now for after stuck notes scheduled above... +    if(stop || seek) +    { +      // Reset sustain. +      for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  +        if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)  +          putEvent(MidiPlayEvent(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0)); +    } +    if(seek) +    { +      // Send new song position. +      if(!ext_sync && si.MRTOut()) +      { +        int beat = (pos * 4) / MusEGlobal::config.division; +        putEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0)); +      } +      // Send new controller values. +      MidiCtrlValListList* cll = mp->controller(); +      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; +          // Don't send if part or track is muted or off. +          if(!p || p->mute()) +            continue; +          Track* track = p->track(); +          if(track && (track->isMute() || track->off()))    +            continue; +          unsigned t = (unsigned)imcv->first; +          // Do not add values that are outside of the part. +          if(t >= p->tick() && t < (p->tick() + p->lenTick())) +            // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position. +            mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos); +        } +      } +      // Send continue. +      // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready. +      //if(is_playing && !ext_sync && si.MRTOut()) +      //  putEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0)); +    } +  } +  */ +      while(!eventFifo.isEmpty())    {      MidiPlayEvent e(eventFifo.peek());  +    //printf("MidiJackDevice::processMidi FIFO event time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());       // 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.    } +  //if(!(stop || (seek && is_playing))) +  //  processStuckNotes();   +      if(_playEvents.empty()) -  { -    //printf("MidiJackDevice::processMidi play events empty\n");       return; -  }    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());       // 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) -    { -      MidiPort* mp = &MusEGlobal::midiPorts[_port]; -      if(i->type() == ME_CONTROLLER)  -      { -        int da = i->dataA(); -        int db = i->dataB(); -        db = mp->limitValToInstrCtlRange(da, db); -        if(!mp->setHwCtrlState(i->channel(), da, db)) -          continue; -        //mp->setHwCtrlState(i->channel(), da, db); -      } -      else -      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 -      if(i->type() == ME_PROGRAM)  -      { -        if(!mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA())) -          continue; -        //mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA()); -      } -    } +    if(mp && !mp->sendHwCtrlState(*i, true)) // Force the event to be sent. +      continue;      // 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;    }    _playEvents.erase(_playEvents.begin(), i); +} + +/* +//--------------------------------------------------------- +//   handleStop +//--------------------------------------------------------- + +void MidiJackDevice::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 = &MusEGlobal::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); +//       putEvent(ev); +//       // Do sendEvent to get the optimizations - send only on a change of value. +//       //mp->sendEvent(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(!MusEGlobal::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(MusEGlobal::audio->tickPos() * 4 / config.division); +//     } +//   }   +} +*/ + +/* +//--------------------------------------------------------- +//   handleSeek +//--------------------------------------------------------- + +void MidiJackDevice::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 = &MusEGlobal::midiPorts[_port]; +  //MidiCtrlValListList* cll = mp->controller(); +  //int pos = MusEGlobal::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; +//       //printf("MidiAlsaDevice::handleSeek _port:%d ctl:%d num:%d val:%d\n", _port, ivl->first >> 24, vl->num(), imcv->second.val);  +//       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()) ) +//         // Keep this and the section in processMidi() just in case we need to revert... +//         //_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val)); +//         // Hmm, play event list for immediate playback? Try putEvent, putMidiEvent, or sendEvent (for the optimizations) instead.  +//         mp->sendEvent(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(!MusEGlobal::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) / MusEGlobal::config.division; +//          +//       //bool isPlaying = (state == PLAY); +//       bool isPlaying = MusEGlobal::audio->isPlaying();  // TODO Check this it includes LOOP1 and LOOP2 besides PLAY.  p4.0.22 +//          +//       mp->sendStop(); +//       mp->sendSongpos(beat); +//       // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready. +//       //if(isPlaying) +//       //  mp->sendContinue(); +//     }     +//   }  } +*/  //---------------------------------------------------------  //   initMidiJack diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h index d2c14190..c8f7f901 100644 --- a/muse2/muse/driver/jackmidi.h +++ b/muse2/muse/driver/jackmidi.h @@ -74,13 +74,15 @@ class MidiJackDevice : public MidiDevice {     public:        MidiJackDevice(const QString& name);  +      virtual ~MidiJackDevice();         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 handleStop();   +      //virtual void handleSeek();        virtual void processMidi(); -      virtual ~MidiJackDevice();         virtual void recordEvent(MidiRecordEvent&); diff --git a/muse2/muse/driver/rtctimer.cpp b/muse2/muse/driver/rtctimer.cpp index 365b8501..c50fadf6 100644 --- a/muse2/muse/driver/rtctimer.cpp +++ b/muse2/muse/driver/rtctimer.cpp @@ -99,9 +99,9 @@ unsigned int RtcTimer::setTimerFreq(unsigned int freq)      {      int rc = ioctl(timerFd, RTC_IRQP_SET, freq);      if (rc == -1) { -            fprintf(stderr, "RtcTimer::setTimerFreq(): cannot set tick on /dev/rtc: %s\n", +            fprintf(stderr, "RtcTimer::setTimerFreq(): cannot set freq %d on /dev/rtc: %s\n", freq,                 strerror(errno)); -            fprintf(stderr, "  precise timer not available\n"); +            fprintf(stderr, "  precise timer not available, check file permissions and allowed RTC freq (/sys/class/rtc/rtc0/max_user_freq)\n");              return 0;              }      return freq; diff --git a/muse2/muse/driver/rtctimer.h b/muse2/muse/driver/rtctimer.h index 425ea643..2b1921a2 100644 --- a/muse2/muse/driver/rtctimer.h +++ b/muse2/muse/driver/rtctimer.h @@ -1,12 +1,12 @@ -  //========================================================= -  //  MusE -  //  Linux Music Editor -  //  $Id: rtctimer.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $ -  // -  //  Most code moved from midiseq.cpp -  // -  //  (C) Copyright -2004 Werner Schweer (werner@seh.de) -  //  (C) Copyright 2004 Robert Jonsson (rj@spamatica.se) +//========================================================= +//  MusE +//  Linux Music Editor +//  $Id: rtctimer.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $ +// +//  Most code moved from midiseq.cpp +// +//  (C) Copyright -2004 Werner Schweer (werner@seh.de) +//  (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -22,7 +22,7 @@  //  along with this program; if not, write to the Free Software  //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.  // -  //========================================================= +//=========================================================  #ifndef __RTCTIMER_H__  #define __RTCTIMER_H__ @@ -59,4 +59,4 @@ class RtcTimer : public Timer{  } // namespace MusECore -#endif //__ALSATIMER_H__ +#endif //__RTCTIMER_H__  | 
