diff --git a/Source/JaySynth.cpp b/Source/JaySynth.cpp index 92c5fe7..edd2a25 100644 --- a/Source/JaySynth.cpp +++ b/Source/JaySynth.cpp @@ -126,6 +126,8 @@ JaySynth::JaySynth (int num_voices, String pathToWaves) m_clock_cnt_bar = 0; m_lastTime_ms = 0; m_estimatedTime_ms = 0; + m_numMidiClocksPerBeat = 1; + m_numMidiClocksPerBar = 1; m_isMidiClockStarted = false; } @@ -1014,7 +1016,9 @@ void JaySynth::renderNextBlock (AudioSampleBuffer& outputBuffer, } } if (useEvent) - handleMidiEvent (m); + { + handleMidiEvent (m); + } startSample += numThisTime; numSamples -= numThisTime; @@ -1028,8 +1032,11 @@ void JaySynth::updateMidiTiming(const MidiMessage& m) int denom; m.getTimeSignatureInfo(nom, denom); - m_numMidiClocksPerBeat = m_numMidiclocksPerFourQuarterBeats/denom; - m_numMidiClocksPerBar = nom*m_numMidiClocksPerBeat; + if (denom > 0) + { + m_numMidiClocksPerBeat = m_numMidiclocksPerFourQuarterBeats/denom; + m_numMidiClocksPerBar = nom*m_numMidiClocksPerBeat; + } } void JaySynth::handleMidiEvent (const MidiMessage& m) @@ -1129,55 +1136,48 @@ void JaySynth::handleMidiEvent (const MidiMessage& m) // BPM Estimation double deltaTime_ms = currTime_ms - m_lastTime_ms; - if (m_lastTime_ms) + if (m_lastTime_ms > 0.0) { m_estimatedTime_ms = (1.0-alpha_1)*m_estimatedTime_ms + alpha_1*deltaTime_ms; - voiceSetMidiBpm(m_lastTime_ms*m_numMidiclocksPerQuarterNote); } m_lastTime_ms = currTime_ms; // Quarter clock generation m_clock_cnt_bar = m_clock_cnt_bar % m_numMidiClocksPerBar; - if (m_clock_cnt_bar % m_numMidiClocksPerBeat == 0) + if (m_isMidiClockStarted) { - // Send quarter pulse with current BPM estimation - midi_quarter_clock_info_t info; - - info.bpm = (uint32_t)(m_numMidiclocksPerQuarterNote*m_estimatedTime_ms + 0.5); - info.type = 1; - if (m_clock_cnt_bar == 0) - { - info.type = 2; - } - if (m_isMidiClockStarted) + voiceSetMidiBeat(m_clock_cnt_bar % m_numMidiclocksPerQuarterNote); + if (m_clock_cnt_bar % m_numMidiClocksPerBeat == 0) { + // Send quarter pulse with current BPM estimation + midi_quarter_clock_info_t info; + + info.bpm = (uint32_t)(m_numMidiclocksPerQuarterNote*m_estimatedTime_ms + 0.5); + info.type = 1; + if (m_clock_cnt_bar == 0) + { + info.type = 2; + } listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICLOCK, &info); } - voiceSetMidiBeat(m_clock_cnt_bar); } m_clock_cnt_bar++; } } -void JaySynth::voiceSetMidiBpm(synth_float_t bpm) +void JaySynth::voiceSetMidiBeat(int quarterBeatCount) { + lfo_t *pLfo = &m_pVoices[0].pCom->glfo[0]; + synth_float_t phase = (synth_float_t)quarterBeatCount/m_numMidiclocksPerQuarterNote; + LFO_sync(pLfo, phase); + for (int i=0; i < max_num_voices; i++) { JaySynthVoice* const voice = voices.getUnchecked (i); - voice->setMidiBpm(bpm); + voice->setMidiBeat(quarterBeatCount); } } -void JaySynth::voiceSetMidiBeat(int beatcount) -{ - for (int i=0; i < max_num_voices; i++) - { - JaySynthVoice* const voice = voices.getUnchecked (i); - voice->setMidiBeat(beatcount); - } - -} - //============================================================================== // Voice trigger stuff //============================================================================== diff --git a/Source/JaySynth.h b/Source/JaySynth.h index 73de305..50bcc8a 100644 --- a/Source/JaySynth.h +++ b/Source/JaySynth.h @@ -87,8 +87,7 @@ public: const float velocity, bool doTrigger); void Voicestop (JaySynthVoice* voice, const bool allowTailOff); - void voiceSetMidiBpm(synth_float_t bpm); - void voiceSetMidiBeat(int beatcount); + void voiceSetMidiBeat(int quarterBeatCount); int getNumVoicesPlaying (SynthesiserSound* soundToPlay); void clearKeysPressed(void); @@ -262,6 +261,7 @@ private: double m_lastTime_ms; double m_estimatedTime_ms; bool m_isMidiClockStarted; + void updateMidiTiming(const MidiMessage& m); }; diff --git a/Source/JaySynthVoice.h b/Source/JaySynthVoice.h index 81cdf17..f252455 100644 --- a/Source/JaySynthVoice.h +++ b/Source/JaySynthVoice.h @@ -62,17 +62,8 @@ public: currentlyPlayingSound = nullptr; } - void setMidiBpm(synth_float_t bpm) - { - LFO_Param2Set(&m_pVoice->lfo[0], LFO_PARAM2_FREQ, 1.0/bpm); - } - void setMidiBeat(int beatCounter) { - if (beatCounter == 0) - { - LFO_Reset(&m_pVoice->lfo[0], 0); - } } private: diff --git a/Source/synth/lfo.c b/Source/synth/lfo.c index 0103b36..591e954 100644 --- a/Source/synth/lfo.c +++ b/Source/synth/lfo.c @@ -12,13 +12,23 @@ // -------------------------------------------------------------- // internal funcs // -------------------------------------------------------------- +void LFO_set_omega(lfo_t *pObj, synth_float_t omega) +{ + if (omega < 0.0 || omega > 1.0) + { + return; + } + pObj->b = 2.0 * sin(omega*pi); + pObj->dx = omega; +} + void LFO_freq_update(lfo_t *pObj) { - synth_float_t f; + synth_float_t omega; - f = pObj->param[LFO_PARAM2_FREQ]; - pObj->b = 2.0 * sin(f*pi / pObj->fs); - pObj->dx = f/pObj->fs; + omega = pObj->param[LFO_PARAM2_FREQ]/ pObj->fs; + + LFO_set_omega(pObj, omega); if (pObj->param[LFO_PARAM2_DELAY] > 0) { @@ -51,6 +61,59 @@ void LFO_smmother_update(lfo_t *pObj) } +synth_float_t Sync_mod(synth_float_t x, synth_float_t y) +{ + if (y == 0) + { + return 0; + } + synth_float_t result = fmod(x, y); + + if (result < 0) + { + result += y; + } + + return result; +} + +void Sync_init(sync_t *pObj) +{ + pObj->phase = 0; + pObj->phase_ref = 0; + pObj->phase_adjusted = 0; + pObj->omega = 0.0; + pObj->accu = 0; + pObj->klead = 1.0; + pObj->klag = 0.04/200; + pObj->phase_update = 0; +} + +void Sync_phase_update(sync_t *pObj, synth_float_t phase_ref) +{ + pObj->phase_ref = phase_ref; + pObj->phase_update = 1; +} + +int Sync_process(sync_t *pObj) +{ + int do_lfo_update = 0; + synth_float_t perr = 0; + if (pObj->phase_update) + { + do_lfo_update = 1; + pObj->phase_update = 0; + perr = (synth_float_t)Sync_mod(pObj->phase - pObj->phase_ref, 1.0) - (synth_float_t)0.5; +// SynthDebug("phase_ref=%f, phase=%f, perr=%f\n", pObj->phase_ref, pObj->phase_adjusted, perr); + } + pObj->phase_adjusted = Sync_mod(pObj->phase - 0.5, 1.0); + pObj->omega = -(pObj->klag*pObj->accu + pObj->klead*perr); + pObj->phase = Sync_mod(pObj->phase + pObj->omega, 1.0); + pObj->accu += perr; + + return do_lfo_update; +} + // -------------------------------------------------------------- // Exported functions // -------------------------------------------------------------- @@ -79,6 +142,8 @@ void LFO_Init(lfo_t *pObj, synth_float_t fs) LFO_SetBufsize(pObj, SYNTH_MAX_BUFSIZE); Noise_Init(&pObj->noise, 1+(UINT32)clock() * (UINT32)clock()); + + Sync_init(&pObj->sync); } void LFO_Free(lfo_t *pObj) @@ -126,6 +191,11 @@ void LFO_Reset(lfo_t *pObj, synth_float_t initial_phase) } +void LFO_sync(lfo_t *pObj, synth_float_t phase_ref) +{ + Sync_phase_update(&pObj->sync, phase_ref); +} + void LFO_Param2Set(lfo_t *pObj, UINT32 type, synth_float_t value) { switch(type) @@ -204,6 +274,13 @@ synth_float_t* LFO_ProcessDataV(lfo_t *pObj, UINT32 len) // Create phase for (i=i0; i< len; i++) { + if (Sync_process(&pObj->sync)) + { + LFO_set_omega(pObj, pObj->sync.omega); + SynthDebug("BPM=%f\n", pObj->sync.omega*pObj->fs*60); + } + pObj->x = pObj->sync.phase_adjusted; + in = pObj->x + pObj->offset; pObj->out = pObj->smooth_a*pObj->out + pObj->smooth_b*in; out = pObj->out; @@ -537,6 +614,6 @@ synth_float_t* LFO_ProcessDataV(lfo_t *pObj, UINT32 len) } } } - + return pObj->pOut; } diff --git a/Source/synth/lfo.h b/Source/synth/lfo.h index 434d911..1dcc6d0 100644 --- a/Source/synth/lfo.h +++ b/Source/synth/lfo.h @@ -40,6 +40,38 @@ enum LFO_NUM_PARAMS }; +typedef struct _ssync_t +{ + synth_float_t phase; + synth_float_t phase_ref; + synth_float_t phase_adjusted; + synth_float_t omega; + + synth_float_t klead; + synth_float_t klag; + synth_float_t accu; + + int phase_update; + +} sync_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +// -------------------------------------------------------------- +// Exported functions +// -------------------------------------------------------------- +void Sync_init(sync_t *pObj); +void Sync_phase_update(sync_t *pObj, synth_float_t phase_ref); +int Sync_process(sync_t *pObj); + +#if defined(__cplusplus) +} + +#endif +// -------------------------------------------------------------- + typedef struct _slfo_t { synth_float_t param[LFO_NUM_PARAMS]; @@ -53,6 +85,7 @@ typedef struct _slfo_t UINT32 smooth_is_negative; synth_float_t delay_x, delay_dx, attack_y, attack_a; synth_float_t gain, offset; + sync_t sync; } lfo_t; @@ -69,6 +102,7 @@ void LFO_Free(lfo_t *pObj); void LFO_SetFS(lfo_t *pObj, synth_float_t fs); void LFO_SetBufsize(lfo_t *pObj, UINT32 bufsize); void LFO_Reset(lfo_t *pObj, synth_float_t initial_phase); +void LFO_sync(lfo_t *pObj, synth_float_t phase); void LFO_Param2Set(lfo_t *pObj, UINT32 type, synth_float_t value); synth_float_t* LFO_ProcessDataV(lfo_t *pObj, UINT32 len);