From 2115a958b194acce712767101e4bbed1ee96e7d6 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 18 May 2016 19:27:39 -1000 Subject: [PATCH] Timing fixes for SON playback --- driver/main.cpp | 12 +++++++----- include/amuse/SongState.hpp | 1 + lib/Engine.cpp | 4 ++-- lib/Sequencer.cpp | 3 +++ lib/SongState.cpp | 31 +++++++++++++++++-------------- lib/Submix.cpp | 1 - lib/Voice.cpp | 17 +++++++++++------ 7 files changed, 41 insertions(+), 28 deletions(-) diff --git a/driver/main.cpp b/driver/main.cpp index 95902ad..229344b 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -10,6 +10,8 @@ #include #include +#define VOL_FACTOR 0.25 + static logvisor::Module Log("amuseplay"); static amuse::IntrusiveAudioGroupData LoadFromArgs(int argc, const boo::SystemChar** argv, @@ -204,7 +206,7 @@ struct AppCallback : boo::IApplicationCallback if (m_seq) m_seq->allOff(); m_seq = m_engine->seqPlay(m_groupId, setupId, nullptr); - m_seq->setVolume(m_volume); + m_seq->setVolume(m_volume * VOL_FACTOR); if (m_arrData) m_seq->playSong(m_arrData.get(), false); @@ -804,18 +806,18 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, if (m_app.m_volume < 1.f) m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f); if (m_app.m_vox) - m_app.m_vox->setVolume(m_app.m_volume); + m_app.m_vox->setVolume(m_app.m_volume * VOL_FACTOR); if (m_app.m_seq) - m_app.m_seq->setVolume(m_app.m_volume); + m_app.m_seq->setVolume(m_app.m_volume * VOL_FACTOR); m_app.m_updateDisp = true; break; case boo::ESpecialKey::Down: if (m_app.m_volume > 0.f) m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f); if (m_app.m_vox) - m_app.m_vox->setVolume(m_app.m_volume); + m_app.m_vox->setVolume(m_app.m_volume * VOL_FACTOR); if (m_app.m_seq) - m_app.m_seq->setVolume(m_app.m_volume); + m_app.m_seq->setVolume(m_app.m_volume * VOL_FACTOR); m_app.m_updateDisp = true; break; default: break; diff --git a/include/amuse/SongState.hpp b/include/amuse/SongState.hpp index cd7df7c..5bd9d90 100644 --- a/include/amuse/SongState.hpp +++ b/include/amuse/SongState.hpp @@ -98,6 +98,7 @@ class SongState uint32_t m_curTick = 0; /**< Current playback position for all channels */ SongPlayState m_songState = SongPlayState::Playing; /**< High-level state of Song playback */ + double m_curDt = 0.f; /**< Cumulative dt value for time-remainder tracking */ public: /** initialize state for Song data at `ptr` */ diff --git a/lib/Engine.cpp b/lib/Engine.cpp index 41751d7..49dc825 100644 --- a/lib/Engine.cpp +++ b/lib/Engine.cpp @@ -13,14 +13,14 @@ namespace amuse Engine::~Engine() { + for (std::shared_ptr& seq : m_activeSequencers) + seq->_destroy(); while (m_activeSubmixes.size()) removeSubmix(&m_activeSubmixes.front()); for (std::shared_ptr& emitter : m_activeEmitters) emitter->_destroy(); for (std::shared_ptr& vox : m_activeVoices) vox->_destroy(); - for (std::shared_ptr& seq : m_activeSequencers) - seq->_destroy(); } Engine::Engine(IBackendVoiceAllocator& backend) diff --git a/lib/Sequencer.cpp b/lib/Sequencer.cpp index 1e4a537..8003357 100644 --- a/lib/Sequencer.cpp +++ b/lib/Sequencer.cpp @@ -143,6 +143,9 @@ std::shared_ptr Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo if (!m_page) return {}; + /* Ensure keyoff sent first */ + keyOff(note, 0); + std::shared_ptr ret = m_parent.m_engine._allocateVoice(m_parent.m_audioGroup, m_parent.m_groupId, 32000.0, true, false, m_submix); diff --git a/lib/SongState.cpp b/lib/SongState.cpp index d2c18a1..37b3b37 100644 --- a/lib/SongState.cpp +++ b/lib/SongState.cpp @@ -124,6 +124,9 @@ SongState::Channel::Channel(SongState& parent, uint8_t midiChan, uint32_t startT m_modWheelData = song + header.m_modOff; m_waitCountdown = startTick; + m_lastPitchTick = startTick; + m_lastModTick = startTick; + m_waitCountdown += int32_t(DecodeTimeRLE(m_data)); } void SongState::initialize(const unsigned char* ptr) @@ -246,10 +249,6 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) } } - /* Bootstrap first delta-time */ - if (m_data == m_dataBase) - m_waitCountdown = DecodeTimeRLE(m_data); - /* Loop through as many commands as we can for this time period */ while (true) { @@ -257,9 +256,8 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) if (m_waitCountdown) { m_waitCountdown -= ticks; - if (m_waitCountdown <= 0) - m_waitCountdown = 0; - else + ticks = 0; + if (m_waitCountdown > 0) return false; } @@ -290,7 +288,7 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) } /* Set next delta-time */ - m_waitCountdown = DecodeTimeRLE(m_data); + m_waitCountdown += int32_t(DecodeTimeRLE(m_data)); } return false; @@ -302,12 +300,17 @@ bool SongState::advance(Sequencer& seq, double dt) if (m_songState == SongPlayState::Stopped) return true; - bool done = true; - while (dt > 0.0) + bool done = false; + m_curDt += dt; + while (m_curDt > 0.0) { + done = true; + /* Compute ticks to compute based on current tempo */ - int32_t remTicks = dt * m_tempo * 384 / 60; - if (!remTicks) remTicks = 1; + double ticksPerSecond = m_tempo * 384 / 60; + int32_t remTicks = std::ceil(m_curDt * ticksPerSecond); + if (!remTicks) + break; /* See if there's an upcoming tempo change in this interval */ if (m_tempoPtr && m_tempoPtr->m_tick != 0xffffffff) @@ -335,9 +338,9 @@ bool SongState::advance(Sequencer& seq, double dt) m_curTick += remTicks; if (m_tempo == 0) - dt = 0.0; + m_curDt = 0.0; else - dt -= remTicks / double(m_tempo * 384 / 60); + m_curDt -= remTicks / ticksPerSecond; } if (done) diff --git a/lib/Submix.cpp b/lib/Submix.cpp index 2e9167d..048cdb9 100644 --- a/lib/Submix.cpp +++ b/lib/Submix.cpp @@ -6,7 +6,6 @@ namespace amuse void Submix::_destroy() { m_destroyed = true; - m_backendSubmix.reset(); } Submix::Submix(Engine& engine, Submix* smx) diff --git a/lib/Voice.cpp b/lib/Voice.cpp index 06332f4..0a01a5c 100644 --- a/lib/Voice.cpp +++ b/lib/Voice.cpp @@ -18,8 +18,6 @@ void Voice::_destroy() for (std::shared_ptr& vox : m_childVoices) vox->_destroy(); - - m_backendVoice.reset(); } Voice::~Voice() @@ -557,9 +555,6 @@ void Voice::_macroKeyOff() _doKeyOff(); m_voxState = VoiceState::KeyOff; } - - for (const std::shared_ptr& vox : m_childVoices) - vox->keyOff(); } void Voice::keyOff() @@ -575,10 +570,12 @@ void Voice::keyOff() 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(); + + for (const std::shared_ptr& vox : m_childVoices) + vox->keyOff(); } void Voice::message(int32_t val) @@ -780,13 +777,21 @@ void Voice::setAdsr(ObjectId adsrId, bool dls) { const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId); if (adsr) + { m_volAdsr.reset(adsr, m_state.m_initKey, m_state.m_initVel); + if (m_voxState == VoiceState::KeyOff) + m_volAdsr.keyOff(); + } } else { const ADSR* adsr = m_audioGroup.getPool().tableAsAdsr(adsrId); if (adsr) + { m_volAdsr.reset(adsr); + if (m_voxState == VoiceState::KeyOff) + m_volAdsr.keyOff(); + } } }