2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to:
18 Free Software Foundation, Inc.
19 59 Temple Place - Suite 330
20 Boston, MA 02111-1307, USA
30 typedef struct wavinfo_s
37 int dataofs; // chunk starts this many bytes from file start
41 static unsigned char *data_p;
42 static unsigned char *iff_end;
43 static unsigned char *last_chunk;
44 static unsigned char *iff_data;
45 static int iff_chunk_len;
48 static short GetLittleShort(void)
52 val = BuffLittleShort (data_p);
58 static int GetLittleLong(void)
62 val = BuffLittleLong (data_p);
68 static void FindNextChunk(const char *name)
74 if (data_p >= iff_end)
75 { // didn't find the chunk
81 iff_chunk_len = GetLittleLong();
82 if (iff_chunk_len < 0)
87 if (data_p + iff_chunk_len > iff_end)
94 last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
95 if (!strncmp((const char *)data_p, name, 4))
100 static void FindChunk(const char *name)
102 last_chunk = iff_data;
103 FindNextChunk (name);
108 static void DumpChunks(void)
116 memcpy (str, data_p, 4);
118 iff_chunk_len = GetLittleLong();
119 Con_Printf("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
120 data_p += (iff_chunk_len + 1) & ~1;
121 } while (data_p < iff_end);
131 static wavinfo_t GetWavinfo (char *name, unsigned char *wav, int wavlength)
138 memset (&info, 0, sizeof(info));
144 iff_end = wav + wavlength;
148 if (!(data_p && !strncmp((const char *)data_p+8, "WAVE", 4)))
150 Con_Print("Missing RIFF/WAVE chunks\n");
155 iff_data = data_p + 12;
161 Con_Print("Missing fmt chunk\n");
165 format = GetLittleShort();
168 Con_Print("Microsoft PCM format only\n");
172 info.channels = GetLittleShort();
173 info.rate = GetLittleLong();
175 info.width = GetLittleShort() / 8;
182 info.loopstart = GetLittleLong();
184 // if the next chunk is a LIST chunk, look for a cue length marker
185 FindNextChunk ("LIST");
188 if (!strncmp ((const char *)data_p + 28, "mark", 4))
189 { // this is not a proper parse, but it works with cooledit...
191 i = GetLittleLong (); // samples in loop
192 info.samples = info.loopstart + i;
203 Con_Print("Missing data chunk\n");
208 samples = GetLittleLong () / info.width / info.channels;
212 if (samples < info.samples)
214 Con_Printf ("Sound %s has a bad loop length\n", name);
215 info.samples = samples;
219 info.samples = samples;
221 info.dataofs = data_p - wav;
232 static void WAV_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
234 int i, len = numsampleframes * sfx->format.channels;
235 if (sfx->format.width == 2)
237 const short *bufs = (const short *)sfx->fetcher_data + firstsampleframe * sfx->format.channels;
238 for (i = 0;i < len;i++)
239 outsamplesfloat[i] = bufs[i] * (1.0f / 32768.0f);
243 const signed char *bufb = (const signed char *)sfx->fetcher_data + firstsampleframe * sfx->format.channels;
244 for (i = 0;i < len;i++)
245 outsamplesfloat[i] = bufb[i] * (1.0f / 128.0f);
254 static void WAV_FreeSfx(sfx_t *sfx)
256 // free the loaded sound data
257 Mem_Free(sfx->fetcher_data);
260 const snd_fetcher_t wav_fetcher = { WAV_GetSamplesFloat, NULL, WAV_FreeSfx };
268 qboolean S_LoadWavFile (const char *filename, sfx_t *sfx)
270 fs_offset_t filesize;
274 const unsigned char *inb;
278 if (sfx->fetcher != NULL)
282 data = FS_LoadFile(filename, snd_mempool, false, &filesize);
286 // Don't try to load it if it's not a WAV file
287 if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4))
293 if (developer_loading.integer >= 2)
294 Con_Printf ("Loading WAV file \"%s\"\n", filename);
296 info = GetWavinfo (sfx->name, data, (int)filesize);
297 if (info.channels < 1 || info.channels > 2) // Stereo sounds are allowed (intended for music)
299 Con_Printf("%s has an unsupported number of channels (%i)\n",sfx->name, info.channels);
303 //if (info.channels == 2)
304 // Log_Printf("stereosounds.log", "%s\n", sfx->name);
306 sfx->format.speed = info.rate;
307 sfx->format.width = info.width;
308 sfx->format.channels = info.channels;
309 sfx->fetcher = &wav_fetcher;
310 sfx->fetcher_data = Mem_Alloc(snd_mempool, info.samples * sfx->format.width * sfx->format.channels);
311 sfx->total_length = info.samples;
312 sfx->memsize += filesize;
313 len = info.samples * sfx->format.channels * sfx->format.width;
314 inb = data + info.dataofs;
315 outb = (unsigned char *)sfx->fetcher_data;
320 // we have to byteswap the data at load (better than doing it while mixing)
321 for (i = 0;i < len;i += 2)
329 // we can just copy it straight
330 memcpy(outb, inb, len);
335 // convert unsigned byte sound data to signed bytes for quicker mixing
336 for (i = 0;i < len;i++)
337 outb[i] = inb[i] - 0x80;
340 if (info.loopstart < 0)
341 sfx->loopstart = sfx->total_length;
343 sfx->loopstart = info.loopstart;
344 sfx->loopstart = min(sfx->loopstart, sfx->total_length);
345 sfx->flags &= ~SFXFLAG_STREAMED;