snd_mem.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. /*****************************************************************************
  19. * name: snd_mem.c
  20. *
  21. * desc: sound caching
  22. *
  23. * $Archive: /MissionPack/code/client/snd_mem.c $
  24. *
  25. *****************************************************************************/
  26. #include "snd_local.h"
  27. #define DEF_COMSOUNDMEGS "8"
  28. /*
  29. ===============================================================================
  30. memory management
  31. ===============================================================================
  32. */
  33. static sndBuffer *buffer = NULL;
  34. static sndBuffer *freelist = NULL;
  35. static int inUse = 0;
  36. static int totalInUse = 0;
  37. short *sfxScratchBuffer = NULL;
  38. sfx_t *sfxScratchPointer = NULL;
  39. int sfxScratchIndex = 0;
  40. void SND_free(sndBuffer *v) {
  41. *(sndBuffer **)v = freelist;
  42. freelist = (sndBuffer*)v;
  43. inUse += sizeof(sndBuffer);
  44. }
  45. sndBuffer* SND_malloc() {
  46. sndBuffer *v;
  47. redo:
  48. if (freelist == NULL) {
  49. S_FreeOldestSound();
  50. goto redo;
  51. }
  52. inUse -= sizeof(sndBuffer);
  53. totalInUse += sizeof(sndBuffer);
  54. v = freelist;
  55. freelist = *(sndBuffer **)freelist;
  56. v->next = NULL;
  57. return v;
  58. }
  59. void SND_setup() {
  60. sndBuffer *p, *q;
  61. cvar_t *cv;
  62. int scs;
  63. cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
  64. scs = (cv->integer*1536);
  65. buffer = malloc(scs*sizeof(sndBuffer) );
  66. // allocate the stack based hunk allocator
  67. sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
  68. sfxScratchPointer = NULL;
  69. inUse = scs*sizeof(sndBuffer);
  70. p = buffer;;
  71. q = p + scs;
  72. while (--q > p)
  73. *(sndBuffer **)q = q-1;
  74. *(sndBuffer **)q = NULL;
  75. freelist = p + scs - 1;
  76. Com_Printf("Sound memory manager started\n");
  77. }
  78. /*
  79. ===============================================================================
  80. WAV loading
  81. ===============================================================================
  82. */
  83. static byte *data_p;
  84. static byte *iff_end;
  85. static byte *last_chunk;
  86. static byte *iff_data;
  87. static int iff_chunk_len;
  88. static short GetLittleShort(void)
  89. {
  90. short val = 0;
  91. val = *data_p;
  92. val = val + (*(data_p+1)<<8);
  93. data_p += 2;
  94. return val;
  95. }
  96. static int GetLittleLong(void)
  97. {
  98. int val = 0;
  99. val = *data_p;
  100. val = val + (*(data_p+1)<<8);
  101. val = val + (*(data_p+2)<<16);
  102. val = val + (*(data_p+3)<<24);
  103. data_p += 4;
  104. return val;
  105. }
  106. static void FindNextChunk(char *name)
  107. {
  108. while (1)
  109. {
  110. data_p=last_chunk;
  111. if (data_p >= iff_end)
  112. { // didn't find the chunk
  113. data_p = NULL;
  114. return;
  115. }
  116. data_p += 4;
  117. iff_chunk_len = GetLittleLong();
  118. if (iff_chunk_len < 0)
  119. {
  120. data_p = NULL;
  121. return;
  122. }
  123. data_p -= 8;
  124. last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
  125. if (!strncmp((char *)data_p, name, 4))
  126. return;
  127. }
  128. }
  129. static void FindChunk(char *name)
  130. {
  131. last_chunk = iff_data;
  132. FindNextChunk (name);
  133. }
  134. /*
  135. ============
  136. GetWavinfo
  137. ============
  138. */
  139. static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  140. {
  141. wavinfo_t info;
  142. Com_Memset (&info, 0, sizeof(info));
  143. if (!wav)
  144. return info;
  145. iff_data = wav;
  146. iff_end = wav + wavlength;
  147. // find "RIFF" chunk
  148. FindChunk("RIFF");
  149. if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
  150. {
  151. Com_Printf("Missing RIFF/WAVE chunks\n");
  152. return info;
  153. }
  154. // get "fmt " chunk
  155. iff_data = data_p + 12;
  156. // DumpChunks ();
  157. FindChunk("fmt ");
  158. if (!data_p)
  159. {
  160. Com_Printf("Missing fmt chunk\n");
  161. return info;
  162. }
  163. data_p += 8;
  164. info.format = GetLittleShort();
  165. info.channels = GetLittleShort();
  166. info.rate = GetLittleLong();
  167. data_p += 4+2;
  168. info.width = GetLittleShort() / 8;
  169. if (info.format != 1)
  170. {
  171. Com_Printf("Microsoft PCM format only\n");
  172. return info;
  173. }
  174. // find data chunk
  175. FindChunk("data");
  176. if (!data_p)
  177. {
  178. Com_Printf("Missing data chunk\n");
  179. return info;
  180. }
  181. data_p += 4;
  182. info.samples = GetLittleLong () / info.width;
  183. info.dataofs = data_p - wav;
  184. return info;
  185. }
  186. /*
  187. ================
  188. ResampleSfx
  189. resample / decimate to the current source rate
  190. ================
  191. */
  192. static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
  193. int outcount;
  194. int srcsample;
  195. float stepscale;
  196. int i;
  197. int sample, samplefrac, fracstep;
  198. int part;
  199. sndBuffer *chunk;
  200. stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
  201. outcount = sfx->soundLength / stepscale;
  202. sfx->soundLength = outcount;
  203. samplefrac = 0;
  204. fracstep = stepscale * 256;
  205. chunk = sfx->soundData;
  206. for (i=0 ; i<outcount ; i++)
  207. {
  208. srcsample = samplefrac >> 8;
  209. samplefrac += fracstep;
  210. if( inwidth == 2 ) {
  211. sample = LittleShort ( ((short *)data)[srcsample] );
  212. } else {
  213. sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  214. }
  215. part = (i&(SND_CHUNK_SIZE-1));
  216. if (part == 0) {
  217. sndBuffer *newchunk;
  218. newchunk = SND_malloc();
  219. if (chunk == NULL) {
  220. sfx->soundData = newchunk;
  221. } else {
  222. chunk->next = newchunk;
  223. }
  224. chunk = newchunk;
  225. }
  226. chunk->sndChunk[part] = sample;
  227. }
  228. }
  229. /*
  230. ================
  231. ResampleSfx
  232. resample / decimate to the current source rate
  233. ================
  234. */
  235. static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
  236. int outcount;
  237. int srcsample;
  238. float stepscale;
  239. int i;
  240. int sample, samplefrac, fracstep;
  241. stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
  242. outcount = samples / stepscale;
  243. samplefrac = 0;
  244. fracstep = stepscale * 256;
  245. for (i=0 ; i<outcount ; i++)
  246. {
  247. srcsample = samplefrac >> 8;
  248. samplefrac += fracstep;
  249. if( inwidth == 2 ) {
  250. sample = LittleShort ( ((short *)data)[srcsample] );
  251. } else {
  252. sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  253. }
  254. sfx[i] = sample;
  255. }
  256. return outcount;
  257. }
  258. //=============================================================================
  259. /*
  260. ==============
  261. S_LoadSound
  262. The filename may be different than sfx->name in the case
  263. of a forced fallback of a player specific sound
  264. ==============
  265. */
  266. qboolean S_LoadSound( sfx_t *sfx )
  267. {
  268. byte *data;
  269. short *samples;
  270. wavinfo_t info;
  271. int size;
  272. // player specific sounds are never directly loaded
  273. if ( sfx->soundName[0] == '*') {
  274. return qfalse;
  275. }
  276. // load it in
  277. size = FS_ReadFile( sfx->soundName, (void **)&data );
  278. if ( !data ) {
  279. return qfalse;
  280. }
  281. info = GetWavinfo( sfx->soundName, data, size );
  282. if ( info.channels != 1 ) {
  283. Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
  284. FS_FreeFile (data);
  285. return qfalse;
  286. }
  287. if ( info.width == 1 ) {
  288. Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
  289. }
  290. if ( info.rate != 22050 ) {
  291. Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
  292. }
  293. samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
  294. sfx->lastTimeUsed = Com_Milliseconds()+1;
  295. // each of these compression schemes works just fine
  296. // but the 16bit quality is much nicer and with a local
  297. // install assured we can rely upon the sound memory
  298. // manager to do the right thing for us and page
  299. // sound in as needed
  300. if( sfx->soundCompressed == qtrue) {
  301. sfx->soundCompressionMethod = 1;
  302. sfx->soundData = NULL;
  303. sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
  304. S_AdpcmEncodeSound(sfx, samples);
  305. #if 0
  306. } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
  307. sfx->soundCompressionMethod = 3;
  308. sfx->soundData = NULL;
  309. sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
  310. encodeMuLaw( sfx, samples);
  311. } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
  312. sfx->soundCompressionMethod = 2;
  313. sfx->soundData = NULL;
  314. sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
  315. encodeWavelet( sfx, samples);
  316. #endif
  317. } else {
  318. sfx->soundCompressionMethod = 0;
  319. sfx->soundLength = info.samples;
  320. sfx->soundData = NULL;
  321. ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
  322. }
  323. Hunk_FreeTempMemory(samples);
  324. FS_FreeFile( data );
  325. return qtrue;
  326. }
  327. void S_DisplayFreeMemory() {
  328. Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
  329. }