rpcsx/rpcs3/Emu/Audio/AL/OpenALBackend.cpp
Oschowa a47bda026b Audio/AL: Request our default sampling rate (48kHz) from AL when creating the
context.
Otherwise AL might downsample and output in 44.1kHz unnecessarily, which
happens at least on my system. Also tested on an audio device that
doesn't support 48kHz to makes sure that still works.
2021-02-20 14:31:38 +03:00

212 lines
5 KiB
C++

#include "stdafx.h"
#include "OpenALBackend.h"
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif
LOG_CHANNEL(OpenAL);
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) OpenAL.error("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
OpenALBackend::OpenALBackend()
: AudioBackend()
{
ALCint attribs[] = {ALC_FREQUENCY, DEFAULT_AUDIO_SAMPLING_RATE, 0, 0};
ALCdevice* m_device = alcOpenDevice(nullptr);
checkForAlcError("alcOpenDevice");
ALCcontext* m_context = alcCreateContext(m_device, attribs);
checkForAlcError("alcCreateContext");
alcMakeContextCurrent(m_context);
checkForAlcError("alcMakeContextCurrent");
switch (m_channels)
{
case 2:
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
break;
case 6:
m_format = (m_sample_size == 2) ? AL_FORMAT_51CHN16 : AL_FORMAT_51CHN32;
break;
default:
m_format = (m_sample_size == 2) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
break;
}
}
OpenALBackend::~OpenALBackend()
{
if (alIsSource(m_source))
{
Close();
}
if (ALCcontext* m_context = alcGetCurrentContext())
{
ALCdevice* m_device = alcGetContextsDevice(m_context);
alcMakeContextCurrent(nullptr);
alcDestroyContext(m_context);
alcCloseDevice(m_device);
}
}
void OpenALBackend::Play()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("Play->alGetSourcei(AL_SOURCE_STATE)");
if (state != AL_PLAYING)
{
alSourcePlay(m_source);
checkForAlError("Play->alSourcePlay");
}
}
void OpenALBackend::Pause()
{
AUDIT(alIsSource(m_source));
alSourcePause(m_source);
checkForAlError("Pause->alSourcePause");
}
bool OpenALBackend::IsPlaying()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("IsPlaying->alGetSourcei(AL_SOURCE_STATE)");
return state == AL_PLAYING;
}
void OpenALBackend::Open(u32 num_buffers)
{
AUDIT(!alIsSource(m_source));
// Initialize Source
alGenSources(1, &m_source);
checkForAlError("Open->alGenSources");
alSourcei(m_source, AL_LOOPING, AL_FALSE);
checkForAlError("Open->alSourcei");
// Initialize Buffers
alGenBuffers(num_buffers, m_buffers);
checkForAlError("Open->alGenBuffers");
m_num_buffers = num_buffers;
m_num_unqueued = num_buffers;
}
void OpenALBackend::Close()
{
if (alIsSource(m_source))
{
// Stop & Kill Source
Pause();
alDeleteSources(1, &m_source);
// Free Buffers
alDeleteBuffers(m_num_buffers, m_buffers);
checkForAlError("alDeleteBuffers");
}
}
bool OpenALBackend::AddData(const void* src, u32 num_samples)
{
AUDIT(alIsSource(m_source));
// Unqueue processed buffers, if any
unqueue_processed();
// Fail if there are no free buffers remaining
if (m_num_unqueued == 0)
{
OpenAL.warning("No unqueued buffers remaining");
return false;
}
// Copy data to the next available buffer
alBufferData(m_buffers[m_next_buffer], m_format, src, num_samples * m_sample_size, m_sampling_rate);
checkForAlError("AddData->alBufferData");
// Enqueue buffer
alSourceQueueBuffers(m_source, 1, &m_buffers[m_next_buffer]);
checkForAlError("AddData->alSourceQueueBuffers");
m_num_unqueued--;
m_next_buffer = (m_next_buffer + 1) % m_num_buffers;
return true;
}
void OpenALBackend::Flush()
{
AUDIT(alIsSource(m_source));
// Stop source first
alSourceStop(m_source);
checkForAlError("Flush->alSourceStop");
// Unqueue processed buffers (should now be all of them)
unqueue_processed();
}
void OpenALBackend::unqueue_processed()
{
AUDIT(alIsSource(m_source));
// Get number of buffers
ALint num_processed;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_processed);
checkForAlError("Flush->alGetSourcei(AL_BUFFERS_PROCESSED)");
if (num_processed > 0)
{
// Unqueue all buffers
ALuint x[MAX_AUDIO_BUFFERS];
alSourceUnqueueBuffers(m_source, num_processed, x);
checkForAlError("Flush->alSourceUnqueueBuffers");
m_num_unqueued += num_processed;
}
}
u64 OpenALBackend::GetNumEnqueuedSamples()
{
AUDIT(alIsSource(m_source));
// Get number of buffers queued
ALint num_queued;
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &num_queued);
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_BUFFERS_QUEUED)");
AUDIT(static_cast<u32>(num_queued) <= m_num_buffers - m_num_unqueued);
// Get sample position
ALint sample_pos;
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &sample_pos);
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_SAMPLE_OFFSET)");
// Return
return (num_queued * AUDIO_BUFFER_SAMPLES) + (sample_pos % AUDIO_BUFFER_SAMPLES);
}
f32 OpenALBackend::SetFrequencyRatio(f32 new_ratio)
{
new_ratio = std::clamp(new_ratio, 0.5f, 2.0f);
alSourcef(m_source, AL_PITCH, new_ratio);
checkForAlError("SetFrequencyRatio->alSourcei(AL_PITCH)");
return new_ratio;
}