Sample: Playing a Simple Sine Wave (was: simple bell)

/*

  • Sample of SDL_Audio playing a pure sine wave.
  • Compile with your preferred SDL_main.*
  • Author: Pierre G. Richard
  • Written: 4/12/2004
    */

#include <memory.h>
#include <stdlib.h>
#include “SDL.h”

typedef struct {
SDL_sem * playEnded;
int isEnabled;
unsigned int timeCurr;
unsigned int timeMax;
char const * val;
} ToneCallbackData;

static short const sineVals[] = {
-9720, -9591, -9267, -8778, -8076, -7230, -6228, -5094, -3855, -2529, -1176,
207, 1605, 2964, 4269, 5478, 6597, 7593, 8412, 9084, 9558, 9846, 9921, 9630,
9342, 8778, 8127, 7299, 6291, 5202, 3999, 2700, 1350, -21, -1389, -2733, -
4050,
-5265, -6372, -7365, -8184, -8862, -9309, -9618
/*
| the reference for a 1000Hz wave at -20 dB is:
| -3240, -3197, -3089, -2926, -2692, -2410, -2076, -1698, -1285, -843,
| -392, +69, +535, +988, +1423, +1826, +2199, +2531, +2804, +3028,
| +3186, +3282, +3307, +3210, +3114, +2926, +2709, +2433, +2097, +1734,
| +1333, +900, +450, -7, -463, -911, -1350, -1755, -2124, -2455,
| -2728, -2954, -3103, -3206
*/
};

static char const * const sineValsMax = (char *)sineVals + sizeof(sineVals);

/---------------------------------------------------------------toneCallback-+
| “Play a Tone” callback |
±---------------------------------------------------------------------------
/
static void toneCallback(void * udata, Uint8 * stream, int len)
{
ToneCallbackData d = *(ToneCallbackData *)udata;
if (d.isEnabled) {
if (d.timeCurr < d.timeMax) {
if (d.timeCurr+len > d.timeMax) {
len = d.timeMax - d.timeCurr;
}
((ToneCallbackData *)udata)->timeCurr += len;
len /= 2;
while (len–) {
if (d.val >= sineValsMax) {
d.val = (char const *)sineVals;
}
*stream++ = *(d.val++);
*stream++ = *(d.val++);
}
((ToneCallbackData )udata)->val = d.val;
}else {
d.isEnabled = 0; /
disable self */
SDL_SemPost(d.playEnded);
}
}
}

/-------------------------------------------------------------------playTone-+
| |
±---------------------------------------------------------------------------
/
int playTone(int freq, int duration)
{
SDL_AudioSpec waveSpec;
ToneCallbackData d;
double ratio = freq / 1000.0;
int rc = 0;

waveSpec.freq = (int)(44100 * ratio); // Samples per sec (FM Radio quality)
waveSpec.format = AUDIO_S16LSB; // Signed 16-bit little-endian samples
waveSpec.channels = 1; // Number of sound channels (stereo)
waveSpec.silence = 0;
waveSpec.samples = 4096; // Size of the Audio buffer in samples
waveSpec.padding = 0;
waveSpec.size = 8192;
waveSpec.callback = toneCallback; // “Play a Tone” callback
waveSpec.userdata = &d; // waveCallback data

d.isEnabled = 0; // disable our toneCallback
if (SDL_OpenAudio(&waveSpec, 0) >= 0) {
d.playEnded = SDL_CreateSemaphore(0);
d.timeCurr = 0;
d.timeMax = (int)(82 * duration * ratio);
d.isEnabled = 1;
d.val = (char const *)sineVals;
SDL_PauseAudio(0); // make sure we play
SDL_SemWait(d.playEnded); // wait here until the callback finishes
SDL_DestroySemaphore(d.playEnded);
SDL_CloseAudio();
}
return rc;
}

/-----------------------------------------------------------------------main-+
| (TEST!) |
±---------------------------------------------------------------------------
/
int main(int argc, char ** argv)
{
if (argc == 3) {
int freq = atoi(argv[1]);
int duration = atoi(argv[2]);
if (freq && duration) {
playTone(freq, duration);
return 0;
}
}
playTone(1000, 100);
fprintf(stderr, “Usage: playTone <duration_ms>\n”);
return -1;
}

/===========================================================================/