src/audio/mint/SDL_mintaudio_dma8.c
author Patrice Mandin
Fri, 29 Oct 2004 11:19:03 +0000
changeset 962 176240cf4405
parent 961 185acc07127a
child 1098 2911ff0a32bb
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 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 /*
   104 	if ((cookie_snd & SND_8BIT)==0) {
   105 		DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
   106 	    return(0);
   107 	}
   108 */
   109 	if ((cookie_mch>>16)>MCH_F30) {
   110 		DEBUG_PRINT((DEBUG_NAME "unknown 8 bits audio chip\n"));
   111 		return 0;
   112 	}
   113 
   114 	/* Check if audio is lockable */
   115 	if ((cookie_mch>>16) == MCH_F30) {
   116 		if (Locksnd()!=1) {
   117 			DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
   118 			return(0);
   119 		}
   120 
   121 		Unlocksnd();
   122 	}
   123 
   124 	DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
   125 	return(1);
   126 }
   127 
   128 static void Audio_DeleteDevice(SDL_AudioDevice *device)
   129 {
   130     free(device->hidden);
   131     free(device);
   132 }
   133 
   134 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
   135 {
   136 	SDL_AudioDevice *this;
   137 
   138 	/* Initialize all variables that we clean on shutdown */
   139 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   140     if ( this ) {
   141         memset(this, 0, (sizeof *this));
   142         this->hidden = (struct SDL_PrivateAudioData *)
   143                 malloc((sizeof *this->hidden));
   144     }
   145     if ( (this == NULL) || (this->hidden == NULL) ) {
   146         SDL_OutOfMemory();
   147         if ( this ) {
   148             free(this);
   149         }
   150         return(0);
   151     }
   152     memset(this->hidden, 0, (sizeof *this->hidden));
   153 
   154     /* Set the function pointers */
   155     this->OpenAudio   = Mint_OpenAudio;
   156     this->CloseAudio  = Mint_CloseAudio;
   157     this->LockAudio   = Mint_LockAudio;
   158     this->UnlockAudio = Mint_UnlockAudio;
   159     this->free        = Audio_DeleteDevice;
   160 
   161     return this;
   162 }
   163 
   164 AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
   165 	MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
   166 	Audio_Available, Audio_CreateDevice
   167 };
   168 
   169 static void Mint_LockAudio(_THIS)
   170 {
   171 	void *oldpile;
   172 
   173 	/* Stop replay */
   174 	oldpile=(void *)Super(0);
   175 	DMAAUDIO_IO.control=0;
   176 	Super(oldpile);
   177 }
   178 
   179 static void Mint_UnlockAudio(_THIS)
   180 {
   181 	void *oldpile;
   182 
   183 	/* Restart replay */
   184 	oldpile=(void *)Super(0);
   185 	DMAAUDIO_IO.control=3;
   186 	Super(oldpile);
   187 }
   188 
   189 static void Mint_CloseAudio(_THIS)
   190 {
   191 	void *oldpile;
   192 
   193 	/* Stop replay */
   194 	oldpile=(void *)Super(0);
   195 	DMAAUDIO_IO.control=0;
   196 	Super(oldpile);
   197 
   198 	DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
   199 
   200 	/* Disable interrupt */
   201 	Jdisint(MFP_DMASOUND);
   202 
   203 	DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
   204 
   205 	/* Wait if currently playing sound */
   206 	while (SDL_MintAudio_mutex != 0) {
   207 	}
   208 
   209 	DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
   210 
   211 	/* Clear buffers */
   212 	if (SDL_MintAudio_audiobuf[0]) {
   213 		Mfree(SDL_MintAudio_audiobuf[0]);
   214 		SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   215 	}
   216 
   217 	DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
   218 }
   219 
   220 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
   221 {
   222 	int i, masterprediv, sfreq;
   223 	unsigned long masterclock;
   224 
   225 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
   226 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   227 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   228 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   229 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   230 
   231 	/* Check formats available */
   232 	spec->format = AUDIO_S8;
   233 	
   234 	/* Calculate and select the closest frequency */
   235 	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;
   252 			sfreq=1;
   253 			break;
   254 	}
   255 	
   256 	MINTAUDIO_freqcount=0;
   257 	for (i=sfreq;i<4;i++) {
   258 		SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), masterclock, i-sfreq);
   259 	}
   260 
   261 #if 1
   262 	for (i=0; i<MINTAUDIO_freqcount; i++) {
   263 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   264 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
   265 			MINTAUDIO_frequencies[i].predivisor
   266 		));
   267 	}
   268 #endif
   269 
   270 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
   271 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   272 
   273 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
   274 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   275 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   276 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   277 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   278 
   279 	return 0;
   280 }
   281 
   282 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
   283 {
   284 	void *oldpile;
   285 	unsigned long buffer;
   286 	unsigned char mode;
   287 	
   288 	/* Set replay tracks */
   289 	if (cookie_snd & SND_16BIT) {
   290 		Settracks(0,0);
   291 		Setmontracks(0);
   292 	}
   293 
   294 	oldpile=(void *)Super(0);
   295 
   296 	/* Stop currently playing sound */
   297 	DMAAUDIO_IO.control=0;
   298 
   299 	/* Set buffer */
   300 	buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   301 	DMAAUDIO_IO.start_high = (buffer>>16) & 255;
   302 	DMAAUDIO_IO.start_mid = (buffer>>8) & 255;
   303 	DMAAUDIO_IO.start_low = buffer & 255;
   304 
   305 	buffer += SDL_MintAudio_audiosize;
   306 	DMAAUDIO_IO.end_high = (buffer>>16) & 255;
   307 	DMAAUDIO_IO.end_mid = (buffer>>8) & 255;
   308 	DMAAUDIO_IO.end_low = buffer & 255;
   309 
   310 	mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   311 	if (spec->channels==1) {
   312 		mode |= 1<<7;
   313 	}
   314 	DMAAUDIO_IO.sound_ctrl = mode;	
   315 
   316 	/* Set interrupt */
   317 	Jdisint(MFP_DMASOUND);
   318 	Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
   319 	Jenabint(MFP_DMASOUND);
   320 
   321 	/* Go */
   322 	DMAAUDIO_IO.control = 3;	/* playback + repeat */
   323 
   324 	Super(oldpile);
   325 }
   326 
   327 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
   328 {
   329 	SDL_MintAudio_device = this;
   330 
   331 	/* Check audio capabilities */
   332 	if (Mint_CheckAudio(this, spec)==-1) {
   333 		return -1;
   334 	}
   335 
   336 	SDL_CalculateAudioSpec(spec);
   337 
   338 	/* Allocate memory for audio buffers in DMA-able RAM */
   339 	DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
   340 
   341 	SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
   342 	if (SDL_MintAudio_audiobuf[0]==NULL) {
   343 		SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
   344 		return (-1);
   345 	}
   346 	SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
   347 	SDL_MintAudio_numbuf=0;
   348 	memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
   349 	SDL_MintAudio_audiosize = spec->size;
   350 	SDL_MintAudio_mutex = 0;
   351 
   352 	DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
   353 	DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
   354 
   355 	/* Setup audio hardware */
   356 	Mint_InitAudio(this, spec);
   357 
   358     return(1);	/* We don't use threaded audio */
   359 }