/**
* $Id: audioplayer.c 53 2008-01-10 00:19:41Z mbroeker $
* $URL: http://localhost/svn/c/VirtualReader/trunk/src/audioplayer.c $
*/
#include <audioplayer.h>
typedef struct {
SDL_AudioSpec spec; // internal structure
Uint8 *sound_buffer; // malloced pointer from sdl
Uint32 sound_pos; // position
Uint32 sound_len; // length in bytes
Uint32 length; // Length in Milliseconds
int opened; // bool opened
int loaded; // bool loaded
int verbose; // verbose messages
int timeout; // timeout
int timer; // bool timer
} AudioDevice;
AudioDevice AD;
int audio_init ()
{
/*
* initialize SDL for audio output
*/
if (SDL_Init (SDL_INIT_AUDIO) < 0) {
fprintf (stderr, "audio_init: Cannot initialize SDL-Subsystem\n");
return -1;
}
AD.sound_buffer = 0;
AD.sound_pos = 0;
AD.sound_len = 0;
AD.opened = 0;
AD.loaded = 0;
AD.verbose = 0;
AD.timeout = 0;
AD.timer = 0;
return 0;
}
void audio_shutdown ()
{
/*
* quit sdl
*/
SDL_AudioQuit ();
SDL_Quit ();
}
static void Callback (void *userdata, Uint8 * stream, int len)
{
Uint8 *waveptr = NULL;
/*
* loaded = 0 Segmentation fault
* len = 0 nothing to play
*/
if (!(AD.loaded && len))
return;
waveptr = AD.sound_buffer + AD.sound_pos;
SDL_MixAudio (stream, waveptr, len, SDL_MIX_MAXVOLUME);
AD.sound_pos += len; /* bereits gespielt */
if (audioplayer_gettime () > (AD.length - AD.timeout)) {
AD.sound_pos = AD.length;
AD.sound_len = 0;
AD.timer = 0;
}
}
Uint32 audioplayer_getsoundlen ()
{
return AD.sound_len;
}
void audioplayer_media_info (char *fname)
{
AD.length = audioplayer_getwavelength (fname);
printf ("Playing %s: %d Hz, %d Bit Audio, %d Channel(s), %3.2d ms\n",
fname, AD.spec.freq, audioplayer_getbitrate (), AD.spec.channels, AD.length);
}
int audioplayer_getbitrate ()
{
int bitrate = 0;
switch (AD.spec.format) {
case AUDIO_U8:
case AUDIO_S8:
bitrate = 8;
break;
case AUDIO_S16LSB:
case AUDIO_S16MSB:
case AUDIO_U16LSB:
case AUDIO_U16MSB:
bitrate = 16;
break;
}
return bitrate;
}
Uint32 audioplayer_getwavelength (char *fname)
{
struct stat info;
Uint32 value = 0;
if (fname == NULL)
return AD.length;
if (stat (fname, &info) == 0)
/*
* the value is really big, so be carefull
* changes in the order result in different values
* the storage type isn`t well choosen...
*/
value = ((info.st_size) / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0);
return (value);
}
Uint32 audioplayer_getposition ()
{
return AD.sound_pos;
}
Uint32 audioplayer_gettime ()
{
Uint32 ret;
ret = AD.sound_pos / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0;
return ret;
}
void audioplayer_settime (long tm)
{
AD.sound_pos = tm / 1000.0 * (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0));
/*
* Eine Adresse ...
*/
while ((AD.sound_pos % 2) != 0)
AD.sound_pos++;
if (AD.verbose)
printf ("\e[31m[ATTENTION]\e[37m [#%d/#%d] = %d ms\n", AD.sound_pos, AD.sound_len, audioplayer_gettime ());
}
void audioplayer_stop ()
{
/*
* stops the callback function
*/
SDL_PauseAudio (1);
AD.spec.callback = NULL;
if (AD.loaded == 1)
SDL_FreeWAV (AD.sound_buffer);
AD.loaded = 0;
AD.timer = 0;
}
void audioplayer_delay (Uint32 milliseconds)
{
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = milliseconds * 1000;
while (AD.timer)
nanosleep (&tm, NULL);
}
void audioplayer_setverbose (int verbose)
{
AD.verbose = verbose;
}
int audioplayer (char *fname, Uint32 timeout)
{
if (SDL_LoadWAV (fname, &AD.spec, &AD.sound_buffer, &AD.sound_len) == NULL) {
printf ("SDL: %s\n", SDL_GetError ());
return -1;
}
AD.loaded = 1;
if (!AD.opened) {
AD.spec.callback = Callback;
if (SDL_OpenAudio (&AD.spec, NULL) < 0) {
fprintf (stderr, "Cannot open audio device: %s\n", SDL_GetError ());
return -1;
}
AD.opened = 1;
}
/*
* calls implicitly getwavelength
*/
audioplayer_media_info (fname);
AD.sound_pos = 0;
/*
* starts playback via Callback function
*/
SDL_PauseAudio (0);
/*
* initializes the timeout mechanism
*/
AD.timer = 1;
AD.timeout = timeout;
/*
* controlled delay
*/
audioplayer_delay (timeout);
return 0;
}