1 // SDL_Sound module
2 
3 #include <SDL.h>
4 #include "burner.h"
5 #include "aud_dsp.h"
6 #include <math.h>
7 
8 static unsigned int nSoundFps;
9 
10 extern int delay_ticks(int ticks);
11 
12 int nSDLVolume = SDL_MIX_MAXVOLUME;
13 int (*GetNextSound)(int);               // Callback used to request more sound
14 
15 static SDL_AudioSpec audiospec;
16 
17 static short* SDLAudBuffer;
18 static int nSDLPlayPos;
19 static int nSDLFillSeg;
20 static int nAudLoopLen;
21 
audiospec_callback(void *,Uint8 * stream,int len)22 void audiospec_callback(void* /* data */, Uint8* stream, int len)
23 {
24 #ifdef BUILD_SDL2
25 	SDL_memset(stream, 0, len);
26 #endif
27 	int end = nSDLPlayPos + len;
28 	if (end > nAudLoopLen)
29 	{
30 		SDL_MixAudio(stream, (Uint8*)SDLAudBuffer + nSDLPlayPos, nAudLoopLen - nSDLPlayPos, nSDLVolume);
31 		end -= nAudLoopLen;
32 		SDL_MixAudio(stream + nAudLoopLen - nSDLPlayPos, (Uint8*)SDLAudBuffer, end, nSDLVolume);
33 		nSDLPlayPos = end;
34 	}
35 	else
36 	{
37 		SDL_MixAudio(stream, (Uint8*)SDLAudBuffer + nSDLPlayPos, len, nSDLVolume);
38 		nSDLPlayPos = end;
39 
40 		if (nSDLPlayPos == nAudLoopLen)
41 		{
42 			nSDLPlayPos = 0;
43 		}
44 	}
45 }
46 
SDLSoundGetNextSoundFiller(int)47 static int SDLSoundGetNextSoundFiller(int)                          // int bDraw
48 {
49 	if (nAudNextSound == NULL)
50 	{
51 		return 1;
52 	}
53 	memset(nAudNextSound, 0, nAudSegLen << 2);                  // Write silence into the buffer
54 
55 	return 0;
56 }
57 
SDLSoundBlankSound()58 static int SDLSoundBlankSound()
59 {
60 	if (nAudNextSound)
61 	{
62 		memset(nAudNextSound, 0, nAudSegLen << 2);
63 	}
64 	return 0;
65 }
66 
67 #define WRAP_INC(x) { x++; if (x >= nAudSegCount) x = 0; }
68 
SDLSoundCheck()69 static int SDLSoundCheck()
70 {
71 	int nPlaySeg, nFollowingSeg;
72 
73 	if (!bAudPlaying)
74 		return 1;
75 
76 	// Since the SDL buffer is smaller than a segment, only fill the buffer up to the start of the currently playing segment
77 	nPlaySeg = nSDLPlayPos / (nAudSegLen << 2) - 1;
78 
79 	if (nPlaySeg >= nAudSegCount)
80 	{
81 		nPlaySeg -= nAudSegCount;
82 	}
83 	if (nPlaySeg < 0)
84 	{
85 		nPlaySeg = nAudSegCount - 1;
86 	}
87 
88 	if (nSDLFillSeg == nPlaySeg) {
89 		//	delay_ticks(1);
90 			return 0;
91 		}
92 
93 	// work out which seg we will fill next
94 	nFollowingSeg = nSDLFillSeg;
95 	WRAP_INC(nFollowingSeg);
96 
97 	while (nSDLFillSeg != nPlaySeg)
98 	{
99 		int bDraw;
100 
101 		bDraw = (nFollowingSeg == nPlaySeg);//	|| bAlwaysDrawFrames;	// If this is the last seg of sound, flag bDraw (to draw the graphics)
102 		GetNextSound(bDraw);                                // get more sound into nAudNextSound
103 
104 		if (nAudDSPModule[0])
105 		{
106 			DspDo(nAudNextSound, nAudSegLen);
107 		}
108 
109 		memcpy((char*)SDLAudBuffer + nSDLFillSeg * (nAudSegLen << 2), nAudNextSound, nAudSegLen << 2);
110 
111 		nSDLFillSeg = nFollowingSeg;
112 		WRAP_INC(nFollowingSeg);
113 	}
114 
115 	return 0;
116 }
117 
SDLSoundExit()118 static int SDLSoundExit()
119 {
120 	DspExit();
121 	SDL_CloseAudio();
122 
123 	free(SDLAudBuffer);
124 	SDLAudBuffer = NULL;
125 
126 	free(nAudNextSound);
127 	nAudNextSound = NULL;
128 
129 	return 0;
130 }
131 
SDLSetCallback(int (* pCallback)(int))132 static int SDLSetCallback(int (*pCallback)(int))
133 {
134 	if (pCallback == NULL)
135 	{
136 		GetNextSound = SDLSoundGetNextSoundFiller;
137 	}
138 	else
139 	{
140 		GetNextSound = pCallback;
141 	}
142 	return 0;
143 }
144 
SDLSoundInit()145 static int SDLSoundInit()
146 {
147 	SDL_AudioSpec audiospec_req;
148 	int nSDLBufferSize;
149 
150 	printf("SDLSoundInit (%dHz) (%dFPS)\n", nAudSampleRate[0], nAppVirtualFps);
151 
152 	if (nAudSampleRate[0] <= 0)
153 	{
154 		return 1;
155 	}
156 
157 	nSoundFps = nAppVirtualFps;
158 	nAudSegLen = (nAudSampleRate[0] * 100 + (nSoundFps >> 1)) / nSoundFps;
159 	nAudLoopLen = (nAudSegLen * nAudSegCount) << 2;
160 	for (nSDLBufferSize = 64; nSDLBufferSize < (nAudSegLen >> 1); nSDLBufferSize <<= 1)
161 	{
162 
163 	}
164 
165 	audiospec_req.freq = nAudSampleRate[0];
166 	audiospec_req.format = AUDIO_S16;
167 	audiospec_req.channels = 2;
168 	audiospec_req.samples = nSDLBufferSize;
169 	audiospec_req.callback = audiospec_callback;
170 
171 	SDLAudBuffer = (short*)malloc(nAudLoopLen);
172 	if (SDLAudBuffer == NULL)
173 	{
174 		printf("Couldn't malloc SDLAudBuffer\n");
175 		SDLSoundExit();
176 		return 1;
177 	}
178 	memset(SDLAudBuffer, 0, nAudLoopLen);
179 
180 	nAudNextSound = (short*)malloc(nAudSegLen << 2);
181 	if (nAudNextSound == NULL)
182 	{
183 		SDLSoundExit();
184 		return 1;
185 	}
186 
187 	nSDLPlayPos = 0;
188 	nSDLFillSeg = nAudSegCount - 1;
189 
190 	if (SDL_OpenAudio(&audiospec_req, &audiospec))
191 	{
192 		fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
193 		return 1;
194 	}
195 	DspInit();
196 	SDLSetCallback(NULL);
197 
198 	return 0;
199 }
200 
SDLSoundPlay()201 static int SDLSoundPlay()
202 {
203 	SDL_PauseAudio(0);
204 	bAudPlaying = 1;
205 
206 	return 0;
207 }
208 
SDLSoundStop()209 static int SDLSoundStop()
210 {
211 	SDL_PauseAudio(1);
212 	bAudPlaying = 0;
213 
214 	return 0;
215 }
216 
SDLSoundSetVolume()217 static int SDLSoundSetVolume()
218 {
219 	nSDLVolume = int(SDL_MIX_MAXVOLUME * nAudVolume / 10000);
220 	if (nSDLVolume > SDL_MIX_MAXVOLUME) nSDLVolume=SDL_MIX_MAXVOLUME;
221 	if (nSDLVolume < 0) nSDLVolume=0;
222 	return 1;
223 }
224 
SDLGetSettings(InterfaceInfo *)225 static int SDLGetSettings(InterfaceInfo* /* pInfo */)
226 {
227 	return 0;
228 }
229 
230 struct AudOut AudOutSDL = { SDLSoundBlankSound, SDLSoundCheck, SDLSoundInit, SDLSetCallback, SDLSoundPlay, SDLSoundStop, SDLSoundExit, SDLSoundSetVolume, SDLGetSettings, _T("SDL audio output") };
231