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. #include "quakedef.h"
  21. #include "winquake.h"
  22.  
  23. #define iDirectSoundCreate(a,b,c)       pDirectSoundCreate(a,b,c)
  24.  
  25. HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
  26.  
  27. // 64K is > 1 second at 16-bit, 22050 Hz
  28. #define WAV_BUFFERS                             64
  29. #define WAV_MASK                                0x3F
  30. #define WAV_BUFFER_SIZE                 0x0400
  31. #define SECONDARY_BUFFER_SIZE   0x10000
  32.  
  33. typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
  34.  
  35. static qboolean wavonly;
  36. static qboolean dsound_init;
  37. static qboolean wav_init;
  38. static qboolean snd_firsttime = true, snd_isdirect, snd_iswave;
  39. static qboolean primary_format_set;
  40.  
  41. static int      sample16;
  42. static int      snd_sent, snd_completed;
  43.  
  44.  
  45. /*
  46.  * Global variables. Must be visible to window-procedure function
  47.  *  so it can unlock and free the data block after it has been played.
  48.  */
  49.  
  50. HANDLE          hData;
  51. HPSTR           lpData, lpData2;
  52.  
  53. HGLOBAL         hWaveHdr;
  54. LPWAVEHDR       lpWaveHdr;
  55.  
  56. HWAVEOUT    hWaveOut;
  57.  
  58. WAVEOUTCAPS     wavecaps;
  59.  
  60. DWORD   gSndBufSize;
  61.  
  62. MMTIME          mmstarttime;
  63.  
  64. LPDIRECTSOUND pDS;
  65. LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
  66.  
  67. HINSTANCE hInstDS;
  68.  
  69. qboolean SNDDMA_InitDirect (void);
  70. qboolean SNDDMA_InitWav (void);
  71.  
  72.  
  73. /*
  74. ==================
  75. S_BlockSound
  76. ==================
  77. */
  78. void S_BlockSound (void)
  79. {
  80.  
  81. // DirectSound takes care of blocking itself
  82.         if (snd_iswave)
  83.         {
  84.                 snd_blocked++;
  85.  
  86.                 if (snd_blocked == 1)
  87.                 {
  88.                         waveOutReset (hWaveOut);
  89.                 }
  90.         }
  91. }
  92.  
  93.  
  94. /*
  95. ==================
  96. S_UnblockSound
  97. ==================
  98. */
  99. void S_UnblockSound (void)
  100. {
  101.  
  102. // DirectSound takes care of blocking itself
  103.         if (snd_iswave)
  104.         {
  105.                 snd_blocked--;
  106.         }
  107. }
  108.  
  109.  
  110. /*
  111. ==================
  112. FreeSound
  113. ==================
  114. */
  115. void FreeSound (void)
  116. {
  117.         int             i;
  118.  
  119.         if (pDSBuf)
  120.         {
  121.                 pDSBuf->lpVtbl->Stop(pDSBuf);
  122.                 pDSBuf->lpVtbl->Release(pDSBuf);
  123.         }
  124.  
  125. // only release primary buffer if it's not also the mixing buffer we just released
  126.         if (pDSPBuf && (pDSBuf != pDSPBuf))
  127.         {
  128.                 pDSPBuf->lpVtbl->Release(pDSPBuf);
  129.         }
  130.  
  131.         if (pDS)
  132.         {
  133.                 pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL);
  134.                 pDS->lpVtbl->Release(pDS);
  135.         }
  136.  
  137.         if (hWaveOut)
  138.         {
  139.                 waveOutReset (hWaveOut);
  140.  
  141.                 if (lpWaveHdr)
  142.                 {
  143.                         for (i=0 ; i< WAV_BUFFERS ; i++)
  144.                                 waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
  145.                 }
  146.  
  147.                 waveOutClose (hWaveOut);
  148.  
  149.                 if (hWaveHdr)
  150.                 {
  151.                         GlobalUnlock(hWaveHdr);
  152.                         GlobalFree(hWaveHdr);
  153.                 }
  154.  
  155.                 if (hData)
  156.                 {
  157.                         GlobalUnlock(hData);
  158.                         GlobalFree(hData);
  159.                 }
  160.  
  161.         }
  162.  
  163.         pDS = NULL;
  164.         pDSBuf = NULL;
  165.         pDSPBuf = NULL;
  166.         hWaveOut = 0;
  167.         hData = 0;
  168.         hWaveHdr = 0;
  169.         lpData = NULL;
  170.         lpWaveHdr = NULL;
  171.         dsound_init = false;
  172.         wav_init = false;
  173. }
  174.  
  175.  
  176. /*
  177. ==================
  178. SNDDMA_InitDirect
  179.  
  180. Direct-Sound support
  181. ==================
  182. */
  183. sndinitstat SNDDMA_InitDirect (void)
  184. {
  185.         DSBUFFERDESC    dsbuf;
  186.         DSBCAPS                 dsbcaps;
  187.         DWORD                   dwSize, dwWrite;
  188.         DSCAPS                  dscaps;
  189.         WAVEFORMATEX    format, pformat;
  190.         HRESULT                 hresult;
  191.         int                             reps;
  192.  
  193.         memset ((void *)&sn, 0, sizeof (sn));
  194.  
  195.         shm = &sn;
  196.  
  197.         shm->channels = 2;
  198.         shm->samplebits = 16;
  199.         shm->speed = 11025;
  200.  
  201.         memset (&format, 0, sizeof(format));
  202.         format.wFormatTag = WAVE_FORMAT_PCM;
  203.     format.nChannels = shm->channels;
  204.     format.wBitsPerSample = shm->samplebits;
  205.     format.nSamplesPerSec = shm->speed;
  206.     format.nBlockAlign = format.nChannels
  207.                 *format.wBitsPerSample / 8;
  208.     format.cbSize = 0;
  209.     format.nAvgBytesPerSec = format.nSamplesPerSec
  210.                 *format.nBlockAlign;
  211.  
  212.         if (!hInstDS)
  213.         {
  214.                 hInstDS = LoadLibrary("dsound.dll");
  215.                
  216.                 if (hInstDS == NULL)
  217.                 {
  218.                         Con_SafePrintf ("Couldn't load dsound.dll\n");
  219.                         return SIS_FAILURE;
  220.                 }
  221.  
  222.                 pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
  223.  
  224.                 if (!pDirectSoundCreate)
  225.                 {
  226.                         Con_SafePrintf ("Couldn't get DS proc addr\n");
  227.                         return SIS_FAILURE;
  228.                 }
  229.         }
  230.  
  231.         while ((hresult = iDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
  232.         {
  233.                 if (hresult != DSERR_ALLOCATED)
  234.                 {
  235.                         Con_SafePrintf ("DirectSound create failed\n");
  236.                         return SIS_FAILURE;
  237.                 }
  238.  
  239.                 if (MessageBox (NULL,
  240.                                                 "The sound hardware is in use by another app.\n\n"
  241.                                             "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
  242.                                                 "Sound not available",
  243.                                                 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
  244.                 {
  245.                         Con_SafePrintf ("DirectSoundCreate failure\n"
  246.                                                         "  hardware already in use\n");
  247.                         return SIS_NOTAVAIL;
  248.                 }
  249.         }
  250.  
  251.         dscaps.dwSize = sizeof(dscaps);
  252.  
  253.         if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps))
  254.         {
  255.                 Con_SafePrintf ("Couldn't get DS caps\n");
  256.         }
  257.  
  258.         if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
  259.         {
  260.                 Con_SafePrintf ("No DirectSound driver installed\n");
  261.                 FreeSound ();
  262.                 return SIS_FAILURE;
  263.         }
  264.  
  265.         if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE))
  266.         {
  267.                 Con_SafePrintf ("Set coop level failed\n");
  268.                 FreeSound ();
  269.                 return SIS_FAILURE;
  270.         }
  271.  
  272. // get access to the primary buffer, if possible, so we can set the
  273. // sound hardware format
  274.         memset (&dsbuf, 0, sizeof(dsbuf));
  275.         dsbuf.dwSize = sizeof(DSBUFFERDESC);
  276.         dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
  277.         dsbuf.dwBufferBytes = 0;
  278.         dsbuf.lpwfxFormat = NULL;
  279.  
  280.         memset(&dsbcaps, 0, sizeof(dsbcaps));
  281.         dsbcaps.dwSize = sizeof(dsbcaps);
  282.         primary_format_set = false;
  283.  
  284.         if (!COM_CheckParm ("-snoforceformat"))
  285.         {
  286.                 if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
  287.                 {
  288.                         pformat = format;
  289.  
  290.                         if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
  291.                         {
  292.                                 if (snd_firsttime)
  293.                                         Con_SafePrintf ("Set primary sound buffer format: no\n");
  294.                         }
  295.                         else
  296.                         {
  297.                                 if (snd_firsttime)
  298.                                         Con_SafePrintf ("Set primary sound buffer format: yes\n");
  299.  
  300.                                 primary_format_set = true;
  301.                         }
  302.                 }
  303.         }
  304.  
  305.         if (!primary_format_set || !COM_CheckParm ("-primarysound"))
  306.         {
  307.         // create the secondary buffer we'll actually work with
  308.                 memset (&dsbuf, 0, sizeof(dsbuf));
  309.                 dsbuf.dwSize = sizeof(DSBUFFERDESC);
  310.                 dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
  311.                 dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
  312.                 dsbuf.lpwfxFormat = &format;
  313.  
  314.                 memset(&dsbcaps, 0, sizeof(dsbcaps));
  315.                 dsbcaps.dwSize = sizeof(dsbcaps);
  316.  
  317.                 if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
  318.                 {
  319.                         Con_SafePrintf ("DS:CreateSoundBuffer Failed");
  320.                         FreeSound ();
  321.                         return SIS_FAILURE;
  322.                 }
  323.  
  324.                 shm->channels = format.nChannels;
  325.                 shm->samplebits = format.wBitsPerSample;
  326.                 shm->speed = format.nSamplesPerSec;
  327.  
  328.                 if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
  329.                 {
  330.                         Con_SafePrintf ("DS:GetCaps failed\n");
  331.                         FreeSound ();
  332.                         return SIS_FAILURE;
  333.                 }
  334.  
  335.                 if (snd_firsttime)
  336.                         Con_SafePrintf ("Using secondary sound buffer\n");
  337.         }
  338.         else
  339.         {
  340.                 if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY))
  341.                 {
  342.                         Con_SafePrintf ("Set coop level failed\n");
  343.                         FreeSound ();
  344.                         return SIS_FAILURE;
  345.                 }
  346.  
  347.                 if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
  348.                 {
  349.                         Con_Printf ("DS:GetCaps failed\n");
  350.                         return SIS_FAILURE;
  351.                 }
  352.  
  353.                 pDSBuf = pDSPBuf;
  354.                 Con_SafePrintf ("Using primary sound buffer\n");
  355.         }
  356.  
  357.         // Make sure mixer is active
  358.         pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
  359.  
  360.         if (snd_firsttime)
  361.                 Con_SafePrintf("   %d channel(s)\n"
  362.                                "   %d bits/sample\n"
  363.                                            "   %d bytes/sec\n",
  364.                                            shm->channels, shm->samplebits, shm->speed);
  365.        
  366.         gSndBufSize = dsbcaps.dwBufferBytes;
  367.  
  368. // initialize the buffer
  369.         reps = 0;
  370.  
  371.         while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  372.         {
  373.                 if (hresult != DSERR_BUFFERLOST)
  374.                 {
  375.                         Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n");
  376.                         FreeSound ();
  377.                         return SIS_FAILURE;
  378.                 }
  379.  
  380.                 if (++reps > 10000)
  381.                 {
  382.                         Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n");
  383.                         FreeSound ();
  384.                         return SIS_FAILURE;
  385.                 }
  386.  
  387.         }
  388.  
  389.         memset(lpData, 0, dwSize);
  390. //              lpData[4] = lpData[5] = 0x7f;   // force a pop for debugging
  391.  
  392.         pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0);
  393.  
  394.         /* we don't want anyone to access the buffer directly w/o locking it first. */
  395.         lpData = NULL;
  396.  
  397.         pDSBuf->lpVtbl->Stop(pDSBuf);
  398.         pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
  399.         pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
  400.  
  401.         shm->soundalive = true;
  402.         shm->splitbuffer = false;
  403.         shm->samples = gSndBufSize/(shm->samplebits/8);
  404.         shm->samplepos = 0;
  405.         shm->submission_chunk = 1;
  406.         shm->buffer = (unsigned char *) lpData;
  407.         sample16 = (shm->samplebits/8) - 1;
  408.  
  409.         dsound_init = true;
  410.  
  411.         return SIS_SUCCESS;
  412. }
  413.  
  414.  
  415. /*
  416. ==================
  417. SNDDM_InitWav
  418.  
  419. Crappy windows multimedia base
  420. ==================
  421. */
  422. qboolean SNDDMA_InitWav (void)
  423. {
  424.         WAVEFORMATEX  format;
  425.         int                             i;
  426.         HRESULT                 hr;
  427.        
  428.         snd_sent = 0;
  429.         snd_completed = 0;
  430.  
  431.         shm = &sn;
  432.  
  433.         shm->channels = 2;
  434.         shm->samplebits = 16;
  435.         shm->speed = 11025;
  436.  
  437.         memset (&format, 0, sizeof(format));
  438.         format.wFormatTag = WAVE_FORMAT_PCM;
  439.         format.nChannels = shm->channels;
  440.         format.wBitsPerSample = shm->samplebits;
  441.         format.nSamplesPerSec = shm->speed;
  442.         format.nBlockAlign = format.nChannels
  443.                 *format.wBitsPerSample / 8;
  444.         format.cbSize = 0;
  445.         format.nAvgBytesPerSec = format.nSamplesPerSec
  446.                 *format.nBlockAlign;
  447.        
  448.         /* Open a waveform device for output using window callback. */
  449.         while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
  450.                                         &format,
  451.                                         0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
  452.         {
  453.                 if (hr != MMSYSERR_ALLOCATED)
  454.                 {
  455.                         Con_SafePrintf ("waveOutOpen failed\n");
  456.                         return false;
  457.                 }
  458.  
  459.                 if (MessageBox (NULL,
  460.                                                 "The sound hardware is in use by another app.\n\n"
  461.                                             "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
  462.                                                 "Sound not available",
  463.                                                 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
  464.                 {
  465.                         Con_SafePrintf ("waveOutOpen failure;\n"
  466.                                                         "  hardware already in use\n");
  467.                         return false;
  468.                 }
  469.         }
  470.  
  471.         /*
  472.          * Allocate and lock memory for the waveform data. The memory
  473.          * for waveform data must be globally allocated with
  474.          * GMEM_MOVEABLE and GMEM_SHARE flags.
  475.  
  476.         */
  477.         gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
  478.         hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
  479.         if (!hData)
  480.         {
  481.                 Con_SafePrintf ("Sound: Out of memory.\n");
  482.                 FreeSound ();
  483.                 return false;
  484.         }
  485.         lpData = GlobalLock(hData);
  486.         if (!lpData)
  487.         {
  488.                 Con_SafePrintf ("Sound: Failed to lock.\n");
  489.                 FreeSound ();
  490.                 return false;
  491.         }
  492.         memset (lpData, 0, gSndBufSize);
  493.  
  494.         /*
  495.          * Allocate and lock memory for the header. This memory must
  496.          * also be globally allocated with GMEM_MOVEABLE and
  497.          * GMEM_SHARE flags.
  498.          */
  499.         hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  500.                 (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
  501.  
  502.         if (hWaveHdr == NULL)
  503.         {
  504.                 Con_SafePrintf ("Sound: Failed to Alloc header.\n");
  505.                 FreeSound ();
  506.                 return false;
  507.         }
  508.  
  509.         lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
  510.  
  511.         if (lpWaveHdr == NULL)
  512.         {
  513.                 Con_SafePrintf ("Sound: Failed to lock header.\n");
  514.                 FreeSound ();
  515.                 return false;
  516.         }
  517.  
  518.         memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
  519.  
  520.         /* After allocation, set up and prepare headers. */
  521.         for (i=0 ; i<WAV_BUFFERS ; i++)
  522.         {
  523.                 lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
  524.                 lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
  525.  
  526.                 if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
  527.                                 MMSYSERR_NOERROR)
  528.                 {
  529.                         Con_SafePrintf ("Sound: failed to prepare wave headers\n");
  530.                         FreeSound ();
  531.                         return false;
  532.                 }
  533.         }
  534.  
  535.         shm->soundalive = true;
  536.         shm->splitbuffer = false;
  537.         shm->samples = gSndBufSize/(shm->samplebits/8);
  538.         shm->samplepos = 0;
  539.         shm->submission_chunk = 1;
  540.         shm->buffer = (unsigned char *) lpData;
  541.         sample16 = (shm->samplebits/8) - 1;
  542.  
  543.         wav_init = true;
  544.  
  545.         return true;
  546. }
  547.  
  548. /*
  549. ==================
  550. SNDDMA_Init
  551.  
  552. Try to find a sound device to mix for.
  553. Returns false if nothing is found.
  554. ==================
  555. */
  556.  
  557. int SNDDMA_Init(void)
  558. {
  559.         sndinitstat     stat;
  560.  
  561.         if (COM_CheckParm ("-wavonly"))
  562.                 wavonly = true;
  563.  
  564.         dsound_init = wav_init = 0;
  565.  
  566.         stat = SIS_FAILURE;     // assume DirectSound won't initialize
  567.  
  568.         /* Init DirectSound */
  569.         if (!wavonly)
  570.         {
  571.                 if (snd_firsttime || snd_isdirect)
  572.                 {
  573.                         stat = SNDDMA_InitDirect ();;
  574.  
  575.                         if (stat == SIS_SUCCESS)
  576.                         {
  577.                                 snd_isdirect = true;
  578.  
  579.                                 if (snd_firsttime)
  580.                                         Con_SafePrintf ("DirectSound initialized\n");
  581.                         }
  582.                         else
  583.                         {
  584.                                 snd_isdirect = false;
  585.                                 Con_SafePrintf ("DirectSound failed to init\n");
  586.                         }
  587.                 }
  588.         }
  589.  
  590. // if DirectSound didn't succeed in initializing, try to initialize
  591. // waveOut sound, unless DirectSound failed because the hardware is
  592. // already allocated (in which case the user has already chosen not
  593. // to have sound)
  594.         if (!dsound_init && (stat != SIS_NOTAVAIL))
  595.         {
  596.                 if (snd_firsttime || snd_iswave)
  597.                 {
  598.  
  599.                         snd_iswave = SNDDMA_InitWav ();
  600.  
  601.                         if (snd_iswave)
  602.                         {
  603.                                 if (snd_firsttime)
  604.                                         Con_SafePrintf ("Wave sound initialized\n");
  605.                         }
  606.                         else
  607.                         {
  608.                                 Con_SafePrintf ("Wave sound failed to init\n");
  609.                         }
  610.                 }
  611.         }
  612.  
  613.         snd_firsttime = false;
  614.  
  615.         if (!dsound_init && !wav_init)
  616.         {
  617.                 if (snd_firsttime)
  618.                         Con_SafePrintf ("No sound device initialized\n");
  619.  
  620.                 return 0;
  621.         }
  622.  
  623.         return 1;
  624. }
  625.  
  626. /*
  627. ==============
  628. SNDDMA_GetDMAPos
  629.  
  630. return the current sample position (in mono samples read)
  631. inside the recirculating dma buffer, so the mixing code will know
  632. how many sample are required to fill it up.
  633. ===============
  634. */
  635. int SNDDMA_GetDMAPos(void)
  636. {
  637.         MMTIME  mmtime;
  638.         int             s;
  639.         DWORD   dwWrite;
  640.  
  641.         if (dsound_init)
  642.         {
  643.                 mmtime.wType = TIME_SAMPLES;
  644.                 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
  645.                 s = mmtime.u.sample - mmstarttime.u.sample;
  646.         }
  647.         else if (wav_init)
  648.         {
  649.                 s = snd_sent * WAV_BUFFER_SIZE;
  650.         }
  651.  
  652.  
  653.         s >>= sample16;
  654.  
  655.         s &= (shm->samples-1);
  656.  
  657.         return s;
  658. }
  659.  
  660. /*
  661. ==============
  662. SNDDMA_Submit
  663.  
  664. Send sound to device if buffer isn't really the dma buffer
  665. ===============
  666. */
  667. void SNDDMA_Submit(void)
  668. {
  669.         LPWAVEHDR       h;
  670.         int                     wResult;
  671.  
  672.         if (!wav_init)
  673.                 return;
  674.  
  675.         //
  676.         // find which sound blocks have completed
  677.         //
  678.         while (1)
  679.         {
  680.                 if ( snd_completed == snd_sent )
  681.                 {
  682.                         Con_DPrintf ("Sound overrun\n");
  683.                         break;
  684.                 }
  685.  
  686.                 if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
  687.                 {
  688.                         break;
  689.                 }
  690.  
  691.                 snd_completed++;        // this buffer has been played
  692.         }
  693.  
  694.         //
  695.         // submit two new sound blocks
  696.         //
  697.         while (((snd_sent - snd_completed) >> sample16) < 4)
  698.         {
  699.                 h = lpWaveHdr + ( snd_sent&WAV_MASK );
  700.  
  701.                 snd_sent++;
  702.                 /*
  703.                  * Now the data block can be sent to the output device. The
  704.                  * waveOutWrite function returns immediately and waveform
  705.                  * data is sent to the output device in the background.
  706.                  */
  707.                 wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR));
  708.  
  709.                 if (wResult != MMSYSERR_NOERROR)
  710.                 {
  711.                         Con_SafePrintf ("Failed to write block to device\n");
  712.                         FreeSound ();
  713.                         return;
  714.                 }
  715.         }
  716. }
  717.  
  718. /*
  719. ==============
  720. SNDDMA_Shutdown
  721.  
  722. Reset the sound device for exiting
  723. ===============
  724. */
  725. void SNDDMA_Shutdown(void)
  726. {
  727.         FreeSound ();
  728. }
  729.  
  730.