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