home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quakeworld_src / client / snd_mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  6.9 KB  |  344 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  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.
  8.  
  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.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  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.
  18.  
  19. */
  20. // snd_mem.c: sound caching
  21.  
  22. #include "quakedef.h"
  23.  
  24. int     cache_full_cycle;
  25.  
  26. byte *S_Alloc (int size);
  27.  
  28. /*
  29. ================
  30. ResampleSfx
  31. ================
  32. */
  33. void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
  34. {
  35.   int   outcount;
  36.   int   srcsample;
  37.   float stepscale;
  38.   int   i;
  39.   int   sample, samplefrac, fracstep;
  40.   sfxcache_t  *sc;
  41.   
  42.   sc = Cache_Check (&sfx->cache);
  43.   if (!sc)
  44.     return;
  45.  
  46.   stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2
  47.  
  48.   outcount = sc->length / stepscale;
  49.   sc->length = outcount;
  50.   if (sc->loopstart != -1)
  51.     sc->loopstart = sc->loopstart / stepscale;
  52.  
  53.   sc->speed = shm->speed;
  54.   if (loadas8bit.value)
  55.     sc->width = 1;
  56.   else
  57.     sc->width = inwidth;
  58.   sc->stereo = 0;
  59.  
  60. // resample / decimate to the current source rate
  61.  
  62.   if (stepscale == 1 && inwidth == 1 && sc->width == 1)
  63.   {
  64. // fast special case
  65.     for (i=0 ; i<outcount ; i++)
  66.       ((signed char *)sc->data)[i]
  67.       = (int)( (unsigned char)(data[i]) - 128);
  68.   }
  69.   else
  70.   {
  71. // general case
  72.     samplefrac = 0;
  73.     fracstep = stepscale*256;
  74.     for (i=0 ; i<outcount ; i++)
  75.     {
  76.       srcsample = samplefrac >> 8;
  77.       samplefrac += fracstep;
  78.       if (inwidth == 2)
  79.         sample = LittleShort ( ((short *)data)[srcsample] );
  80.       else
  81.         sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  82.       if (sc->width == 2)
  83.         ((short *)sc->data)[i] = sample;
  84.       else
  85.         ((signed char *)sc->data)[i] = sample >> 8;
  86.     }
  87.   }
  88. }
  89.  
  90. //=============================================================================
  91.  
  92. /*
  93. ==============
  94. S_LoadSound
  95. ==============
  96. */
  97. sfxcache_t *S_LoadSound (sfx_t *s)
  98. {
  99.     char  namebuffer[256];
  100.   byte  *data;
  101.   wavinfo_t info;
  102.   int   len;
  103.   float stepscale;
  104.   sfxcache_t  *sc;
  105.   byte  stackbuf[1*1024];   // avoid dirtying the cache heap
  106.  
  107. // see if still in memory
  108.   sc = Cache_Check (&s->cache);
  109.   if (sc)
  110.     return sc;
  111.  
  112. //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
  113. // load it in
  114.     Q_strcpy(namebuffer, "sound/");
  115.     Q_strcat(namebuffer, s->name);
  116.  
  117. //  Con_Printf ("loading %s\n",namebuffer);
  118.  
  119.   data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
  120.  
  121.   if (!data)
  122.   {
  123.     Con_Printf ("Couldn't load %s\n", namebuffer);
  124.     return NULL;
  125.   }
  126.  
  127.   info = GetWavinfo (s->name, data, com_filesize);
  128.   if (info.channels != 1)
  129.   {
  130.     Con_Printf ("%s is a stereo sample\n",s->name);
  131.     return NULL;
  132.   }
  133.  
  134.   stepscale = (float)info.rate / shm->speed;  
  135.   len = info.samples / stepscale;
  136.  
  137.   len = len * info.width * info.channels;
  138.  
  139.   sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
  140.   if (!sc)
  141.     return NULL;
  142.   
  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;
  148.  
  149.   ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
  150.  
  151.   return sc;
  152. }
  153.  
  154.  
  155.  
  156. /*
  157. ===============================================================================
  158.  
  159. WAV loading
  160.  
  161. ===============================================================================
  162. */
  163.  
  164.  
  165. byte  *data_p;
  166. byte  *iff_end;
  167. byte  *last_chunk;
  168. byte  *iff_data;
  169. int   iff_chunk_len;
  170.  
  171.  
  172. short GetLittleShort(void)
  173. {
  174.   short val = 0;
  175.   val = *data_p;
  176.   val = val + (*(data_p+1)<<8);
  177.   data_p += 2;
  178.   return val;
  179. }
  180.  
  181. int GetLittleLong(void)
  182. {
  183.   int val = 0;
  184.   val = *data_p;
  185.   val = val + (*(data_p+1)<<8);
  186.   val = val + (*(data_p+2)<<16);
  187.   val = val + (*(data_p+3)<<24);
  188.   data_p += 4;
  189.   return val;
  190. }
  191.  
  192. void FindNextChunk(char *name)
  193. {
  194.   while (1)
  195.   {
  196.     data_p=last_chunk;
  197.  
  198.     if (data_p >= iff_end)
  199.     { // didn't find the chunk
  200.       data_p = NULL;
  201.       return;
  202.     }
  203.     
  204.     data_p += 4;
  205.     iff_chunk_len = GetLittleLong();
  206.     if (iff_chunk_len < 0)
  207.     {
  208.       data_p = NULL;
  209.       return;
  210.     }
  211. //    if (iff_chunk_len > 1024*1024)
  212. //      Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
  213.     data_p -= 8;
  214.     last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
  215.     if (!Q_strncmp(data_p, name, 4))
  216.       return;
  217.   }
  218. }
  219.  
  220. void FindChunk(char *name)
  221. {
  222.   last_chunk = iff_data;
  223.   FindNextChunk (name);
  224. }
  225.  
  226.  
  227. #if 0
  228. void DumpChunks(void)
  229. {
  230.   char  str[5];
  231.   
  232.   str[4] = 0;
  233.   data_p=iff_data;
  234.   do
  235.   {
  236.     memcpy (str, data_p, 4);
  237.     data_p += 4;
  238.     iff_chunk_len = GetLittleLong();
  239.     Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
  240.     data_p += (iff_chunk_len + 1) & ~1;
  241.   } while (data_p < iff_end);
  242. }
  243. #endif
  244.  
  245. /*
  246. ============
  247. GetWavinfo
  248. ============
  249. */
  250. wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  251. {
  252.   wavinfo_t info;
  253.   int     i;
  254.   int     format;
  255.   int   samples;
  256.  
  257.   memset (&info, 0, sizeof(info));
  258.  
  259.   if (!wav)
  260.     return info;
  261.     
  262.   iff_data = wav;
  263.   iff_end = wav + wavlength;
  264.  
  265. // find "RIFF" chunk
  266.   FindChunk("RIFF");
  267.   if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
  268.   {
  269.     Con_Printf("Missing RIFF/WAVE chunks\n");
  270.     return info;
  271.   }
  272.  
  273. // get "fmt " chunk
  274.   iff_data = data_p + 12;
  275. // DumpChunks ();
  276.  
  277.   FindChunk("fmt ");
  278.   if (!data_p)
  279.   {
  280.     Con_Printf("Missing fmt chunk\n");
  281.     return info;
  282.   }
  283.   data_p += 8;
  284.   format = GetLittleShort();
  285.   if (format != 1)
  286.   {
  287.     Con_Printf("Microsoft PCM format only\n");
  288.     return info;
  289.   }
  290.  
  291.   info.channels = GetLittleShort();
  292.   info.rate = GetLittleLong();
  293.   data_p += 4+2;
  294.   info.width = GetLittleShort() / 8;
  295.  
  296. // get cue chunk
  297.   FindChunk("cue ");
  298.   if (data_p)
  299.   {
  300.     data_p += 32;
  301.     info.loopstart = GetLittleLong();
  302. //    Con_Printf("loopstart=%d\n", sfx->loopstart);
  303.  
  304.   // if the next chunk is a LIST chunk, look for a cue length marker
  305.     FindNextChunk ("LIST");
  306.     if (data_p)
  307.     {
  308.       if (!strncmp (data_p + 28, "mark", 4))
  309.       { // this is not a proper parse, but it works with cooledit...
  310.         data_p += 24;
  311.         i = GetLittleLong (); // samples in loop
  312.         info.samples = info.loopstart + i;
  313. //        Con_Printf("looped length: %i\n", i);
  314.       }
  315.     }
  316.   }
  317.   else
  318.     info.loopstart = -1;
  319.  
  320. // find data chunk
  321.   FindChunk("data");
  322.   if (!data_p)
  323.   {
  324.     Con_Printf("Missing data chunk\n");
  325.     return info;
  326.   }
  327.  
  328.   data_p += 4;
  329.   samples = GetLittleLong () / info.width;
  330.  
  331.   if (info.samples)
  332.   {
  333.     if (samples < info.samples)
  334.       Sys_Error ("Sound %s has a bad loop length", name);
  335.   }
  336.   else
  337.     info.samples = samples;
  338.  
  339.   info.dataofs = data_p - wav;
  340.   
  341.   return info;
  342. }
  343.  
  344.