Home | History | Annotate | Download | only in mint
      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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /*
     25 	Audio interrupt variables and callback function
     26 
     27 	Patrice Mandin
     28 */
     29 
     30 #include <unistd.h>
     31 
     32 #include <mint/osbind.h>
     33 #include <mint/falcon.h>
     34 #include <mint/mintbind.h>
     35 #include <mint/cookie.h>
     36 
     37 #include "SDL_audio.h"
     38 #include "SDL_mintaudio.h"
     39 #include "SDL_mintaudio_stfa.h"
     40 
     41 /* The audio device */
     42 
     43 SDL_AudioDevice *SDL_MintAudio_device;
     44 Uint8 *SDL_MintAudio_audiobuf[2];	/* Pointers to buffers */
     45 unsigned long SDL_MintAudio_audiosize;		/* Length of audio buffer=spec->size */
     46 volatile unsigned short SDL_MintAudio_numbuf;		/* Buffer to play */
     47 volatile unsigned short SDL_MintAudio_mutex;
     48 volatile unsigned long SDL_MintAudio_clocktics;
     49 cookie_stfa_t	*SDL_MintAudio_stfa;
     50 unsigned short SDL_MintAudio_hasfpu;
     51 
     52 /* MiNT thread variables */
     53 SDL_bool SDL_MintAudio_mint_present;
     54 SDL_bool SDL_MintAudio_quit_thread;
     55 SDL_bool SDL_MintAudio_thread_finished;
     56 long SDL_MintAudio_thread_pid;
     57 
     58 /* The callback function, called by each driver whenever needed */
     59 
     60 void SDL_MintAudio_Callback(void)
     61 {
     62 	Uint8 *buffer;
     63 	SDL_AudioDevice *audio = SDL_MintAudio_device;
     64 
     65  	buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
     66 	SDL_memset(buffer, audio->spec.silence, audio->spec.size);
     67 
     68 	if (audio->paused)
     69 		return;
     70 
     71 	if (audio->convert.needed) {
     72 		int silence;
     73 
     74 		if ( audio->convert.src_format == AUDIO_U8 ) {
     75 			silence = 0x80;
     76 		} else {
     77 			silence = 0;
     78 		}
     79 		SDL_memset(audio->convert.buf, silence, audio->convert.len);
     80 		audio->spec.callback(audio->spec.userdata,
     81 			(Uint8 *)audio->convert.buf,audio->convert.len);
     82 		SDL_ConvertAudio(&audio->convert);
     83 		SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
     84 	} else {
     85 		audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
     86 	}
     87 }
     88 
     89 /* Add a new frequency/clock/predivisor to the current list */
     90 void SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
     91 	Uint32 prediv, int gpio_bits)
     92 {
     93 	int i, p;
     94 
     95 	if (MINTAUDIO_freqcount==MINTAUDIO_maxfreqs) {
     96 		return;
     97 	}
     98 
     99 	/* Search where to insert the frequency (highest first) */
    100 	for (p=0; p<MINTAUDIO_freqcount; p++) {
    101 		if (frequency > MINTAUDIO_frequencies[p].frequency) {
    102 			break;
    103 		}
    104 	}
    105 
    106 	/* Put all following ones farer */
    107 	if (MINTAUDIO_freqcount>0) {
    108 		for (i=MINTAUDIO_freqcount; i>p; i--) {
    109 			SDL_memcpy(&MINTAUDIO_frequencies[i], &MINTAUDIO_frequencies[i-1], sizeof(mint_frequency_t));
    110 		}
    111 	}
    112 
    113 	/* And insert new one */
    114 	MINTAUDIO_frequencies[p].frequency = frequency;
    115 	MINTAUDIO_frequencies[p].masterclock = clock;
    116 	MINTAUDIO_frequencies[p].predivisor = prediv;
    117 	MINTAUDIO_frequencies[p].gpio_bits = gpio_bits;
    118 
    119 	MINTAUDIO_freqcount++;
    120 }
    121 
    122 /* Search for the nearest frequency */
    123 int SDL_MintAudio_SearchFrequency(_THIS, int desired_freq)
    124 {
    125 	int i;
    126 
    127 	/* Only 1 freq ? */
    128 	if (MINTAUDIO_freqcount==1) {
    129 		return 0;
    130 	}
    131 
    132 	/* Check the array */
    133 	for (i=0; i<MINTAUDIO_freqcount; i++) {
    134 		if (desired_freq >= ((MINTAUDIO_frequencies[i].frequency+
    135 			MINTAUDIO_frequencies[i+1].frequency)>>1)) {
    136 			return i;
    137 		}
    138 	}
    139 
    140 	/* Not in the array, give the latest */
    141 	return MINTAUDIO_freqcount-1;
    142 }
    143 
    144 /* Check if FPU is present */
    145 void SDL_MintAudio_CheckFpu(void)
    146 {
    147 	unsigned long cookie_fpu;
    148 
    149 	SDL_MintAudio_hasfpu = 0;
    150 	if (Getcookie(C__FPU, &cookie_fpu) != C_FOUND) {
    151 		return;
    152 	}
    153 	switch ((cookie_fpu>>16)&0xfffe) {
    154 		case 2:
    155 		case 4:
    156 		case 6:
    157 		case 8:
    158 		case 16:
    159 			SDL_MintAudio_hasfpu = 1;
    160 			break;
    161 	}
    162 }
    163 
    164 /* The thread function, used under MiNT with xbios */
    165 int SDL_MintAudio_Thread(long param)
    166 {
    167 	SndBufPtr	pointers;
    168 	SDL_bool	buffers_filled[2] = {SDL_FALSE, SDL_FALSE};
    169 
    170 	SDL_MintAudio_thread_finished = SDL_FALSE;
    171 	while (!SDL_MintAudio_quit_thread) {
    172 		if (Buffptr(&pointers)!=0)
    173 			continue;
    174 
    175 		if (( (unsigned long)pointers.play>=(unsigned long)SDL_MintAudio_audiobuf[0])
    176 			&& ( (unsigned long)pointers.play<=(unsigned long)SDL_MintAudio_audiobuf[1]))
    177 		{
    178 			/* DMA is reading buffer #0, setup buffer #1 if not already done */
    179 			if (!buffers_filled[1]) {
    180 				SDL_MintAudio_numbuf = 1;
    181 				SDL_MintAudio_Callback();
    182 				Setbuffer(0, SDL_MintAudio_audiobuf[1], SDL_MintAudio_audiobuf[1] + SDL_MintAudio_audiosize);
    183 				buffers_filled[1]=SDL_TRUE;
    184 				buffers_filled[0]=SDL_FALSE;
    185 			}
    186 		} else {
    187 			/* DMA is reading buffer #1, setup buffer #0 if not already done */
    188 			if (!buffers_filled[0]) {
    189 				SDL_MintAudio_numbuf = 0;
    190 				SDL_MintAudio_Callback();
    191 				Setbuffer(0, SDL_MintAudio_audiobuf[0], SDL_MintAudio_audiobuf[0] + SDL_MintAudio_audiosize);
    192 				buffers_filled[0]=SDL_TRUE;
    193 				buffers_filled[1]=SDL_FALSE;
    194 			}
    195 		}
    196 
    197 		usleep(100);
    198 	}
    199 	SDL_MintAudio_thread_finished = SDL_TRUE;
    200 	return 0;
    201 }
    202 
    203 void SDL_MintAudio_WaitThread(void)
    204 {
    205 	if (!SDL_MintAudio_mint_present)
    206 		return;
    207 
    208 	if (SDL_MintAudio_thread_finished)
    209 		return;
    210 
    211 	SDL_MintAudio_quit_thread = SDL_TRUE;
    212 	while (!SDL_MintAudio_thread_finished) {
    213 		Syield();
    214 	}
    215 }
    216