diff options
author | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
commit | 9c4664d162c537ba4dd4fd8220971c0fb727103a (patch) | |
tree | 37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/driver | |
parent | e87fedf1be804f7ec774071d844b1f163be30b96 (diff) |
final merge
Diffstat (limited to 'muse2/muse/driver')
-rw-r--r-- | muse2/muse/driver/alsamidi.cpp | 10 | ||||
-rw-r--r-- | muse2/muse/driver/jack.cpp | 182 | ||||
-rw-r--r-- | muse2/muse/driver/jackaudio.h | 2 | ||||
-rw-r--r-- | muse2/muse/driver/jackmidi.cpp | 38 |
4 files changed, 168 insertions, 64 deletions
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp index f75b9c33..e3e71365 100644 --- a/muse2/muse/driver/alsamidi.cpp +++ b/muse2/muse/driver/alsamidi.cpp @@ -1318,24 +1318,24 @@ void alsaProcessMidiInput() break; case SND_SEQ_EVENT_CLOCK: - MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CLOCK); + MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CLOCK, curTime()); //mdev->syncInfo().trigMCSyncDetect(); break; case SND_SEQ_EVENT_START: - MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_START); + MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_START, curTime()); break; case SND_SEQ_EVENT_CONTINUE: - MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CONTINUE); + MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CONTINUE, curTime()); break; case SND_SEQ_EVENT_STOP: - MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_STOP); + MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_STOP, curTime()); break; case SND_SEQ_EVENT_TICK: - MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_TICK); + MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_TICK, curTime()); //mdev->syncInfo().trigTickDetect(); break; diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index 4cc8bfb8..05d47955 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -42,6 +42,7 @@ #include "tempo.h" #include "sync.h" #include "utils.h" +#include "gconfig.h" #include "midi.h" #include "mididev.h" @@ -50,7 +51,7 @@ #include "jackmidi.h" -#define JACK_DEBUG 0 +#define JACK_DEBUG 0 //#include "errorhandler.h" @@ -176,7 +177,7 @@ int JackAudioDevice::processAudio(jack_nframes_t frames, void*) } } } - + //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); } @@ -196,8 +197,21 @@ int JackAudioDevice::processAudio(jack_nframes_t frames, void*) static int processSync(jack_transport_state_t state, jack_position_t* pos, void*) { if (JACK_DEBUG) - printf("processSync()\n"); + { + printf("processSync frame:%u\n", pos->frame); + if(pos->valid & JackPositionBBT) + { + if(JACK_DEBUG) + { + printf("processSync BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n", + pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute); + if(pos->valid & JackBBTFrameOffset) + printf("processSync BBTFrameOffset: %u\n", pos->bbt_offset); + } + } + } + if(!MusEGlobal::useJackTransport.value()) return 1; @@ -237,49 +251,54 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void* //--------------------------------------------------------- static void timebase_callback(jack_transport_state_t /* state */, - jack_nframes_t /* nframes */, + jack_nframes_t nframes, jack_position_t* pos, - int /* new_pos */, + int new_pos, void*) { - if (JACK_DEBUG) - printf("Jack timebase_callback pos->frame:%u MusEGlobal::audio->tickPos:%d MusEGlobal::song->cpos:%d\n", pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos()); - - //Pos p(pos->frame, false); + + if (JACK_DEBUG) + { + if(pos->valid & JackPositionBBT) + printf("timebase_callback BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n", + pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute); + if(pos->valid & JackBBTFrameOffset) + printf("timebase_callback BBTFrameOffset: %u\n", pos->bbt_offset); + if(pos->valid & JackPositionTimecode) + printf("timebase_callback JackPositionTimecode: frame_time:%f next_time:%f\n", pos->frame_time, pos->next_time); + if(pos->valid & JackAudioVideoRatio) + printf("timebase_callback JackAudioVideoRatio: %f\n", pos->audio_frames_per_video_frame); + if(pos->valid & JackVideoFrameOffset) + printf("timebase_callback JackVideoFrameOffset: %u\n", pos->video_offset); + } + + //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 ! //Pos p(MusEGlobal::extSyncFlag.value() ? MusEGlobal::song->cpos() : pos->frame, MusEGlobal::extSyncFlag.value() ? true : false); pos->valid = JackPositionBBT; p.mbt(&pos->bar, &pos->beat, &pos->tick); + pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); pos->bar++; pos->beat++; - pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); - - // - // dummy: - // - //pos->beats_per_bar = 4; - //pos->beat_type = 4; - //pos->ticks_per_beat = 384; - // - /* // From example client transport.c : - float time_beats_per_bar = 4.0; - float time_beat_type = 0.25; // Huh? Inverted? From docs: "Time signature 'denominator'" - double time_ticks_per_beat = 1920.0; // Huh? Ticks per beat should be 24 etc. not 384 or 1920 etc. Otherwise it would be called 'frames_per_beat'. - double time_beats_per_minute = 120.0; - */ - // int z, n; AL::sigmap.timesig(p.tick(), z, n); pos->beats_per_bar = z; pos->beat_type = n; - //pos->ticks_per_beat = config.division; - pos->ticks_per_beat = 24; + pos->ticks_per_beat = MusEGlobal::config.division; + //pos->ticks_per_beat = 24; + + double tempo = MusEGlobal::tempomap.tempo(p.tick()); + pos->beats_per_minute = (60000000.0 / tempo) * double(MusEGlobal::tempomap.globalTempo())/100.0; + if (JACK_DEBUG) + { + printf("timebase_callback is new_pos:%d nframes:%u frame:%u tickPos:%d cpos:%d\n", new_pos, nframes, pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos()); + printf(" new: bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n", + pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute); + } - int tempo = MusEGlobal::tempomap.tempo(p.tick()); - pos->beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0; } //--------------------------------------------------------- @@ -1226,6 +1245,69 @@ jack_transport_state_t JackAudioDevice::transportQuery(jack_position_t* pos) } //--------------------------------------------------------- +// timebaseQuery +// Given the number of frames in this period, get the bar, beat, tick, +// and current absolute tick, and number of ticks in this period. +// Return false if information could not be obtained. +//--------------------------------------------------------- + +bool JackAudioDevice::timebaseQuery(unsigned frames, unsigned* bar, unsigned* beat, unsigned* tick, unsigned* curr_abs_tick, unsigned* next_ticks) +{ + jack_position_t jp; + jack_transport_query(_client, &jp); + + if(JACK_DEBUG) + printf("timebaseQuery frame:%u\n", jp.frame); + + if(jp.valid & JackPositionBBT) + { + if(JACK_DEBUG) + { + printf("timebaseQuery BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n", + jp.bar, jp.beat, jp.tick, jp.bar_start_tick, jp.beats_per_bar, jp.beat_type, jp.ticks_per_beat, jp.beats_per_minute); + if(jp.valid & JackBBTFrameOffset) + printf("timebaseQuery BBTFrameOffset: %u\n", jp.bbt_offset); + } + + if(jp.ticks_per_beat > 0.0) + { + unsigned muse_tick = unsigned((double(jp.tick) / jp.ticks_per_beat) * double(MusEGlobal::config.division)); + unsigned curr_tick = ((jp.bar - 1) * jp.beats_per_bar + (jp.beat - 1)) * double(MusEGlobal::config.division) + muse_tick; + // Prefer the reported frame rate over the app's rate if possible. + double f_rate = jp.frame_rate != 0 ? jp.frame_rate : MusEGlobal::sampleRate; + // beats_per_minute is "supposed" to be quantized to period size - that is, computed + // so that mid-period changes are averaged out to produce a single tempo which + // produces the same tick in the end. If we can rely on that, we should be good accuracy. + unsigned ticks = double(MusEGlobal::config.division) * (jp.beats_per_minute / 60.0) * double(frames) / f_rate; + + if(JACK_DEBUG) + printf("timebaseQuery curr_tick:%u f_rate:%f ticks:%u\n", curr_tick, f_rate, ticks); + + if(bar) *bar = jp.bar; + if(beat) *beat = jp.beat; + if(tick) *tick = muse_tick; + + if(curr_abs_tick) *curr_abs_tick = curr_tick; + if(next_ticks) *next_ticks = ticks; + + return true; + } + } + + if(JACK_DEBUG) + { + if(jp.valid & JackPositionTimecode) + printf("timebaseQuery JackPositionTimecode: frame_time:%f next_time:%f\n", jp.frame_time, jp.next_time); + if(jp.valid & JackAudioVideoRatio) + printf("timebaseQuery JackAudioVideoRatio: %f\n", jp.audio_frames_per_video_frame); + if(jp.valid & JackVideoFrameOffset) + printf("timebaseQuery JackVideoFrameOffset: %u\n", jp.video_offset); + } + + return false; +} + +//--------------------------------------------------------- // systemTime // Return system time. Depends on selected clock source. // With Jack, may be based upon wallclock time, the @@ -1617,7 +1699,7 @@ void JackAudioDevice::seekTransport(unsigned frame) void JackAudioDevice::seekTransport(const Pos &p) { if (JACK_DEBUG) - printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame()); + printf("JackAudioDevice::seekTransport(Pos) frame:%d\n", p.frame()); if(!MusEGlobal::useJackTransport.value()) { @@ -1628,25 +1710,29 @@ void JackAudioDevice::seekTransport(const Pos &p) } if(!checkJackClient(_client)) return; + +// TODO: Be friendly to other apps... Sadly not many of us use jack_transport_reposition. +// This is actually required IF we want the extra position info to show up +// in the sync callback, otherwise we get just the frame only. +// This information is shared on the server, it is directly passed around. +// jack_transport_locate blanks the info from sync until the timebase callback reads +// it again right after, from some timebase master. See process in audio.cpp + +// jack_position_t jp; +// jp.frame = p.frame(); +// +// jp.valid = JackPositionBBT; +// p.mbt(&jp.bar, &jp.beat, &jp.tick); +// jp.bar_start_tick = Pos(jp.bar, 0, 0).tick(); +// jp.bar++; +// jp.beat++; +// jp.beats_per_bar = 5; // TODO Make this correct ! +// jp.beat_type = 8; // +// jp.ticks_per_beat = MusEGlobal::config.division; +// int tempo = MusEGlobal::tempomap.tempo(p.tick()); +// jp.beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0; +// jack_transport_reposition(_client, &jp); - /* - jack_position_t jp; - jp.valid = JackPositionBBT; - p.mbt(&jp.bar, &jp.beat, &jp.tick); - jp.bar++; - jp.beat++; - jp.bar_start_tick = Pos(jp.bar, 0, 0).tick(); - // - // dummy: - // - jp.beats_per_bar = 4; - jp.beat_type = 4; - jp.ticks_per_beat = 384; - int tempo = MusEGlobal::tempomap.tempo(p.tick()); - jp.beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0; - - jack_transport_reposition(_client, &jp); - */ jack_transport_locate(_client, p.frame()); } diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h index 9640ca81..aab60d88 100644 --- a/muse2/muse/driver/jackaudio.h +++ b/muse2/muse/driver/jackaudio.h @@ -80,6 +80,7 @@ class JackAudioDevice : public AudioDevice { virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1); virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1); + jack_client_t* jackClient() const { return _client; } virtual void registerClient(); virtual const char* clientName() { return jackRegisteredName; } @@ -105,6 +106,7 @@ class JackAudioDevice : public AudioDevice { virtual void seekTransport(const Pos &p); virtual void setFreewheel(bool f); jack_transport_state_t transportQuery(jack_position_t* pos); + bool timebaseQuery(unsigned frames, unsigned* bar, unsigned* beat, unsigned* tick, unsigned* curr_abs_tick, unsigned* next_ticks); void graphChanged(); void registrationChanged(); void connectJackMidiPorts(); diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp index 706fa269..e3e67dfb 100644 --- a/muse2/muse/driver/jackmidi.cpp +++ b/muse2/muse/driver/jackmidi.cpp @@ -30,6 +30,7 @@ //#include <jack/midiport.h> #include "jackmidi.h" +#include "jackaudio.h" #include "song.h" #include "globals.h" #include "midi.h" @@ -50,10 +51,6 @@ // Turn on debug messages. //#define JACK_MIDI_DEBUG -namespace MusEGlobal { -extern unsigned int volatile lastExtMidiSyncTick; -} - namespace MusECore { //--------------------------------------------------------- @@ -422,7 +419,7 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event) // Split the events up into channel fifos. Special 'channel' number 17 for sysex events. unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel(); - if(_recordFifo[ch].put(MidiPlayEvent(event))) + if(_recordFifo[ch].put(event)) printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch); } @@ -446,10 +443,18 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev) // catch process play // - //int frameOffset = MusEGlobal::audio->getFrameOffset(); - unsigned pos = MusEGlobal::audio->pos().frame(); - - event.setTime(MusEGlobal::extSyncFlag.value() ? MusEGlobal::lastExtMidiSyncTick : (pos + ev->time)); // p3.3.25 + // These Jack events arrived in the previous period, and it may not have been at the audio position before this one (after a seek). + // This is how our ALSA driver works, events there are timestamped asynchronous of any process, referenced to the CURRENT audio + // position, so that by the time of the NEXT process, THOSE events have also occured in the previous period. + // So, technically this is correct. What MATTERS is how we adjust the times for storage, and/or simultaneous playback in THIS period, + // and TEST: we'll need to make sure any non-contiguous previous period is handled correctly by process - will it work OK as is? + // If ALSA works OK than this should too... +#ifdef _AUDIO_USE_TRUE_FRAME_ + event.setTime(MusEGlobal::audio->previousPos().frame() + ev->time); +#else + event.setTime(MusEGlobal::audio->pos().frame() + ev->time); +#endif + event.setTick(MusEGlobal::lastExtMidiSyncTick); event.setChannel(*(ev->buffer) & 0xf); int type = *(ev->buffer) & 0xf0; @@ -509,9 +514,20 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev) case ME_START: case ME_CONTINUE: case ME_STOP: - if(_port != -1) - MusEGlobal::midiSeq->realtimeSystemInput(_port, type); + { + if(MusEGlobal::audioDevice && MusEGlobal::audioDevice->deviceType() == JACK_MIDI && _port != -1) + { + MusECore::JackAudioDevice* jad = static_cast<MusECore::JackAudioDevice*>(MusEGlobal::audioDevice); + jack_client_t* jc = jad->jackClient(); + if(jc) + { + jack_nframes_t abs_ft = jack_last_frame_time(jc) + ev->time; + double abs_ev_t = double(jack_frames_to_time(jc, abs_ft)) / 1000000.0; + MusEGlobal::midiSeq->realtimeSystemInput(_port, type, abs_ev_t); + } + } return; + } //case ME_SYSEX_END: //break; // return; |