zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit abddd9be8776ba27b13ce11175ba1663a8e0a48b
parent b8ce98deefdaf138a930789a2017b72d49fb2e83
Author: friedolino78 <34608315+friedolino78@users.noreply.github.com>
Date:   Thu, 23 Apr 2020 12:42:35 +0200

fix of this file that was merged in by mistake
Diffstat:
Dsrc/Synth/ADnote.cpp.orig | 2065-------------------------------------------------------------------------------
1 file changed, 0 insertions(+), 2065 deletions(-)

diff --git a/src/Synth/ADnote.cpp.orig b/src/Synth/ADnote.cpp.orig @@ -1,2065 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - ADnote.cpp - The "additive" synthesizer - Copyright (C) 2002-2005 Nasca Octavian Paul - Author: Nasca Octavian Paul - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - -#include <cmath> -#include <cstdlib> -#include <cstdio> -#include <cstring> -#include <cassert> -#include <stdint.h> - -#include "../globals.h" -#include "../Misc/Util.h" -#include "../Misc/Allocator.h" -#include "../Params/ADnoteParameters.h" -#include "../Containers/ScratchString.h" -#include "../Containers/NotePool.h" -#include "ModFilter.h" -#include "OscilGen.h" -#include "ADnote.h" - -#define LENGTHOF(x) ((int)(sizeof(x)/sizeof(x[0]))) - -namespace zyn { -ADnote::ADnote(ADnoteParameters *pars_, const SynthParams &spars, - WatchManager *wm, const char *prefix) - :SynthNote(spars), watch_be4_add(wm, prefix, "noteout/be4_mix"), watch_after_add(wm,prefix,"noteout/after_mix"), - watch_punch(wm, prefix, "noteout/punch"), watch_legato(wm, prefix, "noteout/legato"), pars(*pars_) -{ - memory.beginTransaction(); - tmpwavel = memory.valloc<float>(synth.buffersize); - tmpwaver = memory.valloc<float>(synth.buffersize); - bypassl = memory.valloc<float>(synth.buffersize); - bypassr = memory.valloc<float>(synth.buffersize); - - ADnoteParameters &pars = *pars_; - portamento = spars.portamento; - note_log2_freq = spars.note_log2_freq; - NoteEnabled = ON; - velocity = spars.velocity; - initial_seed = spars.seed; - current_prng_state = spars.seed; - stereo = pars.GlobalPar.PStereo; - - NoteGlobalPar.Detune = getdetune(pars.GlobalPar.PDetuneType, - pars.GlobalPar.PCoarseDetune, - pars.GlobalPar.PDetune); - bandwidthDetuneMultiplier = pars.getBandwidthDetuneMultiplier(); - - if(pars.GlobalPar.PPanning == 0) - NoteGlobalPar.Panning = getRandomFloat(); - else - NoteGlobalPar.Panning = pars.GlobalPar.PPanning / 128.0f; - - NoteGlobalPar.Fadein_adjustment = - pars.GlobalPar.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE; - NoteGlobalPar.Fadein_adjustment *= NoteGlobalPar.Fadein_adjustment; - if(pars.GlobalPar.PPunchStrength != 0) { - NoteGlobalPar.Punch.Enabled = 1; - NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f - NoteGlobalPar.Punch.initialvalue = - ((powf(10, 1.5f * pars.GlobalPar.PPunchStrength / 127.0f) - 1.0f) - * VelF(velocity, - pars.GlobalPar.PPunchVelocitySensing)); - float time = - powf(10, 3.0f * pars.GlobalPar.PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms - float stretch = powf(440.0f / powf(2.0f, spars.note_log2_freq), - pars.GlobalPar.PPunchStretch / 64.0f); - NoteGlobalPar.Punch.dt = 1.0f / (time * synth.samplerate_f * stretch); - } - else - NoteGlobalPar.Punch.Enabled = 0; - - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) - setupVoice(nvoice); - - max_unison = 1; - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) - if(NoteVoicePar[nvoice].unison_size > max_unison) - max_unison = NoteVoicePar[nvoice].unison_size; - - - tmpwave_unison = memory.valloc<float*>(max_unison); - for(int k = 0; k < max_unison; ++k) { - tmpwave_unison[k] = memory.valloc<float>(synth.buffersize); - memset(tmpwave_unison[k], 0, synth.bufferbytes); - } - - initparameters(wm, prefix); - memory.endTransaction(); -} - -void ADnote::setupVoice(int nvoice) -{ - auto &param = pars.VoicePar[nvoice]; - auto &voice = NoteVoicePar[nvoice]; - - - for (int i = 0; i < 14; i++) - voice.pinking[i] = 0.0; - - param.OscilSmp->newrandseed(prng()); - voice.OscilSmp = NULL; - voice.FMSmp = NULL; - voice.VoiceOut = NULL; - - voice.FMVoice = -1; - voice.unison_size = 1; - - if(!pars.VoicePar[nvoice].Enabled) { - voice.Enabled = OFF; - return; //the voice is disabled - } - NoteVoicePar[nvoice].AAEnabled = - pars.VoicePar[nvoice].PAAEnabled; - - const int BendAdj = pars.VoicePar[nvoice].PBendAdjust - 64; - if (BendAdj % 24 == 0) - voice.BendAdjust = BendAdj / 24; - else - voice.BendAdjust = BendAdj / 24.0f; - - const float offset_val = (param.POffsetHz - 64)/64.0f; - voice.OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val))); - - voice.unison_stereo_spread = - pars.VoicePar[nvoice].Unison_stereo_spread / 127.0f; - - int unison = setupVoiceUnison(nvoice); - - - voice.oscfreqhi = memory.valloc<int>(unison); - voice.oscfreqlo = memory.valloc<float>(unison); - - voice.oscfreqhiFM = memory.valloc<unsigned int>(unison); - voice.oscfreqloFM = memory.valloc<float>(unison); - voice.oscposhi = memory.valloc<int>(unison); - voice.oscposlo = memory.valloc<float>(unison); - voice.oscposhiFM = memory.valloc<unsigned int>(unison); - voice.oscposloFM = memory.valloc<float>(unison); - - voice.Enabled = ON; - voice.fixedfreq = pars.VoicePar[nvoice].Pfixedfreq; - voice.fixedfreqET = pars.VoicePar[nvoice].PfixedfreqET; - - setupVoiceDetune(nvoice); - - for(int k = 0; k < unison; ++k) { - voice.oscposhi[k] = 0; - voice.oscposlo[k] = 0.0f; - voice.oscposhiFM[k] = 0; - voice.oscposloFM[k] = 0.0f; - } - - //the extra points contains the first point - voice.OscilSmp = - memory.valloc<float>(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES); - - //Get the voice's oscil or external's voice oscil - int vc = nvoice; - if(pars.VoicePar[nvoice].Pextoscil != -1) - vc = pars.VoicePar[nvoice].Pextoscil; - if(!pars.GlobalPar.Hrandgrouping) - pars.VoicePar[vc].OscilSmp->newrandseed(prng()); - int oscposhi_start = - pars.VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp, - getvoicebasefreq(nvoice), - pars.VoicePar[nvoice].Presonance); - - // This code was planned for biasing the carrier in MOD_RING - // but that's on hold for the moment. Disabled 'cos small - // machines run this stuff too. - // - // //Find range of generated wave - // float min = NoteVoicePar[nvoice].OscilSmp[0]; - // float max = min; - // float *smpls = &(NoteVoicePar[nvoice].OscilSmp[1]); - // for (int i = synth.oscilsize-1; i--; smpls++) - // if (*smpls > max) - // max = *smpls; - // else if (*smpls < min) - // min = *smpls; - // NoteVoicePar[nvoice].OscilSmpMin = min; - // NoteVoicePar[nvoice].OscilSmpMax = max; - - //I store the first elements to the last position for speedups - for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) - voice.OscilSmp[synth.oscilsize + i] = voice.OscilSmp[i]; - - voice.phase_offset = (int)((pars.VoicePar[nvoice].Poscilphase - - 64.0f) / 128.0f * synth.oscilsize + synth.oscilsize * 4); - oscposhi_start += NoteVoicePar[nvoice].phase_offset; - - int kth_start = oscposhi_start; - for(int k = 0; k < unison; ++k) { - voice.oscposhi[k] = kth_start % synth.oscilsize; - //put random starting point for other subvoices - kth_start = oscposhi_start + - (int)(RND * pars.VoicePar[nvoice].Unison_phase_randomness / - 127.0f * (synth.oscilsize - 1)); - } - - voice.FreqLfo = NULL; - voice.FreqEnvelope = NULL; - - voice.AmpLfo = NULL; - voice.AmpEnvelope = NULL; - - voice.Filter = NULL; - voice.FilterEnvelope = NULL; - voice.FilterLfo = NULL; - - voice.filterbypass = param.Pfilterbypass; - - setupVoiceMod(nvoice); - - voice.FMVoice = param.PFMVoice; - voice.FMFreqEnvelope = NULL; - voice.FMAmpEnvelope = NULL; - - voice.FMoldsmp = memory.valloc<float>(unison); - for(int k = 0; k < unison; ++k) - voice.FMoldsmp[k] = 0.0f; //this is for FM (integration) - - voice.firsttick = 1; - voice.DelayTicks = - (int)((expf(param.PDelay / 127.0f * logf(50.0f)) - - 1.0f) / synth.buffersize_f / 10.0f * synth.samplerate_f); -} - -int ADnote::setupVoiceUnison(int nvoice) -{ - auto &voice = NoteVoicePar[nvoice]; - - int unison = pars.VoicePar[nvoice].Unison_size; - if(unison < 1) - unison = 1; - - bool is_pwm = pars.VoicePar[nvoice].PFMEnabled == FMTYPE::PW_MOD; - - if (pars.VoicePar[nvoice].Type != 0) { - // Since noise unison of greater than two is touch goofy... - if (unison > 2) - unison = 2; - } else if (is_pwm) { - /* Pulse width mod uses pairs of subvoices. */ - unison *= 2; - // This many is likely to sound like noise anyhow. - if (unison > 64) - unison = 64; - } - - //compute unison - voice.unison_size = unison; - - voice.unison_base_freq_rap = memory.valloc<float>(unison); - voice.unison_freq_rap = memory.valloc<float>(unison); - voice.unison_invert_phase = memory.valloc<bool>(unison); - const float unison_spread = - pars.getUnisonFrequencySpreadCents(nvoice); - const float unison_real_spread = powf(2.0f, (unison_spread * 0.5f) / 1200.0f); - const float unison_vibratto_a = - pars.VoicePar[nvoice].Unison_vibratto / 127.0f; //0.0f .. 1.0f - - const int true_unison = unison / (is_pwm ? 2 : 1); - switch(true_unison) { - case 1: - voice.unison_base_freq_rap[0] = 1.0f; //if the unison is not used, always make the only subvoice to have the default note - break; - case 2: //unison for 2 subvoices - voice.unison_base_freq_rap[0] = 1.0f / unison_real_spread; - voice.unison_base_freq_rap[1] = unison_real_spread; - break; - default: //unison for more than 2 subvoices - { - float unison_values[true_unison]; - float min = -1e-6f, max = 1e-6f; - for(int k = 0; k < true_unison; ++k) { - float step = (k / (float) (true_unison - 1)) * 2.0f - 1.0f; //this makes the unison spread more uniform - float val = step + (RND * 2.0f - 1.0f) / (true_unison - 1); - unison_values[k] = val; - if (min > val) { - min = val; - } - if (max < val) { - max = val; - } - } - const float diff = max - min; - for(int k = 0; k < true_unison; ++k) { - unison_values[k] = - (unison_values[k] - (max + min) * 0.5f) / diff; //the lowest value will be -1 and the highest will be 1 - voice.unison_base_freq_rap[k] = - powf(2.0f, (unison_spread * unison_values[k]) / 1200); - } - } - } - if (is_pwm) - for (int i = true_unison - 1; i >= 0; i--) { - voice.unison_base_freq_rap[2*i + 1] = - voice.unison_base_freq_rap[i]; - voice.unison_base_freq_rap[2*i] = - voice.unison_base_freq_rap[i]; - } - - //unison vibrattos - if(unison > 2 || (!is_pwm && unison > 1)) - for(int k = 0; k < unison; ++k) //reduce the frequency difference for larger vibrattos - voice.unison_base_freq_rap[k] = 1.0f - + (voice.unison_base_freq_rap[k] - 1.0f) - * (1.0f - unison_vibratto_a); - voice.unison_vibratto.step = memory.valloc<float>(unison); - voice.unison_vibratto.position = memory.valloc<float>(unison); - voice.unison_vibratto.amplitude = - (unison_real_spread - 1.0f) * unison_vibratto_a; - - const float increments_per_second = synth.samplerate_f / synth.buffersize_f; - const float vib_speed = pars.VoicePar[nvoice].Unison_vibratto_speed / 127.0f; - const float vibratto_base_period = 0.25f * powf(2.0f, (1.0f - vib_speed) * 4.0f); - for(int k = 0; k < unison; ++k) { - voice.unison_vibratto.position[k] = RND * 1.8f - 0.9f; - //make period to vary randomly from 50% to 200% vibratto base period - const float vibratto_period = vibratto_base_period - * powf(2.0f, RND * 2.0f - 1.0f); - - const float m = (RND < 0.5f ? -1.0f : 1.0f) * - 4.0f / (vibratto_period * increments_per_second); - voice.unison_vibratto.step[k] = m; - - // Ugly, but the alternative is likely uglier. - if (is_pwm) - for (int i = 0; i < unison; i += 2) { - voice.unison_vibratto.step[i+1] = - voice.unison_vibratto.step[i]; - voice.unison_vibratto.position[i+1] = - voice.unison_vibratto.position[i]; - } - } - - if(unison <= 2) { //no vibratto for a single voice - if (is_pwm) { - voice.unison_vibratto.step[1] = 0.0f; - voice.unison_vibratto.position[1] = 0.0f; - } - if (is_pwm || unison == 1) { - voice.unison_vibratto.step[0] = 0.0f; - voice.unison_vibratto.position[0] = 0.0f; - voice.unison_vibratto.amplitude = 0.0f; - } - } - - //phase invert for unison - voice.unison_invert_phase[0] = false; - if(unison != 1) { - int inv = pars.VoicePar[nvoice].Unison_invert_phase; - switch(inv) { - case 0: - for(int k = 0; k < unison; ++k) - voice.unison_invert_phase[k] = false; - break; - case 1: - for(int k = 0; k < unison; ++k) - voice.unison_invert_phase[k] = (RND > 0.5f); - break; - default: - for(int k = 0; k < unison; ++k) - voice.unison_invert_phase[k] = - (k % inv == 0) ? true : false; - break; - } - } - return unison; -} - -void ADnote::setupVoiceDetune(int nvoice) -{ - //use the Globalpars.detunetype if the detunetype is 0 - if(pars.VoicePar[nvoice].PDetuneType != 0) { - NoteVoicePar[nvoice].Detune = getdetune( - pars.VoicePar[nvoice].PDetuneType, - pars.VoicePar[nvoice]. - PCoarseDetune, - 8192); //coarse detune - NoteVoicePar[nvoice].FineDetune = getdetune( - pars.VoicePar[nvoice].PDetuneType, - 0, - pars.VoicePar[nvoice].PDetune); //fine detune - } - else { - NoteVoicePar[nvoice].Detune = getdetune( - pars.GlobalPar.PDetuneType, - pars.VoicePar[nvoice]. - PCoarseDetune, - 8192); //coarse detune - NoteVoicePar[nvoice].FineDetune = getdetune( - pars.GlobalPar.PDetuneType, - 0, - pars.VoicePar[nvoice].PDetune); //fine detune - } - if(pars.VoicePar[nvoice].PFMDetuneType != 0) - NoteVoicePar[nvoice].FMDetune = getdetune( - pars.VoicePar[nvoice].PFMDetuneType, - pars.VoicePar[nvoice]. - PFMCoarseDetune, - pars.VoicePar[nvoice].PFMDetune); - else - NoteVoicePar[nvoice].FMDetune = getdetune( - pars.GlobalPar.PDetuneType, - pars.VoicePar[nvoice]. - PFMCoarseDetune, - pars.VoicePar[nvoice].PFMDetune); -} - -void ADnote::setupVoiceMod(int nvoice, bool first_run) -{ - auto &param = pars.VoicePar[nvoice]; - auto &voice = NoteVoicePar[nvoice]; - float FMVolume; - - if (param.Type != 0) - voice.FMEnabled = FMTYPE::NONE; - else - voice.FMEnabled = param.PFMEnabled; - - voice.FMFreqFixed = param.PFMFixedFreq; - - //Triggers when a user enables modulation on a running voice - if(!first_run && voice.FMEnabled != FMTYPE::NONE && voice.FMSmp == NULL && voice.FMVoice < 0) { - param.FMSmp->newrandseed(prng()); - voice.FMSmp = memory.valloc<float>(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES); - memset(voice.FMSmp, 0, sizeof(float)*(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES)); - int vc = nvoice; - if(param.PextFMoscil != -1) - vc = param.PextFMoscil; - - float tmp = 1.0f; - if((pars.VoicePar[vc].FMSmp->Padaptiveharmonics != 0) - || (voice.FMEnabled == FMTYPE::MIX) - || (voice.FMEnabled == FMTYPE::RING_MOD)) - tmp = getFMvoicebasefreq(nvoice); - - if(!pars.GlobalPar.Hrandgrouping) - pars.VoicePar[vc].FMSmp->newrandseed(prng()); - - for(int k = 0; k < voice.unison_size; ++k) - voice.oscposhiFM[k] = (voice.oscposhi[k] - + pars.VoicePar[vc].FMSmp->get( - voice.FMSmp, tmp)) - % synth.oscilsize; - - for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) - voice.FMSmp[synth.oscilsize + i] = voice.FMSmp[i]; - int oscposhiFM_add = - (int)((param.PFMoscilphase - - 64.0f) / 128.0f * synth.oscilsize - + synth.oscilsize * 4); - for(int k = 0; k < voice.unison_size; ++k) { - voice.oscposhiFM[k] += oscposhiFM_add; - voice.oscposhiFM[k] %= synth.oscilsize; - } - } - - - //Compute the Voice's modulator volume (incl. damping) - float fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice), - param.PFMVolumeDamp / 64.0f - 1.0f); - const float fmvolume_ = param.FMvolume / 100.0f; - switch(voice.FMEnabled) { - case FMTYPE::PHASE_MOD: - case FMTYPE::PW_MOD: - fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice), - param.PFMVolumeDamp / 64.0f); - FMVolume = (expf(fmvolume_ * FM_AMP_MULTIPLIER) - 1.0f) - * fmvoldamp * 4.0f; - break; - case FMTYPE::FREQ_MOD: - FMVolume = (expf(fmvolume_ * FM_AMP_MULTIPLIER) - 1.0f) - * fmvoldamp * 4.0f; - break; - default: - if(fmvoldamp > 1.0f) - fmvoldamp = 1.0f; - FMVolume = fmvolume_ * fmvoldamp; - break; - } - - //Voice's modulator velocity sensing - voice.FMVolume = FMVolume * - VelF(velocity, pars.VoicePar[nvoice].PFMVelocityScaleFunction); -} - -SynthNote *ADnote::cloneLegato(void) -{ - SynthParams sp{memory, ctl, synth, time, velocity, - (bool)portamento, legato.param.note_log2_freq, true, - initial_seed }; - return memory.alloc<ADnote>(&pars, sp); -} - -// ADlegatonote: This function is (mostly) a copy of ADnote(...) and -// initparameters() stuck together with some lines removed so that it -// only alter the already playing note (to perform legato). It is -// possible I left stuff that is not required for this. -void ADnote::legatonote(const LegatoParams &lpars) -{ - //ADnoteParameters &pars = *partparams; - // Manage legato stuff - if(legato.update(lpars)) - return; - - portamento = lpars.portamento; - note_log2_freq = lpars.note_log2_freq; - initial_seed = lpars.seed; - current_prng_state = lpars.seed; - - if(lpars.velocity > 1.0f) - velocity = 1.0f; - else - velocity = lpars.velocity; - - const float basefreq = powf(2.0f, note_log2_freq); - - NoteGlobalPar.Detune = getdetune(pars.GlobalPar.PDetuneType, - pars.GlobalPar.PCoarseDetune, - pars.GlobalPar.PDetune); - bandwidthDetuneMultiplier = pars.getBandwidthDetuneMultiplier(); - - if(pars.GlobalPar.PPanning) - NoteGlobalPar.Panning = pars.GlobalPar.PPanning / 128.0f; - - NoteGlobalPar.Filter->updateSense(velocity, - pars.GlobalPar.PFilterVelocityScale, - pars.GlobalPar.PFilterVelocityScaleFunction); - - - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - auto &voice = NoteVoicePar[nvoice]; - float FMVolume; - - if(voice.Enabled == OFF) - continue; //(gf) Stay the same as first note in legato. - - voice.fixedfreq = pars.VoicePar[nvoice].Pfixedfreq; - voice.fixedfreqET = pars.VoicePar[nvoice].PfixedfreqET; - - //use the Globalpars.detunetype if the detunetype is 0 - if(pars.VoicePar[nvoice].PDetuneType != 0) { - voice.Detune = getdetune( - pars.VoicePar[nvoice].PDetuneType, - pars.VoicePar[nvoice].PCoarseDetune, - 8192); //coarse detune - voice.FineDetune = getdetune( - pars.VoicePar[nvoice].PDetuneType, - 0, - pars.VoicePar[nvoice].PDetune); //fine detune - } - else { - voice.Detune = getdetune( - pars.GlobalPar.PDetuneType, - pars.VoicePar[nvoice].PCoarseDetune, - 8192); //coarse detune - voice.FineDetune = getdetune( - pars.GlobalPar.PDetuneType, - 0, - pars.VoicePar[nvoice].PDetune); //fine detune - } - if(pars.VoicePar[nvoice].PFMDetuneType != 0) - voice.FMDetune = getdetune( - pars.VoicePar[nvoice].PFMDetuneType, - pars.VoicePar[nvoice].PFMCoarseDetune, - pars.VoicePar[nvoice].PFMDetune); - else - voice.FMDetune = getdetune( - pars.GlobalPar.PDetuneType, - pars.VoicePar[nvoice].PFMCoarseDetune, - pars.VoicePar[nvoice].PFMDetune); - - auto &voiceFilter = voice.Filter; - if(voiceFilter) { - const auto &vce = pars.VoicePar[nvoice]; - voiceFilter->updateSense(velocity, vce.PFilterVelocityScale, - vce.PFilterVelocityScaleFunction); - } - - voice.filterbypass = - pars.VoicePar[nvoice].Pfilterbypass; - - - voice.FMVoice = pars.VoicePar[nvoice].PFMVoice; - - //Compute the Voice's modulator volume (incl. damping) - float fmvoldamp = powf(440.0f / getvoicebasefreq(nvoice), - pars.VoicePar[nvoice].PFMVolumeDamp / 64.0f - - 1.0f); - - switch(voice.FMEnabled) { - case FMTYPE::PHASE_MOD: - case FMTYPE::PW_MOD: - fmvoldamp = - powf(440.0f / getvoicebasefreq( - nvoice), pars.VoicePar[nvoice].PFMVolumeDamp - / 64.0f); - FMVolume = - (expf(pars.VoicePar[nvoice].FMvolume / 100.0f - * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f; - break; - case FMTYPE::FREQ_MOD: - FMVolume = - (expf(pars.VoicePar[nvoice].FMvolume / 100.0f - * FM_AMP_MULTIPLIER) - 1.0f) * fmvoldamp * 4.0f; - break; - default: - if(fmvoldamp > 1.0f) - fmvoldamp = 1.0f; - FMVolume = - pars.VoicePar[nvoice].FMvolume - / 100.0f * fmvoldamp; - break; - } - - //Voice's modulator velocity sensing - voice.FMVolume = FMVolume * - VelF(velocity, - pars.VoicePar[nvoice].PFMVelocityScaleFunction); - } - /// initparameters(); - - /////////////// - // Altered content of initparameters(): - - int tmp[NUM_VOICES]; - - NoteGlobalPar.Volume = dB2rap(pars.GlobalPar.Volume) //-60 dB .. 20 dB - * VelF( - velocity, - pars.GlobalPar.PAmpVelocityScaleFunction); //velocity sensing - - { - auto *filter = NoteGlobalPar.Filter; - filter->updateSense(velocity, pars.GlobalPar.PFilterVelocityScale, - pars.GlobalPar.PFilterVelocityScaleFunction); - filter->updateNoteFreq(basefreq); - } - - // Forbids the Modulation Voice to be greater or equal than voice - for(int i = 0; i < NUM_VOICES; ++i) - if(NoteVoicePar[i].FMVoice >= i) - NoteVoicePar[i].FMVoice = -1; - - // Voice Parameter init - for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - Voice& vce = NoteVoicePar[nvoice]; - if(NoteVoicePar[nvoice].Enabled == 0) - continue; - - NoteVoicePar[nvoice].noisetype = pars.VoicePar[nvoice].Type; - /* Voice Amplitude Parameters Init */ - NoteVoicePar[nvoice].Volume = - dB2rap(pars.VoicePar[nvoice].volume) // -60 dB .. 0 dB - * VelF(velocity, - pars.VoicePar[nvoice].PAmpVelocityScaleFunction); //velocity - if(pars.VoicePar[nvoice].volume == -60.0) - NoteVoicePar[nvoice].Volume = 0; - - if(pars.VoicePar[nvoice].PVolumeminus != 0) - NoteVoicePar[nvoice].Volume = -NoteVoicePar[nvoice].Volume; - - NoteVoicePar[nvoice].AAEnabled = - pars.VoicePar[nvoice].PAAEnabled; - - if(pars.VoicePar[nvoice].PPanning == 0) { - NoteVoicePar[nvoice].Panning = getRandomFloat(); - } else - NoteVoicePar[nvoice].Panning = - pars.VoicePar[nvoice].PPanning / 128.0f; - - vce.newamplitude = 1.0f; - if(pars.VoicePar[nvoice].PAmpEnvelopeEnabled - && NoteVoicePar[nvoice].AmpEnvelope) - vce.newamplitude *= NoteVoicePar[nvoice].AmpEnvelope->envout_dB(); - - - if(pars.VoicePar[nvoice].PAmpLfoEnabled && NoteVoicePar[nvoice].AmpLfo) - vce.newamplitude *= NoteVoicePar[nvoice].AmpLfo->amplfoout(); - - auto *voiceFilter = NoteVoicePar[nvoice].Filter; - if(voiceFilter) { - voiceFilter->updateSense(velocity, pars.VoicePar[nvoice].PFilterVelocityScale, - pars.VoicePar[nvoice].PFilterVelocityScaleFunction); - voiceFilter->updateNoteFreq(basefreq); - } - - /* Voice Modulation Parameters Init */ - if((NoteVoicePar[nvoice].FMEnabled != FMTYPE::NONE) - && (NoteVoicePar[nvoice].FMVoice < 0)) { - pars.VoicePar[nvoice].FMSmp->newrandseed(prng()); - - //Perform Anti-aliasing only on MIX or RING MODULATION - - int vc = nvoice; - if(pars.VoicePar[nvoice].PextFMoscil != -1) - vc = pars.VoicePar[nvoice].PextFMoscil; - - if(!pars.GlobalPar.Hrandgrouping) - pars.VoicePar[vc].FMSmp->newrandseed(prng()); - - for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) - NoteVoicePar[nvoice].FMSmp[synth.oscilsize + i] = - NoteVoicePar[nvoice].FMSmp[i]; - } - - vce.FMnewamplitude = NoteVoicePar[nvoice].FMVolume - * ctl.fmamp.relamp; - - if(pars.VoicePar[nvoice].PFMAmpEnvelopeEnabled - && NoteVoicePar[nvoice].FMAmpEnvelope) - vce.FMnewamplitude *= - NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB(); - } - - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - for(unsigned i = nvoice + 1; i < NUM_VOICES; ++i) - tmp[i] = 0; - for(unsigned i = nvoice + 1; i < NUM_VOICES; ++i) - if((NoteVoicePar[i].FMVoice == nvoice) && (tmp[i] == 0)) - tmp[i] = 1; - } -} - - -/* - * Kill a voice of ADnote - */ -void ADnote::KillVoice(int nvoice) -{ - auto &voice = NoteVoicePar[nvoice]; - - memory.devalloc(voice.oscfreqhi); - memory.devalloc(voice.oscfreqlo); - memory.devalloc(voice.oscfreqhiFM); - memory.devalloc(voice.oscfreqloFM); - memory.devalloc(voice.oscposhi); - memory.devalloc(voice.oscposlo); - memory.devalloc(voice.oscposhiFM); - memory.devalloc(voice.oscposloFM); - - memory.devalloc(voice.unison_base_freq_rap); - memory.devalloc(voice.unison_freq_rap); - memory.devalloc(voice.unison_invert_phase); - memory.devalloc(voice.FMoldsmp); - memory.devalloc(voice.unison_vibratto.step); - memory.devalloc(voice.unison_vibratto.position); - - NoteVoicePar[nvoice].kill(memory, synth); -} - -/* - * Kill the note - */ -void ADnote::KillNote() -{ - for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - if(NoteVoicePar[nvoice].Enabled == ON) - KillVoice(nvoice); - - if(NoteVoicePar[nvoice].VoiceOut) - memory.dealloc(NoteVoicePar[nvoice].VoiceOut); - } - - NoteGlobalPar.kill(memory); - - NoteEnabled = OFF; -} - -ADnote::~ADnote() -{ - if(NoteEnabled == ON) - KillNote(); - memory.devalloc(tmpwavel); - memory.devalloc(tmpwaver); - memory.devalloc(bypassl); - memory.devalloc(bypassr); - for(int k = 0; k < max_unison; ++k) - memory.devalloc(tmpwave_unison[k]); - memory.devalloc(tmpwave_unison); -} - - -/* - * Init the parameters - */ -void ADnote::initparameters(WatchManager *wm, const char *prefix) -{ - int tmp[NUM_VOICES]; - ScratchString pre = prefix; - const float basefreq = powf(2.0f, note_log2_freq); - - // Global Parameters - NoteGlobalPar.initparameters(pars.GlobalPar, synth, - time, - memory, basefreq, velocity, - stereo, wm, prefix); - - NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output - globalnewamplitude = NoteGlobalPar.Volume - * NoteGlobalPar.AmpEnvelope->envout_dB() - * NoteGlobalPar.AmpLfo->amplfoout(); - - // Forbids the Modulation Voice to be greater or equal than voice - for(int i = 0; i < NUM_VOICES; ++i) - if(NoteVoicePar[i].FMVoice >= i) - NoteVoicePar[i].FMVoice = -1; - - // Voice Parameter init - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - Voice &vce = NoteVoicePar[nvoice]; - ADnoteVoiceParam &param = pars.VoicePar[nvoice]; - - if(vce.Enabled == 0) - continue; - - vce.noisetype = param.Type; - /* Voice Amplitude Parameters Init */ - vce.Volume = dB2rap(param.volume) // -60dB..0dB - * VelF(velocity, param.PAmpVelocityScaleFunction); - if(param.volume == -60.0f) - vce.Volume = 0; - - if(param.PVolumeminus) - vce.Volume = -vce.Volume; - - if(param.PPanning == 0) { - vce.Panning = getRandomFloat(); - } else - vce.Panning = param.PPanning / 128.0f; - - vce.newamplitude = 1.0f; - if(param.PAmpEnvelopeEnabled) { - vce.AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, - basefreq, synth.dt(), wm, - (pre+"VoicePar"+nvoice+"/AmpEnvelope/").c_str); - vce.AmpEnvelope->envout_dB(); //discard the first envelope sample - vce.newamplitude *= vce.AmpEnvelope->envout_dB(); - } - - if(param.PAmpLfoEnabled) { - vce.AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time, wm, - (pre+"VoicePar"+nvoice+"/AmpLfo/").c_str); - vce.newamplitude *= vce.AmpLfo->amplfoout(); - } - - /* Voice Frequency Parameters Init */ - if(param.PFreqEnvelopeEnabled) - vce.FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, - basefreq, synth.dt(), wm, - (pre+"VoicePar"+nvoice+"/FreqEnvelope/").c_str); - - if(param.PFreqLfoEnabled) - vce.FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time, wm, - (pre+"VoicePar"+nvoice+"/FreqLfo/").c_str); - - /* Voice Filter Parameters Init */ - if(param.PFilterEnabled) { - vce.Filter = memory.alloc<ModFilter>(*param.VoiceFilter, synth, time, memory, stereo, - basefreq); - vce.Filter->updateSense(velocity, param.PFilterVelocityScale, - param.PFilterVelocityScaleFunction); - - - if(param.PFilterEnvelopeEnabled) { - vce.FilterEnvelope = - memory.alloc<Envelope>(*param.FilterEnvelope, - basefreq, synth.dt(), wm, - (pre+"VoicePar"+nvoice+"/FilterEnvelope/").c_str); - vce.Filter->addMod(*vce.FilterEnvelope); - } - - if(param.PFilterLfoEnabled) { - vce.FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time, wm, - (pre+"VoicePar"+nvoice+"/FilterLfo/").c_str); - vce.Filter->addMod(*vce.FilterLfo); - } - } - - /* Voice Modulation Parameters Init */ - if((vce.FMEnabled != FMTYPE::NONE) && (vce.FMVoice < 0)) { - param.FMSmp->newrandseed(prng()); - vce.FMSmp = memory.valloc<float>(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES); - - //Perform Anti-aliasing only on MIX or RING MODULATION - - int vc = nvoice; - if(param.PextFMoscil != -1) - vc = param.PextFMoscil; - - float tmp = 1.0f; - if((pars.VoicePar[vc].FMSmp->Padaptiveharmonics != 0) - || (vce.FMEnabled == FMTYPE::MIX) - || (vce.FMEnabled == FMTYPE::RING_MOD)) - tmp = getFMvoicebasefreq(nvoice); - - if(!pars.GlobalPar.Hrandgrouping) - pars.VoicePar[vc].FMSmp->newrandseed(prng()); - - for(int k = 0; k < vce.unison_size; ++k) - vce.oscposhiFM[k] = (vce.oscposhi[k] - + pars.VoicePar[vc].FMSmp->get( - vce.FMSmp, tmp)) - % synth.oscilsize; - - for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) - vce.FMSmp[synth.oscilsize + i] = vce.FMSmp[i]; - int oscposhiFM_add = - (int)((param.PFMoscilphase - - 64.0f) / 128.0f * synth.oscilsize - + synth.oscilsize * 4); - for(int k = 0; k < vce.unison_size; ++k) { - vce.oscposhiFM[k] += oscposhiFM_add; - vce.oscposhiFM[k] %= synth.oscilsize; - } - } - - if(param.PFMFreqEnvelopeEnabled) - vce.FMFreqEnvelope = memory.alloc<Envelope>(*param.FMFreqEnvelope, - basefreq, synth.dt(), wm, - (pre+"VoicePar"+nvoice+"/FMFreqEnvelope/").c_str); - - vce.FMnewamplitude = vce.FMVolume * ctl.fmamp.relamp; - - if(param.PFMAmpEnvelopeEnabled) { - vce.FMAmpEnvelope = - memory.alloc<Envelope>(*param.FMAmpEnvelope, - basefreq, synth.dt(), wm, - (pre+"VoicePar"+nvoice+"/FMAmpEnvelope/").c_str); - vce.FMnewamplitude *= vce.FMAmpEnvelope->envout_dB(); - } - } - - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - for(int i = nvoice + 1; i < NUM_VOICES; ++i) - tmp[i] = 0; - for(int i = nvoice + 1; i < NUM_VOICES; ++i) - if((NoteVoicePar[i].FMVoice == nvoice) && (tmp[i] == 0)) { - NoteVoicePar[nvoice].VoiceOut = - memory.valloc<float>(synth.buffersize); - tmp[i] = 1; - } - - if(NoteVoicePar[nvoice].VoiceOut) - memset(NoteVoicePar[nvoice].VoiceOut, 0, synth.bufferbytes); - } -} - - -/* - * Computes the relative frequency of each unison voice and it's vibratto - * This must be called before setfreq* functions - */ -void ADnote::compute_unison_freq_rap(int nvoice) { - Voice &vce = NoteVoicePar[nvoice]; - if(vce.unison_size == 1) { //no unison - vce.unison_freq_rap[0] = 1.0f; - return; - } - float relbw = ctl.bandwidth.relbw * bandwidthDetuneMultiplier; - for(int k = 0; k < vce.unison_size; ++k) { - float pos = vce.unison_vibratto.position[k]; - float step = vce.unison_vibratto.step[k]; - pos += step; - if(pos <= -1.0f) { - pos = -1.0f; - step = -step; - } - if(pos >= 1.0f) { - pos = 1.0f; - step = -step; - } - float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother - vce.unison_freq_rap[k] = 1.0f - + ((vce.unison_base_freq_rap[k] - - 1.0f) + vibratto_val - * vce.unison_vibratto.amplitude) - * relbw; - - vce.unison_vibratto.position[k] = pos; - step = vce.unison_vibratto.step[k] = step; - } -} - - -/* - * Computes the frequency of an oscillator - */ -void ADnote::setfreq(int nvoice, float in_freq) -{ - Voice &vce = NoteVoicePar[nvoice]; - for(int k = 0; k < vce.unison_size; ++k) { - float freq = fabsf(in_freq) * vce.unison_freq_rap[k]; - float speed = freq * synth.oscilsize_f / synth.samplerate_f; - if(speed > synth.oscilsize_f) - speed = synth.oscilsize_f; - - F2I(speed, vce.oscfreqhi[k]); - vce.oscfreqlo[k] = speed - floorf(speed); - - } -} - -/* - * Computes the frequency of an modullator oscillator - */ -void ADnote::setfreqFM(int nvoice, float in_freq) -{ - Voice &vce = NoteVoicePar[nvoice]; - for(int k = 0; k < vce.unison_size; ++k) { - float freq = fabsf(in_freq) * vce.unison_freq_rap[k]; - float speed = freq * synth.oscilsize_f / synth.samplerate_f; - if(speed > synth.samplerate_f) - speed = synth.samplerate_f; - - F2I(speed, vce.oscfreqhiFM[k]); - vce.oscfreqloFM[k] = speed - floorf(speed); - } -} - -/* - * Get Voice base frequency - */ -float ADnote::getvoicebasefreq(int nvoice, float adjust_log2) const -{ - const float detune = NoteVoicePar[nvoice].Detune / 100.0f - + NoteVoicePar[nvoice].FineDetune / 100.0f - * ctl.bandwidth.relbw * bandwidthDetuneMultiplier - + NoteGlobalPar.Detune / 100.0f; - - if(NoteVoicePar[nvoice].fixedfreq == 0) { - return powf(2.0f, note_log2_freq + detune / 12.0f + adjust_log2); - } - else { //the fixed freq is enabled - const int fixedfreqET = NoteVoicePar[nvoice].fixedfreqET; - float fixedfreq_log2 = log2f(440.0f); - - if(fixedfreqET != 0) { //if the frequency varies according the keyboard note - float tmp_log2 = (note_log2_freq - fixedfreq_log2) * - (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f); - if(fixedfreqET <= 64) - fixedfreq_log2 += tmp_log2; - else - fixedfreq_log2 += tmp_log2 * log2f(3.0f); - } - return powf(2.0f, fixedfreq_log2 + detune / 12.0f + adjust_log2); - } -} - -/* - * Get Voice's Modullator base frequency - */ -float ADnote::getFMvoicebasefreq(int nvoice) const -{ - return getvoicebasefreq(nvoice, NoteVoicePar[nvoice].FMDetune / 1200.0f); -} - -/* - * Computes all the parameters for each tick - */ -void ADnote::computecurrentparameters() -{ - const float relfreq = getFilterCutoffRelFreq(); - int nvoice; - float voicefreq, voicepitch, FMfreq, - FMrelativepitch, globalpitch; - - globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout() - + NoteGlobalPar.FreqLfo->lfoout() - * ctl.modwheel.relmod); - globaloldamplitude = globalnewamplitude; - globalnewamplitude = NoteGlobalPar.Volume - * NoteGlobalPar.AmpEnvelope->envout_dB() - * NoteGlobalPar.AmpLfo->amplfoout(); - - NoteGlobalPar.Filter->update(relfreq, ctl.filterq.relq); - - //compute the portamento, if it is used by this note - float portamentofreqdelta_log2 = 0.0f; - if(portamento != 0) { //this voice use portamento - portamentofreqdelta_log2 = ctl.portamento.freqdelta_log2; - if(ctl.portamento.used == 0) //the portamento has finished - portamento = 0; //this note is no longer "portamented" - } - - //compute parameters for all voices - for(nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - Voice& vce = NoteVoicePar[nvoice]; - if(NoteVoicePar[nvoice].Enabled != ON) - continue; - NoteVoicePar[nvoice].DelayTicks -= 1; - if(NoteVoicePar[nvoice].DelayTicks > 0) - continue; - - compute_unison_freq_rap(nvoice); - - /*******************/ - /* Voice Amplitude */ - /*******************/ - vce.oldamplitude = vce.newamplitude; - vce.newamplitude = 1.0f; - - if(NoteVoicePar[nvoice].AmpEnvelope) - vce.newamplitude *= NoteVoicePar[nvoice].AmpEnvelope->envout_dB(); - - if(NoteVoicePar[nvoice].AmpLfo) - vce.newamplitude *= NoteVoicePar[nvoice].AmpLfo->amplfoout(); - - /****************/ - /* Voice Filter */ - /****************/ - auto *voiceFilter = NoteVoicePar[nvoice].Filter; - if(voiceFilter) { - voiceFilter->update(relfreq, ctl.filterq.relq); - } - - if(NoteVoicePar[nvoice].noisetype == 0) { //compute only if the voice isn't noise - /*******************/ - /* Voice Frequency */ - /*******************/ - voicepitch = 0.0f; - if(NoteVoicePar[nvoice].FreqLfo) - voicepitch += NoteVoicePar[nvoice].FreqLfo->lfoout() / 100.0f - * ctl.bandwidth.relbw; - - if(NoteVoicePar[nvoice].FreqEnvelope) - voicepitch += NoteVoicePar[nvoice].FreqEnvelope->envout() - / 100.0f; - voicefreq = getvoicebasefreq(nvoice, portamentofreqdelta_log2 + - (voicepitch + globalpitch) / 12.0f); //Hz frequency - voicefreq *= - powf(ctl.pitchwheel.relfreq, NoteVoicePar[nvoice].BendAdjust); //change the frequency by the controller - setfreq(nvoice, voicefreq + NoteVoicePar[nvoice].OffsetHz); - - /***************/ - /* Modulator */ - /***************/ - - - if(NoteVoicePar[nvoice].FMEnabled != FMTYPE::NONE) { - FMrelativepitch = NoteVoicePar[nvoice].FMDetune / 100.0f; - if(NoteVoicePar[nvoice].FMFreqEnvelope) - FMrelativepitch += - NoteVoicePar[nvoice].FMFreqEnvelope->envout() / 100.0f; - if (NoteVoicePar[nvoice].FMFreqFixed) - FMfreq = powf(2.0f, FMrelativepitch / 12.0f) * 440.0f; - else - FMfreq = powf(2.0f, FMrelativepitch / 12.0f) * voicefreq; - setfreqFM(nvoice, FMfreq); - - vce.FMoldamplitude = vce.FMnewamplitude; - vce.FMnewamplitude = NoteVoicePar[nvoice].FMVolume - * ctl.fmamp.relamp; - if(NoteVoicePar[nvoice].FMAmpEnvelope) - vce.FMnewamplitude *= - NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB(); - } - } - } -} - - -/* - * Fadein in a way that removes clicks but keep sound "punchy" - */ -inline void ADnote::fadein(float *smps) const -{ - int zerocrossings = 0; - for(int i = 1; i < synth.buffersize; ++i) - if((smps[i - 1] < 0.0f) && (smps[i] > 0.0f)) - zerocrossings++; //this is only the positive crossings - - float tmp = (synth.buffersize_f - 1.0f) / (zerocrossings + 1) / 3.0f; - if(tmp < 8.0f) - tmp = 8.0f; - tmp *= NoteGlobalPar.Fadein_adjustment; - - int n; - F2I(tmp, n); //how many samples is the fade-in - if(n > synth.buffersize) - n = synth.buffersize; - for(int i = 0; i < n; ++i) { //fade-in - float tmp = 0.5f - cosf((float)i / (float) n * PI) * 0.5f; - smps[i] *= tmp; - } -} - -/* - * Computes the Oscillator (Without Modulation) - LinearInterpolation - */ - -/* As the code here is a bit odd due to optimization, here is what happens - * First the current position and frequency are retrieved from the running - * state. These are broken up into high and low portions to indicate how many - * samples are skipped in one step and how many fractional samples are skipped. - * Outside of this method the fractional samples are just handled with floating - * point code, but that's a bit slower than it needs to be. In this code the low - * portions are known to exist between 0.0 and 1.0 and it is known that they are - * stored in single precision floating point IEEE numbers. This implies that - * a maximum of 24 bits are significant. The below code does your standard - * linear interpolation that you'll see throughout this codebase, but by - * sticking to integers for tracking the overflow of the low portion, around 15% - * of the execution time was shaved off in the ADnote test. - */ -inline void ADnote::ComputeVoiceOscillator_LinearInterpolation(int nvoice) -{ -<<<<<<< HEAD - Voice& vce = NoteVoicePar[nvoice]; - for(int k = 0; k < vce.unison_size; ++k) { - int poshi = vce.oscposhi[k]; - int poslo = (int)(vce.oscposlo[k] * (0x01000000)); - int freqhi = vce.oscfreqhi[k]; - int freqlo = (int)(vce.oscfreqlo[k] * (0x01000000)); -======= - for(int k = 0; k < unison_size[nvoice]; ++k) { - int poshi = oscposhi[nvoice][k]; - // convert floating point fractional part (sample interval phase) - // with range [0.0 ... 1.0] to fixed point with 1 digit is 2^-24 - // by multiplying with precalculated 2^24 and casting to integer: - int poslo = (int)(oscposlo[nvoice][k] * 16777216.0f); - int freqhi = oscfreqhi[nvoice][k]; - // same for phase increment: - int freqlo = (int)(oscfreqlo[nvoice][k] * 16777216.0f); ->>>>>>> adsynth more comments and small fixes - float *smps = NoteVoicePar[nvoice].OscilSmp; - float *tw = tmpwave_unison[k]; - assert(vce.oscfreqlo[k] < 1.0f); - for(int i = 0; i < synth.buffersize; ++i) { - tw[i] = (smps[poshi] * (0x01000000 - poslo) + smps[poshi + 1] * poslo)/(16777216.0f); - poslo += freqlo; // increment fractional part (sample interval phase) - poshi += freqhi + (poslo>>24); // add overflow over 24 bits in poslo to poshi - poslo &= 0xffffff; // remove overflow from poslo - poshi &= synth.oscilsize - 1; // remove overflow - } - vce.oscposhi[k] = poshi; - vce.oscposlo[k] = poslo/(16777216.0f); - } -} - - -/* - * Computes the Oscillator (Without Modulation) - windowed sinc Interpolation - */ - -/* As the code here is a bit odd due to optimization, here is what happens - * First the current position and frequency are retrieved from the running - * state. These are broken up into high and low portions to indicate how many - * samples are skipped in one step and how many fractional samples are skipped. - * Outside of this method the fractional samples are just handled with floating - * point code, but that's a bit slower than it needs to be. In this code the low - * portions are known to exist between 0.0 and 1.0 and it is known that they are - * stored in single precision floating point IEEE numbers. This implies that - * a maximum of 24 bits are significant. The below code does your standard - * linear interpolation that you'll see throughout this codebase, but by - * sticking to integers for tracking the overflow of the low portion, around 15% - * of the execution time was shaved off in the ADnote test. - */ -inline void ADnote::ComputeVoiceOscillator_SincInterpolation(int nvoice) -{ - // windowed sinc kernel factor Fs*0.3, rejection 80dB - const float_t kernel[] = { - 0.0010596256917418426f, - 0.004273442181254887f, - 0.0035466063043375785f, - -0.014555483937137638f, - -0.04789321342588484f, - -0.050800020978553066f, - 0.04679847159974432f, - 0.2610646708018185f, - 0.4964802251145513f, - 0.6000513532962539f, - 0.4964802251145513f, - 0.2610646708018185f, - 0.04679847159974432f, - -0.050800020978553066f, - -0.04789321342588484f, - -0.014555483937137638f, - 0.0035466063043375785f, - 0.004273442181254887f, - 0.0010596256917418426f - }; -<<<<<<< HEAD - - - Voice& vce = NoteVoicePar[nvoice]; - for(int k = 0; k < vce.unison_size; ++k) { - int poshi = vce.oscposhi[k]; - int poslo = (int)(vce.oscposlo[k] * (1<<24)); - int freqhi = vce.oscfreqhi[k]; - int freqlo = (int)(vce.oscfreqlo[k] * (1<<24)); - int ovsmpfreqhi = vce.oscfreqhi[k] / 2; - int ovsmpfreqlo = (int)((vce.oscfreqlo[k] / 2) * (1<<24)); - -======= - - for(int k = 0; k < unison_size[nvoice]; ++k) { - int poshi = oscposhi[nvoice][k]; - int poslo = (int)(oscposlo[nvoice][k] * (1<<24)); - int freqhi = oscfreqhi[nvoice][k]; - int freqlo = (int)(oscfreqlo[nvoice][k] * (1<<24)); - int ovsmpfreqhi = oscfreqhi[nvoice][k] / 2; - int ovsmpfreqlo = (int)((oscfreqlo[nvoice][k] / 2) * (1<<24)); - ->>>>>>> adsynth more comments and small fixes - int ovsmpposlo; - int ovsmpposhi; - int uflow; - float *smps = NoteVoicePar[nvoice].OscilSmp; - float *tw = tmpwave_unison[k]; - assert(vce.oscfreqlo[k] < 1.0f); - float out = 0; - - for(int i = 0; i < synth.buffersize; ++i) { - ovsmpposlo = poslo - (LENGTHOF(kernel)-1)/2 * ovsmpfreqlo; - uflow = ovsmpposlo>>24; - ovsmpposhi = poshi - (LENGTHOF(kernel)-1)/2 * ovsmpfreqhi - ((0x00 - uflow) & 0xff); - ovsmpposlo &= 0xffffff; - ovsmpposhi &= synth.oscilsize - 1; - out = 0; - for (int l = 0; l<LENGTHOF(kernel); l++) { - out += kernel[l] * ( - smps[ovsmpposhi] * ((1<<24) - ovsmpposlo) + - smps[ovsmpposhi + 1] * ovsmpposlo)/(1.0f*(1<<24)); - // advance to next kernel sample - ovsmpposlo += ovsmpfreqlo; - ovsmpposhi += ovsmpfreqhi + (ovsmpposlo>>24); // add the 24-bit overflow - ovsmpposlo &= 0xffffff; - ovsmpposhi &= synth.oscilsize - 1; - } - - // advance to next sample - poslo += freqlo; - poshi += freqhi + (poslo>>24); - poslo &= 0xffffff; - poshi &= synth.oscilsize - 1; - - tw[i] = out; - - } - vce.oscposhi[k] = poshi; - vce.oscposlo[k] = poslo/(1.0f*(1<<24)); - } -} - -/* - * Computes the Oscillator (Mixing) - */ -inline void ADnote::ComputeVoiceOscillatorMix(int nvoice) -{ - ComputeVoiceOscillator_LinearInterpolation(nvoice); - - Voice& vce = NoteVoicePar[nvoice]; - if(vce.FMnewamplitude > 1.0f) - vce.FMnewamplitude = 1.0f; - if(vce.FMoldamplitude > 1.0f) - vce.FMoldamplitude = 1.0f; - - if(NoteVoicePar[nvoice].FMVoice >= 0) { - //if I use VoiceOut[] as modullator - int FMVoice = NoteVoicePar[nvoice].FMVoice; - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) { - float amp = INTERPOLATE_AMPLITUDE(vce.FMoldamplitude, - vce.FMnewamplitude, - i, - synth.buffersize); - tw[i] = tw[i] - * (1.0f - amp) + amp * NoteVoicePar[FMVoice].VoiceOut[i]; - } - } - } - else - for(int k = 0; k < vce.unison_size; ++k) { - int poshiFM = vce.oscposhiFM[k]; - float posloFM = vce.oscposloFM[k]; - int freqhiFM = vce.oscfreqhiFM[k]; - float freqloFM = vce.oscfreqloFM[k]; - float *tw = tmpwave_unison[k]; - - for(int i = 0; i < synth.buffersize; ++i) { - float amp = INTERPOLATE_AMPLITUDE(vce.FMoldamplitude, - vce.FMnewamplitude, - i, - synth.buffersize); - tw[i] = tw[i] * (1.0f - amp) + amp - * (NoteVoicePar[nvoice].FMSmp[poshiFM] * (1 - posloFM) - + NoteVoicePar[nvoice].FMSmp[poshiFM + 1] * posloFM); - posloFM += freqloFM; - if(posloFM >= 1.0f) { - posloFM -= 1.0f; - poshiFM++; - } - poshiFM += freqhiFM; - poshiFM &= synth.oscilsize - 1; - } - vce.oscposhiFM[k] = poshiFM; - vce.oscposloFM[k] = posloFM; - } -} - -/* - * Computes the Oscillator (Ring Modulation) - */ -inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice) -{ - ComputeVoiceOscillator_LinearInterpolation(nvoice); - - Voice& vce = NoteVoicePar[nvoice]; - if(vce.FMnewamplitude > 1.0f) - vce.FMnewamplitude = 1.0f; - if(vce.FMoldamplitude > 1.0f) - vce.FMoldamplitude = 1.0f; - if(NoteVoicePar[nvoice].FMVoice >= 0) - // if I use VoiceOut[] as modullator - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) { - float amp = INTERPOLATE_AMPLITUDE(vce.FMoldamplitude, - vce.FMnewamplitude, - i, - synth.buffersize); - int FMVoice = NoteVoicePar[nvoice].FMVoice; - tw[i] *= (1.0f - amp) + amp * NoteVoicePar[FMVoice].VoiceOut[i]; - } - } - else - for(int k = 0; k < vce.unison_size; ++k) { - int poshiFM = vce.oscposhiFM[k]; - float posloFM = vce.oscposloFM[k]; - int freqhiFM = vce.oscfreqhiFM[k]; - float freqloFM = vce.oscfreqloFM[k]; - float *tw = tmpwave_unison[k]; - - for(int i = 0; i < synth.buffersize; ++i) { - float amp = INTERPOLATE_AMPLITUDE(vce.FMoldamplitude, - vce.FMnewamplitude, - i, - synth.buffersize); - tw[i] *= (NoteVoicePar[nvoice].FMSmp[poshiFM] * (1.0f - posloFM) - + NoteVoicePar[nvoice].FMSmp[poshiFM - + 1] * posloFM) * amp - + (1.0f - amp); - posloFM += freqloFM; - if(posloFM >= 1.0f) { - posloFM -= 1.0f; - poshiFM++; - } - poshiFM += freqhiFM; - poshiFM &= synth.oscilsize - 1; - } - vce.oscposhiFM[k] = poshiFM; - vce.oscposloFM[k] = posloFM; - } -} - -/* - * Computes the Oscillator (Phase Modulation or Frequency Modulation) - */ -inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice, - FMTYPE FMmode) -{ - Voice& vce = NoteVoicePar[nvoice]; - if(NoteVoicePar[nvoice].FMVoice >= 0) { - //if I use VoiceOut[] as modulator - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - const float *smps = NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut; - if (FMmode == FMTYPE::PW_MOD && (k & 1)) - for (int i = 0; i < synth.buffersize; ++i) - tw[i] = -smps[i]; - else - memcpy(tw, smps, synth.bufferbytes); - } - } else { - //Compute the modulator and store it in tmpwave_unison[][] - for(int k = 0; k < vce.unison_size; ++k) { - int poshiFM = vce.oscposhiFM[k]; - int posloFM = (int)(vce.oscposloFM[k] * (1<<24)); - int freqhiFM = vce.oscfreqhiFM[k]; - int freqloFM = (int)(vce.oscfreqloFM[k] * (1<<24)); - float *tw = tmpwave_unison[k]; - const float *smps = NoteVoicePar[nvoice].FMSmp; - - for(int i = 0; i < synth.buffersize; ++i) { - tw[i] = (smps[poshiFM] * ((1<<24) - posloFM) - + smps[poshiFM + 1] * posloFM) / (1.0f*(1<<24)); - if (FMmode == FMTYPE::PW_MOD && (k & 1)) - tw[i] = -tw[i]; - - posloFM += freqloFM; - if(posloFM >= (1<<24)) { - posloFM &= 0xffffff;//fmod(posloFM, 1.0f); - poshiFM++; - } - poshiFM += freqhiFM; - poshiFM &= synth.oscilsize - 1; - } - vce.oscposhiFM[k] = poshiFM; - vce.oscposloFM[k] = posloFM/((1<<24)*1.0f); - } - } - // Amplitude interpolation - if(ABOVE_AMPLITUDE_THRESHOLD(vce.FMoldamplitude, - vce.FMnewamplitude)) { - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) - tw[i] *= INTERPOLATE_AMPLITUDE(vce.FMoldamplitude, - vce.FMnewamplitude, - i, - synth.buffersize); - } - } else { - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) - tw[i] *= vce.FMnewamplitude; - } - } - - - //normalize: makes all sample-rates, oscil_sizes to produce same sound - if(FMmode == FMTYPE::FREQ_MOD) { //Frequency modulation - const float normalize = synth.oscilsize_f / 262144.0f * 44100.0f - / synth.samplerate_f; - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - float fmold = vce.FMoldsmp[k]; - for(int i = 0; i < synth.buffersize; ++i) { - fmold = fmodf(fmold + tw[i] * normalize, synth.oscilsize); - tw[i] = fmold; - } - vce.FMoldsmp[k] = fmold; - } - } - else { //Phase or PWM modulation - const float normalize = synth.oscilsize_f / 262144.0f; - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) - tw[i] *= normalize; - } - } - - //do the modulation - for(int k = 0; k < vce.unison_size; ++k) { - float *smps = NoteVoicePar[nvoice].OscilSmp; - float *tw = tmpwave_unison[k]; - int poshi = vce.oscposhi[k]; - int poslo = (int)(vce.oscposlo[k] * (1<<24)); - int freqhi = vce.oscfreqhi[k]; - int freqlo = (int)(vce.oscfreqlo[k] * (1<<24)); - - for(int i = 0; i < synth.buffersize; ++i) { - int FMmodfreqhi = 0; - F2I(tw[i], FMmodfreqhi); - float FMmodfreqlo = tw[i]-FMmodfreqhi;//fmod(tw[i] /*+ 0.0000000001f*/, 1.0f); - if(FMmodfreqhi < 0) - FMmodfreqlo++; - - //carrier - int carposhi = poshi + FMmodfreqhi; - int carposlo = (int)(poslo + FMmodfreqlo); - if (FMmode == FMTYPE::PW_MOD && (k & 1)) - carposhi += NoteVoicePar[nvoice].phase_offset; - - if(carposlo >= (1<<24)) { - carposhi++; - carposlo &= 0xffffff;//fmod(carposlo, 1.0f); - } - carposhi &= (synth.oscilsize - 1); - - tw[i] = (smps[carposhi] * ((1<<24) - carposlo) - + smps[carposhi + 1] * carposlo)/(1.0f*(1<<24)); - - poslo += freqlo; - if(poslo >= (1<<24)) { - poslo &= 0xffffff;//fmod(poslo, 1.0f); - poshi++; - } - - poshi += freqhi; - poshi &= synth.oscilsize - 1; - } - vce.oscposhi[k] = poshi; - vce.oscposlo[k] = (poslo)/((1<<24)*1.0f); - } -} - - -/* - * Computes the Noise - */ -inline void ADnote::ComputeVoiceWhiteNoise(int nvoice) -{ - for(int k = 0; k < NoteVoicePar[nvoice].unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) - tw[i] = RND * 2.0f - 1.0f; - } -} - -inline void ADnote::ComputeVoicePinkNoise(int nvoice) -{ - Voice& vce = NoteVoicePar[nvoice]; - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - float *f = &vce.pinking[k > 0 ? 7 : 0]; - for(int i = 0; i < synth.buffersize; ++i) { - float white = (RND-0.5f)/4.0f; - f[0] = 0.99886f*f[0]+white*0.0555179f; - f[1] = 0.99332f*f[1]+white*0.0750759f; - f[2] = 0.96900f*f[2]+white*0.1538520f; - f[3] = 0.86650f*f[3]+white*0.3104856f; - f[4] = 0.55000f*f[4]+white*0.5329522f; - f[5] = -0.7616f*f[5]-white*0.0168980f; - tw[i] = f[0]+f[1]+f[2]+f[3]+f[4]+f[5]+f[6]+white*0.5362f; - f[6] = white*0.115926f; - } - } -} - -inline void ADnote::ComputeVoiceDC(int nvoice) -{ - for(int k = 0; k < NoteVoicePar[nvoice].unison_size; ++k) { - float *tw = tmpwave_unison[k]; - for(int i = 0; i < synth.buffersize; ++i) - tw[i] = 1.0f; - } -} - - - -/* - * Compute the ADnote samples - * Returns 0 if the note is finished - */ -int ADnote::noteout(float *outl, float *outr) -{ - memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); - memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); - - if(NoteEnabled == OFF) - return 0; - - memset(bypassl, 0, synth.bufferbytes); - memset(bypassr, 0, synth.bufferbytes); - - //Update Changed Parameters From UI - for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - if((NoteVoicePar[nvoice].Enabled != ON) - || (NoteVoicePar[nvoice].DelayTicks > 0)) - continue; - setupVoiceDetune(nvoice); - setupVoiceMod(nvoice, false); - } - - computecurrentparameters(); - - for(unsigned nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - if((NoteVoicePar[nvoice].Enabled != ON) - || (NoteVoicePar[nvoice].DelayTicks > 0)) - continue; - switch (NoteVoicePar[nvoice].noisetype) { - case 0: //voice mode=sound - switch(NoteVoicePar[nvoice].FMEnabled) { - case FMTYPE::MIX: - ComputeVoiceOscillatorMix(nvoice); - break; - case FMTYPE::RING_MOD: - ComputeVoiceOscillatorRingModulation(nvoice); - break; - case FMTYPE::FREQ_MOD: - case FMTYPE::PHASE_MOD: - case FMTYPE::PW_MOD: - ComputeVoiceOscillatorFrequencyModulation(nvoice, - NoteVoicePar[nvoice].FMEnabled); - break; - default: - if(NoteVoicePar[nvoice].AAEnabled) ComputeVoiceOscillator_SincInterpolation(nvoice); - else ComputeVoiceOscillator_LinearInterpolation(nvoice); - //if (config.cfg.Interpolation) ComputeVoiceOscillator_CubicInterpolation(nvoice); - } - break; - case 1: - ComputeVoiceWhiteNoise(nvoice); - break; - case 2: - ComputeVoicePinkNoise(nvoice); - break; - default: - ComputeVoiceDC(nvoice); - break; - } - // Voice Processing - - Voice& vce = NoteVoicePar[nvoice]; - //mix subvoices into voice - memset(tmpwavel, 0, synth.bufferbytes); - if(stereo) - memset(tmpwaver, 0, synth.bufferbytes); - for(int k = 0; k < vce.unison_size; ++k) { - float *tw = tmpwave_unison[k]; - if(stereo) { - float stereo_pos = 0; - bool is_pwm = NoteVoicePar[nvoice].FMEnabled == FMTYPE::PW_MOD; - if (is_pwm) { - if(vce.unison_size > 2) - stereo_pos = k/2 - / (float)(vce.unison_size/2 - - 1) * 2.0f - 1.0f; - } else if(vce.unison_size > 1) { - stereo_pos = k - / (float)(vce.unison_size - - 1) * 2.0f - 1.0f; - } - float stereo_spread = vce.unison_stereo_spread * 2.0f; //between 0 and 2.0f - if(stereo_spread > 1.0f) { - float stereo_pos_1 = (stereo_pos >= 0.0f) ? 1.0f : -1.0f; - stereo_pos = - (2.0f - - stereo_spread) * stereo_pos - + (stereo_spread - 1.0f) * stereo_pos_1; - } - else - stereo_pos *= stereo_spread; - - if(vce.unison_size == 1 || - (is_pwm && vce.unison_size == 2)) - stereo_pos = 0.0f; - float panning = (stereo_pos + 1.0f) * 0.5f; - - - float lvol = (1.0f - panning) * 2.0f; - if(lvol > 1.0f) - lvol = 1.0f; - - float rvol = panning * 2.0f; - if(rvol > 1.0f) - rvol = 1.0f; - - if(vce.unison_invert_phase[k]) { - lvol = -lvol; - rvol = -rvol; - } - - for(int i = 0; i < synth.buffersize; ++i) - tmpwavel[i] += tw[i] * lvol; - for(int i = 0; i < synth.buffersize; ++i) - tmpwaver[i] += tw[i] * rvol; - } - else - for(int i = 0; i < synth.buffersize; ++i) - tmpwavel[i] += tw[i]; - if(nvoice == 0) - watch_be4_add(tmpwavel,synth.buffersize); - } - - float unison_amplitude = 1.0f / sqrtf(vce.unison_size); //reduce the amplitude for large unison sizes - // Amplitude - float oldam = vce.oldamplitude * unison_amplitude; - float newam = vce.newamplitude * unison_amplitude; - - if(ABOVE_AMPLITUDE_THRESHOLD(oldam, newam)) { - int rest = synth.buffersize; - //test if the amplitude if raising and the difference is high - if((newam > oldam) && ((newam - oldam) > 0.25f)) { - rest = 10; - if(rest > synth.buffersize) - rest = synth.buffersize; - for(int i = 0; i < synth.buffersize - rest; ++i) - tmpwavel[i] *= oldam; - if(stereo) - for(int i = 0; i < synth.buffersize - rest; ++i) - tmpwaver[i] *= oldam; - } - // Amplitude interpolation - for(int i = 0; i < rest; ++i) { - float amp = INTERPOLATE_AMPLITUDE(oldam, newam, i, rest); - tmpwavel[i + (synth.buffersize - rest)] *= amp; - if(stereo) - tmpwaver[i + (synth.buffersize - rest)] *= amp; - } - } - else { - for(int i = 0; i < synth.buffersize; ++i) - tmpwavel[i] *= newam; - if(stereo) - for(int i = 0; i < synth.buffersize; ++i) - tmpwaver[i] *= newam; - } - - // Fade in - if(vce.firsttick != 0) { - fadein(&tmpwavel[0]); - if(stereo) - fadein(&tmpwaver[0]); - vce.firsttick = 0; - } - - // Filter - if(NoteVoicePar[nvoice].Filter) { - if(stereo) - NoteVoicePar[nvoice].Filter->filter(tmpwavel, tmpwaver); - else - NoteVoicePar[nvoice].Filter->filter(tmpwavel, 0); - } - - //check if the amplitude envelope is finished, if yes, the voice will be fadeout - if(NoteVoicePar[nvoice].AmpEnvelope) - if(NoteVoicePar[nvoice].AmpEnvelope->finished()) { - for(int i = 0; i < synth.buffersize; ++i) - tmpwavel[i] *= 1.0f - (float)i / synth.buffersize_f; - if(stereo) - for(int i = 0; i < synth.buffersize; ++i) - tmpwaver[i] *= 1.0f - (float)i / synth.buffersize_f; - } - //the voice is killed later - - - // Put the ADnote samples in VoiceOut (without applying Global volume, because I wish to use this voice as a modullator) - if(NoteVoicePar[nvoice].VoiceOut) { - if(stereo) - for(int i = 0; i < synth.buffersize; ++i) - NoteVoicePar[nvoice].VoiceOut[i] = tmpwavel[i] - + tmpwaver[i]; - else //mono - for(int i = 0; i < synth.buffersize; ++i) - NoteVoicePar[nvoice].VoiceOut[i] = tmpwavel[i]; - } - - - // Add the voice that do not bypass the filter to out - if(NoteVoicePar[nvoice].filterbypass == 0) { //no bypass - if(stereo) - for(int i = 0; i < synth.buffersize; ++i) { //stereo - outl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume - * NoteVoicePar[nvoice].Panning * 2.0f; - outr[i] += tmpwaver[i] * NoteVoicePar[nvoice].Volume - * (1.0f - NoteVoicePar[nvoice].Panning) * 2.0f; - } - else - for(int i = 0; i < synth.buffersize; ++i) //mono - outl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume; - } - else { //bypass the filter - if(stereo) - for(int i = 0; i < synth.buffersize; ++i) { //stereo - bypassl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume - * NoteVoicePar[nvoice].Panning * 2.0f; - bypassr[i] += tmpwaver[i] * NoteVoicePar[nvoice].Volume - * (1.0f - - NoteVoicePar[nvoice].Panning) * 2.0f; - } - else - for(int i = 0; i < synth.buffersize; ++i) //mono - bypassl[i] += tmpwavel[i] * NoteVoicePar[nvoice].Volume; - } - // check if there is necessary to process the voice longer (if the Amplitude envelope isn't finished) - if(NoteVoicePar[nvoice].AmpEnvelope) - if(NoteVoicePar[nvoice].AmpEnvelope->finished()) - KillVoice(nvoice); - } - - //Processing Global parameters - if(stereo) { - NoteGlobalPar.Filter->filter(outl, outr); - } else { //set the right channel=left channel - NoteGlobalPar.Filter->filter(outl, 0); - memcpy(outr, outl, synth.bufferbytes); - memcpy(bypassr, bypassl, synth.bufferbytes); - } - - for(int i = 0; i < synth.buffersize; ++i) { - outl[i] += bypassl[i]; - outr[i] += bypassr[i]; - } - - if(ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude, globalnewamplitude)) - // Amplitude Interpolation - for(int i = 0; i < synth.buffersize; ++i) { - float tmpvol = INTERPOLATE_AMPLITUDE(globaloldamplitude, - globalnewamplitude, - i, - synth.buffersize); - outl[i] *= tmpvol * NoteGlobalPar.Panning; - outr[i] *= tmpvol * (1.0f - NoteGlobalPar.Panning); - } - else - for(int i = 0; i < synth.buffersize; ++i) { - outl[i] *= globalnewamplitude * NoteGlobalPar.Panning; - outr[i] *= globalnewamplitude * (1.0f - NoteGlobalPar.Panning); - } - - //Apply the punch - if(NoteGlobalPar.Punch.Enabled != 0) - for(int i = 0; i < synth.buffersize; ++i) { - float punchamp = NoteGlobalPar.Punch.initialvalue - * NoteGlobalPar.Punch.t + 1.0f; - outl[i] *= punchamp; - outr[i] *= punchamp; - NoteGlobalPar.Punch.t -= NoteGlobalPar.Punch.dt; - if(NoteGlobalPar.Punch.t < 0.0f) { - NoteGlobalPar.Punch.Enabled = 0; - break; - } - } - - watch_punch(outl, synth.buffersize); - watch_after_add(outl,synth.buffersize); - - // Apply legato-specific sound signal modifications - legato.apply(*this, outl, outr); - - watch_legato(outl, synth.buffersize); - - // Check if the global amplitude is finished. - // If it does, disable the note - if(NoteGlobalPar.AmpEnvelope->finished()) { - for(int i = 0; i < synth.buffersize; ++i) { //fade-out - float tmp = 1.0f - (float)i / synth.buffersize_f; - outl[i] *= tmp; - outr[i] *= tmp; - } - KillNote(); - } - return 1; -} - - -/* - * Release the key (NoteOff) - */ -void ADnote::releasekey() -{ - for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) - NoteVoicePar[nvoice].releasekey(); - NoteGlobalPar.FreqEnvelope->releasekey(); - NoteGlobalPar.FilterEnvelope->releasekey(); - NoteGlobalPar.AmpEnvelope->releasekey(); -} - -/* - * Check if the note is finished - */ -bool ADnote::finished() const -{ - if(NoteEnabled == ON) - return 0; - else - return 1; -} - -void ADnote::entomb(void) -{ - NoteGlobalPar.AmpEnvelope->forceFinish(); -} - -void ADnote::Voice::releasekey() -{ - if(!Enabled) - return; - if(AmpEnvelope) - AmpEnvelope->releasekey(); - if(FreqEnvelope) - FreqEnvelope->releasekey(); - if(FilterEnvelope) - FilterEnvelope->releasekey(); - if(FMFreqEnvelope) - FMFreqEnvelope->releasekey(); - if(FMAmpEnvelope) - FMAmpEnvelope->releasekey(); -} - -void ADnote::Voice::kill(Allocator &memory, const SYNTH_T &synth) -{ - memory.devalloc(OscilSmp); - memory.dealloc(FreqEnvelope); - memory.dealloc(FreqLfo); - memory.dealloc(AmpEnvelope); - memory.dealloc(AmpLfo); - memory.dealloc(Filter); - memory.dealloc(FilterEnvelope); - memory.dealloc(FilterLfo); - memory.dealloc(FMFreqEnvelope); - memory.dealloc(FMAmpEnvelope); - - if((FMEnabled != FMTYPE::NONE) && (FMVoice < 0)) - memory.devalloc(FMSmp); - - if(VoiceOut) - memset(VoiceOut, 0, synth.bufferbytes); - //the buffer can't be safely deleted as it may be - //an input to another voice - - Enabled = OFF; -} - -void ADnote::Global::kill(Allocator &memory) -{ - memory.dealloc(FreqEnvelope); - memory.dealloc(FreqLfo); - memory.dealloc(AmpEnvelope); - memory.dealloc(AmpLfo); - memory.dealloc(Filter); - memory.dealloc(FilterEnvelope); - memory.dealloc(FilterLfo); -} - -void ADnote::Global::initparameters(const ADnoteGlobalParam &param, - const SYNTH_T &synth, - const AbsTime &time, - class Allocator &memory, - float basefreq, float velocity, - bool stereo, - WatchManager *wm, - const char *prefix) -{ - ScratchString pre = prefix; - FreqEnvelope = memory.alloc<Envelope>(*param.FreqEnvelope, basefreq, - synth.dt(), wm, (pre+"GlobalPar/FreqEnvelope/").c_str); - FreqLfo = memory.alloc<LFO>(*param.FreqLfo, basefreq, time, wm, - (pre+"GlobalPar/FreqLfo/").c_str); - - AmpEnvelope = memory.alloc<Envelope>(*param.AmpEnvelope, basefreq, - synth.dt(), wm, (pre+"GlobalPar/AmpEnvelope/").c_str); - AmpLfo = memory.alloc<LFO>(*param.AmpLfo, basefreq, time, wm, - (pre+"GlobalPar/AmpLfo/").c_str); - - Volume = dB2rap(param.Volume) - * VelF(velocity, param.PAmpVelocityScaleFunction); //sensing - - Filter = memory.alloc<ModFilter>(*param.GlobalFilter, synth, time, memory, - stereo, basefreq); - - FilterEnvelope = memory.alloc<Envelope>(*param.FilterEnvelope, basefreq, - synth.dt(), wm, (pre+"GlobalPar/FilterEnvelope/").c_str); - FilterLfo = memory.alloc<LFO>(*param.FilterLfo, basefreq, time, wm, - (pre+"GlobalPar/FilterLfo/").c_str); - - Filter->addMod(*FilterEnvelope); - Filter->addMod(*FilterLfo); - - { - Filter->updateSense(velocity, param.PFilterVelocityScale, - param.PFilterVelocityScaleFunction); - } -} - -}