|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - audio.c
3:
1.1.1.19 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1.1.5 root 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:
1.1.1.18 root 21: #include "screen.h"
22: #include "video.h" /* FIXME: video.h is dependent on HBL_PALETTE_LINES from screen.h */
23:
1.1 root 24:
1.1.1.15 root 25: int nAudioFrequency = 44100; /* Sound playback frequency */
26: bool bSoundWorking = false; /* Is sound OK */
1.1.1.20 root 27: static volatile bool bPlayingBuffer = false; /* Is playing buffer? */
1.1.1.15 root 28: int SoundBufferSize = 1024 / 4; /* Size of sound buffer (in samples) */
29: int CompleteSndBufIdx; /* Replay-index into MixBuffer */
30: int SdlAudioBufferSize = 0; /* in ms (0 = use default) */
1.1.1.18 root 31: int pulse_swallowing_count = 0; /* Sound disciplined emulation rate controlled by */
32: /* window comparator and pulse swallowing counter */
1.1 root 33:
1.1.1.2 root 34: /*-----------------------------------------------------------------------*/
1.1.1.11 root 35: /**
36: * SDL audio callback function - copy emulation sound to audio system.
37: */
1.1.1.7 root 38: static void Audio_CallBack(void *userdata, Uint8 *stream, int len)
1.1.1.2 root 39: {
1.1.1.12 root 40: Sint16 *pBuffer;
1.1.1.18 root 41: int i, window, nSamplesPerFrame;
1.1.1.7 root 42:
1.1.1.12 root 43: pBuffer = (Sint16 *)stream;
44: len = len / 4; // Use length in samples (16 bit stereo), not in bytes
1.1.1.9 root 45:
1.1.1.18 root 46: /* Adjust emulation rate within +/- 0.58% (10 cents) occasionally,
47: * to synchronize sound. Note that an octave (frequency doubling)
48: * has 12 semitones (12th root of two for a semitone), and that
49: * one semitone has 100 cents (1200th root of two for one cent).
50: * Ten cents are desired, thus, the 120th root of two minus one is
51: * multiplied by 1,000,000 to convert to microseconds, and divided
52: * by nScreenRefreshRate=60 to get a 96 microseconds swallow size.
53: * (2^(10cents/(12semitones*100cents)) - 1) * 10^6 / nScreenRefreshRate
54: * See: main.c - Main_WaitOnVbl()
55: */
56:
57: pulse_swallowing_count = 0; /* 0 = Unaltered emulation rate */
58:
59: if (ConfigureParams.Sound.bEnableSoundSync)
60: {
61: /* Sound synchronized emulation */
62: nSamplesPerFrame = nAudioFrequency/nScreenRefreshRate;
63: window = (nSamplesPerFrame > SoundBufferSize) ? nSamplesPerFrame : SoundBufferSize;
64:
65: /* Window Comparator for SoundBufferSize */
66: if (nGeneratedSamples < window + (window >> 1))
67: /* Increase emulation rate to maintain sound synchronization */
68: pulse_swallowing_count = -5793 / nScreenRefreshRate;
69: else
70: if (nGeneratedSamples > (window << 1) + (window >> 2))
71: /* Decrease emulation rate to maintain sound synchronization */
72: pulse_swallowing_count = 5793 / nScreenRefreshRate;
73:
74: /* Otherwise emulation rate is unaltered. */
75: }
76:
1.1.1.9 root 77: if (nGeneratedSamples >= len)
78: {
1.1.1.10 root 79: /* Enough samples available: Pass completed buffer to audio system
80: * by write samples into sound buffer and by converting them from
81: * 'signed' to 'unsigned' */
82: for (i = 0; i < len; i++)
83: {
1.1.1.12 root 84: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
85: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10 root 86: }
1.1.1.9 root 87: CompleteSndBufIdx += len;
88: nGeneratedSamples -= len;
89: }
1.1.1.10 root 90: else /* Not enough samples available: */
1.1.1.9 root 91: {
1.1.1.10 root 92: for (i = 0; i < nGeneratedSamples; i++)
93: {
1.1.1.12 root 94: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
95: *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10 root 96: }
1.1.1.21 root 97: /* Clear rest of the buffer to ensure we don't play random bytes instead */
98: /* of missing samples */
99: memset(pBuffer, 0, (len - nGeneratedSamples) * 4);
100:
1.1.1.9 root 101: CompleteSndBufIdx += nGeneratedSamples;
102: nGeneratedSamples = 0;
1.1.1.10 root 103:
1.1.1.9 root 104: }
1.1.1.10 root 105:
1.1.1.9 root 106: CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE;
1.1.1.2 root 107: }
108:
1.1 root 109:
1.1.1.2 root 110: /*-----------------------------------------------------------------------*/
1.1.1.11 root 111: /**
1.1.1.14 root 112: * Initialize the audio subsystem. Return true if all OK.
1.1.1.11 root 113: * We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
114: */
1.1.1.2 root 115: void Audio_Init(void)
1.1 root 116: {
1.1.1.9 root 117: SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */
1.1.1.5 root 118:
1.1.1.9 root 119: /* Is enabled? */
120: if (!ConfigureParams.Sound.bEnableSound)
121: {
122: /* Stop any sound access */
123: Log_Printf(LOG_DEBUG, "Sound: Disabled\n");
1.1.1.14 root 124: bSoundWorking = false;
1.1.1.9 root 125: return;
126: }
127:
128: /* Init the SDL's audio subsystem: */
129: if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
130: {
131: if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
132: {
1.1.1.23! root 133: Log_Printf(LOG_WARN, "Could not init audio: %s\n", SDL_GetError() );
1.1.1.14 root 134: bSoundWorking = false;
1.1.1.9 root 135: return;
136: }
137: }
138:
139: /* Set up SDL audio: */
1.1.1.14 root 140: desiredAudioSpec.freq = nAudioFrequency;
1.1.1.15 root 141: desiredAudioSpec.format = AUDIO_S16SYS; /* 16-Bit signed */
142: desiredAudioSpec.channels = 2; /* stereo */
1.1.1.9 root 143: desiredAudioSpec.callback = Audio_CallBack;
144: desiredAudioSpec.userdata = NULL;
145:
1.1.1.15 root 146: /* In most case, setting samples to 1024 will give an equivalent */
147: /* sdl sound buffer of ~20-30 ms (depending on freq). */
148: /* But setting samples to 1024 for all the freq can cause some faulty */
149: /* OS sound drivers to add an important delay when playing sound at lower freq. */
150: /* In that case we use SdlAudioBufferSize (in ms) to compute a value */
151: /* of samples that matches the corresponding freq and buffer size. */
152: if ( SdlAudioBufferSize == 0 ) /* don't compute "samples", use default value */
153: desiredAudioSpec.samples = 1024; /* buffer size in samples */
154: else
155: {
156: int samples = (desiredAudioSpec.freq / 1000) * SdlAudioBufferSize;
157: int power2 = 1;
158: while ( power2 < samples ) /* compute the power of 2 just above samples */
1.1.1.21 root 159: power2 *= 2;
1.1.1.15 root 160:
161: desiredAudioSpec.samples = power2; /* number of samples corresponding to the requested SdlAudioBufferSize */
162: }
163:
164:
165: if (SDL_OpenAudio(&desiredAudioSpec, NULL)) /* Open audio device */
1.1.1.9 root 166: {
1.1.1.23! root 167: Log_Printf(LOG_WARN, "Can't use audio: %s\n", SDL_GetError());
1.1.1.14 root 168: bSoundWorking = false;
169: ConfigureParams.Sound.bEnableSound = false;
1.1.1.9 root 170: SDL_QuitSubSystem(SDL_INIT_AUDIO);
171: return;
172: }
173:
1.1.1.21 root 174: #if WITH_SDL2 /* SDL2 does not set desiredAudioSpec.size anymore */
175: SoundBufferSize = desiredAudioSpec.samples;
176: #else
1.1.1.15 root 177: SoundBufferSize = desiredAudioSpec.size; /* May be different than the requested one! */
178: SoundBufferSize /= 4; /* bytes -> samples (16 bit signed stereo -> 4 bytes per sample) */
1.1.1.21 root 179: #endif
1.1.1.9 root 180: if (SoundBufferSize > MIXBUFFER_SIZE/2)
181: {
1.1.1.23! root 182: Log_Printf(LOG_WARN, "Soundbuffer size is too big (%d > %d)!\n",
! 183: SoundBufferSize, MIXBUFFER_SIZE/2);
1.1.1.9 root 184: }
185:
186: /* All OK */
1.1.1.14 root 187: bSoundWorking = true;
1.1.1.9 root 188: /* And begin */
1.1.1.14 root 189: Audio_EnableAudio(true);
1.1 root 190: }
191:
1.1.1.2 root 192:
193: /*-----------------------------------------------------------------------*/
1.1.1.11 root 194: /**
195: * Free audio subsystem
196: */
1.1.1.2 root 197: void Audio_UnInit(void)
1.1 root 198: {
1.1.1.9 root 199: if (bSoundWorking)
200: {
201: /* Stop */
1.1.1.14 root 202: Audio_EnableAudio(false);
1.1.1.2 root 203:
1.1.1.9 root 204: SDL_CloseAudio();
1.1.1.7 root 205:
1.1.1.14 root 206: bSoundWorking = false;
1.1.1.9 root 207: }
1.1 root 208: }
209:
1.1.1.2 root 210:
211: /*-----------------------------------------------------------------------*/
1.1.1.11 root 212: /**
213: * Lock the audio sub system so that the callback function will not be called.
214: */
1.1.1.5 root 215: void Audio_Lock(void)
1.1 root 216: {
1.1.1.9 root 217: SDL_LockAudio();
1.1 root 218: }
219:
1.1.1.2 root 220:
221: /*-----------------------------------------------------------------------*/
1.1.1.11 root 222: /**
223: * Unlock the audio sub system so that the callback function will be called again.
224: */
1.1.1.5 root 225: void Audio_Unlock(void)
1.1 root 226: {
1.1.1.9 root 227: SDL_UnlockAudio();
1.1 root 228: }
229:
1.1.1.2 root 230:
231: /*-----------------------------------------------------------------------*/
1.1.1.11 root 232: /**
233: * Set audio playback frequency variable, pass as PLAYBACK_xxxx
234: */
1.1.1.14 root 235: void Audio_SetOutputAudioFreq(int nNewFrequency)
1.1 root 236: {
1.1.1.9 root 237: /* Do not reset sound system if nothing has changed! */
1.1.1.14 root 238: if (nNewFrequency != nAudioFrequency)
1.1.1.9 root 239: {
1.1.1.14 root 240: /* Set new frequency */
241: nAudioFrequency = nNewFrequency;
1.1.1.9 root 242:
1.1.1.21 root 243: if (Config_IsMachineFalcon())
1.1.1.17 root 244: {
1.1.1.16 root 245: /* Compute Ratio between host computer sound frequency and Hatari's sound frequency. */
246: Crossbar_Compute_Ratio();
247: }
1.1.1.21 root 248: else if (!Config_IsMachineST())
1.1.1.17 root 249: {
1.1.1.21 root 250: /* Adapt LMC filters to this new frequency */
1.1.1.16 root 251: DmaSnd_Init_Bass_and_Treble_Tables();
252: }
253:
1.1.1.9 root 254: /* Re-open SDL audio interface if necessary: */
255: if (bSoundWorking)
256: {
257: Audio_UnInit();
258: Audio_Init();
259: }
260: }
1.1.1.17 root 261:
1.1.1.22 root 262: /* Apply YM2149 C10 low pass filter ? (except if forced to NONE) */
263: if ( YM2149_LPF_Filter != YM2149_LPF_FILTER_NONE )
264: {
265: if ( Config_IsMachineST() && nAudioFrequency >= 40000 )
266: YM2149_LPF_Filter = YM2149_LPF_FILTER_LPF_STF;
267: else
268: YM2149_LPF_Filter = YM2149_LPF_FILTER_PWM;
269: }
1.1 root 270: }
271:
1.1.1.2 root 272:
273: /*-----------------------------------------------------------------------*/
1.1.1.11 root 274: /**
275: * Start/Stop sound buffer
276: */
1.1.1.12 root 277: void Audio_EnableAudio(bool bEnable)
1.1 root 278: {
1.1.1.9 root 279: if (bEnable && !bPlayingBuffer)
280: {
281: /* Start playing */
1.1.1.14 root 282: SDL_PauseAudio(false);
283: bPlayingBuffer = true;
1.1.1.9 root 284: }
285: else if (!bEnable && bPlayingBuffer)
286: {
287: /* Stop from playing */
1.1.1.14 root 288: SDL_PauseAudio(true);
289: bPlayingBuffer = false;
1.1.1.9 root 290: }
1.1 root 291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.