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