From dcc0fc247b9fe4b39269caf2726792492649bf8b Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Fri, 22 Feb 2013 05:34:24 +0000
Subject: [PATCH] [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 @@
 		</general>
     <specific type="1">
       <gfx>lasergreen</gfx>
+			<sound>laser</sound>
       <delay>500</delay>
       <speed>550</speed>
       <range>300</range>
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)--;