From ebdfaad9a79d9cb2e65a5878b036b66bf2f0161c Mon Sep 17 00:00:00 2001 From: Allanis Date: Tue, 1 Oct 2013 22:12:39 +0100 Subject: [PATCH] [Add] Improved sound system considerably, not used properly yet. --- src/lephisto.c | 2 + src/sound.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++-- src/sound.h | 3 + 3 files changed, 254 insertions(+), 8 deletions(-) diff --git a/src/lephisto.c b/src/lephisto.c index 0cb909a..7d7bc0d 100644 --- a/src/lephisto.c +++ b/src/lephisto.c @@ -332,6 +332,8 @@ void main_loop(void) { glClear(GL_COLOR_BUFFER_BIT); fps_control(); /* Everyone loves fps control.. */ + + sound_update(); /* Update sounds. */ if(toolkit) toolkit_update(); /* To simulate key repetition. */ if(!menu_isOpen(MENU_MAIN)) { if(!paused) update_all(); /* Update game. */ diff --git a/src/sound.c b/src/sound.c index 9830e68..453a0dd 100644 --- a/src/sound.c +++ b/src/sound.c @@ -26,19 +26,64 @@ int sound_disabled = 0; /**< Whether sound is disabled. */ static int sound_reserved = 0; /**< Amount of reserved channels. */ static double sound_pos[3]; /**< Position of listener. */ -/* Give the buffers a name. */ +/** + * @struct alSound + * + * @brief Contains a sound buffer. + */ typedef struct alSound_ { char* name; /**< Buffers name. */ Mix_Chunk* buffer; /**< Buffer data. */ } alSound; +/** + * @typedef voice_state_t + * + * @brief The state of a voice. + * + * @sa alVoice + */ +typedef enum voice_state_ { + VOICE_STOPPED, /**< Voice is stopped. */ + VOICE_PLAYING, /**< Voice is playing. */ + VOICE_DESTROY /**< Voice should get destroyed asap. */ +} voice_state_t; + +/** + * @struct alVoice + * + * @brief Represents a voice in the game. + * + * A voice would be any object that is creating sound. + */ +typedef struct alVoice_ { + struct alVoice_* prev; /**< Linked list previous member. */ + struct alVoice_* next; /**< Linked list next member. */ + + int id; /**< Identifier of the voice. */ + double pos[2]; /**< Position of the voice. */ + int channel; /**< Channel currently in use. */ + unsigned int state; /**< Current state of the sound. */ +} alVoice; + /* List of sounds available (All preloaded into a buffer). */ +static int voice_genid = 0; /**< Voice identifier generator. */ static alSound* sound_list = NULL; /**< List of available sounds. */ static int sound_nlist = 0; /**< Number of available sounds. */ +/* Voice linked list. */ +static alVoice* voice_active; /**< Active voices. */ +static alVoice* voice_pool; /**< Pool of free voices. */ + +/* General prototypes. */ static int sound_makeList(void); static Mix_Chunk* sound_load(char* filename); static void sound_free(alSound* snd); +/* Voices. */ +static void voice_markStopped(int channel); +static alVoice* voice_new(void); +static int voice_add(alVoice* v); +static alVoice* voice_get(int id); /** * @fn int sound_init(void) @@ -77,6 +122,9 @@ int sound_init(void) { sound_makeList(); sound_volume(0.4); + /* Finish function. */ + Mix_ChannelFinished(voice_markStopped); + /* Init the music. */ music_init(); @@ -90,6 +138,19 @@ int sound_init(void) { */ void sound_exit(void) { int i; + alVoice* v; + + /* Free the voices. */ + while(voice_active != NULL) { + v = voice_active; + voice_active = v->next; + free(v); + } + while(voice_pool != NULL) { + v = voice_pool; + voice_pool = v->next; + free(v); + } /* Free the sounds. */ for(i = 0; i < sound_nlist; i++) @@ -155,7 +216,7 @@ int sound_play(int sound) { * @return 0 on success. */ int sound_playPos(int sound, double x, double y) { - int channel; + alVoice* v; double angle, dist; double px, py; @@ -164,28 +225,128 @@ int sound_playPos(int sound, double x, double y) { if((sound < 0) || (sound > sound_nlist)) return -1; - px = x - sound_pos[0]; - py = y - sound_pos[1]; + /* Get a new voice. */ + v = voice_new(); + + v->pos[0] = x; + v->pos[1] = y; + + px = v->pos[0] - sound_pos[0]; + py = v->pos[1] - sound_pos[1]; angle = sound_pos[2] - ANGLE(px, py)/M_PI*180.; - dist = MOD(px, py); - channel = Mix_PlayChannel(-1, sound_list[sound].buffer, 0); + v->channel = Mix_PlayChannel(-1, sound_list[sound].buffer, 0); - if(channel < 0) { + if(v->channel < 0) { WARN("Unable to play sound: %s", Mix_GetError()); return -1; } - if(Mix_SetPosition(channel, (int)angle, (int)dist/10) < 0) { + if(Mix_SetPosition(v->channel, (int)angle, (int)dist/10) < 0) { WARN("Unable to set sound position: %s", Mix_GetError()); return -1; } + /* Actually add the voice to the list. */ + v->state = VOICE_PLAYING; + v->id = ++voice_genid; + voice_add(v); + + return v->id; +} + +/** + * @fn int sound_updatePos(int voice, double x, double y) + * + * @brief Update the position of a voice. + * @param voice Identifier of the voice to update. + * @param x New x position to update to. + * @param y New y position to update to. + */ +int sound_updatePos(int voice, double x, double y) { + alVoice* v; + double angle, dist; + double px, py; + + if(sound_disabled) return 0; + + v = voice_get(voice); + + if(v != NULL) { + v->pos[0] = x; + v->pos[1] = y; + + px = x - sound_pos[0]; + py = y - sound_pos[1]; + + angle = sound_pos[2] - ANGLE(px, py)/M_PI*180.; + dist = MOD(px, py); + + if(Mix_SetPosition(v->channel, (int)angle, (int)dist/10) < 0) { + WARN("Unable to set sound position: %s", Mix_GetError()); + return -1; + } + } return 0; } +/** + * @fn int sound_update(void) + * + * @brief Update the sounds removing obsolete ones and such. + * @return 0 on success. + */ +int sound_update(void) { + alVoice* v, *tv; + + if(sound_disabled) return 0; + + if(voice_active == NULL) return 0; + + /* The actualy control loop. */ + for(v = voice_active; v != NULL; v = v->next) { + /* Destroy and toss into pool. */ + if((v->state == VOICE_STOPPED) || (v->state == VOICE_DESTROY)) { + /* Remove from active list. */ + tv = v->prev; + if(tv == NULL) + voice_active = v->next; + else + tv->next = v->next; + + /* Add to free pool. */ + v->next = voice_pool; + voice_pool = v; + v->channel = 0; + + /* Avoid loop blockage. */ + v = (tv != NULL) ? tv->next : voice_active; + if(v == NULL) break; + } + } + return 0; +} + +/** + * @fn void sound_stop(int voice) + * + * @brief Stop a voice from playing. + * @param voice Identifier of the voice to stop. + */ +void sound_stop(int voice) { + alVoice* v; + + if(sound_disabled) return; + + v = voice_get(voice); + if(v != NULL) { + Mix_HaltChannel(v->channel); + v->state = VOICE_STOPPED; + } +} + /** * @fn int sound_updateListener(double dir, double x, double y) * @@ -410,3 +571,83 @@ void sound_stopGroup(int group) { Mix_HaltGroup(group); } +/** + * @fn static void voice_markStopped(int channel) + * + * @brief Mark the voice to which channel belongs to as stopped. + */ +static void voice_markStopped(int channel) { + alVoice* v; + + for(v = voice_active; v != NULL; v = v->next) + if(v->channel == channel) { + v->state = VOICE_STOPPED; + return; + } +} + +/** + * @fn static alVoice* voice_new(void) + * + * @brief Get a new voice ready to be used. + * @return New voice ready to use. + */ +static alVoice* voice_new(void) { + alVoice* v; + + /* No free voices, allocate a new one. */ + if(voice_pool == NULL) { + v = malloc(sizeof(alVoice)); + memset(v, 0, sizeof(alVoice)); + voice_pool = v; + return v; + } + + /* First free voice. */ + v = voice_pool; + return v; +} + +/** + * @fn static int voice_add(alVoice* v) + * + * @brief Add a voice to the active voice stack. + * @param v Voice to add to the active voice stack. + * @return 0 on success. + */ +static int voice_add(alVoice* v) { + alVoice* tv; + + /* Set previous to point to next. */ + if(v->prev != NULL) { + tv = v->prev; + tv->next = v->next; + } else { /* Set pool to be the next. */ + voice_pool = v->next; + } + + /* Insert to the front of active voices. */ + tv = voice_active; + voice_active = v; + v->next = tv; + return 0; +} + +/** + * @fn static alVoice* voice_get(int id) + * + * @brief Get a voice by identifier. + * @param id Identifier to look for. + * @return Voice matching identifier or NULL if not found. + */ +static alVoice* voice_get(int id) { + alVoice* v; + + if(voice_active == NULL) return NULL; + + for(v = voice_active; v != NULL; v = v->next) + if(v->id == id) + return v; + return NULL; +} + diff --git a/src/sound.h b/src/sound.h index 4a04f76..daf4750 100644 --- a/src/sound.h +++ b/src/sound.h @@ -5,12 +5,15 @@ extern int sound_disabled; /* Sound subsystem. */ int sound_init(void); void sound_exit(void); +int sound_update(void); /* Sound manupulation functions. */ int sound_get(char* name); int sound_volume(const double vol); int sound_play(int sound); int sound_playPos(int sound, double x, double y); +void sound_stop(int voice); +int sound_updatePos(int voice, double x, double y); int sound_updateListener(double dir, double x, double y); /* Group functions. */