• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 // snd_mem.c: sound caching
21 
22 #include "quakedef.h"
23 
24 int			cache_full_cycle;
25 
26 byte *S_Alloc (int size);
27 
28 /*
29 ================
30 ResampleSfx
31 ================
32 */
ResampleSfx(sfx_t * sfx,int inrate,int inwidth,byte * data)33 void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
34 {
35 	int		outcount;
36 	int		srcsample;
37 	float	stepscale;
38 	int		i;
39 	int		sample, samplefrac, fracstep;
40 	sfxcache_t	*sc;
41 
42 	sc = Cache_Check (&sfx->cache);
43 	if (!sc)
44 		return;
45 
46 	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2
47 
48 	outcount = sc->length / stepscale;
49 	sc->length = outcount;
50 	if (sc->loopstart != -1)
51 		sc->loopstart = sc->loopstart / stepscale;
52 
53 	sc->speed = shm->speed;
54 	if (loadas8bit.value)
55 		sc->width = 1;
56 	else
57 		sc->width = inwidth;
58 	sc->stereo = 0;
59 
60 // resample / decimate to the current source rate
61 
62 	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
63 	{
64 // fast special case
65 		for (i=0 ; i<outcount ; i++)
66 			((signed char *)sc->data)[i]
67 			= (int)( (unsigned char)(data[i]) - 128);
68 	}
69 	else
70 	{
71 // general case
72 		samplefrac = 0;
73 		fracstep = stepscale*256;
74 		for (i=0 ; i<outcount ; i++)
75 		{
76 			srcsample = samplefrac >> 8;
77 			samplefrac += fracstep;
78 			if (inwidth == 2)
79 				sample = LittleShort ( ((short *)data)[srcsample] );
80 			else
81 				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
82 			if (sc->width == 2)
83 				((short *)sc->data)[i] = sample;
84 			else
85 				((signed char *)sc->data)[i] = sample >> 8;
86 		}
87 	}
88 }
89 
90 //=============================================================================
91 
92 /*
93 ==============
94 S_LoadSound
95 ==============
96 */
S_LoadSound(sfx_t * s)97 sfxcache_t *S_LoadSound (sfx_t *s)
98 {
99     char	namebuffer[256];
100 	byte	*data;
101 	wavinfo_t	info;
102 	int		len;
103 	float	stepscale;
104 	sfxcache_t	*sc;
105 	byte	stackbuf[1*1024];		// avoid dirtying the cache heap
106 
107 // see if still in memory
108 	sc = Cache_Check (&s->cache);
109 	if (sc)
110 		return sc;
111 
112 //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
113 // load it in
114     Q_strcpy(namebuffer, "sound/");
115     Q_strcat(namebuffer, s->name);
116 
117 //	Con_Printf ("loading %s\n",namebuffer);
118 
119 	data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
120 
121 	if (!data)
122 	{
123 		Con_Printf ("Couldn't load %s\n", namebuffer);
124 		return NULL;
125 	}
126 
127 	info = GetWavinfo (s->name, data, com_filesize);
128 	if (info.channels != 1)
129 	{
130 		Con_Printf ("%s is a stereo sample\n",s->name);
131 		return NULL;
132 	}
133 
134 	stepscale = (float)info.rate / shm->speed;
135 	len = info.samples / stepscale;
136 
137 	len = len * info.width * info.channels;
138 
139 	sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
140 	if (!sc)
141 		return NULL;
142 
143 	sc->length = info.samples;
144 	sc->loopstart = info.loopstart;
145 	sc->speed = info.rate;
146 	sc->width = info.width;
147 	sc->stereo = info.channels;
148 
149 	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
150 
151 	return sc;
152 }
153 
154 
155 
156 /*
157 ===============================================================================
158 
159 WAV loading
160 
161 ===============================================================================
162 */
163 
164 
165 byte	*data_p;
166 byte 	*iff_end;
167 byte 	*last_chunk;
168 byte 	*iff_data;
169 int 	iff_chunk_len;
170 
171 
GetLittleShort(void)172 short GetLittleShort(void)
173 {
174 	short val = 0;
175 	val = *data_p;
176 	val = val + (*(data_p+1)<<8);
177 	data_p += 2;
178 	return val;
179 }
180 
GetLittleLong(void)181 int GetLittleLong(void)
182 {
183 	int val = 0;
184 	val = *data_p;
185 	val = val + (*(data_p+1)<<8);
186 	val = val + (*(data_p+2)<<16);
187 	val = val + (*(data_p+3)<<24);
188 	data_p += 4;
189 	return val;
190 }
191 
FindNextChunk(char * name)192 void FindNextChunk(char *name)
193 {
194 	while (1)
195 	{
196 		data_p=last_chunk;
197 
198 		if (data_p >= iff_end)
199 		{	// didn't find the chunk
200 			data_p = NULL;
201 			return;
202 		}
203 
204 		data_p += 4;
205 		iff_chunk_len = GetLittleLong();
206 		if (iff_chunk_len < 0)
207 		{
208 			data_p = NULL;
209 			return;
210 		}
211 //		if (iff_chunk_len > 1024*1024)
212 //			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
213 		data_p -= 8;
214 		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
215 		if (!Q_strncmp((char*) data_p, name, 4))
216 			return;
217 	}
218 }
219 
FindChunk(char * name)220 void FindChunk(char *name)
221 {
222 	last_chunk = iff_data;
223 	FindNextChunk (name);
224 }
225 
226 
227 #if 0
228 void DumpChunks(void)
229 {
230 	char	str[5];
231 
232 	str[4] = 0;
233 	data_p=iff_data;
234 	do
235 	{
236 		memcpy (str, data_p, 4);
237 		data_p += 4;
238 		iff_chunk_len = GetLittleLong();
239 		Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
240 		data_p += (iff_chunk_len + 1) & ~1;
241 	} while (data_p < iff_end);
242 }
243 #endif
244 
245 /*
246 ============
247 GetWavinfo
248 ============
249 */
GetWavinfo(char * name,byte * wav,int wavlength)250 wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
251 {
252 	wavinfo_t	info;
253 	int     i;
254 	int     format;
255 	int		samples;
256 
257 	memset (&info, 0, sizeof(info));
258 
259 	if (!wav)
260 		return info;
261 
262 	iff_data = wav;
263 	iff_end = wav + wavlength;
264 
265 // find "RIFF" chunk
266 	FindChunk("RIFF");
267 	if (!(data_p && !Q_strncmp((char*) (data_p+8), "WAVE", 4)))
268 	{
269 		Con_Printf("Missing RIFF/WAVE chunks\n");
270 		return info;
271 	}
272 
273 // get "fmt " chunk
274 	iff_data = data_p + 12;
275 // DumpChunks ();
276 
277 	FindChunk("fmt ");
278 	if (!data_p)
279 	{
280 		Con_Printf("Missing fmt chunk\n");
281 		return info;
282 	}
283 	data_p += 8;
284 	format = GetLittleShort();
285 	if (format != 1)
286 	{
287 		Con_Printf("Microsoft PCM format only\n");
288 		return info;
289 	}
290 
291 	info.channels = GetLittleShort();
292 	info.rate = GetLittleLong();
293 	data_p += 4+2;
294 	info.width = GetLittleShort() / 8;
295 
296 // get cue chunk
297 	FindChunk("cue ");
298 	if (data_p)
299 	{
300 		data_p += 32;
301 		info.loopstart = GetLittleLong();
302 //		Con_Printf("loopstart=%d\n", sfx->loopstart);
303 
304 	// if the next chunk is a LIST chunk, look for a cue length marker
305 		FindNextChunk ("LIST");
306 		if (data_p)
307 		{
308 			if (!strncmp ((char*) (data_p + 28), "mark", 4))
309 			{	// this is not a proper parse, but it works with cooledit...
310 				data_p += 24;
311 				i = GetLittleLong ();	// samples in loop
312 				info.samples = info.loopstart + i;
313 //				Con_Printf("looped length: %i\n", i);
314 			}
315 		}
316 	}
317 	else
318 		info.loopstart = -1;
319 
320 // find data chunk
321 	FindChunk("data");
322 	if (!data_p)
323 	{
324 		Con_Printf("Missing data chunk\n");
325 		return info;
326 	}
327 
328 	data_p += 4;
329 	samples = GetLittleLong () / info.width;
330 
331 	if (info.samples)
332 	{
333 		if (samples < info.samples)
334 			Sys_Error ("Sound %s has a bad loop length", name);
335 	}
336 	else
337 		info.samples = samples;
338 
339 	info.dataofs = data_p - wav;
340 
341 	return info;
342 }
343 
344