Home | History | Annotate | Download | only in mint
      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 (STFA 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 #include "../../video/ataricommon/SDL_atarisuper.h"
     42 
     43 #include "SDL_mintaudio.h"
     44 #include "SDL_mintaudio_stfa.h"
     45 
     46 /*--- Defines ---*/
     47 
     48 #define MINT_AUDIO_DRIVER_NAME "mint_stfa"
     49 
     50 /* Debug print info */
     51 #define DEBUG_NAME "audio:stfa: "
     52 #if 0
     53 #define DEBUG_PRINT(what) \
     54 	{ \
     55 		printf what; \
     56 	}
     57 #else
     58 #define DEBUG_PRINT(what)
     59 #endif
     60 
     61 /*--- Static variables ---*/
     62 
     63 static long cookie_snd, cookie_mch;
     64 static cookie_stfa_t *cookie_stfa;
     65 
     66 static const int freqs[16]={
     67 	4995,	6269,	7493,	8192,
     68 	9830,	10971,	12538,	14985,
     69 	16384,	19819,	21943,	24576,
     70 	30720,	32336,	43885,	49152
     71 };
     72 
     73 /*--- Audio driver functions ---*/
     74 
     75 static void Mint_CloseAudio(_THIS);
     76 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
     77 static void Mint_LockAudio(_THIS);
     78 static void Mint_UnlockAudio(_THIS);
     79 
     80 /* To check/init hardware audio */
     81 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
     82 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
     83 
     84 /*--- Audio driver bootstrap functions ---*/
     85 
     86 static int Audio_Available(void)
     87 {
     88 	long dummy;
     89 	const char *envr = SDL_getenv("SDL_AUDIODRIVER");
     90 
     91 	/* Check if user asked a different audio driver */
     92 	if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
     93 		DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
     94 		return(0);
     95 	}
     96 
     97 	/* Cookie _MCH present ? if not, assume ST machine */
     98 	if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
     99 		cookie_mch = MCH_ST;
    100 	}
    101 
    102 	/* Cookie _SND present ? if not, assume ST machine */
    103 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
    104 		cookie_snd = SND_PSG;
    105 	}
    106 
    107 	/* Cookie STFA present ? */
    108 	if (Getcookie(C_STFA, &dummy) != C_FOUND) {
    109 		DEBUG_PRINT((DEBUG_NAME "no STFA audio\n"));
    110 		return(0);
    111 	}
    112 	cookie_stfa = (cookie_stfa_t *) dummy;
    113 
    114 	SDL_MintAudio_stfa = cookie_stfa;
    115 
    116 	DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
    117 	return(1);
    118 }
    119 
    120 static void Audio_DeleteDevice(SDL_AudioDevice *device)
    121 {
    122     SDL_free(device->hidden);
    123     SDL_free(device);
    124 }
    125 
    126 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
    127 {
    128 	SDL_AudioDevice *this;
    129 
    130 	/* Initialize all variables that we clean on shutdown */
    131 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
    132     if ( this ) {
    133         SDL_memset(this, 0, (sizeof *this));
    134         this->hidden = (struct SDL_PrivateAudioData *)
    135                 SDL_malloc((sizeof *this->hidden));
    136     }
    137     if ( (this == NULL) || (this->hidden == NULL) ) {
    138         SDL_OutOfMemory();
    139         if ( this ) {
    140             SDL_free(this);
    141         }
    142         return(0);
    143     }
    144     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    145 
    146     /* Set the function pointers */
    147     this->OpenAudio   = Mint_OpenAudio;
    148     this->CloseAudio  = Mint_CloseAudio;
    149     this->LockAudio   = Mint_LockAudio;
    150     this->UnlockAudio = Mint_UnlockAudio;
    151     this->free        = Audio_DeleteDevice;
    152 
    153     return this;
    154 }
    155 
    156 AudioBootStrap MINTAUDIO_STFA_bootstrap = {
    157 	MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver",
    158 	Audio_Available, Audio_CreateDevice
    159 };
    160 
    161 static void Mint_LockAudio(_THIS)
    162 {
    163 	void *oldpile;
    164 
    165 	/* Stop replay */
    166 	oldpile=(void *)Super(0);
    167 	cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
    168 	SuperToUser(oldpile);
    169 }
    170 
    171 static void Mint_UnlockAudio(_THIS)
    172 {
    173 	void *oldpile;
    174 
    175 	/* Restart replay */
    176 	oldpile=(void *)Super(0);
    177 	cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
    178 	SuperToUser(oldpile);
    179 }
    180 
    181 static void Mint_CloseAudio(_THIS)
    182 {
    183 	void *oldpile;
    184 
    185 	/* Stop replay */
    186 	oldpile=(void *)Super(0);
    187 	cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
    188 	SuperToUser(oldpile);
    189 
    190 	/* Wait if currently playing sound */
    191 	while (SDL_MintAudio_mutex != 0) {
    192 	}
    193 
    194 	/* Clear buffers */
    195 	if (SDL_MintAudio_audiobuf[0]) {
    196 		Mfree(SDL_MintAudio_audiobuf[0]);
    197 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
    198 	}
    199 }
    200 
    201 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
    202 {
    203 	int i;
    204 
    205 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
    206 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
    207 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
    208 	DEBUG_PRINT(("channels=%d, ", spec->channels));
    209 	DEBUG_PRINT(("freq=%d\n", spec->freq));
    210 
    211     if (spec->channels > 2) {
    212         spec->channels = 2;  /* no more than stereo! */
    213     }
    214 
    215 	/* Check formats available */
    216 	MINTAUDIO_freqcount=0;
    217 	for (i=0;i<16;i++) {
    218 		SDL_MintAudio_AddFrequency(this, freqs[i], 0, i, -1);
    219 	}
    220 
    221 #if 1
    222 	for (i=0; i<MINTAUDIO_freqcount; i++) {
    223 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
    224 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
    225 			MINTAUDIO_frequencies[i].predivisor
    226 		));
    227 	}
    228 #endif
    229 
    230 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
    231 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
    232 
    233 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
    234 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
    235 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
    236 	DEBUG_PRINT(("channels=%d, ", spec->channels));
    237 	DEBUG_PRINT(("freq=%d\n", spec->freq));
    238 
    239 	return 0;
    240 }
    241 
    242 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
    243 {
    244 	void *buffer;
    245 	void *oldpile;
    246 
    247 	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
    248 
    249 	oldpile=(void *)Super(0);
    250 
    251 	/* Stop replay */
    252 	cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
    253 
    254 	/* Select replay format */
    255 	cookie_stfa->sound_control = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
    256 	if ((spec->format & 0xff)==8) {
    257 		cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
    258 	} else {
    259 		cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
    260 	}
    261 	if (spec->channels==2) {
    262 		cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
    263 	} else {
    264 		cookie_stfa->sound_control |= STFA_FORMAT_MONO;
    265 	}
    266 	if ((spec->format & 0x8000)!=0) {
    267 		cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
    268 	} else {
    269 		cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
    270 	}
    271 	if ((spec->format & 0x1000)!=0) {
    272 		cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
    273 	} else {
    274 		cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
    275 	}
    276 
    277 	/* Set buffer */
    278 	cookie_stfa->sound_start = (unsigned long) buffer;
    279 	cookie_stfa->sound_end = (unsigned long) (buffer + spec->size);
    280 
    281 	/* Set interrupt */
    282 	cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
    283 
    284 	/* Restart replay */
    285 	cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
    286 
    287 	SuperToUser(oldpile);
    288 
    289 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
    290 }
    291 
    292 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
    293 {
    294 	SDL_MintAudio_device = this;
    295 
    296 	/* Check audio capabilities */
    297 	if (Mint_CheckAudio(this, spec)==-1) {
    298 		return -1;
    299 	}
    300 
    301 	SDL_CalculateAudioSpec(spec);
    302 
    303 	/* Allocate memory for audio buffers in DMA-able RAM */
    304 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
    305 
    306 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
    307 	if (SDL_MintAudio_audiobuf[0]==NULL) {
    308 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
    309 		return (-1);
    310 	}
    311 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
    312 	SDL_MintAudio_numbuf=0;
    313 	SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
    314 	SDL_MintAudio_audiosize = spec->size;
    315 	SDL_MintAudio_mutex = 0;
    316 
    317 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
    318 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
    319 
    320 	SDL_MintAudio_CheckFpu();
    321 
    322 	/* Setup audio hardware */
    323 	Mint_InitAudio(this, spec);
    324 
    325     return(1);	/* We don't use threaded audio */
    326 }
    327