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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* 25 MiNT audio driver 26 using XBIOS functions (GSXB compatible driver) 27 28 Patrice Mandin 29 */ 30 31 /* Mint includes */ 32 #include <mint/osbind.h> 33 #include <mint/falcon.h> 34 #include <mint/cookie.h> 35 36 #include "SDL_audio.h" 37 #include "../SDL_audio_c.h" 38 #include "../SDL_sysaudio.h" 39 40 #include "../../video/ataricommon/SDL_atarimxalloc_c.h" 41 42 #include "SDL_mintaudio.h" 43 #include "SDL_mintaudio_gsxb.h" 44 45 /*--- Defines ---*/ 46 47 #define MINT_AUDIO_DRIVER_NAME "mint_gsxb" 48 49 /* Debug print info */ 50 #define DEBUG_NAME "audio:gsxb: " 51 #if 0 52 #define DEBUG_PRINT(what) \ 53 { \ 54 printf what; \ 55 } 56 #else 57 #define DEBUG_PRINT(what) 58 #endif 59 60 /*--- Static variables ---*/ 61 62 static long cookie_snd, cookie_gsxb; 63 64 /*--- Audio driver functions ---*/ 65 66 static void Mint_CloseAudio(_THIS); 67 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec); 68 static void Mint_LockAudio(_THIS); 69 static void Mint_UnlockAudio(_THIS); 70 71 /* To check/init hardware audio */ 72 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec); 73 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec); 74 75 /* GSXB callbacks */ 76 static void Mint_GsxbInterrupt(void); 77 static void Mint_GsxbNullInterrupt(void); 78 79 /*--- Audio driver bootstrap functions ---*/ 80 81 static int Audio_Available(void) 82 { 83 const char *envr = SDL_getenv("SDL_AUDIODRIVER"); 84 85 /* Check if user asked a different audio driver */ 86 if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) { 87 DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n")); 88 return(0); 89 } 90 91 /* Cookie _SND present ? if not, assume ST machine */ 92 if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) { 93 cookie_snd = SND_PSG; 94 } 95 96 /* Check if we have 16 bits audio */ 97 if ((cookie_snd & SND_16BIT)==0) { 98 DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n")); 99 return(0); 100 } 101 102 /* Cookie GSXB present ? */ 103 cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND); 104 105 /* Is it GSXB ? */ 106 if (((cookie_snd & SND_GSXB)==0) || (cookie_gsxb==0)) { 107 DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n")); 108 return(0); 109 } 110 111 /* Check if audio is lockable */ 112 if (Locksnd()!=1) { 113 DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n")); 114 return(0); 115 } 116 117 Unlocksnd(); 118 119 DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n")); 120 return(1); 121 } 122 123 static void Audio_DeleteDevice(SDL_AudioDevice *device) 124 { 125 SDL_free(device->hidden); 126 SDL_free(device); 127 } 128 129 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 130 { 131 SDL_AudioDevice *this; 132 133 /* Initialize all variables that we clean on shutdown */ 134 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 135 if ( this ) { 136 SDL_memset(this, 0, (sizeof *this)); 137 this->hidden = (struct SDL_PrivateAudioData *) 138 SDL_malloc((sizeof *this->hidden)); 139 } 140 if ( (this == NULL) || (this->hidden == NULL) ) { 141 SDL_OutOfMemory(); 142 if ( this ) { 143 SDL_free(this); 144 } 145 return(0); 146 } 147 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 148 149 /* Set the function pointers */ 150 this->OpenAudio = Mint_OpenAudio; 151 this->CloseAudio = Mint_CloseAudio; 152 this->LockAudio = Mint_LockAudio; 153 this->UnlockAudio = Mint_UnlockAudio; 154 this->free = Audio_DeleteDevice; 155 156 return this; 157 } 158 159 AudioBootStrap MINTAUDIO_GSXB_bootstrap = { 160 MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver", 161 Audio_Available, Audio_CreateDevice 162 }; 163 164 static void Mint_LockAudio(_THIS) 165 { 166 /* Stop replay */ 167 Buffoper(0); 168 } 169 170 static void Mint_UnlockAudio(_THIS) 171 { 172 /* Restart replay */ 173 Buffoper(SB_PLA_ENA|SB_PLA_RPT); 174 } 175 176 static void Mint_CloseAudio(_THIS) 177 { 178 /* Stop replay */ 179 Buffoper(0); 180 181 /* Uninstall interrupt */ 182 if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt)<0) { 183 DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n")); 184 } 185 186 /* Wait if currently playing sound */ 187 while (SDL_MintAudio_mutex != 0) { 188 } 189 190 /* Clear buffers */ 191 if (SDL_MintAudio_audiobuf[0]) { 192 Mfree(SDL_MintAudio_audiobuf[0]); 193 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; 194 } 195 196 /* Unlock sound system */ 197 Unlocksnd(); 198 } 199 200 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec) 201 { 202 long snd_format = 0; 203 int i, resolution, format_signed, format_bigendian; 204 Uint16 test_format = SDL_FirstAudioFormat(spec->format); 205 int valid_datatype = 0; 206 207 resolution = spec->format & 0x00ff; 208 format_signed = ((spec->format & 0x8000)!=0); 209 format_bigendian = ((spec->format & 0x1000)!=0); 210 211 DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff)); 212 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 213 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 214 DEBUG_PRINT(("channels=%d, ", spec->channels)); 215 DEBUG_PRINT(("freq=%d\n", spec->freq)); 216 217 if (spec->channels > 2) { 218 spec->channels = 2; /* no more than stereo! */ 219 } 220 221 while ((!valid_datatype) && (test_format)) { 222 /* Check formats available */ 223 snd_format = Sndstatus(SND_QUERYFORMATS); 224 spec->format = test_format; 225 resolution = spec->format & 0xff; 226 format_signed = (spec->format & (1<<15)); 227 format_bigendian = (spec->format & (1<<12)); 228 switch (test_format) { 229 case AUDIO_U8: 230 case AUDIO_S8: 231 if (snd_format & SND_FORMAT8) { 232 valid_datatype = 1; 233 snd_format = Sndstatus(SND_QUERY8BIT); 234 } 235 break; 236 237 case AUDIO_U16LSB: 238 case AUDIO_S16LSB: 239 case AUDIO_U16MSB: 240 case AUDIO_S16MSB: 241 if (snd_format & SND_FORMAT16) { 242 valid_datatype = 1; 243 snd_format = Sndstatus(SND_QUERY16BIT); 244 } 245 break; 246 247 default: 248 test_format = SDL_NextAudioFormat(); 249 break; 250 } 251 } 252 253 if (!valid_datatype) { 254 SDL_SetError("Unsupported audio format"); 255 return (-1); 256 } 257 258 /* Check signed/unsigned format */ 259 if (format_signed) { 260 if (snd_format & SND_FORMATSIGNED) { 261 /* Ok */ 262 } else if (snd_format & SND_FORMATUNSIGNED) { 263 /* Give unsigned format */ 264 spec->format = spec->format & (~0x8000); 265 } 266 } else { 267 if (snd_format & SND_FORMATUNSIGNED) { 268 /* Ok */ 269 } else if (snd_format & SND_FORMATSIGNED) { 270 /* Give signed format */ 271 spec->format |= 0x8000; 272 } 273 } 274 275 if (format_bigendian) { 276 if (snd_format & SND_FORMATBIGENDIAN) { 277 /* Ok */ 278 } else if (snd_format & SND_FORMATLITTLEENDIAN) { 279 /* Give little endian format */ 280 spec->format = spec->format & (~0x1000); 281 } 282 } else { 283 if (snd_format & SND_FORMATLITTLEENDIAN) { 284 /* Ok */ 285 } else if (snd_format & SND_FORMATBIGENDIAN) { 286 /* Give big endian format */ 287 spec->format |= 0x1000; 288 } 289 } 290 291 /* Calculate and select the closest frequency */ 292 MINTAUDIO_freqcount=0; 293 for (i=1;i<4;i++) { 294 SDL_MintAudio_AddFrequency(this, 295 MASTERCLOCK_44K/(MASTERPREDIV_MILAN*(1<<i)), MASTERCLOCK_44K, 296 (1<<i)-1, -1); 297 } 298 299 #if 1 300 for (i=0; i<MINTAUDIO_freqcount; i++) { 301 DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n", 302 i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock, 303 MINTAUDIO_frequencies[i].predivisor 304 )); 305 } 306 #endif 307 308 MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq); 309 spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; 310 311 DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff)); 312 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 313 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 314 DEBUG_PRINT(("channels=%d, ", spec->channels)); 315 DEBUG_PRINT(("freq=%d\n", spec->freq)); 316 317 return 0; 318 } 319 320 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec) 321 { 322 int channels_mode, prediv; 323 void *buffer; 324 325 /* Stop currently playing sound */ 326 Buffoper(0); 327 328 /* Set replay tracks */ 329 Settracks(0,0); 330 Setmontracks(0); 331 332 /* Select replay format */ 333 switch (spec->format & 0xff) { 334 case 8: 335 if (spec->channels==2) { 336 channels_mode=STEREO8; 337 } else { 338 channels_mode=MONO8; 339 } 340 break; 341 case 16: 342 if (spec->channels==2) { 343 channels_mode=STEREO16; 344 } else { 345 channels_mode=MONO16; 346 } 347 break; 348 default: 349 channels_mode=STEREO16; 350 break; 351 } 352 if (Setmode(channels_mode)<0) { 353 DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n")); 354 } 355 356 prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; 357 Devconnect(DMAPLAY, DAC, CLKEXT, prediv, 1); 358 359 /* Set buffer */ 360 buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 361 if (Setbuffer(0, buffer, buffer + spec->size)<0) { 362 DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n")); 363 } 364 365 /* Install interrupt */ 366 if (NSetinterrupt(2, SI_PLAY, Mint_GsxbInterrupt)<0) { 367 DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n")); 368 } 369 370 /* Go */ 371 Buffoper(SB_PLA_ENA|SB_PLA_RPT); 372 DEBUG_PRINT((DEBUG_NAME "hardware initialized\n")); 373 } 374 375 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) 376 { 377 /* Lock sound system */ 378 if (Locksnd()!=1) { 379 SDL_SetError("Mint_OpenAudio: Audio system already in use"); 380 return(-1); 381 } 382 383 SDL_MintAudio_device = this; 384 385 /* Check audio capabilities */ 386 if (Mint_CheckAudio(this, spec)==-1) { 387 return -1; 388 } 389 390 SDL_CalculateAudioSpec(spec); 391 392 /* Allocate memory for audio buffers in DMA-able RAM */ 393 DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size)); 394 395 SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM); 396 if (SDL_MintAudio_audiobuf[0]==NULL) { 397 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); 398 return (-1); 399 } 400 SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ; 401 SDL_MintAudio_numbuf=0; 402 SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2); 403 SDL_MintAudio_audiosize = spec->size; 404 SDL_MintAudio_mutex = 0; 405 406 DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0])); 407 DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1])); 408 409 SDL_MintAudio_CheckFpu(); 410 411 /* Setup audio hardware */ 412 Mint_InitAudio(this, spec); 413 414 return(1); /* We don't use threaded audio */ 415 } 416 417 static void Mint_GsxbInterrupt(void) 418 { 419 Uint8 *newbuf; 420 421 if (SDL_MintAudio_mutex) 422 return; 423 424 SDL_MintAudio_mutex=1; 425 426 SDL_MintAudio_numbuf ^= 1; 427 SDL_MintAudio_Callback(); 428 newbuf = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 429 Setbuffer(0, newbuf, newbuf + SDL_MintAudio_audiosize); 430 431 SDL_MintAudio_mutex=0; 432 } 433 434 static void Mint_GsxbNullInterrupt(void) 435 { 436 } 437