2#include <ossia/detail/config.hpp>
4#if defined(OSSIA_ENABLE_SDL)
5#if __has_include(<SDL2/SDL_audio.h>)
6#include <SDL2/SDL_config.h>
7#if !defined(SDL_AUDIO_DISABLED)
8#include <ossia/audio/audio_engine.hpp>
9#include <ossia/detail/thread.hpp>
12#include <SDL2/SDL_audio.h>
14#define OSSIA_AUDIO_SDL 1
18class sdl_protocol final :
public audio_engine
20 static constexpr int inputs = 0;
21 static constexpr int outputs = 2;
24 sdl_protocol(
int rate,
int bs)
26 SDL_Init(SDL_INIT_AUDIO);
27 m_desired.freq = rate;
28 m_desired.format = AUDIO_F32SYS;
29 m_desired.channels = outputs;
30 m_desired.samples = bs;
31 m_desired.callback = SDLCallback;
32 m_desired.userdata =
this;
34 m_deviceId = SDL_OpenAudioDevice(
nullptr, 0, &m_desired, &m_obtained, 0);
38 using namespace std::literals;
39 throw std::runtime_error(
"SDL: Couldn't open audio: "s + SDL_GetError());
42 this->effective_sample_rate = m_obtained.freq;
43 this->effective_buffer_size = m_obtained.samples;
44 this->effective_inputs = 0;
45 this->effective_outputs = m_obtained.channels;
47 SDL_PauseAudioDevice(m_deviceId, 0);
51 ~sdl_protocol()
override { stop(); }
53 bool running()
const override
55 return m_activated && SDL_GetAudioDeviceStatus(m_deviceId) == SDL_AUDIO_PLAYING;
63 SDL_CloseAudioDevice(m_deviceId);
70 static void SDLCallback(
void* userData, Uint8* data,
int bytes)
73 static const thread_local auto _
75 ossia::set_thread_name(
"ossia audio 0");
76 ossia::set_thread_pinned(thread_type::Audio, 0);
80 auto& self = *
static_cast<sdl_protocol*
>(userData);
83 self.m_start = std::chrono::steady_clock::now();
85 auto audio_out =
reinterpret_cast<float*
>(data);
86 const int out_chan = self.m_obtained.channels;
87 const int frames = self.m_obtained.samples;
90 assert(frames * out_chan *
sizeof(
float) == bytes);
92 if(self.stop_processing)
95 memset(data, 0, bytes);
100 auto float_data = (
float*)alloca(
sizeof(
float) * frames * out_chan);
101 memset(float_data, 0,
sizeof(
sizeof(
float) * frames * out_chan));
103 auto float_output = (
float**)alloca(
sizeof(
float*) * out_chan);
105 for(
int c = 0; c < out_chan; c++)
107 float_output[c] = float_data + c * frames;
112 auto now = std::chrono::steady_clock::now();
114 = std::chrono::duration_cast<std::chrono::nanoseconds>(now - *self.m_start)
118 ossia::audio_tick_state ts{
nullptr, float_output, 0,
119 out_chan, (uint64_t)frames, nsecs};
122 for(
int j = 0; j < frames; j++)
123 for(
int c = 0; c < out_chan; c++)
124 *audio_out++ = float_output[c][j];
127 self.m_total_frames += frames;
131 SDL_AudioDeviceID m_deviceId{};
132 SDL_AudioSpec m_desired, m_obtained;
133 uint64_t m_total_frames{};
134 std::optional<std::chrono::steady_clock::time_point> m_start;