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