Bug fixes in sequencer and SoundMacro event trapping

This commit is contained in:
Jack Andersen 2016-05-15 16:40:18 -10:00
parent 2c3c9d3885
commit 44bb7a155b
9 changed files with 326 additions and 193 deletions

View File

@ -195,8 +195,8 @@ struct AppCallback : boo::IApplicationCallback
if (m_seq) if (m_seq)
voxCount = m_seq->getVoiceCount(); voxCount = m_seq->getVoiceCount();
printf("\r " printf("\r "
"\r %" PRISize " Setup %d, Chan %d, VOL: %d%%\r", voxCount, "\r %" PRISize " Setup %d, Chan %d, Octave: %d, Vel: %d, VOL: %d%%\r", voxCount,
m_setupId, m_chanId, int(std::rint(m_volume * 100))); m_setupId, m_chanId, m_octave, m_velocity, int(std::rint(m_volume * 100)));
fflush(stdout); fflush(stdout);
} }
@ -353,6 +353,32 @@ struct AppCallback : boo::IApplicationCallback
} }
} }
void charKeyDownRepeat(unsigned long charCode)
{
if (m_seq && m_chanId != -1)
{
switch (charCode)
{
case 'z':
m_octave = amuse::clamp(-1, m_octave - 1, 8);
m_updateDisp = true;
break;
case 'x':
m_octave = amuse::clamp(-1, m_octave + 1, 8);
m_updateDisp = true;
break;
case 'c':
m_velocity = amuse::clamp(0, m_velocity - 1, 127);
m_updateDisp = true;
break;
case 'v':
m_velocity = amuse::clamp(0, m_velocity + 1, 127);
m_updateDisp = true;
break;
}
}
}
void charKeyDown(unsigned long charCode) void charKeyDown(unsigned long charCode)
{ {
charCode = tolower(charCode); charCode = tolower(charCode);
@ -381,15 +407,19 @@ struct AppCallback : boo::IApplicationCallback
{ {
case 'z': case 'z':
m_octave = amuse::clamp(-1, m_octave - 1, 8); m_octave = amuse::clamp(-1, m_octave - 1, 8);
m_updateDisp = true;
break; break;
case 'x': case 'x':
m_octave = amuse::clamp(-1, m_octave + 1, 8); m_octave = amuse::clamp(-1, m_octave + 1, 8);
m_updateDisp = true;
break; break;
case 'c': case 'c':
m_velocity = amuse::clamp(0, m_velocity - 1, 127); m_velocity = amuse::clamp(0, m_velocity - 1, 127);
m_updateDisp = true;
break; break;
case 'v': case 'v':
m_velocity = amuse::clamp(0, m_velocity + 1, 127); m_velocity = amuse::clamp(0, m_velocity + 1, 127);
m_updateDisp = true;
break; break;
case '\t': case '\t':
m_seq->setCtrlValue(m_chanId, 64, 127); m_seq->setCtrlValue(m_chanId, 64, 127);
@ -637,8 +667,9 @@ struct AppCallback : boo::IApplicationCallback
void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
{ {
if (isRepeat) if (isRepeat)
return; m_app.charKeyDownRepeat(charCode);
m_app.charKeyDown(charCode); else
m_app.charKeyDown(charCode);
} }
void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods) void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods)
@ -661,6 +692,8 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f); m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f);
if (m_app.m_vox) if (m_app.m_vox)
m_app.m_vox->setVolume(m_app.m_volume); m_app.m_vox->setVolume(m_app.m_volume);
if (m_app.m_seq)
m_app.m_seq->setVolume(m_app.m_volume);
m_app.m_updateDisp = true; m_app.m_updateDisp = true;
break; break;
case boo::ESpecialKey::Down: case boo::ESpecialKey::Down:
@ -668,6 +701,8 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f); m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f);
if (m_app.m_vox) if (m_app.m_vox)
m_app.m_vox->setVolume(m_app.m_volume); m_app.m_vox->setVolume(m_app.m_volume);
if (m_app.m_seq)
m_app.m_seq->setVolume(m_app.m_volume);
m_app.m_updateDisp = true; m_app.m_updateDisp = true;
break; break;
default: break; default: break;

View File

@ -23,7 +23,7 @@ private:
const ADSR* m_curADSR = nullptr; /**< Current timing envelope */ const ADSR* m_curADSR = nullptr; /**< Current timing envelope */
double m_sustainFactor; /**< Evaluated sustain percentage as a double */ double m_sustainFactor; /**< Evaluated sustain percentage as a double */
double m_releaseStartFactor; /**< Level at whenever release event occurs */ double m_releaseStartFactor; /**< Level at whenever release event occurs */
unsigned m_curMs; /**< Current time of envelope stage */ double m_curMs; /**< Current time of envelope stage */
public: public:
void reset(const ADSR* adsr); void reset(const ADSR* adsr);
void keyOff(); void keyOff();

