Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.