diff --git a/src/conf.c b/src/conf.c index d704015..cc65ab8 100644 --- a/src/conf.c +++ b/src/conf.c @@ -128,6 +128,8 @@ int conf_loadConfig(const char* file) { conf_loadInt("afterburn", input_afterburnSensibility); // Sound. + conf_loadBool("nosound", i); + nosound = i; i = 0; conf_loadFloat("sound", d); if(d) { sound_volume(d); d = 0.; } conf_loadFloat("music", d); diff --git a/src/music.c b/src/music.c index 7de5d36..4356c88 100644 --- a/src/music.c +++ b/src/music.c @@ -169,7 +169,6 @@ static int stream_loadBuffer(ALuint buffer) { // Init/Exit. int music_init(void) { music_vorbis_lock = SDL_CreateMutex(); - music_find(); music_vorbis.file.end = 0; // Indication that it's not loaded.. SDL_mutexP(sound_lock); @@ -185,6 +184,10 @@ int music_init(void) { return 0; } +int music_makeList(void) { + return music_find(); +} + void music_exit(void) { int i; diff --git a/src/music.h b/src/music.h index 96bb65f..3dad535 100644 --- a/src/music.h +++ b/src/music.h @@ -6,6 +6,7 @@ void music_kill(void); // Init/Exit. int music_init(void); +int music_makeList(void); void music_exit(void); // Music control. diff --git a/src/sound.c b/src/sound.c index eb154e5..c47a740 100644 --- a/src/sound.c +++ b/src/sound.c @@ -18,6 +18,37 @@ // right now. // ============================================== +// ============================================== +// Sound Overview: +// --------------- +// +// We use a priority virtual voice system with +// pre-allocated buffers. +// +// Nameing: +// -- buffer - Sound sample. +// -- source - openal object that plays sound. +// -- voice - Virtual object that wants to play sound. +// +// First we allocate all the buffers based on what +// we find inside the datafile. +// Then we allocate all the possible sources (giving +// the music system what it needs). +// Now we allow the user to dynamically create +// voices, these voices will always try to grab +// a source from the source pool. If they can't, +// they will pretend to play the buffer. +// Every so often we'll check to see if the important +// voices are being played and take away the sources +// from the lesser ones. +// ============================================== + +// Sound parameters - TODO: make it variable per source. +#define SOUND_ROLLOFF_FACTOR 1. +#define SOUND_REFERENCE_DIST 500. +#define SOUND_MAX_DIST 1000. + + #define SOUND_PREFIX "../snd/sounds/" #define SOUND_SUFFIX ".wav" @@ -29,6 +60,7 @@ typedef struct alSound_ { #define VOICE_PLAYING (1<<0) // Voice is playing. #define VOICE_LOOPING (1<<1) // Voice is looping. +#define VOICE_DONE (1<<2) // Voice is done - must remove. #define voice_set(v,f) ((v)->flags |= f) #define voice_is(v,f) ((v)->flags & f) @@ -46,10 +78,18 @@ static SDL_Thread* music_player = NULL; static alSound* sound_list = NULL; static int nsound_list = 0; -// Current sources playing. +typedef struct VoiceSource_ { + ALuint source; // Allocated source. + ALuint voice; // Voice id. +} VoiceSource; +static VoiceSource* source_stack = NULL; // And it's stack. +static int source_nstack = 0; + +// Virtual voice stack. static alVoice** voice_stack = NULL; -static int nvoice_stack = 0; -static int mvoice_stack = 0; +static int voice_nstack = 0; +static int voice_mstack = 0; +#define VOICE_CHUNK 64 // Allocate by these chunks. // Volume. static ALfloat svolume = 0.3; @@ -60,13 +100,16 @@ static void sound_free(alSound* snd); static int voice_getSource(alVoice* voc); int sound_init(void) { - int ret = 0; + int mem, ret = 0; + ALenum err; + ret = 0; + + // We'll need a mutex. sound_lock = SDL_CreateMutex(); SDL_mutexP(sound_lock); const ALchar* device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); - DEBUG("OpenAL using device '%s'", device); // Open the default device. al_device = alcOpenDevice(NULL); if(al_device == NULL) { @@ -99,15 +142,43 @@ int sound_init(void) { // Set the distance model. alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); + // We can unlock now. SDL_mutexV(sound_lock); - // Load up all the sounds. - sound_makeList(); - // Start the music server. music_init(); music_player = SDL_CreateThread(music_thread, NULL); + // Start allocating the sources - music has already taken this. + alGetError(); // Another error clear. + mem = 0; + while(((err = alGetError()) == AL_NO_ERROR) && (source_nstack < 128)) { + if(mem < source_nstack+1) { + // Allocate more memory. + mem += 32; + source_stack = realloc(source_stack, sizeof(VoiceSource) * mem); + } + alGenSources(1, &source_stack[source_nstack].source); + source_stack[source_nstack].voice = 0; + source_nstack++; + } + + // Use minimal ram. + source_stack = realloc(source_stack, sizeof(VoiceSource) * source_nstack); + + // Debug magic. + DEBUG("OpenAL: %s", device); + DEBUG("Sources: %d", source_nstack); + DEBUG("Renderer: %s", alGetString(AL_RENDERER)); + DEBUG("Version: %s", alGetString(AL_VERSION)); + + // Load up all the sounds. + sound_makeList(); + music_makeList(); // And music. + + // Now start the music thread. + music_player = SDL_CreateThread(music_thread, NULL); + return 0; snderr_act: @@ -120,6 +191,7 @@ snderr_dev: SDL_mutexV(sound_lock); SDL_DestroyMutex(sound_lock); sound_lock = NULL; + ERR("Sound failed to initialize."); return ret; } @@ -245,6 +317,7 @@ static void sound_free(alSound* snd) { SDL_mutexP(sound_lock); + // Free the stuff. if(snd->name) free(snd->name); alDeleteBuffers(1, &snd->buffer); @@ -256,11 +329,9 @@ void sound_update(void) { if(sound_lock == NULL) return; int i; - // TODO: Prioritize the things. - SDL_mutexP(sound_lock); - for(i = 0; i < nvoice_stack; i++) { + for(i = 0; i < voice_nstack; i++) { if(voice_is(voice_stack[i], VOICE_PLAYING)) { // Update position. alSource3f(voice_stack[i]->source, AL_POSITION, @@ -282,7 +353,7 @@ void sound_volume(const double vol) { svolume = (ALfloat) vol; SDL_mutexP(sound_lock); - for(i = 0; i < nvoice_stack; i++) + for(i = 0; i < voice_nstack; i++) if(voice_set(voice_stack[i], VOICE_PLAYING)) alSourcef(voice_stack[i]->source, AL_GAIN, svolume); SDL_mutexV(sound_lock); @@ -311,8 +382,9 @@ static int voice_getSource(alVoice* voc) { alSourcei(voc->source, AL_BUFFER, voc->buffer); // Distance model. - alSourcef(voc->source, AL_MAX_DISTANCE, 200.); - alSourcef(voc->source, AL_REFERENCE_DISTANCE, 50.); + alSourcef(voc->source, AL_ROLLOFF_FACTOR, SOUND_ROLLOFF_FACTOR); + alSourcef(voc->source, AL_MAX_DISTANCE, SOUND_MAX_DIST); + alSourcef(voc->source, AL_REFERENCE_DISTANCE, SOUND_REFERENCE_DIST); alSourcei(voc->source, AL_SOURCE_RELATIVE, AL_FALSE); alSourcef(voc->source, AL_GAIN, svolume); @@ -339,23 +411,22 @@ alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy (void)vx; (void)vy; + alVoice* voc; if(sound_lock == NULL) return NULL; - alVoice* voc; - - nvoice_stack++; - if(nvoice_stack > mvoice_stack) - voice_stack = realloc(voice_stack, ++mvoice_stack*sizeof(alVoice*)); + voice_nstack++; + if(voice_nstack > voice_mstack) + voice_stack = realloc(voice_stack, ++voice_mstack*sizeof(alVoice*)); voc = malloc(sizeof(alVoice)); - voice_stack[nvoice_stack-1] = voc; + voice_stack[voice_nstack-1] = voc; // Set the data. voc->priority = priority; voc->start = SDL_GetTicks(); voc->buffer = buffer; - if(looping) voice_set(voc, VOICE_LOOPING); + if(looping != 0) voice_set(voc, VOICE_LOOPING); voc->px = px; voc->py = py; //voc->vx = vx; @@ -371,21 +442,26 @@ void sound_delVoice(alVoice* voice) { ALint stat; int i; - for(i = 0; i < nvoice_stack; i++) + // Linear search. + for(i = 0; i < voice_nstack; i++) if(voice == voice_stack[i]) break; // No match found. - if(i >= nvoice_stack) { + if(i >= voice_nstack) { WARN("Unable to find voice to free from stack"); return; } + // Source must exist. if(voice->source) { SDL_mutexP(sound_lock); + // Stop it if playing. alGetSourcei(voice->source, AL_SOURCE_STATE, &stat); if(stat == AL_PLAYING) alSourceStop(voice->source); + + // Clear it and get rid of it. alDeleteSources(1, &voice->source); voice->source = 0; @@ -393,11 +469,12 @@ void sound_delVoice(alVoice* voice) { } free(voice_stack[i]); - nvoice_stack--; - for(; i < nvoice_stack; i++) + voice_nstack--; + for(; i < voice_nstack; i++) voice_stack[i] = voice_stack[i+1]; } +// Update voice position, should be run once per frame. void voice_update(alVoice* voice, double px, double py, double vx, double vy) { (void) vx; (void) vy; @@ -418,11 +495,12 @@ void sound_listener(double dir, double px, double py, double vx, double vy) { SDL_mutexP(sound_lock); + // Set orientation. ALfloat ori[] = { 0., 0., 0., 0., 0., 1. }; ori[0] = cos(dir); ori[1] = sin(dir); alListenerfv(AL_ORIENTATION, ori); - alListener3f(AL_POSITION, px, py, 0.); + alListener3f(AL_POSITION, px, py, 1.); //alListener3f(AL_VELOCITY, vx, vy, 0.); SDL_mutexV(sound_lock); diff --git a/src/sound.h b/src/sound.h index 01ce20c..dfaab8d 100644 --- a/src/sound.h +++ b/src/sound.h @@ -2,11 +2,9 @@ #include <AL/al.h> #include "physics.h" -#define SOUND_REFERENCE_DIST 500. -#define SOUND_MAX_DIST 1000. - // Virtual voice. typedef struct alVoice_ { + ALuint id; // Unique id for the voice. ALuint source; // Source itself, 0 if not set. ALuint buffer; // Buffer.