comparison src/audio/mint/SDL_mintaudio.c @ 398:d219b0e02f5f

Added Atari audio support (thanks Patrice!)
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jun 2002 20:42:53 +0000
parents
children 0ce5a68278fd
comparison
equal deleted inserted replaced
397:283d348cb624 398:d219b0e02f5f
1 /*
2 * MiNT audio driver
3 *
4 * Patrice Mandin
5 */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 /* Mint includes */
12 #include <mint/osbind.h>
13 #include <mint/falcon.h>
14 #include <sys/cookie.h>
15
16 #include "SDL_endian.h"
17 #include "SDL_audio.h"
18 #include "SDL_audio_c.h"
19 #include "SDL_audiomem.h"
20 #include "SDL_sysaudio.h"
21
22 #include "SDL_mintaudio.h"
23 #include "SDL_mintaudiodma.h"
24 #include "SDL_mintaudiogsxb.h"
25 #include "SDL_mintaudiointerrupt_s.h"
26
27 #include "SDL_atarimxalloc_c.h"
28
29 /*--- Defines ---*/
30
31 #define MINT_AUDIO_DRIVER_NAME "mint"
32
33 /* Master clocks for replay frequencies */
34 #define MASTERCLOCK_STE 8010666 /* Not sure of this one */
35 #define MASTERCLOCK_TT 16107953 /* Not sure of this one */
36 #define MASTERCLOCK_FALCON1 25175000
37 #define MASTERCLOCK_FALCON2 32000000 /* Only usable for DSP56K */
38 #define MASTERCLOCK_FALCONEXT -1 /* Clock on DSP56K port, unknown */
39 #define MASTERCLOCK_MILAN1 22579200 /* Standard clock for 44.1 Khz */
40 #define MASTERCLOCK_MILAN2 24576000 /* Standard clock for 48 Khz */
41
42 /* Master clock predivisors */
43 #define MASTERPREDIV_STE 160
44 #define MASTERPREDIV_TT 320
45 #define MASTERPREDIV_FALCON 256
46 #define MASTERPREDIV_MILAN 256
47
48 /* Values>>16 in _MCH cookie */
49 enum {
50 MCH_ST=0,
51 MCH_STE,
52 MCH_TT,
53 MCH_F30
54 };
55
56 /* MFP 68901 interrupt sources */
57 enum {
58 MFP_PARALLEL=0,
59 MFP_DCD,
60 MFP_CTS,
61 MFP_BITBLT,
62 MFP_TIMERD,
63 MFP_BAUDRATE=MFP_TIMERD,
64 MFP_TIMERC,
65 MFP_200HZ=MFP_TIMERC,
66 MFP_ACIA,
67 MFP_DISK,
68 MFP_TIMERB,
69 MFP_HBLANK=MFP_TIMERB,
70 MFP_TERR,
71 MFP_TBE,
72 MFP_RERR,
73 MFP_RBF,
74 MFP_TIMERA,
75 MFP_DMASOUND=MFP_TIMERA,
76 MFP_RING,
77 MFP_MONODETECT
78 };
79
80 /* Xbtimer() timers */
81 enum {
82 XB_TIMERA=0,
83 XB_TIMERB,
84 XB_TIMERC,
85 XB_TIMERD
86 };
87
88 /*--- Static variables ---*/
89
90 static unsigned long cookie_snd, cookie_mch, cookie_gsxb;
91 static Uint16 hardfreq[16];
92 static Uint16 numfreq;
93 static SDL_AudioDevice *SDL_MintAudio_device;
94
95 /*--- Audio driver functions ---*/
96
97 static void Mint_CloseAudio(_THIS);
98 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
99 static void Mint_LockAudio(_THIS);
100 static void Mint_UnlockAudio(_THIS);
101
102 /*--- Audio driver bootstrap functions ---*/
103
104 static int Audio_Available(void)
105 {
106 const char *envr = getenv("SDL_AUDIODRIVER");
107
108 /* Check if user asked a different audio driver */
109 if ((envr) && (strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
110 return 0;
111 }
112
113 /* Cookie _SND present ? if not, assume ST machine */
114 if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
115 cookie_snd = SND_PSG;
116 }
117
118 /* Cookie _MCH present ? if not, assume ST machine */
119 if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
120 cookie_mch = MCH_ST << 16;
121 }
122
123 /* Cookie GSXB present ? */
124 cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
125
126 /* Check if we have xbios functions (Falcon, clones) */
127 if ((cookie_snd & SND_16BIT)!=0) {
128 /* Check if audio is lockable */
129 if (Locksnd()==1) {
130 Unlocksnd();
131 } else {
132 /* Already in use */
133 return(0);
134 }
135
136 return(1);
137 }
138
139 /* Check if we have 8 bits DMA audio (STE, TT) */
140 if ((cookie_snd & SND_8BIT)!=0) {
141 return(1);
142 }
143
144 return(0);
145 }
146
147 static void Audio_DeleteDevice(SDL_AudioDevice *device)
148 {
149 free(device->hidden);
150 free(device);
151 }
152
153 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
154 {
155 SDL_AudioDevice *this;
156
157 /* Initialize all variables that we clean on shutdown */
158 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
159 if ( this ) {
160 memset(this, 0, (sizeof *this));
161 }
162 if ( this == NULL ) {
163 SDL_OutOfMemory();
164 if ( this ) {
165 free(this);
166 }
167 return(0);
168 }
169
170 /* Set the function pointers */
171 this->OpenAudio = Mint_OpenAudio;
172 this->CloseAudio = Mint_CloseAudio;
173 this->LockAudio = Mint_LockAudio;
174 this->UnlockAudio = Mint_UnlockAudio;
175 this->free = Audio_DeleteDevice;
176
177 return this;
178 }
179
180 AudioBootStrap MINTAUDIO_bootstrap = {
181 MINT_AUDIO_DRIVER_NAME, "MiNT audio driver",
182 Audio_Available, Audio_CreateDevice
183 };
184
185 static void Mint_LockAudio(_THIS)
186 {
187 void *oldpile;
188
189 /* Stop replay */
190 if ((cookie_snd & SND_16BIT)!=0) {
191 Buffoper(0);
192 } else if ((cookie_snd & SND_8BIT)!=0) {
193 oldpile=(void *)Super(0);
194 DMAAUDIO_IO.control=0;
195 Super(oldpile);
196 }
197 }
198
199 static void Mint_UnlockAudio(_THIS)
200 {
201 void *oldpile;
202
203 /* Restart replay */
204 if ((cookie_snd & SND_16BIT)!=0) {
205 Buffoper(SB_PLA_ENA|SB_PLA_RPT);
206 } else if ((cookie_snd & SND_8BIT)!=0) {
207 oldpile=(void *)Super(0);
208 DMAAUDIO_IO.control=3;
209 Super(oldpile);
210 }
211 }
212
213 /* This is called from the interrupt routine */
214 void SDL_MintAudio_Callback(void)
215 {
216 SDL_AudioDevice *audio;
217 Uint8 *buffer;
218
219 audio = SDL_MintAudio_device;
220 buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
221
222 if ( ! audio->paused ) {
223 if ( audio->convert.needed ) {
224 audio->spec.callback(audio->spec.userdata,
225 (Uint8 *)audio->convert.buf,audio->convert.len);
226 SDL_ConvertAudio(&audio->convert);
227 memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
228 } else {
229 audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
230 }
231 }
232 }
233
234 static void Mint_StopAudio_Dma8(void)
235 {
236 void *oldpile;
237
238 oldpile=(void *)Super(0);
239 DMAAUDIO_IO.control=0;
240 Super(oldpile);
241
242 Jdisint(MFP_DMASOUND);
243 }
244
245 static void Mint_StopAudio_Xbios(void)
246 {
247 Buffoper(0);
248 Jdisint(MFP_DMASOUND);
249 }
250
251 static void Mint_StopAudio_Gsxb(void)
252 {
253 Buffoper(0);
254 }
255
256 static void Mint_CloseAudio(_THIS)
257 {
258 if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) {
259 Mint_StopAudio_Gsxb();
260 } else if ((cookie_snd & SND_16BIT)!=0) {
261 Mint_StopAudio_Xbios();
262 } else if ((cookie_snd & SND_8BIT)!=0) {
263 Mint_StopAudio_Dma8();
264 }
265
266 /* Clear buffers */
267 if (SDL_MintAudio_audiobuf[0]) {
268 Mfree(SDL_MintAudio_audiobuf[0]);
269 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
270 }
271
272 /* Unlock sound system */
273 if ((cookie_snd & SND_16BIT)!=0) {
274 Unlocksnd();
275 }
276 }
277
278 static void Mint_CheckAudio_Dma8(SDL_AudioSpec *spec)
279 {
280 int i;
281
282 spec->format = AUDIO_S8;
283
284 switch(cookie_mch>>16) {
285 case MCH_STE:
286 /* STE replay frequencies */
287 for (i=0;i<4;i++) {
288 hardfreq[i]=MASTERCLOCK_STE/(MASTERPREDIV_STE*(i+1));
289 }
290
291 if (spec->freq>=(hardfreq[0]+hardfreq[1])>>1) {
292 numfreq=3; /* 50066 */
293 } else if (spec->freq>=(hardfreq[1]+hardfreq[2])>>1) {
294 numfreq=2; /* 25033 */
295 } else if (spec->freq>=(hardfreq[2]+hardfreq[3])>>1) {
296 numfreq=1; /* 12517 */
297 } else {
298 numfreq=0; /* 6258 */
299 }
300
301 spec->freq=hardfreq[numfreq];
302 break;
303 case MCH_TT:
304 /* TT replay frequencies */
305 for (i=0;i<4;i++) {
306 hardfreq[i]=MASTERCLOCK_TT/(MASTERPREDIV_TT*(i+1));
307 }
308
309 if (spec->freq>=(hardfreq[0]+hardfreq[1])>>1) {
310 numfreq=3; /* 50337 */
311 } else if (spec->freq>=(hardfreq[1]+hardfreq[2])>>1) {
312 numfreq=2; /* 25169 */
313 } else if (spec->freq>=(hardfreq[2]+hardfreq[3])>>1) {
314 numfreq=1; /* 12584 */
315 } else {
316 numfreq=0; /* 6292 */
317 }
318 spec->freq=hardfreq[numfreq];
319 break;
320 }
321 }
322
323 static void Mint_CheckAudio_Xbios(SDL_AudioSpec *spec)
324 {
325 int i;
326
327 /* Check conversions needed */
328 switch (spec->format & 0xff) {
329 case 8:
330 spec->format = AUDIO_S8;
331 break;
332 case 16:
333 spec->format = AUDIO_S16MSB;
334 break;
335 }
336
337 /* Check hardware channels */
338 if ((spec->channels==1) && ((spec->format & 0xff)==16)) {
339 spec->channels=2;
340 }
341
342 /* Falcon replay frequencies */
343 for (i=0;i<16;i++) {
344 hardfreq[i]=MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1));
345 }
346
347 /* The Falcon CODEC only support some frequencies */
348 if (spec->freq>=(hardfreq[CLK50K]+hardfreq[CLK33K])>>1) {
349 numfreq=CLK50K; /* 49170 */
350 } else if (spec->freq>=(hardfreq[CLK33K]+hardfreq[CLK25K])>>1) {
351 numfreq=CLK33K; /* 32780 */
352 } else if (spec->freq>=(hardfreq[CLK25K]+hardfreq[CLK20K])>>1) {
353 numfreq=CLK25K; /* 24585 */
354 } else if (spec->freq>=(hardfreq[CLK20K]+hardfreq[CLK16K])>>1) {
355 numfreq=CLK20K; /* 19668 */
356 } else if (spec->freq>=(hardfreq[CLK16K]+hardfreq[CLK12K])>>1) {
357 numfreq=CLK16K; /* 16390 */
358 } else if (spec->freq>=(hardfreq[CLK12K]+hardfreq[CLK10K])>>1) {
359 numfreq=CLK12K; /* 12292 */
360 } else if (spec->freq>=(hardfreq[CLK10K]+hardfreq[CLK8K])>>1) {
361 numfreq=CLK10K; /* 9834 */
362 } else {
363 numfreq=CLK8K; /* 8195 */
364 }
365
366 spec->freq=hardfreq[numfreq];
367 }
368
369 static int Mint_CheckAudio_Gsxb(SDL_AudioSpec *spec)
370 {
371 long snd_format;
372 int i, resolution, format_signed, format_bigendian;
373
374 resolution = spec->format & 0x00ff;
375 format_signed = ((spec->format & 0x8000)!=0);
376 format_bigendian = ((spec->format & 0x1000)!=0);
377
378 /* Check formats available */
379 snd_format = Sndstatus(SND_QUERYFORMATS);
380 switch (resolution) {
381 case 8:
382 if ((snd_format & SND_FORMAT8)==0) {
383 SDL_SetError("Mint_CheckAudio: 8 bits samples not supported");
384 return -1;
385 }
386 snd_format = Sndstatus(SND_QUERY8BIT);
387 break;
388 case 16:
389 if ((snd_format & SND_FORMAT16)==0) {
390 SDL_SetError("Mint_CheckAudio: 16 bits samples not supported");
391 return -1;
392 }
393 snd_format = Sndstatus(SND_QUERY16BIT);
394 break;
395 default:
396 SDL_SetError("Mint_CheckAudio: Unsupported sample resolution");
397 return -1;
398 break;
399 }
400
401 /* Check signed/unsigned format */
402 if (format_signed) {
403 if (snd_format & SND_FORMATSIGNED) {
404 /* Ok */
405 } else if (snd_format & SND_FORMATUNSIGNED) {
406 /* Give unsigned format */
407 spec->format = spec->format & (~0x8000);
408 }
409 } else {
410 if (snd_format & SND_FORMATUNSIGNED) {
411 /* Ok */
412 } else if (snd_format & SND_FORMATSIGNED) {
413 /* Give signed format */
414 spec->format |= 0x8000;
415 }
416 }
417
418 if (format_bigendian) {
419 if (snd_format & SND_FORMATBIGENDIAN) {
420 /* Ok */
421 } else if (snd_format & SND_FORMATLITTLEENDIAN) {
422 /* Give little endian format */
423 spec->format = spec->format & (~0x1000);
424 }
425 } else {
426 if (snd_format & SND_FORMATBIGENDIAN) {
427 /* Ok */
428 } else if (snd_format & SND_FORMATLITTLEENDIAN) {
429 /* Give big endian format */
430 spec->format |= 0x1000;
431 }
432 }
433
434 /* Only xbios functions available = clone with PC board */
435 for (i=0;i<8;i++) {
436 hardfreq[i]=MASTERCLOCK_MILAN1/(MASTERPREDIV_MILAN*(i+1));
437 }
438
439 if (spec->freq>=(hardfreq[CLK_44K]+hardfreq[CLK_22K])>>1) {
440 numfreq = CLK_44K; /* 44100 */
441 } else if (spec->freq>=(hardfreq[CLK_22K]+hardfreq[CLK_11K])>>1) {
442 numfreq = CLK_22K; /* 22050 */
443 } else {
444 numfreq = CLK_11K; /* 11025 */
445 }
446
447 spec->freq=hardfreq[numfreq];
448
449 return 0;
450 }
451
452 static void Mint_InitAudio_Dma8(SDL_AudioSpec *spec)
453 {
454 void *oldpile;
455 unsigned long buffer;
456 unsigned char mode;
457
458 oldpile=(void *)Super(0);
459
460 /* Stop currently playing sound */
461 DMAAUDIO_IO.control=0;
462
463 /* Set buffer */
464 buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
465 DMAAUDIO_IO.start_high = (buffer>>16) & 255;
466 DMAAUDIO_IO.start_mid = (buffer>>8) & 255;
467 DMAAUDIO_IO.start_low = buffer & 255;
468
469 buffer += SDL_MintAudio_audiosize;
470 DMAAUDIO_IO.end_high = (buffer>>16) & 255;
471 DMAAUDIO_IO.end_mid = (buffer>>8) & 255;
472 DMAAUDIO_IO.end_low = buffer & 255;
473
474 mode = numfreq;
475 if (spec->channels==1) {
476 mode |= 1<<7;
477 }
478 DMAAUDIO_IO.mode = mode;
479
480 /* Set interrupt */
481 Jdisint(MFP_DMASOUND);
482 Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_IntDma);
483 Jenabint(MFP_DMASOUND);
484
485 /* Go */
486 DMAAUDIO_IO.control = 3; /* playback + repeat */
487
488 Super(oldpile);
489 }
490
491 static void Mint_InitAudio_Xbios(SDL_AudioSpec *spec)
492 {
493 int channels_mode;
494 void *buffer;
495
496 /* Stop currently playing sound */
497 Buffoper(0);
498
499 Settracks(0,0);
500 Setmontracks(0);
501
502 switch (spec->format & 0xff) {
503 case 8:
504 if (spec->channels==2) {
505 channels_mode=STEREO8;
506 } else {
507 channels_mode=MONO8;
508 }
509 break;
510 case 16:
511 default:
512 channels_mode=STEREO16;
513 break;
514 }
515 Setmode(channels_mode);
516
517 Devconnect(DMAPLAY, DAC, CLK25M, numfreq, 1);
518
519 /* Set buffer */
520 buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
521 Setbuffer(0, buffer, buffer+SDL_MintAudio_audiosize);
522
523 /* Install interrupt */
524 Setinterrupt(SI_TIMERA, SI_PLAY);
525
526 Jdisint(MFP_DMASOUND);
527 Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_IntXbios);
528 Jenabint(MFP_DMASOUND);
529
530 /* Go */
531 Buffoper(SB_PLA_ENA|SB_PLA_RPT);
532 }
533
534 static void Mint_InitAudio_Gsxb(SDL_AudioSpec *spec)
535 {
536 int channels_mode;
537 void *buffer;
538
539 /* Stop currently playing sound */
540 Buffoper(0);
541
542 switch (spec->format & 0xff) {
543 case 8:
544 if (spec->channels==2) {
545 channels_mode=STEREO8;
546 } else {
547 channels_mode=MONO8;
548 }
549 break;
550 case 16:
551 if (spec->channels==2) {
552 channels_mode=STEREO16;
553 } else {
554 channels_mode=MONO16;
555 }
556 break;
557 default:
558 channels_mode=STEREO16;
559 break;
560 }
561 Setmode(channels_mode);
562
563 Devconnect(0, 0, CLKEXT, numfreq, 1);
564
565 /* Set buffer */
566 buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
567 Setbuffer(0, buffer, buffer+SDL_MintAudio_audiosize);
568
569 /* Install interrupt */
570 NSetinterrupt(2, SI_PLAY, SDL_MintAudio_IntGsxb);
571
572 /* Go */
573 Buffoper(SB_PLA_ENA|SB_PLA_RPT);
574 }
575
576 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
577 {
578 /* Lock sound system */
579 if ((cookie_snd & SND_16BIT)!=0) {
580 if (Locksnd()!=1) {
581 SDL_SetError("Mint_OpenAudio: Audio system already in use");
582 return(-1);
583 }
584 }
585
586 /* Check audio capabilities */
587 if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) {
588 if (Mint_CheckAudio_Gsxb(spec)==-1) {
589 return -1;
590 }
591 } else if ((cookie_snd & SND_16BIT)!=0) {
592 Mint_CheckAudio_Xbios(spec);
593 } else if ((cookie_snd & SND_8BIT)!=0) {
594 Mint_CheckAudio_Dma8(spec);
595 }
596
597 SDL_CalculateAudioSpec(spec);
598
599 /* Allocate memory for audio buffers in DMA-able RAM */
600 spec->size = spec->samples;
601 spec->size *= spec->channels;
602 spec->size *= (spec->format & 0xFF)/8;
603
604 SDL_MintAudio_audiosize = spec->size;
605
606 SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(SDL_MintAudio_audiosize *2, MX_STRAM);
607 if (SDL_MintAudio_audiobuf[0]==NULL) {
608 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
609 return (-1);
610 }
611 SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + SDL_MintAudio_audiosize;
612 SDL_MintAudio_numbuf=0;
613 memset(SDL_MintAudio_audiobuf[0], 0, SDL_MintAudio_audiosize * 2);
614 SDL_MintAudio_mutex = 0;
615
616 SDL_MintAudio_device = this;
617
618 /* Setup audio hardware */
619 if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) {
620 Mint_InitAudio_Gsxb(spec);
621 } else if ((cookie_snd & SND_16BIT)!=0) {
622 Mint_InitAudio_Xbios(spec);
623 } else if ((cookie_snd & SND_8BIT)!=0) {
624 Mint_InitAudio_Dma8(spec);
625 }
626
627 return 1;
628 }