Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 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 | */ |
||
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 |
||
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 |
||
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 | */ |
||
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 | |||
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 | |||
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 | |||
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(data_p, name, 4)) |
||
216 | return; |
||
217 | } |
||
218 | } |
||
219 | |||
220 | void FindChunk(char *name) |
||
221 | { |
||
222 | last_chunk = iff_data; |
||
223 | FindNextChunk (name); |
||
224 | } |
||
225 | |||
226 | |||
227 | void DumpChunks(void) |
||
228 | { |
||
229 | char str[5]; |
||
230 | |||
231 | str[4] = 0; |
||
232 | data_p=iff_data; |
||
233 | do |
||
234 | { |
||
235 | memcpy (str, data_p, 4); |
||
236 | data_p += 4; |
||
237 | iff_chunk_len = GetLittleLong(); |
||
238 | Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); |
||
239 | data_p += (iff_chunk_len + 1) & ~1; |
||
240 | } while (data_p < iff_end); |
||
241 | } |
||
242 | |||
243 | /* |
||
244 | ============ |
||
245 | GetWavinfo |
||
246 | ============ |
||
247 | */ |
||
248 | wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) |
||
249 | { |
||
250 | wavinfo_t info; |
||
251 | int i; |
||
252 | int format; |
||
253 | int samples; |
||
254 | |||
255 | memset (&info, 0, sizeof(info)); |
||
256 | |||
257 | if (!wav) |
||
258 | return info; |
||
259 | |||
260 | iff_data = wav; |
||
261 | iff_end = wav + wavlength; |
||
262 | |||
263 | // find "RIFF" chunk |
||
264 | FindChunk("RIFF"); |
||
265 | if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4))) |
||
266 | { |
||
267 | Con_Printf("Missing RIFF/WAVE chunks\n"); |
||
268 | return info; |
||
269 | } |
||
270 | |||
271 | // get "fmt " chunk |
||
272 | iff_data = data_p + 12; |
||
273 | // DumpChunks (); |
||
274 | |||
275 | FindChunk("fmt "); |
||
276 | if (!data_p) |
||
277 | { |
||
278 | Con_Printf("Missing fmt chunk\n"); |
||
279 | return info; |
||
280 | } |
||
281 | data_p += 8; |
||
282 | format = GetLittleShort(); |
||
283 | if (format != 1) |
||
284 | { |
||
285 | Con_Printf("Microsoft PCM format only\n"); |
||
286 | return info; |
||
287 | } |
||
288 | |||
289 | info.channels = GetLittleShort(); |
||
290 | info.rate = GetLittleLong(); |
||
291 | data_p += 4+2; |
||
292 | info.width = GetLittleShort() / 8; |
||
293 | |||
294 | // get cue chunk |
||
295 | FindChunk("cue "); |
||
296 | if (data_p) |
||
297 | { |
||
298 | data_p += 32; |
||
299 | info.loopstart = GetLittleLong(); |
||
300 | // Con_Printf("loopstart=%d\n", sfx->loopstart); |
||
301 | |||
302 | // if the next chunk is a LIST chunk, look for a cue length marker |
||
303 | FindNextChunk ("LIST"); |
||
304 | if (data_p) |
||
305 | { |
||
306 | if (!strncmp (data_p + 28, "mark", 4)) |
||
307 | { // this is not a proper parse, but it works with cooledit... |
||
308 | data_p += 24; |
||
309 | i = GetLittleLong (); // samples in loop |
||
310 | info.samples = info.loopstart + i; |
||
311 | // Con_Printf("looped length: %i\n", i); |
||
312 | } |
||
313 | } |
||
314 | } |
||
315 | else |
||
316 | info.loopstart = -1; |
||
317 | |||
318 | // find data chunk |
||
319 | FindChunk("data"); |
||
320 | if (!data_p) |
||
321 | { |
||
322 | Con_Printf("Missing data chunk\n"); |
||
323 | return info; |
||
324 | } |
||
325 | |||
326 | data_p += 4; |
||
327 | samples = GetLittleLong () / info.width; |
||
328 | |||
329 | if (info.samples) |
||
330 | { |
||
331 | if (samples < info.samples) |
||
332 | Sys_Error ("Sound %s has a bad loop length", name); |
||
333 | } |
||
334 | else |
||
335 | info.samples = samples; |
||
336 | |||
337 | info.dataofs = data_p - wav; |
||
338 | |||
339 | return info; |
||
340 | }>>>24); |
||
341 |