From 529ca21644e0aa555da63acd5cc432876b329df8 Mon Sep 17 00:00:00 2001 From: Allanis Date: Fri, 22 Feb 2013 04:06:47 +0000 Subject: [PATCH 1/2] [Add] Audio engine is now working, it It's fully tuned enough yet however. [Change] Refactored ship.c to comply with xml.* standards. --- src/music.c | 6 +++ src/music.h | 1 + src/outfit.c | 5 +- src/outfit.h | 2 + src/pilot.c | 9 ++++ src/pilot.h | 7 ++- src/player.c | 11 ++++- src/ship.c | 101 +++++++++++++++++++++-------------------- src/ship.h | 3 ++ src/sound.c | 126 +++++++++++++++++++++++++++++++++++++++++---------- src/sound.h | 9 ++-- src/weapon.c | 24 +++++++++- 12 files changed, 224 insertions(+), 80 deletions(-) diff --git a/src/music.c b/src/music.c index 55ae090..62f97c1 100644 --- a/src/music.c +++ b/src/music.c @@ -153,6 +153,8 @@ void music_exit(void) { for(i = 0; i < nmusic_selection; i++) free(music_selection[i]); free(music_selection); + + SDL_DestroyMutex(music_vorbis_lock); } // Internal music loading ruitines. @@ -220,6 +222,10 @@ static void music_free(void) { SDL_mutexV(music_vorbis_lock); } +void music_volume(const double vol) { + alSourcef(music_source, AL_GAIN, (ALfloat)vol); +} + // Music control functions. void music_load(const char* name) { int i; diff --git a/src/music.h b/src/music.h index 857e93c..96bb65f 100644 --- a/src/music.h +++ b/src/music.h @@ -9,6 +9,7 @@ int music_init(void); void music_exit(void); // Music control. +void music_volume(const double vol); void music_load(const char* name); void music_play(void); void music_stop(void); diff --git a/src/outfit.c b/src/outfit.c index a9dce7c..951f890 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -159,6 +159,8 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) { OUTFIT_GFX"%s.png", xml_get(node)); tmp->gfx_space = gl_newSprite(str, 6, 6); } + else if(xml_isNode(node, "sound")) + tmp->sound = sound_get(xml_get(node)); else if(xml_isNode(node, "damage")) { cur = node->children; do { @@ -170,7 +172,8 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) { #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) if(tmp->gfx_space == NULL) WARN("Outfit '%s' missing 'gfx' element", tmp->name); - MELEMENT(tmp->thrust, " thrust"); + MELEMENT(tmp->sound, "sound"); + MELEMENT(tmp->thrust, "thrust"); MELEMENT(tmp->turn, "turn"); MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->range, "duration"); diff --git a/src/outfit.h b/src/outfit.h index 2eceb69..99921de 100644 --- a/src/outfit.h +++ b/src/outfit.h @@ -1,5 +1,6 @@ #pragma once #include "opengl.h" +#include "sound.h" #define outfit_isProp(o,p) ((o)->properties & p) // Property flags. @@ -46,6 +47,7 @@ typedef struct { double damage_armour, damage_shield; // Damage. glTexture* gfx_space; + ALuint sound; // Sound to play. }; struct { // Launcher. //unsigned int delay; // Delay between shots. diff --git a/src/pilot.c b/src/pilot.c index 5ebe951..9450e93 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -254,6 +254,10 @@ static void pilot_update(Pilot* pilot, const double dt) { // Should not go faster. vect_pset(&pilot->solid->vel, VMOD(pilot->solid->vel) - 0.3*pilot->ship->thrust*dt, VANGLE(pilot->solid->vel)); + + // Update the source. + alSource3f(pilot->source, AL_POSITION, pilot->solid->pos.x, pilot->solid->pos.y, 0.); + alSource3f(pilot->source, AL_VELOCITY, pilot->solid->vel.x, pilot->solid->vel.y, 0.); } // Pilot is getting ready or is in, hyperspace. @@ -356,7 +360,12 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi } } + // Sound source. + // Eh.... + + // Set flags and functions. if(flags & PILOT_PLAYER) { + alSourcef(pilot->source, AL_GAIN, 0.); pilot->think = player_think; // Players don't need to thing! :P pilot->render = NULL; // Render will be called from player_think pilot_setFlag(pilot, PILOT_PLAYER); // It's a player! diff --git a/src/pilot.h b/src/pilot.h index 53b8bbd..8d1ff23 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -4,6 +4,7 @@ #include "ai.h" #include "outfit.h" #include "faction.h" +#include "sound.h" #include "ship.h" #define PLAYER_ID 1 @@ -66,7 +67,11 @@ typedef struct Pilot { PilotOutfit* secondary; // Secondary weapon. PilotOutfit* ammo; // Secondary ammo (if needed). - unsigned int flags; // Used for AI etc. + // Sound source. + ALuint source; + + // Misc. + unsigned int flags; // Used for AI etc. unsigned int ptimer; // Generic timer for internal pilot use. // AI. diff --git a/src/player.c b/src/player.c index 30852a1..01232f6 100644 --- a/src/player.c +++ b/src/player.c @@ -174,7 +174,8 @@ void player_new(void) { d = RNG(0, 359)/180.*M_PI; pilot_create(ship, "Player", faction_get("Player"), NULL, d, &v, NULL, PILOT_PLAYER); - gl_bindCamera(&player->solid->pos); + alSourcef(player->source, AL_GAIN, 0.5); + gl_bindCamera(&player->solid->pos); // Set opengl camers. space_init(system); // Welcome message. @@ -796,6 +797,14 @@ void player_think(Pilot* player) { pilot_shoot(player, player_target, 1); vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir); + + // Set the listener stuff. + ALfloat ori[] = { 0., 0., 0., 0., 0., 1. }; + ori[0] = cos(player->solid->dir); + ori[1] = sin(player->solid->dir); + alListenerfv(AL_ORIENTATION, ori); + alListener3f(AL_POSITION, player->solid->pos.x, player->solid->pos.y, 0.); + alListener3f(AL_VELOCITY, player->solid->vel.x, player->solid->vel.y, 0.); } // Modify the radar resolution. diff --git a/src/ship.c b/src/ship.c index ec9a791..ef96c31 100644 --- a/src/ship.c +++ b/src/ship.c @@ -38,81 +38,83 @@ static Ship* ship_parse(xmlNodePtr parent) { ShipOutfit* otmp, *ocur; char str[PATH_MAX] = "\0"; - xmlChar* xstr; + char* stmp; - tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); + tmp->name = xml_nodeProp(parent, "name"); if(tmp->name == NULL) WARN("Ship in "SHIP_DATA" has invalid or no name"); node = parent->xmlChildrenNode; do { // Load all the data. - if(strcmp((char*)node->name, "GFX")==0) { - snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_EXT), - SHIP_GFX"%s"SHIP_EXT, (char*)node->children->content); + if(xml_isNode(node,"GFX")) { + snprintf(str, strlen(xml_get(node)) + sizeof(SHIP_GFX) + sizeof(SHIP_EXT), + SHIP_GFX"%s"SHIP_EXT, xml_get(node)); tmp->gfx_space = gl_newSprite(str, 6, 6); // Target. - snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_TARGET)+sizeof(SHIP_EXT), - SHIP_GFX"%s"SHIP_TARGET SHIP_EXT, (char*)node->children->content); + snprintf(str, strlen(xml_get(node)) + sizeof(SHIP_GFX)+sizeof(SHIP_TARGET)+sizeof(SHIP_EXT), + SHIP_GFX"%s"SHIP_TARGET SHIP_EXT, xml_get(node)); tmp->gfx_target = gl_newImage(str); } - else if(strcmp((char*)node->name, "GUI")==0) - tmp->gui = strdup((char*)node->children->content); - else if(strcmp((char*)node->name, "class")==0) - tmp->class = atoi((char*)node->children->content); - else if(strcmp((char*)node->name, "movement")==0) { + else if(xml_isNode(node, "GUI")) + tmp->gui = strdup(xml_get(node)); + else if(xml_isNode(node, "sound")) + tmp->sound = sound_get(xml_get(node)); + else if(xml_isNode(node, "class")) + tmp->class = atoi(xml_get(node)); + else if(xml_isNode(node, "movement")) { cur = node->children; do { - if(strcmp((char*)cur->name, "thrust")==0) - tmp->thrust = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "turn")==0) - tmp->turn = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "speed")==0) - tmp->speed = atoi((char*)cur->children->content); + if(xml_isNode(cur, "thrust")) + tmp->thrust = xml_getInt(cur); + else if(xml_isNode(cur, "turn")) + tmp->turn = xml_getInt(cur); + else if(xml_isNode(cur, "speed")) + tmp->speed = xml_getInt(cur); } while((cur = cur->next)); } - else if(strcmp((char*)node->name, "health")==0) { + else if(xml_isNode(node, "health")) { cur = node->children; do { - if(strcmp((char*)cur->name, "armour")==0) - tmp->armour = (double)atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "shield")==0) - tmp->shield = (double)atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "energy")==0) - tmp->energy = (double)atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "armour_regen")==0) - tmp->armour_regen = (double)(atoi((char*)cur->children->content))/60.0; - else if(strcmp((char*)cur->name, "shield_regen")==0) - tmp->shield_regen = (double)(atoi((char*)cur->children->content))/60.0; - else if(strcmp((char*)cur->name, "energy_regen")==0) - tmp->energy_regen = (double)(atoi((char*)cur->children->content))/60.0; + if(xml_isNode(cur, "armour")) + tmp->armour = (double)xml_getInt(cur); + else if(xml_isNode(cur, "shield")) + tmp->shield = (double)xml_getInt(cur); + else if(xml_isNode(cur, "energy")) + tmp->energy = (double)xml_getInt(cur); + else if(xml_isNode(cur, "armour_regen")) + tmp->armour_regen = (double)(xml_getInt(cur))/60.0; + else if(xml_isNode(cur, "shield_regen")) + tmp->shield_regen = (double)(xml_getInt(cur))/60.0; + else if(xml_isNode(cur, "energy_regen")) + tmp->energy_regen = (double)(xml_getInt(cur))/60.0; } while((cur = cur->next)); } - else if(strcmp((char*)node->name, "characteristics")==0) { + else if(xml_isNode(node, "characteristics")) { cur = node->children; do { - if(strcmp((char*)cur->name, "crew")==0) - tmp->crew = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "mass")==0) - tmp->mass = (double)atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "cap_weapon")==0) - tmp->cap_weapon = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "cap_cargo")==0) - tmp->cap_cargo = atoi((char*)cur->children->content); + if(xml_isNode(cur, "crew")) + tmp->crew = xml_getInt(cur); + else if(xml_isNode(cur, "mass")) + tmp->mass = (double)xml_getInt(cur); + else if(xml_isNode(cur, "cap_weapon")) + tmp->cap_weapon = xml_getInt(cur); + else if(xml_isNode(cur, "cap_cargo")) + tmp->cap_cargo = xml_getInt(cur); } while((cur = cur->next)); } - else if(strcmp((char*)node->name, "outfits")==0) { + else if(xml_isNode(node, "outfits")) { cur = node->children; do { - if(strcmp((char*)cur->name, "outfit")==0) { + if(xml_isNode(cur, "outfit")) { otmp = MALLOC_L(ShipOutfit); - otmp->data = outfit_get((char*)cur->children->content); - xstr = xmlGetProp(cur, (xmlChar*)"quantity"); - if(!xstr) + otmp->data = outfit_get(xml_get(cur)); + stmp = xml_nodeProp(cur, "quantity"); + if(!stmp) WARN("Ship '%s' is missing tag 'quantity for outfit '%s'", tmp->name, otmp->data->name); - otmp->quantity = atoi((char*)xstr); - free(xstr); + otmp->quantity = atoi(stmp); + free(stmp); otmp->next = NULL; if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp; @@ -130,17 +132,18 @@ static Ship* ship_parse(xmlNodePtr parent) { #define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name) if(tmp->name == NULL) WARN("Ship '%s' missing 'name' tag", tmp->name); if(tmp->gfx_space == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name); + if(tmp->gui == NULL) WARN("Ship '%s' missing 'GUI' element", tmp->name); MELEMENT(tmp->thrust, "thrust"); MELEMENT(tmp->turn, "turn"); MELEMENT(tmp->speed, "speed"); - MELEMENT(tmp->crew, "crew"); - MELEMENT(tmp->mass, "mass"); MELEMENT(tmp->armour, "armour"); MELEMENT(tmp->armour_regen, "armour_regen"); MELEMENT(tmp->shield, "shield"); MELEMENT(tmp->shield_regen, "shield_regen"); MELEMENT(tmp->energy, "energy"); MELEMENT(tmp->energy_regen, "energt_regen"); + MELEMENT(tmp->crew, "crew"); + MELEMENT(tmp->mass, "mass"); MELEMENT(tmp->cap_cargo, "cap_cargo"); MELEMENT(tmp->cap_weapon, "cap_weapon"); #undef MELEMENT diff --git a/src/ship.h b/src/ship.h index 0555900..fbfca35 100644 --- a/src/ship.h +++ b/src/ship.h @@ -36,6 +36,9 @@ typedef struct { // GUI interface. char* gui; + + // Sound. + ALuint sound; // Characteristics. int crew; diff --git a/src/sound.c b/src/sound.c index 256f9a4..2d2e821 100644 --- a/src/sound.c +++ b/src/sound.c @@ -9,20 +9,29 @@ #include "music.h" #include "sound.h" -// This isn't always set? -#ifndef AL_FORMAT_VORBIS_EXT -#define AL_FORMAT_VORBIS_EXT 0x10003 -#endif +#define SOUND_PREFIX "snd/sounds/" +#define SOUND_SUFFIX ".wav" typedef struct { - ALfloat x, y; -} alVector; + char* name; + ALuint buffer; +} alSound; +// Gobal device and context. static ALCcontext* al_context = NULL; static ALCdevice* al_device = NULL; +// Music player thread to assure streaming is perfect. static SDL_Thread* music_player = NULL; +// List of sounds available (All preloaded into a buffer). +static alSound* sound_list = NULL; +static int nsound_list = 0; + +static int sound_makeList(void); +static int sound_load(ALuint* buffer, char* filename); +static void sound_free(alSound* snd); + int sound_init(void) { // Open the default device. al_device = alcOpenDevice(NULL); @@ -38,18 +47,16 @@ int sound_init(void) { return -2; } - // We use the vorbis extension for AL to load it easily. - if(alIsExtensionPresent("AL_EXT_vorbis") == AL_FALSE) { - WARN("AL_EXT_vorbis not available in OpenAL context!"); - return -3; - } - // Set active context. if(alcMakeContextCurrent(al_context)==AL_FALSE) { WARN("Failure to set default context"); return -4; } + // Load up all the sounds. + sound_makeList(); + + // Start the music server. music_init(); music_player = SDL_CreateThread(music_thread, NULL); @@ -59,6 +66,16 @@ int sound_init(void) { // Clean up after the sound system. void sound_exit(void) { + int i; + // Free the sounds. + for(i = 0; i < &nsound_list; i++) + sound_free(&sound_list[i]); + free(sound_list); + sound_list = NULL; + nsound_list = 0; + + // Must stop the music before killing it, + // then thread should commit suicide. music_stop(); music_kill(); SDL_WaitThread(music_player, NULL); @@ -71,19 +88,67 @@ void sound_exit(void) { if(al_device) alcCloseDevice(al_device); } -// Loads a vorbis file. -ALuint sound_sndCreate(char* filename) { - void* ovdata; +// Get the buffer to sound of [name]. +ALuint sound_get(char* name) { + int i; + for(i = 0; i < nsound_list; i++) + if(strcmp(name, sound_list[i].name)==0) + return sound_list[i].buffer; + WARN("Sound '%s' not found in sound list", name); + return 0; +} + +// Make list of available sounds. +static int sound_makeList(void) { + char** files; + uint32_t nfiles, i; + char tmp[64]; + int len; + + // Get the file list. + files = pack_listfiles(data, &nfiles); + + // Load the profiles. + for(i = 0; i < nfiles; i++) + if((strncmp(files[i], SOUND_PREFIX, strlen(SOUND_PREFIX))==0) && + (strncmp(files[i] + strlen(files[i]) - strlen(SOUND_SUFFIX), + SOUND_SUFFIX, strlen(SOUND_SUFFIX))==0)) { + + // Expand the selection size. + sound_list = realloc(sound_list, ++nsound_list * sizeof(alSound)); + + // Remove the prefix and suffix. + len = strlen(files[i]) - strlen(SOUND_SUFFIX SOUND_SUFFIX); + strncpy(tmp, files[i] + strlen(SOUND_PREFIX), len); + tmp[len] = '\0'; + + // give it the new name. + sound_list[nsound_list-1].name = strdup(tmp); + sound_load(&sound_list[nsound_list-1].buffer, files[i]); + } + + // Free the char* allocated by pack. + for(i = 0; i < nfiles; i++) + free(files[i]); + free(files); + + DEBUG("Loaded %d sound%c", nsound_list, (nsound_list==1)?' ':'s'); + + return 0; +} + +// Loads a sound into the sound_list. +static int sound_load(ALuint* buffer, char* filename) { + void* wavdata; unsigned int size; ALenum err; - ALuint buf; // Get the file data buffer from the packfile. - ovdata = pack_readfile(DATA, filename, &size); + wavdata = pack_readfile(DATA, filename, &size); // Bind to OpenAL buffer. - alGenBuffers(1, &buf); - alBufferData(buf, AL_FORMAT_VORBIS_EXT, ovdata, size, 44800); + alGenBuffers(1, buffer); + alBufferData(*buffer, AL_FORMAT_MONO16, wavdata, size, 22050); // Errors? if((err = alGetError()) != AL_NO_ERROR) { @@ -92,11 +157,26 @@ ALuint sound_sndCreate(char* filename) { } // Finish up. - free(ovdata); - return buf; + free(wavdata); + return 0; } -void sound_sndFree(const ALuint snd) { - alDeleteBuffers(1, &snd); +static void sound_free(alSound* snd) { + if(snd->name) free(snd->name); + alDeleteBuffers(1, &snd->buffer); +} + +ALuint sound_dynSource(double px, double py, double vx, double vy, int looping) { + ALuint tmp; + + alGenSources(1, &tmp); + + alSourcei(tmp, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(tmp, AL_POSITION, px, py, 0.); + alSource3f(tmp, AL_VELOCITY, vx, vy, 0.); + + if(looping) alSourcei(tmp, AL_LOOPING, AL_TRUE); + + return tmp; } diff --git a/src/sound.h b/src/sound.h index 06157b8..f66cc08 100644 --- a/src/sound.h +++ b/src/sound.h @@ -2,15 +2,16 @@ #include #include "physics.h" +#define SOUND_REFERENCE_DIST 500. +#define SOUND_MAX_DIST 1000. + // Sound subsystem. int sound_init(void); void sound_exit(void); // Sound manupulation functions. -ALuint sound_sndCreate(char* filename); -void sound_sndFree(const ALuint snd); +ALuint sound_get(char* name); // Source manipulation function. -#define sound_initSource(s) (alGenSources(1, &(s))) -#define sound_delSource(s) (alDeleteSources(1, &(s)) +ALuint sound_dynSource(double px, double py, double vx, double vy, int looping); diff --git a/src/weapon.c b/src/weapon.c index b059eff..23e096b 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -29,7 +29,9 @@ typedef struct Weapon { const Outfit* outfit; // Related outfit that fired. unsigned int timer; // Mainly used to see when the weapon was fired. - // Update position and render. + ALuint source; // Source for sound. + + // Update position and render. void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render. void(*think)(struct Weapon*); // Some missiles need to be inteligent. } Weapon; @@ -44,6 +46,7 @@ static int nwfrontLayer = 0; // Number of elements. static int mwfrontLayer = 0; // Allocated memory size. +static void weapon_sound(Weapon* w); static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel, const unsigned int parent, const unsigned int target); @@ -125,6 +128,14 @@ void weapons_update(const double dt) { weapons_updateLayer(dt, WEAPON_LAYER_FG); } +// Play the weapon sound. +static void weapon_sound(Weapon* w) { + w->source = sound_dynSource(w->solid->pos.x, w->solid->pos.y, + w->solid->vel.x, w->solid->vel.y, 0); + alSourcei(w->source, AL_BUFFER, w->outfit->sound); + alSourcePlay(w->source); +} + // Update all weapons in the layer. static void weapons_updateLayer(const double dt, const WeaponLayer layer) { Weapon** wlayer; @@ -222,6 +233,10 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) { } if(weapon_isSmart(w)) (*w->think)(w); (*w->solid->update)(w->solid, dt); + + // Update the sound. + alSource3f(w->source, AL_POSITION, w->solid->pos.x, w->solid->pos.y, 0.); + alSource3f(w->source, AL_VELOCITY, w->solid->vel.x, w->solid->vel.y, 0.); } // Good shot. @@ -260,14 +275,17 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* vectcpy(&v, vel); vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir)); w->solid = solid_create(mass, rdir, pos, &v); + weapon_sound(w); break; case OUTFIT_TYPE_MISSILE_SEEK_AMMO: mass = w->outfit->mass; w->solid = solid_create(mass, dir, pos, vel); w->think = think_seeker; // Eeek!!! + weapon_sound(w); break; default: // Just dump it where the player is. + w->source = 0; w->solid = solid_create(mass, dir, pos, vel); break; } @@ -336,6 +354,10 @@ static void weapon_destroy(Weapon* w, WeaponLayer layer) { break; } for(i = 0; wlayer[i] != w; i++); // Get us to the current posision. + if(w->source) { + alSourceStop(wlayer[i]->source); + alDeleteSources(1, &wlayer[i]->source); + } weapon_free(wlayer[i]); wlayer[i] = NULL; (*nlayer)--; From dcc0fc247b9fe4b39269caf2726792492649bf8b Mon Sep 17 00:00:00 2001 From: Allanis Date: Fri, 22 Feb 2013 05:34:24 +0000 Subject: [PATCH 2/2] [Add] Sound base support. --- dat/outfit.xml | 1 + src/main.c | 4 +- src/outfit.c | 3 ++ src/pilot.c | 8 ++-- src/player.c | 1 - src/sound.c | 126 ++++++++++++++++++++++++++++++++++++++++++++----- src/sound.h | 23 ++++++++- src/weapon.c | 27 +++-------- 8 files changed, 153 insertions(+), 40 deletions(-) diff --git a/dat/outfit.xml b/dat/outfit.xml index 29d0901..3dc6234 100644 --- a/dat/outfit.xml +++ b/dat/outfit.xml @@ -8,6 +8,7 @@ lasergreen + laser 500 550 300 diff --git a/src/main.c b/src/main.c index 1064d03..b2627bc 100644 --- a/src/main.c +++ b/src/main.c @@ -104,7 +104,7 @@ int main(int argc, char** argv) { // OpenAL sound. if(sound_init()) WARN("Problem setting up sound!"); music_load("Machina"); - music_play(); + //music_play(); // Input. if((indjoystick >= 0) || (namjoystick != NULL)) { @@ -170,6 +170,8 @@ int main(int argc, char** argv) { input_handle(&event); // handles all the events the player keybinds. } + sound_update(); // Do the sound stuff. + glClear(GL_COLOR_BUFFER_BIT); fps_control(); // Who doesn't love FPS control? diff --git a/src/outfit.c b/src/outfit.c index 951f890..0a8a49d 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -105,6 +105,8 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) { snprintf(str, strlen(xml_get(node))+sizeof(OUTFIT_GFX)+4, OUTFIT_GFX"%s.png", xml_get(node)); tmp->gfx_space = gl_newSprite(str, 6, 6); } + else if(xml_isNode(node, "sound")) + tmp->sound = sound_get(xml_get(node)); else if(xml_isNode(node, "damage")) { cur = node->children; do { @@ -116,6 +118,7 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) { #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) if(tmp->gfx_space == NULL) WARN("Outfit '%s' missing 'gfx' element", tmp->name); + MELEMENT(tmp->sound, "sound"); MELEMENT(tmp->delay, "delay"); MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->range, "range"); diff --git a/src/pilot.c b/src/pilot.c index 9450e93..5d633e2 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -252,12 +252,12 @@ static void pilot_update(Pilot* pilot, const double dt) { if(!pilot_isFlag(pilot, PILOT_HYPERSPACE) && VMOD(pilot->solid->vel) > pilot->ship->speed) // Should not go faster. - vect_pset(&pilot->solid->vel, VMOD(pilot->solid->vel) - 0.3*pilot->ship->thrust*dt, + vect_pset(&pilot->solid->vel, pilot->ship->speed, VANGLE(pilot->solid->vel)); // Update the source. - alSource3f(pilot->source, AL_POSITION, pilot->solid->pos.x, pilot->solid->pos.y, 0.); - alSource3f(pilot->source, AL_VELOCITY, pilot->solid->vel.x, pilot->solid->vel.y, 0.); + //alSource3f(pilot->source, AL_POSITION, pilot->solid->pos.x, pilot->solid->pos.y, 0.); + //alSource3f(pilot->source, AL_VELOCITY, pilot->solid->vel.x, pilot->solid->vel.y, 0.); } // Pilot is getting ready or is in, hyperspace. @@ -365,7 +365,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi // Set flags and functions. if(flags & PILOT_PLAYER) { - alSourcef(pilot->source, AL_GAIN, 0.); + //alSourcef(pilot->source, AL_GAIN, 0.); pilot->think = player_think; // Players don't need to thing! :P pilot->render = NULL; // Render will be called from player_think pilot_setFlag(pilot, PILOT_PLAYER); // It's a player! diff --git a/src/player.c b/src/player.c index 01232f6..7977c98 100644 --- a/src/player.c +++ b/src/player.c @@ -174,7 +174,6 @@ void player_new(void) { d = RNG(0, 359)/180.*M_PI; pilot_create(ship, "Player", faction_get("Player"), NULL, d, &v, NULL, PILOT_PLAYER); - alSourcef(player->source, AL_GAIN, 0.5); gl_bindCamera(&player->solid->pos); // Set opengl camers. space_init(system); diff --git a/src/sound.c b/src/sound.c index 2d2e821..1b99d49 100644 --- a/src/sound.c +++ b/src/sound.c @@ -12,11 +12,17 @@ #define SOUND_PREFIX "snd/sounds/" #define SOUND_SUFFIX ".wav" +// Give the buffers a name. typedef struct { - char* name; - ALuint buffer; + char* name; // Buffers name. + ALuint buffer; // Associated OpenAL buffer. } alSound; +#define VOICE_PLAYING (1<<0) // Voice is playing. +#define VOICE_LOOPING (1<<1) // Voice is looping. +#define voice_set(v,f) ((v)->flags |= f) +#define voice_is(v,f) ((v)->flags & f) + // Gobal device and context. static ALCcontext* al_context = NULL; static ALCdevice* al_device = NULL; @@ -28,11 +34,18 @@ static SDL_Thread* music_player = NULL; static alSound* sound_list = NULL; static int nsound_list = 0; +// Current sources playing. +static alVoice** voice_stack = NULL; +static int nvoice_stack = 0; +static int mvoice_stack = 0; + static int sound_makeList(void); static int sound_load(ALuint* buffer, char* filename); static void sound_free(alSound* snd); int sound_init(void) { + 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) { @@ -47,6 +60,9 @@ int sound_init(void) { return -2; } + // Clear the errors. + alGetError(); + // Set active context. if(alcMakeContextCurrent(al_context)==AL_FALSE) { WARN("Failure to set default context"); @@ -166,17 +182,103 @@ static void sound_free(alSound* snd) { alDeleteBuffers(1, &snd->buffer); } -ALuint sound_dynSource(double px, double py, double vx, double vy, int looping) { - ALuint tmp; +// Update the sounds and prioritize them. +void sound_update(void) { + int i; + + // TODO: Prioritize the things. - alGenSources(1, &tmp); + for(i = 0; i < nvoice_stack; i++) { + if(voice_is(voice_stack[i], VOICE_PLAYING)) { + // Update position. + alSource3f(voice_stack[i]->source, AL_POSITION, + voice_stack[i]->px, voice_stack[i]->py, 0.); + alSource3f(voice_stack[i]->source, AL_VELOCITY, + voice_stack[i]->vx, voice_stack[i]->vy, 0.); - alSourcei(tmp, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(tmp, AL_POSITION, px, py, 0.); - alSource3f(tmp, AL_VELOCITY, vx, vy, 0.); - - if(looping) alSourcei(tmp, AL_LOOPING, AL_TRUE); - - return tmp; + } + } +} + +// Create a dynamic moving voice. +alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy, + const ALuint buffer, const int looping) { + + alVoice* voc; + ALenum err; + + nvoice_stack++; + if(nvoice_stack > mvoice_stack) + voice_stack = realloc(voice_stack, ++mvoice_stack*sizeof(alVoice*)); + + voc = malloc(sizeof(alVoice)); + voice_stack[nvoice_stack-1] = voc; + + // Try and grab a source. + voc->source = 0; + alGenSources(1, &voc->source); + err = alGetError(); + if(err != AL_NO_ERROR) voc->source = 0; + + // Set the data. + voc->priority = priority; + voc->start = SDL_GetTicks(); + voc->buffer = buffer; + if(looping) voice_set(voc, VOICE_LOOPING); + voc->px = px; + voc->py = py; + voc->vx = vx; + voc->vy = vy; + + // Set the source. + if(voc->source) { + alSourcei(voc->source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcef(voc->source, AL_GAIN, 1.); + alSourcei(voc->source, AL_BUFFER, buffer); + alSource3f(voc->source, AL_POSITION, voc->px, voc->py, 0.); + alSource3f(voc->source, AL_VELOCITY, voc->vx, voc->vy, 0.); + if(voice_is(voc, VOICE_LOOPING)) + alSourcei(voc->source, AL_LOOPING, AL_TRUE); + + // Try to play the source. + alSourcePlay(voc->source); + err = alGetError(); + if(err == AL_NO_ERROR) voice_set(voc, VOICE_PLAYING); + else DEBUG("Source player failure"); + } + return voc; +} + +void sound_delVoice(alVoice* voice) { + ALint stat; + int i; + + for(i = 0; i < nvoice_stack; i++) + if(voice == voice_stack[i]) + break; + + // No match found. + if(i >= nvoice_stack) { + WARN("Unable to find voice to free from stack"); + return; + } + + if(voice->source) { + alGetSourcei(voice->source, AL_SOURCE_STATE, &stat); + if(stat == AL_PLAYING) alSourceStop(voice->source); + alDeleteSources(1, &voice->source); + voice->source = 0; + } + + nvoice_stack--; + for(; i < nvoice_stack; i++) + voice_stack[i] = voice_stack[i+1]; +} + +void voice_update(alVoice* voice, double px, double py, double vx, double vy) { + voice->px = px; + voice->py = py; + voice->vx = vx; + voice->vy = vy; } diff --git a/src/sound.h b/src/sound.h index f66cc08..b8e62b1 100644 --- a/src/sound.h +++ b/src/sound.h @@ -5,13 +5,32 @@ #define SOUND_REFERENCE_DIST 500. #define SOUND_MAX_DIST 1000. +// Virtual voice. +typedef struct { + ALuint source; // Source itself, 0 if not set. + ALuint buffer; // Buffer. + + int priority; // Base priority. + + double px, py; // Position. + double vx, vy; // Velocity. + + unsigned int start; // Time started in ms. + unsigned int flags; // Flags to set properties. +} alVoice; + // Sound subsystem. int sound_init(void); void sound_exit(void); +void sound_update(void); // Sound manupulation functions. ALuint sound_get(char* name); -// Source manipulation function. -ALuint sound_dynSource(double px, double py, double vx, double vy, int looping); +// Voice manipulation function. +alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy, + const ALuint buffer, const int looping); + +void sound_delVoice(alVoice* voice); +void voice_update(alVoice* voice, double px, double py, double vx, double vy); diff --git a/src/weapon.c b/src/weapon.c index 23e096b..61956f5 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -14,6 +14,9 @@ #define weapon_isSmart(w) (w->think) +#define VOICE_PRIORITY_BOLD 10 // Default. +#define VOICE_PRIORITY_AMMP 8 // Higher. + // Some stuff from pilot. extern Pilot** pilot_stack; extern int pilots; @@ -29,7 +32,7 @@ typedef struct Weapon { const Outfit* outfit; // Related outfit that fired. unsigned int timer; // Mainly used to see when the weapon was fired. - ALuint source; // Source for sound. + //alVoice voice; // Virtual voise. // Update position and render. void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render. @@ -45,8 +48,6 @@ static Weapon** wfrontLayer = NULL; // Behind pilots. static int nwfrontLayer = 0; // Number of elements. static int mwfrontLayer = 0; // Allocated memory size. - -static void weapon_sound(Weapon* w); static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel, const unsigned int parent, const unsigned int target); @@ -128,14 +129,6 @@ void weapons_update(const double dt) { weapons_updateLayer(dt, WEAPON_LAYER_FG); } -// Play the weapon sound. -static void weapon_sound(Weapon* w) { - w->source = sound_dynSource(w->solid->pos.x, w->solid->pos.y, - w->solid->vel.x, w->solid->vel.y, 0); - alSourcei(w->source, AL_BUFFER, w->outfit->sound); - alSourcePlay(w->source); -} - // Update all weapons in the layer. static void weapons_updateLayer(const double dt, const WeaponLayer layer) { Weapon** wlayer; @@ -235,8 +228,9 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) { (*w->solid->update)(w->solid, dt); // Update the sound. - alSource3f(w->source, AL_POSITION, w->solid->pos.x, w->solid->pos.y, 0.); - alSource3f(w->source, AL_VELOCITY, w->solid->vel.x, w->solid->vel.y, 0.); + /*if(w->voise) + voice_update(w->voice, w->solid->pos.x, w->solid->pos.y, + w->solid->vel.x, w->solid->vel.y);*/ } // Good shot. @@ -275,17 +269,14 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* vectcpy(&v, vel); vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir)); w->solid = solid_create(mass, rdir, pos, &v); - weapon_sound(w); break; case OUTFIT_TYPE_MISSILE_SEEK_AMMO: mass = w->outfit->mass; w->solid = solid_create(mass, dir, pos, vel); w->think = think_seeker; // Eeek!!! - weapon_sound(w); break; default: // Just dump it where the player is. - w->source = 0; w->solid = solid_create(mass, dir, pos, vel); break; } @@ -354,10 +345,6 @@ static void weapon_destroy(Weapon* w, WeaponLayer layer) { break; } for(i = 0; wlayer[i] != w; i++); // Get us to the current posision. - if(w->source) { - alSourceStop(wlayer[i]->source); - alDeleteSources(1, &wlayer[i]->source); - } weapon_free(wlayer[i]); wlayer[i] = NULL; (*nlayer)--;