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.
17 #define OV_EXCLUDE_STATIC_CALLBACKS
18 #include <vorbis/codec.h>
19 #include <vorbis/vorbisfile.h>
30 /*---------------------------------------------------------------------------*/
32 #define AUDIO_RATE 44100
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 /*---------------------------------------------------------------------------*/
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
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)
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
++;
109 if (V
->amp
< 0.0f
) V
->amp
= 0.0;
110 if (V
->amp
> 1.0f
) V
->amp
= 1.0;
113 /* Mix stereo audio. */
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
++;
126 if (V
->amp
< 0.0f
) V
->amp
= 0.0;
127 if (V
->amp
> 1.0f
) V
->amp
= 1.0;
134 /* We're at EOF. Loop or end the voice. */
138 ov_raw_seek(&V
->vf
, 0);
147 static struct voice
*voice_init(const char *filename
, float a
)
152 /* Allocate and initialize a new voice structure. */
154 if ((V
= (struct voice
*) calloc(1, sizeof (struct voice
))))
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. */
172 V
->chan
= info
->channels
;
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. */
187 static void voice_free(struct voice
*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. */
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
)
222 /* Iterate over all active voices. */
226 /* Mix this voice. */
228 if (V
->play
&& voice_step(V
, sound_vol
, stream
, length
))
230 /* Delete a finished voice... */
235 V
= P
->next
= V
->next
;
237 V
= voices
= V
->next
;
243 /* ... or continue to the next. */
251 /*---------------------------------------------------------------------------*/
253 void audio_init(void)
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)
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. */
291 /* Release the input buffer. */
295 /* Ogg streams and voice structure remain open to allow quality setting. */
298 void audio_play(const char *filename
, float a
)
304 /* If we're already playing this sound, preempt the running copy. */
308 for (V
= voices
; V
; V
= V
->next
)
309 if (strcmp(V
->name
, filename
) == 0)
311 ov_raw_seek(&V
->vf
, 0);
315 if (V
->amp
> 1.0f
) V
->amp
= 1.0;
316 if (V
->amp
< 0.0f
) V
->amp
= 0.0;
324 /* Create a new voice structure. */
326 V
= voice_init(filename
, a
);
328 /* Add it to the list of sounding voices. */
339 /*---------------------------------------------------------------------------*/
341 void audio_music_play(const char *filename
)
349 if ((music
= voice_init(filename
, 0.0f
)))
358 void audio_music_queue(const char *filename
, float t
)
364 if ((queue
= voice_init(filename
, 0.0f
)))
369 queue
->damp
= +1.0f
/ (AUDIO_RATE
* t
);
376 void audio_music_stop(void)
392 /*---------------------------------------------------------------------------*/
394 void audio_music_fade_out(float t
)
398 if (music
) music
->damp
= -1.0f
/ (AUDIO_RATE
* t
);
403 void audio_music_fade_in(float t
)
407 if (music
) music
->damp
= +1.0f
/ (AUDIO_RATE
* t
);
412 void audio_music_fade_to(float t
, const char *filename
)
416 if (strcmp(filename
, music
->name
) != 0)
418 audio_music_fade_out(t
);
419 audio_music_queue(filename
, t
);
424 * We're fading to the current track. Chances are,
425 * whatever track is still in the queue, we don't want to
435 audio_music_fade_in(t
);
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 /*---------------------------------------------------------------------------*/