Atlas - testsurround.c

Home / ext / SDL / test Lines: 1 | Size: 8150 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 18static int total_channels; 19static 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 */ 30static 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 141static 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 146static 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 193int 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} 283
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.