Add missing credit for Esperanto translation
[neverball.git] / share / audio.c
blob8ff3487ffdadcf8a02b3180f580cf7403c479ec3
1 /*
2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 #include <SDL.h>
17 #define OV_EXCLUDE_STATIC_CALLBACKS
18 #include <vorbis/codec.h>
19 #include <vorbis/vorbisfile.h>
21 #include <string.h>
22 #include <stdlib.h>
24 #include "config.h"
25 #include "audio.h"
26 #include "common.h"
27 #include "fs.h"
28 #include "fs_ov.h"
30 /*---------------------------------------------------------------------------*/
32 #define AUDIO_RATE 44100
33 #define AUDIO_CHAN 2
35 struct voice
37 OggVorbis_File vf;
38 float amp;
39 float damp;
40 int chan;
41 int play;
42 int loop;
43 char *name;
44 struct voice *next;
47 static int audio_state = 0;
48 static float sound_vol = 1.0f;
49 static float music_vol = 1.0f;
51 static SDL_AudioSpec spec;
53 static struct voice *music = NULL;
54 static struct voice *queue = NULL;
55 static struct voice *voices = NULL;
56 static short *buffer = NULL;
58 static ov_callbacks callbacks = {
59 fs_ov_read, fs_ov_seek, fs_ov_close, fs_ov_tell
62 /*---------------------------------------------------------------------------*/
64 #define MIX(d, s) { \
65 int T = (int) (d) + (int) (s); \
66 if (T > 32767) (d) = 32767; \
67 else if (T < -32768) (d) = -32768; \
68 else (d) = (short) T; \
71 static int voice_step(struct voice *V, float volume, Uint8 *stream, int length)
73 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
74 int order = 1;
75 #else
76 int order = 0;
77 #endif
79 short *obuf = (short *) stream;
80 char *ibuf = (char *) buffer;
82 int i, b = 0, n = 1, c = 0, r = 0;
84 /* Compute the total request size for the current stream. */
86 if (V->chan == 1) r = length / 2;
87 if (V->chan == 2) r = length ;
89 /* While data is coming in and data is still needed... */
91 while (n > 0 && r > 0)
93 /* Read audio from the stream. */
95 if ((n = (int) ov_read(&V->vf, ibuf, r, order, 2, 1, &b)) > 0)
97 /* Mix mono audio. */
99 if (V->chan == 1)
100 for (i = 0; i < n / 2; i += 1)
102 short M = (short) (V->amp * volume * buffer[i]);
104 MIX(obuf[c], M); c++;
105 MIX(obuf[c], M); c++;
107 V->amp += V->damp;
109 if (V->amp < 0.0f) V->amp = 0.0;
110 if (V->amp > 1.0f) V->amp = 1.0;
113 /* Mix stereo audio. */
115 if (V->chan == 2)
116 for (i = 0; i < n / 2; i += 2)
118 short L = (short) (V->amp * volume * buffer[i + 0]);
119 short R = (short) (V->amp * volume * buffer[i + 1]);
121 MIX(obuf[c], L); c++;
122 MIX(obuf[c], R); c++;
124 V->amp += V->damp;
126 if (V->amp < 0.0f) V->amp = 0.0;
127 if (V->amp > 1.0f) V->amp = 1.0;
130 r -= n;
132 else
134 /* We're at EOF. Loop or end the voice. */
136 if (V->loop)
138 ov_raw_seek(&V->vf, 0);
139 n = 1;
141 else return 1;
144 return 0;
147 static struct voice *voice_init(const char *filename, float a)
149 struct voice *V;
150 fs_file fp;
152 /* Allocate and initialize a new voice structure. */
154 if ((V = (struct voice *) calloc(1, sizeof (struct voice))))
156 /* Note the name. */
158 V->name = strdup(filename);
160 /* Attempt to open the named Ogg stream. */
162 if ((fp = fs_open(filename, "r")))
164 if (ov_open_callbacks(fp, &V->vf, NULL, 0, callbacks) == 0)
166 vorbis_info *info = ov_info(&V->vf, -1);
168 /* On success, configure the voice. */
170 V->amp = a;
171 V->damp = 0;
172 V->chan = info->channels;
173 V->play = 1;
174 V->loop = 0;
176 if (V->amp > 1.0f) V->amp = 1.0;
177 if (V->amp < 0.0f) V->amp = 0.0;
179 /* The file will be closed when the Ogg is cleared. */
181 else fs_close(fp);
184 return V;
187 static void voice_free(struct voice *V)
189 ov_clear(&V->vf);
191 free(V->name);
192 free(V);
195 /*---------------------------------------------------------------------------*/
197 static void audio_step(void *data, Uint8 *stream, int length)
199 struct voice *V = voices;
200 struct voice *P = NULL;
202 /* Zero the output buffer. */
204 memset(stream, 0, length);
206 /* Mix the background music. */
208 if (music)
210 voice_step(music, music_vol, stream, length);
212 /* If the track has faded out, move to a queued track. */
214 if (music->amp <= 0.0f && music->damp < 0.0f && queue)
216 voice_free(music);
217 music = queue;
218 queue = NULL;
222 /* Iterate over all active voices. */
224 while (V)
226 /* Mix this voice. */
228 if (V->play && voice_step(V, sound_vol, stream, length))
230 /* Delete a finished voice... */
232 struct voice *T = V;
234 if (P)
235 V = P->next = V->next;
236 else
237 V = voices = V->next;
239 voice_free(T);
241 else
243 /* ... or continue to the next. */
245 P = V;
246 V = V->next;
251 /*---------------------------------------------------------------------------*/
253 void audio_init(void)
255 audio_state = 0;
257 /* Configure the audio. */
259 spec.format = AUDIO_S16SYS;
260 spec.channels = AUDIO_CHAN;
261 spec.samples = config_get_d(CONFIG_AUDIO_BUFF);
262 spec.freq = AUDIO_RATE;
263 spec.callback = audio_step;
265 /* Allocate an input buffer. */
267 if ((buffer = (short *) malloc(spec.samples * 4)))
269 /* Start the audio thread. */
271 if (SDL_OpenAudio(&spec, NULL) == 0)
273 audio_state = 1;
274 SDL_PauseAudio(0);
276 else log_printf("Failure to open audio device (%s)\n", SDL_GetError());
279 /* Set the initial volumes. */
281 audio_volume(config_get_d(CONFIG_SOUND_VOLUME),
282 config_get_d(CONFIG_MUSIC_VOLUME));
285 void audio_free(void)
287 /* Halt the audio thread. */
289 SDL_CloseAudio();
291 /* Release the input buffer. */
293 free(buffer);
295 /* Ogg streams and voice structure remain open to allow quality setting. */
298 void audio_play(const char *filename, float a)
300 if (audio_state)
302 struct voice *V;
304 /* If we're already playing this sound, preempt the running copy. */
306 SDL_LockAudio();
308 for (V = voices; V; V = V->next)
309 if (strcmp(V->name, filename) == 0)
311 ov_raw_seek(&V->vf, 0);
313 V->amp = a;
315 if (V->amp > 1.0f) V->amp = 1.0;
316 if (V->amp < 0.0f) V->amp = 0.0;
318 SDL_UnlockAudio();
319 return;
322 SDL_UnlockAudio();
324 /* Create a new voice structure. */
326 V = voice_init(filename, a);
328 /* Add it to the list of sounding voices. */
330 SDL_LockAudio();
332 V->next = voices;
333 voices = V;
335 SDL_UnlockAudio();
339 /*---------------------------------------------------------------------------*/
341 void audio_music_play(const char *filename)
343 if (audio_state)
345 audio_music_stop();
347 SDL_LockAudio();
349 if ((music = voice_init(filename, 0.0f)))
351 music->loop = 1;
354 SDL_UnlockAudio();
358 void audio_music_queue(const char *filename, float t)
360 if (audio_state)
362 SDL_LockAudio();
364 if ((queue = voice_init(filename, 0.0f)))
366 queue->loop = 1;
368 if (t > 0.0f)
369 queue->damp = +1.0f / (AUDIO_RATE * t);
372 SDL_UnlockAudio();
376 void audio_music_stop(void)
378 if (audio_state)
380 SDL_LockAudio();
382 if (music)
384 voice_free(music);
386 music = NULL;
388 SDL_UnlockAudio();
392 /*---------------------------------------------------------------------------*/
394 void audio_music_fade_out(float t)
396 SDL_LockAudio();
398 if (music) music->damp = -1.0f / (AUDIO_RATE * t);
400 SDL_UnlockAudio();
403 void audio_music_fade_in(float t)
405 SDL_LockAudio();
407 if (music) music->damp = +1.0f / (AUDIO_RATE * t);
409 SDL_UnlockAudio();
412 void audio_music_fade_to(float t, const char *filename)
414 if (music)
416 if (strcmp(filename, music->name) != 0)
418 audio_music_fade_out(t);
419 audio_music_queue(filename, t);
421 else
424 * We're fading to the current track. Chances are,
425 * whatever track is still in the queue, we don't want to
426 * hear it anymore.
429 if (queue)
431 voice_free(queue);
432 queue = NULL;
435 audio_music_fade_in(t);
438 else
440 audio_music_play(filename);
441 audio_music_fade_in(t);
445 void audio_volume(int s, int m)
447 sound_vol = (float) s / 10.0f;
448 music_vol = (float) m / 10.0f;
451 /*---------------------------------------------------------------------------*/