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