Timing fixes for SON playback

This commit is contained in:
Jack Andersen 2016-05-18 19:27:39 -10:00
parent 3433a70462
commit 2115a958b1
7 changed files with 41 additions and 28 deletions

View File

@ -10,6 +10,8 @@
#include <thread> #include <thread>
#include <map> #include <map>
#define VOL_FACTOR 0.25
static logvisor::Module Log("amuseplay"); static logvisor::Module Log("amuseplay");
static amuse::IntrusiveAudioGroupData LoadFromArgs(int argc, const boo::SystemChar** argv, static amuse::IntrusiveAudioGroupData LoadFromArgs(int argc, const boo::SystemChar** argv,
@ -204,7 +206,7 @@ struct AppCallback : boo::IApplicationCallback
if (m_seq) if (m_seq)
m_seq->allOff(); m_seq->allOff();
m_seq = m_engine->seqPlay(m_groupId, setupId, nullptr); m_seq = m_engine->seqPlay(m_groupId, setupId, nullptr);
m_seq->setVolume(m_volume); m_seq->setVolume(m_volume * VOL_FACTOR);
if (m_arrData) if (m_arrData)
m_seq->playSong(m_arrData.get(), false); 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) if (m_app.m_volume < 1.f)
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 * VOL_FACTOR);
if (m_app.m_seq) 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; m_app.m_updateDisp = true;
break; break;
case boo::ESpecialKey::Down: case boo::ESpecialKey::Down:
if (m_app.m_volume > 0.f) if (m_app.m_volume > 0.f)
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 * VOL_FACTOR);
if (m_app.m_seq) 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; m_app.m_updateDisp = true;
break; break;
default: break; default: break;

View File

@ -98,6 +98,7 @@ class SongState
uint32_t m_curTick = 0; /**< Current playback position for all channels */ uint32_t m_curTick = 0; /**< Current playback position for all channels */
SongPlayState m_songState = SongPlayState::Playing; /**< High-level state of Song playback */ SongPlayState m_songState = SongPlayState::Playing; /**< High-level state of Song playback */
double m_curDt = 0.f; /**< Cumulative dt value for time-remainder tracking */
public: public:
/** initialize state for Song data at `ptr` */ /** initialize state for Song data at `ptr` */

View File

@ -13,14 +13,14 @@ namespace amuse
Engine::~Engine() Engine::~Engine()
{ {
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
seq->_destroy();
while (m_activeSubmixes.size()) while (m_activeSubmixes.size())
removeSubmix(&m_activeSubmixes.front()); removeSubmix(&m_activeSubmixes.front());
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters) for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
emitter->_destroy(); emitter->_destroy();
for (std::shared_ptr<Voice>& vox : m_activeVoices) for (std::shared_ptr<Voice>& vox : m_activeVoices)
vox->_destroy(); vox->_destroy();
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
seq->_destroy();
} }
Engine::Engine(IBackendVoiceAllocator& backend) Engine::Engine(IBackendVoiceAllocator& backend)

View File

@ -143,6 +143,9 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
if (!m_page) if (!m_page)
return {}; return {};
/* Ensure keyoff sent first */
keyOff(note, 0);
std::shared_ptr<Voice> ret = m_parent.m_engine._allocateVoice(m_parent.m_audioGroup, std::shared_ptr<Voice> ret = m_parent.m_engine._allocateVoice(m_parent.m_audioGroup,
m_parent.m_groupId, 32000.0, m_parent.m_groupId, 32000.0,
true, false, m_submix); true, false, m_submix);

View File

