[Add] Improved sound system considerably, not used properly yet.
This commit is contained in:
parent
6e1d312daf
commit
ebdfaad9a7
@ -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. */
|
||||
|
257
src/sound.c
257
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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user