|
|
1.1 root 1: // snd_mem.c: sound caching
2:
3: #include "client.h"
4: #include "snd_loc.h"
5:
6: int cache_full_cycle;
7:
8: byte *S_Alloc (int size);
9:
10: /*
11: ================
12: ResampleSfx
13: ================
14: */
15: void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
16: {
17: int outcount;
18: int srcsample;
19: float stepscale;
20: int i;
21: int sample, samplefrac, fracstep;
22: sfxcache_t *sc;
23:
24: sc = sfx->cache;
25: if (!sc)
26: return;
27:
28: stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
29:
30: outcount = sc->length / stepscale;
31: sc->length = outcount;
32: if (sc->loopstart != -1)
33: sc->loopstart = sc->loopstart / stepscale;
34:
35: sc->speed = dma.speed;
36: if (s_loadas8bit->value)
37: sc->width = 1;
38: else
39: sc->width = inwidth;
40: sc->stereo = 0;
41:
42: // resample / decimate to the current source rate
43:
44: if (stepscale == 1 && inwidth == 1 && sc->width == 1)
45: {
46: // fast special case
47: for (i=0 ; i<outcount ; i++)
48: ((signed char *)sc->data)[i]
49: = (int)( (unsigned char)(data[i]) - 128);
50: }
51: else
52: {
53: // general case
54: samplefrac = 0;
55: fracstep = stepscale*256;
56: for (i=0 ; i<outcount ; i++)
57: {
58: srcsample = samplefrac >> 8;
59: samplefrac += fracstep;
60: if (inwidth == 2)
61: sample = LittleShort ( ((short *)data)[srcsample] );
62: else
63: sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
64: if (sc->width == 2)
65: ((short *)sc->data)[i] = sample;
66: else
67: ((signed char *)sc->data)[i] = sample >> 8;
68: }
69: }
70: }
71:
72: //=============================================================================
73:
74: /*
75: ==============
76: S_LoadSound
77: ==============
78: */
79: sfxcache_t *S_LoadSound (sfx_t *s)
80: {
81: char namebuffer[MAX_QPATH];
82: byte *data;
83: wavinfo_t info;
84: int len;
85: float stepscale;
86: sfxcache_t *sc;
87: int size;
1.1.1.2 ! root 88: char *name;
1.1 root 89:
90: if (s->name[0] == '*')
91: return NULL;
92:
93: // see if still in memory
94: sc = s->cache;
95: if (sc)
96: return sc;
97:
98: //Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
99: // load it in
1.1.1.2 ! root 100: if (s->truename)
! 101: name = s->truename;
1.1 root 102: else
1.1.1.2 ! root 103: name = s->name;
! 104:
! 105: if (name[0] == '#')
! 106: strcpy(namebuffer, &name[1]);
! 107: else
! 108: Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
1.1 root 109:
110: // Com_Printf ("loading %s\n",namebuffer);
111:
112: size = FS_LoadFile (namebuffer, (void **)&data);
113:
114: if (!data)
115: {
1.1.1.2 ! root 116: Com_DPrintf ("Couldn't load %s\n", namebuffer);
1.1 root 117: return NULL;
118: }
119:
120: info = GetWavinfo (s->name, data, size);
121: if (info.channels != 1)
122: {
123: Com_Printf ("%s is a stereo sample\n",s->name);
124: FS_FreeFile (data);
125: return NULL;
126: }
127:
128: stepscale = (float)info.rate / dma.speed;
129: len = info.samples / stepscale;
130:
131: len = len * info.width * info.channels;
132:
133: sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
134: if (!sc)
135: {
136: FS_FreeFile (data);
137: return NULL;
138: }
139:
140: sc->length = info.samples;
141: sc->loopstart = info.loopstart;
142: sc->speed = info.rate;
143: sc->width = info.width;
144: sc->stereo = info.channels;
145:
146: ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
147:
148: FS_FreeFile (data);
149:
150: return sc;
151: }
152:
153:
154:
155: /*
156: ===============================================================================
157:
158: WAV loading
159:
160: ===============================================================================
161: */
162:
163:
164: byte *data_p;
165: byte *iff_end;
166: byte *last_chunk;
167: byte *iff_data;
168: int iff_chunk_len;
169:
170:
171: short GetLittleShort(void)
172: {
173: short val = 0;
174: val = *data_p;
175: val = val + (*(data_p+1)<<8);
176: data_p += 2;
177: return val;
178: }
179:
180: int GetLittleLong(void)
181: {
182: int val = 0;
183: val = *data_p;
184: val = val + (*(data_p+1)<<8);
185: val = val + (*(data_p+2)<<16);
186: val = val + (*(data_p+3)<<24);
187: data_p += 4;
188: return val;
189: }
190:
191: void FindNextChunk(char *name)
192: {
193: while (1)
194: {
195: data_p=last_chunk;
196:
197: if (data_p >= iff_end)
198: { // didn't find the chunk
199: data_p = NULL;
200: return;
201: }
202:
203: data_p += 4;
204: iff_chunk_len = GetLittleLong();
205: if (iff_chunk_len < 0)
206: {
207: data_p = NULL;
208: return;
209: }
210: // if (iff_chunk_len > 1024*1024)
211: // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
212: data_p -= 8;
213: last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
214: if (!strncmp(data_p, name, 4))
215: return;
216: }
217: }
218:
219: void FindChunk(char *name)
220: {
221: last_chunk = iff_data;
222: FindNextChunk (name);
223: }
224:
225:
226: void DumpChunks(void)
227: {
228: char str[5];
229:
230: str[4] = 0;
231: data_p=iff_data;
232: do
233: {
234: memcpy (str, data_p, 4);
235: data_p += 4;
236: iff_chunk_len = GetLittleLong();
237: Com_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
238: data_p += (iff_chunk_len + 1) & ~1;
239: } while (data_p < iff_end);
240: }
241:
242: /*
243: ============
244: GetWavinfo
245: ============
246: */
247: wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
248: {
249: wavinfo_t info;
250: int i;
251: int format;
252: int samples;
253:
254: memset (&info, 0, sizeof(info));
255:
256: if (!wav)
257: return info;
258:
259: iff_data = wav;
260: iff_end = wav + wavlength;
261:
262: // find "RIFF" chunk
263: FindChunk("RIFF");
264: if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
265: {
266: Com_Printf("Missing RIFF/WAVE chunks\n");
267: return info;
268: }
269:
270: // get "fmt " chunk
271: iff_data = data_p + 12;
272: // DumpChunks ();
273:
274: FindChunk("fmt ");
275: if (!data_p)
276: {
277: Com_Printf("Missing fmt chunk\n");
278: return info;
279: }
280: data_p += 8;
281: format = GetLittleShort();
282: if (format != 1)
283: {
284: Com_Printf("Microsoft PCM format only\n");
285: return info;
286: }
287:
288: info.channels = GetLittleShort();
289: info.rate = GetLittleLong();
290: data_p += 4+2;
291: info.width = GetLittleShort() / 8;
292:
293: // get cue chunk
294: FindChunk("cue ");
295: if (data_p)
296: {
297: data_p += 32;
298: info.loopstart = GetLittleLong();
299: // Com_Printf("loopstart=%d\n", sfx->loopstart);
300:
301: // if the next chunk is a LIST chunk, look for a cue length marker
302: FindNextChunk ("LIST");
303: if (data_p)
304: {
305: if (!strncmp (data_p + 28, "mark", 4))
306: { // this is not a proper parse, but it works with cooledit...
307: data_p += 24;
308: i = GetLittleLong (); // samples in loop
309: info.samples = info.loopstart + i;
310: // Com_Printf("looped length: %i\n", i);
311: }
312: }
313: }
314: else
315: info.loopstart = -1;
316:
317: // find data chunk
318: FindChunk("data");
319: if (!data_p)
320: {
321: Com_Printf("Missing data chunk\n");
322: return info;
323: }
324:
325: data_p += 4;
326: samples = GetLittleLong () / info.width;
327:
328: if (info.samples)
329: {
330: if (samples < info.samples)
331: Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
332: }
333: else
334: info.samples = samples;
335:
336: info.dataofs = data_p - wav;
337:
338: return info;
339: }
340:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.