Files
JaySynth/src/synth/voice.c
T
2025-08-08 16:36:22 +02:00

1255 lines
39 KiB
C

// --------------------------------------------------------------
// --------------------------------------------------------------
#include <stdlib.h>
#include <math.h>
#include <time.h>
#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]);
}
}