[Add] Improved sound system considerably, not used properly yet.

This commit is contained in:
Allanis 2013-10-01 22:12:39 +01:00
parent 6e1d312daf
commit ebdfaad9a7
3 changed files with 254 additions and 8 deletions

View File

@ -332,6 +332,8 @@ void main_loop(void) {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
fps_control(); /* Everyone loves fps control.. */ fps_control(); /* Everyone loves fps control.. */
sound_update(); /* Update sounds. */
if(toolkit) toolkit_update(); /* To simulate key repetition. */ if(toolkit) toolkit_update(); /* To simulate key repetition. */
if(!menu_isOpen(MENU_MAIN)) { if(!menu_isOpen(MENU_MAIN)) {
if(!paused) update_all(); /* Update game. */ if(!paused) update_all(); /* Update game. */

View File

@ -26,19 +26,64 @@ int sound_disabled = 0; /**< Whether sound is disabled. */
static int sound_reserved = 0; /**< Amount of reserved channels. */ static int sound_reserved = 0; /**< Amount of reserved channels. */
static double sound_pos[3]; /**< Position of listener. */ static double sound_pos[3]; /**< Position of listener. */
/* Give the buffers a name. */ /**
* @struct alSound
*
* @brief Contains a sound buffer.
*/
typedef struct alSound_ { typedef struct alSound_ {
char* name; /**< Buffers name. */ char* name; /**< Buffers name. */
Mix_Chunk* buffer; /**< Buffer data. */ Mix_Chunk* buffer; /**< Buffer data. */
} alSound; } 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). */ /* 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 alSound* sound_list = NULL; /**< List of available sounds. */
static int sound_nlist = 0; /**< Number 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 int sound_makeList(void);
static Mix_Chunk* sound_load(char* filename); static Mix_Chunk* sound_load(char* filename);
static void sound_free(alSound* snd); 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) * @fn int sound_init(void)
@ -77,6 +122,9 @@ int sound_init(void) {
sound_makeList(); sound_makeList();
sound_volume(0.4); sound_volume(0.4);
/* Finish function. */
Mix_ChannelFinished(voice_markStopped);
/* Init the music. */ /* Init the music. */
music_init(); music_init();
@ -90,6 +138,19 @@ int sound_init(void) {
*/ */
void sound_exit(void) { void sound_exit(void) {
int i; 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. */ /* Free the sounds. */
for(i = 0; i < sound_nlist; i++) for(i = 0; i < sound_nlist; i++)
@ -155,7 +216,7 @@ int sound_play(int sound) {
* @return 0 on success. * @return 0 on success.
*/ */
int sound_playPos(int sound, double x, double y) { int sound_playPos(int sound, double x, double y) {
int channel; alVoice* v;
double angle, dist; double angle, dist;
double px, py; double px, py;
@ -164,28 +225,128 @@ int sound_playPos(int sound, double x, double y) {
if((sound < 0) || (sound > sound_nlist)) if((sound < 0) || (sound > sound_nlist))
return -1; return -1;
px = x - sound_pos[0]; /* Get a new voice. */
py = y - sound_pos[1]; 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.; angle = sound_pos[2] - ANGLE(px, py)/M_PI*180.;
dist = MOD(px, py); 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()); WARN("Unable to play sound: %s", Mix_GetError());
return -1; 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()); WARN("Unable to set sound position: %s", Mix_GetError());
return -1; 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; 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) * @fn int sound_updateListener(double dir, double x, double y)
* *
@ -410,3 +571,83 @@ void sound_stopGroup(int group) {
Mix_HaltGroup(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;
}

View File

@ -5,12 +5,15 @@ extern int sound_disabled;
/* Sound subsystem. */ /* Sound subsystem. */
int sound_init(void); int sound_init(void);
void sound_exit(void); void sound_exit(void);
int sound_update(void);
/* Sound manupulation functions. */ /* Sound manupulation functions. */
int sound_get(char* name); int sound_get(char* name);
int sound_volume(const double vol); int sound_volume(const double vol);
int sound_play(int sound); int sound_play(int sound);
int sound_playPos(int sound, double x, double y); 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); int sound_updateListener(double dir, double x, double y);
/* Group functions. */ /* Group functions. */