#include "audiostream.h" #include "cfg/cfg.h" #include #include struct SoundFrame { s16 l;s16 r; }; constexpr u32 SAMPLE_COUNT = 512; static SoundFrame RingBuffer[SAMPLE_COUNT]; static u32 WritePtr; //last WRITTEN sample static audiobackend_t *audiobackend_current = nullptr; static std::unique_ptr> audiobackends; // Using a pointer to avoid out of order init u32 GetAudioBackendCount() { return audiobackends != nullptr ? audiobackends->size() : 0; } audiobackend_t* GetAudioBackend(int num) { return audiobackends->at(num); } static void SortAudioBackends() { if (audiobackends != nullptr) std::sort(audiobackends->begin(), audiobackends->end(), [](audiobackend_t *b1, audiobackend_t *b2) { return b1->slug < b2->slug; }); } bool RegisterAudioBackend(audiobackend_t *backend) { verify(backend != nullptr); verify(!backend->slug.empty() && backend->slug != "auto"); if (audiobackends == nullptr) audiobackends = std::unique_ptr>(new std::vector()); audiobackends->push_back(backend); SortAudioBackends(); return true; } audiobackend_t* GetAudioBackend(const std::string& slug) { if (audiobackends != nullptr && !audiobackends->empty()) { if (slug == "auto") { // Don't select the null driver audiobackend_t *autoselection = nullptr; for (auto backend : *audiobackends) if (backend->slug != "null") { autoselection = backend; break; } if (autoselection == nullptr) autoselection = audiobackends->front(); INFO_LOG(AUDIO, "Auto-selected audio backend \"%s\" (%s).", autoselection->slug.c_str(), autoselection->name.c_str()); return autoselection; } else { for (auto backend : *audiobackends) { if (backend->slug == slug) return backend; } WARN_LOG(AUDIO, "WARNING: Audio backend \"%s\" not found!", slug.c_str()); } } else { WARN_LOG(AUDIO, "WARNING: No audio backends available!"); } return nullptr; } static u32 PushAudio(void* frame, u32 amt, bool wait) { if (audiobackend_current != nullptr) return audiobackend_current->push(frame, amt, wait); return 0; } void WriteSample(s16 r, s16 l) { const u32 ptr=(WritePtr+1)%SAMPLE_COUNT; RingBuffer[ptr].r=r; RingBuffer[ptr].l=l; WritePtr=ptr; if (WritePtr == SAMPLE_COUNT - 1) PushAudio(RingBuffer,SAMPLE_COUNT, settings.aica.LimitFPS); } void InitAudio() { if (cfgLoadInt("audio", "disable", 0)) { INFO_LOG(AUDIO, "WARNING: Audio disabled in config!"); return; } cfgSaveInt("audio", "disable", 0); verify(audiobackend_current == nullptr); SortAudioBackends(); std::string audiobackend_slug = settings.audio.backend; audiobackend_current = GetAudioBackend(audiobackend_slug); if (audiobackend_current == nullptr) { INFO_LOG(AUDIO, "WARNING: Running without audio!"); return; } INFO_LOG(AUDIO, "Initializing audio backend \"%s\" (%s)...", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str()); audiobackend_current->init(); } void TermAudio() { if (audiobackend_current != nullptr) { audiobackend_current->term(); INFO_LOG(AUDIO, "Terminating audio backend \"%s\" (%s)...", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str()); audiobackend_current = nullptr; } }