2 * sdlvf - the SDL/vorbisfile sound system
3 * Copyright (C) 2004 Vasilis Vasaitis <vvas@hal.csd.auth.gr>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <vorbis/codec.h>
21 #include <vorbis/vorbisfile.h>
26 #define SDL_SAMPLES 2048
27 #define VORBISFILE_BUFFER 4096
29 #define MIN(x, y) ((x) < (y) ? (x) : (y))
32 * The error strings array, which must be kept in sync with the error
35 static char *audio_errors[] = {
37 "audio playback has been stopped",
38 "could not open input file for reading",
39 "input file does not appear to be an valid bitstream",
40 "unable to get information about the current logical bitstream",
41 "unable to open the audio device"
45 * The static data shared by all SDL/vorbisfile functions. Note that
46 * there is never a need for more than one instance of the sound
47 * system, so this a reasonable thing to do.
49 static OggVorbis_File audio_vf;
50 static volatile int audio_stopped, audio_reopen;
53 * This function is called by SDL when more audio data is needed.
55 static void audio_callback(void *userdata, Uint8 *stream, int len)
57 /* state information kept across calls */
58 static char buf[VORBISFILE_BUFFER];
59 static int buflen = 0;
61 static int stopped = 0, reopen = 0;
66 /* check for exceptional conditions */
67 if (stopped || reopen) {
68 audio_stopped = stopped;
69 audio_reopen = reopen;
72 if (audio_stopped || audio_reopen) return;
74 /* check for leftovers in our buffer */
76 int copy = MIN(buflen, len);
77 memcpy(stream, buf, copy);
80 memmove(buf, buf + copy, buflen);
84 while (filled < len) {
85 int needed = MIN(VORBISFILE_BUFFER, len - filled), read;
87 do read = ov_read(&audio_vf, stream + filled, needed, 0, 2, 1, &curr);
93 if (curr != prev && prev != -1) {
94 memcpy(buf, stream + filled, buflen = read);
95 memset(stream + filled, 0, read);
104 * Opens the audio device based on the parameters of the current
105 * logical bitstream of the Ogg Vorbis file.
107 static int audio_open(void)
115 if ((vi = ov_info(&audio_vf, -1)) == NULL)
116 return SDLVF_BADSTREAM;
118 as.format = AUDIO_S16;
119 as.channels = vi->channels;
120 as.samples = SDL_SAMPLES;
121 as.callback = audio_callback;
123 if (SDL_OpenAudio(&as, NULL) == -1)
124 return SDLVF_NOAUDIO;
127 return SDLVF_PLAYING;
131 * Closes the audio device; provided for naming consistency.
133 static void audio_close(void)
139 * Initialises SDL/vorbisfile and starts playing the Ogg Vorbis file
140 * <fname>. Returns zero (SDLVF_PLAYING) on success; any other value
141 * indicates an error.
143 int sdlvf_init(const char *fname)
147 if ((f = fopen(fname, "rb")) == NULL)
148 return SDLVF_BADFILE;
149 if (ov_open(f, &audio_vf, NULL, 0) != 0) {
153 if ((result = audio_open()) != SDLVF_PLAYING)
159 * Checks the status of SDL/vorbisfile, reopening the audio device if
160 * necessary. It also reports whether audio playback has stopped.
162 int sdlvf_check(void)
165 return SDLVF_STOPPED;
170 return SDLVF_PLAYING;
174 * Seeks to the specified <time> in seconds, taking care of locking
175 * and avoiding clicks and pops.
177 int sdlvf_seek(double time)
181 result = ov_time_seek_lap(&audio_vf, time);
187 * Shuts down SDL/vorbisfile, closing the audio device and freeing
190 void sdlvf_done(void)
197 * Returns the equivalent error string for the supplied error code.
199 char *sdlvf_strerror(int error)
201 return audio_errors[error];