@ -124,6 +124,9 @@ SongState::Channel::Channel(SongState& parent, uint8_t midiChan, uint32_t startT
m_modWheelData = song + header.m_modOff; m_modWheelData = song + header.m_modOff;
m_waitCountdown = startTick; m_waitCountdown = startTick;
m_lastPitchTick = startTick;
m_lastModTick = startTick;
m_waitCountdown += int32_t(DecodeTimeRLE(m_data));
} }
void SongState::initialize(const unsigned char* ptr) 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 */ /* Loop through as many commands as we can for this time period */
while (true) while (true)
{ {
@ -257,9 +256,8 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks)
if (m_waitCountdown) if (m_waitCountdown)
{ {
m_waitCountdown -= ticks; m_waitCountdown -= ticks;
if (m_waitCountdown <= 0) ticks = 0;
m_waitCountdown = 0; if (m_waitCountdown > 0)
else
return false; return false;
} }
@ -290,7 +288,7 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks)
} }
/* Set next delta-time */ /* Set next delta-time */
m_waitCountdown = DecodeTimeRLE(m_data); m_waitCountdown += int32_t(DecodeTimeRLE(m_data));
} }
return false; return false;
@ -302,12 +300,17 @@ bool SongState::advance(Sequencer& seq, double dt)
if (m_songState == SongPlayState::Stopped) if (m_songState == SongPlayState::Stopped)
return true; return true;
bool done = true; bool done = false;
while (dt > 0.0) m_curDt += dt;
while (m_curDt > 0.0)
{ {
done = true;
/* Compute ticks to compute based on current tempo */ /* Compute ticks to compute based on current tempo */
int32_t remTicks = dt * m_tempo * 384 / 60; double ticksPerSecond = m_tempo * 384 / 60;
if (!remTicks) remTicks = 1; int32_t remTicks = std::ceil(m_curDt * ticksPerSecond);
if (!remTicks)
break;
/* See if there's an upcoming tempo change in this interval */ /* See if there's an upcoming tempo change in this interval */
if (m_tempoPtr && m_tempoPtr->m_tick != 0xffffffff) if (m_tempoPtr && m_tempoPtr->m_tick != 0xffffffff)
@ -335,9 +338,9 @@ bool SongState::advance(Sequencer& seq, double dt)
m_curTick += remTicks; m_curTick += remTicks;
if (m_tempo == 0) if (m_tempo == 0)
dt = 0.0; m_curDt = 0.0;
else else
dt -= remTicks / double(m_tempo * 384 / 60); m_curDt -= remTicks / ticksPerSecond;
} }
if (done) if (done)

View File

@ -6,7 +6,6 @@ namespace amuse
void Submix::_destroy() void Submix::_destroy()
{ {
m_destroyed = true; m_destroyed = true;
m_backendSubmix.reset();
} }
Submix::Submix(Engine& engine, Submix* smx) Submix::Submix(Engine& engine, Submix* smx)

View File

@ -18,8 +18,6 @@ void Voice::_destroy()
for (std::shared_ptr<Voice>& vox : m_childVoices) for (std::shared_ptr<Voice>& vox : m_childVoices)
vox->_destroy(); vox->_destroy();
m_backendVoice.reset();
} }
Voice::~Voice() Voice::~Voice()
@ -557,9 +555,6 @@ void Voice::_macroKeyOff()
_doKeyOff(); _doKeyOff();
m_voxState = VoiceState::KeyOff; m_voxState = VoiceState::KeyOff;
} }
for (const std::shared_ptr<Voice>& vox : m_childVoices)
vox->keyOff();
} }
void Voice::keyOff() void Voice::keyOff()
@ -575,10 +570,12 @@ void Voice::keyOff()
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep, loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep,
m_state.m_ticksPerSec, m_state.m_initKey, m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod); m_state.m_initVel, m_state.m_initMod);
return;
} }
else else
_macroKeyOff(); _macroKeyOff();
for (const std::shared_ptr<Voice>& vox : m_childVoices)
vox->keyOff();
} }
void Voice::message(int32_t val) 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); const ADSRDLS* adsr = m_audioGroup.getPool().tableAsAdsrDLS(adsrId);
if (adsr) if (adsr)
{
m_volAdsr.reset(adsr, m_state.m_initKey, m_state.m_initVel); m_volAdsr.reset(adsr, m_state.m_initKey, m_state.m_initVel);
if (m_voxState == VoiceState::KeyOff)
m_volAdsr.keyOff();
}
} }
else else
{ {
const ADSR* adsr = m_audioGroup.getPool().tableAsAdsr(adsrId); const ADSR* adsr = m_audioGroup.getPool().tableAsAdsr(adsrId);
if (adsr) if (adsr)
{
m_volAdsr.reset(adsr); m_volAdsr.reset(adsr);
if (m_voxState == VoiceState::KeyOff)
m_volAdsr.keyOff();
}
} }
} }