diff --git a/src/event.hxx b/src/event.hxx index 0385f26..5460928 100644 --- a/src/event.hxx +++ b/src/event.hxx @@ -28,6 +28,7 @@ namespace Event METRONOME_ACTIVE, TIME_BPM, + TIME_TEMPO_TAP, GUI_PRINT, }; @@ -148,6 +149,17 @@ class EventTimeBPM : public EventBase EventTimeBPM(float b) : bpm(b) {} }; +class EventTimeTempoTap : public EventBase +{ + public: + int type() { return int(TIME_TEMPO_TAP); } + uint32_t size() { return sizeof(EventTimeTempoTap); } + + // no data needed, the event itself is an "event", + // jack measures time intervals in frames & does math + EventTimeTempoTap(){} +}; + // prints the string S in the GUI console class EventGuiPrint : public EventBase diff --git a/src/eventhandlerdsp.cxx b/src/eventhandlerdsp.cxx index 680d262..9071851 100644 --- a/src/eventhandlerdsp.cxx +++ b/src/eventhandlerdsp.cxx @@ -74,6 +74,12 @@ void handleDspEvents() jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventTimeBPM) ); jack->getTimeManager()->setBpm(ev.bpm); } break; } + case Event::TIME_TEMPO_TAP: { + if ( availableRead >= sizeof(EventTimeTempoTap) ) { + EventTimeTempoTap ev; + jack_ringbuffer_read( rbToDsp, (char*)&ev, sizeof(EventTimeTempoTap) ); + jack->getTimeManager()->tap(); + } break; } default: { // just do nothing diff --git a/src/gmastertrack.hxx b/src/gmastertrack.hxx index d939eef..d782a7b 100644 --- a/src/gmastertrack.hxx +++ b/src/gmastertrack.hxx @@ -39,7 +39,12 @@ static void gmastertrack_button_callback(Fl_Widget *w, void *data) { float bpm = b->value() * 160 + 60; // 60 - 220 EventTimeBPM e = EventTimeBPM( bpm ); writeToDspRingbuffer( &e ); - cout << "GUI writing bpm = " << bpm << endl; + } + else if ( strcmp( w->label(), "Tap" ) == 0 ) + { + Avtk::Button* b = (Avtk::Button*)w; + EventTimeTempoTap e; + writeToDspRingbuffer( &e ); } else { @@ -54,8 +59,9 @@ class GMasterTrack : public Fl_Group Fl_Group(x, y, w, h), title( strdup(l) ), bg( x, y , w, h, title ), + + tapTempo(x + 25 + 22, y + 75, 44, 44,"Tap"), /* - button1(x + 5, y + 24, 100, 18,"Rec"), button2(x + 5, y + 44, 100, 18,"Play"), button3(x + 5, y + 64, 100, 18,"Stop"), button4(x + 5, y + 84, 48, 18,"-"), @@ -71,8 +77,10 @@ class GMasterTrack : public Fl_Group */ { ID = privateID++; + + tapTempo.callback( gmastertrack_button_callback, &ID ); + /* - button1.callback( gmastertrack_button_callback, &ID ); button2.callback( gmastertrack_button_callback, &ID ); button3.callback( gmastertrack_button_callback, &ID ); button4.callback( gmastertrack_button_callback, &ID ); @@ -97,8 +105,9 @@ class GMasterTrack : public Fl_Group char* title; Avtk::Background bg; + + Avtk::Button tapTempo; /* - Avtk::Button button1; Avtk::Button button2; Avtk::Button button3; Avtk::Button button4; diff --git a/src/gtrack.hxx b/src/gtrack.hxx index 267d977..ce5f8f4 100644 --- a/src/gtrack.hxx +++ b/src/gtrack.hxx @@ -19,7 +19,9 @@ using namespace std; static void gtrack_button_callback(Fl_Widget *w, void *data) { - int track = *(int*)data; + int track = 0; + if ( data ) + track = *(int*)data; //cout << "Button " << *(int*)data << " " << w->label() << " clicked" << endl; if ( strcmp( w->label() , "Rec" ) == 0 ) @@ -49,8 +51,7 @@ static void gtrack_button_callback(Fl_Widget *w, void *data) { } else if ( strcmp( w->label() , "Vol" ) == 0 ) { - EventLooperLoopLength e = EventLooperLoopLength(track, 0.5); - writeToDspRingbuffer( &e ); + } else { diff --git a/src/metronome.hxx b/src/metronome.hxx index e6c7935..a347c59 100644 --- a/src/metronome.hxx +++ b/src/metronome.hxx @@ -54,7 +54,9 @@ class Metronome : public Observer void setFpb(int f) { fpb = f; - //cout << "Looper " << track << " got fpb of " << fpb << endl; + + // disable play until next beat + playPoint = endPoint + 1; } void process(int nframes, Buffers* buffers) diff --git a/src/timemanager.hxx b/src/timemanager.hxx index e589699..bc91d0f 100644 --- a/src/timemanager.hxx +++ b/src/timemanager.hxx @@ -18,49 +18,71 @@ class TimeManager { public: TimeManager(): - bpm(120), + fpb(120), oldBeat(0) { + tapTempoPos = 0; + tapTempo[0] = 0; + tapTempo[1] = 0; + tapTempo[2] = 0; } - void setBpm(float b) + void setBpm(float bpm) { - char buffer [50]; - sprintf (buffer, "%d", b); - //printf ("[%s] is a string %d chars long\n",buffer,n); + setFpb( 44100 / bpm * 60 ); + } + void setFpb(float f) + { + fpb = f; + char buffer [50]; + sprintf (buffer, "TM, setFpb() %i", int(f) ); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); - bpm = b; for(uint i = 0; i < observers.size(); i++) { - observers.at(i)->setFpb(bpm); + observers.at(i)->setFpb(fpb); } } void registerObserver(Observer* o) { observers.push_back(o); - int fpb = 44100 / bpm * 60; - char buffer [50]; - sprintf (buffer, "TM, bpm = %i, fpb = %i", int(bpm), fpb ); - EventGuiPrint e( buffer ); - writeToGuiRingbuffer( &e ); - - // triggers newly registered object to have bpm set o->setFpb( fpb ); } + void tap() + { + if ( tapTempoPos < 3 ) + { + tapTempo[tapTempoPos] = frame; + } + else + { + // calculate frames per tap + int tapFpb1 = tapTempo[1] - tapTempo[0]; + int tapFpb2 = tapTempo[2] - tapTempo[1]; + + int average = (tapFpb1 + tapFpb2) / 2; + setFpb(average); + } + } + void process(Buffers* buffers) { - int framesPerBeat = (int) buffers->samplerate / (bpm / 60.0); + // tap tempo measurements + frame = buffers->transportFrame; + + //int framesPerBeat = (int) buffers->samplerate / (bpm / 60.0); + + // time signature? buffers->transportPosition->beats_per_bar = 4; buffers->transportPosition->beat_type = 4; - int beat = buffers->transportFrame / framesPerBeat; + int beat = buffers->transportFrame / fpb; //int beat = int(beat); //int tick = int( (beatFloat - beat) * 1920 ); @@ -90,13 +112,21 @@ class TimeManager buffers->transportPosition->tick = 0; buffers->transportPosition->ticks_per_beat = 1920; + + int bpm = int(buffers->samplerate * fpb / 60.0); buffers->transportPosition->beats_per_minute = bpm; } private: - float bpm; + float fpb; int oldBeat; + // tap tempo measurements + int frame; + + int tapTempoPos; + int tapTempo[3]; + std::vector observers; };