home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / snd_mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  6.9 KB  |  342 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. void DumpChunks(void)
  228. {
  229.   char  str[5];
  230.   
  231.   str[4] = 0;
  232.   data_p=iff_data;
  233.   do
  234.   {
  235.     memcpy (str, data_p, 4);
  236.     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);
  241. }
  242.  
  243. /*
  244. ============
  245. GetWavinfo
  246. ============
  247. */
  248. wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  249. {
  250.   wavinfo_t info;
  251.   int     i;
  252.   int     format;
  253.   int   samples;
  254.  
  255.   memset (&info, 0, sizeof(info));
  256.  
  257.   if (!wav)
  258.     return info;
  259.     
  260.   iff_data = wav;
  261.   iff_end = wav + wavlength;
  262.  
  263. // find "RIFF" chunk
  264.   FindChunk("RIFF");
  265.   if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
  266.   {
  267.     Con_Printf("Missing RIFF/WAVE chunks\n");
  268.     return info;
  269.   }
  270.  
  271. // get "fmt " chunk
  272.   iff_data = data_p + 12;
  273. // DumpChunks ();
  274.  
  275.   FindChunk("fmt ");
  276.   if (!data_p)
  277.   {
  278.     Con_Printf("Missing fmt chunk\n");
  279.     return info;
  280.   }
  281.   data_p += 8;
  282.   format = GetLittleShort();
  283.   if (format != 1)
  284.   {
  285.     Con_Printf("Microsoft PCM format only\n");
  286.     return info;
  287.   }
  288.  
  289.   info.channels = GetLittleShort();
  290.   info.rate = GetLittleLong();
  291.   data_p += 4+2;
  292.   info.width = GetLittleShort() / 8;
  293.  
  294. // get cue chunk
  295.   FindChunk("cue ");
  296.   if (data_p)
  297.   {
  298.     data_p += 32;
  299.     info.loopstart = GetLittleLong();
  300. //    Con_Printf("loopstart=%d\n", sfx->loopstart);
  301.  
  302.   // if the next chunk is a LIST chunk, look for a cue length marker
  303.     FindNextChunk ("LIST");
  304.     if (data_p)
  305.     {
  306.       if (!strncmp (data_p + 28, "mark", 4))
  307.       { // this is not a proper parse, but it works with cooledit...
  308.         data_p += 24;
  309.         i = GetLittleLong (); // samples in loop
  310.         info.samples = info.loopstart + i;
  311. //        Con_Printf("looped length: %i\n", i);
  312.       }
  313.     }
  314.   }
  315.   else
  316.     info.loopstart = -1;
  317.  
  318. // find data chunk
  319.   FindChunk("data");
  320.   if (!data_p)
  321.   {
  322.     Con_Printf("Missing data chunk\n");
  323.     return info;
  324.   }
  325.  
  326.   data_p += 4;
  327.   samples = GetLittleLong () / info.width;
  328.  
  329.   if (info.samples)
  330.   {
  331.     if (samples < info.samples)
  332.       Sys_Error ("Sound %s has a bad loop length", name);
  333.   }
  334.   else
  335.     info.samples = samples;
  336.  
  337.   info.dataofs = data_p - wav;
  338.   
  339.   return info;
  340. }
  341.  
  342.