2
#include <SDL/SDL_audio.h>
9
#define M_PI 3.14159265358979323846f
13
#include "emscripten/emscripten.h"
20
const int tone_duration = 1000;
34
Beeper(int frequency, int numChannels, int sdlAudioFormat);
36
void beep(double toneFrequency, int durationMSecs);
38
void generateSamples(T *stream, int length);
41
std::queue<BeepObject> beeps;
45
void audio_callback(void*, Uint8*, int);
47
Beeper::Beeper(int frequency_, int numChannels_, int sdlAudioFormat_) {
51
SDL_AudioSpec desiredSpec;
53
desiredSpec.freq = frequency_;
54
desiredSpec.format = sdlAudioFormat_;
55
desiredSpec.channels = numChannels_;
56
desiredSpec.samples = 1024; // This is samples per channel.
57
desiredSpec.callback = audio_callback;
58
desiredSpec.userdata = this;
60
SDL_AudioSpec obtainedSpec;
62
// you might want to look for errors here
63
SDL_OpenAudio(&desiredSpec, &obtainedSpec);
65
// In this test, we require *exactly* the identical SDL result that we provide, since we test
66
// all various configurations individually.
67
if (obtainedSpec.freq != desiredSpec.freq || obtainedSpec.format != desiredSpec.format
68
|| obtainedSpec.channels != desiredSpec.channels || obtainedSpec.samples != desiredSpec.samples) {
70
throw std::runtime_error("Failed to initialize desired SDL_OpenAudio!");
73
frequency = obtainedSpec.freq;
74
numChannels = obtainedSpec.channels;
75
sdlAudioFormat = obtainedSpec.format;
77
// Immediately start producing audio.
86
void Beeper::generateSamples(T *stream, int length) {
87
const int AMPLITUDE = (sizeof(T) == 2) ? 28000 : 120;
88
const int offset = (sdlAudioFormat == AUDIO_U8) ? 120 : 0;
91
length /= numChannels;
94
memset(stream + numChannels*i, 0, sizeof(T)*numChannels*(length-i));
97
BeepObject& bo = beeps.front();
99
// In Stereo tests, mute one of the channels to be able to distinguish that Stereo output works.
100
if (bo.samplesLeft > tone_duration * frequency / 2 / 1000) {
106
int samplesToDo = std::min(i + bo.samplesLeft, length);
107
bo.samplesLeft -= samplesToDo - i;
109
while (i < samplesToDo) {
110
for(int j = 0; j < numChannels; ++j) {
111
stream[numChannels*i+j] = (T)(offset + (int)(AMPLITUDE * std::sin(phase * 2 * M_PI / frequency)));
112
if (numChannels > 1 && j == mutedChannel) {
113
stream[numChannels*i+j] = 0;
116
phase += bo.toneFrequency;
120
if (bo.samplesLeft == 0) {
126
void Beeper::beep(double toneFrequency, int durationMSecs) {
128
bo.toneFrequency = toneFrequency;
129
bo.samplesLeft = durationMSecs * frequency / 1000;
138
// Test all kinds of various possible formats. Not all are supported, but running this
139
// test will report you which work.
140
const int freqs[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000 };
141
const int channels[] = { 1, 2 };
142
const int sdlAudioFormats[] = { AUDIO_U8, AUDIO_S16LSB /*, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16MSB */ };
144
const char *SdlAudioFormatToString(int sdlAudioType) {
145
switch(sdlAudioType) {
146
case AUDIO_U8: return "AUDIO_U8";
147
case AUDIO_S8: return "AUDIO_S8";
148
case AUDIO_U16LSB: return "AUDIO_U16LSB";
149
case AUDIO_U16MSB: return "AUDIO_U16MSB";
150
case AUDIO_S16LSB: return "AUDIO_S16LSB";
151
case AUDIO_S16MSB: return "AUDIO_S16MSB";
152
default: return "(unknown)";
156
#define NUM_ELEMS(x) (sizeof(x)/sizeof((x)[0]))
158
// Indices to the currently running test.
163
void nextTest(void *unused = 0) {
165
if (f >= NUM_ELEMS(freqs)) {
168
if (c >= NUM_ELEMS(channels)) {
171
if (s >= NUM_ELEMS(sdlAudioFormats)) {
172
printf("All tests done. Quit.\n");
174
emscripten_cancel_main_loop();
187
beep = new Beeper(freqs[f], channels[c], sdlAudioFormats[s]);
189
printf("FAILED to play beep for %d msecs at %d Hz tone with audio format %s, %d channels, and %d samples/sec.\n",
190
tone_duration, (int)Hz, SdlAudioFormatToString(sdlAudioFormats[s]), channels[c], freqs[f]);
195
printf("Playing back a beep for %d msecs at %d Hz tone with audio format %s, %d channels, and %d samples/sec.\n",
196
tone_duration, (int)Hz, SdlAudioFormatToString(sdlAudioFormats[s]), channels[c], freqs[f]);
197
beep->beep(Hz, tone_duration);
202
int size = beep->beeps.size();
204
if (size == 0 && beep) {
208
emscripten_async_call(nextTest, 0, 1500);
216
void audio_callback(void *_beeper, Uint8 *_stream, int _length) {
217
Beeper* beeper = (Beeper*) _beeper;
219
if (beeper->sdlAudioFormat == AUDIO_U8) {
220
Uint8 *stream = (Uint8*) _stream;
221
beeper->generateSamples(stream, _length);
222
} else if (beeper->sdlAudioFormat == AUDIO_S16LSB) {
223
Sint16 *stream = (Sint16*) _stream;
224
int length = _length / 2;
225
beeper->generateSamples(stream, length);
227
assert(false && "Audio sample generation not implemented for current format!\n");
231
int main(int argc, char** argv) {
232
SDL_Init(SDL_INIT_AUDIO);
237
emscripten_set_main_loop(update, 60, 0);