Default volume and pan CC values, MIDI controller ADSR mode

This commit is contained in:
Jack Andersen 2016-06-08 15:22:18 -10:00
parent 8930e005df
commit e8c6418633
6 changed files with 187 additions and 22 deletions

View File

@ -5,6 +5,7 @@
namespace amuse
{
class Voice;
/** Per-sample state tracker for ADSR envelope data */
class Envelope
@ -30,7 +31,9 @@ private:
public:
void reset(const ADSR* adsr);
void reset(const ADSRDLS* adsr, int8_t note, int8_t vel);
void keyOff(const Voice& vox);
void keyOff();
float advance(double dt, const Voice& vox);
float advance(double dt);
bool isComplete() const {return m_phase == State::Complete;}
bool isAdsrSet() const {return m_adsrSet;}

View File

@ -14,6 +14,7 @@ class Voice;
class SoundMacroState
{
friend class Voice;
friend class Envelope;
/** SoundMacro header */
struct Header

View File

@ -32,6 +32,7 @@ class Voice : public Entity
friend class Engine;
friend class Sequencer;
friend class SoundMacroState;
friend class Envelope;
int m_vid; /**< VoiceID of this voice instance */
bool m_emitter; /**< Voice is part of an Emitter */
Submix* m_submix = nullptr; /**< Submix this voice outputs to (or NULL for the main output mix) */
@ -71,7 +72,8 @@ class Voice : public Entity
bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */
uint8_t m_curAftertouch = 0; /**< Aftertouch value (key pressure when 'bottoming out') */
float m_userVol = 1.f; /**< User volume of voice */
float m_targetUserVol = 1.f; /**< Target user volume of voice (slewed to prevent audible aliasing) */
float m_curUserVol = 1.f; /**< Current user volume of voice */
float m_curVol = 1.f; /**< Current volume of voice */
float m_curReverbVol = 0.f; /**< Current reverb volume of voice */
float m_userPan = 0.f; /**< User pan of voice */

View File

@ -1,8 +1,26 @@
#include "amuse/Envelope.hpp"
#include "amuse/Voice.hpp"
namespace amuse
{
static int32_t MIDItoTIME[104] =
{ /* [0..103] -> milliseconds */
0, 10, 20, 30, 40, 50, 60, 70,
80, 90, 100, 110, 110, 120, 130, 140,
150, 160, 170, 190, 200, 220, 230, 250,
270, 290, 310, 330, 350, 380, 410, 440,
470, 500, 540, 580, 620, 660, 710, 760,
820, 880, 940, 1000, 1000, 1100, 1200, 1300,
1400, 1500, 1600, 1700, 1800, 2000, 2100, 2300,
2400, 2600, 2800, 3000, 3200, 3500, 3700, 4000,
4300, 4600, 4900, 5300, 5700, 6100, 6500, 7000,
7500, 8100, 8600, 9300, 9900, 10000, 11000, 12000,
13000, 14000, 15000, 16000, 17000, 18000, 19000, 21000,
22000, 24000, 26000, 28000, 30000, 32000, 34000, 37000,
39000, 42000, 45000, 49000, 50000, 55000, 60000, 65000
};
void Envelope::reset(const ADSR* adsr)
{
m_phase = State::Attack;
@ -27,13 +45,23 @@ void Envelope::reset(const ADSRDLS* adsr, int8_t note, int8_t vel)
m_adsrSet = true;
}
void Envelope::keyOff(const Voice& vox)
{
double releaseTime = m_releaseTime;
if (vox.m_state.m_useAdsrControllers)
releaseTime = MIDItoTIME[clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiRelease)), 103)] / 1000.0;
m_phase = (releaseTime != 0.0) ? State::Release : State::Complete;
m_curTime = 0.0;
}
void Envelope::keyOff()
{
m_phase = (m_releaseTime != 0.0) ? State::Release : State::Complete;
m_curTime = 0.0;
}
float Envelope::advance(double dt)
float Envelope::advance(double dt, const Voice& vox)
{
double thisTime = m_curTime;
m_curTime += dt;
@ -42,14 +70,18 @@ float Envelope::advance(double dt)
{
case State::Attack:
{
if (m_attackTime == 0.0)
double attackTime = m_attackTime;
if (vox.m_state.m_useAdsrControllers)
attackTime = MIDItoTIME[clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiAttack)), 103)] / 1000.0;
if (attackTime == 0.0)
{
m_phase = State::Decay;
m_curTime = 0.0;
m_releaseStartFactor = 1.f;
return 1.f;
}
double attackFac = thisTime / m_attackTime;
double attackFac = thisTime / attackTime;
if (attackFac >= 1.0)
{
m_phase = State::Decay;
@ -62,22 +94,115 @@ float Envelope::advance(double dt)
}
case State::Decay:
{
if (m_decayTime == 0.0)
double decayTime = m_decayTime;
if (vox.m_state.m_useAdsrControllers)
decayTime = MIDItoTIME[clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiDecay)), 103)] / 1000.0;
double sustainFactor = m_sustainFactor;
if (vox.m_state.m_useAdsrControllers)
sustainFactor = clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiSustain)), 127) / 127.0;
if (decayTime == 0.0)
{
m_phase = State::Sustain;
m_curTime = 0.0;
m_releaseStartFactor = m_sustainFactor;
return m_sustainFactor;
m_releaseStartFactor = sustainFactor;
return sustainFactor;
}
double decayFac = thisTime / m_decayTime;
double decayFac = thisTime / decayTime;
if (decayFac >= 1.0)
{
m_phase = State::Sustain;
m_curTime = 0.0;
m_releaseStartFactor = m_sustainFactor;
return m_sustainFactor;
m_releaseStartFactor = sustainFactor;
return sustainFactor;
}
m_releaseStartFactor = (1.0 - decayFac) + decayFac * m_sustainFactor;
m_releaseStartFactor = (1.0 - decayFac) + decayFac * sustainFactor;
return m_releaseStartFactor;
}
case State::Sustain:
{
double sustainFactor = m_sustainFactor;
if (vox.m_state.m_useAdsrControllers)
sustainFactor = clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiSustain)), 127) / 127.0;
return sustainFactor;
}
case State::Release:
{
double releaseTime = m_releaseTime;
if (vox.m_state.m_useAdsrControllers)
releaseTime = MIDItoTIME[clamp(0, int(vox.getCtrlValue(vox.m_state.m_midiRelease)), 103)] / 1000.0;
if (releaseTime == 0.0)
{
m_phase = State::Complete;
return 0.f;
}
double releaseFac = thisTime / releaseTime;
if (releaseFac >= 1.0)
{
m_phase = State::Complete;
return 0.f;
}
return std::min(m_releaseStartFactor, 1.0 - releaseFac);
}
case State::Complete:
default:
return 0.f;
}
}
float Envelope::advance(double dt)
{
double thisTime = m_curTime;
m_curTime += dt;
switch (m_phase)
{
case State::Attack:
{
double attackTime = m_attackTime;
if (attackTime == 0.0)
{
m_phase = State::Decay;
m_curTime = 0.0;
m_releaseStartFactor = 1.f;
return 1.f;
}
double attackFac = thisTime / attackTime;
if (attackFac >= 1.0)
{
m_phase = State::Decay;
m_curTime = 0.0;
m_releaseStartFactor = 1.f;
return 1.f;
}
m_releaseStartFactor = attackFac;
return attackFac;
}
case State::Decay:
{
double decayTime = m_decayTime;
double sustainFactor = m_sustainFactor;
if (decayTime == 0.0)
{
m_phase = State::Sustain;
m_curTime = 0.0;
m_releaseStartFactor = sustainFactor;
return sustainFactor;
}
double decayFac = thisTime / decayTime;
if (decayFac >= 1.0)
{
m_phase = State::Sustain;
m_curTime = 0.0;
m_releaseStartFactor = sustainFactor;
return sustainFactor;
}
m_releaseStartFactor = (1.0 - decayFac) + decayFac * sustainFactor;
return m_releaseStartFactor;
}
case State::Sustain:
@ -86,12 +211,14 @@ float Envelope::advance(double dt)
}
case State::Release:
{
if (m_releaseTime == 0.0)
double releaseTime = m_releaseTime;
if (releaseTime == 0.0)
{
m_phase = State::Complete;
return 0.f;
}
double releaseFac = thisTime / m_releaseTime;
double releaseFac = thisTime / releaseTime;
if (releaseFac >= 1.0)
{
m_phase = State::Complete;

View File

@ -96,6 +96,8 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
m_curVol = m_setup.volume / 127.f;
m_curPan = m_setup.panning / 64.f - 1.f;
m_ctrlVals[7] = 127;
m_ctrlVals[10] = 64;
m_ctrlVals[0x5b] = m_setup.reverb;
m_ctrlVals[0x5d] = m_setup.chorus;
}

View File

@ -100,14 +100,14 @@ void Voice::_doKeyOff()
{
if (m_state.m_inWait && m_state.m_keyoffWait)
{
if (m_volAdsr.isAdsrSet())
m_volAdsr.keyOff();
if (m_volAdsr.isAdsrSet() || m_state.m_useAdsrControllers)
m_volAdsr.keyOff(*this);
if (m_pitchAdsr.isAdsrSet())
m_pitchAdsr.keyOff();
}
else
{
m_volAdsr.keyOff();
m_volAdsr.keyOff(*this);
m_pitchAdsr.keyOff();
}
m_state.keyoffNotify(*this);
@ -289,10 +289,39 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
if (m_state.m_pitchWheelSel)
setPitchWheel(m_state.m_pitchWheelSel.evaluate(*this, m_state) / 127.f);
/* Process user volume slew */
if (m_engine.m_ampMode == AmplitudeMode::PerSample)
{
if (m_targetUserVol != m_curUserVol)
{
float samplesPer5Ms = m_sampleRate * 5.f / 1000.f;
if (samplesPer5Ms > 1.f)
{
float adjRate = 1.f / samplesPer5Ms;
if (m_targetUserVol < m_curUserVol)
{
m_curUserVol -= adjRate;
if (m_targetUserVol > m_curUserVol)
m_curUserVol = m_targetUserVol;
}
else
{
m_curUserVol += adjRate;
if (m_targetUserVol < m_curUserVol)
m_curUserVol = m_targetUserVol;
}
}
else
m_curUserVol = m_targetUserVol;
}
}
else
m_curUserVol = m_targetUserVol;
/* Factor in ADSR envelope state */
float adsr = m_volAdsr.advance(dt);
float adsr = m_volAdsr.advance(dt, *this);
m_lastLevel = m_nextLevel;
m_nextLevel = m_userVol * evalVol * adsr * (m_state.m_curVel / 127.f);
m_nextLevel = m_curUserVol * evalVol * adsr * (m_state.m_curVel / 127.f);
/* Apply tremolo */
if (m_state.m_tremoloSel && (m_tremoloScale || m_tremoloModScale))
@ -585,6 +614,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
m_voxState = VoiceState::Dead;
m_backendVoice->stop();
}
return samples;
}
@ -606,7 +636,7 @@ std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep,
_destroyVoice(vox);
return {};
}
(*vox)->setVolume(m_userVol);
(*vox)->setVolume(m_targetUserVol);
(*vox)->setPan(m_userPan);
(*vox)->setSurroundPan(m_userSpan);
return *vox;
@ -821,7 +851,7 @@ void Voice::stopSample()
void Voice::setVolume(float vol)
{
m_userVol = clamp(0.f, vol, 1.f);
m_targetUserVol = clamp(0.f, vol, 1.f);
for (std::shared_ptr<Voice>& vox : m_childVoices)
vox->setVolume(vol);
}
@ -1000,7 +1030,7 @@ void Voice::setAdsr(ObjectId adsrId, bool dls)
{
m_volAdsr.reset(adsr, m_state.m_initKey, m_state.m_initVel);
if (m_voxState == VoiceState::KeyOff)
m_volAdsr.keyOff();
m_volAdsr.keyOff(*this);
}
}
else
@ -1010,7 +1040,7 @@ void Voice::setAdsr(ObjectId adsrId, bool dls)
{
m_volAdsr.reset(adsr);
if (m_voxState == VoiceState::KeyOff)
m_volAdsr.keyOff();
m_volAdsr.keyOff(*this);
}
}
}