/* ============================================================================== shifter_voice.cpp Created: 25 Oct 2025 2:09:42pm Author: mickl ============================================================================== */ #include "shifter_voice.h" static inline float mtof(float m) { return powf(2, (m - 69.0f) / 12.0f) * 440.0f; } void ShifterVoice::Init(float sample_rate) { portamento_.Init(sample_rate, 0.05f); //default portamento time amplitude_envelope_.Init(sample_rate); amplitude_envelope_.SetAttackTime(0.2f); amplitude_envelope_.SetDecayTime(0.2f); amplitude_envelope_.SetReleaseTime(1.0f); onoff_ = false; overflow_ = false; current_midi = 60; current_period_ = 48000.0f / mtof((float)current_midi); current_amplitude = 0.0f; period_counter = 0.0f; panning = 0.5f; } bool ShifterVoice::IsActive() { return amplitude_envelope_.IsRunning(); } void ShifterVoice::Trigger(int midi_note) { current_midi = midi_note; // Retrigger envelope amplitude_envelope_.Retrigger(false); onoff_ = true; panning = rand() / (float)RAND_MAX; } void ShifterVoice::Release() { onoff_ = false; } void ShifterVoice::Process() { current_amplitude = amplitude_envelope_.Process(onoff_); current_period_ = 48000.0f / mtof(portamento_.Process((float)current_midi)); period_counter++; overflow_ = period_counter >= current_period_; if (overflow_) { period_counter -= current_period_; } } float ShifterVoice::CurrentAmplitude() { return current_amplitude; } float ShifterVoice::CurrentPeriod() { return current_period_; } bool ShifterVoice::PeriodOverflow() { return overflow_; } void ShifterVoice::SetPortamentoTime(float time) { portamento_.SetHtime(time); } void ShifterVoice::SetAdsrTimes(float attack, float decay, float release) { amplitude_envelope_.SetAttackTime(attack); amplitude_envelope_.SetDecayTime(decay); amplitude_envelope_.SetReleaseTime(release); amplitude_envelope_.SetSustainLevel(1.0); } float ShifterVoice::GetPanning(int channel) const { switch (channel) { default: case 0: return panning < .5 ? 1.0 : 2.0f - (panning * 2.0f); case 1: return panning > .5 ? 1.0 : panning * 2.0f; } }