about summary refs log tree commit diff
path: root/src/engine
diff options
context:
space:
mode:
authorJoel de Vahl <joel@stalverk80.se>2007-07-21 16:45:06 +0000
committerJoel de Vahl <joel@stalverk80.se>2007-07-21 16:45:06 +0000
commit18ec4d476ca7776ff856e2b2f08f62f6e39f927f (patch)
treee577a736a914942c348870537ca8e0241ef5a0cb /src/engine
parentd40868e913b9abce48de654871d2b0643c347dda (diff)
downloadzcatch-18ec4d476ca7776ff856e2b2f08f62f6e39f927f.tar.gz
zcatch-18ec4d476ca7776ff856e2b2f08f62f6e39f927f.zip
Rewritten mixer.
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/client/snd.cpp294
1 files changed, 88 insertions, 206 deletions
diff --git a/src/engine/client/snd.cpp b/src/engine/client/snd.cpp
index 5944655e..402483ea 100644
--- a/src/engine/client/snd.cpp
+++ b/src/engine/client/snd.cpp
@@ -37,7 +37,7 @@ inline short clamp(int i)
 	return i;
 }
 
-class mixer : public audio_stream
+static class mixer : public audio_stream
 {
 public:
 	class channel
@@ -64,80 +64,88 @@ public:
 
 	channel channels[MAX_CHANNELS];
 
+	void fill_mono(short *out, unsigned long frames, channel *c, float dv = 0.0f)
+	{
+		for(unsigned long i = 0; i < frames; i++)
+		{
+			float p = (1.0f-(c->pan+1.0f)*0.5f);
+			int val = (int)(p*c->vol * c->data->data[c->tick]);
+			out[i<<1] += (short)val;
+			out[(i<<1)+1] += (short)val;
+			c->tick++;
+			c->vol += dv;
+			if(c->vol < 0.0f) c->vol = 0.0f;
+		}
+	}
+
+	void fill_stereo(short *out, unsigned long frames, channel *c, float dv = 0.0f)
+	{
+		for(unsigned long i = 0; i < frames; i++)
+		{
+			float pl = c->pan<0.0f?-c->pan:1.0f;
+			float pr = c->pan>0.0f?1.0f-c->pan:1.0f;
+			int vl = (int)(pl*c->vol * c->data->data[c->tick]);
+			int vr = (int)(pr*c->vol * c->data->data[c->tick + 1]);
+			out[i<<1] += (short)vl;
+			out[(i<<1)+1] += (short)vr;
+			c->tick += 2;
+			c->vol += dv;
+			if(c->vol < 0.0f) c->vol = 0.0f;
+		}
+	}
+
 	virtual void fill(void *output, unsigned long frames)
 	{
-		//dbg_msg("snd", "mixing!");
-		
 		short *out = (short*)output;
-		bool clamp_flag = false;
-		
-		int active_channels = 0;
+
 		for(unsigned long i = 0; i < frames; i++)
 		{
-			int left = 0;
-			int right = 0;
-			
-			for(int c = 0; c < MAX_CHANNELS; c++)
+			out[i<<1] = 0;
+			out[(i<<1)+1] = 0;
+		}
+
+		for(int c = 0; c < MAX_CHANNELS; c++)
+		{
+			unsigned long filled = 0;
+			while(channels[c].data && filled < frames)
 			{
-				if(channels[c].data)
+				unsigned long to_fill = frames;
+				float dv = 0.0f;
+
+				if(channels[c].stop >= 0)
+					to_fill = (unsigned)channels[c].stop>frames?frames:channels[c].stop;
+				if(channels[c].loop >= 0 &&
+						channels[c].data->sustain_start >= 0)
 				{
-					if(channels[c].data->channels == 1)
-					{
-						left += (int)((1.0f-(channels[c].pan+1.0f)*0.5f) * channels[c].vol * channels[c].data->data[channels[c].tick]);
-						right += (int)((channels[c].pan+1.0f)*0.5f * channels[c].vol * channels[c].data->data[channels[c].tick]);
-						channels[c].tick++;
-					}
-					else
-					{
-						float pl = channels[c].pan<0.0f?-channels[c].pan:1.0f;
-						float pr = channels[c].pan>0.0f?1.0f-channels[c].pan:1.0f;
-						left += (int)(pl*channels[c].vol * channels[c].data->data[channels[c].tick]);
-						right += (int)(pr*channels[c].vol * channels[c].data->data[channels[c].tick + 1]);
-						channels[c].tick += 2;
-					}
-				
-					if(channels[c].loop)
-					{
-						if(channels[c].data->sustain_start >= 0 && channels[c].tick >= channels[c].data->sustain_end)
-							channels[c].tick = channels[c].data->sustain_start;
-						else if(channels[c].tick > channels[c].data->num_samples)
-							channels[c].tick = 0;
-					}
-					else if(channels[c].tick > channels[c].data->num_samples)
-						channels[c].data = 0;
-
-					if(channels[c].stop == 0)
-					{
-						channels[c].stop = -1;
-						channels[c].data = 0;
-					}
-					else if(channels[c].stop > 0)
-					{
-						channels[c].vol = channels[c].old_vol * (float)channels[c].stop * NUM_FRAMES_STOP_INV;
-						channels[c].stop--;
-					}
-					if(channels[c].lerp > 0)
-					{
-						channels[c].vol = (1.0f - (float)channels[c].lerp * NUM_FRAMES_LERP_INV) * channels[c].new_vol +
-							(float)channels[c].lerp * NUM_FRAMES_LERP_INV * channels[c].old_vol;
-						channels[c].lerp--;
-					}
-					active_channels++;
+					unsigned long tmp = channels[c].data->sustain_end - channels[c].tick;
+					to_fill = tmp>frames?frames:tmp;
 				}
-			}
 
-			// TODO: remove these
+				if(channels[c].lerp >= 0)
+				{
+						dv = (channels[c].new_vol - channels[c].old_vol) * NUM_FRAMES_LERP_INV;
+						dbg_msg("mixer", "lerp %f", dv);
+				}
 
-			*out = clamp(left); // left
-			if(*out != left) clamp_flag = true;
-			out++;
-			*out = clamp(right); // right
-			if(*out != right) clamp_flag = true;
-			out++;
-		}
+				if(channels[c].data->channels == 1)
+					fill_mono(out, to_fill, &channels[c], dv);
+				else
+					fill_stereo(out, to_fill, &channels[c], dv);
 
-		if(clamp_flag)
-			dbg_msg("snd", "CLAMPED!");
+				if(channels[c].loop >= 0 &&
+						channels[c].data->sustain_start >= 0 &&
+						channels[c].tick >= channels[c].data->sustain_end)
+					channels[c].tick = channels[c].data->sustain_start;
+				if(channels[c].tick >= channels[c].data->num_samples)
+					channels[c].data = 0;
+
+				channels[c].lerp -= to_fill;
+				if(channels[c].lerp < 0)
+					channels[c].lerp = 0;
+
+				filled += to_fill;
+			}
+		}
 	}
 	
 	int play(sound_data *sound, unsigned loop, float vol, float pan)
