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,
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace amuse
|
|||
class Sequencer : public Entity
|
||||
{
|
||||
public:
|
||||
~Sequencer();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,4 +3,6 @@
|
|||
namespace amuse
|
||||
{
|
||||
|
||||
Sequencer::~Sequencer() {}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
205
lib/Voice.cpp
205
lib/Voice.cpp
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue