flycast/core/oslib/audiostream.cpp

133 lines
3.2 KiB
C++

#include "audiostream.h"
#include "cfg/cfg.h"
#include <algorithm>
#include <memory>
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<std::vector<audiobackend_t *>> 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<std::vector<audiobackend_t *>>(new std::vector<audiobackend_t *>());
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;
}
}