|
|
1.1 root 1: /*
2: Hatari - audio.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: This file contains the routines which pass the audio data to the SDL library.
8: */
9:
10: #include <SDL.h>
11:
12: #include "main.h"
13: #include "audio.h"
14: #include "../m68000.h"
15:
16: #ifdef OGG_MUSIC
17: # include <vorbis/codec.h>
18: # include <vorbis/vorbisfile.h>
19: #endif /* OGG_MUSIC */
20:
21: BOOL bDisableSound = FALSE;
22:
23:
24:
25: #define SND_FREQ 22050
26:
27: /* Converted frontier SFX to wav samples. */
28: #define MAX_SAMPLES 33
29: #define MAX_CHANNELS 4
30:
31: typedef struct wav_stream {
32: Uint8 *buf;
33: int buf_pos;
34: int buf_len;
35: int loop; /* -1 no loop, otherwise specifies loop start pos */
36: } wav_stream;
37:
38: wav_stream sfx_buf[MAX_SAMPLES];
39: wav_stream wav_channels[MAX_CHANNELS];
40:
41: BOOL bSoundWorking = TRUE; /* Is sound OK */
42: volatile BOOL bPlayingBuffer = FALSE; /* Is playing buffer? */
43: int SoundBufferSize = 1024; /* Size of sound buffer */
44:
45: #ifdef OGG_MUSIC
46: static OggVorbis_File music_file;
47: static int music_mode;
48: static BOOL music_playing = FALSE;
49: static int enabled_tracks;
50:
51: static void play_music (int track)
52: {
53: char buf[32];
54: FILE *f;
55:
56: if (music_playing == TRUE) ov_clear (&music_file);
57:
58: snprintf (buf, sizeof (buf), "music/%02d.ogg", track);
59:
60: f = fopen (buf, "rb");
61: if (f == NULL) {
62: music_playing = FALSE;
63: return;
64: }
65:
66: if (ov_open (f, &music_file, NULL, 0) < 0) {
67: fprintf (stderr, "Libvorbis could not open '%s'. Is it an ogg file?\n", buf);
68: fclose (f);
69: music_playing = FALSE;
70: return;
71: }
72:
73: music_playing = TRUE;
74:
75: }
76:
77: int rand_tracknum ()
78: {
79: int track;
80: if (enabled_tracks == 0) return 999;
81: do {
82: track = rand () % 8;
83: } while ((enabled_tracks & (1<<track)) == 0);
84: return track;
85: }
86: #endif /* OGG_MUSIC */
87:
88: void Call_PlayMusic ()
89: {
90: #ifdef OGG_MUSIC
91: /* Playing mode in d0:
92: * -2 = play random track once
93: * -1 = play random tracks continuously
94: * 0+ = play specific track once
95: * d1:d2 is a mask of enabled tracks
96: */
97: //printf ("Play track $%x. Enabled tracks $%x%x.\n", GetReg (0), GetReg (1), GetReg(2));
98: music_mode = GetReg (0);
99:
100: enabled_tracks = 0;
101:
102: if (GetReg (1)&0xff000000) enabled_tracks |= 0x1;
103: if (GetReg (1)&0xff0000) enabled_tracks |= 0x2;
104: if (GetReg (1)&0xff00) enabled_tracks |= 0x4;
105: if (GetReg (1)&0xff) enabled_tracks |= 0x8;
106: if (GetReg (2)&0xff000000) enabled_tracks |= 0x10;
107: if (GetReg (2)&0xff0000) enabled_tracks |= 0x20;
108: if (GetReg (2)&0xff00) enabled_tracks |= 0x40;
109: if (GetReg (2)&0xff) enabled_tracks |= 0x80;
110:
111: SDL_LockAudio ();
112: switch (music_mode) {
113: case -2:
114: /* hyperspace and battle music --
115: * don't play blue danube or reward music */
116: enabled_tracks &= ~0x40;
117: enabled_tracks &= ~0x80;
118: play_music (rand_tracknum ());
119: break;
120: case -1:
121: /* any music */
122: play_music (rand_tracknum ());
123: break;
124: default:
125: play_music (music_mode);
126: break;
127: }
128: SDL_UnlockAudio ();
129:
130: #endif /* OGG_MUSIC */
131: }
132:
133: #ifdef OGG_MUSIC
134: static void stop_music ()
135: {
136: music_playing = FALSE;
137: //printf ("Stop music.\n");
138: ov_clear (&music_file);
139: }
140: #endif /* OGG_MUSIC */
141:
142: void Call_StopMusic ()
143: {
144: #ifdef OGG_MUSIC
145: SDL_LockAudio ();
146: stop_music ();
147: SDL_UnlockAudio ();
148: #endif /* OGG_MUSIC */
149: }
150:
151: void Call_IsMusicPlaying ()
152: {
153: #ifdef OGG_MUSIC
154: SetReg (0, music_playing);
155: #else
156: SetReg (0, 0);
157: #endif /* OGG_MUSIC */
158: }
159:
160: void Call_PlaySFX ()
161: {
162: int sample, chan;
163:
164: SDL_LockAudio ();
165:
166: sample = (short) GetReg (REG_D0);
167: chan = (short) GetReg (REG_D1);
168: //printf ("Playing sample %d on channel %d.\n", sample, chan);
169:
170: wav_channels[chan].buf_pos = 0;
171: wav_channels[chan].buf_len = sfx_buf[sample].buf_len;
172: wav_channels[chan].buf = sfx_buf[sample].buf;
173: wav_channels[chan].loop = sfx_buf[sample].loop;
174:
175: SDL_UnlockAudio ();
176: }
177:
178: /*-----------------------------------------------------------------------*/
179: /*
180: SDL audio callback function - copy emulation sound to audio system.
181: */
182: void Audio_CallBack(void *userdata, Uint8 *pDestBuffer, int len)
183: {
184: Sint8 *pBuffer;
185: int i, j;
186: short sample;
187: BOOL playing = FALSE;
188:
189: pBuffer = pDestBuffer;
190:
191: for (i=0; i<MAX_CHANNELS; i++) {
192: if (wav_channels[i].buf != NULL) {
193: playing = TRUE;
194: break;
195: }
196: }
197:
198: memset (pDestBuffer, 0, len);
199:
200: #ifdef OGG_MUSIC
201: if (music_playing) {
202: i = 0;
203: while (i < len) {
204: int amt;
205: int music_section;
206: amt = ov_read (&music_file, (char *)&pDestBuffer[i],
207: (len - i), 0, 2, 1, &music_section);
208: i += amt;
209:
210: /* end of stream */
211: if (amt == 0) {
212: //printf ("ogg stream ended.\n");
213: if (music_mode == -1) {
214: play_music (rand_tracknum ());
215: } else {
216: stop_music ();
217: }
218: break;
219: }
220: }
221: }
222: #endif /* OGG_MUSIC */
223:
224: if (!playing) return;
225:
226: for (i = 0; i < len; i+=4) {
227: sample = 0;
228: for (j=0; j<MAX_CHANNELS; j++) {
229: if (wav_channels[j].buf == NULL) continue;
230: sample += *(short *)(wav_channels[j].buf + wav_channels[j].buf_pos);
231: wav_channels[j].buf_pos += 2;
232: if (wav_channels[j].buf_pos >= wav_channels[j].buf_len) {
233: /* end of sample. either loop or terminate */
234: if (wav_channels[j].loop != -1) {
235: wav_channels[j].buf_pos = wav_channels[j].loop;
236: } else {
237: wav_channels[j].buf = NULL;
238: }
239: }
240: }
241: /* stereo! */
242: *((short*)pBuffer) += sample;
243: pBuffer += 2;
244: *((short*)pBuffer) += sample;
245: pBuffer += 2;
246: }
247: }
248:
249: /*
250: * Loaded samples must be SND_FREQ, 16-bit signed. Reject
251: * other frequencies but convert 8-bit unsigned.
252: */
253: void check_sample_format (SDL_AudioSpec *spec, Uint8 **buf, int *len, const char *filename)
254: {
255: Uint8 *old_buf = *buf;
256: short *new_buf;
257: int i;
258:
259: if (spec->freq != SND_FREQ) {
260: printf ("Sample %s is the wrong sample rate (wanted %dHz). Ignoring.\n", filename, SND_FREQ);
261: SDL_FreeWAV (*buf);
262: *buf = NULL;
263: return;
264: }
265:
266: if (spec->format == AUDIO_U8) {
267: new_buf = malloc ((*len)*2);
268: for (i=0; i<(*len); i++) {
269: new_buf[i] = (old_buf[i] ^ 128) << 8;
270: }
271: *len *= 2;
272: SDL_FreeWAV (old_buf);
273: *buf = (char *)new_buf;
274: } else if (spec->format != AUDIO_S16) {
275: printf ("Sample %s is not 16-bit-signed or 8-bit unsigned. Ignoring.", filename);
276: SDL_FreeWAV (*buf);
277: *buf = NULL;
278: return;
279: }
280: }
281:
282: /*-----------------------------------------------------------------------*/
283: /*
284: Initialize the audio subsystem. Return TRUE if all OK.
285: We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
286: */
287: void Audio_Init(void)
288: {
289: int i;
290: char filename[32];
291: SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */
292:
293: /* Is enabled? */
294: if(bDisableSound)
295: {
296: /* Stop any sound access */
297: printf("Sound: Disabled\n");
298: bSoundWorking = FALSE;
299: return;
300: }
301:
302: /* Init the SDL's audio subsystem: */
303: if( SDL_WasInit(SDL_INIT_AUDIO)==0 )
304: {
305: if( SDL_InitSubSystem(SDL_INIT_AUDIO)<0 )
306: {
307: fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() );
308: bSoundWorking = FALSE;
309: return;
310: }
311: }
312:
313: /* Set up SDL audio: */
314: desiredAudioSpec.freq = SND_FREQ;
315: desiredAudioSpec.format = AUDIO_S16; /* 8 Bit unsigned */
316: desiredAudioSpec.channels = 2; /* Mono */
317: desiredAudioSpec.samples = 1024; /* Buffer size */
318: desiredAudioSpec.callback = Audio_CallBack;
319: desiredAudioSpec.userdata = NULL;
320:
321: if( SDL_OpenAudio(&desiredAudioSpec, NULL) ) /* Open audio device */
322: {
323: fprintf(stderr, "Can't use audio: %s\n", SDL_GetError());
324: bSoundWorking = FALSE;
325: //ConfigureParams.Sound.bEnableSound = FALSE;
326: return;
327: }
328:
329: SoundBufferSize = desiredAudioSpec.size; /* May be different than the requested one! */
330:
331: for (i=0; i<MAX_SAMPLES; i++) {
332: snprintf (filename, sizeof (filename), "sfx/sfx_%02d.wav", i);
333: if (SDL_LoadWAV (filename, &desiredAudioSpec, &sfx_buf[i].buf,
334: &sfx_buf[i].buf_len) == NULL) {
335: printf ("Error loading %s: %s\n", filename, SDL_GetError ());
336: sfx_buf[i].buf = NULL;
337: }
338: check_sample_format (&desiredAudioSpec, &sfx_buf[i].buf, &sfx_buf[i].buf_len, filename);
339:
340: /* 19 (hyperspace) and 23 (noise) loop */
341: if (i == 19) sfx_buf[i].loop = SND_FREQ; /* loop to about 0.5 sec in */
342: else if (i == 23) sfx_buf[i].loop = 0;
343: else sfx_buf[i].loop = -1;
344: }
345:
346: /* All OK */
347: bSoundWorking = TRUE;
348: /* And begin */
349: Audio_EnableAudio(TRUE);
350: }
351:
352:
353: /*-----------------------------------------------------------------------*/
354: /*
355: Free audio subsystem
356: */
357: void Audio_UnInit(void)
358: {
359: /* Stop */
360: Audio_EnableAudio(FALSE);
361:
362: SDL_CloseAudio();
363: }
364:
365:
366: /*-----------------------------------------------------------------------*/
367: /*
368: Start/Stop sound buffer
369: */
370: void Audio_EnableAudio(BOOL bEnable)
371: {
372: if(bEnable && !bPlayingBuffer)
373: {
374: /* Start playing */
375: SDL_PauseAudio(FALSE);
376: bPlayingBuffer = TRUE;
377: }
378: else if(!bEnable && bPlayingBuffer)
379: {
380: /* Stop from playing */
381: SDL_PauseAudio(!bEnable);
382: bPlayingBuffer = bEnable;
383: }
384: }
385:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.