@@ -154,6 +162,7 @@ public:
 				channels[c].loop = loop;
 				channels[c].vol = vol * GLOBAL_VOLUME_SCALE;
 				channels[c].pan = pan;
+				channels[c].lerp = -1;
 				sound->last_played = time_get();
 				return c;
 			}
@@ -176,134 +185,7 @@ public:
 		channels[id].old_vol = channels[id].vol;
 		channels[id].lerp = NUM_FRAMES_LERP;
 	}
-};
-
-static mixer mixer;
-//static sound_data test_sound;
-
-/*
-extern "C" 
-{
-#include "wavpack/wavpack.h"
-}*/
-
-/*
-static file_stream *read_func_filestream;
-static int32_t read_func(void *buff, int32_t bcount)
-{
-    return read_func_filestream->read(buff, bcount);
-}
-static uchar *format_samples(int bps, uchar *dst, int32_t *src, uint32_t samcnt)
-{
-    int32_t temp;
-
-    switch (bps) {
-
-        case 1:
-            while (samcnt--)
-                *dst++ = *src++ + 128;
-
-            break;
-
-        case 2:
-            while (samcnt--) {
-                *dst++ = (uchar)(temp = *src++);
-                *dst++ = (uchar)(temp >> 8);
-            }
-
-            break;
-
-        case 3:
-            while (samcnt--) {
-                *dst++ = (uchar)(temp = *src++);
-                *dst++ = (uchar)(temp >> 8);
-                *dst++ = (uchar)(temp >> 16);
-            }
-
-            break;
-
-        case 4:
-            while (samcnt--) {
-                *dst++ = (uchar)(temp = *src++);
-                *dst++ = (uchar)(temp >> 8);
-                *dst++ = (uchar)(temp >> 16);
-                *dst++ = (uchar)(temp >> 24);
-            }
-
-            break;
-    }
-
-    return dst;
-}*/
-
-/*
-struct sound_holder
-{
-	sound_data sound;
-	int next;
-};
-
-static const int MAX_SOUNDS = 256;
-static sound_holder sounds[MAX_SOUNDS];
-static int first_free_sound;
-
-bool snd_load_wv(const char *filename, sound_data *snd)
-{
-	// open file
-	file_stream file;
-	if(!file.open_r(filename))
-	{
-		dbg_msg("sound/wv", "failed to open file. filename='%s'", filename);
-		return false;
-	}
-	read_func_filestream = &file;
-	
-	// get info
-	WavpackContext *wpc;
-	char error[128];
-	wpc = WavpackOpenFileInput(read_func, error);
-	if(!wpc)
-	{
-		dbg_msg("sound/wv", "failed to open file. err=%s filename='%s'", error, filename);
-		return false;
-	}
-
-
-	snd->num_samples = WavpackGetNumSamples(wpc);
-    int bps = WavpackGetBytesPerSample(wpc);
-	int channels = WavpackGetReducedChannels(wpc);
-	snd->rate = WavpackGetSampleRate(wpc);
-	int bits = WavpackGetBitsPerSample(wpc);
-	
-	(void)bps;
-	(void)channels;
-	(void)bits;
-	
-	// decompress
-	int datasize = snd->num_samples*2;
-	snd->data = (short*)mem_alloc(datasize, 1);
-	int totalsamples = 0;
-	while(1)
-	{
-		int buffer[1024*4];
-		int samples_unpacked = WavpackUnpackSamples(wpc, buffer, 1024*4);
-		totalsamples += samples_unpacked;
-		
-		if(samples_unpacked)
-		{
-			// convert
-		}
-	}
-	
-	if(snd->num_samples != totalsamples)
-	{
-		dbg_msg("sound/wv", "wrong amount of samples. filename='%s'", filename);
-		mem_free(snd->data);
-		return false;;
-	}
-		
-	return false;
-}*/
+} mixer;
 
 struct sound_holder
 {
@@ -428,11 +310,6 @@ int snd_load_wav(const char *filename)
 					return -1;
 				}
 				
