src/audioplayer.c
changeset 0 06dd3b8d90ad
new file mode 100644
--- /dev/null
+++ b/src/audioplayer.c
@@ -0,0 +1,232 @@
+/**
+ *  $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;
+}