// -------------------------------------------------------------- // -------------------------------------------------------------- #include #include #include #include #include "synth_defs.h" #include "lfo.h" // -------------------------------------------------------------- // internal funcs // -------------------------------------------------------------- void LFO_freq_update(lfo_t *pObj) { pObj->omega = pObj->param[LFO_PARAM2_FREQ]/ pObj->fs; if (pObj->param[LFO_PARAM2_DELAY] > 0) { pObj->delay_dx = 1.0/(pObj->fs*pObj->param[LFO_PARAM2_DELAY]); } else { pObj->delay_dx = 1.0; } pObj->attack_a = 1.0/(pObj->fs*pObj->param[LFO_PARAM2_ATTACK]*LFO_KE); } void LFO_smmother_update(lfo_t *pObj) { pObj->smooth_is_negative = (pObj->param[LFO_PARAM2_SMOOTH] < 0); if (fabs(pObj->param[LFO_PARAM2_SMOOTH]) < 0.001) { pObj->smooth_b = 1; pObj->smooth_is_negative = 0; } else { pObj->smooth_b = fabs((synth_float_t)5/(pObj->param[LFO_PARAM2_SMOOTH]*pObj->fs)); } pObj->smooth_a = 1 - pObj->smooth_b; } synth_float_t Sync_mod(synth_float_t x) { synth_float_t y = x - (int)x; if (y < 0) { y += 1; } return y; } synth_float_t phase_det(synth_float_t lo, synth_float_t ref) { lo = Sync_mod(lo - 0.5); synth_float_t perr = Sync_mod(lo - ref) - (synth_float_t)0.5; return perr; } void Sync_init(sync_t *pObj) { pObj->phase = 0; pObj->phase_int = 0; pObj->phase_ref = 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; } sync_result_t Sync_process(lfo_t *pObj) { sync_t *pSync = &pObj->sync; synth_float_t omega_base = pObj->omega; int sync_mode = (int)pObj->param[LFO_PARAM2_MIDISYNC_MODE]; synth_float_t phase_ref = pSync->phase_ref; sync_result_t result; pSync->phase_int = Sync_mod(pSync->phase_int + pObj->omega); result.phase = pSync->phase; switch (sync_mode) { case LFO_SYNC_MODE_OFF: pSync->phase = Sync_mod(pSync->phase + omega_base); break; case LFO_SYNC_MODE_F: pSync->phase = Sync_mod(pSync->phase + pSync->omega); break; case LFO_SYNC_MODE_F_P: pSync->phase = pSync->phase_int; break; case LFO_SYNC_MODE_P: pSync->phase = Sync_mod(pSync->phase + omega_base); if (pSync->phase_update && phase_ref == 0) { pSync->phase = 0; } break; } result.is_cycle_start = (pSync->phase < result.phase); result.phase = pSync->phase; synth_float_t perr = 0; if (pSync->phase_update) { pSync->phase_update = 0; perr = phase_det(pSync->phase_int, phase_ref); SynthDebug("phase_ref=%f, phase_lo=%f, perr=%f\n", phase_ref, pSync->phase_int, perr); SynthDebug("syncOnFreqUpdate(): BPM=%f\n", pSync->omega*pObj->fs*60); } pSync->omega = omega_base-(pSync->klag*pSync->accu + pSync->klead*perr); pSync->accu += perr; return result; } void Sync_processV(lfo_t* pObj, int len) { sync_t *pSync = &pObj->sync; synth_float_t perr = 0; synth_float_t omega_base = pObj->omega; int sync_mode = (int)pObj->param[LFO_PARAM2_MIDISYNC_MODE]; if (pSync->phase_update) { pSync->phase_update = 0; perr = phase_det(pSync->phase_int, pSync->phase_ref); if (sync_mode == LFO_SYNC_MODE_P) { if (pSync->phase_ref == 0) { pSync->phase = 0; } } SynthDebug("phase_ref=%f, phase_lo=%f, perr=%f\n", pSync->phase_ref, pSync->phase_int, perr); SynthDebug("syncOnFreqUpdate(): BPM=%f\n", pSync->omega*pObj->fs*60); } for (int i=0; i < len; i++) { pObj->pPhase[i].phase_int = pSync->phase_int; pObj->pPhase[i].is_cycle_start = 0; pSync->phase_int = Sync_mod(pSync->phase_int + pSync->omega); pSync->omega = omega_base-(pSync->klag*pSync->accu + pSync->klead*perr); pSync->accu += perr; perr = 0; } switch (sync_mode) { case LFO_SYNC_MODE_P: case LFO_SYNC_MODE_OFF: { for (int i=0; i < len; i++) { pObj->pPhase[i].phase = pSync->phase; synth_float_t phase = pSync->phase; pSync->phase = Sync_mod(pSync->phase + omega_base); pObj->pPhase[i].is_cycle_start = (phase > pSync->phase); } } break; case LFO_SYNC_MODE_F: { for (int i=0; i < len; i++) { pObj->pPhase[i].phase = pSync->phase; synth_float_t phase = pSync->phase; pSync->phase = Sync_mod(pSync->phase + pSync->omega); pObj->pPhase[i].is_cycle_start = (phase > pSync->phase); } } break; case LFO_SYNC_MODE_F_P: { for (int i=0; i < len; i++) { synth_float_t phase = pSync->phase; pSync->phase = pObj->pPhase[i].phase_int; pObj->pPhase[i].is_cycle_start = (phase > pSync->phase); pObj->pPhase[i].phase = pSync->phase; } } break; default: break; } } // -------------------------------------------------------------- // Exported functions // -------------------------------------------------------------- void LFO_Init(lfo_t *pObj, synth_float_t fs) { pObj->fs = fs; pObj->pOut = NULL; pObj->bufsize = 0; pObj->pPhase = NULL; pObj->pWave = NULL; pObj->param[LFO_PARAM2_WAVEFORM] = LFO_WAVEFORM_SINE; pObj->param[LFO_PARAM2_FREQ] = 1; pObj->param[LFO_PARAM2_SMOOTH] = 0.001; // seconds pObj->param[LFO_PARAM2_DELAY] = 0; // seconds pObj->param[LFO_PARAM2_ATTACK] = 0; // seconds pObj->sh_sample = 0; pObj->smooth_out = 0; pObj->offset = 0.0; LFO_Reset(pObj, 0); pObj->freq_update_req = 0; 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) { LFO_SetBufsize(pObj, 0); } void LFO_SetBufsize(lfo_t *pObj, UINT32 size) { if (pObj->bufsize == size) return; pObj->bufsize = size; if (pObj->pOut) free(pObj->pOut); pObj->pOut = NULL; if (pObj->pPhase) free(pObj->pPhase); pObj->pPhase = NULL; if (pObj->pWave) free(pObj->pWave); pObj->pWave = NULL; if (!size) return; pObj->pOut = (synth_float_t*)malloc(pObj->bufsize*sizeof(synth_float_t)); pObj->pPhase = (sync_result_t*)malloc(pObj->bufsize*sizeof(sync_result_t)); pObj->pWave = (synth_float_t*)malloc(pObj->bufsize*sizeof(synth_float_t)); } void LFO_SetFS(lfo_t *pObj, synth_float_t fs) { pObj->fs = fs; LFO_freq_update(pObj); } void LFO_Reset(lfo_t *pObj, synth_float_t initial_phase) { pObj->sync.phase = initial_phase; pObj->smooth_out = 0; pObj->delay_x = 0; pObj->attack_y = 0; LFO_freq_update(pObj); LFO_smmother_update(pObj); } synth_float_t LFO_sync(lfo_t *pObj, synth_float_t phase_ref) { synth_float_t note_1_x = pObj->param[LFO_PARAM2_MIDISYNC_BEATDIV]; phase_ref = Sync_mod(note_1_x*phase_ref); Sync_phase_update(&pObj->sync, phase_ref); // Return BPM return 4*60*pObj->fs*pObj->sync.omega/note_1_x; } void LFO_Param2Set(lfo_t *pObj, UINT32 type, synth_float_t value) { int param_changed = 0; if (pObj->param[type] != value) { pObj->param[type] = value; param_changed = 1; } switch(type) { case LFO_PARAM2_WAVEFORM: pObj->freq_update_req = param_changed; break; case LFO_PARAM2_FREQ: pObj->freq_update_req = param_changed; break; case LFO_PARAM2_SMOOTH: if (param_changed) { LFO_smmother_update(pObj); } break; case LFO_PARAM2_DELAY: pObj->freq_update_req = param_changed; break; case LFO_PARAM2_ATTACK: pObj->freq_update_req = param_changed; break; case LFO_PARAM2_SYMMETRY: if (param_changed) { pObj->offset = 0.5 *value; } break; default: break; } } synth_float_t* LFO_ProcessDataV(lfo_t *pObj, UINT32 len) { UINT32 i; sync_result_t *pPhase = pObj->pPhase; if (pObj->freq_update_req) { pObj->freq_update_req = 0; LFO_freq_update(pObj); } // Process Phase and Frequency #if 0 for (i=0; i< len; i++) { *(pPhase++) = Sync_process(&pObj->sync); } #else Sync_processV(pObj, len); #endif pPhase = pObj->pPhase; synth_float_t *pWave = pObj->pWave; if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SAW) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*sync_result.phase - 1.0; *(pWave++) = 0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SAW_REV) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*sync_result.phase - 1.0; *(pWave++) = -0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SH_UNI) { // Create phase for S/H for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); if (sync_result.is_cycle_start) { pObj->sh_sample = Noise_Uniform(&pObj->noise, 1, 0.5); } *(pWave++) = pObj->sh_sample + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SH_GAUSS) { // Create phase for S/H for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); if (sync_result.is_cycle_start) { do { pObj->sh_sample = Noise_Gaussian(&pObj->noise, sqrt(1.f/36), 0.5); } while ((pObj->sh_sample < 0) || (pObj->sh_sample > 1.f)); } *(pWave++) = pObj->sh_sample + pObj->offset; } } // Create output if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SINE) { for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = sin(2*M_PI*sync_result.phase); *(pWave++) = 0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SINE_REV) { for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = sin(2*M_PI*sync_result.phase); *(pWave++) = -0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_COSINE) { for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = cos(2*M_PI*sync_result.phase); *(pWave++) = 0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_COSINE_REV) { for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = cos(2*M_PI*sync_result.phase); *(pWave++) = -0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SQUARE) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*(synth_float_t)(sync_result.phase < 0.5) - 1.0; *(pWave++) = 0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_SQUARE_REV) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*(synth_float_t)(sync_result.phase < 0.5) - 1.0; *(pWave++) = -0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_TRIANGLE) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*(1-sync_result.phase) - 1.0; if (sync_result.phase < 0.5) { y = 2*sync_result.phase - 1.0; } *(pWave++) = 0.5*y + pObj->offset; } } if (pObj->param[LFO_PARAM2_WAVEFORM] == LFO_WAVEFORM_TRIANGLE_REV) { // Create phase for (i=0; i< len; i++) { sync_result_t sync_result = *(pPhase++); synth_float_t y = 2*(1-sync_result.phase) - 0.5; if (sync_result.phase < 0.5) { y = 2*sync_result.phase - 0.5; } *(pWave++) = -0.5*y + pObj->offset; } } // Output smoothing and delay pWave = pObj->pWave; synth_float_t *pOut = pObj->pOut; for (i=0; i< len; i++) { synth_float_t in = *(pWave++); pObj->delay_x += pObj->delay_dx; if (pObj->delay_x < 1.0) { in = 0; } pObj->smooth_out = pObj->smooth_a*pObj->smooth_out + pObj->smooth_b*in; synth_float_t out = pObj->smooth_out; if (pObj->smooth_is_negative) out = 2*in - pObj->smooth_out; *(pOut++) = out*pObj->attack_y; pObj->attack_y += pObj->attack_a*(1-pObj->attack_y); } return pObj->pOut; }