// -------------------------------------------------------------- // -------------------------------------------------------------- #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) { if (y == 0) { return 0; } synth_float_t result = fmod(x, y); if (result < 0) { result += y; } return result; } synth_float_t phase_det(synth_float_t lo, synth_float_t ref) { lo = Sync_mod(lo - 0.5, 1.0); synth_float_t perr = Sync_mod(lo - ref, 1.0) - (synth_float_t)0.5; return perr; } void Sync_init(sync_t *pObj, lfo_t *pLfo) { 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; pObj->pLfo = pLfo; } 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(sync_t *pObj, synth_float_t omega_base) { int sync_mode = (int)pObj->pLfo->param[LFO_PARAM2_MIDISYNC_MODE]; synth_float_t phase_ref = pObj->phase_ref; sync_result_t result; pObj->phase_int = Sync_mod(pObj->phase_int + pObj->omega, 1.0); result.phase = pObj->phase; switch (sync_mode) { case LFO_SYNC_MODE_OFF: pObj->phase = Sync_mod(pObj->phase + omega_base, 1.0); break; case LFO_SYNC_MODE_F: pObj->phase = Sync_mod(pObj->phase + pObj->omega, 1.0); break; case LFO_SYNC_MODE_F_P: pObj->phase = pObj->phase_int; break; case LFO_SYNC_MODE_P: pObj->phase = Sync_mod(pObj->phase + omega_base, 1.0); if (pObj->phase_update && phase_ref == 0) { pObj->phase = 0; } break; } result.is_cycle_start = (pObj->phase < result.phase); result.phase = pObj->phase; synth_float_t perr = 0; if (pObj->phase_update) { pObj->phase_update = 0; perr = phase_det(pObj->phase_int, phase_ref); SynthDebug("phase_ref=%f, phase_lo=%f, perr=%f\n", phase_ref, pObj->phase_int, perr); // SynthDebug("syncOnFreqUpdate(): BPM=%f\n", omega*pObj->fs*60); } pObj->omega = omega_base-(pObj->klag*pObj->accu + pObj->klead*perr); pObj->accu += perr; return result; } // -------------------------------------------------------------- // 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.5; 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, pObj); } 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); } void 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, 1.0); Sync_phase_update(&pObj->sync, phase_ref); } 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; // Process Phase and Frequency for (i=0; i< len; i++) { *(pPhase++) = Sync_process(&pObj->sync, pObj->omega); if (pObj->freq_update_req) { pObj->freq_update_req = 0; LFO_freq_update(pObj); } } 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; }