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
37 int dataofs; // chunk starts this many bytes from file start
42 static qbyte *iff_end;
43 static qbyte *last_chunk;
44 static qbyte *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(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)
88 last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
89 if (!strncmp(data_p, name, 4))
94 static void FindChunk(char *name)
96 last_chunk = iff_data;
102 static void DumpChunks(void)
110 memcpy (str, data_p, 4);
112 iff_chunk_len = GetLittleLong();
113 Con_Printf("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
114 data_p += (iff_chunk_len + 1) & ~1;
115 } while (data_p < iff_end);
125 static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
132 memset (&info, 0, sizeof(info));
138 iff_end = wav + wavlength;
142 if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
144 Con_Print("Missing RIFF/WAVE chunks\n");
149 iff_data = data_p + 12;
155 Con_Print("Missing fmt chunk\n");
159 format = GetLittleShort();
162 Con_Print("Microsoft PCM format only\n");
166 info.channels = GetLittleShort();
167 info.rate = GetLittleLong();
169 info.width = GetLittleShort() / 8;
176 info.loopstart = GetLittleLong();
178 // if the next chunk is a LIST chunk, look for a cue length marker
179 FindNextChunk ("LIST");
182 if (!strncmp (data_p + 28, "mark", 4))
183 { // this is not a proper parse, but it works with cooledit...
185 i = GetLittleLong (); // samples in loop
186 info.samples = info.loopstart + i;
197 Con_Print("Missing data chunk\n");
202 samples = GetLittleLong () / info.width / info.channels;
206 if (samples < info.samples)
207 Host_Error ("Sound %s has a bad loop length", name);
210 info.samples = samples;
212 info.dataofs = data_p - wav;
223 static const sfxbuffer_t* WAV_FetchSound (channel_t* ch, unsigned int start, unsigned int nbsamples)
225 return ch->sfx->fetcher_data;
229 snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL };
237 qboolean S_LoadWavFile (const char *filename, sfx_t *s)
244 Mem_FreePool (&s->mempool);
245 s->mempool = Mem_AllocPool(s->name, 0, NULL);
248 data = FS_LoadFile(filename, s->mempool, false);
251 Mem_FreePool (&s->mempool);
255 // Don't try to load it if it's not a WAV file
256 if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4))
258 Mem_FreePool (&s->mempool);
262 Con_DPrintf ("Loading WAV file \"%s\"\n", filename);
264 info = GetWavinfo (s->name, data, fs_filesize);
265 // Stereo sounds are allowed (intended for music)
266 if (info.channels < 1 || info.channels > 2)
268 Con_Printf("%s has an unsupported number of channels (%i)\n",s->name, info.channels);
269 Mem_FreePool (&s->mempool);
273 // calculate resampled length
274 len = (int) ((double) info.samples * (double) shm->format.speed / (double) info.rate);
275 len = len * info.width * info.channels;
277 sb = Mem_Alloc (s->mempool, len + sizeof (*sb) - sizeof (sb->data));
280 Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name);
281 Mem_FreePool(&s->mempool);
285 s->fetcher = &wav_fetcher;
286 s->fetcher_data = sb;
287 s->format.speed = info.rate;
288 s->format.width = info.width;
289 s->format.channels = info.channels;
290 if (info.loopstart < 0)
293 s->loopstart = (double)info.loopstart * (double)shm->format.speed / (double)s->format.speed;
294 s->flags &= ~SFXFLAG_STREAMED;
296 #if BYTE_ORDER != LITTLE_ENDIAN
297 // We must convert the WAV data from little endian
298 // to the machine endianess before resampling it
304 len = info.samples * info.channels;
305 ptr = (short*)(data + info.dataofs);
306 for (i = 0; i < len; i++)
307 ptr[i] = LittleShort (ptr[i]);
311 sb->length = ResampleSfx (data + info.dataofs, info.samples, &s->format, sb->data, s->name);
312 s->format.speed = shm->format.speed;
313 s->total_length = sb->length;