View File

@ -4,6 +4,7 @@
#include "Entity.hpp" #include "Entity.hpp"
#include "AudioGroupProject.hpp" #include "AudioGroupProject.hpp"
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <memory> #include <memory>
#include <list> #include <list>
@ -33,6 +34,8 @@ class Sequencer : public Entity
SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */ SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */
bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */ bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */
float m_curVol = 1.f; /**< Current volume of sequencer */
/** State of a single MIDI channel */ /** State of a single MIDI channel */
struct ChannelState struct ChannelState
{ {
@ -45,13 +48,16 @@ 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;
int8_t m_ctrlVals[128]; /**< MIDI controller values */ int8_t m_ctrlVals[128]; /**< MIDI controller values */
void _bringOutYourDead(); void _bringOutYourDead();
size_t getVoiceCount() const;
std::shared_ptr<Voice> keyOn(uint8_t note, uint8_t velocity); std::shared_ptr<Voice> keyOn(uint8_t note, uint8_t velocity);
void keyOff(uint8_t note, uint8_t velocity); void keyOff(uint8_t note, uint8_t velocity);
void setCtrlValue(uint8_t ctrl, int8_t val); void setCtrlValue(uint8_t ctrl, int8_t val);
void setPitchWheel(float pitchWheel); void setPitchWheel(float pitchWheel);
void setVolume(float vol);
void allOff(); void allOff();
void killKeygroup(uint8_t kg, bool now); void killKeygroup(uint8_t kg, bool now);
std::shared_ptr<Voice> findVoice(int vid); std::shared_ptr<Voice> findVoice(int vid);
@ -105,6 +111,9 @@ public:
/** Play MIDI arrangement */ /** Play MIDI arrangement */
void playSong(const unsigned char* arrData, bool dieOnEnd=true); void playSong(const unsigned char* arrData, bool dieOnEnd=true);
/** Set total volume of sequencer */
void setVolume(float vol);
/** Manually kill sequencer for deferred release from engine */ /** Manually kill sequencer for deferred release from engine */
void kill() {m_state = SequencerState::Dead;} void kill() {m_state = SequencerState::Dead;}
}; };

View File

@ -123,7 +123,7 @@ class SoundMacroState
uint8_t m_initKey; /**< Key played for this macro invocation */ uint8_t m_initKey; /**< Key played for this macro invocation */
uint8_t m_curVel; /**< Current velocity played for this macro invocation */ uint8_t m_curVel; /**< Current velocity played for this macro invocation */
uint8_t m_curMod; /**< Current modulation played for this macro invocation */ uint8_t m_curMod; /**< Current modulation played for this macro invocation */
uint32_t m_curKey; /**< Current key played for this macro invocation (in cents) */ uint32_t m_curPitch; /**< Current key played for this macro invocation (in cents) */
double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */ double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */
bool m_keyoff; /**< keyoff message has been received */ bool m_keyoff; /**< keyoff message has been received */
@ -205,18 +205,12 @@ class SoundMacroState
int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */ int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */
/** Messages pending processing for this SoundMacro voice */
std::list<int32_t> m_messageQueue;
/** Event registration data for TRAP_EVENT */ /** Event registration data for TRAP_EVENT */
struct EventTrap struct EventTrap
{ {
ObjectId macroId = 0xffff; ObjectId macroId = 0xffff;
uint16_t macroStep; uint16_t macroStep;
}; };
EventTrap m_keyoffTrap;
EventTrap m_sampleEndTrap;
EventTrap m_messageTrap;
public: public:
/** initialize state for SoundMacro data at `ptr` */ /** initialize state for SoundMacro data at `ptr` */
@ -234,9 +228,6 @@ public:
/** sample end event */ /** sample end event */
void sampleEndNotify(Voice& vox); void sampleEndNotify(Voice& vox);
/** SEND_MESSAGE receive event */
void messageNotify(Voice& vox, int32_t val);
}; };
} }

View File

