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 "32"
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
SND_shutdown(void)103 void SND_shutdown(void)
104 {
105 free(sfxScratchBuffer);
106 free(buffer);
107 }
108
109 /*
110 ================
111 ResampleSfx
112
113 resample / decimate to the current source rate
114 ================
115 */
ResampleSfx(sfx_t * sfx,int channels,int inrate,int inwidth,int samples,byte * data,qboolean compressed)116 static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
117 int outcount;
118 int srcsample;
119 float stepscale;
120 int i, j;
121 int sample, samplefrac, fracstep;
122 int part;
123 sndBuffer *chunk;
124
125 stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
126
127 outcount = samples / stepscale;
128
129 srcsample = 0;
130 samplefrac = 0;
131 fracstep = stepscale * 256 * channels;
132 chunk = sfx->soundData;
133
134 for (i=0 ; i<outcount ; i++)
135 {
136 srcsample += samplefrac >> 8;
137 samplefrac &= 255;
138 samplefrac += fracstep;
139 for (j=0 ; j<channels ; j++)
140 {
141 if( inwidth == 2 ) {
142 sample = ( ((short *)data)[srcsample+j] );
143 } else {
144 sample = (unsigned int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
145 }
146 part = (i*channels+j)&(SND_CHUNK_SIZE-1);
147 if (part == 0) {
148 sndBuffer *newchunk;
149 newchunk = SND_malloc();
150 if (chunk == NULL) {
151 sfx->soundData = newchunk;
152 } else {
153 chunk->next = newchunk;
154 }
155 chunk = newchunk;
156 }
157
158 chunk->sndChunk[part] = sample;
159 }
160 }
161
162 return outcount;
163 }
164
165 /*
166 ================
167 ResampleSfx
168
169 resample / decimate to the current source rate
170 ================
171 */
ResampleSfxRaw(short * sfx,int channels,int inrate,int inwidth,int samples,byte * data)172 static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
173 int outcount;
174 int srcsample;
175 float stepscale;
176 int i, j;
177 int sample, samplefrac, fracstep;
178
179 stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
180
181 outcount = samples / stepscale;
182
183 srcsample = 0;
184 samplefrac = 0;
185 fracstep = stepscale * 256 * channels;
186
187 for (i=0 ; i<outcount ; i++)
188 {
189 srcsample += samplefrac >> 8;
190 samplefrac &= 255;
191 samplefrac += fracstep;
192 for (j=0 ; j<channels ; j++)
193 {
194 if( inwidth == 2 ) {
195 sample = LittleShort ( ((short *)data)[srcsample+j] );
196 } else {
197 sample = (int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
198 }
199 sfx[i*channels+j] = sample;
200 }
201 }
202 return outcount;
203 }
204
205 //=============================================================================
206
207 /*
208 ==============
209 S_LoadSound
210
211 The filename may be different than sfx->name in the case
212 of a forced fallback of a player specific sound
213 ==============
214 */
S_LoadSound(sfx_t * sfx)215 qboolean S_LoadSound( sfx_t *sfx )
216 {
217 byte *data;
218 short *samples;
219 snd_info_t info;
220 // int size;
221
222 // player specific sounds are never directly loaded
223 if ( sfx->soundName[0] == '*') {
224 return qfalse;
225 }
226
227 // load it in
228 data = S_CodecLoad(sfx->soundName, &info);
229 if(!data)
230 return qfalse;
231
232 if ( info.width == 1 ) {
233 Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName);
234 }
235
236 if ( info.rate != 22050 ) {
237 Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName);
238 }
239
240 samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
241
242 sfx->lastTimeUsed = Com_Milliseconds()+1;
243
244 // each of these compression schemes works just fine
245 // but the 16bit quality is much nicer and with a local
246 // install assured we can rely upon the sound memory
247 // manager to do the right thing for us and page
248 // sound in as needed
249
250 if( info.channels == 1 && sfx->soundCompressed == qtrue) {
251 sfx->soundCompressionMethod = 1;
252 sfx->soundData = NULL;
253 sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
254 S_AdpcmEncodeSound(sfx, samples);
255 #if 0
256 } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
257 sfx->soundCompressionMethod = 3;
258 sfx->soundData = NULL;
259 sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
260 encodeMuLaw( sfx, samples);
261 } else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
262 sfx->soundCompressionMethod = 2;
263 sfx->soundData = NULL;
264 sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
265 encodeWavelet( sfx, samples);
266 #endif
267 } else {
268 sfx->soundCompressionMethod = 0;
269 sfx->soundData = NULL;
270 sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
271 }
272
273 sfx->soundChannels = info.channels;
274
275 Hunk_FreeTempMemory(samples);
276 Hunk_FreeTempMemory(data);
277
278 return qtrue;
279 }
280
S_DisplayFreeMemory(void)281 void S_DisplayFreeMemory(void) {
282 Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
283 }
284