src/audio/mint/SDL_mintaudio_gsxb.c
author Patrice Mandin
Fri, 29 Oct 2004 11:19:03 +0000
changeset 962 176240cf4405
parent 961 185acc07127a
child 1097 c83fa1c650dd
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 (GSXB 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_gsxb.h"
    49 
    50 /*--- Defines ---*/
    51 
    52 #define MINT_AUDIO_DRIVER_NAME "mint_gsxb"
    53 
    54 /* Debug print info */
    55 #define DEBUG_NAME "audio:gsxb: "
    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_gsxb;
    68 
    69 /*--- Audio driver functions ---*/
    70 
    71 static void Mint_CloseAudio(_THIS);
    72 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
    73 static void Mint_LockAudio(_THIS);
    74 static void Mint_UnlockAudio(_THIS);
    75 
    76 /* To check/init hardware audio */
    77 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
    78 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
    79 
    80 /*--- Audio driver bootstrap functions ---*/
    81 
    82 static int Audio_Available(void)
    83 {
    84 	const char *envr = getenv("SDL_AUDIODRIVER");
    85 
    86 	/* Check if user asked a different audio driver */
    87 	if ((envr) && (strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
    88 		DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
    89 		return(0);
    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 16 bits audio */
    98 	if ((cookie_snd & SND_16BIT)==0) {
    99 		DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
   100 	    return(0);
   101 	}
   102 
   103 	/* Cookie GSXB present ? */
   104 	cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
   105 
   106 	/* Is it GSXB ? */
   107 	if (((cookie_snd & SND_GSXB)==0) || (cookie_gsxb==0)) {
   108 		DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n"));
   109 		return(0);
   110 	}
   111 
   112 	/* Check if audio is lockable */
   113 	if (Locksnd()!=1) {
   114 		DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
   115 		return(0);
   116 	}
   117 
   118 	Unlocksnd();
   119 
   120 	DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
   121 	return(1);
   122 }
   123 
   124 static void Audio_DeleteDevice(SDL_AudioDevice *device)
   125 {
   126     free(device->hidden);
   127     free(device);
   128 }
   129 
   130 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
   131 {
   132 	SDL_AudioDevice *this;
   133 
   134 	/* Initialize all variables that we clean on shutdown */
   135 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   136     if ( this ) {
   137         memset(this, 0, (sizeof *this));
   138         this->hidden = (struct SDL_PrivateAudioData *)
   139                 malloc((sizeof *this->hidden));
   140     }
   141     if ( (this == NULL) || (this->hidden == NULL) ) {
   142         SDL_OutOfMemory();
   143         if ( this ) {
   144             free(this);
   145         }
   146         return(0);
   147     }
   148     memset(this->hidden, 0, (sizeof *this->hidden));
   149 
   150     /* Set the function pointers */
   151     this->OpenAudio   = Mint_OpenAudio;
   152     this->CloseAudio  = Mint_CloseAudio;
   153     this->LockAudio   = Mint_LockAudio;
   154     this->UnlockAudio = Mint_UnlockAudio;
   155     this->free        = Audio_DeleteDevice;
   156 
   157     return this;
   158 }
   159 
   160 AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
   161 	MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
   162 	Audio_Available, Audio_CreateDevice
   163 };
   164 
   165 static void Mint_LockAudio(_THIS)
   166 {
   167 	/* Stop replay */
   168 	Buffoper(0);
   169 }
   170 
   171 static void Mint_UnlockAudio(_THIS)
   172 {
   173 	/* Restart replay */
   174 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   175 }
   176 
   177 static void Mint_CloseAudio(_THIS)
   178 {
   179 	/* Stop replay */
   180 	Buffoper(0);
   181 
   182 	/* Uninstall interrupt */
   183 	if (NSetinterrupt(2, SI_NONE, SDL_MintAudio_EmptyGsxbInterrupt)<0) {
   184 		DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
   185 	}
   186 
   187 	/* Wait if currently playing sound */
   188 	while (SDL_MintAudio_mutex != 0) {
   189 	}
   190 
   191 	/* Clear buffers */
   192 	if (SDL_MintAudio_audiobuf[0]) {
   193 		Mfree(SDL_MintAudio_audiobuf[0]);
   194 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   195 	}
   196 
   197 	/* Unlock sound system */
   198 	Unlocksnd();
   199 }
   200 
   201 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
   202 {
   203 	long snd_format;
   204 	int i, resolution, format_signed, format_bigendian;
   205 
   206 	resolution = spec->format & 0x00ff;
   207 	format_signed = ((spec->format & 0x8000)!=0);
   208 	format_bigendian = ((spec->format & 0x1000)!=0);
   209 
   210 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
   211 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   212 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   213 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   214 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   215 
   216 	/* Check formats available */
   217 	snd_format = Sndstatus(SND_QUERYFORMATS);
   218 	switch (resolution) {
   219 		case 8:
   220 			if ((snd_format & SND_FORMAT8)==0) {
   221 				SDL_SetError("Mint_CheckAudio: 8 bits samples not supported");
   222 				return -1;
   223 			}
   224 			snd_format = Sndstatus(SND_QUERY8BIT);
   225 			break;
   226 		case 16:
   227 			if ((snd_format & SND_FORMAT16)==0) {
   228 				SDL_SetError("Mint_CheckAudio: 16 bits samples not supported");
   229 				return -1;
   230 			}
   231 			snd_format = Sndstatus(SND_QUERY16BIT);
   232 			break;
   233 		default:
   234 			SDL_SetError("Mint_CheckAudio: Unsupported sample resolution");
   235 			return -1;
   236 			break;
   237 	}
   238 
   239 	/* Check signed/unsigned format */
   240 	if (format_signed) {
   241 		if (snd_format & SND_FORMATSIGNED) {
   242 			/* Ok */
   243 		} else if (snd_format & SND_FORMATUNSIGNED) {
   244 			/* Give unsigned format */
   245 			spec->format = spec->format & (~0x8000);
   246 		}
   247 	} else {
   248 		if (snd_format & SND_FORMATUNSIGNED) {
   249 			/* Ok */
   250 		} else if (snd_format & SND_FORMATSIGNED) {
   251 			/* Give signed format */
   252 			spec->format |= 0x8000;
   253 		}
   254 	}
   255 
   256 	if (format_bigendian) {
   257 		if (snd_format & SND_FORMATBIGENDIAN) {
   258 			/* Ok */
   259 		} else if (snd_format & SND_FORMATLITTLEENDIAN) {
   260 			/* Give little endian format */
   261 			spec->format = spec->format & (~0x1000);
   262 		}
   263 	} else {
   264 		if (snd_format & SND_FORMATLITTLEENDIAN) {
   265 			/* Ok */
   266 		} else if (snd_format & SND_FORMATBIGENDIAN) {
   267 			/* Give big endian format */
   268 			spec->format |= 0x1000;
   269 		}
   270 	}
   271 	
   272 	/* Calculate and select the closest frequency */
   273 	MINTAUDIO_freqcount=0;
   274 	for (i=1;i<4;i++) {
   275 		SDL_MintAudio_AddFrequency(this, MASTERCLOCK_44K/(MASTERPREDIV_MILAN*(1<<i)), MASTERCLOCK_44K, (1<<i)-1);
   276 	}
   277 
   278 #if 1
   279 	for (i=0; i<MINTAUDIO_freqcount; i++) {
   280 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   281 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
   282 			MINTAUDIO_frequencies[i].predivisor
   283 		));
   284 	}
   285 #endif
   286 
   287 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
   288 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   289 
   290 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
   291 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   292 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   293 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   294 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   295 
   296 	return 0;
   297 }
   298 
   299 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
   300 {
   301 	int channels_mode, prediv;
   302 	void *buffer;
   303 
   304 	/* Stop currently playing sound */
   305 	Buffoper(0);
   306 
   307 	/* Set replay tracks */
   308 	Settracks(0,0);
   309 	Setmontracks(0);
   310 
   311 	/* Select replay format */
   312 	switch (spec->format & 0xff) {
   313 		case 8:
   314 			if (spec->channels==2) {
   315 				channels_mode=STEREO8;
   316 			} else {
   317 				channels_mode=MONO8;
   318 			}
   319 			break;
   320 		case 16:
   321 			if (spec->channels==2) {
   322 				channels_mode=STEREO16;
   323 			} else {
   324 				channels_mode=MONO16;
   325 			}
   326 			break;
   327 		default:
   328 			channels_mode=STEREO16;
   329 			break;
   330 	}
   331 	if (Setmode(channels_mode)<0) {
   332 		DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
   333 	}
   334 
   335 	prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   336 	Devconnect(DMAPLAY, DAC, CLKEXT, prediv, 1);
   337 
   338 	/* Set buffer */
   339 	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   340 	if (Setbuffer(0, buffer, buffer + spec->size)<0) {
   341 		DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
   342 	}
   343 	
   344 	/* Install interrupt */
   345 	if (NSetinterrupt(2, SI_PLAY, SDL_MintAudio_GsxbInterrupt)<0) {
   346 		DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
   347 	}
   348 
   349 	/* Go */
   350 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   351 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   352 }
   353 
   354 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
   355 {
   356 	/* Lock sound system */
   357 	if (Locksnd()!=1) {
   358    	    SDL_SetError("Mint_OpenAudio: Audio system already in use");
   359         return(-1);
   360 	}
   361 
   362 	SDL_MintAudio_device = this;
   363 
   364 	/* Check audio capabilities */
   365 	if (Mint_CheckAudio(this, spec)==-1) {
   366 		return -1;
   367 	}
   368 
   369 	SDL_CalculateAudioSpec(spec);
   370 
   371 	/* Allocate memory for audio buffers in DMA-able RAM */
   372 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
   373 
   374 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
   375 	if (SDL_MintAudio_audiobuf[0]==NULL) {
   376 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
   377 		return (-1);
   378 	}
   379 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
   380 	SDL_MintAudio_numbuf=0;
   381 	memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
   382 	SDL_MintAudio_audiosize = spec->size;
   383 	SDL_MintAudio_mutex = 0;
   384 
   385 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
   386 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
   387 
   388 	/* Setup audio hardware */
   389 	Mint_InitAudio(this, spec);
   390 
   391     return(1);	/* We don't use threaded audio */
   392 }