@ -39,6 +39,10 @@ class Voice : public Entity
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */ std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
SoundMacroState m_state; /**< State container for SoundMacro playback */ SoundMacroState m_state; /**< State container for SoundMacro playback */
SoundMacroState::EventTrap m_keyoffTrap; /**< Trap for keyoff (SoundMacro overrides default envelope behavior) */
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
std::list<int32_t> m_messageQueue; /**< Messages pending processing for SoundMacros in this voice */
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */ std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */ uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
@ -118,6 +122,8 @@ class Voice : public Entity
void _reset(); void _reset();
bool _checkSamplePos(); bool _checkSamplePos();
void _doKeyOff(); void _doKeyOff();
void _macroKeyOff();
void _macroSampleEnd();
bool _advanceSample(int16_t& samp); bool _advanceSample(int16_t& samp);
void _setTotalPitch(int32_t cents); void _setTotalPitch(int32_t cents);
bool _isRecursivelyDead(); bool _isRecursivelyDead();

View File

@ -7,15 +7,18 @@ void Envelope::reset(const ADSR* adsr)
{ {
m_phase = State::Attack; m_phase = State::Attack;
m_curADSR = adsr; m_curADSR = adsr;
m_curMs = 0; m_curMs = 0.0;
m_sustainFactor = (adsr->sustainCoarse * 6.25 + adsr->sustainFine * 0.0244) / 100.0; if (m_curADSR->decayCoarse == 128)
m_sustainFactor = 1.f;
else
m_sustainFactor = (adsr->sustainCoarse * 6.25 + adsr->sustainFine * 0.0244) / 100.0;
m_releaseStartFactor = 0.0; m_releaseStartFactor = 0.0;
} }
void Envelope::keyOff() void Envelope::keyOff()
{ {
m_phase = State::Release; m_phase = State::Release;
m_curMs = 0; m_curMs = 0.0;
} }
float Envelope::nextSample(double sampleRate) float Envelope::nextSample(double sampleRate)
@ -36,15 +39,23 @@ float Envelope::nextSample(double sampleRate)
uint16_t attack = m_curADSR->attackCoarse * 255 + m_curADSR->attackFine; uint16_t attack = m_curADSR->attackCoarse * 255 + m_curADSR->attackFine;
if (attack == 0) if (attack == 0)
{ {
m_phase = State::Decay; if (m_curADSR->decayCoarse == 128)
m_curMs = 0; m_phase = State::Sustain;
else
m_phase = State::Decay;
m_curMs = 0.0;
m_releaseStartFactor = 1.f;
return 1.f; return 1.f;
} }
double attackFac = m_curMs / double(attack); double attackFac = m_curMs / double(attack);
if (attackFac >= 1.0) if (attackFac >= 1.0)
{ {
m_phase = State::Decay; if (m_curADSR->decayCoarse == 128)
m_curMs = 0; m_phase = State::Sustain;
else
m_phase = State::Decay;
m_curMs = 0.0;
m_releaseStartFactor = 1.f;
return 1.f; return 1.f;
} }
m_releaseStartFactor = attackFac; m_releaseStartFactor = attackFac;
@ -56,7 +67,7 @@ float Envelope::nextSample(double sampleRate)
if (decay == 0) if (decay == 0)
{ {
m_phase = State::Sustain; m_phase = State::Sustain;
m_curMs = 0; m_curMs = 0.0;
m_releaseStartFactor = m_sustainFactor; m_releaseStartFactor = m_sustainFactor;
return m_sustainFactor; return m_sustainFactor;
} }
@ -64,7 +75,7 @@ float Envelope::nextSample(double sampleRate)
if (decayFac >= 1.0) if (decayFac >= 1.0)
{ {
m_phase = State::Sustain; m_phase = State::Sustain;
m_curMs = 0; m_curMs = 0.0;
m_releaseStartFactor = m_sustainFactor; m_releaseStartFactor = m_sustainFactor;
return m_sustainFactor; return m_sustainFactor;
} }

View File

