From 3995cbc7f3b6a2c7704d37acd8d7eff96f5f3cbe Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sun, 18 Feb 2007 21:58:58 +0000 Subject: [PATCH] New audio output interface now works. --- ChangeLog | 4 +++ src/audio/audio.c | 12 +++++-- src/audio/audio.h | 11 +++++++ src/module/sdl.c | 93 +++++++++++++++++++++++++++++++++---------------------- 4 files changed, 81 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9655493..782cea4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-02-18 + -Revamped audio output API to move resource access to the ao plugin, + allowing for the plugin to have more control over how things are + played. 2007-02-08 -Fixed build so that FFMpeg plugin is not built if libav{codec,format} support is disabled / not detected. diff --git a/src/audio/audio.c b/src/audio/audio.c index 3ebeec1..b706ddd 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -29,12 +29,20 @@ static struct audio_output *ao; -int ao_play(struct audio_data *data, int flags) +struct audio_data *ao_open(const char *resource, int flags) +{ + if (!ao) + return NULL; + + return ao->open(resource, flags); +} + +int ao_play(struct audio_data *data, int nloops) { if (!ao) return -1; - return ao->play(data, flags); + return ao->play(data, nloops); } int ao_init(int flags) diff --git a/src/audio/audio.h b/src/audio/audio.h index 69c989c..ab34478 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -23,6 +23,8 @@ * $Revision$ * $Author$ */ +#ifndef AUDIO_H +#define AUDIO_H /**@defgroup Audio Audio Services * @{ @@ -57,9 +59,16 @@ struct audio_format { struct audio_output { int (*init)(int); + int (*fini)(int); + struct audio_data *(*open)(const char *, int); + void (*close)(struct audio_data *); int (*play)(struct audio_data *, int); + int (*stop)(int); + int (*fade)(int, struct audio_data *, int); }; +int audio_init(void); + /** Initialize audio output driver. * * @param flags Reserved. @@ -138,3 +147,5 @@ int ao_stop(int id); int ao_fade(int id, struct audio_data *data, int nloops); /*@}*/ + +#endif diff --git a/src/module/sdl.c b/src/module/sdl.c index 3fdc808..dbe34f7 100644 --- a/src/module/sdl.c +++ b/src/module/sdl.c @@ -24,6 +24,8 @@ #define SDL_MODULE "SDL" #define SDL_MODULE_VERSION "0.1.0" +#include +#include #include #include "../audio/avfile.h" @@ -48,6 +50,7 @@ struct audio_data { }; static struct channel { + int chanid; struct audio_data *data; int nloops; } *channels; @@ -82,7 +85,7 @@ static int setchannels(int numchannels) } /* Read a block of channel data */ -static void read_channel(int c, int len) +static void stream_read(int c, int len) { Uint8 *stream = channels[c].data->data; int rc; @@ -92,8 +95,11 @@ static void read_channel(int c, int len) if (rc == -1) break; - if (rc < len && channels[c].nloops) { - if (av.rewind(channels[c].data->aid) == -1) break; + if (rc < len && channels[c].nloops != 0) { + if (av.rewind(channels[c].data->aid) == -1) + break; + if (channels[c].nloops > 0) + channels[c].nloops--; } else if (rc < len) break; @@ -113,34 +119,38 @@ static void render_audio(void *userdata, Uint8 *stream, int len) /* Read data for all channels */ for (i = 0; i < nchannels; i++) - if (channels[i].aid >= 0) - read_channel(i, len); + if (channels[i].data && channels[i].data->flags & AUD_OPEN_STREAM) + stream_read(i, len); /* TO DO: Not explode with sample formats other than S16_LE */ for (samp = (Sint16 *) stream; (Uint8 *) samp - stream < len; samp++) { - double m = 0; + double m = 0, c; ptrdiff_t off = samp - (Sint16 *) stream; for (i = 0; i < nchannels; i++) { - if (channels[i].aid == -1) + if (!channels[i].data) continue; - buf = (Sint16 *) channels[i].buf; + buf = (Sint16 *) channels[i].data->data; + c = buf[off]; /* Mix sample into output */ - if (m >= 0 && buf[off] >= 0) - m = (m + (double)buf[off]) - - (m * (double)buf[off]) / 32768; - else if (m <= 0 && buf[off] <= 0) - m = (m + (double)buf[off]) + - (m * (double)buf[off]) / 32768; + if (m >= 0 && c >= 0) + m = (m + c) - (m * c) / 32768; + else if (m <= 0 && c <= 0) + m = (m + c) + (m * c) / 32768; else - m = (m + (double)buf[off]); + m = (m + c); } /* Render sample */ *samp = m; } + + /* Clean up finished channels */ + for (i = 0; i < nchannels; i++) + if (!channels[i].nloops) + channels[i].data = NULL; } static struct audio_data *sdl_ao_open(const char *resource, int flags) @@ -150,7 +160,7 @@ static struct audio_data *sdl_ao_open(const char *resource, int flags) if (!new) goto err; - if (!(new->aid = av.open(resource, AV_INPUT_AUDIO, fmt, NULL))) + if ((new->aid = av.open(resource, AV_INPUT_AUDIO, &fmt, NULL)) == -1) goto err; new->flags = flags; @@ -160,7 +170,7 @@ static struct audio_data *sdl_ao_open(const char *resource, int flags) if (!(new->data = malloc(new->datasz))) goto err; } else if (flags & AUD_OPEN_SAMPLE) { - + goto err; } return new; @@ -177,32 +187,37 @@ static void sdl_ao_close(struct audio_data *data) data_delete(data); } -/* Play the audio data from the given AV id, according to flags. */ -static int sdl_ao_play(int channel, int id, int flags) +static int sdl_ao_play(struct audio_data *data, int nloops) { - int i = channel; - if (channel == -1) - for (i = 0; i < nchannels; i++) - if (channels[i].aid == -1) break; + static int chanid; + int i; - if (i < 0 || i >= nchannels) + if (nloops < -1 || nloops == 0) return -1; SDL_LockAudio(); - /* TO DO: Something more intelligent. */ - if (!(channels[i].buf = malloc(sdlfmt.format * 4))) + for (i = 0; i < nchannels; i++) + if (!channels[i].data) + break; + + /* Cancelling a currently playing channel may be better */ + if (i >= nchannels) return -1; - - channels[i].aid = id; - channels[i].flags = flags; + + data->playing++; + channels[i].data = data; + channels[i].chanid = chanid; + channels[i].nloops = nloops; SDL_UnlockAudio(); - return i; + chanid = (chanid + 1) % INT_MAX+1; + + return chanid; } -/* Open the SDL audio device */ +/* Open the SDL audio device. TO DO: This is ugly, fix it. */ static int sdl_ao_init(int flags) { struct SDL_AudioSpec desired; @@ -211,7 +226,7 @@ static int sdl_ao_init(int flags) if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) { logger.write(LOG_ERROR, SDL_MODULE, "Failed to init audio: %s", SDL_GetError()); - return NULL; + return -1; } /* TO DO: This should be configurable */ @@ -225,7 +240,7 @@ static int sdl_ao_init(int flags) if (SDL_OpenAudio(&desired, &sdlfmt) == -1) { logger.write(LOG_ERROR, SDL_MODULE, "Failed to open audio device: %s", SDL_GetError()); - return NULL; + return -1; } fmt.frequency = sdlfmt.freq; @@ -259,18 +274,22 @@ static int sdl_ao_init(int flags) SDL_PauseAudio(0); - return &fmt; + return 0; err: SDL_CloseAudio(); - return NULL; + return -1; } int init(plugin_useservice_t useservice) { static struct audio_output ao_sdl = { #undef init - .init = sdl_ao_init, - .play = sdl_ao_play, + .init = sdl_ao_init, +// .fini = sdl_ao_fini, + .open = sdl_ao_open, + .close = sdl_ao_close, + .play = sdl_ao_play, +// .stop = sdl_ao_stop, }; if (useservice(LOG_SERVICE, SDL_MODULE, &logger)) -- 2.11.4.GIT