src/audio/mint/SDL_mintaudio_xbios.c
author Patrice Mandin <patmandin@gmail.com>
Mon, 07 Jul 2003 19:16:03 +0000
changeset 644 594422ab8f9f
child 704 c4803992e09c
permissions -rw-r--r--
Atari MiNT: added more audio drivers
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  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 (Falcon)
    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 
    49 /*--- Defines ---*/
    50 
    51 #define MINT_AUDIO_DRIVER_NAME "mint_xbios"
    52 
    53 /* Debug print info */
    54 #define DEBUG_NAME "audio:xbios: "
    55 #if 0
    56 #define DEBUG_PRINT(what) \
    57 	{ \
    58 		printf what; \
    59 	}
    60 #else
    61 #define DEBUG_PRINT(what)
    62 #endif
    63 
    64 /*--- Static variables ---*/
    65 
    66 static unsigned long cookie_snd;
    67 
    68 /*--- Audio driver functions ---*/
    69 
    70 static void Mint_CloseAudio(_THIS);
    71 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
    72 static void Mint_LockAudio(_THIS);
    73 static void Mint_UnlockAudio(_THIS);
    74 
    75 /* To check/init hardware audio */
    76 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
    77 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
    78 
    79 /*--- Audio driver bootstrap functions ---*/
    80 
    81 static int Audio_Available(void)
    82 {
    83 	const char *envr = getenv("SDL_AUDIODRIVER");
    84 
    85 	/* Check if user asked a different audio driver */
    86 	if ((envr) && (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 _SND present ? if not, assume ST machine */
    92 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
    93 		cookie_snd = SND_PSG;
    94 	}
    95 
    96 	/* Check if we have 16 bits audio */
    97 	if ((cookie_snd & SND_16BIT)==0) {
    98 		DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
    99 	    return(0);
   100 	}
   101 
   102 	/* Check if audio is lockable */
   103 	if (Locksnd()!=1) {
   104 		DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
   105 		return(0);
   106 	}
   107 
   108 	Unlocksnd();
   109 
   110 	DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
   111 	return(1);
   112 }
   113 
   114 static void Audio_DeleteDevice(SDL_AudioDevice *device)
   115 {
   116     free(device->hidden);
   117     free(device);
   118 }
   119 
   120 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
   121 {
   122 	SDL_AudioDevice *this;
   123 
   124 	/* Initialize all variables that we clean on shutdown */
   125 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   126     if ( this ) {
   127         memset(this, 0, (sizeof *this));
   128         this->hidden = (struct SDL_PrivateAudioData *)
   129                 malloc((sizeof *this->hidden));
   130     }
   131     if ( (this == NULL) || (this->hidden == NULL) ) {
   132         SDL_OutOfMemory();
   133         if ( this ) {
   134             free(this);
   135         }
   136         return(0);
   137     }
   138     memset(this->hidden, 0, (sizeof *this->hidden));
   139 
   140     /* Set the function pointers */
   141     this->OpenAudio   = Mint_OpenAudio;
   142     this->CloseAudio  = Mint_CloseAudio;
   143     this->LockAudio   = Mint_LockAudio;
   144     this->UnlockAudio = Mint_UnlockAudio;
   145     this->free        = Audio_DeleteDevice;
   146 
   147     return this;
   148 }
   149 
   150 AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
   151 	MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver",
   152 	Audio_Available, Audio_CreateDevice
   153 };
   154 
   155 static void Mint_LockAudio(_THIS)
   156 {
   157 	/* Stop replay */
   158 	Buffoper(0);
   159 }
   160 
   161 static void Mint_UnlockAudio(_THIS)
   162 {
   163 	/* Restart replay */
   164 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   165 }
   166 
   167 static void Mint_CloseAudio(_THIS)
   168 {
   169 	/* Stop replay */
   170 	Buffoper(0);
   171 
   172 	/* Uninstall interrupt */
   173 	Jdisint(MFP_DMASOUND);
   174 
   175 	/* Wait if currently playing sound */
   176 	while (SDL_MintAudio_mutex != 0) {
   177 	}
   178 
   179 	/* Clear buffers */
   180 	if (SDL_MintAudio_audiobuf[0]) {
   181 		Mfree(SDL_MintAudio_audiobuf[0]);
   182 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   183 	}
   184 
   185 	/* Unlock sound system */
   186 	Unlocksnd();
   187 }
   188 
   189 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
   190 {
   191 	int i;
   192 
   193 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
   194 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   195 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x8000)!=0)));
   196 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   197 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   198 
   199 	spec->format |= 0x8000;	/* Audio is always signed */
   200 	if ((spec->format & 0x00ff)==16) {
   201 		spec->format |= 0x1000;	/* Audio is always big endian */
   202 		spec->channels=2;	/* 16 bits always stereo */
   203 	}
   204 
   205 	/* FIXME: check for an external clock */
   206 	MINTAUDIO_sfreq=1;
   207 	MINTAUDIO_nfreq=12;
   208 	for (i=MINTAUDIO_sfreq;i<MINTAUDIO_nfreq;i++) {
   209 		MINTAUDIO_hardfreq[i]=MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1));
   210 		DEBUG_PRINT((DEBUG_NAME "calc:freq(%d)=%lu\n", i, MINTAUDIO_hardfreq[i]));
   211 	}
   212 
   213 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, 1, spec->freq);
   214 	spec->freq=MINTAUDIO_hardfreq[MINTAUDIO_numfreq];
   215 
   216 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
   217 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   218 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x8000)!=0)));
   219 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   220 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   221 
   222 	return 0;
   223 }
   224 
   225 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
   226 {
   227 	int channels_mode;
   228 	void *buffer;
   229 
   230 	/* Stop currently playing sound */
   231 	Buffoper(0);
   232 
   233 	/* Set replay tracks */
   234 	Settracks(0,0);
   235 	Setmontracks(0);
   236 
   237 	/* Select replay format */
   238 	channels_mode=STEREO16;
   239 	switch (spec->format & 0xff) {
   240 		case 8:
   241 			if (spec->channels==2) {
   242 				channels_mode=STEREO8;
   243 			} else {
   244 				channels_mode=MONO8;
   245 			}
   246 			break;
   247 	}
   248 	if (Setmode(channels_mode)<0) {
   249 		DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
   250 	}
   251 
   252 	/* FIXME: select an external clock */
   253 
   254 	Devconnect(DMAPLAY, DAC, CLK25M, MINTAUDIO_numfreq, 1);
   255 	DEBUG_PRINT((DEBUG_NAME "25.175 MHz clock selected, prescaler %d\n", MINTAUDIO_numfreq));
   256 
   257 	/* Set buffer */
   258 	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   259 	if (Setbuffer(0, buffer, buffer + spec->size)<0) {
   260 		DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
   261 	}
   262 	
   263 	/* Install interrupt */
   264 	Jdisint(MFP_DMASOUND);
   265 	Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
   266 	Jenabint(MFP_DMASOUND);
   267 
   268 	if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
   269 		DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
   270 	}
   271 
   272 	/* Go */
   273 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   274 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   275 }
   276 
   277 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
   278 {
   279 	/* Lock sound system */
   280 	if (Locksnd()!=1) {
   281    	    SDL_SetError("Mint_OpenAudio: Audio system already in use");
   282         return(-1);
   283 	}
   284 
   285 	SDL_MintAudio_device = this;
   286 
   287 	/* Check audio capabilities */
   288 	if (Mint_CheckAudio(this, spec)==-1) {
   289 		return -1;
   290 	}
   291 
   292 	SDL_CalculateAudioSpec(spec);
   293 
   294 	/* Allocate memory for audio buffers in DMA-able RAM */
   295 	spec->size = spec->samples;
   296 	spec->size *= spec->channels;
   297 	spec->size *= (spec->format & 0xFF)/8;
   298 
   299 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
   300 
   301 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
   302 	if (SDL_MintAudio_audiobuf[0]==NULL) {
   303 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
   304 		return (-1);
   305 	}
   306 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
   307 	SDL_MintAudio_numbuf=0;
   308 	memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
   309 	SDL_MintAudio_audiosize = spec->size;
   310 	SDL_MintAudio_mutex = 0;
   311 
   312 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
   313 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
   314 
   315 	/* Setup audio hardware */
   316 	Mint_InitAudio(this, spec);
   317 
   318     return(1);	/* We don't use threaded audio */
   319 }