Working SFXGroup playback

This commit is contained in:
Jack Andersen 2016-05-14 12:38:37 -10:00
parent b1e7f66199
commit 1382a1e946
17 changed files with 249 additions and 170 deletions

View File

@ -226,7 +226,7 @@ struct AppCallback : boo::IApplicationCallback
void SFXLoop(const amuse::AudioGroup& group,
const amuse::SFXGroupIndex& index)
{
printf("<space>: keyon/keyon, <left/right>: cycle SFX, <up/down>: volume, <Q>: quit\n");
printf("<space>: keyon/keyoff, <left/right>: cycle SFX, <up/down>: volume, <Q>: quit\n");
std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries
(index.m_sfxEntries.cbegin(), index.m_sfxEntries.cend());
@ -237,7 +237,6 @@ struct AppCallback : boo::IApplicationCallback
while (m_running)
{
m_events.dispatchEvents();
m_engine->pumpEngine();
if (m_wantsNext)
{
@ -269,6 +268,14 @@ struct AppCallback : boo::IApplicationCallback
UpdateSFXDisplay();
}
m_engine->pumpEngine();
if (m_vox && m_vox->state() == amuse::VoiceState::Dead)
{
m_vox.reset();
UpdateSFXDisplay();
}
m_win->waitForRetrace();
}
}

View File

@ -17,6 +17,7 @@ class Emitter : public Entity
friend class Engine;
void _destroy();
public:
~Emitter();
Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox);
void setPos(const Vector3f& pos);

View File

@ -41,6 +41,7 @@ class Engine
std::list<Submix>::iterator _destroySubmix(Submix* smx);
void _bringOutYourDead();
public:
~Engine();
Engine(IBackendVoiceAllocator& backend);
/** Access voice backend of engine */

View File

@ -41,7 +41,7 @@ protected:
}
Engine& m_engine;
const AudioGroup& m_audioGroup;
ObjectId m_objectId; /* if applicable */
ObjectId m_objectId = 0xffff; /* if applicable */
public:
Entity(Engine& engine, const AudioGroup& group, ObjectId oid=ObjectId())
: m_engine(engine), m_audioGroup(group), m_objectId(oid) {}

View File

@ -9,6 +9,7 @@ namespace amuse
class Sequencer : public Entity
{
public:
~Sequencer();
};
}

View File

@ -130,6 +130,7 @@ class SoundMacroState
bool m_sampleEnd; /**< sample has finished playback */
bool m_inWait = false; /**< set when timer/keyoff/sampleend wait active */
bool m_indefiniteWait = false; /**< set when timer wait is indefinite (keyoff/sampleend only) */
bool m_keyoffWait = false; /**< set when active wait is a keyoff wait */
bool m_sampleEndWait = false; /**< set when active wait is a sampleend wait */
double m_waitCountdown; /**< countdown timer for active wait */
@ -210,7 +211,7 @@ class SoundMacroState
/** Event registration data for TRAP_EVENT */
struct EventTrap
{
ObjectId macroId;
ObjectId macroId = 0xffff;
uint16_t macroStep;
};
EventTrap m_keyoffTrap;

View File

@ -21,7 +21,7 @@ enum class VoiceState
{
Playing, /**< SoundMacro actively executing, not in KeyOff */
KeyOff, /**< KeyOff event issued, macro beginning fade-out */
Finished /**< Default state, causes Engine to remove voice at end of pump cycle */
Dead /**< Default state, causes Engine to remove voice at end of pump cycle */
};
/** Individual source of audio */
@ -55,7 +55,7 @@ class Voice : public Entity
double m_sampleRate; /**< Current sample rate computed from relative sample key or SETPITCH */
double m_voiceTime; /**< Current seconds of voice playback (per-sample resolution) */
VoiceState m_voxState = VoiceState::Finished; /**< Current high-level state of voice */
VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */
bool m_sustained = false; /**< Sustain pedal pressed for this voice */
bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */
@ -117,6 +117,7 @@ class Voice : public Entity
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice);
public:
~Voice();
Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx);
Voice(Engine& engine, const AudioGroup& group, ObjectId oid, int vid, bool emitter, Submix* smx);

View File

