summaryrefslogtreecommitdiff
path: root/src/client/snd_mem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/snd_mem.cpp')
-rw-r--r--src/client/snd_mem.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/client/snd_mem.cpp b/src/client/snd_mem.cpp
new file mode 100644
index 0000000..128a471
--- /dev/null
+++ b/src/client/snd_mem.cpp
@@ -0,0 +1,297 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+/*****************************************************************************
+ * name: snd_mem.c
+ *
+ * desc: sound caching
+ *****************************************************************************/
+
+#include "snd_codec.h"
+#include "snd_local.h"
+
+#include "qcommon/cvar.h"
+
+#define DEF_COMSOUNDMEGS "8"
+
+/*
+===============================================================================
+
+memory management
+
+===============================================================================
+*/
+
+static sndBuffer *buffer = NULL;
+static sndBuffer *freelist = NULL;
+static int inUse = 0;
+static int totalInUse = 0;
+
+short *sfxScratchBuffer = NULL;
+sfx_t *sfxScratchPointer = NULL;
+int sfxScratchIndex = 0;
+
+void SND_free(sndBuffer *v)
+{
+ *(sndBuffer **)v = freelist;
+ freelist = (sndBuffer *)v;
+ inUse += sizeof(sndBuffer);
+}
+
+sndBuffer *SND_malloc(void)
+{
+ sndBuffer *v;
+redo:
+ if (freelist == NULL)
+ {
+ S_FreeOldestSound();
+ goto redo;
+ }
+
+ inUse -= sizeof(sndBuffer);
+ totalInUse += sizeof(sndBuffer);
+
+ v = freelist;
+ freelist = *(sndBuffer **)freelist;
+ v->next = NULL;
+
+ return v;
+}
+
+void SND_setup(void)
+{
+ cvar_t* cv = Cvar_Get("com_soundMegs",
+ DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE);
+ int scs = cv->integer * 1536;
+
+ buffer = (sndBuffer*)malloc(scs * sizeof(sndBuffer));
+
+ // allocate the stack based hunk allocator
+ sfxScratchBuffer = (short*)malloc(SND_CHUNK_SIZE * sizeof(short) * 4);
+ sfxScratchPointer = NULL;
+
+ inUse = scs * sizeof(sndBuffer);
+ sndBuffer* p = buffer;
+ sndBuffer* q = p + scs;
+ while (--q > p)
+ {
+ *(sndBuffer **)q = q - 1;
+ }
+
+ *(sndBuffer **)q = NULL;
+ freelist = p + scs - 1;
+
+ Com_Printf("Sound memory manager started\n");
+}
+
+void SND_shutdown(void)
+{
+ free(sfxScratchBuffer);
+ free(buffer);
+}
+
+/*
+================
+ResampleSfx
+
+resample / decimate to the current source rate
+================
+*/
+static int ResampleSfx(sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, bool compressed)
+{
+ float stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+ int outcount = samples / stepscale;
+ int fracstep = stepscale * 256 * channels;
+ sndBuffer* chunk = sfx->soundData;
+
+ int samplefrac = 0;
+ int srcsample = 0;
+
+ for (int i = 0; i < outcount; i++)
+ {
+ srcsample += samplefrac >> 8;
+ samplefrac &= 255;
+ samplefrac += fracstep;
+
+ for (int j = 0; j < channels; j++)
+ {
+ int sample;
+
+ if (inwidth == 2)
+ {
+ sample = ((short *)data)[srcsample + j];
+ }
+ else
+ {
+ sample = (int)((unsigned char)(data[srcsample + j]) - 128) << 8;
+ }
+
+ int part = (i * channels + j) & (SND_CHUNK_SIZE - 1);
+ if (part == 0)
+ {
+ sndBuffer *newchunk = SND_malloc();
+
+ if (chunk == NULL)
+ {
+ sfx->soundData = newchunk;
+ }
+ else
+ {
+ chunk->next = newchunk;
+ }
+ chunk = newchunk;
+ }
+
+ chunk->sndChunk[part] = sample;
+ }
+ }
+
+ return outcount;
+}
+
+/*
+================
+ResampleSfxRaw
+
+resample / decimate to the current source rate
+================
+*/
+static int ResampleSfxRaw(short *sfx, int channels, int inrate, int inwidth, int samples, byte *data)
+{
+ float stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+ int outcount = samples / stepscale;
+ int fracstep = stepscale * 256 * channels;
+
+ int samplefrac = 0;
+ int srcsample = 0;
+
+ for (int i = 0; i < outcount; i++)
+ {
+ srcsample += samplefrac >> 8;
+ srcsample &= 255;
+ samplefrac += fracstep;
+
+ for (int j = 0; j < channels; j++)
+ {
+ int sample;
+ if (inwidth == 2)
+ {
+ sample = LittleShort(((short *)data)[srcsample + j]);
+ }
+ else
+ {
+ sample = (int)((unsigned char)(data[srcsample + j]) - 128) << 8;
+ }
+ sfx[i * channels + j] = sample;
+ }
+ }
+ return outcount;
+}
+
+//=============================================================================
+
+/*
+==============
+S_LoadSound
+
+The filename may be different than sfx->name in the case
+of a forced fallback of a player specific sound
+==============
+*/
+bool S_LoadSound(sfx_t *sfx)
+{
+ snd_info_t info;
+ byte *data = (byte*)S_CodecLoad(sfx->soundName, &info);
+ if (!data)
+ {
+ return false;
+ }
+
+ int size_per_sec = info.rate * info.channels * info.width;
+ if (size_per_sec > 0)
+ {
+ sfx->duration = (int)(1000.0f * ((double)info.size / size_per_sec));
+ }
+
+ if (info.width == 1)
+ {
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n",
+ sfx->soundName);
+ }
+
+ if (info.rate != 22050)
+ {
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n",
+ sfx->soundName);
+ }
+
+ short* samples = (short*)Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
+
+ sfx->lastTimeUsed = Com_Milliseconds() + 1;
+
+ // each of these compression schemes works just fine
+ // but the 16bit quality is much nicer and with a local
+ // install assured we can rely upon the sound memory
+ // manager to do the right thing for us and page
+ // sound in as needed
+
+ if (info.channels == 1 && sfx->soundCompressed == true)
+ {
+ sfx->soundCompressionMethod = 1;
+ sfx->soundData = NULL;
+ sfx->soundLength = ResampleSfxRaw(
+ samples,
+ info.channels,
+ info.rate,
+ info.width,
+ info.samples,
+ data + info.dataofs);
+ S_AdpcmEncodeSound(sfx, samples);
+ }
+ else
+ {
+ sfx->soundCompressionMethod = 0;
+ sfx->soundData = NULL;
+ sfx->soundLength = ResampleSfx(
+ sfx,
+ info.channels,
+ info.rate,
+ info.width,
+ info.samples,
+ data + info.dataofs,
+ false);
+ }
+
+ sfx->soundChannels = info.channels;
+
+ Hunk_FreeTempMemory(samples);
+ Hunk_FreeTempMemory(data);
+
+ return true;
+}
+
+void S_DisplayFreeMemory(void)
+{
+ Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
+}