@ -19,6 +19,18 @@ void Sequencer::ChannelState::_bringOutYourDead()
} }
++it; ++it;
} }
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;)
{
Voice* vox = it->get();
vox->_bringOutYourDead();
if (vox->_isRecursivelyDead())
{
it = m_keyoffVoxs.erase(it);
continue;
}
++it;
}
} }
void Sequencer::_bringOutYourDead() void Sequencer::_bringOutYourDead()
@ -35,10 +47,6 @@ void Sequencer::_destroy()
Entity::_destroy(); Entity::_destroy();
if (m_submix) if (m_submix)
m_submix->m_activeSequencers.erase(this); m_submix->m_activeSequencers.erase(this);
for (const auto& chan : m_chanStates)
for (const auto& vox : chan.second->m_chanVoxs)
vox.second->_destroy();
} }
Sequencer::~Sequencer() {} Sequencer::~Sequencer() {}
@ -83,12 +91,21 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
m_submix->makeChorus(15, m_setup.chorus * 5 / 127, 5000); m_submix->makeChorus(15, m_setup.chorus * 5 / 127, 5000);
} }
size_t Sequencer::ChannelState::getVoiceCount() const
{
size_t ret = 0;
for (const auto& vox : m_chanVoxs)
ret += vox.second->getTotalVoices();
for (const auto& vox : m_keyoffVoxs)
ret += vox->getTotalVoices();
return ret;
}
size_t Sequencer::getVoiceCount() const size_t Sequencer::getVoiceCount() const
{ {
size_t ret = 0; size_t ret = 0;
for (const auto& chan : m_chanStates) for (const auto& chan : m_chanStates)
for (const auto& vox : chan.second->m_chanVoxs) ret += chan.second->getVoiceCount();
ret += vox.second->getTotalVoices();
return ret; return ret;
} }
@ -107,7 +124,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
m_parent.m_engine._destroyVoice(ret.get()); m_parent.m_engine._destroyVoice(ret.get());
return {}; return {};
} }
ret->setVolume(m_setup.volume / 127.f); ret->setVolume(m_parent.m_curVol * m_setup.volume / 127.f);
ret->setPan(m_setup.panning / 64.f - 127.f); ret->setPan(m_setup.panning / 64.f - 127.f);
return ret; return ret;
} }
@ -131,6 +148,7 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
return; return;
keySearch->second->keyOff(); keySearch->second->keyOff();
m_keyoffVoxs.emplace(std::move(keySearch->second));
m_chanVoxs.erase(keySearch); m_chanVoxs.erase(keySearch);
} }
@ -161,6 +179,8 @@ void Sequencer::ChannelState::setPitchWheel(float pitchWheel)
{ {
for (const auto& vox : m_chanVoxs) for (const auto& vox : m_chanVoxs)
vox.second->setPitchWheel(pitchWheel); vox.second->setPitchWheel(pitchWheel);
for (const auto& vox : m_keyoffVoxs)
vox->setPitchWheel(pitchWheel);
} }
void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel) void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel)
@ -209,6 +229,20 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
} }
++it; ++it;
} }
if (now)
{
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;)
{
Voice* vox = it->get();
if (vox->m_keygroup == kg)
{
it = m_keyoffVoxs.erase(it);
continue;
}
++it;
}
}
} }
void Sequencer::killKeygroup(uint8_t kg, bool now) void Sequencer::killKeygroup(uint8_t kg, bool now)
@ -222,6 +256,9 @@ std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
for (const auto& vox : m_chanVoxs) for (const auto& vox : m_chanVoxs)
if (vox.second->vid() == vid) if (vox.second->vid() == vid)
return vox.second; return vox.second;
for (const auto& vox : m_keyoffVoxs)
if (vox->vid() == vid)
return vox;
return {}; return {};
} }
@ -244,6 +281,12 @@ void Sequencer::ChannelState::sendMacroMessage(ObjectId macroId, int32_t val)
if (vox->getObjectId() == macroId) if (vox->getObjectId() == macroId)
vox->message(val); vox->message(val);
} }
for (const auto& v : m_keyoffVoxs)
{
Voice* vox = v.get();
if (vox->getObjectId() == macroId)
vox->message(val);
}
} }
void Sequencer::sendMacroMessage(ObjectId macroId, int32_t val) void Sequencer::sendMacroMessage(ObjectId macroId, int32_t val)
@ -259,4 +302,26 @@ void Sequencer::playSong(const unsigned char* arrData, bool dieOnEnd)
m_state = SequencerState::Playing; m_state = SequencerState::Playing;
} }
void Sequencer::ChannelState::setVolume(float vol)
{
vol = vol * m_setup.volume / 127.f;
for (const auto& v : m_chanVoxs)
{
Voice* vox = v.second.get();
vox->setVolume(vol);
}
for (const auto& v : m_keyoffVoxs)
{
Voice* vox = v.get();
vox->setVolume(vol);
}
}
void Sequencer::setVolume(float vol)
{
m_curVol = vol;
for (auto& chan : m_chanStates)
chan.second->setVolume(vol);
}
} }

View File