@ -14,10 +14,10 @@ AudioGroup::AudioGroup(int groupId, const AudioGroupData& data)
const Sample* AudioGroup::getSample(int sfxId) const
{
for (const auto& ent : m_sdir.m_entries)
if (ent.second.first.m_sfxId == sfxId)
return &ent.second;
return nullptr;
auto search = m_sdir.m_entries.find(sfxId);
if (search == m_sdir.m_entries.cend())
return nullptr;
return &search->second;
}
const unsigned char* AudioGroup::getSampleData(uint32_t offset) const

View File

@ -31,8 +31,8 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
m_soundMacros[id] = cur + 8;
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
m_soundMacros[id] = cur;
cur += size;
}
}
@ -43,7 +43,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
m_tables[id] = cur + 8;
cur += size;
}
@ -55,7 +55,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
m_keymaps[id] = reinterpret_cast<const Keymap*>(cur + 8);
cur += size;
}
@ -67,7 +67,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur+8));

View File

@ -6,6 +6,7 @@ namespace amuse
void AudioGroupSampleDirectory::Entry::swapBig()
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk);
m_sampleRate = SBig(m_sampleRate);
@ -35,7 +36,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data)
const AudioGroupSampleDirectory::Entry* ent =
reinterpret_cast<const AudioGroupSampleDirectory::Entry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
std::pair<Entry, ADPCMParms>& store = m_entries[SBig(ent->m_sfxId)];
store.first = *ent;
store.first.swapBig();

View File

