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 */
|
||||
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
||||
std::unordered_set<std::shared_ptr<Voice>> m_keyoffVoxs;
|
||||
std::weak_ptr<Voice> m_lastVoice;
|
||||
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
|
||||
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
|
||||
int8_t m_curProgram = 0; /**< MIDI program number */
|
||||
|
|
|
@ -145,9 +145,9 @@ class SoundMacroState
|
|||
uint8_t m_midiSustain; /**< Sustain MIDI controller */
|
||||
uint8_t m_midiRelease; /**< Release MIDI controller */
|
||||
|
||||
uint8_t m_portamentoMode; /**< (0: Off, 1: On, 2: MIDI specified) */
|
||||
uint8_t m_portamentoType; /**< (0: New key pressed while old key pressed, 1: Always) */
|
||||
float m_portamentoTime; /**< portamento transition time, 0.f will perform legato */
|
||||
uint8_t m_portamentoMode = 2; /**< (0: Off, 1: On, 2: MIDI specified) */
|
||||
uint8_t m_portamentoType = 0; /**< (0: New key pressed while old key pressed, 1: Always) */
|
||||
float m_portamentoTime = 0.5f; /**< portamento transition time, 0.f will perform legato */
|
||||
|
||||
/** Used to build a multi-component formula for overriding controllers */
|
||||
struct Evaluator
|
||||
|
|
|
@ -96,6 +96,9 @@ 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 */
|
||||
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 */
|
||||
|
@ -275,6 +278,9 @@ public:
|
|||
/** Get note played on voice */
|
||||
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 */
|
||||
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)
|
||||
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 */
|
||||
auto keySearch = m_chanVoxs.find(note);
|
||||
if (keySearch != m_chanVoxs.cend())
|
||||
{
|
||||
if (keySearch->second == m_lastVoice.lock())
|
||||
m_lastVoice.reset();
|
||||
keySearch->second->keyOff();
|
||||
keySearch->second->setPedal(false);
|
||||
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)
|
||||
(*ret)->setPedal(true);
|
||||
|
||||
m_lastVoice = *ret;
|
||||
}
|
||||
|
||||
return *ret;
|
||||
|
@ -189,6 +205,8 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
|||
if (keySearch == m_chanVoxs.cend())
|
||||
return;
|
||||
|
||||
if (keySearch->second == m_lastVoice.lock())
|
||||
m_lastVoice.reset();
|
||||
keySearch->second->keyOff();
|
||||
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||
m_chanVoxs.erase(keySearch);
|
||||
|
@ -303,6 +321,8 @@ void Sequencer::ChannelState::allOff()
|
|||
{
|
||||
for (auto it = m_chanVoxs.begin() ; it != m_chanVoxs.end() ;)
|
||||
{
|
||||
if (it->second == m_lastVoice.lock())
|
||||
m_lastVoice.reset();
|
||||
it->second->keyOff();
|
||||
m_keyoffVoxs.emplace(std::move(it->second));
|
||||
it = m_chanVoxs.erase(it);
|
||||
|
@ -355,6 +375,8 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
|||
Voice* vox = it->second.get();
|
||||
if (vox->m_keygroup == kg)
|
||||
{
|
||||
if (it->second == m_lastVoice.lock())
|
||||
m_lastVoice.reset();
|
||||
if (now)
|
||||
{
|
||||
it = m_chanVoxs.erase(it);
|
||||
|
|
|
@ -135,7 +135,8 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
|||
m_loopCountdown = -1;
|
||||
m_lastPlayMacroVid = -1;
|
||||
m_useAdsrControllers = false;
|
||||
m_portamentoMode = 0;
|
||||
m_portamentoMode = 2;
|
||||
m_portamentoTime = 0.5f;
|
||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
||||
if (swapData)
|
||||
m_header.swapBig();
|
||||
|
|
|
@ -52,6 +52,7 @@ void Voice::_reset()
|
|||
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;
|
||||
|
@ -333,9 +334,24 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
|
|||
newPitch = m_curPitch;
|
||||
refresh |= m_pitchDirty;
|
||||
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)
|
||||
{
|
||||
newPitch = m_curPitch * m_pitchAdsr.advance(dt);
|
||||
newPitch *= m_pitchAdsr.advance(dt);
|
||||
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)
|
||||
{
|
||||
m_panningTime = m_voiceTime;
|
||||
m_panningTime = 0.f;
|
||||
m_panningDur = dur;
|
||||
m_panPos = panPos;
|
||||
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)
|
||||
{
|
||||
m_spanningTime = m_voiceTime;
|
||||
m_spanningTime = 0.f;
|
||||
m_spanningDur = dur;
|
||||
m_spanPos = spanPos;
|
||||
m_spanWidth = spanWidth;
|
||||
|
@ -1015,6 +1031,32 @@ void Voice::setAftertouch(uint8_t 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)
|
||||
{
|
||||
if (ctrl == 0x40)
|
||||
|
@ -1024,10 +1066,6 @@ void Voice::_notifyCtrlChange(uint8_t ctrl, int8_t val)
|
|||
else
|
||||
setPedal(false);
|
||||
}
|
||||
else if (ctrl == 0x41)
|
||||
{
|
||||
printf("PORTAMENTO %d\n", val);
|
||||
}
|
||||
else if (ctrl == 0x5b)
|
||||
{
|
||||
setReverbVol(val / 127.f);
|
||||
|
|
Loading…
Reference in New Issue