|
|
1.1 root 1: /*
1.1.1.5 root 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.
1.1 root 8: */
1.1.1.13 root 9: const char Audio_fileid[] = "Hatari audio.c : " __DATE__ " " __TIME__;
1.1 root 10:
1.1.1.2 root 11: #include <SDL.h>
12:
1.1 root 13: #include "main.h"
14: #include "audio.h"
1.1.1.6 root 15: #include "configuration.h"
1.1.1.9 root 16: #include "log.h"
1.1 root 17: #include "sound.h"
1.1.1.15! root 18: #include "dmaSnd.h"
1.1 root 19:
20:
1.1.1.15! root 21: int nAudioFrequency = 44100; /* Sound playback frequency */
! 22: bool bSoundWorking = false; /* Is sound OK */
! 23: volatile bool bPlayingBuffer = false; /* Is playing buffer? */
! 24: int SoundBufferSize = 1024 / 4; /* Size of sound buffer (in samples) */
! 25: int CompleteSndBufIdx; /* Replay-index into MixBuffer */
! 26: int SdlAudioBufferSize = 0; /* in ms (0 = use default) */
1.1 root 27:
28:
1.1.1.2 root 29: /*-----------------------------------------------------------------------*/
1.1.1.11 root 30: /**
31: * SDL audio callback function - copy emulation sound to audio system.
32: */
1.1.1.7 root 33: static void Audio_CallBack(void *userdata, Uint8 *stream, int len)
1.1.1.2 root 34: {
1.1.1.12 root 35: Sint16 *pBuffer;
1.1.1.9 root 36: int i;
1.1.1.7 root 37:
1.1.1.12 root 38: pBuffer = (Sint16 *)stream;
39: len = len / 4; // Use length in samples (16 bit stereo), not in bytes
1.1.1.9 root 40:
41: if (nGeneratedSamples >= len)
42: {
1.1.1.10 root 43: /* Enough samples available: Pass completed buffer to audio system
44: * by write samples into sound buffer and by converting them from
45: * 'signed' to 'unsigned' */
46: for (i = 0; i < len; i++)
47: {
1.1.1.12 root 48: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
49: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10 root 50: }
1.1.1.9 root 51: CompleteSndBufIdx += len;
52: nGeneratedSamples -= len;
53: }
1.1.1.10 root 54: else /* Not enough samples available: */
1.1.1.9 root 55: {
1.1.1.10 root 56: for (i = 0; i < nGeneratedSamples; i++)
57: {
1.1.1.12 root 58: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
59: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10 root 60: }
61: /* If the buffer is filled more than 50%, mirror sample buffer to fake the
62: * missing samples */
63: if (nGeneratedSamples >= len/2)
64: {
65: int remaining = len - nGeneratedSamples;
1.1.1.12 root 66: memcpy(pBuffer, stream+(nGeneratedSamples-remaining)*4, remaining*4);
1.1.1.10 root 67: }
1.1.1.9 root 68: CompleteSndBufIdx += nGeneratedSamples;
69: nGeneratedSamples = 0;
1.1.1.10 root 70:
1.1.1.9 root 71: }
1.1.1.10 root 72:
1.1.1.9 root 73: CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE;
1.1.1.2 root 74: }
75:
1.1 root 76:
1.1.1.2 root 77: /*-----------------------------------------------------------------------*/
1.1.1.11 root 78: /**
1.1.1.14 root 79: * Initialize the audio subsystem. Return true if all OK.
1.1.1.11 root 80: * We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
81: */
1.1.1.2 root 82: void Audio_Init(void)
1.1 root 83: {
1.1.1.9 root 84: SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */
1.1.1.5 root 85:
1.1.1.9 root 86: /* Is enabled? */
87: if (!ConfigureParams.Sound.bEnableSound)
88: {
89: /* Stop any sound access */
90: Log_Printf(LOG_DEBUG, "Sound: Disabled\n");
1.1.1.14 root 91: bSoundWorking = false;
1.1.1.9 root 92: return;
93: }
94:
95: /* Init the SDL's audio subsystem: */
96: if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
97: {
98: if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
99: {
100: fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() );
1.1.1.14 root 101: bSoundWorking = false;
1.1.1.9 root 102: return;
103: }
104: }
105:
106: /* Set up SDL audio: */
1.1.1.14 root 107: desiredAudioSpec.freq = nAudioFrequency;
1.1.1.15! root 108: desiredAudioSpec.format = AUDIO_S16SYS; /* 16-Bit signed */
! 109: desiredAudioSpec.channels = 2; /* stereo */
1.1.1.9 root 110: desiredAudioSpec.callback = Audio_CallBack;
111: desiredAudioSpec.userdata = NULL;
112:
1.1.1.15! root 113: /* In most case, setting samples to 1024 will give an equivalent */
! 114: /* sdl sound buffer of ~20-30 ms (depending on freq). */
! 115: /* But setting samples to 1024 for all the freq can cause some faulty */
! 116: /* OS sound drivers to add an important delay when playing sound at lower freq. */
! 117: /* In that case we use SdlAudioBufferSize (in ms) to compute a value */
! 118: /* of samples that matches the corresponding freq and buffer size. */
! 119: if ( SdlAudioBufferSize == 0 ) /* don't compute "samples", use default value */
! 120: desiredAudioSpec.samples = 1024; /* buffer size in samples */
! 121: else
! 122: {
! 123: int samples = (desiredAudioSpec.freq / 1000) * SdlAudioBufferSize;
! 124: int power2 = 1;
! 125: while ( power2 < samples ) /* compute the power of 2 just above samples */
! 126: power2 *= 2;
! 127:
! 128: //fprintf ( stderr , "samples %d power %d\n" , samples , power2 );
! 129: desiredAudioSpec.samples = power2; /* number of samples corresponding to the requested SdlAudioBufferSize */
! 130: }
! 131:
! 132:
! 133: if (SDL_OpenAudio(&desiredAudioSpec, NULL)) /* Open audio device */
1.1.1.9 root 134: {
135: fprintf(stderr, "Can't use audio: %s\n", SDL_GetError());
1.1.1.14 root 136: bSoundWorking = false;
137: ConfigureParams.Sound.bEnableSound = false;
1.1.1.9 root 138: SDL_QuitSubSystem(SDL_INIT_AUDIO);
139: return;
140: }
141:
1.1.1.15! root 142: SoundBufferSize = desiredAudioSpec.size; /* May be different than the requested one! */
! 143: SoundBufferSize /= 4; /* bytes -> samples (16 bit signed stereo -> 4 bytes per sample) */
1.1.1.9 root 144: if (SoundBufferSize > MIXBUFFER_SIZE/2)
145: {
146: fprintf(stderr, "Warning: Soundbuffer size is too big!\n");
147: }
148:
149: /* All OK */
1.1.1.14 root 150: bSoundWorking = true;
1.1.1.9 root 151: /* And begin */
1.1.1.14 root 152: Audio_EnableAudio(true);
1.1 root 153: }
154:
1.1.1.2 root 155:
156: /*-----------------------------------------------------------------------*/
1.1.1.11 root 157: /**
158: * Free audio subsystem
159: */
1.1.1.2 root 160: void Audio_UnInit(void)
1.1 root 161: {
1.1.1.9 root 162: if (bSoundWorking)
163: {
164: /* Stop */
1.1.1.14 root 165: Audio_EnableAudio(false);
1.1.1.2 root 166:
1.1.1.9 root 167: SDL_CloseAudio();
1.1.1.7 root 168:
1.1.1.14 root 169: bSoundWorking = false;
1.1.1.9 root 170: }
1.1 root 171: }
172:
1.1.1.2 root 173:
174: /*-----------------------------------------------------------------------*/
1.1.1.11 root 175: /**
176: * Lock the audio sub system so that the callback function will not be called.
177: */
1.1.1.5 root 178: void Audio_Lock(void)
1.1 root 179: {
1.1.1.9 root 180: SDL_LockAudio();
1.1 root 181: }
182:
1.1.1.2 root 183:
184: /*-----------------------------------------------------------------------*/
1.1.1.11 root 185: /**
186: * Unlock the audio sub system so that the callback function will be called again.
187: */
1.1.1.5 root 188: void Audio_Unlock(void)
1.1 root 189: {
1.1.1.9 root 190: SDL_UnlockAudio();
1.1 root 191: }
192:
1.1.1.2 root 193:
194: /*-----------------------------------------------------------------------*/
1.1.1.11 root 195: /**
196: * Set audio playback frequency variable, pass as PLAYBACK_xxxx
197: */
1.1.1.14 root 198: void Audio_SetOutputAudioFreq(int nNewFrequency)
1.1 root 199: {
1.1.1.9 root 200: /* Do not reset sound system if nothing has changed! */
1.1.1.14 root 201: if (nNewFrequency != nAudioFrequency)
1.1.1.9 root 202: {
1.1.1.14 root 203: /* Set new frequency */
204: nAudioFrequency = nNewFrequency;
1.1.1.9 root 205:
206: /* Re-open SDL audio interface if necessary: */
207: if (bSoundWorking)
208: {
209: Audio_UnInit();
210: Audio_Init();
1.1.1.15! root 211: DmaSnd_Init_Bass_and_Treble_Tables();
1.1.1.9 root 212: }
213: }
1.1 root 214: }
215:
1.1.1.2 root 216:
217: /*-----------------------------------------------------------------------*/
1.1.1.11 root 218: /**
219: * Start/Stop sound buffer
220: */
1.1.1.12 root 221: void Audio_EnableAudio(bool bEnable)
1.1 root 222: {
1.1.1.9 root 223: if (bEnable && !bPlayingBuffer)
224: {
225: /* Start playing */
1.1.1.14 root 226: SDL_PauseAudio(false);
227: bPlayingBuffer = true;
1.1.1.9 root 228: }
229: else if (!bEnable && bPlayingBuffer)
230: {
231: /* Stop from playing */
1.1.1.14 root 232: SDL_PauseAudio(true);
233: bPlayingBuffer = false;
1.1.1.9 root 234: }
1.1 root 235: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.