src/audio/mint/SDL_mintaudio_mcsn.c
author Patrice Mandin
Fri, 29 Oct 2004 11:19:03 +0000
changeset 962 176240cf4405
parent 961 185acc07127a
child 1095 f10892fa2e48
permissions -rw-r--r--
Forgot to disable debug messages
     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@libsdl.org
    21 */
    22 
    23 /*
    24 	MiNT audio driver
    25 	using XBIOS functions (MacSound compatible driver)
    26 
    27 	Patrice Mandin
    28 */
    29 
    30 #include <stdlib.h>
    31 #include <stdio.h>
    32 #include <string.h>
    33 
    34 /* Mint includes */
    35 #include <mint/osbind.h>
    36 #include <mint/falcon.h>
    37 #include <mint/cookie.h>
    38 
    39 #include "SDL_endian.h"
    40 #include "SDL_audio.h"
    41 #include "SDL_audio_c.h"
    42 #include "SDL_audiomem.h"
    43 #include "SDL_sysaudio.h"
    44 
    45 #include "SDL_atarimxalloc_c.h"
    46 
    47 #include "SDL_mintaudio.h"
    48 #include "SDL_mintaudio_mcsn.h"
    49 
    50 /*--- Defines ---*/
    51 
    52 #define MINT_AUDIO_DRIVER_NAME "mint_mcsn"
    53 
    54 /* Debug print info */
    55 #define DEBUG_NAME "audio:mcsn: "
    56 #if 0
    57 #define DEBUG_PRINT(what) \
    58 	{ \
    59 		printf what; \
    60 	}
    61 #else
    62 #define DEBUG_PRINT(what)
    63 #endif
    64 
    65 /*--- Static variables ---*/
    66 
    67 static unsigned long cookie_snd, cookie_mch;
    68 static cookie_mcsn_t *cookie_mcsn;
    69 
    70 /*--- Audio driver functions ---*/
    71 
    72 static void Mint_CloseAudio(_THIS);
    73 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
    74 static void Mint_LockAudio(_THIS);
    75 static void Mint_UnlockAudio(_THIS);
    76 
    77 /* To check/init hardware audio */
    78 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
    79 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
    80 
    81 /*--- Audio driver bootstrap functions ---*/
    82 
    83 static int Audio_Available(void)
    84 {
    85 	const char *envr = getenv("SDL_AUDIODRIVER");
    86 
    87 	/* Check if user asked a different audio driver */
    88 	if ((envr) && (strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
    89 		DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
    90 		return(0);
    91 	}
    92 
    93 	/* Cookie _MCH present ? if not, assume ST machine */
    94 	if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
    95 		cookie_mch = MCH_ST;
    96 	}
    97 
    98 	/* Cookie _SND present ? if not, assume ST machine */
    99 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
   100 		cookie_snd = SND_PSG;
   101 	}
   102 
   103 	/* Check if we have 16 bits audio */
   104 	if ((cookie_snd & SND_16BIT)==0) {
   105 		DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
   106 	    return(0);
   107 	}
   108 
   109 	/* Cookie MCSN present ? */
   110 	if (Getcookie(C_McSn, (long *) &cookie_mcsn) != C_FOUND) {
   111 		DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n"));
   112 		return(0);
   113 	}
   114 
   115 	/* Check if interrupt at end of replay */
   116 	if (cookie_mcsn->pint == 0) {
   117 		DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n"));
   118 		return(0);
   119 	}
   120 
   121 	/* Check if audio is lockable */
   122 	if (Locksnd()!=1) {
   123 		DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
   124 		return(0);
   125 	}
   126 
   127 	Unlocksnd();
   128 
   129 	DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
   130 	return(1);
   131 }
   132 
   133 static void Audio_DeleteDevice(SDL_AudioDevice *device)
   134 {
   135     free(device->hidden);
   136     free(device);
   137 }
   138 
   139 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
   140 {
   141 	SDL_AudioDevice *this;
   142 
   143 	/* Initialize all variables that we clean on shutdown */
   144 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   145     if ( this ) {
   146         memset(this, 0, (sizeof *this));
   147         this->hidden = (struct SDL_PrivateAudioData *)
   148                 malloc((sizeof *this->hidden));
   149     }
   150     if ( (this == NULL) || (this->hidden == NULL) ) {
   151         SDL_OutOfMemory();
   152         if ( this ) {
   153             free(this);
   154         }
   155         return(0);
   156     }
   157     memset(this->hidden, 0, (sizeof *this->hidden));
   158 
   159     /* Set the function pointers */
   160     this->OpenAudio   = Mint_OpenAudio;
   161     this->CloseAudio  = Mint_CloseAudio;
   162     this->LockAudio   = Mint_LockAudio;
   163     this->UnlockAudio = Mint_UnlockAudio;
   164     this->free        = Audio_DeleteDevice;
   165 
   166     return this;
   167 }
   168 
   169 AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
   170 	MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver",
   171 	Audio_Available, Audio_CreateDevice
   172 };
   173 
   174 static void Mint_LockAudio(_THIS)
   175 {
   176 	/* Stop replay */
   177 	Buffoper(0);
   178 }
   179 
   180 static void Mint_UnlockAudio(_THIS)
   181 {
   182 	/* Restart replay */
   183 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   184 }
   185 
   186 static void Mint_CloseAudio(_THIS)
   187 {
   188 	/* Stop replay */
   189 	Buffoper(0);
   190 
   191 	/* Uninstall interrupt */
   192 	Jdisint(MFP_DMASOUND);
   193 
   194 	/* Wait if currently playing sound */
   195 	while (SDL_MintAudio_mutex != 0) {
   196 	}
   197 
   198 	/* Clear buffers */
   199 	if (SDL_MintAudio_audiobuf[0]) {
   200 		Mfree(SDL_MintAudio_audiobuf[0]);
   201 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   202 	}
   203 
   204 	/* Unlock sound system */
   205 	Unlocksnd();
   206 }
   207 
   208 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
   209 {
   210 	int i;
   211 	unsigned long masterclock, masterprediv;
   212 
   213 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
   214 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   215 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   216 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   217 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   218 
   219 	/* Check formats available */
   220 	MINTAUDIO_freqcount=0;
   221 	switch(cookie_mcsn->play) {
   222 		case MCSN_ST:
   223 			spec->channels=1;
   224 			spec->format=8; /* FIXME: is it signed or unsigned ? */
   225 			SDL_MintAudio_AddFrequency(this, 12500, 0, 0);
   226 			break;
   227 		case MCSN_TT:	/* Also STE, Mega STE */
   228 			spec->format=AUDIO_S8;
   229 			masterclock=MASTERCLOCK_STE;
   230 			masterprediv=MASTERPREDIV_STE;
   231 			if ((cookie_mch>>16)==MCH_TT) {
   232 				masterclock=MASTERCLOCK_TT;
   233 				masterprediv=MASTERPREDIV_TT;
   234 			}
   235 			for (i=0; i<4; i++) {
   236 				SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), masterclock, 3-i);
   237 			}
   238 			break;
   239 		case MCSN_FALCON:	/* Also Mac */
   240 			for (i=1; i<12; i++) {
   241 				/* Remove unusable Falcon codec predivisors */
   242 				if ((i==6) || (i==8) || (i==10)) {
   243 					continue;
   244 				}
   245 				SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), CLK25M, i+1);
   246 			}
   247 			if (cookie_mcsn->res1 != 0) {
   248 				for (i=1; i<4; i++) {
   249 					SDL_MintAudio_AddFrequency(this, (cookie_mcsn->res1)/(MASTERPREDIV_FALCON*(1<<i)), CLKEXT, (1<<i)-1);
   250 				}
   251 			}
   252 			spec->format |= 0x8000;	/* Audio is always signed */
   253 			if ((spec->format & 0x00ff)==16) {
   254 				spec->format |= 0x1000;	/* Audio is always big endian */
   255 				spec->channels=2;	/* 16 bits always stereo */
   256 			}
   257 			break;
   258 	}
   259 
   260 #if 1
   261 	for (i=0; i<MINTAUDIO_freqcount; i++) {
   262 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   263 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
   264 			MINTAUDIO_frequencies[i].predivisor
   265 		));
   266 	}
   267 #endif
   268 
   269 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
   270 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   271 
   272 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
   273 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   274 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   275 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   276 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   277 
   278 	return 0;
   279 }
   280 
   281 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
   282 {
   283 	int channels_mode, prediv, dmaclock;
   284 	void *buffer;
   285 
   286 	/* Stop currently playing sound */
   287 	Buffoper(0);
   288 
   289 	/* Set replay tracks */
   290 	Settracks(0,0);
   291 	Setmontracks(0);
   292 
   293 	/* Select replay format */
   294 	channels_mode=STEREO16;
   295 	switch (spec->format & 0xff) {
   296 		case 8:
   297 			if (spec->channels==2) {
   298 				channels_mode=STEREO8;
   299 			} else {
   300 				channels_mode=MONO8;
   301 			}
   302 			break;
   303 	}
   304 	if (Setmode(channels_mode)<0) {
   305 		DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
   306 	}
   307 
   308 	dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock;
   309 	prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   310 	switch(cookie_mcsn->play) {
   311 		case MCSN_TT:
   312 			Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, 1);
   313 			Soundcmd(SETPRESCALE, prediv);
   314 			DEBUG_PRINT((DEBUG_NAME "STE/TT prescaler selected\n"));
   315 			break;
   316 		case MCSN_FALCON:
   317 			Devconnect(DMAPLAY, DAC, dmaclock, prediv, 1);
   318 			DEBUG_PRINT((DEBUG_NAME "Falcon prescaler selected\n"));
   319 			break;
   320 	}
   321 
   322 	/* Set buffer */
   323 	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   324 	if (Setbuffer(0, buffer, buffer + spec->size)<0) {
   325 		DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
   326 	}
   327 	
   328 	/* Install interrupt */
   329 	Jdisint(MFP_DMASOUND);
   330 	Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
   331 	Jenabint(MFP_DMASOUND);
   332 
   333 	if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
   334 		DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
   335 	}
   336 
   337 	/* Go */
   338 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   339 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   340 }
   341 
   342 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
   343 {
   344 	/* Lock sound system */
   345 	if (Locksnd()!=1) {
   346    	    SDL_SetError("Mint_OpenAudio: Audio system already in use");
   347         return(-1);
   348 	}
   349 
   350 	SDL_MintAudio_device = this;
   351 
   352 	/* Check audio capabilities */
   353 	if (Mint_CheckAudio(this, spec)==-1) {
   354 		return -1;
   355 	}
   356 
   357 	SDL_CalculateAudioSpec(spec);
   358 
   359 	/* Allocate memory for audio buffers in DMA-able RAM */
   360 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
   361 
   362 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
   363 	if (SDL_MintAudio_audiobuf[0]==NULL) {
   364 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
   365 		return (-1);
   366 	}
   367 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
   368 	SDL_MintAudio_numbuf=0;
   369 	memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
   370 	SDL_MintAudio_audiosize = spec->size;
   371 	SDL_MintAudio_mutex = 0;
   372 
   373 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
   374 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
   375 
   376 	/* Setup audio hardware */
   377 	Mint_InitAudio(this, spec);
   378 
   379     return(1);	/* We don't use threaded audio */
   380 }