Mercurial > foo_out_sdl
changeset 0:e9bb126753e7
*: initial commit
totally untested besides the wrapper; need to get msvc running
| author | Paper <paper@tflc.us> |
|---|---|
| date | Sat, 03 Jan 2026 23:52:56 -0500 |
| parents | |
| children | 20d02a178406 |
| files | foo_out_sdl.cc foo_out_sdl_funcs.h foo_out_sdl_wrapper.c |
| diffstat | 3 files changed, 193 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foo_out_sdl.cc Sat Jan 03 23:52:56 2026 -0500 @@ -0,0 +1,165 @@ +/* SDL output for foobar2000. + * Somewhat scuffed since SDL does not provide latency */ + +#include <SDL3/SDL.h> + +#if audio_sample_size == 32 +# define OUTSDL_USE_NATIVE_F32 1 +# define OUTSDL_FORMAT SDL_AUDIO_F32 +#else +# define OUTSDL_FORMAT SDL_AUDIO_S32 +#endif + +class OutputSDL : public output { +public: + OutputSDL(); + ~OutputSDL(); + + virtual double get_latency() override; + virtual void process_samples(const audio_chunk &p_chunk) override; + virtual void update(bool &p_ready) override; + virtual void pause(bool p_state) override; + virtual void flush() override; + virtual void force_play() override; + virtual void volume_set(double p_val) override; + +private: + void ReinitStream(unsigned int channels, unsigned int freq); + + SDL_AudioStream *stream_; +#ifndef OUTSDL_USE_NATIVE_F32 + std::vector<t_int32> buffer_; +#endif + SDL_AudioSpec spec_; + HANDLE sdl_; + +#define FUNC(type, x, params, callparams) decltype(&SDL_##x) sdl3_##x; +#include "foo_out_sdl_funcs.h" +}; + +OutputSDL::OutputSDL() + : sdl_(nullptr) + , stream_(nullptr) +#ifndef OUTSDL_USE_NATIVE_F32 + /* sane default size */ + , buffer_(8096) +#endif +{ + sdl_ = LoadLibraryA("foo_out_sdl_wrapper.dll"); + if (!sdl3_) + return; + +#define FUNC(type, x, params, callparams) \ + sdl3_##x = (decltype(&SDL_##x))GetProcAddress(sdl_, "SDL_" #x); \ + if (!sdl3_##x) \ + return; +#include "foo_out_sdl_funcs.h" + + // increment subsystem counter + // hope this succeeds!!! + sdl3_InitSubSystem(SDL_INIT_AUDIO); + + /* make a guess */ + spec_.format = OUTSDL_FORMAT; + spec_.channels = 2; /* Stereo is most likely. Who cares about surround? :) */ + spec_.freq = 44100; /* guess CD quality */ + + // TODO supply output devices + stream_ = sdl3_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec_, nullptr, nullptr); +} + +OutputSDL::~OutputSDL() +{ + if (sdl_ && stream_ && sdl3_DestroyAudioStream) + sdl3_DestroyAudioStream(stream_); + if (sdl_ && sdl3_QuitSubSystem) + sdl3_QuitSubSystem(SDL_INIT_AUDIO); + if (sdl_) + FreeLibrary(sdl_); +} + +void OutputSDL::ReinitStream(unsigned int channels, unsigned int freq) +{ + // Fast path; no change + // I'm assuming that the channel input config is the same for fb2k + // and for SDL. This may not be the case. Whatever.. + if (spec_.channels == channels && spec_.freq == freq) + return; + + spec_.channels = channels; + spec_.freq = freq; + + // tell SDL about our change + sdl3_SetAudioStreamFormat(stream_, &spec_, nullptr); +} + +virtual double OutputSDL::get_latency() +{ + // TODO assume that one buffer's worth is queued + return 0.016; // i guess +} + +virtual void OutputSDL::process_samples(const audio_chunk &p_chunk) +{ + // Reinitialize stream with possibly new values for channels and frequency + ReinitStream(p_chunk.get_channels(), p_chunk.get_srate()); + + /* NOTE this is only actually tested with stereo */ +#ifdef OUTSDL_USE_NATIVE_F32 + /* audio_sample is 32-bit floating point; SDL can use this directly */ + sdl3_PutAudioStreamData(stream_, p_chunk.get_data(), p_chunk.get_data_size()); +#else + /* Expand the buffer if necessary */ + t_size sz = p_chunk.get_data_size(); + + if (sz > buffer_.size()) + buffer_.resize(sz); + + /* Convert to int32 */ + audio_math::convert_to_int32(p_chunk.get_data(), sz, buffer_.data(), buffer_.size()); + + /* Add int32 audio to stream */ + sdl3_PutAudioStreamData(stream_, buffer_.data(), buffer_.size()); +#endif +} + +virtual void OutputSDL::update(bool &p_ready) +{ + /* seems legit */ + p_ready = (sdl3_GetAudioStreamQueued(stream_) == 0); +} + +virtual void OutputSDL::pause(bool p_state) +{ + if (p_state) { + sdl3_PauseAudioStreamDevice(stream_); + } else { + sdl3_ResumeAudioStreamDevice(stream_); + } +} + +// . these are easy +virtual void OutputSDL::flush() +{ + sdl3_ClearAudioStream(stream_); +} + +virtual void OutputSDL::force_play() +{ + sdl3_FlushAudioStream(stream_); +} + +virtual void OutputSDL::volume_set(double p_val) +{ + sdl3_SetAudioStreamGain(stream_, p_val); +} + +static output_factory_t<OutputSDL> g_output_sdl_factory; + +//////////////////////////////////////////////////////////////////////////////// + +const char *about = "Copyright (c) paper <paper@tflc.us>, 2026\n"; + +// very beta ;) +DECLARE_COMPONENT_VERSION("SDL output", "0.1", about); +VALIDATE_COMPONENT_FILENAME("foo_out_sdl.dll");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foo_out_sdl_funcs.h Sat Jan 03 23:52:56 2026 -0500 @@ -0,0 +1,12 @@ +FUNC(SDL_AudioStream *, OpenAudioDeviceStream, (SDL_AudioDeviceID devid, const SDL_AudioSpec *spec, SDL_AudioStreamCallback callback, void *userdata), (devid, spec, callback, userdata)) +FUNC(void, DestroyAudioStream, (SDL_AudioStream *stream), (stream)) +FUNC(bool, SetAudioStreamFormat, (SDL_AudioStream *stream, const SDL_AudioSpec *src_spec, const SDL_AudioSpec *dst_spec), (stream, src_spec, dst_spec)) +FUNC(bool, PutAudioStreamData, (SDL_AudioStream *stream, const void *buf, int len), (stream, buf, len)) +FUNC(bool, PauseAudioStreamDevice, (SDL_AudioStream *stream), (stream)) +FUNC(bool, ResumeAudioStreamDevice, (SDL_AudioStream *stream), (stream)) +FUNC(bool, ClearAudioStream, (SDL_AudioStream *stream), (stream)) +FUNC(bool, FlushAudioStream, (SDL_AudioStream *stream), (stream)) +FUNC(bool, SetAudioStreamGain, (SDL_AudioStream *stream, float gain), (stream, gain)) +FUNC(bool, InitSubSystem, (SDL_InitFlags flags), (flags)) +FUNC(void, QuitSubSystem, (SDL_InitFlags flags), (flags)) +#undef FUNC \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foo_out_sdl_wrapper.c Sat Jan 03 23:52:56 2026 -0500 @@ -0,0 +1,16 @@ +#include <stdint.h> + +typedef struct SDL_AudioStream SDL_AudioStream; +typedef struct SDL_AudioSpec SDL_AudioSpec; +typedef uint32_t SDL_AudioDeviceID; +typedef uint32_t SDL_InitFlags; +typedef void (__cdecl *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount); + +#define FUNC(type, x, params, callparams) \ + __attribute__((ms_abi)) __cdecl extern \ + type sdl3_##x params \ + { \ + type SDL_##x params; \ + return SDL_##x callparams; \ + } +#include "foo_out_sdl_funcs.h"
