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 <map>
#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;

View File

@ -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` */

View File

@ -13,14 +13,14 @@ namespace amuse
Engine::~Engine()
{
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
seq->_destroy();
while (m_activeSubmixes.size())
removeSubmix(&m_activeSubmixes.front());
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
emitter->_destroy();
for (std::shared_ptr<Voice>& vox : m_activeVoices)
vox->_destroy();
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
seq->_destroy();
}
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)
return {};
/* Ensure keyoff sent first */
keyOff(note, 0);
std::shared_ptr<Voice> ret = m_parent.m_engine._allocateVoice(m_parent.m_audioGroup,
m_parent.m_groupId, 32000.0,
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_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)

View File

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

View File

@ -18,8 +18,6 @@ void Voice::_destroy()
for (std::shared_ptr<Voice>& 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<Voice>& 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<Voice>& 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();
}
}
}