mirror of https://github.com/AxioDL/amuse.git
Working SFXGroup playback
This commit is contained in:
parent
b1e7f66199
commit
1382a1e946
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace amuse
|
||||||
class Sequencer : public Entity
|
class Sequencer : public Entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
~Sequencer();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -3,4 +3,6 @@
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Sequencer::~Sequencer() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
205
lib/Voice.cpp
205
lib/Voice.cpp
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue