Support float32 output in SDL2 audio backend (with int16 fallback)
This commit is contained in:
parent
64ffe27c2a
commit
e23455356d
1 changed files with 34 additions and 15 deletions
|
|
@ -8,10 +8,7 @@
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <atomic>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
|
@ -39,6 +36,7 @@ namespace psemek::sdl2
|
||||||
|
|
||||||
audio::channel_ptr output_;
|
audio::channel_ptr output_;
|
||||||
|
|
||||||
|
template <typename SampleType>
|
||||||
static void callback(void * userdata, std::uint8_t * stream, int len);
|
static void callback(void * userdata, std::uint8_t * stream, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -48,14 +46,23 @@ namespace psemek::sdl2
|
||||||
SDL_AudioSpec desired, obtained;
|
SDL_AudioSpec desired, obtained;
|
||||||
desired.freq = audio::frequency;
|
desired.freq = audio::frequency;
|
||||||
desired.channels = 2;
|
desired.channels = 2;
|
||||||
desired.format = AUDIO_S16SYS;
|
desired.format = AUDIO_F32SYS;
|
||||||
desired.samples = 256;
|
desired.samples = 256;
|
||||||
desired.callback = &callback;
|
desired.callback = &callback<float>;
|
||||||
desired.userdata = this;
|
desired.userdata = this;
|
||||||
if (device_ = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); device_ == 0)
|
if (device_ = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); device_ == 0)
|
||||||
|
{
|
||||||
|
log::error() << "SDL_OpenAudioDevice failed: " << SDL_GetError();
|
||||||
|
log::error() << "Fallback to int16 audio output";
|
||||||
|
desired.format = AUDIO_S16SYS;
|
||||||
|
desired.callback = &callback<std::int16_t>;
|
||||||
|
if (device_ = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); device_ == 0)
|
||||||
|
{
|
||||||
fail("SDL_OpenAudioDevice failed:");
|
fail("SDL_OpenAudioDevice failed:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log::info() << "Initialized audio: " << static_cast<int>(obtained.channels) << " channels, " << obtained.freq << " Hz, " << obtained.samples << " samples";
|
log::info() << "Initialized audio: " << static_cast<int>(obtained.channels) << " channels, " << obtained.freq << " Hz, " << obtained.samples << " samples " << (desired.format == AUDIO_F32SYS ? "f32" : "i16");
|
||||||
|
|
||||||
buffer_.resize(obtained.samples * obtained.channels);
|
buffer_.resize(obtained.samples * obtained.channels);
|
||||||
output_ = std::make_shared<audio::channel>();
|
output_ = std::make_shared<audio::channel>();
|
||||||
|
|
@ -67,6 +74,7 @@ namespace psemek::sdl2
|
||||||
SDL_CloseAudioDevice(device_);
|
SDL_CloseAudioDevice(device_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename SampleType>
|
||||||
void audio_engine_impl::callback(void * userdata, std::uint8_t * dst_u8, int len)
|
void audio_engine_impl::callback(void * userdata, std::uint8_t * dst_u8, int len)
|
||||||
{
|
{
|
||||||
static std::string const profiler_str = "audio";
|
static std::string const profiler_str = "audio";
|
||||||
|
|
@ -74,7 +82,7 @@ namespace psemek::sdl2
|
||||||
|
|
||||||
auto self = static_cast<audio_engine_impl *>(userdata);
|
auto self = static_cast<audio_engine_impl *>(userdata);
|
||||||
auto stream = self->output()->stream();
|
auto stream = self->output()->stream();
|
||||||
std::int16_t * dst = reinterpret_cast<std::int16_t *>(dst_u8);
|
SampleType * dst = reinterpret_cast<SampleType *>(dst_u8);
|
||||||
|
|
||||||
if (!self->thread_registered_)
|
if (!self->thread_registered_)
|
||||||
{
|
{
|
||||||
|
|
@ -82,7 +90,10 @@ namespace psemek::sdl2
|
||||||
self->thread_registered_ = true;
|
self->thread_registered_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t const size = len / 2;
|
std::size_t const size = len / sizeof(SampleType);
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<SampleType, std::int16_t>)
|
||||||
|
{
|
||||||
std::size_t read = 0;
|
std::size_t read = 0;
|
||||||
if (stream)
|
if (stream)
|
||||||
read = stream->read({self->buffer_.data(), size});
|
read = stream->read({self->buffer_.data(), size});
|
||||||
|
|
@ -90,6 +101,14 @@ namespace psemek::sdl2
|
||||||
|
|
||||||
for (auto s : self->buffer_)
|
for (auto s : self->buffer_)
|
||||||
*dst++ = static_cast<std::int16_t>(std::max(std::min((65535.f * s - 1.f) / 2.f, 32767.f), -32768.f));
|
*dst++ = static_cast<std::int16_t>(std::max(std::min((65535.f * s - 1.f) / 2.f, 32767.f), -32768.f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::size_t read = 0;
|
||||||
|
if (stream)
|
||||||
|
read = stream->read({dst, size});
|
||||||
|
std::fill(dst + read, dst + size, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
if (auto duration = prof.duration(); duration > (size * audio::inv_frequency / 2))
|
if (auto duration = prof.duration(); duration > (size * audio::inv_frequency / 2))
|
||||||
log::warning() << "Audio can't keep up, callback took " << std::setprecision(5) << (1000.0 * duration) << " ms";
|
log::warning() << "Audio can't keep up, callback took " << std::setprecision(5) << (1000.0 * duration) << " ms";
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue