home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / glquake_src / snd_mix.c < prev    next >
C/C++ Source or Header  |  2000-02-07  |  9KB  |  411 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_mix.c -- portable code to mix sounds for snd_dma.c
  21.  
  22. #include "quakedef.h"
  23.  
  24. #ifdef _WIN32
  25. #include "winquake.h"
  26. #else
  27. #define DWORD unsigned long
  28. #endif
  29.  
  30. #define PAINTBUFFER_SIZE  512
  31. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  32. int   snd_scaletable[32][256];
  33. int   *snd_p, snd_linear_count, snd_vol;
  34. short *snd_out;
  35.  
  36. #ifdef __060__
  37. #undef AMIGA
  38. #endif
  39.  
  40. #ifdef AMIGA
  41. extern void S_TransferPaintBuffer(int);
  42. #else
  43.  
  44. void Snd_WriteLinearBlastStereo16 (void);
  45.  
  46. #if !id386
  47. void Snd_WriteLinearBlastStereo16 (void)
  48. {
  49.   int   i;
  50.   int   val;
  51.  
  52.   for (i=0 ; i<snd_linear_count ; i+=2)
  53.   {
  54.     val = (snd_p[i]*snd_vol)>>8;
  55.     if (val > 0x7fff)
  56.       snd_out[i] = 0x7fff;
  57.     else if (val < (short)0x8000)
  58.       snd_out[i] = (short)0x8000;
  59.     else
  60.       snd_out[i] = val;
  61.  
  62.     val = (snd_p[i+1]*snd_vol)>>8;
  63.     if (val > 0x7fff)
  64.       snd_out[i+1] = 0x7fff;
  65.     else if (val < (short)0x8000)
  66.       snd_out[i+1] = (short)0x8000;
  67.     else
  68.       snd_out[i+1] = val;
  69.   }
  70. }
  71. #endif
  72.  
  73. void S_TransferStereo16 (int endtime)
  74. {
  75.   int   lpos;
  76.   int   lpaintedtime;
  77.   DWORD *pbuf;
  78. #ifdef _WIN32
  79.   int   reps;
  80.   DWORD dwSize,dwSize2;
  81.   DWORD *pbuf2;
  82.   HRESULT hresult;
  83. #endif
  84.   
  85.   snd_vol = volume.value*256;
  86.  
  87.   snd_p = (int *) paintbuffer;
  88.   lpaintedtime = paintedtime;
  89.  
  90. #ifdef _WIN32
  91.   if (pDSBuf)
  92.   {
  93.     reps = 0;
  94.  
  95.     while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  96.                      &pbuf2, &dwSize2, 0)) != DS_OK)
  97.     {
  98.       if (hresult != DSERR_BUFFERLOST)
  99.       {
  100.         Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
  101.         S_Shutdown ();
  102.         S_Startup ();
  103.         return;
  104.       }
  105.  
  106.       if (++reps > 10000)
  107.       {
  108.         Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
  109.         S_Shutdown ();
  110.         S_Startup ();
  111.         return;
  112.       }
  113.     }
  114.   }
  115.   else
  116. #endif
  117.   {
  118.     pbuf = (DWORD *)shm->buffer;
  119.   }
  120.  
  121.   while (lpaintedtime < endtime)
  122.   {
  123.   // handle recirculating buffer issues
  124.     lpos = lpaintedtime & ((shm->samples>>1)-1);
  125.  
  126.     snd_out = (short *) pbuf + (lpos<<1);
  127.  
  128.     snd_linear_count = (shm->samples>>1) - lpos;
  129.     if (lpaintedtime + snd_linear_count > endtime)
  130.       snd_linear_count = endtime - lpaintedtime;
  131.  
  132.     snd_linear_count <<= 1;
  133.  
  134.   // write a linear blast of samples
  135.     Snd_WriteLinearBlastStereo16 ();
  136.  
  137.     snd_p += snd_linear_count;
  138.     lpaintedtime += (snd_linear_count>>1);
  139.   }
  140.  
  141. #ifdef _WIN32
  142.   if (pDSBuf)
  143.     pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  144. #endif
  145. }
  146.  
  147. void S_TransferPaintBuffer(int endtime)
  148. {
  149.   int   out_idx;
  150.   int   count;
  151.   int   out_mask;
  152.   int   *p;
  153.   int   step;
  154.   int   val;
  155.   int   snd_vol;
  156.   DWORD *pbuf;
  157. #ifdef _WIN32
  158.   int   reps;
  159.   DWORD dwSize,dwSize2;
  160.   DWORD *pbuf2;
  161.   HRESULT hresult;
  162. #endif
  163.  
  164.   if (shm->samplebits == 16 && shm->channels == 2)
  165.   {
  166.     S_TransferStereo16 (endtime);
  167.     return;
  168.   }
  169.   
  170.   p = (int *) paintbuffer;
  171.   count = (endtime - paintedtime) * shm->channels;
  172.   out_mask = shm->samples - 1; 
  173.   out_idx = paintedtime * shm->channels & out_mask;
  174.   step = 3 - shm->channels;
  175.   snd_vol = volume.value*256;
  176.  
  177. #ifdef _WIN32
  178.   if (pDSBuf)
  179.   {
  180.     reps = 0;
  181.  
  182.     while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  183.                      &pbuf2,&dwSize2, 0)) != DS_OK)
  184.     {
  185.       if (hresult != DSERR_BUFFERLOST)
  186.       {
  187.         Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
  188.         S_Shutdown ();
  189.         S_Startup ();
  190.         return;
  191.       }
  192.  
  193.       if (++reps > 10000)
  194.       {
  195.         Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
  196.         S_Shutdown ();
  197.         S_Startup ();
  198.         return;
  199.       }
  200.     }
  201.   }
  202.   else
  203. #endif
  204.   {
  205.     pbuf = (DWORD *)shm->buffer;
  206.   }
  207.  
  208.   if (shm->samplebits == 16)
  209.   {
  210.     short *out = (short *) pbuf;
  211.     while (count--)
  212.     {
  213.       val = (*p * snd_vol) >> 8;
  214.       p+= step;
  215.       if (val > 0x7fff)
  216.         val = 0x7fff;
  217.       else if (val < (short)0x8000)
  218.         val = (short)0x8000;
  219.       out[out_idx] = val;
  220.       out_idx = (out_idx + 1) & out_mask;
  221.     }
  222.   }
  223.   else if (shm->samplebits == 8)
  224.   {
  225.     unsigned char *out = (unsigned char *) pbuf;
  226.     while (count--)
  227.     {
  228.       val = (*p * snd_vol) >> 8;
  229.       p+= step;
  230.       if (val > 0x7fff)
  231.         val = 0x7fff;
  232.       else if (val < (short)0x8000)
  233.         val = (short)0x8000;
  234.       out[out_idx] = (val>>8) + 128;
  235.       out_idx = (out_idx + 1) & out_mask;
  236.     }
  237.   }
  238.  
  239. #ifdef _WIN32
  240.   if (pDSBuf) {
  241.     DWORD dwNewpos, dwWrite;
  242.     int il = paintedtime;
  243.     int ir = endtime - paintedtime;
  244.     
  245.     ir += il;
  246.  
  247.     pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  248.  
  249.     pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
  250.  
  251. //    if ((dwNewpos >= il) && (dwNewpos <= ir))
  252. //      Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
  253.   }
  254. #endif
  255. }
  256. #endif /* AMIGA */
  257.  
  258.  
  259. /*
  260. ===============================================================================
  261.  
  262. CHANNEL MIXING
  263.  
  264. ===============================================================================
  265. */
  266.  
  267. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
  268. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
  269.  
  270. void S_PaintChannels(int endtime)
  271. {
  272.   int   i;
  273.   int   end;
  274.   channel_t *ch;
  275.   sfxcache_t  *sc;
  276.   int   ltime, count;
  277.  
  278.   while (paintedtime < endtime)
  279.   {
  280.   // if paintbuffer is smaller than DMA buffer
  281.     end = endtime;
  282.     if (endtime - paintedtime > PAINTBUFFER_SIZE)
  283.       end = paintedtime + PAINTBUFFER_SIZE;
  284.  
  285.   // clear the paint buffer
  286.     Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  287.  
  288.   // paint in the channels.
  289.     ch = channels;
  290.     for (i=0; i<total_channels ; i++, ch++)
  291.     {
  292.       if (!ch->sfx)
  293.         continue;
  294.       if (!ch->leftvol && !ch->rightvol)
  295.         continue;
  296.       sc = S_LoadSound (ch->sfx);
  297.       if (!sc)
  298.         continue;
  299.  
  300.       ltime = paintedtime;
  301.  
  302.       while (ltime < end)
  303.       { // paint up to end
  304.         if (ch->end < end)
  305.           count = ch->end - ltime;
  306.         else
  307.           count = end - ltime;
  308.  
  309.         if (count > 0)
  310.         { 
  311.           if (sc->width == 1)
  312.             SND_PaintChannelFrom8(ch, sc, count);
  313.           else
  314.             SND_PaintChannelFrom16(ch, sc, count);
  315.   
  316.           ltime += count;
  317.         }
  318.  
  319.       // if at end of loop, restart
  320.         if (ltime >= ch->end)
  321.         {
  322.           if (sc->loopstart >= 0)
  323.           {
  324.             ch->pos = sc->loopstart;
  325.             ch->end = ltime + sc->length - ch->pos;
  326.           }
  327.           else        
  328.           { // channel just stopped
  329.             ch->sfx = NULL;
  330.             break;
  331.           }
  332.         }
  333.       }
  334.                                 
  335.     }
  336.  
  337.   // transfer out according to DMA format
  338.     S_TransferPaintBuffer(end);
  339.     paintedtime = end;
  340.   }
  341. }
  342.  
  343. void SND_InitScaletable (void)
  344. {
  345.   int   i, j;
  346.   
  347.   for (i=0 ; i<32 ; i++)
  348.     for (j=0 ; j<256 ; j++)
  349.       snd_scaletable[i][j] = ((signed char)j) * i * 8;
  350. }
  351.  
  352.  
  353. #if !id386
  354.  
  355. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
  356. {
  357.   int   data;
  358.   int   *lscale, *rscale;
  359.   unsigned char *sfx;
  360.   int   i;
  361.  
  362.   if (ch->leftvol > 255)
  363.     ch->leftvol = 255;
  364.   if (ch->rightvol > 255)
  365.     ch->rightvol = 255;
  366.     
  367.   lscale = snd_scaletable[ch->leftvol >> 3];
  368.   rscale = snd_scaletable[ch->rightvol >> 3];
  369.   sfx = (signed char *)sc->data + ch->pos;
  370.  
  371.   for (i=0 ; i<count ; i++)
  372.   {
  373.     data = sfx[i];
  374.     paintbuffer[i].left += lscale[data];
  375.     paintbuffer[i].right += rscale[data];
  376.   }
  377.   
  378.   ch->pos += count;
  379. }
  380.  
  381. #endif  // !id386
  382.  
  383.  
  384. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
  385. {
  386.   int data;
  387.   int left, right;
  388.   int leftvol, rightvol;
  389.   signed short *sfx;
  390.   int i;
  391.  
  392.   leftvol = ch->leftvol;
  393.   rightvol = ch->rightvol;
  394.   sfx = (signed short *)sc->data + ch->pos;
  395.  
  396.   for (i=0 ; i<count ; i++)
  397.   {
  398.     data = sfx[i];
  399.     left = (data * leftvol) >> 8;
  400.     right = (data * rightvol) >> 8;
  401.     paintbuffer[i].left += left;
  402.     paintbuffer[i].right += right;
  403.   }
  404.  
  405.   ch->pos += count;
  406. }
  407.  
  408. #ifdef __060__
  409. #define AMIGA
  410. #endif
  411.