// -------------------------------------------------------------- // -------------------------------------------------------------- #include #include #include #include "synth/synth_types.h" #include "synth_defs.h" #include "vector_utils.h" #include "voice.h" // -------------------------------------------------------------- // Exported functions // -------------------------------------------------------------- void Voice_ModInit(voice_common_t *pCom) { int i; synth_float_t k; synth_float_t a; // make frequency (Hz) table k = 1.0594630943593; // 12th root of 2 a = 440.f/64; // a a *= k; // b a *= k; // bb a *= k; // c, frequency of midi note 0 for (i = 0; i < NUM_FREQS; i++) // 128 midi notes { pCom->freqTab[i] = (synth_float_t)a; a *= k; } for (i = 0; i < SYNTH_MAX_BUFSIZE; i++) // 128 midi notes { pCom->pBuf_zeros[i] = (synth_float_t)0; pCom->pBuf_ones[i] = (synth_float_t)1; } } void Voice_ModFree(voice_common_t *pCom) { (void)pCom; } void VoiceInit(voice_t *pObj, voice_common_t *pCom, UINT32 id, synth_float_t fs) { INT32 i; pObj->id = id; pObj->pCom = pCom; pObj->fs = fs; pObj->bufsize = 0; if (pObj->id == 0) { Voice_ModInit(pCom); } VCF_Init(&pObj->vcf, id, &pCom->vcf, fs); for (i = 0; i < VOICE_NUM_ENV; i++) { ENV_Init(&pObj->env[i], fs); } for (i = 0; i < VOICE_NUM_OSC; i++) { Smooth_Init(&pObj->smooth_vco_enable[i], fs, 0.05, 0.05, 0); Smooth_Init(&pObj->smooth_vco_portamento[i], fs, 0.001, 0.001, 440); } // memset(pObj->pParam_smoother, 0, VOICE_NUM_PARAMS*sizeof(smooth_t*)); // Create parameter smoother // VOICE_PARAM_VCA_ENV_GAIN // pObj->pParam_smoother[VOICE_PARAM_VCA_ENV_GAIN] = (smooth_t*)malloc(sizeof(smooth_t)); // Smooth_Init(pObj->pParam_smoother[VOICE_PARAM_VCA_ENV_GAIN], fs, 0.01, 0.01, 0); for (i = 0; i < VOICE_NUM_OSC; i++) { VCO_Init(&pObj->vco[i], pObj->id*VOICE_NUM_OSC+i, &pCom->vco, fs); } for (i = 0; i < VOICE_NUM_LFO; i++) { LFO_Init(&pObj->lfo[i], fs); } // First voice initializes global LFOs if (pObj->id == 0) { for (i = 0; i < VOICE_NUM_LFO; i++) LFO_Init(&pCom->glfo[i], fs); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Init(&pCom->genv[i], fs); VCF_Init(&pCom->gvcf[0], MAX_POLYPHONY, &pCom->vcf, fs); VCF_Init(&pCom->gvcf[1], MAX_POLYPHONY+1, &pCom->vcf, fs); Noise_Init(&pCom->gnoise, 1+(UINT32)clock() * (UINT32)clock()); } pObj->state = note_state_idle; pObj->param[VOICE_PARAM_VCA_ENV_GAIN] = (synth_float_t)1; pObj->param[VOICE_PARAM_VCF_ENV_GAIN] = (synth_float_t)1; pObj->param[VOICE_PARAM_VCF_F] = (synth_float_t)1; pObj->param[VOICE_PARAM_VCF_Q] = (synth_float_t)0.7; pObj->param[VOICE_PARAM_VCF_Q_GAIN_0] = (synth_float_t)1; pObj->param[VOICE_PARAM_VCF_Q_CTRL_0] = (synth_float_t)0; pObj->param[VOICE_PARAM_OSC_0_PHASE] = 0; pObj->param[VOICE_PARAM_OSC_1_PHASE] = 0; pObj->param[VOICE_PARAM_OSC_0_TRANSPOSE] = 0; pObj->param[VOICE_PARAM_OSC_1_TRANSPOSE] = 0; pObj->param[VOICE_PARAM_KEY] = 128; pObj->param[VOICE_PARAM_OSC_0_SCALE] = 1.f; pObj->param[VOICE_PARAM_OSC_1_SCALE] = 1.f; pObj->param[VOICE_PARAM_MASTER_TUNE] = 1.f; pObj->param[VOICE_PARAM_MASTER_FREF] = 1.f; pObj->param[VOICE_PARAM_VOICE_PAN] = 0; pObj->pBuf_Q = NULL; VoiceSetBufsize(pObj, SYNTH_MAX_BUFSIZE); } void VoiceFree(voice_t *pObj) { int i; VoiceSetBufsize(pObj, 0); VCF_Free(&pObj->vcf); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Free(&pObj->env[i]); for (i = 0; i < VOICE_NUM_OSC; i++) VCO_Free(&pObj->vco[i]); for (i = 0; i < VOICE_NUM_LFO; i++) LFO_Free(&pObj->lfo[i]); // First voice frees global LFOs if (pObj->id == 0) { for (i = 0; i < VOICE_NUM_LFO; i++) LFO_Free(&pObj->pCom->glfo[i]); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Free(&pObj->pCom->genv[i]); VCF_Free(&pObj->pCom->gvcf[0]); VCF_Free(&pObj->pCom->gvcf[1]); Noise_Free(&pObj->pCom->gnoise); } for (i = 0; i < VOICE_NUM_OSC; i++) { Smooth_Free(&pObj->smooth_vco_enable[i]); Smooth_Free(&pObj->smooth_vco_portamento[i]); } // Delete parameter smoother // VOICE_PARAM_VCA_ENV_GAIN // Smooth_Free(pObj->pParam_smoother[VOICE_PARAM_VCA_ENV_GAIN]); // free(pObj->pParam_smoother[VOICE_PARAM_VCA_ENV_GAIN]); if (pObj->id == 0) Voice_ModFree(pObj->pCom); } void VoiceSetFS(voice_t *pObj, synth_float_t fs) { int i; pObj->fs = fs; for (i = 0; i < VOICE_NUM_ENV; i++) ENV_SetFS(&pObj->env[i], fs); VCF_SetFS(&pObj->vcf, fs); for (i = 0; i < VOICE_NUM_OSC; i++) Smooth_SetFS(&pObj->smooth_vco_enable[i], fs); for (i = 0; i < VOICE_NUM_OSC; i++) VCO_SetFS(&pObj->vco[i], fs); for (i = 0; i < VOICE_NUM_LFO; i++) LFO_SetFS(&pObj->lfo[i], fs); // First voice sets sample rate for global LFOs if (pObj->id == 0) { for (i = 0; i < VOICE_NUM_LFO; i++) LFO_SetFS(&pObj->pCom->glfo[i], fs); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_SetFS(&pObj->pCom->genv[i], fs); VCF_SetFS(&pObj->pCom->gvcf[0], fs); VCF_SetFS(&pObj->pCom->gvcf[1], fs); } } void VoiceSetBufsize(voice_t *pObj, UINT32 size) { int i; for (i = 0; i < VOICE_NUM_OSC; i++) { VCO_SetBufsize(&pObj->vco[i], size); } for (i = 0; i < VOICE_NUM_LFO; i++) { LFO_SetBufsize(&pObj->lfo[i], size); } // First voice sets bufsize for global LFOs if (pObj->id == 0) { for (i = 0; i < VOICE_NUM_LFO; i++) LFO_SetBufsize(&pObj->pCom->glfo[i], size); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_SetBufsize(&pObj->pCom->genv[i], size); VCF_SetBufsize(&pObj->pCom->gvcf[0], size); VCF_SetBufsize(&pObj->pCom->gvcf[1], size); } VCF_SetBufsize(&pObj->vcf, size); for (i = 0; i < VOICE_NUM_ENV; i++) ENV_SetBufsize(&pObj->env[i], size); if (pObj->bufsize == size) return; pObj->bufsize = size; if (pObj->pBuf_Q) free(pObj->pBuf_Q); pObj->pBuf_Q = NULL; if (!size) return; pObj->pBuf_Q = (synth_float_t*)malloc(pObj->bufsize*sizeof(synth_float_t)); } void VoiceEvent(voice_t *pObj, UINT32 type) { int i; switch(type) { case voice_event_trigger: case voice_event_retrigger: for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Event(&pObj->env[i], env_event_retrigger); VCF_Coeff_update(&pObj->vcf); if (pObj->state == note_state_idle) VCF_clear_state(&pObj->vcf); pObj->state = note_state_triggered; for (i = 0; i < VOICE_NUM_OSC; i++) { if ((int)pObj->param[VOICE_PARAM_OSC_0_RESTART_ON_TRIGGER+i] > 0.5) if (type == voice_event_trigger) VCO_Reset(&pObj->vco[i], pObj->param[VOICE_PARAM_OSC_0_PHASE+i]); VCO_Start(&pObj->vco[i]); Smooth_SetValue(&pObj->smooth_vco_enable[i], pObj->param[VOICE_PARAM_OSC_0_ENABLE+i]*((synth_float_t)1E-6+pObj->param[VOICE_PARAM_OSC_0_LEVEL+i])); } for (i = 0; i < VOICE_NUM_LFO; i++) { if ((int)pObj->param[VOICE_PARAM_LFO_0_SYNC+i] == VOICE_LFO_SYNC_RESTART) LFO_Reset(&pObj->lfo[i], 0); } // Global events for (i = 0; i < VOICE_NUM_LFO; i++) { if ((int)pObj->param[VOICE_PARAM_LFO_0_SYNC+i] == VOICE_LFO_SYNC_RESTART) LFO_Reset(&pObj->pCom->glfo[i], 0); } for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Event(&pObj->pCom->genv[i], env_event_retrigger); VCF_Coeff_update(&pObj->pCom->gvcf[0]); VCF_Coeff_update(&pObj->pCom->gvcf[1]); break; case voice_event_shutdown: case voice_event_release: for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Event(&pObj->pCom->genv[i], env_event_release); if (pObj->state == note_state_idle) break; for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Event(&pObj->env[i], env_event_release); pObj->state = note_state_released; break; default: break; } }; synth_float_t getKeyFreq(voice_t *pObj, int key) { int index = jsy_max(0, jsy_min(NUM_FREQS-1, key)); return pObj->pCom->freqTab[index]; } synth_float_t getPitch(voice_t *pObj, UINT32 osc_id) { synth_float_t pitch; pitch = getKeyFreq(pObj, (int)pObj->param[VOICE_PARAM_KEY] + (int)pObj->param[VOICE_PARAM_OSC_0_TRANSPOSE+osc_id]) * pObj->param[VOICE_PARAM_OSC_0_SCALE+osc_id] * pObj->param[VOICE_PARAM_OSC_0_DETUNE+osc_id] * pObj->param[VOICE_PARAM_MASTER_TUNE] * pObj->param[VOICE_PARAM_MASTER_FREF]; return pitch; } void VoiceParam2Set(voice_t *pObj, UINT32 type, synth_float_t value) { pObj->param[type] = value; switch(type) { case VOICE_PARAM_VOICE_PAN: if (pObj->id % 2) pObj->param[type] = jsy_min(1, jsy_max(-1, -value/100)); else pObj->param[type] = jsy_min(1, jsy_max(-1, value/100)); break; case VOICE_PARAM_PORTAMENTO_TIME: Smooth_SetT(&pObj->smooth_vco_portamento[0], value, value); Smooth_SetT(&pObj->smooth_vco_portamento[1], value, value); break; case VOICE_PARAM_MASTER_FREF: pObj->param[type] = value/440; pObj->vco_pitch[0] = getPitch(pObj, 0); pObj->vco_pitch[1] = getPitch(pObj, 1); break; case VOICE_PARAM_MASTER_TUNE: pObj->param[type] = pow(2, (double)value/(double)(12*100)); pObj->vco_pitch[0] = getPitch(pObj, 0); pObj->vco_pitch[1] = getPitch(pObj, 1); break; case VOICE_PARAM_OSC_0_WAVEFORM: case VOICE_PARAM_OSC_1_WAVEFORM: VCO_Param2Set(&pObj->vco[type-VOICE_PARAM_OSC_0_WAVEFORM], OSC_PARAM2_WAVEFORM, (int)pObj->param[type]); break; case VOICE_PARAM_OSC_0_SCALE: case VOICE_PARAM_OSC_1_SCALE: pObj->vco_pitch[type-VOICE_PARAM_OSC_0_SCALE] = getPitch(pObj, type-VOICE_PARAM_OSC_0_SCALE); break; case VOICE_PARAM_OSC_0_TRANSPOSE: case VOICE_PARAM_OSC_1_TRANSPOSE: pObj->param[type] = (int)value; pObj->vco_pitch[type-VOICE_PARAM_OSC_0_TRANSPOSE] = getPitch(pObj, type-VOICE_PARAM_OSC_0_TRANSPOSE); break; case VOICE_PARAM_OSC_0_DETUNE: case VOICE_PARAM_OSC_1_DETUNE: pObj->param[type] = pow(2, (double)value/(double)(12*100)); pObj->vco_pitch[type-VOICE_PARAM_OSC_0_DETUNE] = getPitch(pObj, type-VOICE_PARAM_OSC_0_DETUNE); break; case VOICE_PARAM_OSC_0_DUTYCYCLE: case VOICE_PARAM_OSC_1_DUTYCYCLE: pObj->param[type] = value / 100; VCO_Param2Set(&pObj->vco[type-VOICE_PARAM_OSC_0_DUTYCYCLE], OSC_PARAM2_DUTYCYCLE, pObj->param[type]); break; case VOICE_PARAM_KEY: pObj->vco_pitch[0] = getPitch(pObj, 0); pObj->vco_pitch[1] = getPitch(pObj, 1); break; case VOICE_PARAM_OSC_0_FM_AMT_0: case VOICE_PARAM_OSC_1_FM_AMT_0: pObj->param[type] = value / 12; break; case VOICE_PARAM_OSC_0_PWM_AMT_0: case VOICE_PARAM_OSC_1_PWM_AMT_0: case VOICE_PARAM_OSC_0_PWM_AMT_1: case VOICE_PARAM_OSC_1_PWM_AMT_1: case VOICE_PARAM_OSC_0_AM_AMT_0: case VOICE_PARAM_OSC_1_AM_AMT_0: case VOICE_PARAM_OSC_0_AM_AMT_1: case VOICE_PARAM_OSC_1_AM_AMT_1: case VOICE_PARAM_OSC_0_FM_AMT_1: case VOICE_PARAM_OSC_1_FM_AMT_1: case VOICE_PARAM_OSC_0_LEVEL: case VOICE_PARAM_OSC_1_LEVEL: case VOICE_PARAM_VCA_ENV_GAIN: case VOICE_PARAM_VCF_ENV_GAIN: case VOICE_PARAM_VCF_F_AMT_0: case VOICE_PARAM_VCF_Q_AMT_0: case VOICE_PARAM_VCF_F_AMT_1: case VOICE_PARAM_VCF_Q_AMT_1: case VOICE_PARAM_NOISE_LEVEL: case VOICE_PARAM_VCA_AM_AMT_0: case VOICE_PARAM_VCA_PAN_AMT_0: case VOICE_PARAM_VCF_Q_GAIN_0: case VOICE_PARAM_VCF_Q_CTRL_0: pObj->param[type] = value / 100; break; case VOICE_PARAM_OSC_0_FM_SRC_0: case VOICE_PARAM_OSC_1_FM_SRC_0: case VOICE_PARAM_OSC_0_AM_SRC_0: case VOICE_PARAM_OSC_1_AM_SRC_0: case VOICE_PARAM_OSC_0_PWM_SRC_0: case VOICE_PARAM_OSC_1_PWM_SRC_0: case VOICE_PARAM_VCF_F_SRC_0: case VOICE_PARAM_VCF_Q_SRC_0: case VOICE_PARAM_VCA_AM_SRC_0: case VOICE_PARAM_VCA_PAN_SRC_0: case VOICE_PARAM_OSC_0_FM_SRC_1: case VOICE_PARAM_OSC_1_FM_SRC_1: case VOICE_PARAM_OSC_0_AM_SRC_1: case VOICE_PARAM_OSC_1_AM_SRC_1: case VOICE_PARAM_OSC_0_PWM_SRC_1: case VOICE_PARAM_OSC_1_PWM_SRC_1: case VOICE_PARAM_VCF_F_SRC_1: case VOICE_PARAM_VCF_Q_SRC_1: pObj->param[type] = (int)value; break; case VOICE_PARAM_OSC_0_FM_SRC_OP: case VOICE_PARAM_OSC_1_FM_SRC_OP: case VOICE_PARAM_OSC_0_AM_SRC_OP: case VOICE_PARAM_OSC_1_AM_SRC_OP: case VOICE_PARAM_OSC_0_PWM_SRC_OP: case VOICE_PARAM_OSC_1_PWM_SRC_OP: case VOICE_PARAM_VCF_F_SRC_OP: case VOICE_PARAM_VCF_Q_SRC_OP: pObj->param[type] = (int)value; break; case VOICE_PARAM_VCF_TYPE: VCF_SetType(&pObj->vcf, (int)pObj->param[type]); if (pObj->id == 0) { VCF_SetType(&pObj->pCom->gvcf[0], (UINT32)pObj->param[type]); VCF_SetType(&pObj->pCom->gvcf[1], (UINT32)pObj->param[type]); } break; case VOICE_PARAM_VCF_ORDER: VCF_SetOrder(&pObj->vcf, (int)(pObj->param[type]+1)*2); if (pObj->id == 0) { VCF_SetOrder(&pObj->pCom->gvcf[0], (UINT32)(pObj->param[type]+1)*2); VCF_SetOrder(&pObj->pCom->gvcf[1], (UINT32)(pObj->param[type]+1)*2); } break; case VOICE_PARAM_VCF_F: VCF_SetF(&pObj->vcf, pObj->param[type]); if (pObj->id == 0) { VCF_SetF(&pObj->pCom->gvcf[0], pObj->param[type]); VCF_SetF(&pObj->pCom->gvcf[1], pObj->param[type]); } break; case VOICE_PARAM_VCF_Q: VCF_SetQ(&pObj->vcf, pObj->param[type]); if (pObj->id == 0) { VCF_SetQ(&pObj->pCom->gvcf[0], pObj->param[type]); VCF_SetQ(&pObj->pCom->gvcf[1], pObj->param[type]); } break; case VOICE_PARAM_ENV_0_A: case VOICE_PARAM_ENV_1_A: case VOICE_PARAM_ENV_2_A: case VOICE_PARAM_ENV_3_A: pObj->param[type] = value / 1000; ENV_Param2Set(&pObj->env[type-VOICE_PARAM_ENV_0_A], ENV_PARAM2_A, pObj->param[type]); if (pObj->id == 0) { ENV_Param2Set(&pObj->pCom->genv[type-VOICE_PARAM_ENV_0_A], ENV_PARAM2_A, pObj->param[type]); } break; case VOICE_PARAM_ENV_0_D: case VOICE_PARAM_ENV_1_D: case VOICE_PARAM_ENV_2_D: case VOICE_PARAM_ENV_3_D: pObj->param[type] = value / 1000; if (type == VOICE_PARAM_VCF_ENV_D) { pObj->param[type] = 3*value / 1000; } ENV_Param2Set(&pObj->env[type-VOICE_PARAM_ENV_0_D], ENV_PARAM2_D, pObj->param[type]); if (pObj->id == 0) { ENV_Param2Set(&pObj->pCom->genv[type-VOICE_PARAM_ENV_0_D], ENV_PARAM2_D, pObj->param[type]); } break; case VOICE_PARAM_ENV_0_S: case VOICE_PARAM_ENV_1_S: case VOICE_PARAM_ENV_2_S: case VOICE_PARAM_ENV_3_S: pObj->param[type] = value / 100; ENV_Param2Set(&pObj->env[type-VOICE_PARAM_ENV_0_S], ENV_PARAM2_S, pObj->param[type]); if (pObj->id == 0) { ENV_Param2Set(&pObj->pCom->genv[type-VOICE_PARAM_ENV_0_S], ENV_PARAM2_S, pObj->param[type]); } break; case VOICE_PARAM_ENV_0_R: case VOICE_PARAM_ENV_1_R: case VOICE_PARAM_ENV_2_R: case VOICE_PARAM_ENV_3_R: pObj->param[type] = value / 1000; if (type == VOICE_PARAM_VCF_ENV_R) { pObj->param[type] = 3*value / 1000; } ENV_Param2Set(&pObj->env[type-VOICE_PARAM_ENV_0_R], ENV_PARAM2_R, pObj->param[type]); if (pObj->id == 0) { ENV_Param2Set(&pObj->pCom->genv[type-VOICE_PARAM_ENV_0_R], ENV_PARAM2_R, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_MODE: case VOICE_PARAM_LFO_1_MODE: case VOICE_PARAM_LFO_2_MODE: case VOICE_PARAM_LFO_3_MODE: case VOICE_PARAM_LFO_0_SYNC: case VOICE_PARAM_LFO_1_SYNC: case VOICE_PARAM_LFO_2_SYNC: case VOICE_PARAM_LFO_3_SYNC: break; case VOICE_PARAM_LFO_0_SPEED: case VOICE_PARAM_LFO_1_SPEED: case VOICE_PARAM_LFO_2_SPEED: case VOICE_PARAM_LFO_3_SPEED: LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_SPEED], LFO_PARAM2_FREQ, pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_SPEED], LFO_PARAM2_FREQ, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_SMOOTH: case VOICE_PARAM_LFO_1_SMOOTH: case VOICE_PARAM_LFO_2_SMOOTH: case VOICE_PARAM_LFO_3_SMOOTH: pObj->param[type] = value / 1000; LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_SMOOTH], LFO_PARAM2_SMOOTH, pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_SMOOTH], LFO_PARAM2_SMOOTH, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_DELAY: case VOICE_PARAM_LFO_1_DELAY: case VOICE_PARAM_LFO_2_DELAY: case VOICE_PARAM_LFO_3_DELAY: pObj->param[type] = value / 1000; LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_DELAY], LFO_PARAM2_DELAY, pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_DELAY], LFO_PARAM2_DELAY, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_ATTACK: case VOICE_PARAM_LFO_1_ATTACK: case VOICE_PARAM_LFO_2_ATTACK: case VOICE_PARAM_LFO_3_ATTACK: pObj->param[type] = value / 1000; LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_ATTACK], LFO_PARAM2_ATTACK, pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_ATTACK], LFO_PARAM2_ATTACK, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_SHAPE: case VOICE_PARAM_LFO_1_SHAPE: case VOICE_PARAM_LFO_2_SHAPE: case VOICE_PARAM_LFO_3_SHAPE: LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_SHAPE], LFO_PARAM2_WAVEFORM, (int)pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_SHAPE], LFO_PARAM2_WAVEFORM, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_SYMMETRY: case VOICE_PARAM_LFO_1_SYMMETRY: case VOICE_PARAM_LFO_2_SYMMETRY: case VOICE_PARAM_LFO_3_SYMMETRY: pObj->param[type] = value / 100; LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_SYMMETRY], LFO_PARAM2_SYMMETRY, pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_SYMMETRY], LFO_PARAM2_SYMMETRY, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_MIDISYNC_MODE: case VOICE_PARAM_LFO_1_MIDISYNC_MODE: case VOICE_PARAM_LFO_2_MIDISYNC_MODE: case VOICE_PARAM_LFO_3_MIDISYNC_MODE: LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_MIDISYNC_MODE], LFO_PARAM2_MIDISYNC_MODE, (int)pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_MIDISYNC_MODE], LFO_PARAM2_MIDISYNC_MODE, pObj->param[type]); } break; case VOICE_PARAM_LFO_0_MIDISYNC_BEATDIV: case VOICE_PARAM_LFO_1_MIDISYNC_BEATDIV: case VOICE_PARAM_LFO_2_MIDISYNC_BEATDIV: case VOICE_PARAM_LFO_3_MIDISYNC_BEATDIV: LFO_Param2Set(&pObj->lfo[type-VOICE_PARAM_LFO_0_MIDISYNC_BEATDIV], LFO_PARAM2_MIDISYNC_BEATDIV, (int)pObj->param[type]); // First voice sets params for global LFOs if (pObj->id == 0) { LFO_Param2Set(&pObj->pCom->glfo[type-VOICE_PARAM_LFO_0_MIDISYNC_BEATDIV], LFO_PARAM2_MIDISYNC_BEATDIV, pObj->param[type]); } break; default: break; } } synth_float_t VoiceParamGet(voice_t *pObj, UINT32 type) { return pObj->param[type]; } UINT32 VoiceStateGet(voice_t *pObj) { return pObj->state; } void VoiceProcessDataV_Common(voice_t *pObj, float *pOut1, float *pOut2, UINT32 len) { UINT32 i; (void)pOut1; (void)pOut2; voice_common_t *pCom = pObj->pCom; // First voice only if (pObj->id == 0) { // Processes global LFOs for (i=0; i < VOICE_NUM_LFO; i++) { if ((int)pObj->param[VOICE_PARAM_LFO_0_MODE+i] == VOICE_LFO_MODE_GLOBAL) { pCom->pBuf_LFO_gbl[i] = LFO_ProcessDataV(&pCom->glfo[i], len); } } // Zero noise output for (i=0; i< len; i++) { pCom->noise_out[i] = 0; } #if 0 // Process global envelope generators for (i=0; i < (INT32)VOICE_NUM_ENV; i++) { pCom->pBuf_ENV_gbl[i] = ENV_ProcessDataV(&pCom->genv[i], len); } // Assign modulation sources i = 0; pModSrc[i++] = pCom->pBuf_zeros; // Off pModSrc[i++] = pCom->pBuf_LFO_gbl[0]; pModSrc[i++] = pCom->pBuf_LFO_gbl[1]; pModSrc[i++] = pCom->pBuf_LFO_gbl[2]; pModSrc[i++] = pCom->pBuf_LFO_gbl[3]; pModSrc[i++] = pCom->pBuf_ENV_gbl[0]; // Env. 0 pModSrc[i++] = pCom->pBuf_ENV_gbl[1]; // Env. 1 pModSrc[i++] = pCom->pBuf_ENV_gbl[2]; // Env. 2 pModSrc[i++] = pCom->pBuf_ENV_gbl[3]; // Env. 3 pModSrc[i++] = pCom->pBuf_zeros; // VCO 1 AM/FM pModSrc[i++] = pCom->pBuf_zeros; // VCO 2 AM/FM // Mix Cutoff modulator env_gain = pObj->param[VOICE_PARAM_VCF_ENV_GAIN]; if ((int)pObj->param[VOICE_PARAM_VCF_F_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_VCF_F_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_1]], pObj->param[VOICE_PARAM_VCF_F_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_1]], len); if (pObj->param[VOICE_PARAM_VCF_F_AMT_1] <= 0) Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1, len); else Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 0, len); break; } } Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_0], pCom->pBuf_ENV_gbl[VOICE_ENV_VCF], env_gain, len); Clamp_inplace_V(vcf_fm, -1, 1, len); // Mix resonance modulator if ((int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_VCF_Q_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1]], pObj->param[VOICE_PARAM_VCF_Q_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1]], len); if (pObj->param[VOICE_PARAM_VCF_Q_AMT_1] <= 0) Add_inplace_VV(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1, len); else Add_inplace_VV(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 0, len); break; } } Mul_inplace_VS(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_0], len); Clamp_inplace_V(vcf_qm, -1, 1, len); for (i=0; i< len; i++) temp[i] = pOut1[i]; pCom->pBuf_VCF_gbl_out = VCF_ProcessDataV(&pObj->pCom->gvcf[0], vcf_fm, vcf_qm, temp, len); for (i=0; i< len; i++) pOut1[i] = pCom->pBuf_VCF_gbl_out[i]; for (i=0; i< len; i++) temp[i] = pOut2[i]; pCom->pBuf_VCF_gbl_out = VCF_ProcessDataV(&pObj->pCom->gvcf[1], vcf_fm, vcf_qm, temp, len); for (i=0; i< len; i++) pOut2[i] = pCom->pBuf_VCF_gbl_out[i]; #endif if (pObj->param[VOICE_PARAM_NOISE_ENABLE] > (synth_float_t)0.5) { if ((int)pObj->param[VOICE_PARAM_NOISE_SHAPE] == VOICE_NOISE_SHAPE_WHITE) { for (i=0; i< len; i++) { pCom->noise_out[i] = Noise_Uniform(&pCom->gnoise, 2.0f, 0.0); } } if ((int)pObj->param[VOICE_PARAM_NOISE_SHAPE] == VOICE_NOISE_SHAPE_PINK) { for (i=0; i< len; i++) { pCom->noise_out[i] = Noise_Gaussian(&pCom->gnoise, 2*0.28867513459481f, 0.0); } } } } } void VoiceProcessDataV(voice_t *pObj, float *pOut1, float *pOut2, UINT32 len) { int i, j; synth_float_t out, env_gain; synth_float_t *pBuf_ENV[VOICE_NUM_ENV], *pBuf_Postvcf; synth_float_t *pBuf_OSC[VOICE_NUM_OSC]; synth_float_t *pBuf_LFO[VOICE_NUM_LFO]; UINT32 vco_is_disabled[VOICE_NUM_OSC]; synth_float_t *pModSrc[VOICE_NUM_MOD_SOURCES]; voice_common_t *pCom = pObj->pCom; // Temp Variables synth_float_t VCO_fmout[VOICE_NUM_OSC][SYNTH_MAX_BUFSIZE]; synth_float_t vco_pwm[SYNTH_MAX_BUFSIZE]; synth_float_t vco_fm[SYNTH_MAX_BUFSIZE]; synth_float_t vco_am[SYNTH_MAX_BUFSIZE]; synth_float_t vcf_fm[SYNTH_MAX_BUFSIZE]; synth_float_t vcf_qm[SYNTH_MAX_BUFSIZE]; synth_float_t vca_am[SYNTH_MAX_BUFSIZE]; synth_float_t vca_pan[SYNTH_MAX_BUFSIZE]; synth_float_t vco_pitch[VOICE_NUM_OSC][SYNTH_MAX_BUFSIZE]; synth_float_t osc_out[SYNTH_MAX_BUFSIZE]; synth_float_t osc_out_smoothed[VOICE_NUM_OSC][SYNTH_MAX_BUFSIZE]; #if 0 // Process parameter smoothing for (i=0; i < (INT32)VOICE_NUM_PARAMS; i++) { if (pObj->pParam_smoother[i]) { if (!Smooth_is_settled(pObj->pParam_smoother[i], pObj->param[i])) { Smooth_Process_V(pObj->pParam_smoother[i], pObj->param[i], pObj->param_smoothed[i], len); } } } #endif // Process envelope generators for (i=0; i < (INT32)VOICE_NUM_ENV; i++) { pBuf_ENV[i] = ENV_ProcessDataV(&pObj->env[i], len); } // Process LFOs for (i=0; i < (INT32)VOICE_NUM_LFO; i++) { if ((int)pObj->param[VOICE_PARAM_LFO_0_MODE+i] == VOICE_LFO_MODE_INDIVIDUAL) { pBuf_LFO[i] = LFO_ProcessDataV(&pObj->lfo[i], len); } } // Use global LFO for (i=0; i < (INT32)VOICE_NUM_LFO; i++) { if ((int)pObj->param[VOICE_PARAM_LFO_0_MODE+i] == VOICE_LFO_MODE_GLOBAL) { pBuf_LFO[i] = pCom->pBuf_LFO_gbl[i]; } } // Assign modulation sources i = 0; pModSrc[i++] = pCom->pBuf_zeros; // Off pModSrc[i++] = pBuf_LFO[0]; pModSrc[i++] = pBuf_LFO[1]; pModSrc[i++] = pBuf_LFO[2]; pModSrc[i++] = pBuf_LFO[3]; pModSrc[i++] = pBuf_ENV[0]; // Env. 0 pModSrc[i++] = pBuf_ENV[1]; // Env. 1 pModSrc[i++] = pBuf_ENV[2]; // Env. 2 pModSrc[i++] = pBuf_ENV[3]; // Env. 3 pModSrc[i++] = pCom->pBuf_zeros; // VCO 1 AM/FM pModSrc[i++] = pCom->pBuf_zeros; // VCO 2 AM/FM // Process smoothing for VCO switching for (i=0; i < (INT32)VOICE_NUM_OSC; i++) { vco_is_disabled[i] = Smooth_is_settled(&pObj->smooth_vco_enable[i], 0) && (UINT32)(pObj->param[VOICE_PARAM_OSC_0_ENABLE+i] < (synth_float_t)0.5); } // Process pitche for VCOs for (i=0; i < (INT32)VOICE_NUM_OSC; i++) { if (pObj->param[VOICE_PARAM_PORTAMENTO_TIME] <= (synth_float_t)0.001) { Add_inplace_VS(vco_pitch[i], 0, pObj->vco_pitch[i], len); } else { Smooth_Process_V(&pObj->smooth_vco_portamento[i], pObj->vco_pitch[i], vco_pitch[i], len); } } // Process Oscillators pBuf_OSC[0] = VCO_GetProcessBuffer(&pObj->vco[0]); if (!vco_is_disabled[0]) { // FM 0 if ((int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_1]], pObj->param[VOICE_PARAM_OSC_0_FM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_0_FM_AMT_1] <= 0) Add_inplace_VV(vco_fm, pObj->param[VOICE_PARAM_OSC_0_FM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_0]], 1, len); else Add_inplace_VV(vco_fm, pObj->param[VOICE_PARAM_OSC_0_FM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_FM_SRC_0]], 0, len); break; } } Clamp_inplace_V(vco_fm, -1, 1, len); Mul_inplace_VS(vco_fm, pObj->param[VOICE_PARAM_OSC_0_FM_AMT_0], len); // PWM 0 if ((int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_1]], pObj->param[VOICE_PARAM_OSC_0_PWM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_0_PWM_AMT_1] <= 0) Add_inplace_VV(vco_pwm, pObj->param[VOICE_PARAM_OSC_0_PWM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_0]], 1, len); else Add_inplace_VV(vco_pwm, pObj->param[VOICE_PARAM_OSC_0_PWM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_PWM_SRC_0]], 0, len); break; } } Mul_inplace_VS(vco_pwm, pObj->param[VOICE_PARAM_OSC_0_PWM_AMT_0], len); // Process VCO 0 VCO_ProcessDataV(&pObj->vco[0], vco_pitch[0], vco_fm, vco_pwm, NULL, NULL, len); // AM 0 if ((int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_1]], pObj->param[VOICE_PARAM_OSC_0_AM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_0_AM_AMT_1] <= 0) Add_inplace_VV(vco_am, pObj->param[VOICE_PARAM_OSC_0_AM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0]], 1, len); else Add_inplace_VV(vco_am, pObj->param[VOICE_PARAM_OSC_0_AM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0]], 0, len); break; } } if (((int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_0] != VOICE_MOD_SRC_0_DISABLED) || ((int)pObj->param[VOICE_PARAM_OSC_0_AM_SRC_1] != VOICE_MOD_SRC_1_DISABLED)) { if (pObj->param[VOICE_PARAM_OSC_0_AM_AMT_0] <= 0) { Add_inplace_VS(vco_am, pObj->param[VOICE_PARAM_OSC_0_AM_AMT_0], 1, len); } else { Add_inplace_VS(vco_am, pObj->param[VOICE_PARAM_OSC_0_AM_AMT_0], 0, len); } Clamp_inplace_V(vco_am, 0, 1, len); // Modulate Mul_inplace_VV(pBuf_OSC[0], vco_am, len); } } if (!vco_is_disabled[0]) { Add_VS(VCO_fmout[0], pBuf_OSC[0], 0.5, 0.5, len); pModSrc[VOICE_MOD_SRC_VCO_0] = VCO_fmout[0]; // pModSrc[VOICE_MOD_SRC_VCO_0] = pBuf_OSC[0]; } pBuf_OSC[1] = VCO_GetProcessBuffer(&pObj->vco[1]); if (!vco_is_disabled[1]) { // FM 1 if ((int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_1]], pObj->param[VOICE_PARAM_OSC_1_FM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_fm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_1_FM_AMT_1] <= 0) Add_inplace_VV(vco_fm, pObj->param[VOICE_PARAM_OSC_1_FM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_0]], 1, len); else Add_inplace_VV(vco_fm, pObj->param[VOICE_PARAM_OSC_1_FM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_FM_SRC_0]], 0, len); break; } } Clamp_inplace_V(vco_fm, -1, 1, len); Mul_inplace_VS(vco_fm, pObj->param[VOICE_PARAM_OSC_1_FM_AMT_0], len); // PWM 1 if ((int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_1]], pObj->param[VOICE_PARAM_OSC_1_PWM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_pwm, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_1_PWM_AMT_1] <= 0) Add_inplace_VV(vco_pwm, pObj->param[VOICE_PARAM_OSC_1_PWM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_0]], 1, len); else Add_inplace_VV(vco_pwm, pObj->param[VOICE_PARAM_OSC_1_PWM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_PWM_SRC_0]], 0, len); break; } } Mul_inplace_VS(vco_pwm, pObj->param[VOICE_PARAM_OSC_1_PWM_AMT_0], len); // Process VCO 1 VCO_ProcessDataV(&pObj->vco[1], vco_pitch[1], vco_fm, vco_pwm, NULL, NULL, len); // AM 1 if ((int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_1]], pObj->param[VOICE_PARAM_OSC_1_AM_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vco_am, pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_1]], len); if (pObj->param[VOICE_PARAM_OSC_1_AM_AMT_1] <= 0) Add_inplace_VV(vco_am, pObj->param[VOICE_PARAM_OSC_1_AM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0]], 1, len); else Add_inplace_VV(vco_am, pObj->param[VOICE_PARAM_OSC_1_AM_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0]], 0, len); break; } } if (((int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_0] != VOICE_MOD_SRC_0_DISABLED) || ((int)pObj->param[VOICE_PARAM_OSC_1_AM_SRC_1] != VOICE_MOD_SRC_1_DISABLED)) { if (pObj->param[VOICE_PARAM_OSC_1_AM_AMT_0] <= 0) { Add_inplace_VS(vco_am, pObj->param[VOICE_PARAM_OSC_1_AM_AMT_0], 1, len); } else { Add_inplace_VS(vco_am, pObj->param[VOICE_PARAM_OSC_1_AM_AMT_0], 0, len); } Clamp_inplace_V(vco_am, 0, 1, len); // Modulate Mul_inplace_VV(pBuf_OSC[1], vco_am, len); } } if (!vco_is_disabled[1]) { Add_VS(VCO_fmout[1], pBuf_OSC[1], 0.5, 0.5, len); pModSrc[VOICE_MOD_SRC_VCO_1] = VCO_fmout[1]; // pModSrc[VOICE_MOD_SRC_VCO_1] = pBuf_OSC[1]; } // Smooth Oscillator output during switching on/off and do level adjust here for (i=0; i < (INT32)VOICE_NUM_OSC; i++) { Smooth_Process_VV(&pObj->smooth_vco_enable[i], pObj->param[VOICE_PARAM_OSC_0_ENABLE+i], pBuf_OSC[i], osc_out_smoothed[i], len); } // Mix Oscillators Add_VV(osc_out, osc_out_smoothed[0], pObj->param[VOICE_PARAM_OSC_0_LEVEL], pCom->noise_out, pObj->param[VOICE_PARAM_NOISE_LEVEL], len); Add_inplace_VV(osc_out, 1, osc_out_smoothed[1], pObj->param[VOICE_PARAM_OSC_1_LEVEL], len); // Mix Cutoff modulator env_gain = pObj->param[VOICE_PARAM_VCF_ENV_GAIN]; if ((int)pObj->param[VOICE_PARAM_VCF_F_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_VCF_F_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_1]], pObj->param[VOICE_PARAM_VCF_F_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vcf_fm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_1]], len); if (pObj->param[VOICE_PARAM_VCF_F_AMT_1] <= 0) Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 1, len); else Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_F_SRC_0]], 0, len); break; } } Add_inplace_VV(vcf_fm, pObj->param[VOICE_PARAM_VCF_F_AMT_0], pBuf_ENV[VOICE_ENV_VCF], env_gain, len); Clamp_inplace_V(vcf_fm, -1, 1, len); // Mix resonance modulator if ((int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1] == VOICE_MOD_SRC_1_DISABLED) { Add_VS(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1.0, 0, len); } else { switch((int)pObj->param[VOICE_PARAM_VCF_Q_SRC_OP]) { default: case VOICE_MOD_SRC_OP_ADD: Add_VV(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1.0, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1]], pObj->param[VOICE_PARAM_VCF_Q_AMT_1], len); break; case VOICE_MOD_SRC_OP_MUL: Mul_VV(vcf_qm, pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_1]], len); if (pObj->param[VOICE_PARAM_VCF_Q_AMT_1] <= 0) Add_inplace_VV(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 1, len); else Add_inplace_VV(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_1], pModSrc[(int)pObj->param[VOICE_PARAM_VCF_Q_SRC_0]], 0, len); break; } } Mul_inplace_VS(vcf_qm, pObj->param[VOICE_PARAM_VCF_Q_AMT_0], len); Clamp_inplace_V(vcf_qm, -1, 1, len); // Filter envelope and filtering for (i=0; i < (INT32)VOICE_NUM_OSC; i++) { vco_is_disabled[i] = Smooth_is_settled(&pObj->smooth_vco_enable[i], 0) && (pObj->param[VOICE_PARAM_OSC_0_ENABLE+i] < (synth_float_t)0.5); } if (vco_is_disabled[0] && vco_is_disabled[1] && (pObj->param[VOICE_PARAM_NOISE_ENABLE] < (synth_float_t)0.5)) { pBuf_Postvcf = osc_out; } else { pBuf_Postvcf = VCF_ProcessDataV(&pObj->vcf, vcf_fm, vcf_qm, osc_out, len); } // Amplifier envelope and voice panning env_gain = 0.25f*jsy_max(0, jsy_min(1, pObj->param[VOICE_PARAM_VCA_ENV_GAIN])); // VCA AM Mul_VS(vca_am, pModSrc[(int)pObj->param[VOICE_PARAM_VCA_AM_SRC_0]], pObj->param[VOICE_PARAM_VCA_AM_AMT_0], len); Add_inplace_VS(vca_am, -1.0, 1.0, len); // VCA PAN if ((int)pObj->param[VOICE_PARAM_VCA_PAN_SRC_0] != VOICE_MOD_SRC_0_DISABLED) { Add_VS(vca_pan, pModSrc[(int)pObj->param[VOICE_PARAM_VCA_PAN_SRC_0]], 2.0, -1.0, len); Mul_inplace_VS(vca_pan, pObj->param[VOICE_PARAM_VCA_PAN_AMT_0], len); } else { Add_VS(vca_pan, pModSrc[(int)pObj->param[VOICE_PARAM_VCA_PAN_SRC_0]], 0, pObj->param[VOICE_PARAM_VCA_PAN_AMT_0], len); } for (j=0; j < (INT32)len; j++) { // env_gain = 0.25f*jsy_max(0, jsy_min(1, pObj->param_smoothed[VOICE_PARAM_VCA_ENV_GAIN][j])); out = pBuf_Postvcf[j] * pBuf_ENV[VOICE_ENV_VCA][j] * env_gain * vca_am[j]; (*pOut1++) += (float)((1+pObj->param[VOICE_PARAM_VOICE_PAN])*(1+vca_pan[j])*out); (*pOut2++) += (float)((1-pObj->param[VOICE_PARAM_VOICE_PAN])*(1-vca_pan[j])*out); } if (ENV_IsIdle(&pObj->env[VOICE_ENV_VCA])) { pObj->state = note_state_idle; for (i = 0; i < VOICE_NUM_ENV; i++) ENV_Reset(&pObj->env[i]); } }