Subversion Repositories Kolibri OS

Rev

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_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.