mirror of https://github.com/AxioDL/amuse.git
Add Channel-Portamento support
This commit is contained in:
parent
d132b1be34
commit
a047b1f6c8
|
@ -52,6 +52,7 @@ class Sequencer : public Entity
|
||||||
/** Voices corresponding to currently-pressed keys in channel */
|
/** Voices corresponding to currently-pressed keys in channel */
|
||||||
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
||||||
std::unordered_set<std::shared_ptr<Voice>> m_keyoffVoxs;
|
std::unordered_set<std::shared_ptr<Voice>> m_keyoffVoxs;
|
||||||
|
std::weak_ptr<Voice> m_lastVoice;
|
||||||
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
|
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
|
||||||
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
|
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
|
||||||
int8_t m_curProgram = 0; /**< MIDI program number */
|
int8_t m_curProgram = 0; /**< MIDI program number */
|
||||||
|
|
|
@ -145,9 +145,9 @@ class SoundMacroState
|
||||||
uint8_t m_midiSustain; /**< Sustain MIDI controller */
|
uint8_t m_midiSustain; /**< Sustain MIDI controller */
|
||||||
uint8_t m_midiRelease; /**< Release MIDI controller */
|
uint8_t m_midiRelease; /**< Release MIDI controller */
|
||||||
|
|
||||||
uint8_t m_portamentoMode; /**< (0: Off, 1: On, 2: MIDI specified) */
|
uint8_t m_portamentoMode = 2; /**< (0: Off, 1: On, 2: MIDI specified) */
|
||||||
uint8_t m_portamentoType; /**< (0: New key pressed while old key pressed, 1: Always) */
|
uint8_t m_portamentoType = 0; /**< (0: New key pressed while old key pressed, 1: Always) */
|
||||||
float m_portamentoTime; /**< portamento transition time, 0.f will perform legato */
|
float m_portamentoTime = 0.5f; /**< portamento transition time, 0.f will perform legato */
|
||||||
|
|
||||||
/** Used to build a multi-component formula for overriding controllers */
|
/** Used to build a multi-component formula for overriding controllers */
|
||||||
struct Evaluator
|
struct Evaluator
|
||||||
|
|
|
@ -96,6 +96,9 @@ class Voice : public Entity
|
||||||
Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */
|
Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */
|
||||||
int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */
|
int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */
|
||||||
|
|
||||||
|
float m_portamentoTime; /**< 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_pitchSweep1; /**< Current value of PITCHSWEEP1 controller (in cents) */
|
||||||
uint32_t m_pitchSweep2; /**< Current value of PITCHSWEEP2 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_pitchSweep1Add; /**< Value to add to PITCHSWEEP1 controller each cycle */
|
||||||
|
@ -275,6 +278,9 @@ public:
|
||||||
/** Get note played on voice */
|
/** Get note played on voice */
|
||||||
uint8_t getLastNote() const {return m_state.m_initKey;}
|
uint8_t getLastNote() const {return m_state.m_initKey;}
|
||||||
|
|
||||||
|
/** Do portamento glide; returns `false` if portamento disabled */
|
||||||
|
bool doPortamento(uint8_t newNote);
|
||||||
|
|
||||||
/** Get MIDI Controller value on voice */
|
/** Get MIDI Controller value on voice */
|
||||||
int8_t getCtrlValue(uint8_t ctrl) const
|
int8_t getCtrlValue(uint8_t ctrl) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -135,10 +135,24 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
if (!m_page)
|
if (!m_page)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
||||||
|
if (std::shared_ptr<Voice> lastVoice = m_lastVoice.lock())
|
||||||
|
{
|
||||||
|
uint8_t lastNote = lastVoice->getLastNote();
|
||||||
|
if (lastVoice->doPortamento(note))
|
||||||
|
{
|
||||||
|
m_chanVoxs.erase(lastNote);
|
||||||
|
m_chanVoxs[note] = lastVoice;
|
||||||
|
return lastVoice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure keyoff sent first */
|
/* Ensure keyoff sent first */
|
||||||
auto keySearch = m_chanVoxs.find(note);
|
auto keySearch = m_chanVoxs.find(note);
|
||||||
if (keySearch != m_chanVoxs.cend())
|
if (keySearch != m_chanVoxs.cend())
|
||||||
{
|
{
|
||||||
|
if (keySearch->second == m_lastVoice.lock())
|
||||||
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
keySearch->second->setPedal(false);
|
keySearch->second->setPedal(false);
|
||||||
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
|
@ -167,6 +181,8 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
|
|
||||||
if (m_ctrlVals[64] > 64)
|
if (m_ctrlVals[64] > 64)
|
||||||
(*ret)->setPedal(true);
|
(*ret)->setPedal(true);
|
||||||
|
|
||||||
|
m_lastVoice = *ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *ret;
|
return *ret;
|
||||||
|
@ -189,6 +205,8 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
||||||
if (keySearch == m_chanVoxs.cend())
|
if (keySearch == m_chanVoxs.cend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (keySearch->second == m_lastVoice.lock())
|
||||||
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
m_chanVoxs.erase(keySearch);
|
m_chanVoxs.erase(keySearch);
|
||||||
|
@ -303,6 +321,8 @@ void Sequencer::ChannelState::allOff()
|
||||||
{
|
{
|
||||||
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;)
|
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;)
|
||||||
{
|
{
|
||||||
|
if (it->second == m_lastVoice.lock())
|
||||||
|
m_lastVoice.reset();
|
||||||
it->second->keyOff();
|
it->second->keyOff();
|
||||||
m_keyoffVoxs.emplace(std::move(it->second));
|
m_keyoffVoxs.emplace(std::move(it->second));
|
||||||
it = m_chanVoxs.erase(it);
|
it = m_chanVoxs.erase(it);
|
||||||
|
@ -355,6 +375,8 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
Voice* vox = it->second.get();
|
Voice* vox = it->second.get();
|
||||||
if (vox->m_keygroup == kg)
|
if (vox->m_keygroup == kg)
|
||||||
{
|
{
|
||||||
|
if (it->second == m_lastVoice.lock())
|
||||||
|
m_lastVoice.reset();
|
||||||
if (now)
|
if (now)
|
||||||
{
|
{
|
||||||
it = m_chanVoxs.erase(it);
|
it = m_chanVoxs.erase(it);
|
||||||
|
|
|
@ -135,7 +135,8 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
||||||
m_loopCountdown = -1;
|
m_loopCountdown = -1;
|
||||||
m_lastPlayMacroVid = -1;
|
m_lastPlayMacroVid = -1;
|
||||||
m_useAdsrControllers = false;
|
m_useAdsrControllers = false;
|
||||||
m_portamentoMode = 0;
|
m_portamentoMode = 2;
|
||||||
|
m_portamentoTime = 0.5f;
|
||||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
m_header = *reinterpret_cast<const Header*>(ptr);
|
||||||
if (swapData)
|
if (swapData)
|
||||||
m_header.swapBig();
|
m_header.swapBig();
|
||||||
|
|
|
@ -52,6 +52,7 @@ void Voice::_reset()
|
||||||
m_pitchSweep2 = 0;
|
m_pitchSweep2 = 0;
|
||||||
m_pitchSweep2Times = 0;
|
m_pitchSweep2Times = 0;
|
||||||
m_pitchSweep2It = 0;
|
m_pitchSweep2It = 0;
|
||||||
|
m_portamentoTime = -1.f;
|
||||||
m_envelopeTime = -1.f;
|
m_envelopeTime = -1.f;
|
||||||
m_panningTime = -1.f;
|
m_panningTime = -1.f;
|
||||||
m_spanningTime = -1.f;
|
m_spanningTime = -1.f;
|
||||||
|
@ -333,9 +334,24 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
|
||||||
newPitch = m_curPitch;
|
newPitch = m_curPitch;
|
||||||
refresh |= m_pitchDirty;
|
refresh |= m_pitchDirty;
|
||||||
m_pitchDirty = false;
|
m_pitchDirty = false;
|
||||||
|
if (m_portamentoTime >= 0.f)
|
||||||
|
{
|
||||||
|
m_portamentoTime += dt;
|
||||||
|
float t = std::max(0.f, std::min(1.f, m_portamentoTime / m_state.m_portamentoTime));
|
||||||
|
|
||||||
|
newPitch = (m_curPitch * (1.0f - t)) + (m_portamentoTarget * t);
|
||||||
|
refresh = true;
|
||||||
|
|
||||||
|
/* Done with portamento */
|
||||||
|
if (m_portamentoTime > m_state.m_portamentoTime)
|
||||||
|
{
|
||||||
|
m_portamentoTime = -1.f;
|
||||||
|
m_curPitch = m_portamentoTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_pitchEnv)
|
if (m_pitchEnv)
|
||||||
{
|
{
|
||||||
newPitch = m_curPitch * m_pitchAdsr.advance(dt);
|
newPitch *= m_pitchAdsr.advance(dt);
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +881,7 @@ void Voice::startFadeIn(double dur, float vol, const Curve* envCurve)
|
||||||
|
|
||||||
void Voice::startPanning(double dur, uint8_t panPos, int8_t panWidth)
|
void Voice::startPanning(double dur, uint8_t panPos, int8_t panWidth)
|
||||||
{
|
{
|
||||||
m_panningTime = m_voiceTime;
|
m_panningTime = 0.f;
|
||||||
m_panningDur = dur;
|
m_panningDur = dur;
|
||||||
m_panPos = panPos;
|
m_panPos = panPos;
|
||||||
m_panWidth = panWidth;
|
m_panWidth = panWidth;
|
||||||
|
@ -873,7 +889,7 @@ void Voice::startPanning(double dur, uint8_t panPos, int8_t panWidth)
|
||||||
|
|
||||||
void Voice::startSpanning(double dur, uint8_t spanPos, int8_t spanWidth)
|
void Voice::startSpanning(double dur, uint8_t spanPos, int8_t spanWidth)
|
||||||
{
|
{
|
||||||
m_spanningTime = m_voiceTime;
|
m_spanningTime = 0.f;
|
||||||
m_spanningDur = dur;
|
m_spanningDur = dur;
|
||||||
m_spanPos = spanPos;
|
m_spanPos = spanPos;
|
||||||
m_spanWidth = spanWidth;
|
m_spanWidth = spanWidth;
|
||||||
|
@ -1015,6 +1031,32 @@ void Voice::setAftertouch(uint8_t aftertouch)
|
||||||
vox->setAftertouch(aftertouch);
|
vox->setAftertouch(aftertouch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Voice::doPortamento(uint8_t newNote)
|
||||||
|
{
|
||||||
|
bool pState;
|
||||||
|
switch (m_state.m_portamentoMode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
pState = false;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pState = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pState = getCtrlValue(65) >= 64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pState)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_portamentoTime = 0.f;
|
||||||
|
m_portamentoTarget = newNote * 100;
|
||||||
|
m_state.m_initKey = newNote;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Voice::_notifyCtrlChange(uint8_t ctrl, int8_t val)
|
void Voice::_notifyCtrlChange(uint8_t ctrl, int8_t val)
|
||||||
{
|
{
|
||||||
if (ctrl == 0x40)
|
if (ctrl == 0x40)
|
||||||
|
@ -1024,10 +1066,6 @@ void Voice::_notifyCtrlChange(uint8_t ctrl, int8_t val)
|
||||||
else
|
else
|
||||||
setPedal(false);
|
setPedal(false);
|
||||||
}
|
}
|
||||||
else if (ctrl == 0x41)
|
|
||||||
{
|
|
||||||
printf("PORTAMENTO %d\n", val);
|
|
||||||
}
|
|
||||||
else if (ctrl == 0x5b)
|
else if (ctrl == 0x5b)
|
||||||
{
|
{
|
||||||
setReverbVol(val / 127.f);
|
setReverbVol(val / 127.f);
|
||||||
|
|
Loading…
Reference in New Issue