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, void SFXLoop(const amuse::AudioGroup& group,
const amuse::SFXGroupIndex& index) 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 std::map<uint16_t, const amuse::SFXGroupIndex::SFXEntry*> sortEntries
(index.m_sfxEntries.cbegin(), index.m_sfxEntries.cend()); (index.m_sfxEntries.cbegin(), index.m_sfxEntries.cend());
@ -237,7 +237,6 @@ struct AppCallback : boo::IApplicationCallback
while (m_running) while (m_running)
{ {
m_events.dispatchEvents(); m_events.dispatchEvents();
m_engine->pumpEngine();
if (m_wantsNext) if (m_wantsNext)
{ {
@ -269,6 +268,14 @@ struct AppCallback : boo::IApplicationCallback
UpdateSFXDisplay(); UpdateSFXDisplay();
} }
m_engine->pumpEngine();
if (m_vox && m_vox->state() == amuse::VoiceState::Dead)
{
m_vox.reset();
UpdateSFXDisplay();
}
m_win->waitForRetrace(); m_win->waitForRetrace();
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ enum class VoiceState
{ {
Playing, /**< SoundMacro actively executing, not in KeyOff */ Playing, /**< SoundMacro actively executing, not in KeyOff */
KeyOff, /**< KeyOff event issued, macro beginning fade-out */ 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 */ /** 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_sampleRate; /**< Current sample rate computed from relative sample key or SETPITCH */
double m_voiceTime; /**< Current seconds of voice playback (per-sample resolution) */ 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_sustained = false; /**< Sustain pedal pressed for this voice */
bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */ 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); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice);
public: public:
~Voice();
Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx); 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); 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 const Sample* AudioGroup::getSample(int sfxId) const
{ {
for (const auto& ent : m_sdir.m_entries) auto search = m_sdir.m_entries.find(sfxId);
if (ent.second.first.m_sfxId == sfxId) if (search == m_sdir.m_entries.cend())
return &ent.second; return nullptr;
return nullptr; return &search->second;
} }
const unsigned char* AudioGroup::getSampleData(uint32_t offset) const 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) while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{ {
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur)); 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_soundMacros[id] = cur + 8; m_soundMacros[id] = cur;
cur += size; cur += size;
} }
} }
@ -43,7 +43,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff) while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{ {
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur)); 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; m_tables[id] = cur + 8;
cur += size; cur += size;
} }
@ -55,7 +55,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff) while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{ {
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur)); 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); m_keymaps[id] = reinterpret_cast<const Keymap*>(cur + 8);
cur += size; cur += size;
} }
@ -67,7 +67,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff) while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{ {
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur)); 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]; std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur+8)); uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur+8));

View File

@ -6,6 +6,7 @@ namespace amuse
void AudioGroupSampleDirectory::Entry::swapBig() void AudioGroupSampleDirectory::Entry::swapBig()
{ {
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff); m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk); m_unk = SBig(m_unk);
m_sampleRate = SBig(m_sampleRate); m_sampleRate = SBig(m_sampleRate);
@ -35,7 +36,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data)
const AudioGroupSampleDirectory::Entry* ent = const AudioGroupSampleDirectory::Entry* ent =
reinterpret_cast<const AudioGroupSampleDirectory::Entry*>(cur); 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 = *ent;
store.first.swapBig(); store.first.swapBig();

View File

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

View File

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

View File

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

View File

@ -33,7 +33,14 @@ float Envelope::nextSample(double sampleRate)
{ {
case State::Attack: 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) if (attackFac >= 1.0)
{ {
m_phase = State::Decay; m_phase = State::Decay;
@ -45,7 +52,15 @@ float Envelope::nextSample(double sampleRate)
} }
case State::Decay: 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) if (decayFac >= 1.0)
{ {
m_phase = State::Sustain; m_phase = State::Sustain;
@ -62,7 +77,10 @@ float Envelope::nextSample(double sampleRate)
} }
case State::Release: 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) if (releaseFac >= 1.0)
return 0.f; return 0.f;
return (1.0 - releaseFac) * m_releaseStartFactor; return (1.0 - releaseFac) * m_releaseStartFactor;

View File

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

View File

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

View File

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