From 8930e005df7a528b3d15866d2039e835f566a61d Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 1 Jun 2016 16:28:48 -1000 Subject: [PATCH] Integrate relevant evaluators into Voice state --- include/amuse/Envelope.hpp | 2 + include/amuse/Voice.hpp | 52 +++++++++++---------- lib/Envelope.cpp | 2 + lib/SoundMacroState.cpp | 6 +-- lib/Voice.cpp | 93 +++++++++++++++++++++++++------------- 5 files changed, 96 insertions(+), 59 deletions(-) diff --git a/include/amuse/Envelope.hpp b/include/amuse/Envelope.hpp index 79604a9..e865a38 100644 --- a/include/amuse/Envelope.hpp +++ b/include/amuse/Envelope.hpp @@ -26,12 +26,14 @@ private: double m_releaseTime = 0.02; /**< Time of release in seconds */ double m_releaseStartFactor = 0.0; /**< Level at whenever release event occurs */ double m_curTime = 0.0; /**< Current time of envelope stage in seconds */ + bool m_adsrSet = false; public: void reset(const ADSR* adsr); void reset(const ADSRDLS* adsr, int8_t note, int8_t vel); void keyOff(); float advance(double dt); bool isComplete() const {return m_phase == State::Complete;} + bool isAdsrSet() const {return m_adsrSet;} }; } diff --git a/include/amuse/Voice.hpp b/include/amuse/Voice.hpp index 7fa18f7..1098787 100644 --- a/include/amuse/Voice.hpp +++ b/include/amuse/Voice.hpp @@ -79,14 +79,14 @@ class Voice : public Entity float m_userSpan = 0.f; /**< User span of voice */ float m_curSpan = 0.f; /**< Current surround pan of voice */ float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */ - int32_t m_pitchWheelUp; /**< Up range for pitchwheel control in cents */ - int32_t m_pitchWheelDown; /**< Down range for pitchwheel control in cents */ - int32_t m_pitchWheelVal; /**< Current resolved pitchwheel delta for control */ + int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */ + int32_t m_pitchWheelDown = 600; /**< Down range for pitchwheel control in cents */ + int32_t m_pitchWheelVal = 0; /**< Current resolved pitchwheel delta for control */ int32_t m_curPitch; /**< Current base pitch in cents */ - bool m_pitchDirty; /**< m_curPitch has been updated and needs sending to voice */ + bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */ Envelope m_volAdsr; /**< Volume envelope */ - double m_envelopeTime; /**< time since last ENVELOPE command, -1 for no active volume-sweep */ + double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */ double m_envelopeDur; /**< requested duration of last ENVELOPE command */ float m_envelopeStart; /**< initial value for last ENVELOPE command */ float m_envelopeEnd; /**< final value for last ENVELOPE command */ @@ -96,42 +96,41 @@ class Voice : public Entity Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */ int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */ - float m_portamentoTime; /**< time since last portamento invocation, -1 for no active portamento-glide */ + float m_portamentoTime = -1.f; /**< time since last portamento invocation, -1 for no active portamento-glide */ int32_t m_portamentoTarget; /**< destination pitch for latest portamento invocation */ - uint32_t m_pitchSweep1; /**< Current value of PITCHSWEEP1 controller (in cents) */ - uint32_t m_pitchSweep2; /**< Current value of PITCHSWEEP2 controller (in cents) */ - int16_t m_pitchSweep1Add; /**< Value to add to PITCHSWEEP1 controller each cycle */ - int16_t m_pitchSweep2Add; /**< Value to add to PITCHSWEEP2 controller each cycle */ - uint8_t m_pitchSweep1Times; /**< Remaining times to advance PITCHSWEEP1 controller */ - uint8_t m_pitchSweep2Times; /**< Remaining times to advance PITCHSWEEP2 controller */ - uint8_t m_pitchSweep1It; /**< Current iteration of PITCHSWEEP1 controller */ - uint8_t m_pitchSweep2It; /**< Current iteration of PITCHSWEEP2 controller */ + uint32_t m_pitchSweep1 = 0; /**< Current value of PITCHSWEEP1 controller (in cents) */ + uint32_t m_pitchSweep2 = 0; /**< Current value of PITCHSWEEP2 controller (in cents) */ + int16_t m_pitchSweep1Add = 0; /**< Value to add to PITCHSWEEP1 controller each cycle */ + int16_t m_pitchSweep2Add = 0; /**< Value to add to PITCHSWEEP2 controller each cycle */ + uint8_t m_pitchSweep1Times = 0; /**< Remaining times to advance PITCHSWEEP1 controller */ + uint8_t m_pitchSweep2Times = 0; /**< Remaining times to advance PITCHSWEEP2 controller */ + uint8_t m_pitchSweep1It = 0; /**< Current iteration of PITCHSWEEP1 controller */ + uint8_t m_pitchSweep2It = 0; /**< Current iteration of PITCHSWEEP2 controller */ - float m_panningTime; /**< time since last PANNING command, -1 for no active pan-sweep */ + float m_panningTime = -1.f; /**< time since last PANNING command, -1 for no active pan-sweep */ float m_panningDur; /**< requested duration of last PANNING command */ uint8_t m_panPos; /**< initial pan value of last PANNING command */ int8_t m_panWidth; /**< delta pan value to target of last PANNING command */ - float m_spanningTime; /**< time since last SPANNING command, -1 for no active span-sweep */ + float m_spanningTime = -1.f; /**< time since last SPANNING command, -1 for no active span-sweep */ float m_spanningDur; /**< requested duration of last SPANNING command */ uint8_t m_spanPos; /**< initial pan value of last SPANNING command */ int8_t m_spanWidth; /**< delta pan value to target of last SPANNING command */ - int32_t m_vibratoLevel; /**< scale of vibrato effect (in cents) */ - int32_t m_vibratoModLevel; /**< scale of vibrato mod-wheel influence (in cents) */ - float m_vibratoPeriod; /**< vibrato wave period-time, 0.f will disable vibrato */ - bool m_vibratoModWheel; /**< vibrato scaled with mod-wheel if set */ + int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */ + int32_t m_vibratoModLevel = 0; /**< scale of vibrato mod-wheel influence (in cents) */ + float m_vibratoPeriod = 0.f; /**< vibrato wave period-time, 0.f will disable vibrato */ + bool m_vibratoModWheel = false; /**< vibrato scaled with mod-wheel if set */ - float m_tremoloScale; /**< minimum volume factor produced via LFO */ - float m_tremoloModScale; /**< minimum volume factor produced via LFO, scaled via mod wheel */ + float m_tremoloScale = 0.f; /**< minimum volume factor produced via LFO */ + float m_tremoloModScale = 0.f; /**< minimum volume factor produced via LFO, scaled via mod wheel */ - float m_lfoPeriods[2]; /**< time-periods for LFO1 and LFO2 */ + float m_lfoPeriods[2] = {}; /**< time-periods for LFO1 and LFO2 */ std::unique_ptr m_ctrlValsSelf; /**< Self-owned MIDI Controller values */ int8_t* m_extCtrlVals = nullptr; /**< MIDI Controller values (external storage) */ void _destroy(); - void _reset(); bool _checkSamplePos(bool& looped); void _doKeyOff(); void _macroKeyOff(); @@ -307,7 +306,10 @@ public: } /** Get ModWheel value on voice */ - int8_t getModWheel() const {return getCtrlValue(1);} + int8_t getModWheel() const + { + return m_state.m_modWheelSel ? m_state.m_modWheelSel.evaluate(*this, m_state) : getCtrlValue(1); + } /** 'install' external MIDI controller storage */ void installCtrlValues(int8_t* cvs) diff --git a/lib/Envelope.cpp b/lib/Envelope.cpp index 594a8b8..e53ed50 100644 --- a/lib/Envelope.cpp +++ b/lib/Envelope.cpp @@ -12,6 +12,7 @@ void Envelope::reset(const ADSR* adsr) m_sustainFactor = adsr->getSustain(); m_releaseTime = adsr->getRelease(); m_releaseStartFactor = 0.0; + m_adsrSet = true; } void Envelope::reset(const ADSRDLS* adsr, int8_t note, int8_t vel) @@ -23,6 +24,7 @@ void Envelope::reset(const ADSRDLS* adsr, int8_t note, int8_t vel) m_sustainFactor = adsr->getSustain(); m_releaseTime = adsr->getRelease(); m_releaseStartFactor = 0.0; + m_adsrSet = true; } void Envelope::keyOff() diff --git a/lib/SoundMacroState.cpp b/lib/SoundMacroState.cpp index 90d18ed..9bd970e 100644 --- a/lib/SoundMacroState.cpp +++ b/lib/SoundMacroState.cpp @@ -54,12 +54,12 @@ float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroSta case 130: /* LFO1 */ if (vox.m_lfoPeriods[0]) - thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[0] * 2.f * M_PIF); + thisValue = (std::sin(vox.m_voiceTime / vox.m_lfoPeriods[0] * 2.f * M_PIF) / 2.f + 1.f) * 127.f; break; case 131: /* LFO2 */ if (vox.m_lfoPeriods[1]) - thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[1] * 2.f * M_PIF); + thisValue = (std::sin(vox.m_voiceTime / vox.m_lfoPeriods[1] * 2.f * M_PIF) / 2.f + 1.f) * 127.f; break; case 132: /* Surround panning */ @@ -346,7 +346,7 @@ bool SoundMacroState::advance(Voice& vox, double dt) int16_t macroStep = *reinterpret_cast(&cmd.m_data[3]); //int8_t priority = cmd.m_data[5]; //int8_t maxVoices = cmd.m_data[6]; - + std::shared_ptr sibVox = vox.startChildMacro(addNote, macroId, macroStep); if (sibVox) m_lastPlayMacroVid = sibVox->vid(); diff --git a/lib/Voice.cpp b/lib/Voice.cpp index 2c5ae30..4a8668a 100644 --- a/lib/Voice.cpp +++ b/lib/Voice.cpp @@ -39,32 +39,6 @@ Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, //fprintf(stderr, "ALLOC %d\n", m_vid); } -void Voice::_reset() -{ - m_curAftertouch = 0; - m_pitchWheelUp = 600; - m_pitchWheelDown = 600; - m_pitchWheelVal = 0; - m_pitchDirty = true; - m_pitchSweep1 = 0; - m_pitchSweep1Times = 0; - m_pitchSweep1It = 0; - m_pitchSweep2 = 0; - m_pitchSweep2Times = 0; - m_pitchSweep2It = 0; - m_portamentoTime = -1.f; - m_envelopeTime = -1.f; - m_panningTime = -1.f; - m_spanningTime = -1.f; - m_vibratoLevel = 0; - m_vibratoModLevel = 0; - m_vibratoPeriod = 0.f; - m_tremoloScale = 0.f; - m_tremoloModScale = 0.f; - m_lfoPeriods[0] = 0.f; - m_lfoPeriods[1] = 0.f; -} - void Voice::_macroSampleEnd() { if (m_sampleEndTrap.macroId != 0xffff) @@ -124,8 +98,18 @@ bool Voice::_checkSamplePos(bool& looped) void Voice::_doKeyOff() { - m_volAdsr.keyOff(); - m_pitchAdsr.keyOff(); + if (m_state.m_inWait && m_state.m_keyoffWait) + { + if (m_volAdsr.isAdsrSet()) + m_volAdsr.keyOff(); + if (m_pitchAdsr.isAdsrSet()) + m_pitchAdsr.keyOff(); + } + else + { + m_volAdsr.keyOff(); + m_pitchAdsr.keyOff(); + } m_state.keyoffNotify(*this); } @@ -260,16 +244,55 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) if (m_envelopeCurve) t = (*m_envelopeCurve)[int(t*127.f)] / 127.f; m_curVol = clamp(0.f, (start * (1.0f - t)) + (end * t), 1.f); + + //printf("%d %f\n", m_vid, m_curVol); /* Done with envelope */ if (m_envelopeTime > m_envelopeDur) m_envelopeTime = -1.f; } + /* Dynamically evaluate per-sample SoundMacro parameters */ + float evalVol = m_state.m_volumeSel ? ((m_state.m_volumeSel.evaluate(*this, m_state) / 127.f) * m_curVol) : m_curVol; + + bool panDirty = false; + if (m_state.m_panSel) + { + float evalPan = (m_state.m_panSel.evaluate(*this, m_state) - 64.f) / 64.f; + if (evalPan != m_curPan) + { + m_curPan = evalPan; + panDirty = true; + } + } + if (m_state.m_spanSel) + { + float evalSpan = (m_state.m_spanSel.evaluate(*this, m_state) - 64.f) / 64.f; + if (evalSpan != m_curSpan) + { + m_curSpan = evalSpan; + panDirty = true; + } + } + if (m_state.m_reverbSel) + { + float evalRev = m_state.m_reverbSel.evaluate(*this, m_state) / 127.f; + if (evalRev != m_curReverbVol) + { + m_curReverbVol = evalRev; + panDirty = true; + } + } + if (panDirty) + _setPan(m_curPan); + + if (m_state.m_pitchWheelSel) + setPitchWheel(m_state.m_pitchWheelSel.evaluate(*this, m_state) / 127.f); + /* Factor in ADSR envelope state */ float adsr = m_volAdsr.advance(dt); m_lastLevel = m_nextLevel; - m_nextLevel = m_userVol * m_curVol * adsr * (m_state.m_curVel / 127.f); + m_nextLevel = m_userVol * evalVol * adsr * (m_state.m_curVel / 127.f); /* Apply tremolo */ if (m_state.m_tremoloSel && (m_tremoloScale || m_tremoloModScale)) @@ -396,6 +419,14 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data) /* Process SoundMacro; bootstrapping sample if needed */ bool dead = m_state.advance(*this, samples / m_sampleRate); + /* Process per-block evaluators here */ + if (m_state.m_pedalSel) + { + bool pedal = m_state.m_pedalSel.evaluate(*this, m_state) >= 64; + if (pedal != m_sustained) + setPedal(pedal); + } + if (m_curSample) { uint32_t blockSampleCount = _GetBlockSampleCount(m_curFormat); @@ -729,9 +760,9 @@ void Voice::startSample(int16_t sampId, int32_t offset) m_curSample = m_audioGroup.getSample(sampId); if (m_curSample) { - _reset(); m_sampleRate = m_curSample->first.m_sampleRate; m_curPitch = m_curSample->first.m_pitch; + m_pitchDirty = true; setPitchWheel(m_curPitchWheel); m_backendVoice->resetSampleRate(m_curSample->first.m_sampleRate); @@ -1044,7 +1075,7 @@ bool Voice::doPortamento(uint8_t newNote) pState = true; break; case 2: - pState = getCtrlValue(65) >= 64; + pState = (m_state.m_portamentoSel ? m_state.m_portamentoSel.evaluate(*this, m_state) : getCtrlValue(65)) >= 64; break; }