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