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 DMA 8bits (hardware access) 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_dma8.h" 44 45 /*--- Defines ---*/ 46 47 #define MINT_AUDIO_DRIVER_NAME "mint_dma8" 48 49 /* Debug print info */ 50 #define DEBUG_NAME "audio:dma8: " 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 unsigned long cookie_snd, cookie_mch; 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 /*--- Audio driver bootstrap functions ---*/ 76 77 static int Audio_Available(void) 78 { 79 const char *envr = SDL_getenv("SDL_AUDIODRIVER"); 80 81 /* Check if user asked a different audio driver */ 82 if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) { 83 DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n")); 84 return 0; 85 } 86 87 /* Cookie _MCH present ? if not, assume ST machine */ 88 if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) { 89 cookie_mch = MCH_ST; 90 } 91 92 /* Cookie _SND present ? if not, assume ST machine */ 93 if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) { 94 cookie_snd = SND_PSG; 95 } 96 97 /* Check if we have 8 bits audio */ 98 if ((cookie_snd & SND_8BIT)==0) { 99 DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n")); 100 return(0); 101 } 102 103 /* Check if audio is lockable */ 104 if (cookie_snd & SND_16BIT) { 105 if (Locksnd()!=1) { 106 DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n")); 107 return(0); 108 } 109 110 Unlocksnd(); 111 } 112 113 DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n")); 114 return(1); 115 } 116 117 static void Audio_DeleteDevice(SDL_AudioDevice *device) 118 { 119 SDL_free(device->hidden); 120 SDL_free(device); 121 } 122 123 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 124 { 125 SDL_AudioDevice *this; 126 127 /* Initialize all variables that we clean on shutdown */ 128 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 129 if ( this ) { 130 SDL_memset(this, 0, (sizeof *this)); 131 this->hidden = (struct SDL_PrivateAudioData *) 132 SDL_malloc((sizeof *this->hidden)); 133 } 134 if ( (this == NULL) || (this->hidden == NULL) ) { 135 SDL_OutOfMemory(); 136 if ( this ) { 137 SDL_free(this); 138 } 139 return(0); 140 } 141 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 142 143 /* Set the function pointers */ 144 this->OpenAudio = Mint_OpenAudio; 145 this->CloseAudio = Mint_CloseAudio; 146 this->LockAudio = Mint_LockAudio; 147 this->UnlockAudio = Mint_UnlockAudio; 148 this->free = Audio_DeleteDevice; 149 150 return this; 151 } 152 153 AudioBootStrap MINTAUDIO_DMA8_bootstrap = { 154 MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver", 155 Audio_Available, Audio_CreateDevice 156 }; 157 158 static void Mint_LockAudio(_THIS) 159 { 160 void *oldpile; 161 162 /* Stop replay */ 163 oldpile=(void *)Super(0); 164 DMAAUDIO_IO.control=0; 165 Super(oldpile); 166 } 167 168 static void Mint_UnlockAudio(_THIS) 169 { 170 void *oldpile; 171 172 /* Restart replay */ 173 oldpile=(void *)Super(0); 174 DMAAUDIO_IO.control=3; 175 Super(oldpile); 176 } 177 178 static void Mint_CloseAudio(_THIS) 179 { 180 void *oldpile; 181 182 /* Stop replay */ 183 oldpile=(void *)Super(0); 184 DMAAUDIO_IO.control=0; 185 Super(oldpile); 186 187 DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n")); 188 189 /* Disable interrupt */ 190 Jdisint(MFP_DMASOUND); 191 192 DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n")); 193 194 /* Wait if currently playing sound */ 195 while (SDL_MintAudio_mutex != 0) { 196 } 197 198 DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n")); 199 200 /* Clear buffers */ 201 if (SDL_MintAudio_audiobuf[0]) { 202 Mfree(SDL_MintAudio_audiobuf[0]); 203 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; 204 } 205 206 DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n")); 207 } 208 209 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec) 210 { 211 int i, masterprediv, sfreq; 212 unsigned long masterclock; 213 214 DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff)); 215 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 216 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 217 DEBUG_PRINT(("channels=%d, ", spec->channels)); 218 DEBUG_PRINT(("freq=%d\n", spec->freq)); 219 220 if (spec->channels > 2) 221 spec->channels = 2; 222 223 /* Check formats available */ 224 spec->format = AUDIO_S8; 225 226 /* Calculate and select the closest frequency */ 227 sfreq=0; 228 masterclock=MASTERCLOCK_STE; 229 masterprediv=MASTERPREDIV_STE; 230 switch(cookie_mch>>16) { 231 /* 232 case MCH_STE: 233 masterclock=MASTERCLOCK_STE; 234 masterprediv=MASTERPREDIV_STE; 235 break; 236 */ 237 case MCH_TT: 238 masterclock=MASTERCLOCK_TT; 239 masterprediv=MASTERPREDIV_TT; 240 break; 241 case MCH_F30: 242 case MCH_ARANYM: 243 masterclock=MASTERCLOCK_FALCON1; 244 masterprediv=MASTERPREDIV_FALCON; 245 sfreq=1; 246 break; 247 } 248 249 MINTAUDIO_freqcount=0; 250 for (i=sfreq;i<4;i++) { 251 SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), 252 masterclock, i-sfreq, -1); 253 } 254 255 #if 1 256 for (i=0; i<MINTAUDIO_freqcount; i++) { 257 DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n", 258 i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock, 259 MINTAUDIO_frequencies[i].predivisor 260 )); 261 } 262 #endif 263 264 MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq); 265 spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; 266 267 DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff)); 268 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); 269 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); 270 DEBUG_PRINT(("channels=%d, ", spec->channels)); 271 DEBUG_PRINT(("freq=%d\n", spec->freq)); 272 273 return 0; 274 } 275 276 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec) 277 { 278 void *oldpile; 279 unsigned long buffer; 280 unsigned char mode; 281 282 /* Set replay tracks */ 283 if (cookie_snd & SND_16BIT) { 284 Settracks(0,0); 285 Setmontracks(0); 286 } 287 288 oldpile=(void *)Super(0); 289 290 /* Stop currently playing sound */ 291 DMAAUDIO_IO.control=0; 292 293 /* Set buffer */ 294 buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 295 DMAAUDIO_IO.start_high = (buffer>>16) & 255; 296 DMAAUDIO_IO.start_mid = (buffer>>8) & 255; 297 DMAAUDIO_IO.start_low = buffer & 255; 298 299 buffer += SDL_MintAudio_audiosize; 300 DMAAUDIO_IO.end_high = (buffer>>16) & 255; 301 DMAAUDIO_IO.end_mid = (buffer>>8) & 255; 302 DMAAUDIO_IO.end_low = buffer & 255; 303 304 mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; 305 if (spec->channels==1) { 306 mode |= 1<<7; 307 } 308 DMAAUDIO_IO.sound_ctrl = mode; 309 310 /* Set interrupt */ 311 Jdisint(MFP_DMASOUND); 312 Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt); 313 Jenabint(MFP_DMASOUND); 314 315 if (cookie_snd & SND_16BIT) { 316 if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) { 317 DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n")); 318 } 319 } 320 321 /* Go */ 322 DMAAUDIO_IO.control = 3; /* playback + repeat */ 323 324 Super(oldpile); 325 } 326 327 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) 328 { 329 SDL_MintAudio_device = this; 330 331 /* Check audio capabilities */ 332 if (Mint_CheckAudio(this, spec)==-1) { 333 return -1; 334 } 335 336 SDL_CalculateAudioSpec(spec); 337 338 /* Allocate memory for audio buffers in DMA-able RAM */ 339 DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size)); 340 341 SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM); 342 if (SDL_MintAudio_audiobuf[0]==NULL) { 343 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); 344 return (-1); 345 } 346 SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ; 347 SDL_MintAudio_numbuf=0; 348 SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2); 349 SDL_MintAudio_audiosize = spec->size; 350 SDL_MintAudio_mutex = 0; 351 352 DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0])); 353 DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1])); 354 355 SDL_MintAudio_CheckFpu(); 356 357 /* Setup audio hardware */ 358 Mint_InitAudio(this, spec); 359 360 return(1); /* We don't use threaded audio */ 361 } 362