annotate foo_out_sdl.cc @ 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
1 /* SDL output for foobar2000.
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
2 * Somewhat scuffed since SDL does not provide latency */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
3
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
4 #include <SDL3/SDL.h>
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
5
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
6 #if audio_sample_size == 32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
7 # define OUTSDL_USE_NATIVE_F32 1
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
8 # define OUTSDL_FORMAT SDL_AUDIO_F32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
9 #else
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
10 # define OUTSDL_FORMAT SDL_AUDIO_S32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
11 #endif
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
12
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
13 class OutputSDL : public output {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
14 public:
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
15 OutputSDL();
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
16 ~OutputSDL();
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
17
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
18 virtual double get_latency() override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
19 virtual void process_samples(const audio_chunk &p_chunk) override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
20 virtual void update(bool &p_ready) override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
21 virtual void pause(bool p_state) override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
22 virtual void flush() override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
23 virtual void force_play() override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
24 virtual void volume_set(double p_val) override;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
25
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
26 private:
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
27 void ReinitStream(unsigned int channels, unsigned int freq);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
28
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
29 SDL_AudioStream *stream_;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
30 #ifndef OUTSDL_USE_NATIVE_F32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
31 std::vector<t_int32> buffer_;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
32 #endif
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
33 SDL_AudioSpec spec_;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
34 HANDLE sdl_;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
35
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
36 #define FUNC(type, x, params, callparams) decltype(&SDL_##x) sdl3_##x;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
37 #include "foo_out_sdl_funcs.h"
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
38 };
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
39
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
40 OutputSDL::OutputSDL()
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
41 : sdl_(nullptr)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
42 , stream_(nullptr)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
43 #ifndef OUTSDL_USE_NATIVE_F32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
44 /* sane default size */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
45 , buffer_(8096)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
46 #endif
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
47 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
48 sdl_ = LoadLibraryA("foo_out_sdl_wrapper.dll");
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
49 if (!sdl3_)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
50 return;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
51
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
52 #define FUNC(type, x, params, callparams) \
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
53 sdl3_##x = (decltype(&SDL_##x))GetProcAddress(sdl_, "SDL_" #x); \
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
54 if (!sdl3_##x) \
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
55 return;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
56 #include "foo_out_sdl_funcs.h"
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
57
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
58 // increment subsystem counter
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
59 // hope this succeeds!!!
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
60 sdl3_InitSubSystem(SDL_INIT_AUDIO);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
61
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
62 /* make a guess */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
63 spec_.format = OUTSDL_FORMAT;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
64 spec_.channels = 2; /* Stereo is most likely. Who cares about surround? :) */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
65 spec_.freq = 44100; /* guess CD quality */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
66
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
67 // TODO supply output devices
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
68 stream_ = sdl3_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec_, nullptr, nullptr);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
69 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
70
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
71 OutputSDL::~OutputSDL()
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
72 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
73 if (sdl_ && stream_ && sdl3_DestroyAudioStream)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
74 sdl3_DestroyAudioStream(stream_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
75 if (sdl_ && sdl3_QuitSubSystem)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
76 sdl3_QuitSubSystem(SDL_INIT_AUDIO);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
77 if (sdl_)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
78 FreeLibrary(sdl_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
79 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
80
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
81 void OutputSDL::ReinitStream(unsigned int channels, unsigned int freq)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
82 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
83 // Fast path; no change
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
84 // I'm assuming that the channel input config is the same for fb2k
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
85 // and for SDL. This may not be the case. Whatever..
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
86 if (spec_.channels == channels && spec_.freq == freq)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
87 return;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
88
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
89 spec_.channels = channels;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
90 spec_.freq = freq;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
91
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
92 // tell SDL about our change
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
93 sdl3_SetAudioStreamFormat(stream_, &spec_, nullptr);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
94 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
95
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
96 virtual double OutputSDL::get_latency()
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
97 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
98 // TODO assume that one buffer's worth is queued
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
99 return 0.016; // i guess
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
100 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
101
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
102 virtual void OutputSDL::process_samples(const audio_chunk &p_chunk)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
103 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
104 // Reinitialize stream with possibly new values for channels and frequency
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
105 ReinitStream(p_chunk.get_channels(), p_chunk.get_srate());
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
106
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
107 /* NOTE this is only actually tested with stereo */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
108 #ifdef OUTSDL_USE_NATIVE_F32
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
109 /* audio_sample is 32-bit floating point; SDL can use this directly */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
110 sdl3_PutAudioStreamData(stream_, p_chunk.get_data(), p_chunk.get_data_size());
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
111 #else
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
112 /* Expand the buffer if necessary */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
113 t_size sz = p_chunk.get_data_size();
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
114
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
115 if (sz > buffer_.size())
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
116 buffer_.resize(sz);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
117
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
118 /* Convert to int32 */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
119 audio_math::convert_to_int32(p_chunk.get_data(), sz, buffer_.data(), buffer_.size());
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
120
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
121 /* Add int32 audio to stream */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
122 sdl3_PutAudioStreamData(stream_, buffer_.data(), buffer_.size());
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
123 #endif
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
124 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
125
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
126 virtual void OutputSDL::update(bool &p_ready)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
127 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
128 /* seems legit */
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
129 p_ready = (sdl3_GetAudioStreamQueued(stream_) == 0);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
130 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
131
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
132 virtual void OutputSDL::pause(bool p_state)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
133 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
134 if (p_state) {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
135 sdl3_PauseAudioStreamDevice(stream_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
136 } else {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
137 sdl3_ResumeAudioStreamDevice(stream_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
138 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
139 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
140
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
141 // . these are easy
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
142 virtual void OutputSDL::flush()
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
143 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
144 sdl3_ClearAudioStream(stream_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
145 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
146
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
147 virtual void OutputSDL::force_play()
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
148 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
149 sdl3_FlushAudioStream(stream_);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
150 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
151
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
152 virtual void OutputSDL::volume_set(double p_val)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
153 {
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
154 sdl3_SetAudioStreamGain(stream_, p_val);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
155 }
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
156
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
157 static output_factory_t<OutputSDL> g_output_sdl_factory;
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
158
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
159 ////////////////////////////////////////////////////////////////////////////////
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
160
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
161 const char *about = "Copyright (c) paper <paper@tflc.us>, 2026\n";
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
162
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
163 // very beta ;)
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
164 DECLARE_COMPONENT_VERSION("SDL output", "0.1", about);
e9bb126753e7 *: initial commit
Paper <paper@tflc.us>
parents:
diff changeset
165 VALIDATE_COMPONENT_FILENAME("foo_out_sdl.dll");