1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2004 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 (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 unsigned 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 unsigned 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, (long *) &cookie_mcsn) != C_FOUND) { 116 DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n")); 117 return(0); 118 } 119 120 /* Check if interrupt at end of replay */ 121 if (cookie_mcsn->pint == 0) { 122 DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n")); 123 return(0); 124 } 125 126 /* Check if audio is lockable */ 127 if (Locksnd()!=1) { 128 DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n")); 129 return(0); 130 } 131 132 Unlocksnd(); 133 134 DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n")); 135 return(1); 136 } 137 138 static void Audio_DeleteDevice(SDL_AudioDevice *device) 139 { 140 SDL_free(device->hidden); 141 SDL_free(device); 142 } 143 144 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 145 { 146 SDL_AudioDevice *this; 147 148 /* Initialize all variables that we clean on shutdown */ 149 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 150 if ( this ) { 151 SDL_memset(this, 0, (sizeof *this)); 152 this->hidden = (struct SDL_PrivateAudioData *) 153 SDL_malloc((sizeof *this->hidden)); 154 } 155 if ( (this == NULL) || (this->hidden == NULL) ) { 156 SDL_OutOfMemory(); 157 if ( this ) { 158 SDL_free(this); 159 } 160 return(0); 161 } 162 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 163 164 /* Set the function pointers */ 165 this->OpenAudio = Mint_OpenAudio; 166 this->CloseAudio = Mint_CloseAudio; 167 this->LockAudio = Mint_LockAudio; 168 this->UnlockAudio = Mint_UnlockAudio; 169 this->free = Audio_DeleteDevice; 170 171 return this; 172 } 173 174 AudioBootStrap MINTAUDIO_MCSN_bootstrap = { 175 MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver", 176 Audio_Available, Audio_CreateDevice 177 }; 178 179 static void Mint_LockAudio(_THIS) 180 { 181 /* Stop replay */ 182 Buffoper(0); 183 } 184 185 static void Mint_UnlockAudio(_THIS) 186 { 187 /* Restart replay */ 188 Buffoper(SB_PLA_ENA|SB_PLA_RPT); 189 } 190 191 static void Mint_CloseAudio(_THIS) 192 { 193 /* Stop replay */ 194 SDL_MintAudio_WaitThread(); 195 Buffoper(0); 196 197 if (!SDL_MintAudio_mint_present) { 198 /* Uninstall interrupt */ 199 Jdisint(MFP_DMASOUND); 200 } 201 202 /* Wait if currently playing sound */ 203 while (SDL_MintAudio_mutex != 0) { 204 } 205 206 /* Clear buffers */ 207 if (SDL_MintAudio_audiobuf[0]) { 208 Mfree(SDL_MintAudio_audiobuf[0]); 209 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; 210 } 211 212 /* Unlock sound system */ 213 Unlocksnd(); 214 } 215 216 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec) 217 { 218 int i; 219 unsigned long masterclock, masterprediv; 220 221 DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff)); 222 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 223 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 224 DEBUG_PRINT(("channels=%d, ", spec->channels)); 225 DEBUG_PRINT(("freq=%d\n", spec->freq)); 226 227 if (spec->channels > 2) { 228 spec->channels = 2; /* no more than stereo! */ 229 } 230 231 /* Check formats available */ 232 MINTAUDIO_freqcount=0; 233 switch(cookie_mcsn->play) { 234 case MCSN_ST: 235 spec->channels=1; 236 spec->format=8; /* FIXME: is it signed or unsigned ? */ 237 SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1); 238 break; 239 case MCSN_TT: /* Also STE, Mega STE */ 240 spec->format=AUDIO_S8; 241 masterclock=MASTERCLOCK_STE; 242 masterprediv=MASTERPREDIV_STE; 243 if ((cookie_mch>>16)==MCH_TT) { 244 masterclock=MASTERCLOCK_TT; 245 masterprediv=MASTERPREDIV_TT; 246 } 247 for (i=0; i<4; i++) { 248 SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), 249 masterclock, 3-i, -1); 250 } 251 break; 252 case MCSN_FALCON: /* Also Mac */ 253 for (i=1; i<12; i++) { 254 /* Remove unusable Falcon codec predivisors */ 255 if ((i==6) || (i==8) || (i==10)) { 256 continue; 257 } 258 SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), 259 CLK25M, i+1, -1); 260 } 261 if (cookie_mcsn->res1 != 0) { 262 for (i=1; i<4; i++) { 263 SDL_MintAudio_AddFrequency(this, (cookie_mcsn->res1)/(MASTERPREDIV_FALCON*(1<<i)), 264 CLKEXT, (1<<i)-1, -1); 265 } 266 } 267 spec->format |= 0x8000; /* Audio is always signed */ 268 if ((spec->format & 0x00ff)==16) { 269 spec->format |= 0x1000; /* Audio is always big endian */ 270 spec->channels=2; /* 16 bits always stereo */ 271 } 272 break; 273 } 274 275 #if 1 276 for (i=0; i<MINTAUDIO_freqcount; i++) { 277 DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n", 278 i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock, 279 MINTAUDIO_frequencies[i].predivisor 280 )); 281 } 282 #endif 283 284 MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq); 285 spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; 286 287 DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff)); 288 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 289 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 290 DEBUG_PRINT(("channels=%d, ", spec->channels)); 291 DEBUG_PRINT(("freq=%d\n", spec->freq)); 292 293 return 0; 294 } 295 296 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec) 297 { 298 int channels_mode, prediv, dmaclock; 299 void *buffer; 300 301 /* Stop currently playing sound */ 302 SDL_MintAudio_quit_thread = SDL_FALSE; 303 SDL_MintAudio_thread_finished = SDL_TRUE; 304 SDL_MintAudio_WaitThread(); 305 Buffoper(0); 306 307 /* Set replay tracks */ 308 Settracks(0,0); 309 Setmontracks(0); 310 311 /* Select replay format */ 312 channels_mode=STEREO16; 313 switch (spec->format & 0xff) { 314 case 8: 315 if (spec->channels==2) { 316 channels_mode=STEREO8; 317 } else { 318 channels_mode=MONO8; 319 } 320 break; 321 } 322 if (Setmode(channels_mode)<0) { 323 DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n")); 324 } 325 326 dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock; 327 prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; 328 switch(cookie_mcsn->play) { 329 case MCSN_TT: 330 Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, 1); 331 Soundcmd(SETPRESCALE, prediv); 332 DEBUG_PRINT((DEBUG_NAME "STE/TT prescaler selected\n")); 333 break; 334 case MCSN_FALCON: 335 Devconnect(DMAPLAY, DAC, dmaclock, prediv, 1); 336 DEBUG_PRINT((DEBUG_NAME "Falcon prescaler selected\n")); 337 break; 338 } 339 340 /* Set buffer */ 341 buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 342 if (Setbuffer(0, buffer, buffer + spec->size)<0) { 343 DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n")); 344 } 345 346 if (SDL_MintAudio_mint_present) { 347 SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0); 348 } else { 349 /* Install interrupt */ 350 Jdisint(MFP_DMASOUND); 351 Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt); 352 Jenabint(MFP_DMASOUND); 353 354 if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) { 355 DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n")); 356 } 357 } 358 359 /* Go */ 360 Buffoper(SB_PLA_ENA|SB_PLA_RPT); 361 DEBUG_PRINT((DEBUG_NAME "hardware initialized\n")); 362 } 363 364 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) 365 { 366 /* Lock sound system */ 367 if (Locksnd()!=1) { 368 SDL_SetError("Mint_OpenAudio: Audio system already in use"); 369 return(-1); 370 } 371 372 SDL_MintAudio_device = this; 373 374 /* Check audio capabilities */ 375 if (Mint_CheckAudio(this, spec)==-1) { 376 return -1; 377 } 378 379 SDL_CalculateAudioSpec(spec); 380 381 /* Allocate memory for audio buffers in DMA-able RAM */ 382 DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size)); 383 384 SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM); 385 if (SDL_MintAudio_audiobuf[0]==NULL) { 386 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); 387 return (-1); 388 } 389 SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ; 390 SDL_MintAudio_numbuf=0; 391 SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2); 392 SDL_MintAudio_audiosize = spec->size; 393 SDL_MintAudio_mutex = 0; 394 395 DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0])); 396 DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1])); 397 398 SDL_MintAudio_CheckFpu(); 399 400 /* Setup audio hardware */ 401 Mint_InitAudio(this, spec); 402 403 return(1); /* We don't use SDL threaded audio */ 404 } 405