about summary refs log tree commit diff
path: root/src/engine/client/sound.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/client/sound.cpp')
-rw-r--r--src/engine/client/sound.cpp92
1 files changed, 55 insertions, 37 deletions
diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp
index c2ca91f7..343fa2e8 100644
--- a/src/engine/client/sound.cpp
+++ b/src/engine/client/sound.cpp
@@ -1,8 +1,11 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#include <base/math.h>
 #include <base/system.h>
+
 #include <engine/graphics.h>
 #include <engine/storage.h>
+
 #include <engine/shared/config.h>
 
 #include "SDL.h"
@@ -19,8 +22,6 @@ enum
 	NUM_SAMPLES = 512,
 	NUM_VOICES = 64,
 	NUM_CHANNELS = 16,
-	
-	MAX_FRAMES = 1024
 };
 
 struct CSample
@@ -63,7 +64,8 @@ static int m_MixingRate = 48000;
 static volatile int m_SoundVolume = 100;
 
 static int m_NextVoice = 0;
-
+static int *m_pMixBuffer = 0;	// buffer only used by the thread callback function
+static unsigned m_MaxFrames = 0;
 
 // TODO: there should be a faster way todo this
 static short Int2Short(int i)
@@ -84,26 +86,27 @@ static int IntAbs(int i)
 
 static void Mix(short *pFinalOut, unsigned Frames)
 {
-	int aMixBuffer[MAX_FRAMES*2] = {0};
 	int MasterVol;
+	mem_zero(m_pMixBuffer, m_MaxFrames*2*sizeof(int));
+	Frames = min(Frames, m_MaxFrames);
 
 	// aquire lock while we are mixing
 	lock_wait(m_SoundLock);
-	
+
 	MasterVol = m_SoundVolume;
-	
+
 	for(unsigned i = 0; i < NUM_VOICES; i++)
 	{
 		if(m_aVoices[i].m_pSample)
 		{
 			// mix voice
 			CVoice *v = &m_aVoices[i];
-			int *pOut = aMixBuffer;
+			int *pOut = m_pMixBuffer;
 
 			int Step = v->m_pSample->m_Channels; // setup input sources
 			short *pInL = &v->m_pSample->m_pData[v->m_Tick*Step];
 			short *pInR = &v->m_pSample->m_pData[v->m_Tick*Step+1];
-			
+
 			unsigned End = v->m_pSample->m_NumFrames-v->m_Tick;
 
 			int Rvol = v->m_pChannel->m_Vol;
@@ -112,7 +115,7 @@ static void Mix(short *pFinalOut, unsigned Frames)
 			// make sure that we don't go outside the sound data
 			if(Frames < End)
 				End = Frames;
-			
+
 			// check if we have a mono sound
 			if(v->m_pSample->m_Channels == 1)
 				pInR = pInL;
@@ -126,14 +129,14 @@ static void Mix(short *pFinalOut, unsigned Frames)
 				int dy = v->m_Y - m_CenterY;
 				int Dist = (int)sqrtf((float)dx*dx+dy*dy); // float here. nasty
 				int p = IntAbs(dx);
-				if(Dist < Range)
+				if(Dist >= 0 && Dist < Range)
 				{
 					// panning
 					if(dx > 0)
 						Lvol = ((Range-p)*Lvol)/Range;
 					else
 						Rvol = ((Range-p)*Rvol)/Range;
-					
+
 					// falloff
 					Lvol = (Lvol*(Range-Dist))/Range;
 					Rvol = (Rvol*(Range-Dist))/Range;
@@ -154,7 +157,7 @@ static void Mix(short *pFinalOut, unsigned Frames)
 				pInR += Step;
 				v->m_Tick++;
 			}
-			
+
 			// free voice if not used any more
 			if(v->m_Tick == v->m_pSample->m_NumFrames)
 			{
@@ -165,8 +168,8 @@ static void Mix(short *pFinalOut, unsigned Frames)
 			}
 		}
 	}
-	
-	
+
+
 	// release the lock
 	lock_release(m_SoundLock);
 
@@ -176,8 +179,8 @@ static void Mix(short *pFinalOut, unsigned Frames)
 		for(unsigned i = 0; i < Frames; i++)
 		{
 			int j = i<<1;
-			int vl = ((aMixBuffer[j]*MasterVol)/101)>>8;
-			int vr = ((aMixBuffer[j+1]*MasterVol)/101)>>8;
+			int vl = ((m_pMixBuffer[j]*MasterVol)/101)>>8;
+			int vr = ((m_pMixBuffer[j+1]*MasterVol)/101)>>8;
 
 			pFinalOut[j] = Int2Short(vl);
 			pFinalOut[j+1] = Int2Short(vr);
@@ -201,14 +204,20 @@ int CSound::Init()
 	m_SoundEnabled = 0;
 	m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
 	m_pStorage = Kernel()->RequestInterface<IStorage>();
-	
+
 	SDL_AudioSpec Format;
-	
+
 	m_SoundLock = lock_create();
-	
+
 	if(!g_Config.m_SndEnable)
 		return 0;
-	
+
+	if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
+	{
+		dbg_msg("gfx", "unable to init SDL audio: %s", SDL_GetError());
+		return -1;
+	}
+
 	m_MixingRate = g_Config.m_SndRate;
 
 	// Set 16-bit stereo audio at 22Khz
@@ -228,8 +237,11 @@ int CSound::Init()
 	else
 		dbg_msg("client/sound", "sound init successful");
 
+	m_MaxFrames = g_Config.m_SndBufferSize*2;
+	m_pMixBuffer = (int *)mem_alloc(m_MaxFrames*2*sizeof(int), 1);
+
 	SDL_PauseAudio(0);
-	
+
 	m_SoundEnabled = 1;
 	Update(); // update the volume
 	return 0;
@@ -239,24 +251,30 @@ int CSound::Update()
 {
 	// update volume
 	int WantedVolume = g_Config.m_SndVolume;
-	
+
 	if(!m_pGraphics->WindowActive() && g_Config.m_SndNonactiveMute)
 		WantedVolume = 0;
-	
+
 	if(WantedVolume != m_SoundVolume)
 	{
 		lock_wait(m_SoundLock);
 		m_SoundVolume = WantedVolume;
 		lock_release(m_SoundLock);
 	}
-	
+
 	return 0;
 }
 
 int CSound::Shutdown()
 {
 	SDL_CloseAudio();
+	SDL_QuitSubSystem(SDL_INIT_AUDIO);
 	lock_destroy(m_SoundLock);
+	if(m_pMixBuffer)
+	{
+		mem_free(m_pMixBuffer);
+		m_pMixBuffer = 0;
+	}
 	return 0;
 }
 
@@ -277,7 +295,7 @@ void CSound::RateConvert(int SampleID)
 	CSample *pSample = &m_aSamples[SampleID];
 	int NumFrames = 0;
 	short *pNewData = 0;
-	
+
 	// make sure that we need to convert this sound
 	if(!pSample->m_pData || pSample->m_Rate == m_MixingRate)
 		return;
@@ -285,7 +303,7 @@ void CSound::RateConvert(int SampleID)
 	// allocate new data
 	NumFrames = (int)((pSample->m_NumFrames/(float)pSample->m_Rate)*m_MixingRate);
 	pNewData = (short *)mem_alloc(NumFrames*pSample->m_Channels*sizeof(short), 1);
-	
+
 	for(int i = 0; i < NumFrames; i++)
 	{
 		// resample TODO: this should be done better, like linear atleast
@@ -293,7 +311,7 @@ void CSound::RateConvert(int SampleID)
 		int f = (int)(a*pSample->m_NumFrames);
 		if(f >= pSample->m_NumFrames)
 			f = pSample->m_NumFrames-1;
-		
+
 		// set new data
 		if(pSample->m_Channels == 1)
 			pNewData[i] = pSample->m_pData[f];
@@ -303,7 +321,7 @@ void CSound::RateConvert(int SampleID)
 			pNewData[i*2+1] = pSample->m_pData[f*2+1];
 		}
 	}
-	
+
 	// free old data and apply new
 	mem_free(pSample->m_pData);
 	pSample->m_pData = pNewData;
@@ -321,15 +339,15 @@ int CSound::LoadWV(const char *pFilename)
 	int SampleID = -1;
 	char aError[100];
 	WavpackContext *pContext;
-	
+
 	// don't waste memory on sound when we are stress testing
 	if(g_Config.m_DbgStress)
 		return -1;
-		
+
 	// no need to load sound when we are running with no sound
 	if(!m_SoundEnabled)
 		return 1;
-		
+
 	if(!m_pStorage)
 		return -1;
 
@@ -372,7 +390,7 @@ int CSound::LoadWV(const char *pFilename)
 			dbg_msg("sound/wv", "file is %d Hz, not 44100 Hz. filename='%s'", snd->rate, filename);
 			return -1;
 		}*/
-		
+
 		if(BitsPerSample != 16)
 		{
 			dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", BitsPerSample, pFilename);
@@ -382,7 +400,7 @@ int CSound::LoadWV(const char *pFilename)
 		pData = (int *)mem_alloc(4*m_aSamples*m_aChannels, 1);
 		WavpackUnpackSamples(pContext, pData, m_aSamples); // TODO: check return value
 		pSrc = pData;
-		
+
 		pSample->m_pData = (short *)mem_alloc(2*m_aSamples*m_aChannels, 1);
 		pDst = pSample->m_pData;
 
@@ -428,9 +446,9 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
 {
 	int VoiceID = -1;
 	int i;
-	
+
 	lock_wait(m_SoundLock);
-	
+
 	// search for voice
 	for(i = 0; i < NUM_VOICES; i++)
 	{
@@ -442,7 +460,7 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
 			break;
 		}
 	}
-	
+
 	// voice found, use it
 	if(VoiceID != -1)
 	{
@@ -457,7 +475,7 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
 		m_aVoices[VoiceID].m_X = (int)x;
 		m_aVoices[VoiceID].m_Y = (int)y;
 	}
-	
+
 	lock_release(m_SoundLock);
 	return VoiceID;
 }