/* ============================================================================== This file was generated by user! ============================================================================== */ #include #include #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); ScopedPointerpIn = 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_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, ¶mID_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, ¶mID_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); } 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()) { // Quarter clock generation m_clock_cnt_bar = m_clock_cnt_bar % m_numMidiClocksPerBar; if (m_isMidiClockStarted) { #if WITH_DEV_SYNCED_LFO // Sync LFO and BPM Estimation synth_float_t bpm = 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)(bpm + 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++; } } synth_float_t JaySynth::voiceSetMidiBeat(int barBeatCount) { synth_float_t bpm = 0; for (int i=0; i < VOICE_NUM_LFO; i++) { lfo_t *pLfo = &m_pVoices[0].pCom->glfo[i]; synth_float_t phase = Sync_mod((synth_float_t)barBeatCount/m_numMidiClocksPerBar); bpm += LFO_sync(pLfo, phase)/VOICE_NUM_LFO; } for (int i=0; i < max_num_voices; i++) { JaySynthVoice* const voice = voices.getUnchecked (i); voice->setMidiBeat(barBeatCount); } return bpm; } //============================================================================== // 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); } //==============================================================================