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