-				// skip extra bytes (not used for uncompressed)
-				//int extra_bytes = fmt[14] | (fmt[15]<<8);
-				//dbg_msg("sound/wav", "%d", extra_bytes);
-				//file.skip(extra_bytes);
-				
 				// next state
 				state++;
 			}
@@ -468,22 +345,27 @@ int snd_load_wav(const char *filename)
 		{
 			if(head[0] == 's' && head[1] == 'm' && head[2] == 'p' && head[3] == 'l')
 			{
-				int smpl[9];
-				int loop[6];
+				unsigned char smpl[36];
+				unsigned char loop[24];
+				dbg_msg("sound/wav", "got sustain");
 
 				file.read(smpl, sizeof(smpl));
+				unsigned num_loops = (smpl[28] | (smpl[29]<<8) | (smpl[30]<<16) | (smpl[31]<<24));
+				unsigned skip = (smpl[32] | (smpl[33]<<8) | (smpl[34]<<16) | (smpl[35]<<24));
 
-				if(smpl[7] > 0)
+				if(num_loops > 0)
 				{
 					file.read(loop, sizeof(loop));
-					sounds[id].sound.sustain_start = loop[2] * sounds[id].sound.channels;
-					sounds[id].sound.sustain_end = loop[3] * sounds[id].sound.channels;
+					unsigned start = (loop[8] | (loop[9]<<8) | (loop[10]<<16) | (loop[11]<<24));
+					unsigned end = (loop[12] | (loop[13]<<8) | (loop[14]<<16) | (loop[15]<<24));
+					sounds[id].sound.sustain_start = start * sounds[id].sound.channels;
+					sounds[id].sound.sustain_end = end * sounds[id].sound.channels;
 				}
 
-				if(smpl[7] > 1)
-					file.skip((smpl[7]-1) * sizeof(loop));
+				if(num_loops > 1)
+					file.skip((num_loops-1) * sizeof(loop));
 
-				file.skip(smpl[8]);
+				file.skip(skip);
 				state++;
 			}
 			else
@@ -494,7 +376,7 @@ int snd_load_wav(const char *filename)
 	}
 
 	if(id >= 0)
-		dbg_msg("sound/wav", "loaded %s", filename);
+		dbg_msg("sound/wav", "loaded %s, sustain start: %d end: %d", filename, sounds[id].sound.sustain_start, sounds[id].sound.sustain_end);
 	else
 		dbg_msg("sound/wav", "failed to load %s", filename);