1 /*
2   Hatari - audio.c
3 
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.
6 
7   This file contains the routines which pass the audio data to the SDL library.
8 */
9 const char Audio_fileid[] = "Hatari audio.c : " __DATE__ " " __TIME__;
10 
11 #include <SDL.h>
12 
13 #include "main.h"
14 #include "audio.h"
15 #include "configuration.h"
16 #include "log.h"
17 #include "sound.h"
18 #include "dmaSnd.h"
19 #include "falcon/crossbar.h"
20 
21 #include "screen.h"
22 #include "video.h"	/* FIXME: video.h is dependent on HBL_PALETTE_LINES from screen.h */
23 
24 
25 int nAudioFrequency = 44100;			/* Sound playback frequency */
26 bool bSoundWorking = false;			/* Is sound OK */
27 static volatile bool bPlayingBuffer = false;	/* Is playing buffer? */
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) */
31 int pulse_swallowing_count = 0;			/* Sound disciplined emulation rate controlled by  */
32 						/*  window comparator and pulse swallowing counter */
33 
34 /*-----------------------------------------------------------------------*/
35 /**
36  * SDL audio callback function - copy emulation sound to audio system.
37  */
Audio_CallBack(void * userdata,Uint8 * stream,int len)38 static void Audio_CallBack(void *userdata, Uint8 *stream, int len)
39 {
40 	Sint16 *pBuffer;
41 	int i, window, nSamplesPerFrame;
42 
43 	pBuffer = (Sint16 *)stream;
44 	len = len / 4;  // Use length in samples (16 bit stereo), not in bytes
45 
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 
77 	if (nGeneratedSamples >= len)
78 	{
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 		{
84 			*pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
85 			*pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
86 		}
87 		CompleteSndBufIdx += len;
88 		nGeneratedSamples -= len;
89 	}
90 	else  /* Not enough samples available: */
91 	{
92 		for (i = 0; i < nGeneratedSamples; i++)
93 		{
94 			*pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
95 			*pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
96 		}
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 
101 		CompleteSndBufIdx += nGeneratedSamples;
102 		nGeneratedSamples = 0;
103 
104 	}
105 
106 	CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE;
107 }
108 
109 
110 /*-----------------------------------------------------------------------*/
111 /**
112  * Initialize the audio subsystem. Return true if all OK.
113  * We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
114  */
Audio_Init(void)115 void Audio_Init(void)
116 {
117 	SDL_AudioSpec desiredAudioSpec;    /* We fill in the desired SDL audio options here */
118 
119 	/* Is enabled? */
120 	if (!ConfigureParams.Sound.bEnableSound)
121 	{
122 		/* Stop any sound access */
123 		Log_Printf(LOG_DEBUG, "Sound: Disabled\n");
124 		bSoundWorking = false;
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 		{
133 			Log_Printf(LOG_WARN, "Could not init audio: %s\n", SDL_GetError() );
134 			bSoundWorking = false;
135 			return;
136 		}
137 	}
138 
139 	/* Set up SDL audio: */
140 	desiredAudioSpec.freq = nAudioFrequency;
141 	desiredAudioSpec.format = AUDIO_S16SYS;		/* 16-Bit signed */
142 	desiredAudioSpec.channels = 2;			/* stereo */
143 	desiredAudioSpec.callback = Audio_CallBack;
144 	desiredAudioSpec.userdata = NULL;
145 
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 */
159 			power2 *= 2;
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 */
166 	{
167 		Log_Printf(LOG_WARN, "Can't use audio: %s\n", SDL_GetError());
168 		bSoundWorking = false;
169 		ConfigureParams.Sound.bEnableSound = false;
170 		SDL_QuitSubSystem(SDL_INIT_AUDIO);
171 		return;
172 	}
173 
174 #if WITH_SDL2						/* SDL2 does not set desiredAudioSpec.size anymore */
175 	SoundBufferSize = desiredAudioSpec.samples;
176 #else
177 	SoundBufferSize = desiredAudioSpec.size;	/* May be different than the requested one! */
178 	SoundBufferSize /= 4;				/* bytes -> samples (16 bit signed stereo -> 4 bytes per sample) */
179 #endif
180 	if (SoundBufferSize > MIXBUFFER_SIZE/2)
181 	{
182 		Log_Printf(LOG_WARN, "Soundbuffer size is too big (%d > %d)!\n",
183 			   SoundBufferSize, MIXBUFFER_SIZE/2);
184 	}
185 
186 	/* All OK */
187 	bSoundWorking = true;
188 	/* And begin */
189 	Audio_EnableAudio(true);
190 }
191 
192 
193 /*-----------------------------------------------------------------------*/
194 /**
195  * Free audio subsystem
196  */
Audio_UnInit(void)197 void Audio_UnInit(void)
198 {
199 	if (bSoundWorking)
200 	{
201 		/* Stop */
202 		Audio_EnableAudio(false);
203 
204 		SDL_CloseAudio();
205 
206 		bSoundWorking = false;
207 	}
208 }
209 
210 
211 /*-----------------------------------------------------------------------*/
212 /**
213  * Lock the audio sub system so that the callback function will not be called.
214  */
Audio_Lock(void)215 void Audio_Lock(void)
216 {
217 	SDL_LockAudio();
218 }
219 
220 
221 /*-----------------------------------------------------------------------*/
222 /**
223  * Unlock the audio sub system so that the callback function will be called again.
224  */
Audio_Unlock(void)225 void Audio_Unlock(void)
226 {
227 	SDL_UnlockAudio();
228 }
229 
230 
231 /*-----------------------------------------------------------------------*/
232 /**
233  * Set audio playback frequency variable, pass as PLAYBACK_xxxx
234  */
Audio_SetOutputAudioFreq(int nNewFrequency)235 void Audio_SetOutputAudioFreq(int nNewFrequency)
236 {
237 	/* Do not reset sound system if nothing has changed! */
238 	if (nNewFrequency != nAudioFrequency)
239 	{
240 		/* Set new frequency */
241 		nAudioFrequency = nNewFrequency;
242 
243 		if (Config_IsMachineFalcon())
244 		{
245 			/* Compute Ratio between host computer sound frequency and Hatari's sound frequency. */
246 			Crossbar_Compute_Ratio();
247 		}
248 		else if (!Config_IsMachineST())
249 		{
250 			/* Adapt LMC filters to this new frequency */
251 			DmaSnd_Init_Bass_and_Treble_Tables();
252 		}
253 
254 		/* Re-open SDL audio interface if necessary: */
255 		if (bSoundWorking)
256 		{
257 			Audio_UnInit();
258 			Audio_Init();
259 		}
260 	}
261 
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 	}
270 }
271 
272 
273 /*-----------------------------------------------------------------------*/
274 /**
275  * Start/Stop sound buffer
276  */
Audio_EnableAudio(bool bEnable)277 void Audio_EnableAudio(bool bEnable)
278 {
279 	if (bEnable && !bPlayingBuffer)
280 	{
281 		/* Start playing */
282 		SDL_PauseAudio(false);
283 		bPlayingBuffer = true;
284 	}
285 	else if (!bEnable && bPlayingBuffer)
286 	{
287 		/* Stop from playing */
288 		SDL_PauseAudio(true);
289 		bPlayingBuffer = false;
290 	}
291 }
292