symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/dc/SDL_dcaudio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 Sam Lantinga
       
     4 
       
     5     This library is free software; you can redistribute it and/or
       
     6     modify it under the terms of the GNU Lesser General Public
       
     7     License as published by the Free Software Foundation; either
       
     8     version 2.1 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     Lesser General Public License for more details.
       
    14 
       
    15     You should have received a copy of the GNU Lesser General Public
       
    16     License along with this library; if not, write to the Free Software
       
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    18 
       
    19     Sam Lantinga
       
    20     slouken@libsdl.org
       
    21 
       
    22 */
       
    23 #include "SDL_config.h"
       
    24 
       
    25 /* Output dreamcast aica */
       
    26 
       
    27 #include "SDL_timer.h"
       
    28 #include "SDL_audio.h"
       
    29 #include "../SDL_audiomem.h"
       
    30 #include "../SDL_audio_c.h"
       
    31 #include "../SDL_audiodev_c.h"
       
    32 #include "SDL_dcaudio.h"
       
    33 
       
    34 #include "aica.h"
       
    35 #include <dc/spu.h>
       
    36 
       
    37 /* Audio driver functions */
       
    38 static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    39 static void DCAUD_WaitAudio(_THIS);
       
    40 static void DCAUD_PlayAudio(_THIS);
       
    41 static Uint8 *DCAUD_GetAudioBuf(_THIS);
       
    42 static void DCAUD_CloseAudio(_THIS);
       
    43 
       
    44 /* Audio driver bootstrap functions */
       
    45 static int DCAUD_Available(void)
       
    46 {
       
    47 	return 1;
       
    48 }
       
    49 
       
    50 static void DCAUD_DeleteDevice(SDL_AudioDevice *device)
       
    51 {
       
    52 	SDL_free(device->hidden);
       
    53 	SDL_free(device);
       
    54 }
       
    55 
       
    56 static SDL_AudioDevice *DCAUD_CreateDevice(int devindex)
       
    57 {
       
    58 	SDL_AudioDevice *this;
       
    59 
       
    60 	/* Initialize all variables that we clean on shutdown */
       
    61 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
       
    62 	if ( this ) {
       
    63 		SDL_memset(this, 0, (sizeof *this));
       
    64 		this->hidden = (struct SDL_PrivateAudioData *)
       
    65 				SDL_malloc((sizeof *this->hidden));
       
    66 	}
       
    67 	if ( (this == NULL) || (this->hidden == NULL) ) {
       
    68 		SDL_OutOfMemory();
       
    69 		if ( this ) {
       
    70 			SDL_free(this);
       
    71 		}
       
    72 		return(0);
       
    73 	}
       
    74 	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
    75 
       
    76 	/* Set the function pointers */
       
    77 	this->OpenAudio = DCAUD_OpenAudio;
       
    78 	this->WaitAudio = DCAUD_WaitAudio;
       
    79 	this->PlayAudio = DCAUD_PlayAudio;
       
    80 	this->GetAudioBuf = DCAUD_GetAudioBuf;
       
    81 	this->CloseAudio = DCAUD_CloseAudio;
       
    82 
       
    83 	this->free = DCAUD_DeleteDevice;
       
    84 
       
    85 	spu_init();
       
    86 
       
    87 	return this;
       
    88 }
       
    89 
       
    90 AudioBootStrap DCAUD_bootstrap = {
       
    91 	"dcaudio", "Dreamcast AICA audio",
       
    92 	DCAUD_Available, DCAUD_CreateDevice
       
    93 };
       
    94 
       
    95 /* This function waits until it is possible to write a full sound buffer */
       
    96 static void DCAUD_WaitAudio(_THIS)
       
    97 {
       
    98 	if (this->hidden->playing) {
       
    99 		/* wait */
       
   100 		while(aica_get_pos(0)/this->spec.samples == this->hidden->nextbuf) {
       
   101 			thd_pass();
       
   102 		}
       
   103 	}
       
   104 }
       
   105 
       
   106 #define	SPU_RAM_BASE	0xa0800000
       
   107 
       
   108 static void spu_memload_stereo8(int leftpos,int rightpos,void *src0,size_t size)
       
   109 {
       
   110 	uint8 *src = src0;
       
   111 	uint32 *left  = (uint32*)(leftpos +SPU_RAM_BASE);
       
   112 	uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
       
   113 	size = (size+7)/8;
       
   114 	while(size--) {
       
   115 		unsigned lval,rval;
       
   116 		lval = *src++;
       
   117 		rval = *src++;
       
   118 		lval|= (*src++)<<8;
       
   119 		rval|= (*src++)<<8;
       
   120 		lval|= (*src++)<<16;
       
   121 		rval|= (*src++)<<16;
       
   122 		lval|= (*src++)<<24;
       
   123 		rval|= (*src++)<<24;
       
   124 		g2_write_32(left++,lval);
       
   125 		g2_write_32(right++,rval);
       
   126 		g2_fifo_wait();
       
   127 	}
       
   128 }
       
   129 
       
   130 static void spu_memload_stereo16(int leftpos,int rightpos,void *src0,size_t size)
       
   131 {
       
   132 	uint16 *src = src0;
       
   133 	uint32 *left  = (uint32*)(leftpos +SPU_RAM_BASE);
       
   134 	uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
       
   135 	size = (size+7)/8;
       
   136 	while(size--) {
       
   137 		unsigned lval,rval;
       
   138 		lval = *src++;
       
   139 		rval = *src++;
       
   140 		lval|= (*src++)<<16;
       
   141 		rval|= (*src++)<<16;
       
   142 		g2_write_32(left++,lval);
       
   143 		g2_write_32(right++,rval);
       
   144 		g2_fifo_wait();
       
   145 	}
       
   146 }
       
   147 
       
   148 static void DCAUD_PlayAudio(_THIS)
       
   149 {
       
   150 	SDL_AudioSpec *spec = &this->spec;
       
   151 	unsigned int offset;
       
   152 
       
   153 	if (this->hidden->playing) {
       
   154 		/* wait */
       
   155 		while(aica_get_pos(0)/spec->samples == this->hidden->nextbuf) {
       
   156 			thd_pass();
       
   157 		}
       
   158 	}
       
   159 
       
   160 	offset = this->hidden->nextbuf*spec->size;
       
   161 	this->hidden->nextbuf^=1;
       
   162 	/* Write the audio data, checking for EAGAIN on broken audio drivers */
       
   163 	if (spec->channels==1) {
       
   164 		spu_memload(this->hidden->leftpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
       
   165 	} else {
       
   166 		offset/=2;
       
   167 		if ((this->spec.format&255)==8) {
       
   168 			spu_memload_stereo8(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
       
   169 		} else {
       
   170 			spu_memload_stereo16(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
       
   171 		}
       
   172 	}
       
   173 
       
   174 	if (!this->hidden->playing) {
       
   175 		int mode;
       
   176 		this->hidden->playing = 1;
       
   177 		mode = (spec->format==AUDIO_S8)?SM_8BIT:SM_16BIT;
       
   178 		if (spec->channels==1) {
       
   179 			aica_play(0,mode,this->hidden->leftpos,0,spec->samples*2,spec->freq,255,128,1);
       
   180 		} else {
       
   181 			aica_play(0,mode,this->hidden->leftpos ,0,spec->samples*2,spec->freq,255,0,1);
       
   182 			aica_play(1,mode,this->hidden->rightpos,0,spec->samples*2,spec->freq,255,255,1);
       
   183 		}
       
   184 	}
       
   185 }
       
   186 
       
   187 static Uint8 *DCAUD_GetAudioBuf(_THIS)
       
   188 {
       
   189 	return(this->hidden->mixbuf);
       
   190 }
       
   191 
       
   192 static void DCAUD_CloseAudio(_THIS)
       
   193 {
       
   194 	aica_stop(0);
       
   195 	if (this->spec.channels==2) aica_stop(1);
       
   196 	if ( this->hidden->mixbuf != NULL ) {
       
   197 		SDL_FreeAudioMem(this->hidden->mixbuf);
       
   198 		this->hidden->mixbuf = NULL;
       
   199 	}
       
   200 }
       
   201 
       
   202 static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   203 {
       
   204     Uint16 test_format = SDL_FirstAudioFormat(spec->format);
       
   205     int valid_datatype = 0;
       
   206     while ((!valid_datatype) && (test_format)) {
       
   207         spec->format = test_format;
       
   208         switch (test_format) {
       
   209             /* only formats Dreamcast accepts... */
       
   210             case AUDIO_S8:
       
   211             case AUDIO_S16LSB:
       
   212                 valid_datatype = 1;
       
   213                 break;
       
   214 
       
   215             default:
       
   216                 test_format = SDL_NextAudioFormat();
       
   217                 break;
       
   218         }
       
   219     }
       
   220 
       
   221     if (!valid_datatype) {  /* shouldn't happen, but just in case... */
       
   222         SDL_SetError("Unsupported audio format");
       
   223         return (-1);
       
   224     }
       
   225 
       
   226     if (spec->channels > 2)
       
   227         spec->channels = 2;  /* no more than stereo on the Dreamcast. */
       
   228 
       
   229 	/* Update the fragment size as size in bytes */
       
   230 	SDL_CalculateAudioSpec(spec);
       
   231 
       
   232 	/* Allocate mixing buffer */
       
   233 	this->hidden->mixlen = spec->size;
       
   234 	this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
       
   235 	if ( this->hidden->mixbuf == NULL ) {
       
   236 		return(-1);
       
   237 	}
       
   238 	SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
       
   239 	this->hidden->leftpos = 0x11000;
       
   240 	this->hidden->rightpos = 0x11000+spec->size;
       
   241 	this->hidden->playing = 0;
       
   242 	this->hidden->nextbuf = 0;
       
   243 
       
   244 	/* We're ready to rock and roll. :-) */
       
   245 	return(0);
       
   246 }