/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2009 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" /* Allow access to a raw mixing buffer */ #include #include "SDL.h" #include "SDL_endian.h" #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_ndsaudio.h" #include "soundcommon.h" /* Audio driver functions */ static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec); static void NDS_WaitAudio(_THIS); static void NDS_PlayAudio(_THIS); static Uint8 *NDS_GetAudioBuf(_THIS); static void NDS_CloseAudio(_THIS); /* Audio driver bootstrap functions */ u32 framecounter = 0,soundoffset = 0; static SDL_AudioDevice *sdl_nds_audiodevice; //void SoundMixCallback(void *stream,u32 size) //{ // //printf("SoundMixCallback\n"); // // Uint8 *buffer; // // buffer = sdl_nds_audiodevice->hidden->mixbuf; // memset(buffer, sdl_nds_audiodevice->spec.silence, size); // // if (!sdl_nds_audiodevice->paused){ // // // //if (sdl_nds_audiodevice->convert.needed) { // // int silence; // // // if (sdl_nds_audiodevice->convert.src_format == AUDIO_U8 ) { // // silence = 0x80; // // } else { // // silence = 0; // // } // // memset(sdl_nds_audiodevice->convert.buf, silence, sdl_nds_audiodevice->convert.len); // // sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata, // // (Uint8 *)sdl_nds_audiodevice->convert.buf,sdl_nds_audiodevice->convert.len); // // SDL_ConvertAudio(&sdl_nds_audiodevice->convert); // // memcpy(buffer, sdl_nds_audiodevice->convert.buf, sdl_nds_audiodevice->convert.len_cvt); // //} else // { // sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata, buffer, size); // //memcpy((Sint16 *)stream,buffer, size); // } // // } // // if(soundsystem->format == 8) // { // int i; // s32 *buffer32 = (s32 *)buffer; // s32 *stream32 = (s32 *)stream; // for(i=0;i buffer 16bit // //if (buffer[i] &0x80) // //((Sint16*)stream)[i] = 0xff00 | buffer[i]; // ((Sint16*)stream)[i] = (buffer[i] - 128) << 8; // // //else // // ((Sint16*)stream)[i] = buffer[i]; // } // //register signed char *pSrc =buffer; // //register short *pDest =stream; // //int x; // // for (x=size; x>0; x--) // // { // // register short temp = (((short)*pSrc)-128)<<8; // // pSrc++; // // *pDest++ = temp; // // } // // //memcpy((Sint16 *)stream,buffer, size); // } //} void SoundMixCallback(void *stream,u32 len) { SDL_AudioDevice *audio = (SDL_AudioDevice *)sdl_nds_audiodevice; /* Silence the buffer, since it's ours */ SDL_memset(stream, audio->spec.silence, len); /* Only do soemthing if audio is enabled */ if ( ! audio->enabled ) return; if ( ! audio->paused ) { if ( audio->convert.needed ) { //fprintf(stderr,"converting audio\n"); SDL_mutexP(audio->mixer_lock); (*audio->spec.callback)(audio->spec.userdata, (Uint8 *)audio->convert.buf,audio->convert.len); SDL_mutexV(audio->mixer_lock); SDL_ConvertAudio(&audio->convert); SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt); } else { SDL_mutexP(audio->mixer_lock); (*audio->spec.callback)(audio->spec.userdata, (Uint8 *)stream, len); SDL_mutexV(audio->mixer_lock); } } return; } void MixSound(void) { int remain; if(soundsystem->format == 8) { if((soundsystem->soundcursor + soundsystem->numsamples) > soundsystem->buffersize) { SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->buffersize - soundsystem->soundcursor); remain = soundsystem->numsamples - (soundsystem->buffersize - soundsystem->soundcursor); SoundMixCallback(soundsystem->mixbuffer,remain); } else { SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->numsamples); } } else { if((soundsystem->soundcursor + soundsystem->numsamples) > (soundsystem->buffersize >> 1)) { SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],(soundsystem->buffersize >> 1) - soundsystem->soundcursor); remain = soundsystem->numsamples - ((soundsystem->buffersize >> 1) - soundsystem->soundcursor); SoundMixCallback(soundsystem->mixbuffer,remain); } else { SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],soundsystem->numsamples); } } } void InterruptHandler(void) { framecounter++; } void FiFoHandler(void) { u32 command; while ( !(REG_IPC_FIFO_CR & (IPC_FIFO_RECV_EMPTY)) ) { command = REG_IPC_FIFO_RX; switch(command) { case FIFO_NONE: break; case UPDATEON_ARM9: REG_IME = 0; MixSound(); REG_IME = 1; SendCommandToArm7(MIXCOMPLETE_ONARM9); break; } } } static int Audio_Available(void) { return(1); } static void Audio_DeleteDevice(SDL_AudioDevice *device) { } static SDL_AudioDevice *Audio_CreateDevice(int devindex) { SDL_AudioDevice *this; /* Initialize all variables that we clean on shutdown */ this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); if ( this ) { SDL_memset(this, 0, (sizeof *this)); this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); } if ( (this == NULL) || (this->hidden == NULL) ) { SDL_OutOfMemory(); if ( this ) { SDL_free(this); } return(0); } SDL_memset(this->hidden, 0, (sizeof *this->hidden)); /* Set the function pointers */ this->OpenAudio = NDS_OpenAudio; this->WaitAudio = NDS_WaitAudio; this->PlayAudio = NDS_PlayAudio; this->GetAudioBuf = NDS_GetAudioBuf; this->CloseAudio = NDS_CloseAudio; this->free = Audio_DeleteDevice; //fprintf(stderr,"Audio_CreateDevice\n"); return this; } AudioBootStrap NDSAUD_bootstrap = { "nds", "NDS audio", Audio_Available, Audio_CreateDevice }; void static NDS_WaitAudio(_THIS) { //printf("NDS_WaitAudio\n"); } static void NDS_PlayAudio(_THIS) { //printf("playing audio\n"); if (this->paused) return; } static Uint8 *NDS_GetAudioBuf(_THIS) { return NULL;//(this->hidden->mixbuf); } static void NDS_CloseAudio(_THIS) { /* if ( this->hidden->mixbuf != NULL ) { SDL_FreeAudioMem(this->hidden->mixbuf); this->hidden->mixbuf = NULL; }*/ } static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec) { //printf("NDS_OpenAudio\n"); int format = 0; //switch(spec->format&0xff) { //case 8: spec->format = AUDIO_S8;format=8; break; //case 16: spec->format = AUDIO_S16LSB;format=16; break; //default: // SDL_SetError("Unsupported audio format"); // return(-1); //} switch (spec->format&~0x1000) { case AUDIO_S8: /* Signed 8-bit audio supported */ format=8; break; case AUDIO_U8: spec->format ^= 0x80;format=8; break; case AUDIO_U16: /* Unsigned 16-bit audio unsupported, convert to S16 */ spec->format ^=0x8000;format=16; case AUDIO_S16: /* Signed 16-bit audio supported */ format=16; break; } /* Update the fragment size as size in bytes */ SDL_CalculateAudioSpec(spec); /* Allocate mixing buffer */ //this->hidden->mixlen = spec->size; //this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); //if ( this->hidden->mixbuf == NULL ) { // SDL_SetError("Out of Memory"); // return(-1); //} SDL_NDSAudio_mutex = 0; sdl_nds_audiodevice=this; irqInit(); irqSet(IRQ_VBLANK,&InterruptHandler); irqSet(IRQ_FIFO_NOT_EMPTY,&FiFoHandler); irqEnable(IRQ_FIFO_NOT_EMPTY); REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR | IPC_FIFO_RECV_IRQ; SoundSystemInit(spec->freq,spec->size,0,format); SoundStartMixer(); return(1); }