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