git-svn-id: http://moon:8086/svn/software/trunk/projects/JaySynth@729 b431acfa-c32f-4a4a-93f1-934dc6c82436
1258 lines
39 KiB
C
1258 lines
39 KiB
C
// --------------------------------------------------------------
|
|
// --------------------------------------------------------------
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <time.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 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]*(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 = max(0, 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] = min(1, max(-1, -value/100));
|
|
else
|
|
pObj->param[type] = min(1, 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, value/(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, value/(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], pObj->param[type]);
|
|
VCF_SetType(&pObj->pCom->gvcf[1], 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], (int)(pObj->param[type]+1)*2);
|
|
VCF_SetOrder(&pObj->pCom->gvcf[1], (int)(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;
|
|
|
|
voice_common_t *pCom = pObj->pCom;
|
|
synth_float_t *pModSrc[VOICE_NUM_MOD_SOURCES];
|
|
synth_float_t env_gain;
|
|
|
|
// Temp Variables
|
|
synth_float_t vcf_fm[SYNTH_MAX_BUFSIZE];
|
|
synth_float_t vcf_qm[SYNTH_MAX_BUFSIZE];
|
|
synth_float_t temp[SYNTH_MAX_BUFSIZE];
|
|
|
|
// 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] > 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) && (pObj->param[VOICE_PARAM_OSC_0_ENABLE+i] < 0.5);
|
|
}
|
|
|
|
// Process pitche for VCOs
|
|
for (i=0; i < (INT32)VOICE_NUM_OSC; i++)
|
|
{
|
|
if (pObj->param[VOICE_PARAM_PORTAMENTO_TIME] <= 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] < 0.5);
|
|
}
|
|
if (vco_is_disabled[0] && vco_is_disabled[1] && (pObj->param[VOICE_PARAM_NOISE_ENABLE] < 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*max(0, 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*max(0, 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]);
|
|
|
|
}
|
|
}
|