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 the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // snd_mem.c: sound caching
26 byte
*S_Alloc (int size
);
33 void ResampleSfx (sfx_t
*sfx
, int inrate
, int inwidth
, byte
*data
)
39 int sample
, samplefrac
, fracstep
;
42 sc
= Cache_Check (&sfx
->cache
);
46 stepscale
= (float)inrate
/ shm
->speed
; // this is usually 0.5, 1, or 2
48 outcount
= sc
->length
/ stepscale
;
49 sc
->length
= outcount
;
50 if (sc
->loopstart
!= -1)
51 sc
->loopstart
= sc
->loopstart
/ stepscale
;
53 sc
->speed
= shm
->speed
;
60 // resample / decimate to the current source rate
62 if (stepscale
== 1 && inwidth
== 1 && sc
->width
== 1)
65 for (i
=0 ; i
<outcount
; i
++)
66 ((signed char *)sc
->data
)[i
]
67 = (int)( (unsigned char)(data
[i
]) - 128);
73 fracstep
= stepscale
*256;
74 for (i
=0 ; i
<outcount
; i
++)
76 srcsample
= samplefrac
>> 8;
77 samplefrac
+= fracstep
;
79 sample
= LittleShort ( ((short *)data
)[srcsample
] );
81 sample
= (int)( (unsigned char)(data
[srcsample
]) - 128) << 8;
83 ((short *)sc
->data
)[i
] = sample
;
85 ((signed char *)sc
->data
)[i
] = sample
>> 8;
90 //=============================================================================
97 sfxcache_t
*S_LoadSound (sfx_t
*s
)
105 byte stackbuf
[1*1024]; // avoid dirtying the cache heap
107 // see if still in memory
108 sc
= Cache_Check (&s
->cache
);
112 //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
114 Q_strcpy(namebuffer
, "sound/");
115 Q_strcat(namebuffer
, s
->name
);
117 // Con_Printf ("loading %s\n",namebuffer);
119 data
= COM_LoadStackFile(namebuffer
, stackbuf
, sizeof(stackbuf
));
123 Con_Printf ("Couldn't load %s\n", namebuffer
);
127 info
= GetWavinfo (s
->name
, data
, com_filesize
);
128 if (info
.channels
!= 1)
130 Con_Printf ("%s is a stereo sample\n",s
->name
);
134 stepscale
= (float)info
.rate
/ shm
->speed
;
135 len
= info
.samples
/ stepscale
;
137 len
= len
* info
.width
* info
.channels
;
139 sc
= Cache_Alloc ( &s
->cache
, len
+ sizeof(sfxcache_t
), s
->name
);
143 sc
->length
= info
.samples
;
144 sc
->loopstart
= info
.loopstart
;
145 sc
->speed
= info
.rate
;
146 sc
->width
= info
.width
;
147 sc
->stereo
= info
.channels
;
149 ResampleSfx (s
, sc
->speed
, sc
->width
, data
+ info
.dataofs
);
157 ===============================================================================
161 ===============================================================================
172 short GetLittleShort(void)
176 val
= val
+ (*(data_p
+1)<<8);
181 int GetLittleLong(void)
185 val
= val
+ (*(data_p
+1)<<8);
186 val
= val
+ (*(data_p
+2)<<16);
187 val
= val
+ (*(data_p
+3)<<24);
192 void FindNextChunk(char *name
)
198 if (data_p
>= iff_end
)
199 { // didn't find the chunk
205 iff_chunk_len
= GetLittleLong();
206 if (iff_chunk_len
< 0)
211 // if (iff_chunk_len > 1024*1024)
212 // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
214 last_chunk
= data_p
+ 8 + ( (iff_chunk_len
+ 1) & ~1 );
215 if (!Q_strncmp(data_p
, name
, 4))
220 void FindChunk(char *name
)
222 last_chunk
= iff_data
;
223 FindNextChunk (name
);
227 void DumpChunks(void)
235 memcpy (str
, data_p
, 4);
237 iff_chunk_len
= GetLittleLong();
238 Con_Printf ("0x%x : %s (%d)\n", (int)(data_p
- 4), str
, iff_chunk_len
);
239 data_p
+= (iff_chunk_len
+ 1) & ~1;
240 } while (data_p
< iff_end
);
248 wavinfo_t
GetWavinfo (char *name
, byte
*wav
, int wavlength
)
255 memset (&info
, 0, sizeof(info
));
261 iff_end
= wav
+ wavlength
;
265 if (!(data_p
&& !Q_strncmp(data_p
+8, "WAVE", 4)))
267 Con_Printf("Missing RIFF/WAVE chunks\n");
272 iff_data
= data_p
+ 12;
278 Con_Printf("Missing fmt chunk\n");
282 format
= GetLittleShort();
285 Con_Printf("Microsoft PCM format only\n");
289 info
.channels
= GetLittleShort();
290 info
.rate
= GetLittleLong();
292 info
.width
= GetLittleShort() / 8;
299 info
.loopstart
= GetLittleLong();
300 // Con_Printf("loopstart=%d\n", sfx->loopstart);
302 // if the next chunk is a LIST chunk, look for a cue length marker
303 FindNextChunk ("LIST");
306 if (!strncmp (data_p
+ 28, "mark", 4))
307 { // this is not a proper parse, but it works with cooledit...
309 i
= GetLittleLong (); // samples in loop
310 info
.samples
= info
.loopstart
+ i
;
311 // Con_Printf("looped length: %i\n", i);
322 Con_Printf("Missing data chunk\n");
327 samples
= GetLittleLong () / info
.width
;
331 if (samples
< info
.samples
)
332 Sys_Error ("Sound %s has a bad loop length", name
);
335 info
.samples
= samples
;
337 info
.dataofs
= data_p
- wav
;