@ -37,9 +37,9 @@ static const size_t LPTapDelays[] =
void ReverbDelayLine::allocate(int32_t delay)
{
delay += 2;
x8_length = delay * sizeof(float);
x8_length = delay;
xc_inputs.reset(new float[delay]);
memset(xc_inputs.get(), 0, x8_length);
memset(xc_inputs.get(), 0, x8_length * sizeof(float));
x10_lastInput = 0.f;
setdelay(delay / 2);
x0_inPoint = 0;
@ -48,7 +48,7 @@ void ReverbDelayLine::allocate(int32_t delay)
void ReverbDelayLine::setdelay(int32_t delay)
{
x4_outPoint = x0_inPoint - delay * sizeof(float);
x4_outPoint = x0_inPoint - delay;
while (x4_outPoint < 0)
x4_outPoint += x8_length;
}
@ -162,23 +162,23 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
{
sample2 = *preDelayPtr;
*preDelayPtr = sample;
preDelayPtr += 4;
preDelayPtr += 1;
if (preDelayPtr == lastPreDelaySamp)
preDelayPtr = preDelayLine;
}
/* Comb filter stage */
linesC[0].xc_inputs[linesC[0].x0_inPoint] = combCoefs[0] * linesC[0].x10_lastInput + sample2;
linesC[0].x0_inPoint += 4;
linesC[0].x0_inPoint += 1;
linesC[1].xc_inputs[linesC[1].x0_inPoint] = combCoefs[1] * linesC[1].x10_lastInput + sample2;
linesC[1].x0_inPoint += 4;
linesC[1].x0_inPoint += 1;
linesC[0].x10_lastInput = linesC[0].xc_inputs[linesC[0].x4_outPoint];
linesC[0].x4_outPoint += 4;
linesC[0].x4_outPoint += 1;
linesC[1].x10_lastInput = linesC[1].xc_inputs[linesC[1].x4_outPoint];
linesC[1].x4_outPoint += 4;
linesC[1].x4_outPoint += 1;
if (linesC[0].x0_inPoint == linesC[0].x8_length)
linesC[0].x0_inPoint = 0;
@ -197,10 +197,10 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
xf0_allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput;
float lowPass = -(xf0_allPassCoef * linesAP[0].xc_inputs[linesAP[0].x0_inPoint] -
linesAP[0].x10_lastInput);
linesAP[0].x0_inPoint += 4;
linesAP[0].x0_inPoint += 1;
linesAP[0].x10_lastInput = linesAP[0].xc_inputs[linesAP[0].x4_outPoint];
linesAP[0].x4_outPoint += 4;
linesAP[0].x4_outPoint += 1;
if (linesAP[0].x0_inPoint == linesAP[0].x8_length)
linesAP[0].x0_inPoint = 0;
@ -212,10 +212,10 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
linesAP[1].xc_inputs[linesAP[1].x0_inPoint] = xf0_allPassCoef * linesAP[1].x10_lastInput + lpLastOut;
float allPass = -(xf0_allPassCoef * linesAP[1].xc_inputs[linesAP[1].x0_inPoint] -
linesAP[1].x10_lastInput);
linesAP[1].x0_inPoint += 4;
linesAP[1].x0_inPoint += 1;
linesAP[1].x10_lastInput = linesAP[1].xc_inputs[linesAP[1].x4_outPoint];
linesAP[1].x4_outPoint += 4;
linesAP[1].x4_outPoint += 1;
if (linesAP[1].x0_inPoint == linesAP[1].x8_length)
linesAP[1].x0_inPoint = 0;
@ -249,7 +249,7 @@ void EffectReverbHiImp<T>::_update()
float timeSamples = x148_x1d0_time * m_sampleRate;
for (int c=0 ; c<8 ; ++c)
{
for (int t=0 ; t<2 ; ++t)
for (int t=0 ; t<3 ; ++t)
{
ReverbDelayLine& combLine = xb4_C[c][t];
size_t tapDelay = CTapDelays[t] * m_sampleRate / 32000.0;
@ -333,23 +333,29 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
{
sample2 = *preDelayPtr;
*preDelayPtr = sample;
preDelayPtr += 4;
preDelayPtr += 1;
if (preDelayPtr == lastPreDelaySamp)
preDelayPtr = preDelayLine;
}
/* Comb filter stage */
linesC[0].xc_inputs[linesC[0].x0_inPoint] = combCoefs[0] * linesC[0].x10_lastInput + sample2;
linesC[0].x0_inPoint += 4;
linesC[0].x0_inPoint += 1;
linesC[1].xc_inputs[linesC[1].x0_inPoint] = combCoefs[1] * linesC[1].x10_lastInput + sample2;
linesC[1].x0_inPoint += 4;
linesC[1].x0_inPoint += 1;
linesC[2].xc_inputs[linesC[2].x0_inPoint] = combCoefs[2] * linesC[2].x10_lastInput + sample2;
linesC[2].x0_inPoint += 1;
linesC[0].x10_lastInput = linesC[0].xc_inputs[linesC[0].x4_outPoint];
linesC[0].x4_outPoint += 4;
linesC[0].x4_outPoint += 1;
linesC[1].x10_lastInput = linesC[1].xc_inputs[linesC[1].x4_outPoint];
linesC[1].x4_outPoint += 4;
linesC[1].x4_outPoint += 1;
linesC[2].x10_lastInput = linesC[2].xc_inputs[linesC[2].x4_outPoint];
linesC[2].x4_outPoint += 1;
if (linesC[0].x0_inPoint == linesC[0].x8_length)
linesC[0].x0_inPoint = 0;
@ -357,23 +363,29 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
if (linesC[1].x0_inPoint == linesC[1].x8_length)
linesC[1].x0_inPoint = 0;
if (linesC[2].x0_inPoint == linesC[2].x8_length)
linesC[2].x0_inPoint = 0;
if (linesC[0].x4_outPoint == linesC[0].x8_length)
linesC[0].x4_outPoint = 0;
if (linesC[1].x4_outPoint == linesC[1].x8_length)
linesC[1].x4_outPoint = 0;
if (linesC[2].x4_outPoint == linesC[2].x8_length)
linesC[2].x4_outPoint = 0;
/* All-pass filter stage */
linesAP[0].xc_inputs[linesAP[0].x0_inPoint] =
allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput;
allPassCoef * linesAP[0].x10_lastInput + linesC[0].x10_lastInput + linesC[1].x10_lastInput + linesC[2].x10_lastInput;
linesAP[1].xc_inputs[linesAP[1].x0_inPoint] =
allPassCoef * linesAP[1].x10_lastInput -
(allPassCoef * linesAP[0].xc_inputs[linesAP[0].x0_inPoint] - linesAP[0].x10_lastInput);
float lowPass = -(allPassCoef * linesAP[1].xc_inputs[linesAP[1].x0_inPoint] - linesAP[1].x10_lastInput);
linesAP[0].x0_inPoint += 4;
linesAP[1].x0_inPoint += 4;
linesAP[0].x0_inPoint += 1;
linesAP[1].x0_inPoint += 1;
if (linesAP[0].x0_inPoint == linesAP[0].x8_length)
linesAP[0].x0_inPoint = 0;
@ -382,10 +394,10 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
linesAP[1].x0_inPoint = 0;
linesAP[0].x10_lastInput = linesAP[0].xc_inputs[linesAP[0].x4_outPoint];
linesAP[0].x4_outPoint += 4;
linesAP[0].x4_outPoint += 1;
linesAP[1].x10_lastInput = linesAP[1].xc_inputs[linesAP[1].x4_outPoint];
linesAP[1].x4_outPoint += 4;
linesAP[1].x4_outPoint += 1;
if (linesAP[0].x4_outPoint == linesAP[0].x8_length)
linesAP[0].x4_outPoint = 0;
@ -396,10 +408,10 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
lpLastOut = damping * lpLastOut + lowPass * 0.3f;
lineLP.xc_inputs[lineLP.x0_inPoint] = allPassCoef * lineLP.x10_lastInput + lpLastOut;
float allPass = -(allPassCoef * lineLP.xc_inputs[lineLP.x0_inPoint] - lineLP.x10_lastInput);
lineLP.x0_inPoint += 4;
lineLP.x0_inPoint += 1;
lineLP.x10_lastInput = lineLP.xc_inputs[lineLP.x4_outPoint];
lineLP.x4_outPoint += 4;
lineLP.x4_outPoint += 1;
if (lineLP.x0_inPoint == lineLP.x8_length)
lineLP.x0_inPoint = 0;

View File

@ -5,6 +5,8 @@
namespace amuse
{
Emitter::~Emitter() {}
Emitter::Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox)
: Entity(engine, group, vox->getObjectId()), m_vox(std::move(vox))
{

View File

@ -11,6 +11,8 @@
namespace amuse
{
Engine::~Engine() {}
Engine::Engine(IBackendVoiceAllocator& backend)
: m_backend(backend)
{}
@ -56,7 +58,7 @@ void Engine::_bringOutYourDead()
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
{
Emitter* emitter = it->get();
if (emitter->getVoice()->m_voxState == VoiceState::Finished)
if (emitter->getVoice()->m_voxState == VoiceState::Dead)
{
emitter->_destroy();
it = m_activeEmitters.erase(it);
@ -69,7 +71,7 @@ void Engine::_bringOutYourDead()
{
Voice* vox = it->get();
vox->_bringOutYourDead();
if (vox->m_voxState == VoiceState::Finished)
if (vox->m_voxState == VoiceState::Dead)
{
it = _destroyVoice(vox);
continue;
@ -106,7 +108,7 @@ const AudioGroup* Engine::addAudioGroup(int groupId, const AudioGroupData& data)
const SFXGroupIndex& sfxGroup = pair.second;
m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
for (const auto& pair : sfxGroup.m_sfxEntries)
m_sfxLookup[pair.first] = std::make_pair(ret, pair.second->objId);
m_sfxLookup[pair.first] = std::make_pair(ret, SBig(pair.second->objId));
}
return ret;

View File

@ -33,7 +33,14 @@ float Envelope::nextSample(double sampleRate)
{
case State::Attack:
{
double attackFac = m_curMs / (m_curADSR->attackCoarse * 255 + m_curADSR->attackFine);
uint16_t attack = m_curADSR->attackCoarse * 255 + m_curADSR->attackFine;
if (attack == 0)
{
m_phase = State::Decay;
m_curMs = 0;
return 1.f;
}
double attackFac = m_curMs / double(attack);
if (attackFac >= 1.0)
{
m_phase = State::Decay;
@ -45,7 +52,15 @@ float Envelope::nextSample(double sampleRate)
}
case State::Decay:
{
double decayFac = m_curMs / (m_curADSR->decayCoarse * 255 + m_curADSR->decayFine);
uint16_t decay = m_curADSR->decayCoarse * 255 + m_curADSR->decayFine;
if (decay == 0)
{
m_phase = State::Sustain;
m_curMs = 0;
m_releaseStartFactor = m_sustainFactor;
return m_sustainFactor;
}
double decayFac = m_curMs / double(decay);
if (decayFac >= 1.0)
{
m_phase = State::Sustain;
@ -62,7 +77,10 @@ float Envelope::nextSample(double sampleRate)
}
case State::Release:
{
double releaseFac = m_curMs / (m_curADSR->releaseCoarse * 255 + m_curADSR->releaseFine);
uint16_t release = m_curADSR->releaseCoarse * 255 + m_curADSR->releaseFine;
if (release == 0)
return 0.f;
double releaseFac = m_curMs / double(release);
if (releaseFac >= 1.0)
return 0.f;
return (1.0 - releaseFac) * m_releaseStartFactor;

View File

@ -3,4 +3,6 @@
namespace amuse
{
Sequencer::~Sequencer() {}
}

View File

@ -12,6 +12,7 @@ namespace amuse
void SoundMacroState::Header::swapBig()
{
m_size = SBig(m_size);
m_macroId = SBig(m_macroId);
}
void SoundMacroState::Command::swapBig()
@ -150,10 +151,14 @@ bool SoundMacroState::advance(Voice& vox, double dt)
/* Advance wait timer if active, returning if waiting */
if (m_inWait)
{
m_waitCountdown -= dt;
if (m_waitCountdown < 0.f)
m_inWait = false;
else
if (!m_indefiniteWait)
{
m_waitCountdown -= dt;
if (m_waitCountdown < 0.f)
m_inWait = false;
}
if (m_inWait)
{
m_execTime += dt;
return false;
@ -218,20 +223,27 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int16_t time = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
/* Set wait state */
float q = ms ? 1000.f : m_ticksPerSec;
float secTime = time / q;
if (absolute)
if (time >= 0)
{
if (secTime <= m_execTime)
break;
m_waitCountdown = secTime - m_execTime;
float q = ms ? 1000.f : m_ticksPerSec;
float secTime = time / q;
if (absolute)
{
if (secTime <= m_execTime)
break;
m_waitCountdown = secTime - m_execTime;
}
else
m_waitCountdown = secTime;
/* Randomize at the proper resolution */
if (random)
secTime = std::fmod(vox.getEngine().nextRandom() / q, secTime);
m_indefiniteWait = false;
}
else
m_waitCountdown = secTime;
/* Randomize at the proper resolution */
if (random)
secTime = std::fmod(vox.getEngine().nextRandom() / q, secTime);
m_indefiniteWait = true;
m_inWait = true;
m_keyoffWait = keyRelease;
@ -293,19 +305,26 @@ bool SoundMacroState::advance(Voice& vox, double dt)
int16_t time = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
/* Set wait state */
float secTime = time / 1000.f;
if (absolute)
if (time >= 0)
{
if (secTime <= m_execTime)
break;
m_waitCountdown = secTime - m_execTime;
float secTime = time / 1000.f;
if (absolute)
{
if (secTime <= m_execTime)
break;
m_waitCountdown = secTime - m_execTime;
}
else
m_waitCountdown = secTime;
/* Randomize at the proper resolution */
if (random)
secTime = std::fmod(vox.getEngine().nextRandom() / 1000.f, secTime);
m_indefiniteWait = false;
}
else
m_waitCountdown = secTime;
/* Randomize at the proper resolution */
if (random)
secTime = std::fmod(vox.getEngine().nextRandom() / 1000.f, secTime);
m_indefiniteWait = true;
m_inWait = true;
m_keyoffWait = keyRelease;
@ -546,7 +565,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
noteLo *= 100;
noteHi *= 100;
m_curKey = vox.getEngine().nextRandom() % (noteHi - noteLo) + noteLo;
m_curKey = vox.getEngine().nextRandom() % ((noteHi - noteLo) + noteLo);
if (!free)
m_curKey = m_curKey / 100 * 100 + detune;

View File

@ -22,6 +22,8 @@ void Voice::_destroy()
vox->_destroy();
}
Voice::~Voice() {}
Voice::Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx)
: Entity(engine, group), m_vid(vid), m_emitter(emitter), m_submix(smx)
{
@ -83,6 +85,7 @@ void Voice::_doKeyOff()
{
m_volAdsr.keyOff();
m_pitchAdsr.keyOff();
m_state.keyoffNotify(*this);
}
void Voice::_setTotalPitch(int32_t cents)
@ -99,7 +102,7 @@ void Voice::_bringOutYourDead()
{
Voice* vox = it->get();
vox->_bringOutYourDead();
if (vox->m_voxState == VoiceState::Finished)
if (vox->m_voxState == VoiceState::Dead)
{
it = _destroyVoice(vox);
continue;
@ -263,112 +266,119 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
uint32_t samplesRem = samples;
size_t samplesProc = 0;
bool dead = false;
/* Attempt to load stopped sample for immediate decoding */
if (!m_curSample)
dead = m_state.advance(*this, 0.0);
if (m_curSample)
{
dead = m_state.advance(*this, samples / m_sampleRate);
uint32_t block = m_curSamplePos / 14;
uint32_t rem = m_curSamplePos % 14;
if (rem)
if (!dead)
{
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
uint32_t decSamples;
uint32_t block = m_curSamplePos / 14;
uint32_t rem = m_curSamplePos % 14;
switch (m_curFormat)
if (rem)
{
case SampleFormat::DSP:
{
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;
}
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
uint32_t decSamples;
/* Per-sample processing */
for (int i=0 ; i<decSamples ; ++i)
{
++samplesProc;
++m_curSamplePos;
if (_advanceSample(data[i]))
return samplesProc;
switch (m_curFormat)
{
case SampleFormat::DSP:
{
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;
}
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 (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 (samplesRem)
memset(data, 0, sizeof(int16_t) * samplesRem);
return samples;
}
}
}
}
else
{
dead = m_state.advance(*this, 0.0);
memset(data, 0, sizeof(int16_t) * samples);
}
if (dead)
m_voxState = VoiceState::Finished;
{
m_voxState = VoiceState::Dead;
m_backendVoice->stop();
}
return samples;
}
@ -412,6 +422,7 @@ bool Voice::loadSoundMacro(ObjectId macroId, int macroStep, double ticksPerSec,
}
m_voxState = VoiceState::Playing;
m_backendVoice->start();
return true;
}
@ -441,18 +452,17 @@ void Voice::startSample(int16_t sampId, int32_t offset)
m_sampleRate = m_curSample->first.m_sampleRate;
m_curPitch = m_curSample->first.m_pitch;
m_pitchDirty = true;
m_backendVoice->stop();
m_backendVoice->resetSampleRate(m_curSample->first.m_sampleRate);
m_curSamplePos = offset;
m_curSampleData = m_audioGroup.getSampleData(m_curSample->first.m_sampleOff);
m_prev1 = 0;
m_prev2 = 0;
uint32_t numSamples = m_curSample->first.m_numSamples & 0xffffff;
SampleFormat fmt = SampleFormat(m_curSample->first.m_numSamples >> 24);
m_curFormat = SampleFormat(m_curSample->first.m_numSamples >> 24);
m_lastSamplePos = m_curSample->first.m_loopLengthSamples ?
(m_curSample->first.m_loopStartSample + m_curSample->first.m_loopLengthSamples) : numSamples;
if (fmt != SampleFormat::DSP && fmt != SampleFormat::PCM)
if (m_curFormat != SampleFormat::DSP && m_curFormat != SampleFormat::PCM)
{
m_curSample = nullptr;
return;
@ -461,7 +471,7 @@ void Voice::startSample(int16_t sampId, int32_t offset)
_checkSamplePos();
/* Seek DSPADPCM state if needed */
if (m_curSamplePos && fmt == SampleFormat::DSP)
if (m_curSamplePos && m_curFormat == SampleFormat::DSP)
{
uint32_t block = m_curSamplePos / 14;
uint32_t rem = m_curSamplePos % 14;
@ -473,14 +483,11 @@ void Voice::startSample(int16_t sampId, int32_t offset)
DSPDecompressFrameStateOnly(m_curSampleData + 8 * block, m_curSample->second.m_coefs,
&m_prev1, &m_prev2, rem);
}
m_backendVoice->start();
}
}
void Voice::stopSample()
{
m_backendVoice->stop();
m_curSample = nullptr;
}
@ -600,7 +607,8 @@ void Voice::setReverbVol(float rvol)
void Voice::setAdsr(ObjectId adsrId)
{
const ADSR* adsr = m_audioGroup.getPool().tableAsAdsr(adsrId);
m_volAdsr.reset(adsr);
if (adsr)
m_volAdsr.reset(adsr);
}
void Voice::setPitchFrequency(uint32_t hz, uint16_t fine)
@ -613,9 +621,12 @@ void Voice::setPitchFrequency(uint32_t hz, uint16_t fine)
void Voice::setPitchAdsr(ObjectId adsrId, int32_t cents)
{
const ADSR* adsr = m_audioGroup.getPool().tableAsAdsr(adsrId);
m_pitchAdsr.reset(adsr);
m_pitchEnvRange = cents;
m_pitchEnv = true;
if (adsr)
{
m_pitchAdsr.reset(adsr);
m_pitchEnvRange = cents;
m_pitchEnv = true;
}
}
void Voice::setPitchWheelRange(int8_t up, int8_t down)