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