@ -123,11 +123,12 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
m_initKey = midiKey; m_initKey = midiKey;
m_initVel = midiVel; m_initVel = midiVel;
m_initMod = midiMod; m_initMod = midiMod;
m_curVel = 0; m_curVel = midiVel;
m_curMod = 0; m_curMod = midiMod;
m_curKey = 0; m_curPitch = midiKey * 100;
m_pc.clear(); m_pc.clear();
m_pc.push_back({ptr, step}); m_pc.push_back({ptr, step});
m_inWait = false;
m_execTime = 0.f; m_execTime = 0.f;
m_keyoff = false; m_keyoff = false;
m_sampleEnd = false; m_sampleEnd = false;
@ -135,9 +136,6 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
m_lastPlayMacroVid = -1; m_lastPlayMacroVid = -1;
m_useAdsrControllers = false; m_useAdsrControllers = false;
m_portamentoMode = 0; m_portamentoMode = 0;
m_keyoffTrap.macroId = 0xffff;
m_sampleEndTrap.macroId = 0xffff;
m_messageTrap.macroId = 0xffff;
m_header = *reinterpret_cast<const Header*>(ptr); m_header = *reinterpret_cast<const Header*>(ptr);
m_header.swapBig(); m_header.swapBig();
} }
@ -154,7 +152,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
/* Advance wait timer if active, returning if waiting */ /* Advance wait timer if active, returning if waiting */
if (m_inWait) if (m_inWait)
{ {
if (!m_indefiniteWait) if (m_keyoffWait && m_keyoff)
m_inWait = false;
else if (m_sampleEndWait && m_sampleEnd)
m_inWait = false;
else if (!m_indefiniteWait)
{ {
m_waitCountdown -= dt; m_waitCountdown -= dt;
if (m_waitCountdown < 0.f) if (m_waitCountdown < 0.f)
@ -178,7 +180,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
{ {
case Op::End: case Op::End:
case Op::Stop: case Op::Stop:
m_pc.clear(); m_pc.back().second = -1;
return true; return true;
case Op::SplitKey: case Op::SplitKey:
{ {
@ -193,7 +195,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
m_pc.back().second = macroStep; m_pc.back().second = macroStep;
else else
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec, vox.loadSoundObject(macroId, macroStep, m_ticksPerSec,
m_initKey, m_initVel, m_initMod); m_initKey, m_initVel, m_initMod);
} }
break; break;
@ -480,6 +482,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
} }
vox.startSample(smpId, offset); vox.startSample(smpId, offset);
vox.setPitchKey(m_curPitch);
break; break;
} }
case Op::StopSample: case Op::StopSample:
@ -489,7 +492,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
} }
case Op::KeyOff: case Op::KeyOff:
{ {
vox.keyOff(); vox._macroKeyOff();
break; break;
} }
case Op::SplitRnd: case Op::SplitRnd:
@ -568,11 +571,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
noteLo *= 100; noteLo *= 100;
noteHi *= 100; noteHi *= 100;
m_curKey = vox.getEngine().nextRandom() % ((noteHi - noteLo) + noteLo); m_curPitch = vox.getEngine().nextRandom() % ((noteHi - noteLo) + noteLo);
if (!free) if (!free)
m_curKey = m_curKey / 100 * 100 + detune; m_curPitch = m_curPitch / 100 * 100 + detune;
vox.setPitchKey(m_curKey); vox.setPitchKey(m_curPitch);
break; break;
} }
case Op::AddNote: case Op::AddNote:
@ -583,7 +586,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int8_t ms = cmd.m_data[4]; int8_t ms = cmd.m_data[4];
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]); int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
m_curKey = (orgKey ? m_initKey : m_curKey) + add * 100 + detune; m_curPitch = (orgKey ? (m_initKey * 100) : m_curPitch) + add * 100 + detune;
/* Set wait state */ /* Set wait state */
if (timeMs) if (timeMs)
@ -594,7 +597,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
m_inWait = true; m_inWait = true;
} }
vox.setPitchKey(m_curKey); vox.setPitchKey(m_curPitch);
break; break;
} }
case Op::SetNote: case Op::SetNote:
@ -604,7 +607,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int8_t ms = cmd.m_data[4]; int8_t ms = cmd.m_data[4];
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]); int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
m_curKey = key * 100 + detune; m_curPitch = key * 100 + detune;
/* Set wait state */ /* Set wait state */
if (timeMs) if (timeMs)
@ -615,7 +618,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
m_inWait = true; m_inWait = true;
} }
vox.setPitchKey(m_curKey); vox.setPitchKey(m_curPitch);
break; break;
} }
case Op::LastNote: case Op::LastNote:
@ -625,7 +628,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int8_t ms = cmd.m_data[4]; int8_t ms = cmd.m_data[4];
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]); int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
m_curKey = (add + vox.getLastNote()) * 100 + detune; m_curPitch = (add + vox.getLastNote()) * 100 + detune;
/* Set wait state */ /* Set wait state */
if (timeMs) if (timeMs)
@ -636,7 +639,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
m_inWait = true; m_inWait = true;
} }
vox.setPitchKey(m_curKey); vox.setPitchKey(m_curPitch);
break; break;
} }
case Op::Portamento: case Op::Portamento:
@ -774,16 +777,16 @@ bool SoundMacroState::advance(Voice& vox, double dt)
switch (event) switch (event)
{ {
case 0: case 0:
m_keyoffTrap.macroId = macroId; vox.m_keyoffTrap.macroId = macroId;
m_keyoffTrap.macroStep = macroStep; vox.m_keyoffTrap.macroStep = macroStep;
break; break;
case 1: case 1:
m_sampleEndTrap.macroId = macroId; vox.m_sampleEndTrap.macroId = macroId;
m_sampleEndTrap.macroStep = macroStep; vox.m_sampleEndTrap.macroStep = macroStep;
break; break;
case 2: case 2:
m_messageTrap.macroId = macroId; vox.m_messageTrap.macroId = macroId;
m_messageTrap.macroStep = macroStep; vox.m_messageTrap.macroStep = macroStep;
break; break;
default: break; default: break;
} }
@ -797,16 +800,16 @@ bool SoundMacroState::advance(Voice& vox, double dt)
switch (event) switch (event)
{ {
case 0: case 0:
m_keyoffTrap.macroId = 0xffff; vox.m_keyoffTrap.macroId = 0xffff;
m_keyoffTrap.macroStep = -1; vox.m_keyoffTrap.macroStep = -1;
break; break;
case 1: case 1:
m_sampleEndTrap.macroId = 0xffff; vox.m_sampleEndTrap.macroId = 0xffff;
m_sampleEndTrap.macroStep = -1; vox.m_sampleEndTrap.macroStep = -1;
break; break;
case 2: case 2:
m_messageTrap.macroId = 0xffff; vox.m_messageTrap.macroId = 0xffff;
m_messageTrap.macroStep = -1; vox.m_messageTrap.macroStep = -1;
break; break;
default: break; default: break;
} }
@ -834,10 +837,10 @@ bool SoundMacroState::advance(Voice& vox, double dt)
case Op::GetMessage: case Op::GetMessage:
{ {
uint8_t vid = cmd.m_data[0]; uint8_t vid = cmd.m_data[0];
if (m_messageQueue.size()) if (vox.m_messageQueue.size())
{ {
m_variables[vid] = m_messageQueue.front(); m_variables[vid] = vox.m_messageQueue.front();
m_messageQueue.pop_front(); vox.m_messageQueue.pop_front();
} }
else else
m_variables[vid] = 0; m_variables[vid] = 0;
@ -1221,47 +1224,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
void SoundMacroState::keyoffNotify(Voice& vox) void SoundMacroState::keyoffNotify(Voice& vox)
{ {
m_keyoff = true; m_keyoff = true;
if (m_inWait && m_keyoffWait)
m_inWait = false;
if (m_keyoffTrap.macroId != 0xffff)
{
if (m_keyoffTrap.macroId == m_header.m_macroId)
m_pc.back().second = m_keyoffTrap.macroStep;
else
vox.loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep,
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
}
} }
void SoundMacroState::sampleEndNotify(Voice& vox) void SoundMacroState::sampleEndNotify(Voice& vox)
{ {
m_sampleEnd = true; m_sampleEnd = true;
if (m_inWait && m_sampleEndWait)
m_inWait = false;
if (m_sampleEndTrap.macroId != 0xffff)
{
if (m_sampleEndTrap.macroId == m_header.m_macroId)
m_pc.back().second = m_sampleEndTrap.macroStep;
else
vox.loadSoundObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep,
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
}
}
void SoundMacroState::messageNotify(Voice& vox, int32_t val)
{
m_messageQueue.push_back(val);
if (m_messageTrap.macroId != 0xffff)
{
if (m_messageTrap.macroId == m_header.m_macroId)
m_pc.back().second = m_messageTrap.macroStep;
else
vox.loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep,
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
}
} }
} }

