Skip to content

Commit

Permalink
JACK Transport reposition
Browse files Browse the repository at this point in the history
  • Loading branch information
Igevorse committed Jun 29, 2014
1 parent c24022f commit d2b2050
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 28 deletions.
4 changes: 4 additions & 0 deletions mscore/driver.h
Expand Up @@ -47,12 +47,16 @@ class Driver {
virtual void stopTransport() = 0; virtual void stopTransport() = 0;
virtual void startTransport() = 0; virtual void startTransport() = 0;
virtual Transport getState() = 0; virtual Transport getState() = 0;
virtual void seekTransport(int) {}
virtual bool instantSeek() {return true;} // False only in JackAudio
virtual int sampleRate() const = 0; virtual int sampleRate() const = 0;
virtual void registerPort(const QString& /*name*/, bool /*input*/, bool /*midi*/) {} virtual void registerPort(const QString& /*name*/, bool /*input*/, bool /*midi*/) {}
virtual void unregisterPort(int) {} virtual void unregisterPort(int) {}
virtual void putEvent(const NPlayEvent&, unsigned /*framePos*/) {} virtual void putEvent(const NPlayEvent&, unsigned /*framePos*/) {}
virtual void midiRead() {} virtual void midiRead() {}
virtual void handleTimeSigTempoChanged() {} virtual void handleTimeSigTempoChanged() {}
virtual void checkTransportSeek(int, int) {}
virtual int bufferSize() {return 0;}
}; };




Expand Down
75 changes: 61 additions & 14 deletions mscore/jackaudio.cpp
Expand Up @@ -25,6 +25,7 @@
// #include "msynth/synti.h" // #include "msynth/synti.h"
#include "seq.h" #include "seq.h"
#include "libmscore/score.h" #include "libmscore/score.h"
#include "libmscore/repeatlist.h"


#include <jack/midiport.h> #include <jack/midiport.h>


Expand Down Expand Up @@ -282,24 +283,33 @@ int JackAudio::framePos() const
return (int)n; return (int)n;
} }


//---------------------------------------------------------
// freewheel_callback
//---------------------------------------------------------


static int bufsize_callback(jack_nframes_t /*n*/, void*) static void freewheel_callback(int /*starting*/, void*)
{ {
// qDebug("JACK: buffersize changed %d", n);
return 0;
} }


//--------------------------------------------------------- //---------------------------------------------------------
// freewheel_callback // sampleRateCallback
//--------------------------------------------------------- //---------------------------------------------------------


static void freewheel_callback(int /*starting*/, void*) int sampleRateCallback(jack_nframes_t sampleRate, void*)
{ {
qDebug("JACK: sample rate changed: %d", sampleRate);
MScore::sampleRate = sampleRate;
return 0;
} }


static int srate_callback(jack_nframes_t, void*) //---------------------------------------------------------
// bufferSizeCallback called if JACK buffer changed
//---------------------------------------------------------

int bufferSizeCallback(jack_nframes_t nframes, void *arg)
{ {
// qDebug("JACK: sample rate changed: %d", n); JackAudio* audio = (JackAudio*)arg;
audio->setBufferSize(nframes);
return 0; return 0;
} }


