|
|
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 "configuration.h" ! 15: #include "memAlloc.h" ! 16: #include "misc.h" ! 17: #include "decode.h" ! 18: ! 19: #define SND_FREQ 22050 ! 20: ! 21: /* Converted frontier SFX to wav samples. */ ! 22: #define MAX_SAMPLES 33 ! 23: #define MAX_CHANNELS 4 ! 24: ! 25: typedef struct wav_stream { ! 26: Uint8 *buf; ! 27: int buf_pos; ! 28: int buf_len; ! 29: int loop; /* -1 no loop, otherwise specifies loop start pos */ ! 30: } wav_stream; ! 31: ! 32: wav_stream sfx_buf[MAX_SAMPLES]; ! 33: wav_stream wav_channels[MAX_CHANNELS]; ! 34: ! 35: void Call_PlaySFX (unsigned long params) ! 36: { ! 37: int sample, chan; ! 38: ! 39: SDL_LockAudio (); ! 40: ! 41: sample = Regs[REG_D0] & 0xffff; ! 42: chan = Regs[REG_D1] & 0xffff; ! 43: //printf ("Playing sample %d on channel %d.\n", sample, chan); ! 44: ! 45: wav_channels[chan].buf_pos = 0; ! 46: wav_channels[chan].buf_len = sfx_buf[sample].buf_len; ! 47: wav_channels[chan].buf = sfx_buf[sample].buf; ! 48: wav_channels[chan].loop = sfx_buf[sample].loop; ! 49: ! 50: SDL_UnlockAudio (); ! 51: } ! 52: ! 53: void Audio_Reset () ! 54: { ! 55: int i; ! 56: SDL_LockAudio (); ! 57: for (i=0; i<MAX_CHANNELS; i++) { ! 58: wav_channels[i].buf = NULL; ! 59: } ! 60: SDL_UnlockAudio (); ! 61: } ! 62: ! 63: /* 11Khz, 22Khz, 44Khz playback */ ! 64: int SoundPlayBackFrequencies[] = ! 65: { ! 66: 11025, /* PLAYBACK_LOW */ ! 67: 22050, /* PLAYBACK_MEDIUM */ ! 68: 44100, /* PLAYBACK_HIGH */ ! 69: }; ! 70: ! 71: ! 72: BOOL bDisableSound = FALSE; ! 73: BOOL bSoundWorking = TRUE; /* Is sound OK */ ! 74: volatile BOOL bPlayingBuffer = FALSE; /* Is playing buffer? */ ! 75: int OutputAudioFreqIndex = FREQ_22Khz; /* Playback rate (11Khz,22Khz or 44Khz) */ ! 76: float PlayVolume = 0.0f; ! 77: int SoundBufferSize = 1024; /* Size of sound buffer */ ! 78: int CompleteSndBufIdx; /* Replay-index into MixBuffer */ ! 79: ! 80: ! 81: ! 82: /*-----------------------------------------------------------------------*/ ! 83: /* ! 84: SDL audio callback function - copy emulation sound to audio system. ! 85: */ ! 86: void Audio_CallBack(void *userdata, Uint8 *pDestBuffer, int len) ! 87: { ! 88: Sint8 *pBuffer; ! 89: int i, j; ! 90: short sample; ! 91: BOOL playing = FALSE; ! 92: ! 93: pBuffer = pDestBuffer; ! 94: ! 95: for (i=0; i<MAX_CHANNELS; i++) { ! 96: if (wav_channels[i].buf != NULL) { ! 97: playing = TRUE; ! 98: break; ! 99: } ! 100: } ! 101: ! 102: if (!playing) { ! 103: memset (pDestBuffer, 0, len); ! 104: return; ! 105: } ! 106: ! 107: for (i = 0; i < len; i+=2) { ! 108: sample = 0; ! 109: for (j=0; j<MAX_CHANNELS; j++) { ! 110: if (wav_channels[j].buf == NULL) continue; ! 111: sample += *(short *)(wav_channels[j].buf + wav_channels[j].buf_pos); ! 112: wav_channels[j].buf_pos += 2; ! 113: if (wav_channels[j].buf_pos >= wav_channels[j].buf_len) { ! 114: /* end of sample. either loop or terminate */ ! 115: if (wav_channels[j].loop != -1) { ! 116: wav_channels[j].buf_pos = wav_channels[j].loop; ! 117: } else { ! 118: wav_channels[j].buf = NULL; ! 119: } ! 120: } ! 121: } ! 122: *((short*)pBuffer) = sample; ! 123: pBuffer += 2; ! 124: } ! 125: } ! 126: ! 127: /* ! 128: * Loaded samples must be SND_FREQ, 16-bit signed. Reject ! 129: * other frequencies but convert 8-bit unsigned. ! 130: */ ! 131: void check_sample_format (SDL_AudioSpec *spec, Uint8 **buf, int *len, const char *filename) ! 132: { ! 133: Uint8 *old_buf = *buf; ! 134: short *new_buf; ! 135: int i; ! 136: ! 137: if (spec->freq != SND_FREQ) { ! 138: printf ("Sample %s is the wrong sample rate (wanted %dHz). Ignoring.\n", filename, SND_FREQ); ! 139: SDL_FreeWAV (*buf); ! 140: *buf = NULL; ! 141: return; ! 142: } ! 143: ! 144: if (spec->format == AUDIO_U8) { ! 145: new_buf = malloc ((*len)*2); ! 146: for (i=0; i<(*len); i++) { ! 147: new_buf[i] = (old_buf[i] ^ 128) << 8; ! 148: } ! 149: *len *= 2; ! 150: SDL_FreeWAV (old_buf); ! 151: *buf = (char *)new_buf; ! 152: } else if (spec->format != AUDIO_S16) { ! 153: printf ("Sample %s is not 16-bit-signed or 8-bit unsigned. Ignoring.", filename); ! 154: SDL_FreeWAV (*buf); ! 155: *buf = NULL; ! 156: return; ! 157: } ! 158: } ! 159: ! 160: /*-----------------------------------------------------------------------*/ ! 161: /* ! 162: Initialize the audio subsystem. Return TRUE if all OK. ! 163: We use direct access to the sound buffer, set to a unsigned 8-bit mono stream. ! 164: */ ! 165: void Audio_Init(void) ! 166: { ! 167: int i; ! 168: char filename[32]; ! 169: SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */ ! 170: ! 171: /* Is enabled? */ ! 172: if(bDisableSound) ! 173: { ! 174: /* Stop any sound access */ ! 175: printf("Sound: Disabled\n"); ! 176: bSoundWorking = FALSE; ! 177: return; ! 178: } ! 179: ! 180: /* Init the SDL's audio subsystem: */ ! 181: if( SDL_WasInit(SDL_INIT_AUDIO)==0 ) ! 182: { ! 183: if( SDL_InitSubSystem(SDL_INIT_AUDIO)<0 ) ! 184: { ! 185: fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() ); ! 186: bSoundWorking = FALSE; ! 187: return; ! 188: } ! 189: } ! 190: ! 191: /* Set up SDL audio: */ ! 192: desiredAudioSpec.freq = SND_FREQ; ! 193: desiredAudioSpec.format = AUDIO_S16; /* 8 Bit unsigned */ ! 194: desiredAudioSpec.channels = 1; /* Mono */ ! 195: desiredAudioSpec.samples = 1024; /* Buffer size */ ! 196: desiredAudioSpec.callback = Audio_CallBack; ! 197: desiredAudioSpec.userdata = NULL; ! 198: ! 199: if( SDL_OpenAudio(&desiredAudioSpec, NULL) ) /* Open audio device */ ! 200: { ! 201: fprintf(stderr, "Can't use audio: %s\n", SDL_GetError()); ! 202: bSoundWorking = FALSE; ! 203: ConfigureParams.Sound.bEnableSound = FALSE; ! 204: return; ! 205: } ! 206: ! 207: SoundBufferSize = desiredAudioSpec.size; /* May be different than the requested one! */ ! 208: ! 209: for (i=0; i<MAX_SAMPLES; i++) { ! 210: snprintf (filename, sizeof (filename), "sfx/sfx_%02d.wav", i); ! 211: if (SDL_LoadWAV (filename, &desiredAudioSpec, &sfx_buf[i].buf, ! 212: &sfx_buf[i].buf_len) == NULL) { ! 213: printf ("Error loading %s: %s\n", filename, SDL_GetError ()); ! 214: sfx_buf[i].buf = NULL; ! 215: } ! 216: check_sample_format (&desiredAudioSpec, &sfx_buf[i].buf, &sfx_buf[i].buf_len, filename); ! 217: ! 218: /* 19 (hyperspace) and 23 (noise) loop */ ! 219: if (i == 19) sfx_buf[i].loop = SND_FREQ; /* loop to about 0.5 sec in */ ! 220: else if (i == 23) sfx_buf[i].loop = 0; ! 221: else sfx_buf[i].loop = -1; ! 222: } ! 223: ! 224: /* All OK */ ! 225: bSoundWorking = TRUE; ! 226: /* And begin */ ! 227: Audio_EnableAudio(TRUE); ! 228: } ! 229: ! 230: ! 231: /*-----------------------------------------------------------------------*/ ! 232: /* ! 233: Free audio subsystem ! 234: */ ! 235: void Audio_UnInit(void) ! 236: { ! 237: /* Stop */ ! 238: Audio_EnableAudio(FALSE); ! 239: ! 240: SDL_CloseAudio(); ! 241: } ! 242: ! 243: ! 244: /*-----------------------------------------------------------------------*/ ! 245: /* ! 246: Lock the audio sub system so that the callback function will not be called. ! 247: */ ! 248: void Audio_Lock(void) ! 249: { ! 250: SDL_LockAudio(); ! 251: } ! 252: ! 253: ! 254: /*-----------------------------------------------------------------------*/ ! 255: /* ! 256: Unlock the audio sub system so that the callback function will be called again. ! 257: */ ! 258: void Audio_Unlock(void) ! 259: { ! 260: SDL_UnlockAudio(); ! 261: } ! 262: ! 263: ! 264: /*-----------------------------------------------------------------------*/ ! 265: /* ! 266: Set audio playback frequency variable, pass as PLAYBACK_xxxx ! 267: */ ! 268: void Audio_SetOutputAudioFreq(int Frequency) ! 269: { ! 270: /* Do not reset sound system if nothing has changed! */ ! 271: if(Frequency != OutputAudioFreqIndex) ! 272: { ! 273: /* Set new frequency, index into SoundPlayBackFrequencies[] */ ! 274: OutputAudioFreqIndex = Frequency; ! 275: ! 276: /* Re-open SDL audio interface... */ ! 277: Audio_UnInit(); ! 278: Audio_Init(); ! 279: } ! 280: } ! 281: ! 282: ! 283: /*-----------------------------------------------------------------------*/ ! 284: /* ! 285: Start/Stop sound buffer ! 286: */ ! 287: void Audio_EnableAudio(BOOL bEnable) ! 288: { ! 289: if(bEnable && !bPlayingBuffer) ! 290: { ! 291: /* Start playing */ ! 292: SDL_PauseAudio(FALSE); ! 293: bPlayingBuffer = TRUE; ! 294: } ! 295: else if(!bEnable && bPlayingBuffer) ! 296: { ! 297: /* Stop from playing */ ! 298: SDL_PauseAudio(!bEnable); ! 299: bPlayingBuffer = bEnable; ! 300: } ! 301: } ! 302: ! 303: ! 304: /*-----------------------------------------------------------------------*/ ! 305: /* ! 306: Scale sample value (-128...127) according to 'PlayVolume' setting ! 307: */ ! 308: Sint16 Audio_ModifyVolume(Sint16 Sample) ! 309: { ! 310: /* If full volume, just use current value */ ! 311: if (PlayVolume==1.0f) ! 312: return(Sample); ! 313: ! 314: /* Else, scale volume */ ! 315: Sample = (Sint16)((float)Sample*PlayVolume); ! 316: ! 317: return(Sample); ! 318: } ! 319:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.