Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "includes.h"
- struct SSfxData
- {
- u8* buf;
- u32 len;
- };
- struct SSfxGene
- {
- u8 nInit; // Son initialisé (1) ou pas (0).
- HWAVEOUT hWaveOut;
- LPWAVEHDR lpWaveHdr;
- u8 *lpData;
- SSfxData pSfxData[e_Sfx_LAST];
- u8 bNeedRestart;
- wav_channel_t wav_channel[NUM_CHANNELS];
- int snd_sent, snd_completed, snd_mixed;
- int sample16;
- };
- struct SSfxGene gSfx;
- // Sound, initialisation. A appeler 1 fois.
- void Sfx_SoundInit(void)
- {
- WAVEFORMATEX format;
- HRESULT hr;
- DWORD sndBufSize, i;
- Sfx_SoundDeInit();
- // Set 16-bit stereo audio at 22Khz.
- memset (&format, 0, sizeof(format));
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = 2;
- format.wBitsPerSample = 16;
- format.nSamplesPerSec = 22050;
- format.nBlockAlign = format.nChannels*format.wBitsPerSample / 8;
- format.cbSize = 0;
- format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign;
- // Open a waveform device for output using window callback.
- hr = waveOutOpen((LPHWAVEOUT)&gSfx.hWaveOut, WAVE_MAPPER,
- &format, 0, 0L, CALLBACK_NULL);
- if (hr != MMSYSERR_NOERROR)
- return;
- // Allocating waveform buffer.
- sndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
- gSfx.lpData = (u8*)malloc(sndBufSize);
- if (gSfx.lpData == NULL) {
- Sfx_SoundDeInit();
- return;
- }
- memset(gSfx.lpData, 0, sndBufSize);
- /*
- * Allocate memory for the header
- */
- gSfx.lpWaveHdr = (LPWAVEHDR)malloc((DWORD)sizeof(WAVEHDR) * WAV_BUFFERS);
- if (gSfx.lpWaveHdr == NULL) {
- Sfx_SoundDeInit();
- return;
- }
- memset(gSfx.lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
- // After allocation, set up and prepare headers.
- for (i = 0; i < WAV_BUFFERS; i++) {
- gSfx.lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
- gSfx.lpWaveHdr[i].lpData = (LPSTR)(gSfx.lpData + i*WAV_BUFFER_SIZE);
- if (waveOutPrepareHeader(gSfx.hWaveOut, &gSfx.lpWaveHdr[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
- Sfx_SoundDeInit();
- return;
- }
- }
- gSfx.bNeedRestart = TRUE;
- gSfx.nInit = TRUE;
- gSfx.sample16 = 1;
- for (i = 0; i < NUM_CHANNELS; i++)
- Sfx_ResetChannel(i);
- }
- void Sfx_SoundDeInit(void)
- {
- // Shutting down sound system
- if (gSfx.hWaveOut) {
- waveOutReset(gSfx.hWaveOut);
- if (gSfx.lpWaveHdr) {
- for (int i = 0; i < WAV_BUFFERS; i++)
- waveOutUnprepareHeader(gSfx.hWaveOut, gSfx.lpWaveHdr+i, sizeof(WAVEHDR));
- }
- waveOutClose(gSfx.hWaveOut);
- if (gSfx.lpWaveHdr)
- free(gSfx.lpWaveHdr);
- if (gSfx.lpData)
- free(gSfx.lpData);
- }
- gSfx.snd_sent = 0;
- gSfx.snd_completed = 0;
- gSfx.snd_mixed = 0;
- gSfx.sample16 = 0;
- gSfx.hWaveOut = NULL;
- gSfx.lpData = NULL;
- gSfx.lpWaveHdr = NULL;
- gSfx.nInit = FALSE;
- }
- // Chargement de tous les fichiers WAV.
- void Sfx_LoadWavFiles(LPCWSTR curPath)
- {
- WCHAR path[MAX_PATH];
- HANDLE hFile;
- DWORD i, size, readBytes = 0;
- LPCWSTR pSfxFilenames[e_Sfx_LAST] = {
- L"sfx\\_pill_bonus.wav", L"sfx\\_pill_malus.wav", L"sfx\\_shot.wav", L"sfx\\_door_through.wav",
- L"sfx\\_menu_click.wav", L"sfx\\_brick_bounce.wav", L"sfx\\_ball_bounce.wav", L"sfx\\_explosion1.wav",
- L"sfx\\_explosion2.wav", L"sfx\\_brick_dissolve.wav", L"sfx\\_extra_life.wav", L"sfx\\_bat_ping.wav",
- L"sfx\\_bat_magnet.wav",
- };
- if (!gSfx.nInit)
- return;
- for (i = 0; i < e_Sfx_LAST; i++) {
- // Load the sound file and convert it to 16-bit stereo at 22kHz
- swprintf_s(path, MAX_PATH, L"%s\\%s", curPath, pSfxFilenames[i]);
- hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == NULL || (size = GetFileSize(hFile, NULL)) < 0x2c) {
- WriteDebug(L"Couldn't load %s: %d\n", pSfxFilenames[i], GetLastError());
- return;
- }
- size -= 0x2C;
- SetFilePointer(hFile, 0x2C, 0, FILE_BEGIN);
- gSfx.pSfxData[i].len = size;
- gSfx.pSfxData[i].buf = (u8*)malloc(size);
- ReadFile(hFile, gSfx.pSfxData[i].buf, size, &readBytes, NULL);
- CloseHandle(hFile);
- }
- }
- // Libère les ressources occupées par les fichiers WAV.
- void Sfx_FreeWavFiles(void)
- {
- if (!gSfx.nInit)
- return;
- for (int i = 0; i < e_Sfx_LAST; i++)
- free(gSfx.pSfxData[i].buf);
- }
- // Joue un son.
- // Le minimum :
- // On commence par chercher un canal vide.
- // Si il n'y en a pas, on note celui qui à la priorité la plus faible.
- // Si plusieurs ont la même priorité, on note celui qui est le plus proche de la fin.
- // Enfin, si la prio du son à jouer est ok, on le joue dans le canal noté.
- void Sfx_AddSfx(u32 nSfxNo, u32 nSfxPrio)
- {
- u32 index;
- u8 nPrioMinVal = 255;
- u32 nPrioMinPos = 0;
- u32 nPrioMinDiff = (u32)-1;
- if (nSfxNo < 0 || nSfxNo >= e_Sfx_LAST)
- return;
- // Look for an empty (or finished) sound slot.
- for (index = 0; index < NUM_CHANNELS; index++) {
- if (gSfx.wav_channel[index].status == wav_idle)
- break;
- else if (gSfx.wav_channel[index].data == gSfx.pSfxData[nSfxNo].buf)
- if (gSfx.wav_channel[index].position == 0)
- return;
- if (gSfx.wav_channel[index].prio < nPrioMinVal) {
- nPrioMinVal = gSfx.wav_channel[index].prio;
- nPrioMinPos = index;
- nPrioMinDiff = gSfx.wav_channel[index].position;
- } else if (gSfx.wav_channel[index].prio == nPrioMinVal) {
- if (gSfx.wav_channel[index].position < nPrioMinDiff) {
- //nPrioMinVal = sounds[index].nPrio;
- nPrioMinPos = index;
- nPrioMinDiff = gSfx.wav_channel[index].position;
- }
- }
- }
- // On a trouvé un emplacement libre ?
- if (index == NUM_CHANNELS) {
- // Non, la prio demandée est > ou == à la prio mini en cours ?
- if (nSfxPrio < nPrioMinVal)
- return;
- index = nPrioMinPos;
- }
- // Put the sound data in the slot (it starts playing immediately).
- gSfx.wav_channel[index].data = gSfx.pSfxData[nSfxNo].buf;
- gSfx.wav_channel[index].position = 0;
- gSfx.wav_channel[index].length = gSfx.pSfxData[nSfxNo].len;
- gSfx.wav_channel[index].prio = (u8)nSfxPrio;
- gSfx.wav_channel[index].status = wav_playing;
- }
- // This function clears a "slot" and makes it ready for another sound
- void Sfx_ResetChannel(int slot)
- {
- gSfx.wav_channel[slot].status = wav_idle;
- gSfx.wav_channel[slot].position = 0;
- gSfx.wav_channel[slot].length = 0;
- gSfx.wav_channel[slot].data = 0;
- gSfx.wav_channel[slot].prio = 0;
- }
- void CheckSoundBuffers(void)
- {
- while (1) {
- if (gSfx.snd_completed == gSfx.snd_sent)
- break;
- if (!(gSfx.lpWaveHdr[gSfx.snd_completed & WAV_MASK].dwFlags & WHDR_DONE))
- break;
- gSfx.snd_completed++; // this buffer has been played
- }
- }
- short MixSample16(int a, int b)
- {
- int m = 0;
- a += 32768;
- b += 32768;
- // Pick the equation
- if ((a < 32768) || (b < 32768)) {
- // Viktor's first equation when both sources are "quiet"
- // (i.e. less than middle of the dynamic range)
- m = a * b / 32768;
- } else {
- // Viktor's second equation when one or both sources are loud
- m = 2 * (a + b) - (a * b) / 32768 - 65536;
- }
- // Output is unsigned (0..65536) so convert back to signed (-32768..32767)
- if (m > 65535) m = 65535;
- return (short)(m - 32768);
- }
- void Sfx_PrepareSoundBuffers(void)
- {
- // Mixing channel index.
- int chan;
- // These are for using the waveOut mixing buffers
- int buff_filled, buff_avail;
- int sound_pending = 0;
- int sampcnt;
- short *buffout;
- if (!gSfx.nInit)
- return;
- // Look for sounds that need to be played
- for (chan = 0; chan < NUM_CHANNELS; chan++ ) {
- // BAL - a status variable would be MUCH better (idle v playing)
- // Check if channel is active. (has a data pointer)
- if (gSfx.wav_channel[chan].status == wav_playing) {
- // found one waiting, increase the counter
- sound_pending++;
- }
- }
- // If no sounds to mix then jump out
- if (sound_pending == 0)
- return;
- // See if any sound buffers have been finished and returned
- CheckSoundBuffers();
- buff_filled = 0;
- buff_avail = BUFF_AHEAD-(gSfx.snd_sent-gSfx.snd_completed);
- sampcnt = WAV_BUFFER_SIZE/SAMPLESIZE;
- // Need another loop here to handle all the buffers and the sound pending flag
- while ((buff_filled < buff_avail) && (sound_pending > 0)) {
- // Setup the output buffer using one of the waveOut buffers
- buffout = (short*)gSfx.lpWaveHdr[(gSfx.snd_sent+buff_filled)&WAV_MASK].lpData;
- memset(buffout, 0, WAV_BUFFER_SIZE); // clear the buffer section to silence
- for (int i = 0; ((i < sampcnt) && (sound_pending > 0)); i += 2) {
- for (chan = 0; chan < NUM_CHANNELS; chan++) {
- // Check channel, if active.
- if (gSfx.wav_channel[chan].status == wav_playing) {
- // left
- buffout[i] = MixSample16(buffout[i],
- *((short*)&gSfx.wav_channel[chan].data[gSfx.wav_channel[chan].position]));
- // right
- buffout[i+1] = MixSample16(buffout[i+1],
- *((short*)&gSfx.wav_channel[chan].data[gSfx.wav_channel[chan].position+2]));
- // take the high word of the value, shift it down and add to the position
- gSfx.wav_channel[chan].position += 4;
- // Is this sound finished?
- if (gSfx.wav_channel[chan].position >= gSfx.wav_channel[chan].length) {
- Sfx_ResetChannel(chan);
- sound_pending--;
- }
- }
- }
- }
- buff_filled++;
- gSfx.snd_mixed++;
- }
- }
- void Sfx_SubmitSoundBuffers()
- {
- if (!gSfx.nInit)
- return;
- //
- // submit a few new sound blocks
- //
- if (gSfx.snd_sent == gSfx.snd_completed) {
- gSfx.bNeedRestart = TRUE;
- waveOutPause(gSfx.hWaveOut);
- }
- while (((gSfx.snd_sent - gSfx.snd_completed) >> gSfx.sample16) < BUFF_AHEAD) {
- if (gSfx.snd_mixed <= gSfx.snd_sent)
- break;
- /*
- * Now the data block can be sent to the output device. The
- * waveOutWrite function returns immediately and waveform
- * data is sent to the output device in the background.
- */
- int wResult = waveOutWrite(gSfx.hWaveOut,
- &gSfx.lpWaveHdr[gSfx.snd_sent & WAV_MASK], sizeof(WAVEHDR));
- gSfx.snd_sent++;
- if (wResult != MMSYSERR_NOERROR) {
- Sfx_SoundDeInit();
- return;
- }
- }
- if (gSfx.bNeedRestart) {
- waveOutRestart(gSfx.hWaveOut);
- gSfx.bNeedRestart = FALSE;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement