diff options
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testsurround.c')
-rw-r--r-- | src/contrib/SDL-3.2.20/test/testsurround.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testsurround.c b/src/contrib/SDL-3.2.20/test/testsurround.c new file mode 100644 index 0000000..36b33f4 --- /dev/null +++ b/src/contrib/SDL-3.2.20/test/testsurround.c | |||
@@ -0,0 +1,282 @@ | |||
1 | /* | ||
2 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied | ||
5 | warranty. In no event will the authors be held liable for any damages | ||
6 | arising from the use of this software. | ||
7 | |||
8 | Permission is granted to anyone to use this software for any purpose, | ||
9 | including commercial applications, and to alter it and redistribute it | ||
10 | freely. | ||
11 | */ | ||
12 | |||
13 | /* Program to test surround sound audio channels */ | ||
14 | #include <SDL3/SDL.h> | ||
15 | #include <SDL3/SDL_main.h> | ||
16 | #include <SDL3/SDL_test.h> | ||
17 | |||
18 | static int total_channels; | ||
19 | static int active_channel; | ||
20 | |||
21 | #define SAMPLE_RATE_HZ 48000 | ||
22 | #define QUICK_TEST_TIME_MSEC 100 | ||
23 | #define CHANNEL_TEST_TIME_SEC 5 | ||
24 | #define MAX_AMPLITUDE SDL_MAX_SINT16 | ||
25 | |||
26 | #define SINE_FREQ_HZ 500 | ||
27 | #define LFE_SINE_FREQ_HZ 50 | ||
28 | |||
29 | /* The channel layout is defined in SDL_audio.h */ | ||
30 | static const char *get_channel_name(int channel_index, int channel_count) | ||
31 | { | ||
32 | switch (channel_count) { | ||
33 | case 1: | ||
34 | return "Mono"; | ||
35 | case 2: | ||
36 | switch (channel_index) { | ||
37 | case 0: | ||
38 | return "Front Left"; | ||
39 | case 1: | ||
40 | return "Front Right"; | ||
41 | } | ||
42 | break; | ||
43 | case 3: | ||
44 | switch (channel_index) { | ||
45 | case 0: | ||
46 | return "Front Left"; | ||
47 | case 1: | ||
48 | return "Front Right"; | ||
49 | case 2: | ||
50 | return "Low Frequency Effects"; | ||
51 | } | ||
52 | break; | ||
53 | case 4: | ||
54 | switch (channel_index) { | ||
55 | case 0: | ||
56 | return "Front Left"; | ||
57 | case 1: | ||
58 | return "Front Right"; | ||
59 | case 2: | ||
60 | return "Back Left"; | ||
61 | case 3: | ||
62 | return "Back Right"; | ||
63 | } | ||
64 | break; | ||
65 | case 5: | ||
66 | switch (channel_index) { | ||
67 | case 0: | ||
68 | return "Front Left"; | ||
69 | case 1: | ||
70 | return "Front Right"; | ||
71 | case 2: | ||
72 | return "Low Frequency Effects"; | ||
73 | case 3: | ||
74 | return "Back Left"; | ||
75 | case 4: | ||
76 | return "Back Right"; | ||
77 | } | ||
78 | break; | ||
79 | case 6: | ||
80 | switch (channel_index) { | ||
81 | case 0: | ||
82 | return "Front Left"; | ||
83 | case 1: | ||
84 | return "Front Right"; | ||
85 | case 2: | ||
86 | return "Front Center"; | ||
87 | case 3: | ||
88 | return "Low Frequency Effects"; | ||
89 | case 4: | ||
90 | return "Back Left"; | ||
91 | case 5: | ||
92 | return "Back Right"; | ||
93 | } | ||
94 | break; | ||
95 | case 7: | ||
96 | switch (channel_index) { | ||
97 | case 0: | ||
98 | return "Front Left"; | ||
99 | case 1: | ||
100 | return "Front Right"; | ||
101 | case 2: | ||
102 | return "Front Center"; | ||
103 | case 3: | ||
104 | return "Low Frequency Effects"; | ||
105 | case 4: | ||
106 | return "Back Center"; | ||
107 | case 5: | ||
108 | return "Side Left"; | ||
109 | case 6: | ||
110 | return "Side Right"; | ||
111 | } | ||
112 | break; | ||
113 | case 8: | ||
114 | switch (channel_index) { | ||
115 | case 0: | ||
116 | return "Front Left"; | ||
117 | case 1: | ||
118 | return "Front Right"; | ||
119 | case 2: | ||
120 | return "Front Center"; | ||
121 | case 3: | ||
122 | return "Low Frequency Effects"; | ||
123 | case 4: | ||
124 | return "Back Left"; | ||
125 | case 5: | ||
126 | return "Back Right"; | ||
127 | case 6: | ||
128 | return "Side Left"; | ||
129 | case 7: | ||
130 | return "Side Right"; | ||
131 | } | ||
132 | break; | ||
133 | default: | ||
134 | break; | ||
135 | } | ||
136 | SDLTest_AssertCheck(false, "Invalid channel_index for channel_count: channel_count=%d channel_index=%d", channel_count, channel_index); | ||
137 | SDL_assert(0); | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | static bool is_lfe_channel(int channel_index, int channel_count) | ||
142 | { | ||
143 | return (channel_count == 3 && channel_index == 2) || (channel_count >= 6 && channel_index == 3); | ||
144 | } | ||
145 | |||
146 | static void SDLCALL fill_buffer(void *userdata, SDL_AudioStream *stream, int len, int totallen) | ||
147 | { | ||
148 | const int samples = len / sizeof(Sint16); | ||
149 | Sint16 *buffer = NULL; | ||
150 | static int total_samples = 0; | ||
151 | int i; | ||
152 | |||
153 | /* This can happen for a short time when switching devices */ | ||
154 | if (active_channel == total_channels) { | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | buffer = (Sint16 *) SDL_calloc(samples, sizeof(Sint16)); | ||
159 | if (!buffer) { | ||
160 | return; /* oh well. */ | ||
161 | } | ||
162 | |||
163 | /* Play a sine wave on the active channel only */ | ||
164 | for (i = active_channel; i < samples; i += total_channels) { | ||
165 | float time = (float)total_samples++ / SAMPLE_RATE_HZ; | ||
166 | int sine_freq = is_lfe_channel(active_channel, total_channels) ? LFE_SINE_FREQ_HZ : SINE_FREQ_HZ; | ||
167 | int amplitude; | ||
168 | |||
169 | /* Gradually ramp up and down to avoid audible pops when switching between channels */ | ||
170 | if (total_samples < SAMPLE_RATE_HZ) { | ||
171 | amplitude = total_samples * MAX_AMPLITUDE / SAMPLE_RATE_HZ; | ||
172 | } else if (total_samples > (CHANNEL_TEST_TIME_SEC - 1) * SAMPLE_RATE_HZ) { | ||
173 | amplitude = (CHANNEL_TEST_TIME_SEC * SAMPLE_RATE_HZ - total_samples) * MAX_AMPLITUDE / SAMPLE_RATE_HZ; | ||
174 | } else { | ||
175 | amplitude = MAX_AMPLITUDE; | ||
176 | } | ||
177 | |||
178 | buffer[i] = (Sint16)(SDL_sin(6.283185f * sine_freq * time) * amplitude); | ||
179 | |||
180 | /* Reset our state for next callback if this channel test is finished */ | ||
181 | if (total_samples == CHANNEL_TEST_TIME_SEC * SAMPLE_RATE_HZ) { | ||
182 | total_samples = 0; | ||
183 | active_channel++; | ||
184 | break; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | SDL_PutAudioStreamData(stream, buffer, samples * sizeof (Sint16)); | ||
189 | |||
190 | SDL_free(buffer); | ||
191 | } | ||
192 | |||
193 | int main(int argc, char *argv[]) | ||
194 | { | ||
195 | SDL_AudioDeviceID *devices; | ||
196 | SDLTest_CommonState *state; | ||
197 | int devcount = 0; | ||
198 | int i; | ||
199 | |||
200 | /* Initialize test framework */ | ||
201 | state = SDLTest_CommonCreateState(argv, 0); | ||
202 | if (!state) { | ||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | if (!SDLTest_CommonDefaultArgs(state, argc, argv)) { | ||
207 | SDLTest_CommonQuit(state); | ||
208 | return 1; | ||
209 | } | ||
210 | |||
211 | if (!SDL_Init(SDL_INIT_AUDIO)) { | ||
212 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | /* Show the list of available drivers */ | ||
217 | SDL_Log("Available audio drivers:"); | ||
218 | for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { | ||
219 | SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); | ||
220 | } | ||
221 | |||
222 | SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); | ||
223 | |||
224 | devices = SDL_GetAudioPlaybackDevices(&devcount); | ||
225 | if (!devices) { | ||
226 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioPlaybackDevices() failed: %s", SDL_GetError()); | ||
227 | } | ||
228 | |||
229 | SDL_Log("Available audio devices:"); | ||
230 | for (i = 0; i < devcount; i++) { | ||
231 | SDL_Log("%s", SDL_GetAudioDeviceName(devices[i])); | ||
232 | } | ||
233 | |||
234 | for (i = 0; i < devcount; i++) { | ||
235 | SDL_AudioStream *stream = NULL; | ||
236 | const char *devname = SDL_GetAudioDeviceName(devices[i]); | ||
237 | int j; | ||
238 | SDL_AudioSpec spec; | ||
239 | |||
240 | SDL_Log("Testing audio device: %s", devname); | ||
241 | |||
242 | if (!SDL_GetAudioDeviceFormat(devices[i], &spec, NULL)) { | ||
243 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioDeviceFormat() failed: %s", SDL_GetError()); | ||
244 | continue; | ||
245 | } | ||
246 | |||
247 | SDL_Log(" (%d channels)", spec.channels); | ||
248 | |||
249 | spec.freq = SAMPLE_RATE_HZ; | ||
250 | spec.format = SDL_AUDIO_S16; | ||
251 | |||
252 | /* These are used by the fill_buffer callback */ | ||
253 | total_channels = spec.channels; | ||
254 | active_channel = 0; | ||
255 | |||
256 | stream = SDL_OpenAudioDeviceStream(devices[i], &spec, fill_buffer, NULL); | ||
257 | if (!stream) { | ||
258 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_OpenAudioDeviceStream() failed: %s", SDL_GetError()); | ||
259 | continue; | ||
260 | } | ||
261 | SDL_ResumeAudioStreamDevice(stream); | ||
262 | |||
263 | for (j = 0; j < total_channels; j++) { | ||
264 | const int sine_freq = is_lfe_channel(j, total_channels) ? LFE_SINE_FREQ_HZ : SINE_FREQ_HZ; | ||
265 | |||
266 | SDL_Log("Playing %d Hz test tone on channel: %s", sine_freq, get_channel_name(j, total_channels)); | ||
267 | |||
268 | /* fill_buffer() will increment the active channel */ | ||
269 | if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_TESTS_QUICK") != NULL) { | ||
270 | SDL_Delay(QUICK_TEST_TIME_MSEC); | ||
271 | } else { | ||
272 | SDL_Delay(CHANNEL_TEST_TIME_SEC * 1000); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | SDL_DestroyAudioStream(stream); | ||
277 | } | ||
278 | SDL_free(devices); | ||
279 | |||
280 | SDL_Quit(); | ||
281 | return 0; | ||
282 | } | ||