diff options
Diffstat (limited to 'apps/plugins/sdl/src/audio/mint/SDL_mintaudio_mcsn.c')
-rw-r--r-- | apps/plugins/sdl/src/audio/mint/SDL_mintaudio_mcsn.c | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/audio/mint/SDL_mintaudio_mcsn.c b/apps/plugins/sdl/src/audio/mint/SDL_mintaudio_mcsn.c new file mode 100644 index 0000000000..387609b168 --- /dev/null +++ b/apps/plugins/sdl/src/audio/mint/SDL_mintaudio_mcsn.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* | ||
25 | MiNT audio driver | ||
26 | using XBIOS functions (MacSound compatible driver) | ||
27 | |||
28 | Patrice Mandin | ||
29 | */ | ||
30 | |||
31 | #include <support.h> | ||
32 | |||
33 | /* Mint includes */ | ||
34 | #include <mint/osbind.h> | ||
35 | #include <mint/falcon.h> | ||
36 | #include <mint/cookie.h> | ||
37 | |||
38 | #include "SDL_audio.h" | ||
39 | #include "../SDL_audio_c.h" | ||
40 | #include "../SDL_sysaudio.h" | ||
41 | |||
42 | #include "../../video/ataricommon/SDL_atarimxalloc_c.h" | ||
43 | |||
44 | #include "SDL_mintaudio.h" | ||
45 | #include "SDL_mintaudio_mcsn.h" | ||
46 | |||
47 | /*--- Defines ---*/ | ||
48 | |||
49 | #define MINT_AUDIO_DRIVER_NAME "mint_mcsn" | ||
50 | |||
51 | /* Debug print info */ | ||
52 | #define DEBUG_NAME "audio:mcsn: " | ||
53 | #if 0 | ||
54 | #define DEBUG_PRINT(what) \ | ||
55 | { \ | ||
56 | printf what; \ | ||
57 | } | ||
58 | #else | ||
59 | #define DEBUG_PRINT(what) | ||
60 | #endif | ||
61 | |||
62 | /*--- Static variables ---*/ | ||
63 | |||
64 | static long cookie_snd, cookie_mch; | ||
65 | static cookie_mcsn_t *cookie_mcsn; | ||
66 | |||
67 | /*--- Audio driver functions ---*/ | ||
68 | |||
69 | static void Mint_CloseAudio(_THIS); | ||
70 | static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec); | ||
71 | static void Mint_LockAudio(_THIS); | ||
72 | static void Mint_UnlockAudio(_THIS); | ||
73 | |||
74 | /* To check/init hardware audio */ | ||
75 | static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec); | ||
76 | static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec); | ||
77 | |||
78 | /*--- Audio driver bootstrap functions ---*/ | ||
79 | |||
80 | static int Audio_Available(void) | ||
81 | { | ||
82 | long dummy; | ||
83 | const char *envr = SDL_getenv("SDL_AUDIODRIVER"); | ||
84 | |||
85 | SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND); | ||
86 | |||
87 | /* We can't use XBIOS in interrupt with Magic, don't know about thread */ | ||
88 | if (Getcookie(C_MagX, &dummy) == C_FOUND) { | ||
89 | return(0); | ||
90 | } | ||
91 | |||
92 | /* Check if user asked a different audio driver */ | ||
93 | if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) { | ||
94 | DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n")); | ||
95 | return(0); | ||
96 | } | ||
97 | |||
98 | /* Cookie _MCH present ? if not, assume ST machine */ | ||
99 | if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) { | ||
100 | cookie_mch = MCH_ST; | ||
101 | } | ||
102 | |||
103 | /* Cookie _SND present ? if not, assume ST machine */ | ||
104 | if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) { | ||
105 | cookie_snd = SND_PSG; | ||
106 | } | ||
107 | |||
108 | /* Check if we have 16 bits audio */ | ||
109 | if ((cookie_snd & SND_16BIT)==0) { | ||
110 | DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n")); | ||
111 | return(0); | ||
112 | } | ||
113 | |||
114 | /* Cookie MCSN present ? */ | ||
115 | if (Getcookie(C_McSn, &dummy) != C_FOUND) { | ||
116 | DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n")); | ||
117 | return(0); | ||
118 | } | ||
119 | cookie_mcsn = (cookie_mcsn_t *) dummy; | ||
120 | |||
121 | /* Check if interrupt at end of replay */ | ||
122 | if (cookie_mcsn->pint == 0) { | ||
123 | DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n")); | ||
124 | return(0); | ||
125 | } | ||
126 | |||
127 | /* Check if audio is lockable */ | ||
128 | if (Locksnd()!=1) { | ||
129 | DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n")); | ||
130 | return(0); | ||
131 | } | ||
132 | |||
133 | Unlocksnd(); | ||
134 | |||
135 | DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n")); | ||
136 | return(1); | ||
137 | } | ||
138 | |||
139 | static void Audio_DeleteDevice(SDL_AudioDevice *device) | ||
140 | { | ||
141 | SDL_free(device->hidden); | ||
142 | SDL_free(device); | ||
143 | } | ||
144 | |||
145 | static SDL_AudioDevice *Audio_CreateDevice(int devindex) | ||
146 | { | ||
147 | SDL_AudioDevice *this; | ||
148 | |||
149 | /* Initialize all variables that we clean on shutdown */ | ||
150 | this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); | ||
151 | if ( this ) { | ||
152 | SDL_memset(this, 0, (sizeof *this)); | ||
153 | this->hidden = (struct SDL_PrivateAudioData *) | ||
154 | SDL_malloc((sizeof *this->hidden)); | ||
155 | } | ||
156 | if ( (this == NULL) || (this->hidden == NULL) ) { | ||
157 | SDL_OutOfMemory(); | ||
158 | if ( this ) { | ||
159 | SDL_free(this); | ||
160 | } | ||
161 | return(0); | ||
162 | } | ||
163 | SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | ||
164 | |||
165 | /* Set the function pointers */ | ||
166 | this->OpenAudio = Mint_OpenAudio; | ||
167 | this->CloseAudio = Mint_CloseAudio; | ||
168 | this->LockAudio = Mint_LockAudio; | ||
169 | this->UnlockAudio = Mint_UnlockAudio; | ||
170 | this->free = Audio_DeleteDevice; | ||
171 | |||
172 | return this; | ||
173 | } | ||
174 | |||
175 | AudioBootStrap MINTAUDIO_MCSN_bootstrap = { | ||
176 | MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver", | ||
177 | Audio_Available, Audio_CreateDevice | ||
178 | }; | ||
179 | |||
180 | static void Mint_LockAudio(_THIS) | ||
181 | { | ||
182 | /* Stop replay */ | ||
183 | Buffoper(0); | ||
184 | } | ||
185 | |||
186 | static void Mint_UnlockAudio(_THIS) | ||
187 | { | ||
188 | /* Restart replay */ | ||
189 | Buffoper(SB_PLA_ENA|SB_PLA_RPT); | ||
190 | } | ||
191 | |||
192 | static void Mint_CloseAudio(_THIS) | ||
193 | { | ||
194 | /* Stop replay */ | ||
195 | SDL_MintAudio_WaitThread(); | ||
196 | Buffoper(0); | ||
197 | |||
198 | if (!SDL_MintAudio_mint_present) { | ||
199 | /* Uninstall interrupt */ | ||
200 | Jdisint(MFP_DMASOUND); | ||
201 | } | ||
202 | |||
203 | /* Wait if currently playing sound */ | ||
204 | while (SDL_MintAudio_mutex != 0) { | ||
205 | } | ||
206 | |||
207 | /* Clear buffers */ | ||
208 | if (SDL_MintAudio_audiobuf[0]) { | ||
209 | Mfree(SDL_MintAudio_audiobuf[0]); | ||
210 | SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; | ||
211 | } | ||
212 | |||
213 | /* Unlock sound system */ | ||
214 | Unlocksnd(); | ||
215 | } | ||
216 | |||
217 | static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec) | ||
218 | { | ||
219 | int i; | ||
220 | unsigned long masterclock, masterprediv; | ||
221 | |||
222 | DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff)); | ||
223 | DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); | ||
224 | DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); | ||
225 | DEBUG_PRINT(("channels=%d, ", spec->channels)); | ||
226 | DEBUG_PRINT(("freq=%d\n", spec->freq)); | ||
227 | |||
228 | if (spec->channels > 2) { | ||
229 | spec->channels = 2; /* no more than stereo! */ | ||
230 | } | ||
231 | |||
232 | /* Check formats available */ | ||
233 | MINTAUDIO_freqcount=0; | ||
234 | switch(cookie_mcsn->play) { | ||
235 | case MCSN_ST: | ||
236 | spec->channels=1; | ||
237 | spec->format=8; /* FIXME: is it signed or unsigned ? */ | ||
238 | SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1); | ||
239 | break; | ||
240 | case MCSN_TT: /* Also STE, Mega STE */ | ||
241 | spec->format=AUDIO_S8; | ||
242 | masterclock=MASTERCLOCK_STE; | ||
243 | masterprediv=MASTERPREDIV_STE; | ||
244 | if ((cookie_mch>>16)==MCH_TT) { | ||
245 | masterclock=MASTERCLOCK_TT; | ||
246 | masterprediv=MASTERPREDIV_TT; | ||
247 | } | ||
248 | for (i=0; i<4; i++) { | ||
249 | SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), | ||
250 | masterclock, 3-i, -1); | ||
251 | } | ||
252 | break; | ||
253 | case MCSN_FALCON: /* Also Mac */ | ||
254 | for (i=1; i<12; i++) { | ||
255 | /* Remove unusable Falcon codec predivisors */ | ||
256 | if ((i==6) || (i==8) || (i==10)) { | ||
257 | continue; | ||
258 | } | ||
259 | SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), | ||
260 | CLK25M, i+1, -1); | ||
261 | } | ||
262 | if (cookie_mcsn->res1 != 0) { | ||
263 | for (i=1; i<4; i++) { | ||
264 | SDL_MintAudio_AddFrequency(this, (cookie_mcsn->res1)/(MASTERPREDIV_FALCON*(1<<i)), | ||
265 | CLKEXT, (1<<i)-1, -1); | ||
266 | } | ||
267 | } | ||
268 | spec->format |= 0x8000; /* Audio is always signed */ | ||
269 | if ((spec->format & 0x00ff)==16) { | ||
270 | spec->format |= 0x1000; /* Audio is always big endian */ | ||
271 | spec->channels=2; /* 16 bits always stereo */ | ||
272 | } | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | #if 0 | ||
277 | for (i=0; i<MINTAUDIO_freqcount; i++) { | ||
278 | DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n", | ||
279 | i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock, | ||
280 | MINTAUDIO_frequencies[i].predivisor | ||
281 | )); | ||
282 | } | ||
283 | #endif | ||
284 | |||
285 | MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq); | ||
286 | spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; | ||
287 | |||
288 | DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff)); | ||
289 | DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); | ||
290 | DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); | ||
291 | DEBUG_PRINT(("channels=%d, ", spec->channels)); | ||
292 | DEBUG_PRINT(("freq=%d\n", spec->freq)); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec) | ||
298 | { | ||
299 | int channels_mode, prediv, dmaclock; | ||
300 | void *buffer; | ||
301 | |||
302 | /* Stop currently playing sound */ | ||
303 | SDL_MintAudio_quit_thread = SDL_FALSE; | ||
304 | SDL_MintAudio_thread_finished = SDL_TRUE; | ||
305 | SDL_MintAudio_WaitThread(); | ||
306 | Buffoper(0); | ||
307 | |||
308 | /* Set replay tracks */ | ||
309 | Settracks(0,0); | ||
310 | Setmontracks(0); | ||
311 | |||
312 | /* Select replay format */ | ||
313 | channels_mode=STEREO16; | ||
314 | switch (spec->format & 0xff) { | ||
315 | case 8: | ||
316 | if (spec->channels==2) { | ||
317 | channels_mode=STEREO8; | ||
318 | } else { | ||
319 | channels_mode=MONO8; | ||
320 | } | ||
321 | break; | ||
322 | } | ||
323 | if (Setmode(channels_mode)<0) { | ||
324 | DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n")); | ||
325 | } | ||
326 | |||
327 | dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock; | ||
328 | prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; | ||
329 | switch(cookie_mcsn->play) { | ||
330 | case MCSN_TT: | ||
331 | Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, 1); | ||
332 | Soundcmd(SETPRESCALE, prediv); | ||
333 | DEBUG_PRINT((DEBUG_NAME "STE/TT prescaler selected\n")); | ||
334 | break; | ||
335 | case MCSN_FALCON: | ||
336 | Devconnect(DMAPLAY, DAC, dmaclock, prediv, 1); | ||
337 | DEBUG_PRINT((DEBUG_NAME "Falcon prescaler selected\n")); | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | /* Set buffer */ | ||
342 | buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; | ||
343 | if (Setbuffer(0, buffer, buffer + spec->size)<0) { | ||
344 | DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n")); | ||
345 | } | ||
346 | |||
347 | if (SDL_MintAudio_mint_present) { | ||
348 | SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0); | ||
349 | } else { | ||
350 | /* Install interrupt */ | ||
351 | Jdisint(MFP_DMASOUND); | ||
352 | Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt); | ||
353 | Jenabint(MFP_DMASOUND); | ||
354 | |||
355 | if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) { | ||
356 | DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n")); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | /* Go */ | ||
361 | Buffoper(SB_PLA_ENA|SB_PLA_RPT); | ||
362 | DEBUG_PRINT((DEBUG_NAME "hardware initialized\n")); | ||
363 | } | ||
364 | |||
365 | static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) | ||
366 | { | ||
367 | /* Lock sound system */ | ||
368 | if (Locksnd()!=1) { | ||
369 | SDL_SetError("Mint_OpenAudio: Audio system already in use"); | ||
370 | return(-1); | ||
371 | } | ||
372 | |||
373 | SDL_MintAudio_device = this; | ||
374 | |||
375 | /* Check audio capabilities */ | ||
376 | if (Mint_CheckAudio(this, spec)==-1) { | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | SDL_CalculateAudioSpec(spec); | ||
381 | |||
382 | /* Allocate memory for audio buffers in DMA-able RAM */ | ||
383 | DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size)); | ||
384 | |||
385 | SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM); | ||
386 | if (SDL_MintAudio_audiobuf[0]==NULL) { | ||
387 | SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); | ||
388 | return (-1); | ||
389 | } | ||
390 | SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ; | ||
391 | SDL_MintAudio_numbuf=0; | ||
392 | SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2); | ||
393 | SDL_MintAudio_audiosize = spec->size; | ||
394 | SDL_MintAudio_mutex = 0; | ||
395 | |||
396 | DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0])); | ||
397 | DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1])); | ||
398 | |||
399 | SDL_MintAudio_CheckFpu(); | ||
400 | |||
401 | /* Setup audio hardware */ | ||
402 | Mint_InitAudio(this, spec); | ||
403 | |||
404 | return(1); /* We don't use SDL threaded audio */ | ||
405 | } | ||