src/audio/mint/SDL_mintaudio_xbios.c
author Ozkan Sezer <sezeroz@gmail.com>
Sat, 14 Sep 2019 17:00:50 +0300
branchSDL-1.2
changeset 13077 cd46eb772bee
parent 9022 de368e497138
permissions -rw-r--r--
make SDL_qsort.c to actually link (missing SDL_stdinc.h include)

also sync its comments with version 1.15 from mainstream
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2012 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 #include "SDL_config.h"
    23 
    24 /*
    25 	MiNT audio driver
    26 	using XBIOS functions (Falcon)
    27 
    28 	Patrice Mandin, Didier Méquignon
    29 */
    30 
    31 #include <unistd.h>
    32 #include <support.h>
    33 
    34 /* Mint includes */
    35 #include <mint/osbind.h>
    36 #include <mint/falcon.h>
    37 #include <mint/cookie.h>
    38 
    39 #include "SDL_audio.h"
    40 #include "../SDL_audio_c.h"
    41 #include "../SDL_sysaudio.h"
    42 
    43 #include "../../video/ataricommon/SDL_atarimxalloc_c.h"
    44 #include "../../video/ataricommon/SDL_atarisuper.h"
    45 
    46 #include "SDL_mintaudio.h"
    47 #include "SDL_mintaudio_dma8.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 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 static void Mint_SwapBuffers(Uint8 *nextbuf, int nextsize);
    79 
    80 /*--- Audio driver bootstrap functions ---*/
    81 
    82 static int Audio_Available(void)
    83 {
    84 /*	unsigned long dummy;*/
    85 	const char *envr = SDL_getenv("SDL_AUDIODRIVER");
    86 
    87 	/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);*/
    88 	SDL_MintAudio_mint_present = SDL_FALSE;
    89 
    90 	/* We can't use XBIOS in interrupt with Magic, don't know about thread */
    91 	/*if (Getcookie(C_MagX, &dummy) == C_FOUND) {
    92 		return(0);
    93 	}*/
    94 
    95 	/* Check if user asked a different audio driver */
    96 	if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
    97 		DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
    98 		return(0);
    99 	}
   100 
   101 	/* Cookie _SND present ? if not, assume ST machine */
   102 	if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
   103 		cookie_snd = SND_PSG;
   104 	}
   105 
   106 	/* Check if we have 16 bits audio */
   107 	if ((cookie_snd & SND_16BIT)==0) {
   108 		DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\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 "XBIOS audio available!\n"));
   121 	return(1);
   122 }
   123 
   124 static void Audio_DeleteDevice(SDL_AudioDevice *device)
   125 {
   126     SDL_free(device->hidden);
   127     SDL_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 *)SDL_malloc(sizeof(SDL_AudioDevice));
   136     if ( this ) {
   137         SDL_memset(this, 0, (sizeof *this));
   138         this->hidden = (struct SDL_PrivateAudioData *)
   139                 SDL_malloc((sizeof *this->hidden));
   140     }
   141     if ( (this == NULL) || (this->hidden == NULL) ) {
   142         SDL_OutOfMemory();
   143         if ( this ) {
   144             SDL_free(this);
   145         }
   146         return(0);
   147     }
   148     SDL_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_XBIOS_bootstrap = {
   161 	MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS 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 	SDL_MintAudio_WaitThread();
   181 	Buffoper(0);
   182 
   183 	if (!SDL_MintAudio_mint_present) {
   184 		/* Uninstall interrupt */
   185 		Jdisint(MFP_DMASOUND);
   186 	}
   187 
   188 	SDL_MintAudio_FreeBuffers();
   189 
   190 	/* Unlock sound system */
   191 	Unlocksnd();
   192 }
   193 
   194 /* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
   195 static void Devconnect2(int src, int dst, int sclk, int pre)
   196 {		
   197 	static const unsigned short MASK1[3] = { 0, 0x6000, 0 };
   198 	static const unsigned short MASK2[4] = { 0xFFF0, 0xFF8F, 0xF0FF, 0x0FFF };
   199 	static const unsigned short INDEX1[4] = {  1, 3, 5, 7 };
   200 	static const unsigned short INDEX2[4] = {  0, 2, 4, 6 };
   201 	unsigned short sync_div,dev_ctrl,dest_ctrl;
   202 	void *oldstack;
   203 
   204 	if (dst==0) {
   205 		return;
   206 	}
   207 
   208 	oldstack=(void *)Super(0);
   209 
   210 	dev_ctrl = DMAAUDIO_IO.dev_ctrl;
   211 	dest_ctrl = DMAAUDIO_IO.dest_ctrl;
   212 	dev_ctrl &= MASK2[src];
   213 
   214 	if (src==ADC) {
   215 		dev_ctrl |= MASK1[sclk];
   216 	} else {
   217 		dev_ctrl |= (INDEX1[sclk] << (src<<4));
   218 	}
   219 
   220 	if (dst & DMAREC) {		
   221 		dest_ctrl &= 0xFFF0;
   222 		dest_ctrl |= INDEX1[src];
   223 	}
   224 
   225 	if (dst & DSPRECV) {		
   226 		dest_ctrl &= 0xFF8F;
   227 		dest_ctrl |= (INDEX1[src]<<4); 
   228 	}
   229 
   230 	if (dst & EXTOUT) {		
   231 		dest_ctrl &= 0xF0FF;
   232 		dest_ctrl |= (INDEX1[src]<<8); 
   233 	}
   234 
   235 	if (dst & DAC) {		
   236 		dev_ctrl &= 0x0FFF;
   237 		dev_ctrl |= MASK1[sclk]; 
   238 		dest_ctrl &=  0x0FFF;
   239 		dest_ctrl |= (INDEX2[src]<<12); 
   240 	}
   241 
   242 	sync_div = DMAAUDIO_IO.sync_div;
   243 	if (sclk==CLKEXT) {
   244 		pre<<=8;
   245 		sync_div &= 0xF0FF;
   246 	} else {
   247 		sync_div &= 0xFFF0;
   248 	}
   249 	sync_div |= pre;
   250 
   251 	DMAAUDIO_IO.dev_ctrl = dev_ctrl;
   252 	DMAAUDIO_IO.dest_ctrl = dest_ctrl;
   253 	DMAAUDIO_IO.sync_div = sync_div;
   254 
   255 	SuperToUser(oldstack);
   256 }
   257 
   258 static void Mint_CheckExternalClock(_THIS)
   259 {
   260 #define SIZE_BUF_CLOCK_MEASURE (44100/10)
   261 
   262 	char *buffer;
   263 	int i, j;
   264 
   265 	/* DSP present with its GPIO port ? */
   266 	if ((cookie_snd & SND_DSP)==0) {
   267 		return;
   268 	}
   269 
   270 	buffer = Atari_SysMalloc(SIZE_BUF_CLOCK_MEASURE, MX_STRAM);
   271 	if (buffer==NULL) {
   272 		DEBUG_PRINT((DEBUG_NAME "Not enough memory for the measure\n"));
   273 		return;
   274 	}
   275 	SDL_memset(buffer, 0, SIZE_BUF_CLOCK_MEASURE);
   276 
   277 	Buffoper(0);
   278 	Settracks(0,0);
   279 	Setmontracks(0);
   280 	Setmode(MONO8);
   281 	Jdisint(MFP_TIMERA);
   282 
   283 	for (i=0; i<2; i++) {
   284 		Gpio(GPIO_SET,7);      /* DSP port gpio outputs */
   285 		Gpio(GPIO_WRITE,2+i);  /* 22.5792/24.576 MHz for 44.1/48KHz */
   286 		Devconnect2(DMAPLAY, DAC, CLKEXT, CLK50K);  /* Matrix and clock source */
   287 		Setbuffer(0, buffer, buffer + SIZE_BUF_CLOCK_MEASURE);		           /* Set buffer */
   288 		Xbtimer(XB_TIMERA, 5, 38, SDL_MintAudio_XbiosInterruptMeasureClock); /* delay mode timer A, prediv /64, 1KHz */
   289 		Jenabint(MFP_TIMERA);
   290 		SDL_MintAudio_clocktics = 0;
   291 		Buffoper(SB_PLA_ENA);
   292 		usleep(110000);
   293 
   294 		if((Buffoper(-1) & 1)==0) {
   295 			if (SDL_MintAudio_clocktics) {
   296 				unsigned long khz;
   297 
   298 				khz = ((SIZE_BUF_CLOCK_MEASURE/SDL_MintAudio_clocktics) +1) & 0xFFFFFFFE;
   299 				DEBUG_PRINT((DEBUG_NAME "measure %d: freq=%lu KHz\n", i+1, khz));
   300 
   301 				if(khz==44) {
   302 					for (j=1; j<4; j++) {
   303 						SDL_MintAudio_AddFrequency(this, MASTERCLOCK_44K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_44K, (1<<j)-1, 2+i);
   304 					}
   305 				} else if (khz==48) {
   306 					for (j=1; j<4; j++) {
   307 						SDL_MintAudio_AddFrequency(this, MASTERCLOCK_48K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_48K, (1<<j)-1, 2+i);
   308 					}
   309 				}
   310 			} else {
   311 				DEBUG_PRINT((DEBUG_NAME "No measure\n"));
   312 			}
   313 		} else {
   314 			DEBUG_PRINT((DEBUG_NAME "No SDMA clock\n"));
   315 		}
   316 
   317 		Buffoper(0);             /* stop */
   318 		Jdisint(MFP_TIMERA);     /* Uninstall interrupt */
   319 	}
   320 
   321 	Mfree(buffer);
   322 }
   323 
   324 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
   325 {
   326 	int i;
   327 
   328 	DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
   329 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   330 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   331 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   332 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   333 
   334     if (spec->channels > 2) {
   335         spec->channels = 2;  /* no more than stereo! */
   336     }
   337 
   338 	spec->format |= 0x8000;	/* Audio is always signed */
   339 	if ((spec->format & 0x00ff)==16) {
   340 		spec->format |= 0x1000;	/* Audio is always big endian */
   341 		spec->channels=2;	/* 16 bits always stereo */
   342 	}
   343 
   344 	MINTAUDIO_freqcount=0;
   345 
   346 	/* Add external clocks if present */
   347 	Mint_CheckExternalClock(this);
   348 
   349 	/* Standard clocks */
   350 	for (i=1;i<12;i++) {
   351 		/* Remove unusable Falcon codec predivisors */
   352 		if ((i==6) || (i==8) || (i==10)) {
   353 			continue;
   354 		}
   355 		SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), MASTERCLOCK_FALCON1, i, -1);
   356 	}
   357 
   358 #if 1
   359 	for (i=0; i<MINTAUDIO_freqcount; i++) {
   360 		DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   361 			i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
   362 			MINTAUDIO_frequencies[i].predivisor
   363 		));
   364 	}
   365 #endif
   366 
   367 	MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
   368 	spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   369 
   370 	DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
   371 	DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
   372 	DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
   373 	DEBUG_PRINT(("channels=%d, ", spec->channels));
   374 	DEBUG_PRINT(("freq=%d\n", spec->freq));
   375 
   376 	return 0;
   377 }
   378 
   379 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
   380 {
   381 	int channels_mode, prediv;
   382 
   383 	/* Stop currently playing sound */
   384 	SDL_MintAudio_quit_thread = SDL_FALSE;
   385 	SDL_MintAudio_thread_finished = SDL_TRUE;
   386 	SDL_MintAudio_WaitThread();
   387 	Buffoper(0);
   388 
   389 	/* Set replay tracks */
   390 	Settracks(0,0);
   391 	Setmontracks(0);
   392 
   393 	/* Select replay format */
   394 	channels_mode=STEREO16;
   395 	switch (spec->format & 0xff) {
   396 		case 8:
   397 			if (spec->channels==2) {
   398 				channels_mode=STEREO8;
   399 			} else {
   400 				channels_mode=MONO8;
   401 			}
   402 			break;
   403 	}
   404 	if (Setmode(channels_mode)<0) {
   405 		DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
   406 	}
   407 
   408 	prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   409 	if (MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits != -1) {
   410 		Gpio(GPIO_SET,7);		/* DSP port gpio outputs */
   411 		Gpio(GPIO_WRITE, MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits);
   412 		Devconnect2(DMAPLAY, DAC|EXTOUT, CLKEXT, prediv);
   413 	} else {
   414 		Devconnect2(DMAPLAY, DAC, CLK25M, prediv);
   415 	}
   416 
   417 	/* Set buffer */
   418 	Mint_SwapBuffers(MINTAUDIO_audiobuf[0], MINTAUDIO_audiosize);
   419 	
   420 	if (SDL_MintAudio_mint_present) {
   421 		SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
   422 	} else {
   423 		/* Install interrupt */
   424 		Jdisint(MFP_DMASOUND);
   425 		Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
   426 		/*Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);*/
   427 		Jenabint(MFP_DMASOUND);
   428 
   429 		if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
   430 			DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
   431 		}
   432 	}
   433 
   434 	/* Go */
   435 	Buffoper(SB_PLA_ENA|SB_PLA_RPT);
   436 	DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   437 }
   438 
   439 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
   440 {
   441 	/* Lock sound system */
   442 	if (Locksnd()!=1) {
   443    	    SDL_SetError("Mint_OpenAudio: Audio system already in use");
   444         return(-1);
   445 	}
   446 
   447 	SDL_MintAudio_device = this;
   448 
   449 	/* Check audio capabilities */
   450 	if (Mint_CheckAudio(this, spec)==-1) {
   451 		return -1;
   452 	}
   453 
   454 	if (!SDL_MintAudio_InitBuffers(spec)) {
   455 		return -1;
   456 	}
   457 
   458 	/* Setup audio hardware */
   459 	MINTAUDIO_swapbuf = Mint_SwapBuffers;
   460 	Mint_InitAudio(this, spec);
   461 
   462     return(1);	/* We don't use SDL threaded audio */
   463 }
   464 
   465 static void Mint_SwapBuffers(Uint8 *nextbuf, int nextsize)
   466 {
   467 	unsigned long buffer = (unsigned long) nextbuf;
   468 
   469 	Setbuffer(0, buffer, buffer + nextsize);
   470 }