Advertisement
Guest User

Untitled

a guest
Sep 25th, 2016
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. #include "includes.h"
  3.  
  4. struct SSfxData
  5. {
  6.     u8*     buf;
  7.     u32     len;
  8. };
  9.  
  10. struct SSfxGene
  11. {
  12.     u8              nInit;      // Son initialisé (1) ou pas (0).
  13.  
  14.     HWAVEOUT        hWaveOut;
  15.     LPWAVEHDR       lpWaveHdr;
  16.     u8              *lpData;
  17.  
  18.     SSfxData        pSfxData[e_Sfx_LAST];
  19.     u8              bNeedRestart;
  20.  
  21.     wav_channel_t   wav_channel[NUM_CHANNELS];
  22.     int             snd_sent, snd_completed, snd_mixed;
  23.     int             sample16;
  24. };
  25.  
  26. struct SSfxGene gSfx;
  27.  
  28. // Sound, initialisation. A appeler 1 fois.
  29. void Sfx_SoundInit(void)
  30. {
  31.     WAVEFORMATEX    format;
  32.     HRESULT         hr;
  33.     DWORD           sndBufSize, i;
  34.  
  35.     Sfx_SoundDeInit();
  36.  
  37.     // Set 16-bit stereo audio at 22Khz.
  38.     memset (&format, 0, sizeof(format));
  39.     format.wFormatTag       = WAVE_FORMAT_PCM;
  40.     format.nChannels        = 2;
  41.     format.wBitsPerSample   = 16;
  42.     format.nSamplesPerSec   = 22050;
  43.     format.nBlockAlign      = format.nChannels*format.wBitsPerSample / 8;
  44.     format.cbSize           = 0;
  45.     format.nAvgBytesPerSec  = format.nSamplesPerSec*format.nBlockAlign;
  46.  
  47.     // Open a waveform device for output using window callback.
  48.     hr = waveOutOpen((LPHWAVEOUT)&gSfx.hWaveOut, WAVE_MAPPER,
  49.             &format, 0, 0L, CALLBACK_NULL);
  50.  
  51.     if (hr != MMSYSERR_NOERROR)
  52.         return;
  53.  
  54.     // Allocating waveform buffer.
  55.     sndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
  56.     gSfx.lpData = (u8*)malloc(sndBufSize);
  57.     if (gSfx.lpData == NULL) {
  58.         Sfx_SoundDeInit();
  59.         return;
  60.     }
  61.  
  62.     memset(gSfx.lpData, 0, sndBufSize);
  63.  
  64.     /*
  65.      * Allocate memory for the header
  66.      */
  67.  
  68.     gSfx.lpWaveHdr = (LPWAVEHDR)malloc((DWORD)sizeof(WAVEHDR) * WAV_BUFFERS);
  69.     if (gSfx.lpWaveHdr == NULL) {
  70.         Sfx_SoundDeInit();
  71.         return;
  72.     }
  73.  
  74.     memset(gSfx.lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
  75.  
  76.     // After allocation, set up and prepare headers.
  77.     for (i = 0; i < WAV_BUFFERS; i++) {
  78.         gSfx.lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
  79.         gSfx.lpWaveHdr[i].lpData = (LPSTR)(gSfx.lpData + i*WAV_BUFFER_SIZE);
  80.  
  81.         if (waveOutPrepareHeader(gSfx.hWaveOut, &gSfx.lpWaveHdr[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
  82.             Sfx_SoundDeInit();
  83.             return;
  84.         }
  85.     }
  86.  
  87.     gSfx.bNeedRestart = TRUE;
  88.     gSfx.nInit = TRUE;
  89.     gSfx.sample16 = 1;
  90.  
  91.     for (i = 0; i < NUM_CHANNELS; i++)
  92.         Sfx_ResetChannel(i);
  93. }
  94.  
  95. void Sfx_SoundDeInit(void)
  96. {
  97.     // Shutting down sound system
  98.     if (gSfx.hWaveOut) {
  99.         waveOutReset(gSfx.hWaveOut);
  100.  
  101.         if (gSfx.lpWaveHdr) {
  102.             for (int i = 0; i < WAV_BUFFERS; i++)
  103.                 waveOutUnprepareHeader(gSfx.hWaveOut, gSfx.lpWaveHdr+i, sizeof(WAVEHDR));
  104.         }
  105.  
  106.         waveOutClose(gSfx.hWaveOut);
  107.  
  108.         if (gSfx.lpWaveHdr)
  109.             free(gSfx.lpWaveHdr);
  110.  
  111.         if (gSfx.lpData)
  112.             free(gSfx.lpData);
  113.     }
  114.  
  115.     gSfx.snd_sent = 0;
  116.     gSfx.snd_completed = 0;
  117.     gSfx.snd_mixed = 0;
  118.     gSfx.sample16 = 0;
  119.  
  120.     gSfx.hWaveOut = NULL;
  121.     gSfx.lpData = NULL;
  122.     gSfx.lpWaveHdr = NULL;
  123.  
  124.     gSfx.nInit = FALSE;
  125. }
  126.  
  127. // Chargement de tous les fichiers WAV.
  128. void Sfx_LoadWavFiles(LPCWSTR curPath)
  129. {
  130.     WCHAR   path[MAX_PATH];
  131.     HANDLE  hFile;
  132.     DWORD   i, size, readBytes = 0;
  133.  
  134.     LPCWSTR pSfxFilenames[e_Sfx_LAST] = {
  135.         L"sfx\\_pill_bonus.wav", L"sfx\\_pill_malus.wav", L"sfx\\_shot.wav", L"sfx\\_door_through.wav",
  136.         L"sfx\\_menu_click.wav", L"sfx\\_brick_bounce.wav", L"sfx\\_ball_bounce.wav", L"sfx\\_explosion1.wav",
  137.         L"sfx\\_explosion2.wav", L"sfx\\_brick_dissolve.wav", L"sfx\\_extra_life.wav", L"sfx\\_bat_ping.wav",
  138.         L"sfx\\_bat_magnet.wav",
  139.     };
  140.  
  141.     if (!gSfx.nInit)
  142.         return;
  143.  
  144.     for (i = 0; i < e_Sfx_LAST; i++) {
  145.         // Load the sound file and convert it to 16-bit stereo at 22kHz
  146.         swprintf_s(path, MAX_PATH, L"%s\\%s", curPath, pSfxFilenames[i]);
  147.  
  148.         hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  149.         if (hFile == NULL || (size = GetFileSize(hFile, NULL)) < 0x2c) {
  150.             WriteDebug(L"Couldn't load %s: %d\n", pSfxFilenames[i], GetLastError());
  151.             return;
  152.         }
  153.  
  154.         size -= 0x2C;
  155.         SetFilePointer(hFile, 0x2C, 0, FILE_BEGIN);
  156.  
  157.         gSfx.pSfxData[i].len = size;
  158.         gSfx.pSfxData[i].buf = (u8*)malloc(size);
  159.         ReadFile(hFile, gSfx.pSfxData[i].buf, size, &readBytes, NULL);
  160.         CloseHandle(hFile);
  161.     }
  162. }
  163.  
  164. // Libère les ressources occupées par les fichiers WAV.
  165. void Sfx_FreeWavFiles(void)
  166. {
  167.     if (!gSfx.nInit)
  168.         return;
  169.  
  170.     for (int i = 0; i < e_Sfx_LAST; i++)
  171.         free(gSfx.pSfxData[i].buf);
  172. }
  173.  
  174.  
  175. // Joue un son.
  176. // Le minimum :
  177. // On commence par chercher un canal vide.
  178. // Si il n'y en a pas, on note celui qui à la priorité la plus faible.
  179. // Si plusieurs ont la même priorité, on note celui qui est le plus proche de la fin.
  180. // Enfin, si la prio du son à jouer est ok, on le joue dans le canal noté.
  181. void Sfx_AddSfx(u32 nSfxNo, u32 nSfxPrio)
  182. {
  183.     u32 index;
  184.  
  185.     u8  nPrioMinVal = 255;
  186.     u32 nPrioMinPos = 0;
  187.     u32 nPrioMinDiff = (u32)-1;
  188.  
  189.     if (nSfxNo < 0 || nSfxNo >= e_Sfx_LAST)
  190.         return;
  191.  
  192.     // Look for an empty (or finished) sound slot.
  193.     for (index = 0; index < NUM_CHANNELS; index++) {
  194.         if (gSfx.wav_channel[index].status == wav_idle)
  195.             break;
  196.         else if (gSfx.wav_channel[index].data == gSfx.pSfxData[nSfxNo].buf)
  197.             if (gSfx.wav_channel[index].position == 0)
  198.                 return;
  199.        
  200.         if (gSfx.wav_channel[index].prio < nPrioMinVal) {
  201.             nPrioMinVal = gSfx.wav_channel[index].prio;
  202.             nPrioMinPos = index;
  203.             nPrioMinDiff = gSfx.wav_channel[index].position;
  204.         } else if (gSfx.wav_channel[index].prio == nPrioMinVal) {
  205.             if (gSfx.wav_channel[index].position < nPrioMinDiff) {
  206.                 //nPrioMinVal = sounds[index].nPrio;
  207.                 nPrioMinPos = index;
  208.                 nPrioMinDiff = gSfx.wav_channel[index].position;
  209.             }
  210.         }
  211.     }
  212.  
  213.     // On a trouvé un emplacement libre ?
  214.     if (index == NUM_CHANNELS) {
  215.         // Non, la prio demandée est > ou == à la prio mini en cours ?
  216.         if (nSfxPrio < nPrioMinVal)
  217.             return;
  218.  
  219.         index = nPrioMinPos;
  220.     }
  221.  
  222.     // Put the sound data in the slot (it starts playing immediately).
  223.     gSfx.wav_channel[index].data = gSfx.pSfxData[nSfxNo].buf;
  224.     gSfx.wav_channel[index].position = 0;
  225.     gSfx.wav_channel[index].length = gSfx.pSfxData[nSfxNo].len;
  226.     gSfx.wav_channel[index].prio = (u8)nSfxPrio;
  227.     gSfx.wav_channel[index].status = wav_playing;
  228. }
  229.  
  230. // This function clears a "slot" and makes it ready for another sound
  231. void Sfx_ResetChannel(int slot)
  232. {
  233.     gSfx.wav_channel[slot].status = wav_idle;
  234.     gSfx.wav_channel[slot].position = 0;
  235.     gSfx.wav_channel[slot].length = 0;
  236.     gSfx.wav_channel[slot].data = 0;
  237.     gSfx.wav_channel[slot].prio = 0;
  238. }
  239.  
  240. void CheckSoundBuffers(void)
  241. {
  242.     while (1) {
  243.         if (gSfx.snd_completed == gSfx.snd_sent)
  244.             break;
  245.  
  246.         if (!(gSfx.lpWaveHdr[gSfx.snd_completed & WAV_MASK].dwFlags & WHDR_DONE))
  247.             break;
  248.  
  249.         gSfx.snd_completed++;   // this buffer has been played
  250.     }
  251. }
  252.  
  253. short MixSample16(int a, int b)
  254. {
  255.     int m = 0;
  256.     a += 32768;
  257.     b += 32768;
  258.  
  259.     // Pick the equation
  260.     if ((a < 32768) || (b < 32768)) {
  261.         // Viktor's first equation when both sources are "quiet"
  262.         // (i.e. less than middle of the dynamic range)
  263.         m = a * b / 32768;
  264.     } else {
  265.         // Viktor's second equation when one or both sources are loud
  266.         m = 2 * (a + b) - (a * b) / 32768 - 65536;
  267.     }
  268.  
  269.     // Output is unsigned (0..65536) so convert back to signed (-32768..32767)
  270.     if (m > 65535) m = 65535;
  271.  
  272.     return (short)(m - 32768);
  273. }
  274.  
  275. void Sfx_PrepareSoundBuffers(void)
  276. {
  277.     // Mixing channel index.
  278.     int             chan;
  279.  
  280.     // These are for using the waveOut mixing buffers
  281.     int             buff_filled, buff_avail;
  282.     int             sound_pending = 0;
  283.     int             sampcnt;
  284.     short           *buffout;
  285.  
  286.     if (!gSfx.nInit)
  287.         return;
  288.  
  289.     // Look for sounds that need to be played
  290.     for (chan = 0; chan < NUM_CHANNELS; chan++ ) {
  291.         // BAL - a status variable would be MUCH better (idle v playing)
  292.         // Check if channel is active. (has a data pointer)
  293.         if (gSfx.wav_channel[chan].status == wav_playing) {
  294.             // found one waiting, increase the counter
  295.             sound_pending++;
  296.         }
  297.     }
  298.  
  299.     // If no sounds to mix then jump out
  300.     if (sound_pending == 0)
  301.         return;
  302.  
  303.     // See if any sound buffers have been finished and returned
  304.     CheckSoundBuffers();
  305.  
  306.     buff_filled = 0;
  307.     buff_avail = BUFF_AHEAD-(gSfx.snd_sent-gSfx.snd_completed);
  308.     sampcnt = WAV_BUFFER_SIZE/SAMPLESIZE;
  309.  
  310.     // Need another loop here to handle all the buffers and the sound pending flag
  311.     while ((buff_filled < buff_avail) && (sound_pending > 0)) {
  312.         // Setup the output buffer using one of the waveOut buffers
  313.         buffout = (short*)gSfx.lpWaveHdr[(gSfx.snd_sent+buff_filled)&WAV_MASK].lpData;
  314.         memset(buffout, 0, WAV_BUFFER_SIZE);  // clear the buffer section to silence
  315.        
  316.         for (int i = 0; ((i < sampcnt) && (sound_pending > 0)); i += 2) {
  317.             for (chan = 0; chan < NUM_CHANNELS; chan++) {
  318.                 // Check channel, if active.
  319.                 if (gSfx.wav_channel[chan].status == wav_playing) {
  320.                     // left
  321.                     buffout[i] = MixSample16(buffout[i],
  322.                         *((short*)&gSfx.wav_channel[chan].data[gSfx.wav_channel[chan].position]));
  323.                    
  324.                     // right
  325.                     buffout[i+1] = MixSample16(buffout[i+1],
  326.                         *((short*)&gSfx.wav_channel[chan].data[gSfx.wav_channel[chan].position+2]));
  327.  
  328.                     // take the high word of the value, shift it down and add to the position
  329.                     gSfx.wav_channel[chan].position += 4;
  330.  
  331.                     // Is this sound finished?
  332.                     if (gSfx.wav_channel[chan].position >= gSfx.wav_channel[chan].length) {
  333.                         Sfx_ResetChannel(chan);
  334.                         sound_pending--;
  335.                     }
  336.                 }
  337.             }
  338.         }
  339.  
  340.         buff_filled++;
  341.         gSfx.snd_mixed++;
  342.     }
  343. }
  344.  
  345. void Sfx_SubmitSoundBuffers()
  346. {
  347.     if (!gSfx.nInit)
  348.         return;
  349.  
  350.     //
  351.     // submit a few new sound blocks
  352.     //
  353.     if (gSfx.snd_sent == gSfx.snd_completed) {
  354.         gSfx.bNeedRestart = TRUE;
  355.         waveOutPause(gSfx.hWaveOut);
  356.     }
  357.    
  358.     while (((gSfx.snd_sent - gSfx.snd_completed) >> gSfx.sample16) < BUFF_AHEAD) {
  359.         if (gSfx.snd_mixed <= gSfx.snd_sent)
  360.             break;
  361.  
  362.         /*
  363.          * Now the data block can be sent to the output device. The
  364.          * waveOutWrite function returns immediately and waveform
  365.          * data is sent to the output device in the background.
  366.          */
  367.         int wResult = waveOutWrite(gSfx.hWaveOut,
  368.             &gSfx.lpWaveHdr[gSfx.snd_sent & WAV_MASK], sizeof(WAVEHDR));
  369.         gSfx.snd_sent++;
  370.  
  371.         if (wResult != MMSYSERR_NOERROR) {
  372.             Sfx_SoundDeInit();
  373.             return;
  374.         }
  375.     }
  376.  
  377.     if (gSfx.bNeedRestart) {
  378.         waveOutRestart(gSfx.hWaveOut);
  379.         gSfx.bNeedRestart = FALSE;
  380.     }
  381. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement