diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/sdl_audio_beep.cpp | 292 |
1 files changed, 204 insertions, 88 deletions
diff --git a/tests/sdl_audio_beep.cpp b/tests/sdl_audio_beep.cpp index 4bcc3b85..afe6a610 100644 --- a/tests/sdl_audio_beep.cpp +++ b/tests/sdl_audio_beep.cpp @@ -2,127 +2,243 @@ #include <SDL/SDL_audio.h> #include <queue> #include <cmath> +#include <stdio.h> +#include <assert.h> -const int AMPLITUDE = 28000; -const int FREQUENCY = 44100; +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif -struct BeepObject -{ - double freq; - int samplesLeft; +#ifdef EMSCRIPTEN +#include "emscripten/emscripten.h" +#endif + +#ifdef main +#undef main +#endif + +const int tone_duration = 2000; + +struct BeepObject { + double toneFrequency; + int samplesLeft; }; -class Beeper -{ +class Beeper { private: - double v; - std::queue<BeepObject> beeps; + double phase; + int frequency; + int numChannels; + int mutedChannel; public: - Beeper(); - ~Beeper(); - void beep(double freq, int duration); - void generateSamples(Sint16 *stream, int length); - void wait(); + Beeper(int frequency, int numChannels, int sdlAudioFormat); + ~Beeper(); + void beep(double toneFrequency, int durationMSecs); + template<typename T> + void generateSamples(T *stream, int length); + void wait(); + + std::queue<BeepObject> beeps; + int sdlAudioFormat; }; void audio_callback(void*, Uint8*, int); -Beeper::Beeper() -{ - SDL_AudioSpec desiredSpec; +Beeper::Beeper(int frequency_, int numChannels_, int sdlAudioFormat_) { + phase = 0.0; + mutedChannel = 1; - desiredSpec.freq = FREQUENCY; - desiredSpec.format = AUDIO_S16SYS; - desiredSpec.channels = 1; - desiredSpec.samples = 2048; - desiredSpec.callback = audio_callback; - desiredSpec.userdata = this; + SDL_AudioSpec desiredSpec; - SDL_AudioSpec obtainedSpec; + desiredSpec.freq = frequency_; + desiredSpec.format = sdlAudioFormat_; + desiredSpec.channels = numChannels_; + desiredSpec.samples = 1024; // This is samples per channel. + desiredSpec.callback = audio_callback; + desiredSpec.userdata = this; - // you might want to look for errors here - SDL_OpenAudio(&desiredSpec, &obtainedSpec); + SDL_AudioSpec obtainedSpec; - // start play audio - SDL_PauseAudio(0); -} + // you might want to look for errors here + SDL_OpenAudio(&desiredSpec, &obtainedSpec); -Beeper::~Beeper() -{ + // In this test, we require *exactly* the identical SDL result that we provide, since we test + // all various configurations individually. + if (obtainedSpec.freq != desiredSpec.freq || obtainedSpec.format != desiredSpec.format + || obtainedSpec.channels != desiredSpec.channels || obtainedSpec.samples != desiredSpec.samples) { SDL_CloseAudio(); + throw std::runtime_error("Failed to initialize desired SDL_OpenAudio!"); + } + + frequency = obtainedSpec.freq; + numChannels = obtainedSpec.channels; + sdlAudioFormat = obtainedSpec.format; + + // Immediately start producing audio. + SDL_PauseAudio(0); } -void Beeper::generateSamples(Sint16 *stream, int length) -{ - int i = 0; - while (i < length) { - - if (beeps.empty()) { - while (i < length) { - stream[i] = 0; - i++; - } - return; - } - BeepObject& bo = beeps.front(); +Beeper::~Beeper() { + SDL_CloseAudio(); +} + +template<typename T> +void Beeper::generateSamples(T *stream, int length) { + const int AMPLITUDE = (sizeof(T) == 2) ? 28000 : 120; + const int offset = (sdlAudioFormat == AUDIO_U8) ? 120 : 0; + + int i = 0; + length /= numChannels; + while (i < length) { + if (beeps.empty()) { + memset(stream + numChannels*i, 0, sizeof(T)*numChannels*(length-i)); + return; + } + BeepObject& bo = beeps.front(); - int samplesToDo = std::min(i + bo.samplesLeft, length); - bo.samplesLeft -= samplesToDo - i; + // In Stereo tests, mute one of the channels to be able to distinguish that Stereo output works. + if (bo.samplesLeft > tone_duration * frequency / 2 / 1000) { + mutedChannel = 1; + } else { + mutedChannel = 0; + } - while (i < samplesToDo) { - stream[i] = AMPLITUDE * std::sin(v * 2 * M_PI / FREQUENCY); - i++; - v += bo.freq; - } + int samplesToDo = std::min(i + bo.samplesLeft, length); + bo.samplesLeft -= samplesToDo - i; - if (bo.samplesLeft == 0) { - beeps.pop(); + while (i < samplesToDo) { + for(int j = 0; j < numChannels; ++j) { + stream[numChannels*i+j] = (T)(offset + (int)(AMPLITUDE * std::sin(phase * 2 * M_PI / frequency))); + if (numChannels > 1 && j == mutedChannel) { + stream[numChannels*i+j] = 0; } + } + phase += bo.toneFrequency; + i++; } + + if (bo.samplesLeft == 0) { + beeps.pop(); + } + } } -void Beeper::beep(double freq, int duration) -{ - BeepObject bo; - bo.freq = freq; - bo.samplesLeft = duration * FREQUENCY / 1000; +void Beeper::beep(double toneFrequency, int durationMSecs) { + BeepObject bo; + bo.toneFrequency = toneFrequency; + bo.samplesLeft = durationMSecs * frequency / 1000; + + SDL_LockAudio(); + beeps.push(bo); + SDL_UnlockAudio(); +} - SDL_LockAudio(); - beeps.push(bo); - SDL_UnlockAudio(); +Beeper *beep = 0; + +// Test all kinds of various possible formats. Not all are supported, but running this +// test will report you which work. +const int freqs[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000 }; +const int channels[] = { 1, 2 }; +const int sdlAudioFormats[] = { AUDIO_U8, AUDIO_S16LSB /*, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16MSB */ }; + +const char *SdlAudioFormatToString(int sdlAudioType) { + switch(sdlAudioType) { + case AUDIO_U8: return "AUDIO_U8"; + case AUDIO_S8: return "AUDIO_S8"; + case AUDIO_U16LSB: return "AUDIO_U16LSB"; + case AUDIO_U16MSB: return "AUDIO_U16MSB"; + case AUDIO_S16LSB: return "AUDIO_S16LSB"; + case AUDIO_S16MSB: return "AUDIO_S16MSB"; + default: return "(unknown)"; + } } -void Beeper::wait() -{ - int size; - do { - SDL_Delay(20); - SDL_LockAudio(); - size = beeps.size(); - SDL_UnlockAudio(); - } while (size > 0); +#define NUM_ELEMS(x) (sizeof(x)/sizeof((x)[0])) + +// Indices to the currently running test. +int f = -1; +int c = 0; +int s = 0; + +void nextTest(void *unused = 0) { + ++f; + if (f >= NUM_ELEMS(freqs)) { + f = 0; + ++c; + if (c >= NUM_ELEMS(channels)) { + c = 0; + ++s; + if (s >= NUM_ELEMS(sdlAudioFormats)) { + printf("All tests done. Quit.\n"); +#ifdef EMSCRIPTEN + emscripten_cancel_main_loop(); + int result = 1; + REPORT_RESULT(); +#endif + return; + } + } + } + + double Hz = 440; + try { + beep = new Beeper(freqs[f], channels[c], sdlAudioFormats[s]); + } catch(...) { + printf("FAILED to play beep for %d msecs at %d Hz tone with audio format %s, %d channels, and %d samples/sec.\n", + tone_duration, (int)Hz, SdlAudioFormatToString(sdlAudioFormats[s]), channels[c], freqs[f]); + nextTest(); + return; + } + + printf("Playing back a beep for %d msecs at %d Hz tone with audio format %s, %d channels, and %d samples/sec.\n", + tone_duration, (int)Hz, SdlAudioFormatToString(sdlAudioFormats[s]), channels[c], freqs[f]); + beep->beep(Hz, tone_duration); +} +void update() { + SDL_LockAudio(); + int size = beep->beeps.size(); + SDL_UnlockAudio(); + if (size == 0 && beep) { + delete beep; + beep = 0; +#ifdef EMSCRIPTEN + emscripten_async_call(nextTest, 0, 500); +#else + SDL_Delay(500); + nextTest(); +#endif + } } -void audio_callback(void *_beeper, Uint8 *_stream, int _length) -{ +void audio_callback(void *_beeper, Uint8 *_stream, int _length) { + Beeper* beeper = (Beeper*) _beeper; + + if (beeper->sdlAudioFormat == AUDIO_U8) { + Uint8 *stream = (Uint8*) _stream; + beeper->generateSamples(stream, _length); + } else if (beeper->sdlAudioFormat == AUDIO_S16LSB) { Sint16 *stream = (Sint16*) _stream; int length = _length / 2; - Beeper* beeper = (Beeper*) _beeper; - beeper->generateSamples(stream, length); + } else { + assert(false && "Audio sample generation not implemented for current format!\n"); + } } -int main(int argc, char* argv[]) -{ - SDL_Init(SDL_INIT_AUDIO); - - int duration = 1000; - double Hz = 440; - - Beeper b; - b.beep(Hz, duration); - b.wait(); - - return 0; -}
\ No newline at end of file +int main(int argc, char** argv) { + SDL_Init(SDL_INIT_AUDIO); + + nextTest(); + +#ifdef EMSCRIPTEN + emscripten_set_main_loop(update, 60, 0); +#else + while(beep) { + SDL_Delay(20); + update(); + } +#endif + + return 0; +} |