Files
JaySynth/Source/JaySynth.cpp
T
2020-08-17 12:07:25 +00:00

1619 lines
45 KiB
C++

/*
==============================================================================
This file was generated by user!
==============================================================================
*/
#include <math.h>
#include <stdio.h>
#include "synth/synth_defs.h"
#include "JaySynthSound.h"
#include "JaySynthVoice.h"
#include "JaySynthMonophonicMGR.h"
#include "JaySynthMidiCC.h"
#include "JaySynth.h"
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define WITH_OLD_HUMANIZE
#include "synth/lfo.h"
#ifndef WITH_DEV_SYNCED_LFO
#define WITH_DEV_SYNCED_LFO 1
#endif
//==============================================================================
/** A JaySynth that just plays incredible sounds.. */
JaySynth::JaySynth (int num_voices, String pathToWaves)
{
int i, j;
char paramName[256];
pMidCC_editBuffer = NULL;
memset(synth_common.vco.wt.wave_rawdata, 0, sizeof(synth_common.vco.wt.wave_rawdata));
if (pathToWaves != String::empty)
{
File wavesFile = File(pathToWaves);
ScopedPointer<FileInputStream>pIn = wavesFile.createInputStream();
pIn->read(synth_common.vco.wt.wave_rawdata, sizeof(synth_common.vco.wt.wave_rawdata));
}
max_num_voices = num_voices;
total_num_voices = num_voices;
m_pVoices = new voice_t[num_voices];
for (i = 0; i < num_voices; i++)
addVoice (new JaySynthVoice(&m_pVoices[i], i, &synth_common)); // These voices will play our sounds..
addSound (new JaySynthSound());
lastPitchWheelValue = 8192;
lastmidiChannel = 0;
paramInfoInit(&pb_range[0], 0, NULL);
paramInfoInit(&pb_range[1], 1, NULL);
paramInfoSet(&pb_range[0], 1, 1, 0.5, -12, 0, +12, 0);
paramInfoSet(&pb_range[1], 1, 1, 0.5, -12, 0, +12, 0);
pPer_voice_controls = new per_voice_control_t[max_num_voices];
memset(pPer_voice_controls, 0, max_num_voices*sizeof(per_voice_control_t));
pCurrNoteInfos = new midi_note_info_t[max_num_voices];
memset(pCurrNoteInfos, 0, max_num_voices*sizeof(midi_note_info_t));
ClearControls();
memset(params, 0, SYNTH_NUM_PARAMS*sizeof(synth_float_t));
memset(last_midiCC_info, 0, NUM_MIDI_CONTROLLERS*sizeof(midiCC_info_t));
memset(&last_midi_note_info, 0, sizeof(last_midi_note_info));
clearKeysPressed();
for (i=0; i < NUM_MIDI_CONTROLLERS; i++)
last_midiCC_info[i].ID = i;
// Init humanize parameter from global parameter constraints
humanize_voice_param = new param_info_t*[SYNTH_NUM_PARAMS];
ppHumanizedSliders = new synth_float_t*[SYNTH_NUM_PARAMS];
for (i=0; i < SYNTH_NUM_PARAMS; i++)
{
humanize_voice_param[i] = new param_info_t[max_num_voices];
ppHumanizedSliders[i] = new synth_float_t[max_num_voices];
for (j=0; j < max_num_voices; j++)
{
snprintf(paramName, sizeof(paramName), "%s Voice# %03d", getParamInfo(i)->pName, j);
paramInfoInit(&humanize_voice_param[i][j], getParamInfo(i)->id, paramName);
paramInfoCopy(&humanize_voice_param[i][j], getParamInfo(i));
ppHumanizedSliders[i][j] = 0;
}
}
updateParameters();
next_possible_voice = 0;
oldest_voice = 0;
doHumanize = 0;
isHumanize = 0;
m_doMonophon = 0;
m_isMonophon = 0;
m_doUnison = 0;
m_isUnison = 0;
m_unisonGain = 1;
m_doMonophonRetrigger = true;
m_num_audiothreads = SystemStats::getNumCpus();
m_ppAudioThread = new JaySynthThread*[m_num_audiothreads];
m_ppEventAudioThreadRdy = new WaitableEvent*[m_num_audiothreads];
SynthDebug("Creating threads...\n");
for (i=0; i < m_num_audiothreads; i++)
{
m_ppEventAudioThreadRdy[i] = new WaitableEvent();
m_ppAudioThread[i] = new JaySynthThread(m_ppEventAudioThreadRdy[i], m_pVoices, num_voices, i, m_num_audiothreads);
}
SynthDebug("Starting %d threads ...\n", m_num_audiothreads);
for (i=0; i < m_num_audiothreads; i++)
{
m_ppAudioThread[i]->startThread (12);
}
m_clock_cnt_bar = 0;
m_lastTime_ms = 0;
m_estimatedTime_ms = 0;
m_numMidiClocksPerBeat = 1;
m_numMidiClocksPerBar = 1;
m_isMidiClockStarted = false;
}
JaySynth::~JaySynth()
{
int i, j;
SynthDebug("Stopping threads...\n");
for (i=0; i < m_num_audiothreads; i++)
{
m_ppAudioThread[i]->stopThread(10000);
}
SynthDebug("Deleting threads...\n");
for (i=0; i < m_num_audiothreads; i++)
{
delete(m_ppAudioThread[i]);
}
delete(m_ppAudioThread);
SynthDebug("delete params\n");
paramInfoFree(&pb_range[0]);
paramInfoFree(&pb_range[1]);
SynthDebug("delete voices\n");
for (i=0; i < SYNTH_NUM_PARAMS; i++)
{
for (j=0; j < max_num_voices; j++)
{
paramInfoFree(&humanize_voice_param[i][j]);
}
delete (humanize_voice_param[i]);
delete (ppHumanizedSliders[i]);
}
delete (humanize_voice_param);
delete (ppHumanizedSliders);
for (i = max_num_voices; --i >= 0;)
{
removeVoice(i);
}
delete (pPer_voice_controls);
delete (pCurrNoteInfos);
delete (m_pVoices);
for (i=0; i < m_num_audiothreads; i++)
{
delete (m_ppEventAudioThreadRdy[i]);
}
delete(m_ppEventAudioThreadRdy);
}
synth_float_t JaySynth::getVolume(void)
{
return master_volume*m_unisonGain;
}
void JaySynth::humanizeParam (int paramID, bool useRandom, UINT32 random_seed, synth_float_t spread_min, synth_float_t variance)
{
#ifdef WITH_OLD_HUMANIZE
int j;
synth_float_t spread;
noise_gen_t noise;
Noise_Init(&noise, random_seed);
for (j=0; j < max_num_voices; j++)
{
if (useRandom)
do
{
spread = Noise_Gaussian(&noise, variance*sqrt(1.f/12), 0.0);
} while (fabs(spread) < spread_min);
else
spread = variance*((synth_float_t)j/max_num_voices -0.5);
paramInfoSet(&humanize_voice_param[paramID][j],
/*base*/getParamInfo(paramID)->base,
/*kexp*/getParamInfo(paramID)->kexp,
/*scenter*/getParamInfo(paramID)->scenter,
/*pmin*/getParamInfo(paramID)->pmin ,
/*pcenter*/-1E6/*getParamInfo(i)->pcenter*/,
/*pmax*/getParamInfo(paramID)->pmax * (1+spread),
/*pinterval*/0);
ppHumanizedSliders[paramID][j] = spread;
}
Noise_Free(&noise);
#else
int j;
synth_float_t spread, spread_dir, value_lo, value_hi;
noise_gen_t noise;
Noise_Init(&noise, random_seed);
spread_dir = 1.0;
for (j=0; j < GET_NUM_VOICES; j++)
{
if (useRandom)
{
do
{
spread = Noise_Gaussian(&noise, variance*sqrt(1.f/12), 0.0);
} while (fabs(spread) < spread_min);
spread = fabs(spread)*spread_dir;
}
else
spread = variance*((synth_float_t)j/GET_NUM_VOICES -0.5);
value_lo = clampParam(getParamInfo(paramID), getParamInfo(paramID)->pmin * (1 + spread));
value_hi = clampParam(getParamInfo(paramID), getParamInfo(paramID)->pmax * (1 + spread));
paramInfoSet(&humanize_voice_param[paramID][j],
/*base*/getParamInfo(paramID)->base,
/*kexp*/getParamInfo(paramID)->kexp,
/*scenter*/getParamInfo(paramID)->scenter,
/*pmin*/ value_lo,
/*pcenter*/-1E6/*getParamInfo(i)->pcenter*/,
/*pmax*/value_hi,
/*pinterval*/0);
spread_dir = -spread_dir;
}
Noise_Free(&noise);
#endif
}
void JaySynth::setSampleRate (synth_float_t sampleRate)
{
int i;
Synthesiser::setCurrentPlaybackSampleRate (sampleRate);
for (i=0; i < max_num_voices; i++)
((JaySynthVoice*)getVoice(i))->setSampleRate(sampleRate);
}
void JaySynth::setBufsize (int /*bufsize*/)
{
}
void JaySynth::humanizeModeChanged(void)
{
if (doHumanize ^ isHumanize)
{
isHumanize = doHumanize;
humanizeVarianceChanged_VCO();
humanizeVarianceChanged_VCF();
humanizeVarianceChanged_ENV();
updateParameters();
}
}
void JaySynth::humanizeVarianceChanged_VCO(void)
{
#ifdef WITH_OLD_HUMANIZE
humanizeParam(SYNTH_PARAM_TUNE, true, 0x1234561, 0, 0.5*humanize_var_vco);
// humanizeParam(SYNTH_PARAM_OSC_0_DETUNE, true, 0x293857, 0, humanize_var_vco);
// humanizeParam(SYNTH_PARAM_OSC_1_DETUNE, true, 0x137573, 0, humanize_var_vco);
// Re-Read parameter
setParameter(SYNTH_PARAM_TUNE, params[SYNTH_PARAM_TUNE]);
// setParameter(SYNTH_PARAM_OSC_0_DETUNE, params[SYNTH_PARAM_OSC_0_DETUNE]);
// setParameter(SYNTH_PARAM_OSC_1_DETUNE, params[SYNTH_PARAM_OSC_1_DETUNE]);
#else
int i;
synth_float_t f_ref;
noise_gen_t noise;
Noise_Init(&noise, 0x1234561);
for (i=0; i < GET_NUM_VOICES; i++)
{
f_ref = Noise_Gaussian(&noise, 100*humanize_var_vco, 440.0);
if (isHumanize)
((JaySynthVoice*)getVoice(i))->setParameter(VOICE_PARAM_MASTER_FREF, f_ref);
else
((JaySynthVoice*)getVoice(i))->setParameter(VOICE_PARAM_MASTER_FREF, 440.0);
}
Noise_Free(&noise);
#endif
}
void JaySynth::humanizeVarianceChanged_VCF(void)
{
humanizeParam(SYNTH_PARAM_VCF_F, true, 0x1234561, 0, 0.5*humanize_var_vcf);
humanizeParam(SYNTH_PARAM_VCF_Q, true, 0x1234561, 0, 0.05*humanize_var_vcf);
// Re-Read parameter
setParameter(SYNTH_PARAM_VCF_F, params[SYNTH_PARAM_VCF_F]);
setParameter(SYNTH_PARAM_VCF_Q, params[SYNTH_PARAM_VCF_Q]);
}
void JaySynth::humanizeVarianceChanged_ENV(void)
{
humanizeParam(SYNTH_PARAM_VCA_ENV_A, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_VCA_ENV_D, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_VCA_ENV_R, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_VCF_ENV_A, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_VCF_ENV_D, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_VCF_ENV_R, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_2_A, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_2_D, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_2_R, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_3_A, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_3_D, true, 0x1234561, 0, humanize_var_env);
humanizeParam(SYNTH_PARAM_ENV_3_R, true, 0x1234561, 0, humanize_var_env);
// Re-Read parameter
setParameter(SYNTH_PARAM_VCA_ENV_A, params[SYNTH_PARAM_VCA_ENV_A]);
setParameter(SYNTH_PARAM_VCA_ENV_D, params[SYNTH_PARAM_VCA_ENV_D]);
setParameter(SYNTH_PARAM_VCA_ENV_R, params[SYNTH_PARAM_VCA_ENV_R]);
setParameter(SYNTH_PARAM_VCF_ENV_A, params[SYNTH_PARAM_VCF_ENV_A]);
setParameter(SYNTH_PARAM_VCF_ENV_D, params[SYNTH_PARAM_VCF_ENV_D]);
setParameter(SYNTH_PARAM_VCF_ENV_R, params[SYNTH_PARAM_VCF_ENV_R]);
setParameter(SYNTH_PARAM_ENV_2_A, params[SYNTH_PARAM_ENV_2_A]);
setParameter(SYNTH_PARAM_ENV_2_D, params[SYNTH_PARAM_ENV_2_D]);
setParameter(SYNTH_PARAM_ENV_2_R, params[SYNTH_PARAM_ENV_2_R]);
setParameter(SYNTH_PARAM_ENV_3_A, params[SYNTH_PARAM_ENV_3_A]);
setParameter(SYNTH_PARAM_ENV_3_D, params[SYNTH_PARAM_ENV_3_D]);
setParameter(SYNTH_PARAM_ENV_3_R, params[SYNTH_PARAM_ENV_3_R]);
}
//==============================================================================
// Parameter stuff
//==============================================================================
void JaySynth::ClearControls(void)
{
memset(controls, 0, SYNTH_NUM_PARAMS*sizeof(synth_float_t));
}
void JaySynth::updateParameters(void)
{
int paramID, voice;
for (paramID=0; paramID < SYNTH_NUM_PARAMS; paramID++)
{
if (pMidCC_editBuffer)
{
for (voice=0; voice < GET_NUM_VOICES; voice++)
{
setPerVoiceControl(voice, SYNTH_PER_VOICE_CONTROL_VELKEY, paramID, pMidCC_editBuffer->getVelKeyControl(paramID, pCurrNoteInfos[voice].velocity, pCurrNoteInfos[voice].note));
}
}
setParam(paramID, -1);
}
}
void JaySynth::updateParameter(int paramID)
{
int voice;
if (paramID >= SYNTH_NUM_PARAMS)
return;
if (pMidCC_editBuffer)
{
for (voice=0; voice < GET_NUM_VOICES; voice++)
{
setPerVoiceControl(voice, SYNTH_PER_VOICE_CONTROL_VELKEY, paramID, pMidCC_editBuffer->getVelKeyControl(paramID, pCurrNoteInfos[voice].velocity, pCurrNoteInfos[voice].note));
}
}
setParam(paramID, -1);
}
synth_float_t JaySynth::getParameter(int paramID)
{
if (paramID < SYNTH_NUM_PARAMS)
return params[paramID];
return 0;
}
void JaySynth::setParameter(int paramID, synth_float_t param)
{
params[paramID] = param;
setParam(paramID, -1);
paramID_changed = paramID;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_PARAM, &paramID_changed);
}
void JaySynth::setControl(int paramID, synth_float_t param)
{
controls[paramID] = param;
setParam(paramID, -1);
paramID_changed = paramID;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_PARAM, &paramID_changed);
}
void JaySynth::setPerVoiceControl(int voice, int channel, int paramID, synth_float_t param)
{
pPer_voice_controls[voice].ctrl[channel][paramID] = param;
setParam(paramID, voice);
}
void JaySynth::setParam(int paramID, int voice)
{
int i, j, voice_param_type, voice_min, voice_max;
synth_float_t param;
param_info_t *pParamInfo = getParamInfo(paramID);
if (!pParamInfo)
return;
voice_param_type = -1;
param = clampParam(pParamInfo, params[paramID] + controls[paramID]);
switch (paramID)
{
case SYNTH_PARAM_VOLUME:
master_volume = param/100;
break;
case SYNTH_PARAM_TUNE:
voice_param_type = VOICE_PARAM_MASTER_TUNE;
break;
case SYNTH_PARAM_TOTAL_NUM_VOICES:
total_num_voices = (int)param;
break;
case SYNTH_PARAM_VOICE_PAN_SPREAD:
voice_param_type = VOICE_PARAM_VOICE_PAN;
break;
case SYNTH_PARAM_HUMANIZE_ENABLE:
doHumanize = param >= 0.5;
break;
case SYNTH_PARAM_HUMANIZE_VAR_VCO:
humanize_var_vco = param/100;
break;
case SYNTH_PARAM_HUMANIZE_VAR_VCF:
humanize_var_vcf = param/100;
break;
case SYNTH_PARAM_HUMANIZE_VAR_ENV:
humanize_var_env = param/100;
break;
case SYNTH_PARAM_MONOPHONIC_ENABLE:
m_doMonophon = param >= 0.5;
break;
case SYNTH_PARAM_MONOPHONIC_RETRIGGER_ENABLE:
m_doMonophonRetrigger = param >= 0.5;
break;
case SYNTH_PARAM_UNISONO_ENABLE:
m_doUnison = param >= 0.5;
break;
case SYNTH_PARAM_UNISONO_NUM_VOICES:
unison_num_voices = (int)param;
break;
case SYNTH_PARAM_PORTAMENTO_TIME:
voice_param_type = VOICE_PARAM_PORTAMENTO_TIME;
break;
case SYNTH_PARAM_NOISE_ENABLE:
voice_param_type = VOICE_PARAM_NOISE_ENABLE;
break;
case SYNTH_PARAM_NOISE_LEVEL:
voice_param_type = VOICE_PARAM_NOISE_LEVEL;
break;
case SYNTH_PARAM_NOISE_SHAPE:
voice_param_type = VOICE_PARAM_NOISE_SHAPE;
break;
case SYNTH_PARAM_VCF_TYPE:
voice_param_type = VOICE_PARAM_VCF_TYPE;
break;
case SYNTH_PARAM_VCF_ORDER:
voice_param_type = VOICE_PARAM_VCF_ORDER;
break;
case SYNTH_PARAM_VCF_F:
voice_param_type = VOICE_PARAM_VCF_F;
break;
case SYNTH_PARAM_VCF_Q:
voice_param_type = VOICE_PARAM_VCF_Q;
break;
case SYNTH_PARAM_OSC_0_ENABLE:
case SYNTH_PARAM_OSC_1_ENABLE:
voice_param_type = VOICE_PARAM_OSC_0_ENABLE + (paramID - SYNTH_PARAM_OSC_0_ENABLE);
break;
case SYNTH_PARAM_OSC_0_RESTART_ON_TRIGGER:
case SYNTH_PARAM_OSC_1_RESTART_ON_TRIGGER:
voice_param_type = VOICE_PARAM_OSC_0_RESTART_ON_TRIGGER + (paramID - SYNTH_PARAM_OSC_0_RESTART_ON_TRIGGER);
break;
case SYNTH_PARAM_OSC_0_LEVEL:
case SYNTH_PARAM_OSC_1_LEVEL:
voice_param_type = VOICE_PARAM_OSC_0_LEVEL + (paramID - SYNTH_PARAM_OSC_0_LEVEL);
break;
case SYNTH_PARAM_OSC_0_DUTYCYCLE:
case SYNTH_PARAM_OSC_1_DUTYCYCLE:
voice_param_type = VOICE_PARAM_OSC_0_DUTYCYCLE + (paramID - SYNTH_PARAM_OSC_0_DUTYCYCLE);
break;
case SYNTH_PARAM_OSC_0_DETUNE:
case SYNTH_PARAM_OSC_1_DETUNE:
voice_param_type = VOICE_PARAM_OSC_0_DETUNE + (paramID - SYNTH_PARAM_OSC_0_DETUNE);
break;
case SYNTH_PARAM_OSC_0_TRANSPOSE:
case SYNTH_PARAM_OSC_1_TRANSPOSE:
voice_param_type = VOICE_PARAM_OSC_0_TRANSPOSE + (paramID - SYNTH_PARAM_OSC_0_TRANSPOSE);
break;
case SYNTH_PARAM_OSC_0_PB_RANGE_MIN:
case SYNTH_PARAM_OSC_1_PB_RANGE_MIN:
paramInfoSetPMIN(&pb_range[(paramID - SYNTH_PARAM_OSC_0_PB_RANGE_MIN)], param);
handlePitchWheel(lastmidiChannel, lastPitchWheelValue);
break;
case SYNTH_PARAM_OSC_0_PB_RANGE_MAX:
case SYNTH_PARAM_OSC_1_PB_RANGE_MAX:
paramInfoSetPMAX(&pb_range[(paramID - SYNTH_PARAM_OSC_0_PB_RANGE_MAX)], param);
handlePitchWheel(lastmidiChannel, lastPitchWheelValue);
break;
case SYNTH_PARAM_OSC_0_WAVEFORM:
case SYNTH_PARAM_OSC_1_WAVEFORM:
voice_param_type = VOICE_PARAM_OSC_0_WAVEFORM + (paramID - SYNTH_PARAM_OSC_0_WAVEFORM);
break;
case SYNTH_PARAM_OSC_0_FM_AMT_0:
case SYNTH_PARAM_OSC_1_FM_AMT_0:
voice_param_type = VOICE_PARAM_OSC_0_FM_AMT_0 + (paramID - SYNTH_PARAM_OSC_0_FM_AMT_0);
break;
case SYNTH_PARAM_OSC_0_FM_AMT_1:
case SYNTH_PARAM_OSC_1_FM_AMT_1:
voice_param_type = VOICE_PARAM_OSC_0_FM_AMT_1 + (paramID - SYNTH_PARAM_OSC_0_FM_AMT_1);
break;
case SYNTH_PARAM_OSC_0_FM_SRC_0:
case SYNTH_PARAM_OSC_1_FM_SRC_0:
voice_param_type = VOICE_PARAM_OSC_0_FM_SRC_0 + (paramID - SYNTH_PARAM_OSC_0_FM_SRC_0);
break;
case SYNTH_PARAM_OSC_0_FM_SRC_1:
case SYNTH_PARAM_OSC_1_FM_SRC_1:
voice_param_type = VOICE_PARAM_OSC_0_FM_SRC_1 + (paramID - SYNTH_PARAM_OSC_0_FM_SRC_1);
break;
case SYNTH_PARAM_OSC_0_FM_SRC_OP:
case SYNTH_PARAM_OSC_1_FM_SRC_OP:
voice_param_type = VOICE_PARAM_OSC_0_FM_SRC_OP + (paramID - SYNTH_PARAM_OSC_0_FM_SRC_OP);
break;
case SYNTH_PARAM_OSC_0_AM_AMT_0:
case SYNTH_PARAM_OSC_1_AM_AMT_0:
voice_param_type = VOICE_PARAM_OSC_0_AM_AMT_0 + (paramID - SYNTH_PARAM_OSC_0_AM_AMT_0);
break;
case SYNTH_PARAM_OSC_0_AM_AMT_1:
case SYNTH_PARAM_OSC_1_AM_AMT_1:
voice_param_type = VOICE_PARAM_OSC_0_AM_AMT_1 + (paramID - SYNTH_PARAM_OSC_0_AM_AMT_1);
break;
case SYNTH_PARAM_OSC_0_AM_SRC_0:
case SYNTH_PARAM_OSC_1_AM_SRC_0:
voice_param_type = VOICE_PARAM_OSC_0_AM_SRC_0 + (paramID - SYNTH_PARAM_OSC_0_AM_SRC_0);
break;
case SYNTH_PARAM_OSC_0_AM_SRC_1:
case SYNTH_PARAM_OSC_1_AM_SRC_1:
voice_param_type = VOICE_PARAM_OSC_0_AM_SRC_1 + (paramID - SYNTH_PARAM_OSC_0_AM_SRC_1);
break;
case SYNTH_PARAM_OSC_0_AM_SRC_OP:
case SYNTH_PARAM_OSC_1_AM_SRC_OP:
voice_param_type = VOICE_PARAM_OSC_0_AM_SRC_OP + (paramID - SYNTH_PARAM_OSC_0_AM_SRC_OP);
break;
case SYNTH_PARAM_OSC_0_PWM_AMT_0:
case SYNTH_PARAM_OSC_1_PWM_AMT_0:
voice_param_type = VOICE_PARAM_OSC_0_PWM_AMT_0 + (paramID - SYNTH_PARAM_OSC_0_PWM_AMT_0);
break;
case SYNTH_PARAM_OSC_0_PWM_AMT_1:
case SYNTH_PARAM_OSC_1_PWM_AMT_1:
voice_param_type = VOICE_PARAM_OSC_0_PWM_AMT_1 + (paramID - SYNTH_PARAM_OSC_0_PWM_AMT_1);
break;
case SYNTH_PARAM_OSC_0_PWM_SRC_0:
case SYNTH_PARAM_OSC_1_PWM_SRC_0:
voice_param_type = VOICE_PARAM_OSC_0_PWM_SRC_0 + (paramID - SYNTH_PARAM_OSC_0_PWM_SRC_0);
break;
case SYNTH_PARAM_OSC_0_PWM_SRC_1:
case SYNTH_PARAM_OSC_1_PWM_SRC_1:
voice_param_type = VOICE_PARAM_OSC_0_PWM_SRC_1 + (paramID - SYNTH_PARAM_OSC_0_PWM_SRC_1);
break;
case SYNTH_PARAM_OSC_0_PWM_SRC_OP:
case SYNTH_PARAM_OSC_1_PWM_SRC_OP:
voice_param_type = VOICE_PARAM_OSC_0_PWM_SRC_OP + (paramID - SYNTH_PARAM_OSC_0_PWM_SRC_OP);
break;
case SYNTH_PARAM_ENV_0_A:
case SYNTH_PARAM_ENV_1_A:
case SYNTH_PARAM_ENV_2_A:
case SYNTH_PARAM_ENV_3_A:
voice_param_type = VOICE_PARAM_ENV_0_A + (paramID - SYNTH_PARAM_ENV_0_A);
break;
case SYNTH_PARAM_ENV_0_D:
case SYNTH_PARAM_ENV_1_D:
case SYNTH_PARAM_ENV_2_D:
case SYNTH_PARAM_ENV_3_D:
voice_param_type = VOICE_PARAM_ENV_0_D + (paramID - SYNTH_PARAM_ENV_0_D);
break;
case SYNTH_PARAM_ENV_0_S:
case SYNTH_PARAM_ENV_1_S:
case SYNTH_PARAM_ENV_2_S:
case SYNTH_PARAM_ENV_3_S:
voice_param_type = VOICE_PARAM_ENV_0_S + (paramID - SYNTH_PARAM_ENV_0_S);
break;
case SYNTH_PARAM_ENV_0_R:
case SYNTH_PARAM_ENV_1_R:
case SYNTH_PARAM_ENV_2_R:
case SYNTH_PARAM_ENV_3_R:
voice_param_type = VOICE_PARAM_ENV_0_R + (paramID - SYNTH_PARAM_ENV_0_R);
break;
case SYNTH_PARAM_VCA_AM_AMT_0:
voice_param_type = VOICE_PARAM_VCA_AM_AMT_0;
break;
case SYNTH_PARAM_VCA_AM_SRC_0:
voice_param_type = VOICE_PARAM_VCA_AM_SRC_0;
break;
case SYNTH_PARAM_VCA_PAN_AMT_0:
voice_param_type = VOICE_PARAM_VCA_PAN_AMT_0;
break;
case SYNTH_PARAM_VCA_PAN_SRC_0:
voice_param_type = VOICE_PARAM_VCA_PAN_SRC_0;
break;
case SYNTH_PARAM_VCA_ENV_AMT:
voice_param_type = VOICE_PARAM_VCA_ENV_GAIN;
break;
case SYNTH_PARAM_VCF_ENV_AMT:
voice_param_type = VOICE_PARAM_VCF_ENV_GAIN;
break;
case SYNTH_PARAM_VCF_F_AMT_0:
voice_param_type = VOICE_PARAM_VCF_F_AMT_0;
break;
case SYNTH_PARAM_VCF_F_AMT_1:
voice_param_type = VOICE_PARAM_VCF_F_AMT_1;
break;
case SYNTH_PARAM_VCF_F_SRC_0:
voice_param_type = VOICE_PARAM_VCF_F_SRC_0;
break;
case SYNTH_PARAM_VCF_F_SRC_1:
voice_param_type = VOICE_PARAM_VCF_F_SRC_1;
break;
case SYNTH_PARAM_VCF_F_SRC_OP:
voice_param_type = VOICE_PARAM_VCF_F_SRC_OP;
break;
case SYNTH_PARAM_VCF_Q_AMT_0:
voice_param_type = VOICE_PARAM_VCF_Q_AMT_0;
break;
case SYNTH_PARAM_VCF_Q_AMT_1:
voice_param_type = VOICE_PARAM_VCF_Q_AMT_1;
break;
case SYNTH_PARAM_VCF_Q_SRC_0:
voice_param_type = VOICE_PARAM_VCF_Q_SRC_0;
break;
case SYNTH_PARAM_VCF_Q_SRC_1:
voice_param_type = VOICE_PARAM_VCF_Q_SRC_1;
break;
case SYNTH_PARAM_VCF_Q_SRC_OP:
voice_param_type = VOICE_PARAM_VCF_Q_SRC_OP;
break;
case SYNTH_PARAM_LFO_0_SPEED:
case SYNTH_PARAM_LFO_1_SPEED:
case SYNTH_PARAM_LFO_2_SPEED:
case SYNTH_PARAM_LFO_3_SPEED:
voice_param_type = VOICE_PARAM_LFO_0_SPEED + (paramID - SYNTH_PARAM_LFO_0_SPEED);
break;
case SYNTH_PARAM_LFO_0_SMOOTH:
case SYNTH_PARAM_LFO_1_SMOOTH:
case SYNTH_PARAM_LFO_2_SMOOTH:
case SYNTH_PARAM_LFO_3_SMOOTH:
voice_param_type = VOICE_PARAM_LFO_0_SMOOTH + (paramID - SYNTH_PARAM_LFO_0_SMOOTH);
break;
case SYNTH_PARAM_LFO_0_DELAY:
case SYNTH_PARAM_LFO_1_DELAY:
case SYNTH_PARAM_LFO_2_DELAY:
case SYNTH_PARAM_LFO_3_DELAY:
voice_param_type = VOICE_PARAM_LFO_0_DELAY + (paramID - SYNTH_PARAM_LFO_0_DELAY);
break;
case SYNTH_PARAM_LFO_0_ATTACK:
case SYNTH_PARAM_LFO_1_ATTACK:
case SYNTH_PARAM_LFO_2_ATTACK:
case SYNTH_PARAM_LFO_3_ATTACK:
voice_param_type = VOICE_PARAM_LFO_0_ATTACK + (paramID - SYNTH_PARAM_LFO_0_ATTACK);
break;
case SYNTH_PARAM_LFO_0_SHAPE:
case SYNTH_PARAM_LFO_1_SHAPE:
case SYNTH_PARAM_LFO_2_SHAPE:
case SYNTH_PARAM_LFO_3_SHAPE:
voice_param_type = VOICE_PARAM_LFO_0_SHAPE + (paramID - SYNTH_PARAM_LFO_0_SHAPE);
break;
case SYNTH_PARAM_LFO_0_MODE:
case SYNTH_PARAM_LFO_1_MODE:
case SYNTH_PARAM_LFO_2_MODE:
case SYNTH_PARAM_LFO_3_MODE:
voice_param_type = VOICE_PARAM_LFO_0_MODE + (paramID - SYNTH_PARAM_LFO_0_MODE);
break;
case SYNTH_PARAM_LFO_0_SYNC:
case SYNTH_PARAM_LFO_1_SYNC:
case SYNTH_PARAM_LFO_2_SYNC:
case SYNTH_PARAM_LFO_3_SYNC:
voice_param_type = VOICE_PARAM_LFO_0_SYNC + (paramID - SYNTH_PARAM_LFO_0_SYNC);
break;
case SYNTH_PARAM_LFO_0_SYMMETRY:
case SYNTH_PARAM_LFO_1_SYMMETRY:
case SYNTH_PARAM_LFO_2_SYMMETRY:
case SYNTH_PARAM_LFO_3_SYMMETRY:
voice_param_type = VOICE_PARAM_LFO_0_SYMMETRY + (paramID - SYNTH_PARAM_LFO_0_SYMMETRY);
break;
case SYNTH_PARAM_LFO_0_MIDISYNC_MODE:
case SYNTH_PARAM_LFO_1_MIDISYNC_MODE:
case SYNTH_PARAM_LFO_2_MIDISYNC_MODE:
case SYNTH_PARAM_LFO_3_MIDISYNC_MODE:
voice_param_type = VOICE_PARAM_LFO_0_MIDISYNC_MODE + (paramID - SYNTH_PARAM_LFO_0_MIDISYNC_MODE);
break;
case SYNTH_PARAM_LFO_0_MIDISYNC_BEATDIV:
case SYNTH_PARAM_LFO_1_MIDISYNC_BEATDIV:
case SYNTH_PARAM_LFO_2_MIDISYNC_BEATDIV:
case SYNTH_PARAM_LFO_3_MIDISYNC_BEATDIV:
voice_param_type = VOICE_PARAM_LFO_0_MIDISYNC_BEATDIV + (paramID - SYNTH_PARAM_LFO_0_MIDISYNC_BEATDIV);
break;
default:
break;
}
if (voice_param_type >= 0)
{
voice_min = voice;
voice_max = voice;
if (voice < 0)
{
voice_min = 0;
voice_max = GET_NUM_VOICES-1;
}
if (isHumanize)
{
synth_float_t slider;
for (i=voice_min; i <= voice_max; i++)
{
slider = toSlider(pParamInfo, params[paramID]) + ppHumanizedSliders[paramID][i];
param = toParam(pParamInfo, slider) + controls[paramID];
for (j=0; j < SYNTH_PER_VOICE_CONTROL_SIZE; j++)
param += pPer_voice_controls[i].ctrl[j][paramID];
param = clampParam(pParamInfo, param);
((JaySynthVoice*)getVoice(i))->setParameter(voice_param_type, param);
}
}
else
{
for (i=voice_min; i <= voice_max; i++)
{
param = params[paramID] + controls[paramID];
for (j=0; j < SYNTH_PER_VOICE_CONTROL_SIZE; j++)
param += pPer_voice_controls[i].ctrl[j][paramID];
param = clampParam(pParamInfo, param);
((JaySynthVoice*)getVoice(i))->setParameter(voice_param_type, param);
}
}
}
}
//==============================================================================
// Midi-Event stuff
//==============================================================================
void JaySynth::handlePitchWheel (const int midiChannel, const int wheelValue)
{
int i;
synth_float_t scale, value;
lastPitchWheelValue = wheelValue;
lastmidiChannel = midiChannel;
value = (synth_float_t)wheelValue/16384; // PB-Range 0 to 1, center at 0.5
scale = pow(2, toParam(&pb_range[0], value)/12);
for (i=0; i < GET_NUM_VOICES; i++)
((JaySynthVoice*)getVoice(i))->setParameter(VOICE_PARAM_OSC_0_SCALE, scale);
scale = pow(2, toParam(&pb_range[1], value)/12);
for (i=0; i < GET_NUM_VOICES; i++)
((JaySynthVoice*)getVoice(i))->setParameter(VOICE_PARAM_OSC_1_SCALE, scale);
}
void JaySynth::handleController (const int midiChannel,
const int controllerNumber,
const int controllerValue)
{
midiCC_info.channel = midiChannel;
midiCC_info.ID = controllerNumber;
midiCC_info.value = (synth_float_t)controllerValue/127;
last_midiCC_info[controllerNumber] = midiCC_info;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICC, &midiCC_info);
switch (controllerNumber)
{
case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64); break;
case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64); break;
case 0x43: handleSoftPedal (midiChannel, controllerValue >= 64); break;
default: break;
}
const ScopedLock sl (lock);
for (int i = 0; i < GET_NUM_VOICES; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->controllerMoved (controllerNumber, controllerValue);
}
}
void JaySynth::handleSustainPedal (int midiChannel, bool isDown)
{
jassert (midiChannel > 0 && midiChannel <= 16);
const ScopedLock sl (lock);
if (isDown)
{
sustainPedalsDown.setBit (midiChannel);
}
else
{
for (int i = 0; i < GET_NUM_VOICES; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
Voicestop (voice, true);
}
sustainPedalsDown.clearBit (midiChannel);
}
}
void JaySynth::handleSostenutoPedal (int midiChannel, bool isDown)
{
jassert (midiChannel > 0 && midiChannel <= 16);
const ScopedLock sl (lock);
for (int i = 0; i < GET_NUM_VOICES; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel))
{
if (isDown)
voice->sostenutoPedalDown = true;
else if (voice->sostenutoPedalDown)
Voicestop (voice, true);
}
}
}
void JaySynth::handleSoftPedal (int midiChannel, bool /*isDown*/)
{
(void) midiChannel;
jassert (midiChannel > 0 && midiChannel <= 16);
}
//==============================================================================
// Audio data rendering stuff
//==============================================================================
void JaySynth::renderNextBlock (AudioSampleBuffer& outputBuffer,
const MidiBuffer& midiData,
int startSample,
int numSamples)
{
int i;
int numVoicesPlaying;
float *buf1, *buf2;
// must set the sample rate before using this!
float sr = Synthesiser::getSampleRate();
jassert (sr != 0);
const ScopedLock sl (lock);
MidiBuffer::Iterator midiIterator (midiData);
midiIterator.setNextSamplePosition (startSample);
MidiMessage m (0xf4, 0.0);
while (numSamples > 0)
{
int midiEventPos;
const bool useEvent = midiIterator.getNextEvent (m, midiEventPos)
&& midiEventPos < startSample + numSamples;
const int numThisTime = useEvent ? midiEventPos - startSample
: numSamples;
if (numThisTime > 0)
{
// Process global voice data
buf1 = outputBuffer.getWritePointer (0, startSample);
buf2 = outputBuffer.getWritePointer (1, startSample);
VoiceProcessDataV_Common(&m_pVoices[0], buf1, buf2, numThisTime);
// Start audio threads
for (i=0; i < m_num_audiothreads; i++)
{
m_ppAudioThread[i]->go(numThisTime);
}
// Wait for audio threads finishing and add buffer
for (i=0; i < m_num_audiothreads; i++)
{
m_ppEventAudioThreadRdy[i]->wait(-1);
outputBuffer.addFrom(0, startSample, m_ppAudioThread[i]->getBuffer(), 0, 0, numThisTime, 1.0);
outputBuffer.addFrom(1, startSample, m_ppAudioThread[i]->getBuffer(), 1, 0, numThisTime, 1.0);
}
}
// Clear note if voice is idle
for (int i = 0; i < max_num_voices; i++)
{
if (m_pVoices[i].state == note_state_idle)
{
if (voices.getUnchecked(i)->currentlyPlayingNote >= 0)
{
voices.getUnchecked(i)->clearCurrentNote();
numVoicesPlaying = getNumVoicesPlaying(sounds.getUnchecked(0));
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_NUM_VOICES_PLAYING, &numVoicesPlaying);
}
}
}
if (useEvent)
{
handleMidiEvent (m);
}
startSample += numThisTime;
numSamples -= numThisTime;
}
}
void JaySynth::updateMidiTiming(const MidiMessage& m)
{
// Quarter clock generation
int nom;
int denom;
m.getTimeSignatureInfo(nom, denom);
if (denom > 0)
{
m_numMidiClocksPerBeat = m_numMidiclocksPerFourQuarterBeats/denom;
m_numMidiClocksPerBar = nom*m_numMidiClocksPerBeat;
}
}
void JaySynth::handleMidiEvent (const MidiMessage& m)
{
updateMidiTiming(m);
if (m.isNoteOn())
{
noteOn (m.getChannel(),
m.getNoteNumber(),
m.getFloatVelocity());
}
if (m.isNoteOff())
{
noteOff (m.getChannel(),
m.getNoteNumber(),
true);
}
if (m.isAllNotesOff() || m.isAllSoundOff())
{
allNotesOff (m.getChannel(), true);
}
if (m.isPitchWheel())
{
const int channel = m.getChannel();
const int wheelPos = m.getPitchWheelValue();
lastPitchWheelValues [channel - 1] = wheelPos;
handlePitchWheel (channel, wheelPos);
}
if (m.isController())
{
handleController (m.getChannel(),
m.getControllerNumber(),
m.getControllerValue());
}
if (m.isMidiMachineControlMessage())
{
SynthDebug("MidiMachineControlMessage(%08X)\n", m.getMidiMachineControlCommand());
}
if (m.isTempoMetaEvent())
{
SynthDebug("TempoMetaEvent\n");
}
if (m.isTimeSignatureMetaEvent())
{
int nom;
int denom;
m.getTimeSignatureInfo(nom, denom);
SynthDebug("isTimeSignatureMetaEvent\n");
SynthDebug("Time signature %d/%d\n", nom, denom);
}
if (m.isMidiStart())
{
SynthDebug("MidiStart\n");
m_isMidiClockStarted = true;
}
if (m.isMidiContinue())
{
SynthDebug("MidiContinue\n");
m_isMidiClockStarted = true;
}
if (m.isMidiStop())
{
SynthDebug("MidiStop\n");
m_isMidiClockStarted = false;
}
if (m.isSongPositionPointer())
{
SynthDebug("SongPositionPointer\n");
m_clock_cnt_bar = (6 * m.getSongPositionPointerMidiBeat()) % m_numMidiClocksPerBar;
SynthDebug("getSongPositionPointerMidiBeat(): %u -> %u clocks\n", m.getSongPositionPointerMidiBeat(), m_clock_cnt_bar);
m_lastTime_ms = 0;
}
if (m.isQuarterFrame())
{
SynthDebug("QuarterFrame\n");
}
if (m.isFullFrame())
{
SynthDebug("FullFrame\n");
}
if (m.isTempoMetaEvent())
{
SynthDebug("TempoMetaEvent = %f\n", m.getTempoSecondsPerQuarterNote());
SynthDebug("TimeStamp = %f\n", m.getTimeStamp());
}
if (m.isMidiClock())
{
const double alpha_1 = 2.0/m_numMidiclocksPerQuarterNote;
const double currTime_ms = juce::Time::getMillisecondCounterHiRes();
// BPM Estimation
double deltaTime_ms = currTime_ms - m_lastTime_ms;
if (m_lastTime_ms > 0.0)
{
m_estimatedTime_ms = (1.0-alpha_1)*m_estimatedTime_ms + alpha_1*deltaTime_ms;
}
m_lastTime_ms = currTime_ms;
// Quarter clock generation
m_clock_cnt_bar = m_clock_cnt_bar % m_numMidiClocksPerBar;
if (m_isMidiClockStarted)
{
#if WITH_DEV_SYNCED_LFO
voiceSetMidiBeat(m_clock_cnt_bar);
#endif
if (m_clock_cnt_bar % m_numMidiClocksPerBeat == 0)
{
// Send quarter pulse with current BPM estimation
midi_quarter_clock_info_t info;
info.bpm = (uint32_t)(m_numMidiclocksPerQuarterNote*m_estimatedTime_ms + 0.5);
info.type = 1;
if (m_clock_cnt_bar == 0)
{
info.type = 2;
}
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICLOCK, &info);
}
}
m_clock_cnt_bar++;
}
}
void JaySynth::voiceSetMidiBeat(int barBeatCount)
{
lfo_t *pLfo = &m_pVoices[0].pCom->glfo[0];
synth_float_t phase = Sync_mod((synth_float_t)barBeatCount/m_numMidiClocksPerBar);
LFO_sync(pLfo, phase);
for (int i=0; i < max_num_voices; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
voice->setMidiBeat(barBeatCount);
}
}
//==============================================================================
// Voice trigger stuff
//==============================================================================
void JaySynth::Voicestart (JaySynthVoice* const voice,
SynthesiserSound* const sound,
const int midiChannel,
const int midiNoteNumber,
const float velocity, bool doTrigger)
{
int numVoicesPlaying;
if (voice != nullptr && sound != nullptr)
{
// if (voice->getCurrentlyPlayingSound() != nullptr)
// if (!isMonophon)
// voice->stopNote (false);
if (pMidCC_editBuffer)
{
for (int paramID=0; paramID < SYNTH_NUM_PARAMS; paramID++)
{
if (pMidCC_editBuffer->isAssignedVelKeyControl(paramID))
setPerVoiceControl(voice->m_pVoice->id, SYNTH_PER_VOICE_CONTROL_VELKEY, paramID, pMidCC_editBuffer->getVelKeyControl(paramID, velocity, midiNoteNumber));
}
}
pCurrNoteInfos[voice->m_pVoice->id].note = midiNoteNumber;
pCurrNoteInfos[voice->m_pVoice->id].velocity = velocity;
VoiceParam2Set(voice->m_pVoice, VOICE_PARAM_KEY, midiNoteNumber);
// if (!m_isMonophon || (m_isMonophon && doTrigger && (m_num_keys_pressed_last == 0)) || (m_isMonophon && doTrigger && m_doMonophonRetrigger && (m_highest_key_last < midiNoteNumber)))
if (!m_isMonophon || (m_isMonophon && doTrigger && (m_num_keys_pressed_last == 0)) || (m_isMonophon && m_doMonophonRetrigger && (m_latest_key != m_latest_key_last)))
{
voice->startNote (midiNoteNumber, velocity, sound,
lastPitchWheelValues [midiChannel - 1]);
}
voice->currentlyPlayingNote = midiNoteNumber;
// voice->noteOnTime = ++lastNoteOnCounter;
voice->currentlyPlayingSound = sound;
voice->keyIsDown = true;
voice->sostenutoPedalDown = false;
numVoicesPlaying = getNumVoicesPlaying(sounds.getUnchecked(0));
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_NUM_VOICES_PLAYING, &numVoicesPlaying);
}
}
void JaySynth::Voicestop (JaySynthVoice* voice, const bool allowTailOff)
{
jassert (voice != nullptr);
voice->stopNote (allowTailOff);
// the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
}
void JaySynth::allNotesOff (const int midiChannel, const bool allowTailOff)
{
int i;
int numVoicesPlaying;
const ScopedLock sl (lock);
clearKeysPressed();
for (i=0; i < max_num_voices; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->stopNote (allowTailOff);
}
sustainPedalsDown.clear();
next_possible_voice = 0;
oldest_voice = 0;
}
void JaySynth::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
{
int i, j, latest_note;
float latest_vel;
const ScopedLock sl (lock);
last_midi_note_info.note = midiNoteNumber;
last_midi_note_info.velocity = velocity;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_NOTE_PRESSED, &last_midi_note_info);
setKeyPressed(midiNoteNumber, velocity);
if (m_isMonophon)
{
latest_note = m_latest_key;
latest_vel = m_monoMGR.getVel(m_latest_key);
for (i=0; i < sounds.size(); i++)
{
SynthesiserSound* const sound = sounds.getUnchecked(i);
if (m_isUnison)
{
for (j=0; j < unison_num_voices; j++)
{
Voicestart (voices.getUnchecked (j), sound, midiChannel, latest_note, latest_vel, true);
}
}
else
{
Voicestart (voices.getUnchecked (0), sound, midiChannel, latest_note, latest_vel, true);
}
}
}
else
{
for (int i = sounds.size(); --i >= 0;)
{
SynthesiserSound* const sound = sounds.getUnchecked(i);
if (sound->appliesToNote (midiNoteNumber)
&& sound->appliesToChannel (midiChannel))
{
// If hitting a note that's still ringing, stop it first (it could be
// still playing because of the sustain or sostenuto pedal).
// for (j=0; j < max_num_voices; j++)
// {
// JaySynthVoice* const voice = voices.getUnchecked (j);
//
// if (!m_isMonophon)
// {
// if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel))
// Voicestop (voice, true);
// }
// }
if (m_isUnison)
{
for (j=0; j < unison_num_voices; j++)
{
Voicestart (getFreeVoice (sound, isNoteStealingEnabled()), sound, midiChannel, midiNoteNumber, velocity, true);
}
}
else
{
Voicestart (getFreeVoice (sound, isNoteStealingEnabled()), sound, midiChannel, midiNoteNumber, velocity, true);
}
}
}
}
}
void JaySynth::noteOff (const int midiChannel,
const int midiNoteNumber,
const bool allowTailOff)
{
int i, j, latest_note;
float latest_vel;
const ScopedLock sl (lock);
midi_note_info_t midi_note_info;
midi_note_info.note = midiNoteNumber;
midi_note_info.velocity = 0;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_NOTE_RELEASED, &midi_note_info);
setKeyPressed(midiNoteNumber, 0);
if (m_isMonophon)
{
latest_note = m_latest_key;
latest_vel = m_monoMGR.getVel(m_latest_key);
if (latest_note >= 0)
{
for (i = sounds.size(); --i >= 0;)
{
SynthesiserSound* const sound = sounds.getUnchecked(i);
if (m_isUnison)
{
for (j=0; j < unison_num_voices; j++)
{
Voicestart (voices.getUnchecked (j), sound, midiChannel, latest_note, latest_vel, false);
}
}
else
{
Voicestart (voices.getUnchecked (0), sound, midiChannel, latest_note, latest_vel, false);
}
}
}
else
{
for (i=0; i < max_num_voices; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
voice->keyIsDown = false;
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
{
Voicestop (voice, allowTailOff);
}
}
}
}
else
{
for (i=0; i < max_num_voices; i++)
{
JaySynthVoice* const voice = voices.getUnchecked (i);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
{
SynthesiserSound* const sound = voice->getCurrentlyPlayingSound();
if (sound != nullptr
&& sound->appliesToNote (midiNoteNumber)
&& sound->appliesToChannel (midiChannel))
{
voice->keyIsDown = false;
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
Voicestop (voice, allowTailOff);
}
}
}
}
}
//==============================================================================
// Voice management stuff
//==============================================================================
void JaySynth::unisonoModeChanged(void)
{
int key;
float vel;
// if ((m_doMonophon ^ m_isMonophon) || (m_doUnison ^ m_isUnison))
{
m_isMonophon = m_doMonophon;
m_isUnison = m_doUnison;
allNotesOff(0, false);
if (m_isMonophon)
{
key = m_latest_key;
vel = m_monoMGR.getVel(m_latest_key);
}
if (m_isUnison)
{
m_unisonGain = 5.0/(4 + unison_num_voices);
}
else
{
m_unisonGain = 1;
}
}
}
void JaySynth::advanceNextPossibleVoice(void)
{
next_possible_voice++;
if (next_possible_voice >= total_num_voices)
next_possible_voice = 0;
}
int JaySynth::getNextPossibleVoice(void)
{
return next_possible_voice;
}
void JaySynth::advanceOldestVoice(void)
{
oldest_voice++;
if (oldest_voice >= total_num_voices)
oldest_voice = 0;
}
int JaySynth::getOldestVoice(void)
{
return oldest_voice;
}
int JaySynth::getNumVoicesPlaying (SynthesiserSound* soundToPlay)
{
int i, numVoicesFound;
const ScopedLock sl (lock);
numVoicesFound = 0;
for (i = 0; i < max_num_voices; i++)
{
if (voices.getUnchecked (i)->getCurrentlyPlayingNote() >= 0
&& voices.getUnchecked (i)->canPlaySound (soundToPlay))
{
numVoicesFound++;
}
}
return numVoicesFound;
}
JaySynthVoice* JaySynth::getFreeVoice (SynthesiserSound* soundToPlay,
const bool stealIfNoneAvailable)
{
int i, freeVoiceFound;
const ScopedLock sl (lock);
freeVoiceFound = -1;
for (i = 0; i < total_num_voices; i++)
{
if (voices.getUnchecked (getNextPossibleVoice())->getCurrentlyPlayingNote() < 0
&& voices.getUnchecked (getNextPossibleVoice())->canPlaySound (soundToPlay))
{
freeVoiceFound = getNextPossibleVoice();
advanceNextPossibleVoice();
break;
}
advanceNextPossibleVoice();
}
if (freeVoiceFound >= 0)
{
return voices.getUnchecked (freeVoiceFound);
}
if (stealIfNoneAvailable)
{
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
JaySynthVoice* oldest = voices.getUnchecked (getOldestVoice());
for (i = 0; i < total_num_voices; i++)
{
advanceOldestVoice();
if (voices.getUnchecked (getOldestVoice())->getCurrentlyPlayingNote() >= 0)
break;
}
jassert (oldest != nullptr);
return oldest;
}
return nullptr;
}
void JaySynth::clearKeysPressed(void)
{
m_monoMGR.init();
m_num_keys_pressed = -1;
m_latest_key = -1;
m_highest_key = -1;
m_num_keys_pressed_last = -1;
m_latest_key_last = -1;
m_highest_key_last = -1;
}
void JaySynth::setKeyPressed(int key, float vel)
{
m_num_keys_pressed_last = m_monoMGR.getNumNotes();
m_latest_key_last = m_monoMGR.getLatestNote();
m_highest_key_last = m_monoMGR.getHighestNote();
m_monoMGR.add(key, vel);
m_num_keys_pressed = m_monoMGR.getNumNotes();
m_latest_key = m_monoMGR.getLatestNote();
m_highest_key = m_monoMGR.getHighestNote();
}
void JaySynthThread::run(void)
{
float *buf1, *buf2;
SynthDebug("Thread entry\n");
while(!threadShouldExit())
{
if (wait(1000))
{
m_buffer->clear (0, 0, m_sample_len);
m_buffer->clear (1, 0, m_sample_len);
buf1 = m_buffer->getWritePointer (0, 0);
buf2 = m_buffer->getWritePointer (1, 0);
for (int i = m_voice_offset; i < m_num_voices; i += m_voice_step)
{
if (m_pVoices[i].state == note_state_idle)
continue;
VoiceProcessDataV(&m_pVoices[i], buf1, buf2, m_sample_len);
}
m_pEventRdy->signal();
}
}
SynthDebug("Thread exit\n");
}
JaySynthThread::JaySynthThread(WaitableEvent *pEventRdy, voice_t *pVoices, int num_voices, int offset, int step)
: Thread(L"JaySynthAudioThread_" + String(offset))
{
m_pEventRdy = pEventRdy;
m_num_voices = num_voices;
m_pVoices = pVoices;
m_voice_offset = offset;
m_voice_step = step;
m_buffer = new AudioSampleBuffer(2, SYNTH_MAX_BUFSIZE);
m_sample_len = SYNTH_MAX_BUFSIZE;
}
void JaySynthThread::go(int len)
{
if (len <= SYNTH_MAX_BUFSIZE)
{
m_sample_len = len;
notify();
}
}
AudioSampleBuffer& JaySynthThread::getBuffer(void)
{
return *m_buffer;
}
JaySynthThread::~JaySynthThread()
{
// delete (m_buffer);
}
//==============================================================================