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