Expand Down Expand Up @@ -339,6 +349,7 @@ void JackAudio::timebase(jack_transport_state_t state, jack_nframes_t /*nframes*
qDebug()<<"Time signature and tempo changed: "<< pos->beats_per_minute<<", bar: "<< pos->bar<<",beat: "<<pos->beat<<", tick:"<<pos->tick<<", time sig: "<<pos->beats_per_bar<<"/"<<pos->beat_type; qDebug()<<"Time signature and tempo changed: "<< pos->beats_per_minute<<", bar: "<< pos->bar<<",beat: "<<pos->beat<<", tick:"<<pos->tick<<", time sig: "<<pos->beats_per_bar<<"/"<<pos->beat_type;
audio->timeSigTempoChanged = false; audio->timeSigTempoChanged = false;
} }
// TODO: Handle new_pos
} }
//--------------------------------------------------------- //---------------------------------------------------------
// processAudio // processAudio
Expand Down Expand Up @@ -457,13 +468,14 @@ bool JackAudio::init()
jack_set_error_function(jackError); jack_set_error_function(jackError);
jack_set_process_callback(client, processAudio, this); jack_set_process_callback(client, processAudio, this);
//jack_on_shutdown(client, processShutdown, this); //jack_on_shutdown(client, processShutdown, this);
jack_set_buffer_size_callback(client, bufsize_callback, this); jack_set_sample_rate_callback(client, sampleRateCallback, this);
jack_set_sample_rate_callback(client, srate_callback, this);
jack_set_port_registration_callback(client, registration_callback, this); jack_set_port_registration_callback(client, registration_callback, this);
jack_set_graph_order_callback(client, graph_callback, this); jack_set_graph_order_callback(client, graph_callback, this);
jack_set_freewheel_callback (client, freewheel_callback, this); jack_set_freewheel_callback (client, freewheel_callback, this);
if (jack_set_timebase_callback(client, 1, timebase, this) != 0) if (jack_set_timebase_callback(client, 1, timebase, this) != 0)
fprintf(stderr, "Unable to take over timebase.\n"); qDebug("Unable to take over timebase.");
if( jack_set_buffer_size_callback (client, bufferSizeCallback, this) != 0)
qDebug("Can not set bufferSizeCallback");
_segmentSize = jack_get_buffer_size(client); _segmentSize = jack_get_buffer_size(client);


MScore::sampleRate = sampleRate(); MScore::sampleRate = sampleRate();
Expand Down Expand Up @@ -531,12 +543,12 @@ void JackAudio::stopTransport()


Transport JackAudio::getState() Transport JackAudio::getState()
{ {
jack_position_t pos; int transportState = jack_transport_query(client, NULL);
int transportState = jack_transport_query(client, &pos);
switch (transportState) { switch (transportState) {
case JackTransportStopped: return Transport::STOP; case JackTransportStopped: return Transport::STOP;
case JackTransportLooping: case JackTransportLooping:
case JackTransportRolling: return Transport::PLAY; case JackTransportRolling: return Transport::PLAY;
case JackTransportStarting: return seq->isPlaying()?Transport::PLAY:Transport::STOP;// Keep current state
default: default:
return Transport::STOP; return Transport::STOP;
} }
Expand Down Expand Up @@ -638,9 +650,44 @@ void JackAudio::midiRead()
// midiDriver->read(); // midiDriver->read();
} }


//---------------------------------------------------------
// Called after tempo or time signature
// changed while playback
//---------------------------------------------------------

void JackAudio::handleTimeSigTempoChanged() void JackAudio::handleTimeSigTempoChanged()
{ {
timeSigTempoChanged = true; timeSigTempoChanged = true;
} }
}


//---------------------------------------------------------
// checkTransportSeek
//---------------------------------------------------------

void JackAudio::checkTransportSeek(int cur_frame, int nframes)
{
// Obtaining the current JACK Transport position
jack_position_t pos;
jack_transport_query(client, &pos);

int srate = MScore::sampleRate;
int cur_utick = seq->score()->utime2utick((qreal)cur_frame / srate);
int utick = seq->score()->utime2utick((qreal)pos.frame / srate);

// Conversion is not precise, should check frames and uticks
if (labs((long int)cur_frame-(long int)pos.frame)>nframes+1 && abs(utick - cur_utick)> seq->score()->utime2utick((qreal)nframes / srate)+1) {
qDebug()<<"JACK Transport position changed, cur_frame: "<<cur_frame<<",pos.frame: "<<pos.frame<<", frame diff: "<<labs((long int)cur_frame-(long int)pos.frame)<<"cur utick:"<<cur_utick<<",seek to utick: "<<utick<<", tick diff: "<<abs(utick - cur_utick);
seq->seek(utick, false);
}
}

//---------------------------------------------------------
// seekTransport
//---------------------------------------------------------

void JackAudio::seekTransport(int utick)
{
qDebug()<<"jack locate to utick: "<<utick<<", frame: "<<seq->score()->utick2utime(utick) * MScore::sampleRate;
jack_transport_locate(client, seq->score()->utick2utime(utick) * MScore::sampleRate);
}
}
5 changes: 5 additions & 0 deletions mscore/jackaudio.h
Expand Up @@ -62,13 +62,18 @@ class JackAudio : public Driver {
virtual void startTransport(); virtual void startTransport();
virtual void stopTransport(); virtual void stopTransport();
virtual Transport getState() override; virtual Transport getState() override;
virtual void seekTransport(int);
virtual bool instantSeek() {return false;} // False only in JackAudio
virtual int sampleRate() const { return jack_get_sample_rate(client); } virtual int sampleRate() const { return jack_get_sample_rate(client); }
virtual void putEvent(const NPlayEvent&, unsigned framePos); virtual void putEvent(const NPlayEvent&, unsigned framePos);
virtual void midiRead(); virtual void midiRead();


virtual void registerPort(const QString& name, bool input, bool midi); virtual void registerPort(const QString& name, bool input, bool midi);
virtual void unregisterPort(int); virtual void unregisterPort(int);
virtual void handleTimeSigTempoChanged(); virtual void handleTimeSigTempoChanged();
virtual void checkTransportSeek(int, int);
virtual int bufferSize() {return _segmentSize;}
void setBufferSize(int nframes) { _segmentSize = nframes;}
}; };




Expand Down
2 changes: 1 addition & 1 deletion mscore/jackweakapi.cpp
Expand Up @@ -249,7 +249,7 @@ DECL_FUNCTION(int, jack_set_timebase_callback, (jack_client_t *client,
DECL_FUNCTION(int, jack_transport_locate, (jack_client_t *client, jack_nframes_t frame), (client, frame)); DECL_FUNCTION(int, jack_transport_locate, (jack_client_t *client, jack_nframes_t frame), (client, frame));
DECL_FUNCTION(jack_transport_state_t, jack_transport_query, (const jack_client_t *client, jack_position_t *pos), (client, pos)); DECL_FUNCTION(jack_transport_state_t, jack_transport_query, (const jack_client_t *client, jack_position_t *pos), (client, pos));
DECL_FUNCTION(jack_nframes_t, jack_get_current_transport_frame, (const jack_client_t *client), (client)); DECL_FUNCTION(jack_nframes_t, jack_get_current_transport_frame, (const jack_client_t *client), (client));
DECL_FUNCTION(int, jack_transport_reposition, (jack_client_t *client, jack_position_t *pos), (client, pos)); DECL_FUNCTION(int, jack_transport_reposition, (jack_client_t *client, const jack_position_t *pos), (client, pos));
DECL_VOID_FUNCTION(jack_transport_start, (jack_client_t *client), (client)); DECL_VOID_FUNCTION(jack_transport_start, (jack_client_t *client), (client));
DECL_VOID_FUNCTION(jack_transport_stop, (jack_client_t *client), (client)); DECL_VOID_FUNCTION(jack_transport_stop, (jack_client_t *client), (client));
// DECL_VOID_FUNCTION(jack_get_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo)); // DECL_VOID_FUNCTION(jack_get_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo));
Expand Down
59 changes: 47 additions & 12 deletions mscore/seq.cpp
Expand Up @@ -316,10 +316,17 @@ void Seq::start()
if ((mscore->loop())) { if ((mscore->loop())) {
if(cs->selection().isRange()) if(cs->selection().isRange())
setLoopSelection(); setLoopSelection();
seek(cs->repeatList()->tick2utick(cs->loopInTick())); if (state == Transport::STOP) {
qDebug()<<"___calling seek from start with LoopInTick utick = "<<cs->repeatList()->tick2utick(cs->loopInTick());
seek(cs->repeatList()->tick2utick(cs->loopInTick()));
}
}
else {
if (state == Transport::STOP) {
qDebug()<<"___calling seek from start with playpos utick = "<<cs->repeatList()->tick2utick(cs->playPos());
seek(cs->repeatList()->tick2utick(cs->playPos()));
}
} }
else
seek(cs->repeatList()->tick2utick(cs->playPos()));
_driver->startTransport(); _driver->startTransport();
} }


Expand All @@ -339,7 +346,8 @@ void Seq::stop()
} }
if (!_driver) if (!_driver)
return; return;
_driver->stopTransport(); if(_driver->getState() == Transport::PLAY)
_driver->stopTransport();
if (cv) if (cv)
cv->setCursorOn(false); cv->setCursorOn(false);
if (cs) { if (cs) {
Expand Down Expand Up @@ -664,14 +672,16 @@ void Seq::process(unsigned n, float* buffer)
{ {
unsigned frames = n; unsigned frames = n;
Transport driverState = _driver->getState(); Transport driverState = _driver->getState();
// Checking for the reposition from Transport
_driver->checkTransportSeek(playTime, frames);


if (driverState != state) { if (driverState != state) {
// Got a message from JACK Transport panel: Play // Got a message from JACK Transport panel: Play
if (state == Transport::STOP && driverState == Transport::PLAY) { if (state == Transport::STOP && driverState == Transport::PLAY) {


if((preferences.useJackMidi || preferences.useJackAudio) && !getAction("play")->isChecked()) { if((preferences.useJackMidi || preferences.useJackAudio) && !getAction("play")->isChecked()) {
// Do not play while editing elements // Do not play while editing elements
if(mscore->state()==STATE_NORMAL && isRunning() && canStart()) { if (mscore->state() == STATE_NORMAL && isRunning() && canStart()) {
if (playlistChanged) if (playlistChanged)
collectEvents(); collectEvents();
getAction("play")->setChecked(true); getAction("play")->setChecked(true);
Expand Down Expand Up @@ -771,9 +781,20 @@ void Seq::process(unsigned n, float* buffer)
int utickLoop = cs->repeatList()->tick2utick(cs->loopOutTick()); int utickLoop = cs->repeatList()->tick2utick(cs->loopOutTick());
if (utickLoop < utickEnd) if (utickLoop < utickEnd)
if ((*pPlayPos)->first >= utickLoop) { if ((*pPlayPos)->first >= utickLoop) {
qDebug ("Process playPos = %d in/out tick = %d/%d getCurTick() = %d tickLoop = %d playTime = %d", qDebug ("Process playPos = %d in/out tick = %d/%d getCurTick() = %d tickLoop = %d playTime = %d",
(*pPlayPos)->first, cs->loopInTick(), cs->loopOutTick(), getCurTick(), utickLoop, *pPlayTime); (*pPlayPos)->first, cs->loopInTick(), cs->loopOutTick(), getCurTick(), utickLoop, *pPlayTime);
emit toGui('3'); // Exit this function to avoid segmentation fault in Scoreview if (_driver->instantSeek()) {
emit toGui('3');
}
else { // JACK
int loopInUtick = cs->repeatList()->tick2utick(cs->loopInTick());
seek(loopInUtick);
if (loopInUtick != 0) {
int seekto = loopInUtick-2*cs->utime2utick((qreal)_driver->bufferSize() / MScore::sampleRate);
seek((seekto>0)?seekto:0,false);
}
}
// Exit this function to avoid segmentation fault in Scoreview
return; return;
} }
} }
Expand Down Expand Up @@ -970,11 +991,18 @@ void Seq::setPos(int utick)
// send seek message to sequencer // send seek message to sequencer
//--------------------------------------------------------- //---------------------------------------------------------


void Seq::seek(int utick) void Seq::seek(int utick, bool can_wait)
{ {
if (cs == 0) if (cs == 0)
return; return;


// If driver can't seek immediately, just send a signal to seek.
if (!_driver->instantSeek() && can_wait) {
_driver->seekTransport(utick);
if (utick != 0)
return; // rewind to 0 immediately
}

if (playlistChanged) if (playlistChanged)
collectEvents(); collectEvents();
int tick = cs->repeatList()->utick2tick(utick); int tick = cs->repeatList()->utick2tick(utick);
Expand All @@ -992,7 +1020,8 @@ void Seq::seek(int utick, Segment* seg)
if (seg) if (seg)
mscore->currentScoreView()->moveCursor(seg->tick()); mscore->currentScoreView()->moveCursor(seg->tick());


cs->setPlayPos(cs->repeatList()->utick2tick(utick)); int tick = cs->repeatList()->utick2tick(utick);
cs->setPlayPos(tick);
cs->setLayoutAll(false); cs->setLayoutAll(false);
cs->end(); cs->end();


Expand All @@ -1003,7 +1032,7 @@ void Seq::seek(int utick, Segment* seg)


guiToSeq(SeqMsg(SeqMsgId::SEEK, utick)); guiToSeq(SeqMsg(SeqMsgId::SEEK, utick));
guiPos = events.lower_bound(utick); guiPos = events.lower_bound(utick);
mscore->setPos(utick); mscore->setPos(tick);
unmarkNotes(); unmarkNotes();
cs->update(); cs->update();
} }
Expand Down Expand Up @@ -1317,6 +1346,7 @@ void Seq::heartBeatTimeout()


if (state != Transport::PLAY || inCountIn) if (state != Transport::PLAY || inCountIn)
return; return;

int endTime = playTime; int endTime = playTime;


mutex.lock(); mutex.lock();
Expand Down Expand Up @@ -1458,8 +1488,13 @@ void Seq::setLoopSelection()
cs->setLoopOutTick(cs->selection().tickEnd()); cs->setLoopOutTick(cs->selection().tickEnd());
} }


//---------------------------------------------------------
// Called after tempo or time signature
// changed while playback
//---------------------------------------------------------

void Seq::handleTimeSigTempoChanged() void Seq::handleTimeSigTempoChanged()
{ {
_driver->handleTimeSigTempoChanged(); _driver->handleTimeSigTempoChanged();
} }
} }
2 changes: 1 addition & 1 deletion mscore/seq.h
Expand Up @@ -157,7 +157,7 @@ class Seq : public QObject, public Sequencer {


public slots: public slots:
void setRelTempo(double); void setRelTempo(double);
void seek(int); void seek(int, bool can_wait = true);
void stopNotes(int channel = -1); void stopNotes(int channel = -1);
void start(); void start();
void stop(); void stop();
Expand Down

0 comments on commit d2b2050

Please sign in to comment.