snd_mem.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // snd_mem.c: sound caching
  16. #include "quakedef.h"
  17. int cache_full_cycle;
  18. byte *S_Alloc (int size);
  19. /*
  20. ================
  21. ResampleSfx
  22. ================
  23. */
  24. void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
  25. {
  26. int outcount;
  27. int srcsample;
  28. float stepscale;
  29. int i;
  30. int sample, samplefrac, fracstep;
  31. sfxcache_t *sc;
  32. sc = Cache_Check (&sfx->cache);
  33. if (!sc)
  34. return;
  35. stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2
  36. outcount = sc->length / stepscale;
  37. sc->length = outcount;
  38. if (sc->loopstart != -1)
  39. sc->loopstart = sc->loopstart / stepscale;
  40. sc->speed = shm->speed;
  41. if (loadas8bit.value)
  42. sc->width = 1;
  43. else
  44. sc->width = inwidth;
  45. sc->stereo = 0;
  46. // resample / decimate to the current source rate
  47. if (stepscale == 1 && inwidth == 1 && sc->width == 1)
  48. {
  49. // fast special case
  50. for (i=0 ; i<outcount ; i++)
  51. ((signed char *)sc->data)[i]
  52. = (int)( (unsigned char)(data[i]) - 128);
  53. }
  54. else
  55. {
  56. // general case
  57. samplefrac = 0;
  58. fracstep = stepscale*256;
  59. for (i=0 ; i<outcount ; i++)
  60. {
  61. srcsample = samplefrac >> 8;
  62. samplefrac += fracstep;
  63. if (inwidth == 2)
  64. sample = LittleShort ( ((short *)data)[srcsample] );
  65. else
  66. sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  67. if (sc->width == 2)
  68. ((short *)sc->data)[i] = sample;
  69. else
  70. ((signed char *)sc->data)[i] = sample >> 8;
  71. }
  72. }
  73. }
  74. //=============================================================================
  75. /*
  76. ==============
  77. S_LoadSound
  78. ==============
  79. */
  80. sfxcache_t *S_LoadSound (sfx_t *s)
  81. {
  82. char namebuffer[256];
  83. byte *data;
  84. wavinfo_t info;
  85. int len;
  86. float stepscale;
  87. sfxcache_t *sc;
  88. byte stackbuf[1*1024]; // avoid dirtying the cache heap
  89. // see if still in memory
  90. sc = Cache_Check (&s->cache);
  91. if (sc)
  92. return sc;
  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. // Con_Printf ("loading %s\n",namebuffer);
  98. data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
  99. if (!data)
  100. {
  101. Con_Printf ("Couldn't load %s\n", namebuffer);
  102. return NULL;
  103. }
  104. info = GetWavinfo (s->name, data, com_filesize);
  105. if (info.channels != 1)
  106. {
  107. Con_Printf ("%s is a stereo sample\n",s->name);
  108. return NULL;
  109. }
  110. stepscale = (float)info.rate / shm->speed;
  111. len = info.samples / stepscale;
  112. len = len * info.width * info.channels;
  113. sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
  114. if (!sc)
  115. return NULL;
  116. sc->length = info.samples;
  117. sc->loopstart = info.loopstart;
  118. sc->speed = info.rate;
  119. sc->width = info.width;
  120. sc->stereo = info.channels;
  121. ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
  122. return sc;
  123. }
  124. /*
  125. ===============================================================================
  126. WAV loading
  127. ===============================================================================
  128. */
  129. byte *data_p;
  130. byte *iff_end;
  131. byte *last_chunk;
  132. byte *iff_data;
  133. int iff_chunk_len;
  134. short GetLittleShort(void)
  135. {
  136. short val = 0;
  137. val = *data_p;
  138. val = val + (*(data_p+1)<<8);
  139. data_p += 2;
  140. return val;
  141. }
  142. int GetLittleLong(void)
  143. {
  144. int val = 0;
  145. val = *data_p;
  146. val = val + (*(data_p+1)<<8);
  147. val = val + (*(data_p+2)<<16);
  148. val = val + (*(data_p+3)<<24);
  149. data_p += 4;
  150. return val;
  151. }
  152. void FindNextChunk(char *name)
  153. {
  154. while (1)
  155. {
  156. data_p=last_chunk;
  157. if (data_p >= iff_end)
  158. { // didn't find the chunk
  159. data_p = NULL;
  160. return;
  161. }
  162. data_p += 4;
  163. iff_chunk_len = GetLittleLong();
  164. if (iff_chunk_len < 0)
  165. {
  166. data_p = NULL;
  167. return;
  168. }
  169. // if (iff_chunk_len > 1024*1024)
  170. // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
  171. data_p -= 8;
  172. last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
  173. if (!Q_strncmp(data_p, name, 4))
  174. return;
  175. }
  176. }
  177. void FindChunk(char *name)
  178. {
  179. last_chunk = iff_data;
  180. FindNextChunk (name);
  181. }
  182. #if 0
  183. void DumpChunks(void)
  184. {
  185. char str[5];
  186. str[4] = 0;
  187. data_p=iff_data;
  188. do
  189. {
  190. memcpy (str, data_p, 4);
  191. data_p += 4;
  192. iff_chunk_len = GetLittleLong();
  193. Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
  194. data_p += (iff_chunk_len + 1) & ~1;
  195. } while (data_p < iff_end);
  196. }
  197. #endif
  198. /*
  199. ============
  200. GetWavinfo
  201. ============
  202. */
  203. wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  204. {
  205. wavinfo_t info;
  206. int i;
  207. int format;
  208. int samples;
  209. memset (&info, 0, sizeof(info));
  210. if (!wav)
  211. return info;
  212. iff_data = wav;
  213. iff_end = wav + wavlength;
  214. // find "RIFF" chunk
  215. FindChunk("RIFF");
  216. if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
  217. {
  218. Con_Printf("Missing RIFF/WAVE chunks\n");
  219. return info;
  220. }
  221. // get "fmt " chunk
  222. iff_data = data_p + 12;
  223. // DumpChunks ();
  224. FindChunk("fmt ");
  225. if (!data_p)
  226. {
  227. Con_Printf("Missing fmt chunk\n");
  228. return info;
  229. }
  230. data_p += 8;
  231. format = GetLittleShort();
  232. if (format != 1)
  233. {
  234. Con_Printf("Microsoft PCM format only\n");
  235. return info;
  236. }
  237. info.channels = GetLittleShort();
  238. info.rate = GetLittleLong();
  239. data_p += 4+2;
  240. info.width = GetLittleShort() / 8;
  241. // get cue chunk
  242. FindChunk("cue ");
  243. if (data_p)
  244. {
  245. data_p += 32;
  246. info.loopstart = GetLittleLong();
  247. // Con_Printf("loopstart=%d\n", sfx->loopstart);
  248. // if the next chunk is a LIST chunk, look for a cue length marker
  249. FindNextChunk ("LIST");
  250. if (data_p)
  251. {
  252. if (!strncmp (data_p + 28, "mark", 4))
  253. { // this is not a proper parse, but it works with cooledit...
  254. data_p += 24;
  255. i = GetLittleLong (); // samples in loop
  256. info.samples = info.loopstart + i;
  257. // Con_Printf("looped length: %i\n", i);
  258. }
  259. }
  260. }
  261. else
  262. info.loopstart = -1;
  263. // find data chunk
  264. FindChunk("data");
  265. if (!data_p)
  266. {
  267. Con_Printf("Missing data chunk\n");
  268. return info;
  269. }
  270. data_p += 4;
  271. samples = GetLittleLong () / info.width;
  272. if (info.samples)
  273. {
  274. if (samples < info.samples)
  275. Sys_Error ("Sound %s has a bad loop length", name);
  276. }
  277. else
  278. info.samples = samples;
  279. info.dataofs = data_p - wav;
  280. return info;
  281. }