// Copyright (C) 2011 Valeriano Alfonso Rodriguez (Kableado) #ifdef WIN32 #define _WIN32_WINNT 0x0501 #include #endif #include #include "Audio.h" static void Audio_MixerCallback(void *ud,Uint8 *stream,int l); //////////////////////////////////////////////// // AudioWave // /////////////// // Reference to a sound. typedef struct Tag_AudioWave { SDL_AudioSpec spec; Uint32 len; Uint8 *buffer; struct Tag_AudioWave *next; } AudioWave; AudioWave *_waves=NULL; //////////////////////////////////////////////// // AudioChan // /////////////// // Reference to a sound. typedef struct Tag_AudioChan { AudioWave *wave; Uint32 pos; unsigned char rightvol; unsigned char leftvol; struct Tag_AudioChan *next; } AudioChan; AudioChan *_channels=NULL; AudioChan *_free_channels=NULL; ///////////////////////////// // Audio_Init // // Initializes the game audio. int Audio_Init(){ SDL_AudioSpec as; SDL_AudioSpec as2; // Initialize audio subsistem #ifdef WIN32 // Force DSound Driver on win32 putenv("SDL_AUDIODRIVER=dsound"); #endif if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0){ printf("Audio_Init: Failure initializing SDL Audio.\n"); printf("Audio_Init: SDL Error: %s\n",SDL_GetError()); return(0); } // Open the audio device using the desired parameters as.freq = 44100; as.format = AUDIO_S16SYS; as.channels = 2; as.samples = 1024; as.callback = Audio_MixerCallback; if(SDL_OpenAudio(&as, &as2) < 0){ printf("Audio_Init: Failure opening audio.\n"); printf("Audio_Init: SDL Error: %s\n",SDL_GetError()); return(0); } // Asert results if( as2.format != AUDIO_S16SYS || as2.freq != 44100 || as2.channels != 2 ) { printf("Audio_Init: Failure opening audio. (44.1Khz/16b/2c).\n"); SDL_CloseAudio(); return(0); } // Unpause and ready to go SDL_PauseAudio(0); return(1); } ///////////////////////////// // Audio_MixerCallback // // Mixes the audio channels. static void Audio_MixerCallback(void *ud,Uint8 *stream,int l){ signed short *ptr_out,*ptr_wave; AudioChan *prevchan; AudioChan *chan; AudioWave *wave; int len=l/4; // Asume 16bpb and 2 output chan int chan_remain; int len_mix; int i; // Clean memset(stream,0,len); // Mix all the channels prevchan=NULL; chan=_channels; while(chan){ if(!chan->wave){ // Remove finished channels AudioChan *aux_chan=chan->next; chan->next=_free_channels; _free_channels=chan; chan=aux_chan; if(prevchan){ prevchan->next=chan; }else{ _channels=chan; } continue; } // Prepare the pointers ptr_out=(signed short *)stream; ptr_wave=((signed short *)chan->wave->buffer)+chan->pos; wave=chan->wave; // Determine mixing lenght chan_remain=wave->len-chan->pos; if(chan_remain>len){ len_mix=len; }else{ len_mix=chan_remain; chan->wave=NULL; } // Mix the buffer for(i=0;ileftvol)>>8; if(temp>(1<<14)){ ptr_out[0]=1<<14; }else if(temp<-(1<<14)){ ptr_out[0]=-(1<<14); }else{ ptr_out[0]=temp; } // Right Channel temp=ptr_out[1]; temp+=(ptr_wave[0]*chan->rightvol)>>8; if(temp>(1<<14)){ ptr_out[1]=1<<14; }else if(temp<-(1<<14)){ ptr_out[1]=-(1<<14); }else{ ptr_out[1]=temp; } // Next sample ptr_out+=2; ptr_wave++; } chan->pos+=len_mix; // Next channel prevchan=chan; chan=chan->next; } } ///////////////////////////// // Audio_Frame // // Notify a frame update to the audio subsystem. void Audio_Frame(){ } ///////////////////////////// // Audio_LoadSound // // Loads a sound, giving a reference. AudioSnd Audio_LoadSound(char *filename){ AudioWave *wave; // Allocate and load the sound wave=malloc(sizeof(AudioWave)); if( SDL_LoadWAV(filename, &wave->spec, &wave->buffer, &wave->len) == NULL ) { printf("Audio_LoadSound: Failure Loading sound: %s\n",filename); printf("Audio_LoadSound: SDL Error: %s\n",SDL_GetError()); free(wave); return(NULL); } // Asert results if( wave->spec.format != AUDIO_S16 || wave->spec.freq != 44100 || wave->spec.channels != 1 ) { printf("Audio_LoadSound: Failure opening sound. (44.1Khz/16b/1c).\n"); SDL_FreeWAV(wave->buffer); free(wave); return(0); } // Correct the lenght wave->len/=2; // Take a reference wave->next=_waves; _waves=wave; return((AudioSnd)wave); } ///////////////////////////// // Audio_PlaySound // // Loads a sound, giving a reference. void Audio_PlaySound(AudioSnd snd, float leftvol, float rightvol) { AudioChan *chan; AudioWave *wave; if(!snd) return; // Cast AudioSnd to AudioWave wave=snd; // Get a free channel if(_free_channels){ chan=_free_channels; _free_channels=chan->next; chan->next=NULL; }else{ chan=malloc(sizeof(AudioChan)); chan->next=NULL; } // Initialize the channel chan->wave=wave; chan->pos=0; chan->rightvol=(rightvol*255); chan->leftvol=(leftvol*255); chan->next=_channels; _channels=chan; }