mirror of https://github.com/AxioDL/amuse.git
Timing fixes for SON playback
This commit is contained in:
parent
3433a70462
commit
2115a958b1
|
@ -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;
|
||||||
|
|
|
@ -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` */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue