|
|
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.