|
|
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;
88:
89: if (s->name[0] == '*')
90: return NULL;
91:
92: // see if still in memory
93: sc = s->cache;
94: if (sc)
95: return sc;
96:
97: //Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
98: // load it in
99: if (s->name[0] == '#')
100: strcpy(namebuffer, &s->name[1]);
101: else
102: Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", s->name);
103:
104: // Com_Printf ("loading %s\n",namebuffer);
105:
106: size = FS_LoadFile (namebuffer, (void **)&data);
107:
108: if (!data)
109: {
110: Com_Printf ("Couldn't load %s\n", namebuffer);
111: return NULL;
112: }
113:
114: info = GetWavinfo (s->name, data, size);
115: if (info.channels != 1)
116: {
117: Com_Printf ("%s is a stereo sample\n",s->name);
118: FS_FreeFile (data);
119: return NULL;
120: }
121:
122: stepscale = (float)info.rate / dma.speed;
123: len = info.samples / stepscale;
124:
125: len = len * info.width * info.channels;
126:
127: sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
128: if (!sc)
129: {
130: FS_FreeFile (data);
131: return NULL;
132: }
133:
134: sc->length = info.samples;
135: sc->loopstart = info.loopstart;
136: sc->speed = info.rate;
137: sc->width = info.width;
138: sc->stereo = info.channels;
139:
140: ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
141:
142: FS_FreeFile (data);
143:
144: return sc;
145: }
146:
147:
148:
149: /*
150: ===============================================================================
151:
152: WAV loading
153:
154: ===============================================================================
155: */
156:
157:
158: byte *data_p;
159: byte *iff_end;
160: byte *last_chunk;
161: byte *iff_data;
162: int iff_chunk_len;
163:
164:
165: short GetLittleShort(void)
166: {
167: short val = 0;
168: val = *data_p;
169: val = val + (*(data_p+1)<<8);
170: data_p += 2;
171: return val;
172: }
173:
174: int GetLittleLong(void)
175: {
176: int val = 0;
177: val = *data_p;
178: val = val + (*(data_p+1)<<8);
179: val = val + (*(data_p+2)<<16);
180: val = val + (*(data_p+3)<<24);
181: data_p += 4;
182: return val;
183: }
184:
185: void FindNextChunk(char *name)
186: {
187: while (1)
188: {
189: data_p=last_chunk;
190:
191: if (data_p >= iff_end)
192: { // didn't find the chunk
193: data_p = NULL;
194: return;
195: }
196:
197: data_p += 4;
198: iff_chunk_len = GetLittleLong();
199: if (iff_chunk_len < 0)
200: {
201: data_p = NULL;
202: return;
203: }
204: // if (iff_chunk_len > 1024*1024)
205: // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
206: data_p -= 8;
207: last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
208: if (!strncmp(data_p, name, 4))
209: return;
210: }
211: }
212:
213: void FindChunk(char *name)
214: {
215: last_chunk = iff_data;
216: FindNextChunk (name);
217: }
218:
219:
220: void DumpChunks(void)
221: {
222: char str[5];
223:
224: str[4] = 0;
225: data_p=iff_data;
226: do
227: {
228: memcpy (str, data_p, 4);
229: data_p += 4;
230: iff_chunk_len = GetLittleLong();
231: Com_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
232: data_p += (iff_chunk_len + 1) & ~1;
233: } while (data_p < iff_end);
234: }
235:
236: /*
237: ============
238: GetWavinfo
239: ============
240: */
241: wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
242: {
243: wavinfo_t info;
244: int i;
245: int format;
246: int samples;
247:
248: memset (&info, 0, sizeof(info));
249:
250: if (!wav)
251: return info;
252:
253: iff_data = wav;
254: iff_end = wav + wavlength;
255:
256: // find "RIFF" chunk
257: FindChunk("RIFF");
258: if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
259: {
260: Com_Printf("Missing RIFF/WAVE chunks\n");
261: return info;
262: }
263:
264: // get "fmt " chunk
265: iff_data = data_p + 12;
266: // DumpChunks ();
267:
268: FindChunk("fmt ");
269: if (!data_p)
270: {
271: Com_Printf("Missing fmt chunk\n");
272: return info;
273: }
274: data_p += 8;
275: format = GetLittleShort();
276: if (format != 1)
277: {
278: Com_Printf("Microsoft PCM format only\n");
279: return info;
280: }
281:
282: info.channels = GetLittleShort();
283: info.rate = GetLittleLong();
284: data_p += 4+2;
285: info.width = GetLittleShort() / 8;
286:
287: // get cue chunk
288: FindChunk("cue ");
289: if (data_p)
290: {
291: data_p += 32;
292: info.loopstart = GetLittleLong();
293: // Com_Printf("loopstart=%d\n", sfx->loopstart);
294:
295: // if the next chunk is a LIST chunk, look for a cue length marker
296: FindNextChunk ("LIST");
297: if (data_p)
298: {
299: if (!strncmp (data_p + 28, "mark", 4))
300: { // this is not a proper parse, but it works with cooledit...
301: data_p += 24;
302: i = GetLittleLong (); // samples in loop
303: info.samples = info.loopstart + i;
304: // Com_Printf("looped length: %i\n", i);
305: }
306: }
307: }
308: else
309: info.loopstart = -1;
310:
311: // find data chunk
312: FindChunk("data");
313: if (!data_p)
314: {
315: Com_Printf("Missing data chunk\n");
316: return info;
317: }
318:
319: data_p += 4;
320: samples = GetLittleLong () / info.width;
321:
322: if (info.samples)
323: {
324: if (samples < info.samples)
325: Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
326: }
327: else
328: info.samples = samples;
329:
330: info.dataofs = data_p - wav;
331:
332: return info;
333: }
334:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.