1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5
6 This file is part of Tremulous.
7
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ===========================================================================
22 */
23
24 /*****************************************************************************
25 * name: snd_mem.c
26 *
27 * desc: sound caching
28 *
29 * $Archive: /MissionPack/code/client/snd_mem.c $
30 *
31 *****************************************************************************/
32
33 #include "snd_local.h"
34 #include "snd_codec.h"
35
36 #define DEF_COMSOUNDMEGS "8"
37
38 /*
39 ===============================================================================
40
41 memory management
42
43 ===============================================================================
44 */
45
46 static sndBuffer *buffer = NULL;
47 static sndBuffer *freelist = NULL;
48 static int inUse = 0;
49 static int totalInUse = 0;
50
51 short *sfxScratchBuffer = NULL;
52 sfx_t *sfxScratchPointer = NULL;
53 int sfxScratchIndex = 0;
54
SND_free(sndBuffer * v)55 void SND_free(sndBuffer *v) {
56 *(sndBuffer **)v = freelist;
57 freelist = (sndBuffer*)v;
58 inUse += sizeof(sndBuffer);
59 }
60
SND_malloc(void)61 sndBuffer* SND_malloc(void) {
62 sndBuffer *v;
63 redo:
64 if (freelist == NULL) {
65 S_FreeOldestSound();
66 goto redo;
67 }
68
69 inUse -= sizeof(sndBuffer);
70 totalInUse += sizeof(sndBuffer);
71
72 v = freelist;
73 freelist = *(sndBuffer **)freelist;
74 v->next = NULL;
75 return v;
76 }
77
SND_setup(void)78 void SND_setup(void) {
79 sndBuffer *p, *q;
80 cvar_t *cv;
81 int scs;
82
83 cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
84
85 scs = (cv->integer*1536);
86
87 buffer = malloc(scs*sizeof(sndBuffer) );
88 // allocate the stack based hunk allocator
89 sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
90 sfxScratchPointer = NULL;
91
92 inUse = scs*sizeof(sndBuffer);
93 p = buffer;;
94 q = p + scs;
95 while (--q > p)
96 *(sndBuffer **)q = q-1;
97
98 *(sndBuffer **)q = NULL;
99 freelist = p + scs - 1;
100
101 Com_Printf("Sound memory manager started\n");
102 }
103
104 /*
105 ================
106 ResampleSfx
107
108 resample / decimate to the current source rate
109 ================
110 */
ResampleSfx(sfx_t * sfx,int inrate,int inwidth,byte * data,qboolean compressed)111 static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
112 int outcount;
113 int srcsample;
114 float stepscale;
115 int i;
116 int sample, samplefrac, fracstep;
117 int part;
118 sndBuffer *chunk;
119
120 stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
121
122 outcount = sfx->soundLength / stepscale;
123 sfx->soundLength = outcount;
124
125 samplefrac = 0;
126 fracstep = stepscale * 256;
127 chunk = sfx->soundData;
128
129 for (i=0 ; i<outcount ; i++)
130 {
131 srcsample = samplefrac >> 8;
132 samplefrac += fracstep;
133 if( inwidth == 2 ) {
134 sample = ( ((short *)data)[srcsample] );
135 } else {
136 sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
137 }
138 part = (i&(SND_CHUNK_SIZE-1));
139 if (part == 0) {
140 sndBuffer *newchunk;
141 newchunk = SND_malloc();
142 if (chunk == NULL) {
143 sfx->soundData = newchunk;
144 } else {
145 chunk->next = newchunk;
146 }
147 chunk = newchunk;
148 }
149
150 chunk->sndChunk[part] = sample;
151 }
152 }
153
154 /*
155 ================
156 ResampleSfx
157
158 resample / decimate to the current source rate
159 ================
160 */
ResampleSfxRaw(short * sfx,int inrate,int inwidth,int samples,byte * data)161 static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
162 int outcount;
163 int srcsample;
164 float stepscale;
165 int i;
166 int sample, samplefrac, fracstep;
167
168 stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
169
170 outcount = samples / stepscale;
171
172 samplefrac = 0;
173 fracstep = stepscale * 256;
174
175 for (i=0 ; i<outcount ; i++)
176 {
177 srcsample = samplefrac >> 8;
178 samplefrac += fracstep;
179 if( inwidth == 2 ) {
180 sample = LittleShort ( ((short *)data)[srcsample] );
181 } else {
182 sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
183 }
184 sfx[i] = sample;
185 }
186 return outcount;
187 }
188
189 //=============================================================================
190
191 /*
192 ==============
193 S_LoadSound
194
195 The filename may be different than sfx->name in the case
196 of a forced fallback of a player specific sound
197 ==============
198 */
S_LoadSound(sfx_t * sfx)199 qboolean S_LoadSound( sfx_t *sfx )
200 {
201 byte *data;
202 short *samples;
203 snd_info_t info;
204 // int size;
205
206 // player specific sounds are never directly loaded
207 if ( sfx->soundName[0] == '*') {
208 return qfalse;
209 }
210
211 // load it in
212 data = S_CodecLoad(sfx->soundName, &info);
213 if(!data)
214 return qfalse;
215
216 if ( info.width == 1 ) {
217 Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
218 }
219
220 if ( info.rate != 22050 ) {
221 Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
222 }
223
224 samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
225
226 sfx->lastTimeUsed = Com_Milliseconds()+1;
227
228 // each of these compression schemes works just fine
229 // but the 16bit quality is much nicer and with a local
230 // install assured we can rely upon the sound memory
231 // manager to do the right thing for us and page
232 // sound in as needed
233
234 if( sfx->soundCompressed == qtrue) {
235 sfx->soundCompressionMethod = 1;
236 sfx->soundData = NULL;
237 sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, data + info.dataofs );
238 S_AdpcmEncodeSound(sfx, samples);
239 #if 0
240 } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
241 sfx->soundCompressionMethod = 3;
242 sfx->soundData = NULL;
243 sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
244 encodeMuLaw( sfx, samples);
245 } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
246 sfx->soundCompressionMethod = 2;
247 sfx->soundData = NULL;
248 sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
249 encodeWavelet( sfx, samples);
250 #endif
251 } else {
252 sfx->soundCompressionMethod = 0;
253 sfx->soundLength = info.samples;
254 sfx->soundData = NULL;
255 ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
256 }
257
258 Hunk_FreeTempMemory(samples);
259 Z_Free(data);
260
261 return qtrue;
262 }
263
S_DisplayFreeMemory(void)264 void S_DisplayFreeMemory(void) {
265 Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
266 }
267