View File

@ -70,6 +70,24 @@ void Voice::_reset()
memset(m_extCtrlVals, 0, 128); memset(m_extCtrlVals, 0, 128);
} }
void Voice::_macroSampleEnd()
{
if (m_sampleEndTrap.macroId != 0xffff)
{
if (m_sampleEndTrap.macroId == m_state.m_header.m_macroId)
{
m_state.m_pc.back().second = m_sampleEndTrap.macroStep;
m_state.m_inWait = false;
}
else
loadSoundObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep,
m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod);
}
else
m_state.sampleEndNotify(*this);
}
bool Voice::_checkSamplePos() bool Voice::_checkSamplePos()
{ {
if (m_curSamplePos >= m_lastSamplePos) if (m_curSamplePos >= m_lastSamplePos)
@ -84,7 +102,7 @@ bool Voice::_checkSamplePos()
else else
{ {
/* Notify sample end */ /* Notify sample end */
m_state.sampleEndNotify(*this); _macroSampleEnd();
m_curSample = nullptr; m_curSample = nullptr;
return true; return true;
} }
@ -93,7 +111,7 @@ bool Voice::_checkSamplePos()
/* Looped samples issue sample end when ADSR envelope complete */ /* Looped samples issue sample end when ADSR envelope complete */
if (m_volAdsr.isComplete()) if (m_volAdsr.isComplete())
{ {
m_state.sampleEndNotify(*this); _macroSampleEnd();
m_curSample = nullptr; m_curSample = nullptr;
return true; return true;
} }
@ -110,6 +128,7 @@ void Voice::_doKeyOff()
void Voice::_setTotalPitch(int32_t cents) void Voice::_setTotalPitch(int32_t cents)
{ {
fprintf(stderr, "PITCH %d\n", cents);
int32_t interval = cents - m_curSample->first.m_pitch * 100; int32_t interval = cents - m_curSample->first.m_pitch * 100;
double ratio = std::exp2(interval / 1200.0); double ratio = std::exp2(interval / 1200.0);
m_sampleRate = m_curSample->first.m_sampleRate * ratio; m_sampleRate = m_curSample->first.m_sampleRate * ratio;
@ -304,7 +323,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
{ {
uint32_t samplesRem = samples; uint32_t samplesRem = samples;
size_t samplesProc = 0; size_t samplesProc = 0;
bool dead = false; bool dead = true;
/* Attempt to load stopped sample for immediate decoding */ /* Attempt to load stopped sample for immediate decoding */
if (!m_curSample) if (!m_curSample)
@ -313,48 +332,91 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
if (m_curSample) if (m_curSample)
{ {
dead = m_state.advance(*this, samples / m_sampleRate); dead = m_state.advance(*this, samples / m_sampleRate);
if (!dead) uint32_t block = m_curSamplePos / 14;
uint32_t rem = m_curSamplePos % 14;
if (rem)
{ {
uint32_t block = m_curSamplePos / 14; uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
uint32_t rem = m_curSamplePos % 14; uint32_t decSamples;
if (rem) switch (m_curFormat)
{ {
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14); case SampleFormat::DSP:
uint32_t decSamples; {
decSamples = DSPDecompressFrameRanged(data, m_curSampleData + 8 * block,
switch (m_curFormat) m_curSample->second.m_coefs,
{ &m_prev1, &m_prev2, rem, remCount);
case SampleFormat::DSP: break;
{
decSamples = DSPDecompressFrameRanged(data, m_curSampleData + 8 * block,
m_curSample->second.m_coefs,
&m_prev1, &m_prev2, rem, remCount);
break;
}
case SampleFormat::PCM:
{
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
for (uint32_t i=0 ; i<remCount ; ++i)
data[i] = SBig(pcm[m_curSamplePos+i]);
decSamples = remCount;
break;
}
default: return 0;
}
/* Per-sample processing */
for (int i=0 ; i<decSamples ; ++i)
{
++samplesProc;
++m_curSamplePos;
if (_advanceSample(data[i]))
return samplesProc;
}
samplesRem -= decSamples;
data += decSamples;
} }
case SampleFormat::PCM:
{
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
for (uint32_t i=0 ; i<remCount ; ++i)
data[i] = SBig(pcm[m_curSamplePos+i]);
decSamples = remCount;
break;
}
default: return 0;
}
/* Per-sample processing */
for (int i=0 ; i<decSamples ; ++i)
{
++samplesProc;
++m_curSamplePos;
if (_advanceSample(data[i]))
return samplesProc;
}
samplesRem -= decSamples;
data += decSamples;
}
if (_checkSamplePos())
{
if (samplesRem)
memset(data, 0, sizeof(int16_t) * samplesRem);
return samples;
}
while (samplesRem)
{
block = m_curSamplePos / 14;
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
uint32_t decSamples;
switch (m_curFormat)
{
case SampleFormat::DSP:
{
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block,
m_curSample->second.m_coefs,
&m_prev1, &m_prev2, remCount);
break;
}
case SampleFormat::PCM:
{
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
for (uint32_t i=0 ; i<remCount ; ++i)
data[i] = SBig(pcm[m_curSamplePos+i]);
decSamples = remCount;
break;
}
default: return 0;
}
/* Per-sample processing */
for (int i=0 ; i<decSamples ; ++i)
{
++samplesProc;
++m_curSamplePos;
if (_advanceSample(data[i]))
return samplesProc;
}
samplesRem -= decSamples;
data += decSamples;
if (_checkSamplePos()) if (_checkSamplePos())
{ {
@ -362,58 +424,15 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
memset(data, 0, sizeof(int16_t) * samplesRem); memset(data, 0, sizeof(int16_t) * samplesRem);
return samples; return samples;
} }
while (samplesRem)
{
block = m_curSamplePos / 14;
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
uint32_t decSamples;
switch (m_curFormat)
{
case SampleFormat::DSP:
{
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block,
m_curSample->second.m_coefs,
&m_prev1, &m_prev2, remCount);
break;
}
case SampleFormat::PCM:
{
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
for (uint32_t i=0 ; i<remCount ; ++i)
data[i] = SBig(pcm[m_curSamplePos+i]);
decSamples = remCount;
break;
}
default: return 0;
}
/* Per-sample processing */
for (int i=0 ; i<decSamples ; ++i)
{
++samplesProc;
++m_curSamplePos;
if (_advanceSample(data[i]))
return samplesProc;
}
samplesRem -= decSamples;
data += decSamples;
if (_checkSamplePos())
{
if (samplesRem)
memset(data, 0, sizeof(int16_t) * samplesRem);
return samples;
}
}
} }
} }
else else
memset(data, 0, sizeof(int16_t) * samples); memset(data, 0, sizeof(int16_t) * samples);
if (dead) if (dead && m_voxState == VoiceState::KeyOff &&
m_sampleEndTrap.macroId == 0xffff &&
m_messageTrap.macroId == 0xffff &&
m_volAdsr.isComplete())
{ {
m_voxState = VoiceState::Dead; m_voxState = VoiceState::Dead;
m_backendVoice->stop(); m_backendVoice->stop();
@ -483,13 +502,13 @@ bool Voice::_loadLayer(const std::vector<const LayerMapping*>& layer, int macroS
{ {
if (midiKey >= mapping->keyLo && midiKey <= mapping->keyHi) if (midiKey >= mapping->keyLo && midiKey <= mapping->keyHi)
{ {
midiKey += mapping->transpose; uint8_t mappingKey = midiKey + mapping->transpose;
if (m_voxState != VoiceState::Playing) if (m_voxState != VoiceState::Playing)
ret |= loadSoundObject(SBig(mapping->objectId), macroStep, ticksPerSec, ret |= loadSoundObject(SBig(mapping->objectId), macroStep, ticksPerSec,
midiKey, midiVel, midiMod, pushPc); mappingKey, midiVel, midiMod, pushPc);
else else
ret |= _startChildMacro(SBig(mapping->objectId), macroStep, ticksPerSec, ret |= _startChildMacro(SBig(mapping->objectId), macroStep, ticksPerSec,
midiKey, midiVel, midiMod, pushPc).operator bool(); mappingKey, midiVel, midiMod, pushPc).operator bool();
} }
} }
return ret; return ret;
@ -514,7 +533,7 @@ bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec
return false; return false;
} }
void Voice::keyOff() void Voice::_macroKeyOff()
{ {
if (m_sustained) if (m_sustained)
m_sustainKeyOff = true; m_sustainKeyOff = true;
@ -527,8 +546,38 @@ void Voice::keyOff()
m_voxState = VoiceState::KeyOff; m_voxState = VoiceState::KeyOff;
} }
void Voice::keyOff()
{
if (m_keyoffTrap.macroId != 0xffff)
{
if (m_keyoffTrap.macroId == m_state.m_header.m_macroId)
{
m_state.m_pc.back().second = m_keyoffTrap.macroStep;
m_state.m_inWait = false;
}
else
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep,
m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod);
return;
}
else
_macroKeyOff();
}
void Voice::message(int32_t val) void Voice::message(int32_t val)
{ {
m_messageQueue.push_back(val);
if (m_messageTrap.macroId != 0xffff)
{
if (m_messageTrap.macroId == m_state.m_header.m_macroId)
m_state.m_pc.back().second = m_messageTrap.macroStep;
else
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep,
m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod);
}
} }
void Voice::startSample(int16_t sampId, int32_t offset) void Voice::startSample(int16_t sampId, int32_t offset)