diff --git a/Src/IAEngine/imp/cpp/Audio.cpp b/Src/IAEngine/imp/cpp/Audio.cpp index 28eb3ad..087c6d6 100644 --- a/Src/IAEngine/imp/cpp/Audio.cpp +++ b/Src/IAEngine/imp/cpp/Audio.cpp @@ -19,12 +19,26 @@ #include #include +#include #include namespace ia::iae { + struct TrackData + { + BOOL IsActive{}; + MIX_Track *Track{}; + INT32 LoopTimes{}; + TimePeriod LoopDelay{}; + std::thread *PlaybackThread; + + std::mutex Mutex; + std::condition_variable CV; + }; + MIX_Mixer *g_mixer{}; - Vector g_tracks; + Vector g_tracks; + Vector g_destroyQueue; Vector g_audioData; VOID Audio::Initialize() @@ -38,7 +52,48 @@ namespace ia::iae VOID Audio::Terminate() { + for (SIZE_T i = 0; i < g_tracks.size(); i++) + { + { + std::lock_guard lock(g_tracks[i]->Mutex); + g_tracks[i]->IsActive = false; + } + g_tracks[i]->CV.notify_one(); + g_tracks[i]->PlaybackThread->join(); + delete g_tracks[i]; + } + MIX_StopAllTracks(g_mixer, 0); g_audioData.clear(); + g_tracks.clear(); + } + + VOID Audio::Update() + { + for (SIZE_T i = 0; i < g_tracks.size(); i++) + { + auto &t = g_tracks[i]; + if (!t->IsActive && !MIX_TrackPlaying(t->Track)) + DestroyTrack(i); + } + + // [IATODO]: IMPL: Destroy queue + } + + INT64 Audio::CreateTrack() + { + g_tracks.pushBack(new TrackData{true, MIX_CreateTrack(g_mixer)}); + return g_tracks.size() - 1; + } + + VOID Audio::DestroyTrack(IN INT64 trackHandle) + { + if(trackHandle >= g_tracks.size()) + return; + auto& t = g_tracks[trackHandle]; + ClearTrack(trackHandle); + MIX_StopTrack(t->Track, 0); + t->IsActive = false; + g_destroyQueue.pushBack(trackHandle); } Sound Audio::CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize) @@ -47,62 +102,55 @@ namespace ia::iae return Sound(g_audioData.size() - 1); } - INT64 Audio::CreateTrack() - { - g_tracks.pushBack(MIX_CreateTrack(g_mixer)); - return g_tracks.size() - 1; - } - - VOID Audio::DestroyTrack(IN INT64 trackHandle) - { - ClearTrack(trackHandle); - } - VOID Audio::QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle) { - MIX_SetTrackAudio(g_tracks[trackHandle], g_audioData[dataHandle]); + MIX_SetTrackAudio(g_tracks[trackHandle]->Track, g_audioData[dataHandle]); } VOID Audio::PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay) { - struct __callback_data - { - INT32 loopTimes; - TimePeriod loopDelay; - }; - - const auto callbackData = new __callback_data{.loopTimes = loopTimes, .loopDelay = loopDelay}; - - MIX_PlayTrack(g_tracks[trackHandle], 0); - MIX_SetTrackStoppedCallback( - g_tracks[trackHandle], - [](PVOID _callbackData, MIX_Track *track) { - const auto callbackData = (__callback_data *) _callbackData; - if (callbackData->loopTimes < 0) - goto loop_next_iteration; - else if (callbackData->loopTimes == 0) - return; - else - callbackData->loopTimes -= 1; - loop_next_iteration: - std::this_thread::sleep_for(std::chrono::milliseconds((INT32) (callbackData->loopDelay.GetValue() * 1000))); - MIX_PlayTrack(track, 0); - }, - callbackData); + auto &t = g_tracks[trackHandle]; + t->LoopTimes = loopTimes; + t->LoopDelay = loopDelay; + if (t->LoopTimes == 0) + t->IsActive = false; + else + t->PlaybackThread = new std::thread([trackHandle]() { + auto &t = g_tracks[trackHandle]; + while (t->IsActive) + { + if (MIX_TrackPlaying(t->Track)) + continue; + if (t->LoopTimes < 0) + goto loop_next_iteration; + else if (!t->LoopTimes) + { + t->IsActive = false; + return; + } + t->LoopTimes--; + loop_next_iteration: + std::unique_lock lock(t->Mutex); + t->CV.wait_for(lock, std::chrono::milliseconds((INT32) (t->LoopDelay.GetValue() * 1000)), + [t]() { return !t->IsActive; }); + MIX_PlayTrack(t->Track, 0); + } + }); + MIX_PlayTrack(t->Track, 0); } VOID Audio::ClearTrack(IN INT64 trackHandle) { - MIX_StopTrack(g_tracks[trackHandle], 0); + MIX_StopTrack(g_tracks[trackHandle]->Track, 0); } VOID Audio::PauseTrack(IN INT64 trackHandle) { - MIX_PauseTrack(g_tracks[trackHandle]); + MIX_PauseTrack(g_tracks[trackHandle]->Track); } VOID Audio::ResumeTrack(IN INT64 trackHandle) { - MIX_ResumeTrack(g_tracks[trackHandle]); + MIX_ResumeTrack(g_tracks[trackHandle]->Track); } } // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/IAEngine.cpp b/Src/IAEngine/imp/cpp/IAEngine.cpp index 62c3674..f42ff9d 100644 --- a/Src/IAEngine/imp/cpp/IAEngine.cpp +++ b/Src/IAEngine/imp/cpp/IAEngine.cpp @@ -138,6 +138,7 @@ namespace ia::iae g_physicsDebugDrawEnabled = !g_physicsDebugDrawEnabled; Physics::Update(); + Audio::Update(); if B_LIKELY (g_activeScene) g_activeScene->Update(); diff --git a/Src/IAEngine/inc/IAEngine/Audio.hpp b/Src/IAEngine/inc/IAEngine/Audio.hpp index dda5d67..4528792 100644 --- a/Src/IAEngine/inc/IAEngine/Audio.hpp +++ b/Src/IAEngine/inc/IAEngine/Audio.hpp @@ -63,12 +63,14 @@ namespace ia::iae public: STATIC VOID Initialize(); STATIC VOID Terminate(); - - STATIC Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize); + + STATIC VOID Update(); STATIC INT64 CreateTrack(); STATIC VOID DestroyTrack(IN INT64 trackHandle); + STATIC Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize); + STATIC VOID QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle); STATIC VOID PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay); STATIC VOID ClearTrack(IN INT64 trackHandle);