diff --git a/driver/amuseplay.cpp b/driver/amuseplay.cpp index 4b1613f..c62c16e 100644 --- a/driver/amuseplay.cpp +++ b/driver/amuseplay.cpp @@ -125,7 +125,7 @@ struct AppCallback : boo::IApplicationCallback UpdateSongDisplay(); } - void SongLoop(const amuse::SongGroupIndex& index) + void SongLoop(const amuse::SongGroupIndex& index, boo::IAudioVoiceEngine& booEngine) { printf( "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n" @@ -202,7 +202,7 @@ struct AppCallback : boo::IApplicationCallback UpdateSongDisplay(); } - m_engine->pumpEngine(); + m_win->waitForRetrace(&booEngine); size_t voxCount; int8_t progId; @@ -231,8 +231,6 @@ struct AppCallback : boo::IApplicationCallback m_seq.reset(); break; } - - m_win->waitForRetrace(); } } @@ -260,7 +258,7 @@ struct AppCallback : boo::IApplicationCallback UpdateSFXDisplay(); } - void SFXLoop(const amuse::SFXGroupIndex& index) + void SFXLoop(const amuse::SFXGroupIndex& index, boo::IAudioVoiceEngine& booEngine) { printf(": keyon/keyoff, : cycle SFX, : volume, : quit\n"); @@ -306,7 +304,7 @@ struct AppCallback : boo::IApplicationCallback UpdateSFXDisplay(); } - m_engine->pumpEngine(); + m_win->waitForRetrace(&booEngine); if (m_vox && m_vox->state() == amuse::VoiceState::Dead) { @@ -322,8 +320,6 @@ struct AppCallback : boo::IApplicationCallback m_seq.reset(); break; } - - m_win->waitForRetrace(); } } @@ -876,9 +872,9 @@ struct AppCallback : boo::IApplicationCallback /* Enter playback loop */ if (m_sfxGroup) - SFXLoop(*sfxIndex); + SFXLoop(*sfxIndex, *voxEngine); else - SongLoop(*songIndex); + SongLoop(*songIndex, *voxEngine); printf("\n\n"); } diff --git a/driver/amuserender.cpp b/driver/amuserender.cpp index 25dc2de..0d178b3 100644 --- a/driver/amuserender.cpp +++ b/driver/amuserender.cpp @@ -470,7 +470,7 @@ int main(int argc, const boo::SystemChar** argv) signal(SIGINT, SIGINTHandler); do { - engine.pumpEngine(); + voxEngine->pumpAndMixVoices(); wroteFrames += voxEngine->get5MsFrames(); printf("\rFrame %" PRISize, wroteFrames); fflush(stdout); diff --git a/include/amuse/BooBackend.hpp b/include/amuse/BooBackend.hpp index c38cdc3..a53976e 100644 --- a/include/amuse/BooBackend.hpp +++ b/include/amuse/BooBackend.hpp @@ -116,10 +116,11 @@ public: }; /** Backend voice allocator implementation for boo mixer */ -class BooBackendVoiceAllocator : public IBackendVoiceAllocator +class BooBackendVoiceAllocator : public IBackendVoiceAllocator, public boo::IAudioVoiceEngineCallback { friend class BooBackendMIDIReader; boo::IAudioVoiceEngine& m_booEngine; + Engine* m_cbInterface = nullptr; public: BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine); @@ -127,11 +128,11 @@ public: std::unique_ptr allocateSubmix(Submix& clientSmx, bool mainOut, int busId); std::vector> enumerateMIDIDevices(); std::unique_ptr allocateMIDIReader(Engine& engine, const char* name = nullptr); - void register5MsCallback(std::function&& callback); - void unregister5MsCallback(); + void setCallbackInterface(Engine* engine); AudioChannelSet getAvailableSet(); - void pumpAndMixVoices(); void setVolume(float vol); + void on5MsInterval(boo::IAudioVoiceEngine& engine, double dt); + void onPumpCycleComplete(boo::IAudioVoiceEngine& engine); }; } diff --git a/include/amuse/Engine.hpp b/include/amuse/Engine.hpp index 14f0de9..513d092 100644 --- a/include/amuse/Engine.hpp +++ b/include/amuse/Engine.hpp @@ -65,7 +65,6 @@ class Engine std::list>::iterator _destroySequencer(std::list>::iterator it); void _bringOutYourDead(); - void _5MsCallback(double dt); public: ~Engine(); @@ -74,9 +73,6 @@ public: /** Access voice backend of engine */ IBackendVoiceAllocator& getBackend() { return m_backend; } - /** Update all active audio entities and fill OS audio buffers as needed */ - void pumpEngine(); - /** Add audio group data pointers to engine; must remain resident! */ const AudioGroup* addAudioGroup(const AudioGroupData& data); @@ -130,6 +126,14 @@ public: /** Obtain list of active sequencers */ std::list>& getActiveSequencers() { return m_activeSequencers; } + + /** All mixing occurs in virtual 5ms intervals; + * this is called at the start of each interval for all mixable entities */ + void _on5MsInterval(IBackendVoiceAllocator& engine, double dt); + + /** When a pumping cycle is complete this is called to allow the client to + * perform periodic cleanup tasks */ + void _onPumpCycleComplete(IBackendVoiceAllocator& engine); }; } diff --git a/include/amuse/IBackendVoiceAllocator.hpp b/include/amuse/IBackendVoiceAllocator.hpp index 9490c86..0c28e9a 100644 --- a/include/amuse/IBackendVoiceAllocator.hpp +++ b/include/amuse/IBackendVoiceAllocator.hpp @@ -53,17 +53,11 @@ public: /** Amuse obtains speaker-configuration from the platform this way */ virtual AudioChannelSet getAvailableSet() = 0; - /** Amuse flushes voice samples to the backend this way */ - virtual void pumpAndMixVoices() = 0; - /** Set volume of main mix out */ virtual void setVolume(float vol) = 0; - /** Amuse may request callbacks 200-updates-per-second virtually */ - virtual void register5MsCallback(std::function&& callback) = 0; - - /** This is important to ensure orderly cleanup */ - virtual void unregister5MsCallback() = 0; + /** Amuse registers for key callback events from the mixing engine this way */ + virtual void setCallbackInterface(Engine* engine) = 0; }; } diff --git a/lib/BooBackend.cpp b/lib/BooBackend.cpp index 44f796e..4f816a8 100644 --- a/lib/BooBackend.cpp +++ b/lib/BooBackend.cpp @@ -254,7 +254,11 @@ void BooBackendMIDIReader::stopSeq() {} void BooBackendMIDIReader::reset() {} -BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : m_booEngine(booEngine) {} +BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) +: m_booEngine(booEngine) +{ + booEngine.setCallbackInterface(this); +} std::unique_ptr BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch) @@ -280,19 +284,24 @@ std::unique_ptr BooBackendVoiceAllocator::allocateMIDIReader(Engine return ret; } -void BooBackendVoiceAllocator::register5MsCallback(std::function&& callback) +void BooBackendVoiceAllocator::setCallbackInterface(Engine* engine) { - m_booEngine.register5MsCallback(std::move(callback)); -} - -void BooBackendVoiceAllocator::unregister5MsCallback() -{ - m_booEngine.unregister5MsCallback(); + m_cbInterface = engine; } AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); } -void BooBackendVoiceAllocator::pumpAndMixVoices() { m_booEngine.pumpAndMixVoices(); } - void BooBackendVoiceAllocator::setVolume(float vol) { m_booEngine.setVolume(vol); } + +void BooBackendVoiceAllocator::on5MsInterval(boo::IAudioVoiceEngine& engine, double dt) +{ + if (m_cbInterface) + m_cbInterface->_on5MsInterval(*this, dt); +} + +void BooBackendVoiceAllocator::onPumpCycleComplete(boo::IAudioVoiceEngine& engine) +{ + if (m_cbInterface) + m_cbInterface->_onPumpCycleComplete(*this); +} } diff --git a/lib/Engine.cpp b/lib/Engine.cpp index c5bada3..de24488 100644 --- a/lib/Engine.cpp +++ b/lib/Engine.cpp @@ -15,7 +15,7 @@ static const float FullLevels[8] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; Engine::~Engine() { - m_backend.unregister5MsCallback(); + m_backend.setCallbackInterface(nullptr); for (std::shared_ptr& seq : m_activeSequencers) if (!seq->m_destroyed) seq->_destroy(); @@ -31,7 +31,7 @@ Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode) m_defaultStudio->getAuxA().makeReverbStd(0.5f, 0.8f, 3.0f, 0.5f, 0.1f); m_defaultStudio->getAuxB().makeChorus(15, 0, 500); m_defaultStudioReady = true; - backend.register5MsCallback(std::bind(&Engine::_5MsCallback, this, std::placeholders::_1)); + m_backend.setCallbackInterface(this); m_midiReader = backend.allocateMIDIReader(*this); } @@ -172,7 +172,7 @@ void Engine::_bringOutYourDead() } } -void Engine::_5MsCallback(double dt) +void Engine::_on5MsInterval(IBackendVoiceAllocator& engine, double dt) { if (m_midiReader) m_midiReader->pumpReader(dt); @@ -180,10 +180,8 @@ void Engine::_5MsCallback(double dt) seq->advance(dt); } -/** Update all active audio entities and fill OS audio buffers as needed */ -void Engine::pumpEngine() +void Engine::_onPumpCycleComplete(IBackendVoiceAllocator& engine) { - m_backend.pumpAndMixVoices(); _bringOutYourDead(); /* Determine lowest available free vid */