From 77f3f52e0d86c6add577ae581fb8b3ab0cc04b81 Mon Sep 17 00:00:00 2001 From: oz Date: Wed, 27 Jan 2021 18:50:24 +0300 Subject: [PATCH] WaveMix v4. --- Doc/FuncStats.xlsx | Bin 39390 -> 39409 bytes SpaceCadetPinball/WaveMix.cpp | 781 +++++++++++++++++++++++++++++++++- SpaceCadetPinball/WaveMix.h | 37 +- 3 files changed, 779 insertions(+), 39 deletions(-) diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 78ee3f0b5dfcc22f6a8dbd5fecd831f8c4634ff2..d957b4608bcce0b38f5c13a8b42cc3f24fa54861 100644 GIT binary patch delta 31296 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 delta 31226 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 MUl=fr;*bshA8GC~wMagic1 = 21554; globals->WaveBlockArray = nullptr; globals->SettingsDialogActiveFlag = 0; - globals->unknown44 = 655370; + globals->DefaultVolume.L = 10; + globals->DefaultVolume.R = 10; memset(globals->aChannel, 0xFFu, sizeof globals->aChannel); memmove(&globals->PCM, &gpFormat, 0x10u); if (!ReadConfigSettings(&mixConfig)) @@ -89,17 +90,99 @@ HANDLE WaveMix::ConfigureInit(MIXCONFIG* lpConfig) int WaveMix::CloseSession(HANDLE hMixSession) { + Globals = SessionToGlobalDataPtr(hMixSession); + if (!Globals) + return 5; + + Activate(hMixSession, false); + CloseChannel(hMixSession, 0, 1); + memset(Globals, 0, sizeof(GLOBALS)); + Globals = nullptr; + if (!hMixSession || !LocalFree(hMixSession)) + return 5; + return 0; } int WaveMix::OpenChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) { + GLOBALS* globals = SessionToGlobalDataPtr(hMixSession); + Globals = globals; + if (!globals) + return 5; + if (dwFlags > 2) + return 10; + if (dwFlags == 2 && (iChannel > 16 || iChannel < 1)) + return 11; + if (dwFlags == 0 && iChannel >= 16) + return 11; + + if (dwFlags) + { + if (dwFlags == 1) + iChannel = 16; + + for (auto index = iChannel - 1; index >= 0; --index) + { + if (globals->aChannel[index] == reinterpret_cast(-1)) + { + globals->aChannel[index] = nullptr; + globals->ChannelVolume[index].L = globals->DefaultVolume.L; + globals->ChannelVolume[index].R = globals->DefaultVolume.R; + ++globals->iChannels; + } + } + } + else + { + if (globals->aChannel[iChannel] != reinterpret_cast(-1)) + return 4; + globals->aChannel[iChannel] = nullptr; + globals->ChannelVolume[iChannel].L = globals->DefaultVolume.L; + globals->ChannelVolume[iChannel].R = globals->DefaultVolume.R; + ++globals->iChannels; + } return 0; } int WaveMix::CloseChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) { - return 0; + Globals = SessionToGlobalDataPtr(hMixSession); + if (!Globals) + return 5; + + int minChannel = iChannel, maxChannel; + int result = FlushChannel(hMixSession, iChannel, dwFlags | 2); + if (!result) + { + if ((dwFlags & 1) != 0) + { + minChannel = 0; + maxChannel = 16; + } + else + { + maxChannel = iChannel + 1; + if (iChannel >= maxChannel) + return 0; + } + + CHANNELNODE** channelPtr = &Globals->aChannel[minChannel]; + int index = maxChannel - minChannel; + do + { + if (*channelPtr != reinterpret_cast(-1)) + { + *channelPtr = reinterpret_cast(-1); + --Globals->iChannels; + } + ++channelPtr; + --index; + } + while (index); + return 0; + } + return result; } int WaveMix::FlushChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) @@ -155,11 +238,273 @@ int WaveMix::FlushChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) MIXWAVE* WaveMix::OpenWave(HANDLE hMixSession, LPCSTR szWaveFilename, HINSTANCE hInst, unsigned dwFlags) { - return new MIXWAVE{}; + _MMIOINFO pmmioinfo; + _MMCKINFO pmmcki, pmmFmt; + HWAVEOUT phwo; + WAVEFORMATEX pwfx; + HMMIO hMmio = nullptr; + HGLOBAL hResData = nullptr; + HPSTR wavBuffer3 = nullptr; + auto globals = SessionToGlobalDataPtr(hMixSession); + pwfx.wFormatTag = globals->PCM.wf.wFormatTag; + pwfx.nChannels = globals->PCM.wf.nChannels; + pwfx.nSamplesPerSec = globals->PCM.wf.nSamplesPerSec; + pwfx.nAvgBytesPerSec = globals->PCM.wf.nAvgBytesPerSec; + Globals = globals; + pwfx.nBlockAlign = globals->PCM.wf.nBlockAlign; + pwfx.wBitsPerSample = globals->PCM.wBitsPerSample; + pwfx.cbSize = 0; + if (waveOutOpen(&phwo, 0xFFFFFFFF, &pwfx, 0, 0, 1u)) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "The waveform device can't play this format.", "WavMix32", 0x30u); + return nullptr; + } + + auto mixWave = static_cast(GlobalLock(GlobalAlloc(0x2040u, 0x42u))); + if (!mixWave) + { + if (ShowDebugDialogs) + MessageBoxA( + nullptr, + "Unable to allocate memory for waveform data. Try making more memory available by closing other applications.", + "WavMix32", + 0x40u); + return nullptr; + } + + do + { + if ((dwFlags & 2) != 0) + { + HRSRC hrsc = FindResourceA(hInst, szWaveFilename, "WAVE"); + if (!hrsc || (hResData = LoadResource(hInst, hrsc)) == nullptr) + { + if (HIWORD(szWaveFilename)) + wsprintfA(string_buffer, "Failed to open 'WAVE' resource '%s'.", szWaveFilename); + else + wsprintfA(string_buffer, "Failed to open 'WAVE' resource %u.", LOWORD(szWaveFilename)); + if (ShowDebugDialogs) + MessageBoxA(nullptr, string_buffer, "WavMix32", 0x30u); + break; + } + + memset(&pmmioinfo, 0, sizeof(pmmioinfo)); + pmmioinfo.pchBuffer = static_cast(LockResource(hResData)); + if (!pmmioinfo.pchBuffer) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "Failed to lock 'WAVE' resource", "WavMix32", 0x30u); + FreeResource(hResData); + hResData = nullptr; + break; + } + + pmmioinfo.cchBuffer = SizeofResource(hInst, hrsc); + pmmioinfo.fccIOProc = FOURCC_MEM; + pmmioinfo.adwInfo[0] = 0; + hMmio = mmioOpenA(nullptr, &pmmioinfo, 0); + if (!hMmio) + { + if (ShowDebugDialogs) + { + wsprintfA(string_buffer, + "Failed to open resource, mmioOpen error=%u.\nMay need to make sure resource is marked read-write", + pmmioinfo.wErrorRet); + MessageBoxA(nullptr, string_buffer, "WavMix32", 0x30u); + } + break; + } + } + else if ((dwFlags & 4) != 0) + { + memcpy(&pmmioinfo, szWaveFilename, sizeof(pmmioinfo)); + hMmio = mmioOpenA(nullptr, &pmmioinfo, 0); + if (!hMmio) + { + if (ShowDebugDialogs) + { + wsprintfA(string_buffer, + "Failed to open memory file, mmioOpen error=%u.\nMay need to make sure memory is read-write", + pmmioinfo.wErrorRet); + MessageBoxA(nullptr, string_buffer, "WavMix32", 0x30u); + } + break; + } + } + else + { + hMmio = mmioOpenA(const_cast(szWaveFilename), nullptr, 0x10000u); + if (!hMmio) + { + if (ShowDebugDialogs) + { + wsprintfA(string_buffer, "Failed to open wave file %s.", szWaveFilename); + MessageBoxA(nullptr, string_buffer, "WavMix32", 0x30u); + } + break; + } + } + + pmmcki.fccType = mmioFOURCC('W', 'A', 'V', 'E'); + if (mmioDescend(hMmio, &pmmcki, nullptr, 0x20u)) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "This is not a WAVE file.", "WavMix32", 0x30u); + break; + } + + pmmFmt.ckid = mmioFOURCC('f', 'm', 't', ' '); + if (mmioDescend(hMmio, &pmmFmt, &pmmcki, 0x10u)) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "WAVE file is corrupted.", "WavMix32", 0x30u); + break; + } + if (mmioRead(hMmio, (HPSTR)mixWave, 16) != 16) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "Failed to read format chunk.", "WavMix32", 0x30u); + break; + } + if (mixWave->pcm.wf.wFormatTag != 1) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "The file is not a PCM file.", "WavMix32", 0x30u); + break; + } + + mmioAscend(hMmio, &pmmFmt, 0); + pmmFmt.ckid = mmioFOURCC('d', 'a', 't', 'a'); + if (mmioDescend(hMmio, &pmmFmt, &pmmcki, 0x10u)) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "WAVE file has no data chunk.", "WavMix32", 0x30u); + break; + } + auto dataSize = pmmFmt.cksize; + if (!pmmFmt.cksize) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "The data chunk has no data.", "WavMix32", 0x30u); + break; + } + + auto lpData = static_cast(GlobalLock(GlobalAlloc(0x2002u, pmmFmt.cksize))); + if (!lpData) + { + if (ShowDebugDialogs) + MessageBoxA( + nullptr, + "Unable to allocate memory for waveform data. Try making more memory available by closing other applications.", + "WavMix32", + 0x40u); + break; + } + + auto readCount = mmioRead(hMmio, lpData, dataSize); + if (readCount != static_cast(dataSize)) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "Failed to read data chunk.", "WavMix32", 0x30u); + break; + } + lpData = WaveFormatConvert(&Globals->PCM, &mixWave->pcm, lpData, &dataSize); + if (!lpData) + { + if (ShowDebugDialogs) + MessageBoxA(nullptr, "Failed to convert wave format.", "WavMix32", 0x30u); + break; + } + mmioClose(hMmio, 0); + if (hResData) + FreeResource(hResData); + mixWave->wh.dwBufferLength = dataSize; + mixWave->wh.lpData = lpData; + mixWave->wh.dwFlags = 0; + mixWave->wh.dwLoops = 0; + mixWave->wh.dwUser = 0; + mixWave->wMagic = 21554; + memmove(mixWave, &Globals->PCM, 0x10u); + + if (HIWORD(szWaveFilename)) + { + auto fileNameLength = lstrlenA(szWaveFilename); + int copyOffset = fileNameLength > 15 ? fileNameLength - 15 : 0; + lstrcpyA(mixWave->szWaveFilename, &szWaveFilename[copyOffset]); + } + else + { + wsprintfA(mixWave->szWaveFilename, "res#%u", LOWORD(szWaveFilename)); + } + return mixWave; + } + while (false); + + if (hMmio) + mmioClose(hMmio, 0); + GlobalUnlock(GlobalHandle(mixWave)); + GlobalFree(GlobalHandle(mixWave)); + if (wavBuffer3) + { + GlobalUnlock(GlobalHandle(wavBuffer3)); + GlobalFree(GlobalHandle(wavBuffer3)); + } + if (hResData) + FreeResource(hResData); + return nullptr; } int WaveMix::FreeWave(HANDLE hMixSession, MIXWAVE* lpMixWave) { + GLOBALS* globals = SessionToGlobalDataPtr(hMixSession); + if (!globals) + return 5; + if (!IsValidLPMIXWAVE(lpMixWave)) + return 5; + + CHANNELNODE** channelPtr = globals->aChannel; + for (auto index = 16; index; --index) + { + CHANNELNODE* channel = *channelPtr; + if (channel != reinterpret_cast(-1)) + { + CHANNELNODE* prevChannel = nullptr; + while (channel) + { + if (channel->lpMixWave == lpMixWave) + { + if (prevChannel) + { + prevChannel->next = channel->next; + FreeChannelNode(channel); + channel = prevChannel->next; + } + else + { + channel = channel->next; + FreeChannelNode(channel); + *channelPtr = channel; + } + } + else + { + prevChannel = channel; + channel = channel->next; + } + } + } + ++channelPtr; + } + + if (lpMixWave->wh.lpData) + { + GlobalUnlock(GlobalHandle(lpMixWave->wh.lpData)); + GlobalFree(GlobalHandle(lpMixWave->wh.lpData)); + } + lpMixWave->wMagic = 0; + GlobalUnlock(GlobalHandle(lpMixWave)); + GlobalFree(GlobalHandle(lpMixWave)); return 0; } @@ -206,6 +551,24 @@ int WaveMix::Activate(HANDLE hMixSession, bool fActivate) void WaveMix::Pump() { + Globals = GlobalsActive; + if (GlobalsActive) + { + auto xHDR = play_queue.first; + while (xHDR) + { + if ((xHDR->wh.dwFlags & 1) != 0) + { + RemoveFromPlayingQueue(xHDR); + xHDR->fAvailable = 1; + xHDR = play_queue.first; + } + else + xHDR = xHDR->QNext; + } + FreePlayedBlocks(); + while (MixerPlay(GetWaveBlock(), 1)); + } } int WaveMix::Play(MIXPLAYPARAMS* lpMixPlayParams) @@ -285,25 +648,17 @@ void WaveMix::InitChannelNodes() void WaveMix::InitVolumeTable() { - int index2 = 0; int index3Sub = 0; - char* tablePtr = &volume_table[128]; - do + for (auto volume = 0; volume < 11; volume++) { - int index1 = -128; - int divSmth = index3Sub; - do + auto tablePtr = &volume_table[volume][0]; + for (auto divSmth = index3Sub, sample = 0; sample < 256; ++sample) { - tablePtr[index1] = static_cast(divSmth / 10 + 128); - divSmth += index2; - ++index1; + tablePtr[sample] = static_cast(divSmth / 10 + 128); + divSmth += volume; } - while (index1 < 128); - ++index2; index3Sub -= 128; - tablePtr += 256; } - while (tablePtr <= &volume_table[2688]); } void WaveMix::ShowWaveOutDevices() @@ -1574,9 +1929,399 @@ void WaveMix::ReleaseWaveDevice(GLOBALS* globals) } } -void WaveMix::cmixit(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, int iNumWaves, +HPSTR WaveMix::WaveFormatConvert(PCMWAVEFORMAT* lpOutWF, PCMWAVEFORMAT* lpInWF, HPSTR lpInData, DWORD* dwDataSize) +{ + if (lpInWF->wf.nChannels == lpOutWF->wf.nChannels && + lpInWF->wf.nSamplesPerSec == lpOutWF->wf.nSamplesPerSec && + lpInWF->wBitsPerSample == lpOutWF->wBitsPerSample) + { + return lpInData; + } + HPSTR dataBuf = BitsPerSampleAlign(lpInData, lpInWF->wBitsPerSample, lpOutWF->wBitsPerSample, dwDataSize); + if (!dataBuf) + return nullptr; + dataBuf = ChannelAlign(dataBuf, lpInWF->wf.nChannels, lpOutWF->wf.nChannels, lpOutWF->wBitsPerSample / 8, + dwDataSize); + if (!dataBuf) + return nullptr; + dataBuf = SamplesPerSecAlign(dataBuf, lpInWF->wf.nSamplesPerSec, lpOutWF->wf.nSamplesPerSec, + lpOutWF->wBitsPerSample / 8, lpOutWF->wf.nChannels, dwDataSize); + return dataBuf; +} + +HPSTR WaveMix::BitsPerSampleAlign(HPSTR lpInData, WORD nInBPS, WORD nOutBPS, DWORD* dwDataSize) +{ + LPVOID dataBuf = nullptr; + + if (nInBPS == nOutBPS) + return lpInData; + + if ((nInBPS == 8 || nInBPS == 16) && (nOutBPS == 8 || nOutBPS == 16)) + { + DWORD dwNumSamples = *dwDataSize / (nInBPS / 8u); + *dwDataSize = dwNumSamples * (nOutBPS / 8u); + + dataBuf = GlobalLock(GlobalAlloc(0x2002u, *dwDataSize)); + if (dataBuf) + { + if (nInBPS / 8u <= nOutBPS / 8u) + { + auto dst = static_cast<__int16*>(dataBuf); + for (auto src = lpInData; dwNumSamples; --dwNumSamples) + *dst++ = static_cast((*src++ - 128) * 256); + } + else + { + auto dst = static_cast(dataBuf); + for (auto src = reinterpret_cast<__int16*>(lpInData); dwNumSamples; --dwNumSamples) + { + *dst++ = static_cast(*src++ / 256 + 128); + } + } + } + else + { + if (ShowDebugDialogs) + MessageBoxA( + nullptr, + "Unable to allocate memory for waveform data. Try making more memory available by closing other applications.", + "WavMix32", + 0x40u); + } + } + + GlobalUnlock(GlobalHandle(lpInData)); + GlobalFree(GlobalHandle(lpInData)); + return static_cast(dataBuf); +} + +HPSTR WaveMix::ChannelAlign(HPSTR lpInData, WORD nInChannels, WORD nOutChannels, WORD nBytesPerSample, + DWORD* dwDataSize) +{ + if (nInChannels == nOutChannels) + return lpInData; + DWORD dwNumSamples = *dwDataSize / nBytesPerSample / nInChannels; + *dwDataSize = dwNumSamples * nBytesPerSample * nOutChannels; + char* dataBuf = static_cast(GlobalLock(GlobalAlloc(0x2002u, *dwDataSize))); + if (dataBuf) + { + if (nInChannels < nOutChannels) + { + if (nBytesPerSample == 1) + { + auto src = lpInData; + auto dst = dataBuf; + for (; dwNumSamples; --dwNumSamples) + { + *dst++ = *src; + *dst++ = *src++; + } + } + else + { + auto src = reinterpret_cast(lpInData); + auto dst = reinterpret_cast(dataBuf); + for (; dwNumSamples; --dwNumSamples) + { + *dst++ = *src; + *dst++ = *src++; + } + } + } + else + { + if (nBytesPerSample == 1) + { + auto src = reinterpret_cast(lpInData); + auto dst = reinterpret_cast(dataBuf); + for (; dwNumSamples; --dwNumSamples, src += 2) + { + *dst++ = static_cast((src[0] + src[1]) / 2); + } + } + else + { + auto src = reinterpret_cast<__int16*>(lpInData); + auto dst = reinterpret_cast<__int16*>(dataBuf); + for (; dwNumSamples; --dwNumSamples, src += 2) + { + *dst++ = static_cast((src[0] + src[1]) / 2); + } + } + } + } + else + { + if (ShowDebugDialogs) + MessageBoxA( + nullptr, + "Unable to allocate memory for waveform data. Try making more memory available by closing other applications.", + "WavMix32", + 0x40u); + dataBuf = nullptr; + } + + GlobalUnlock(GlobalHandle(lpInData)); + GlobalFree(GlobalHandle(lpInData)); + return dataBuf; +} + +HPSTR WaveMix::SamplesPerSecAlign(HPSTR lpInData, DWORD nInSamplesPerSec, DWORD nOutSamplesPerSec, WORD nBytesPerSample, + WORD nChannels, DWORD* dwDataSize) +{ + if (nInSamplesPerSec == nOutSamplesPerSec) + return lpInData; + auto sampleSize = nBytesPerSample * nChannels; + auto dwNumSamples = *dwDataSize / sampleSize; + unsigned int nRep, nSkip, dwNumSamples2; + if (nOutSamplesPerSec <= nInSamplesPerSec) + { + nRep = 0; + nSkip = nInSamplesPerSec / nOutSamplesPerSec; + dwNumSamples2 = dwNumSamples / nSkip; + } + else + { + nSkip = 0; + nRep = nOutSamplesPerSec / nInSamplesPerSec; + dwNumSamples2 = dwNumSamples * nRep; + } + *dwDataSize = sampleSize * dwNumSamples2; + + auto dataBuf = static_cast(GlobalLock(GlobalAlloc(0x2002u, sampleSize * dwNumSamples2))); + if (!dataBuf) + { + if (ShowDebugDialogs) + MessageBoxA( + nullptr, + "Unable to allocate memory for waveform data. Try making more memory available by closing other applications.", + "WavMix32", + 0x40u); + GlobalUnlock(GlobalHandle(lpInData)); + GlobalFree(GlobalHandle(lpInData)); + return nullptr; + } + + auto lpInDataBup = lpInData; + auto dataBufBup = dataBuf; + if (nRep <= 0) + { + for (auto index = dwNumSamples2 - 1; index; --index) + { + AvgSample(dataBuf, lpInData, nSkip, nBytesPerSample, nChannels); + lpInData += sampleSize * nSkip; + dataBuf += sampleSize; + } + for (; sampleSize; --sampleSize) + *dataBuf++ = *lpInData++; + } + else + { + for (auto index = dwNumSamples - 1; index; --index) + { + RepSample(dataBuf, lpInData, nRep, nBytesPerSample, nChannels); + lpInData += sampleSize; + dataBuf += sampleSize * nRep; + } + for (auto index1 = nRep; index1; --index1) + { + auto src = lpInData; + for (auto index2 = sampleSize; index2; --index2) + *dataBuf++ = *src++; + } + } + + GlobalUnlock(GlobalHandle(lpInDataBup)); + GlobalFree(GlobalHandle(lpInDataBup)); + return dataBufBup; +} + +void WaveMix::AvgSample(HPSTR lpOutData, HPSTR lpInData, unsigned nSkip, int nBytesPerSample, int nChannels) +{ + if (nBytesPerSample == 1) + { + auto dst = lpOutData; + for (auto channelIndex = nChannels; channelIndex; --channelIndex) + { + auto src = lpInData++; + auto average = 0; + for (auto avgIndex = nSkip; avgIndex; --avgIndex) + { + average += static_cast(*src) - 128; + src += nChannels; + } + *dst++ = static_cast(average / nSkip + 128); + } + } + else + { + auto src = reinterpret_cast<__int16*>(lpInData); + auto dst = reinterpret_cast<__int16*>(lpOutData); + for (auto channelIndex = nChannels; channelIndex; --channelIndex) + { + auto curSrc = src++; + auto average2 = 0; + for (auto avgIndex = nSkip; avgIndex; --avgIndex) + { + average2 += *curSrc; + curSrc += nChannels; + } + *dst++ = static_cast(average2 / nSkip); /*Was *dst = */ + } + } +} + +void WaveMix::RepSample(HPSTR lpOutData, HPSTR lpInData, unsigned nRep, int nBytesPerSample, int nChannels) +{ + if (nBytesPerSample == 1) + { + auto src = reinterpret_cast(lpInData); + auto dst = reinterpret_cast(lpOutData); + for (auto channelIndex = nChannels; channelIndex; --channelIndex) + { + auto sample = *src; + auto dst2 = &dst[nChannels]; + auto delta = (src[nChannels] - src[0]) / nRep; + *dst = *src; + dst++; + for (auto repeatIndex = nRep - 1; repeatIndex; repeatIndex--) + { + sample += delta; + *dst2 = sample; + dst2 += nChannels; + } + ++src; + } + } + else + { + auto src = reinterpret_cast<__int16*>(lpInData); + auto dst = reinterpret_cast<__int16*>(lpOutData); + for (auto channelIndex2 = nChannels; channelIndex2; channelIndex2--) + { + auto sample = *src; + auto dst2 = &dst[nChannels]; + auto delta = (src[nChannels] - src[0]) / nRep; /*Was dst[nChannels] - */ + *dst = *src; + ++dst; + for (auto repeatIndex2 = nRep - 1; repeatIndex2; --repeatIndex2) + { + sample += delta; + *dst2 = sample; + dst2 += nChannels; + } + ++src; + } + } +} + +bool WaveMix::IsValidLPMIXWAVE(MIXWAVE* lpMixWave) +{ + return lpMixWave && lpMixWave->wMagic == 21554; +} + +void WaveMix::FreePlayedBlocks() +{ + auto position = MyWaveOutGetPosition(Globals->hWaveOut, Globals->fGoodGetPos); + for (int i = 0; i < MAXCHANNELS; i ++) + { + CHANNELNODE* channel = Globals->aChannel[i]; + if (channel && channel != reinterpret_cast(-1)) + { + while (channel && position >= channel->dwEndPos) + { + Globals->aChannel[i] = channel->next; + if (channel->PlayParams.hWndNotify) + PostMessageA(channel->PlayParams.hWndNotify, MM_WOM_DONE, i, + reinterpret_cast(channel->lpMixWave)); + FreeChannelNode(channel); + channel = Globals->aChannel[i]; + } + } + } + if (!Globals->fGoodGetPos && !play_queue.first) + { + for (int i = 0; i < MAXCHANNELS; i++) + { + auto channel = Globals->aChannel[i]; + if (channel) + { + if (channel != reinterpret_cast(-1)) + { + PostMessageA(Globals->hWndApp, 0x400u, 0, reinterpret_cast(Globals)); + } + } + } + } +} + +void WaveMix::cmixit(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volumeArr, int iNumWaves, unsigned __int16 length) { + if (!length) + return; + + if (Globals->PCM.wf.nChannels == 2) + { + if (iNumWaves == 1) + { + auto src = rgWaveSrc[0]; + for (auto index = (length - 1u) / 2u + 1u; index; --index) + { + *lpDest++ = volume_table[volumeArr->L][*src++]; + *lpDest++ = volume_table[volumeArr->R][*src++]; + } + } + else + { + for (auto srcOffset = 0u, index = (length - 1u) / 2u + 1u; index; index--) + { + auto sampleR = 128; + auto sampleL = 128; + auto volumePtr = volumeArr; + for (auto channelIndex = 0; channelIndex < iNumWaves; channelIndex++) + { + auto src = rgWaveSrc[channelIndex] + srcOffset; + sampleL += volume_table[volumePtr->L][src[0]] - 128; + sampleR += volume_table[volumePtr->R][src[1]] - 128; + ++volumePtr; + } + + srcOffset += 2; + lpDest[0] = min(max(sampleL, 0), 255); + lpDest[1] = min(max(sampleR, 0), 255); + lpDest += 2; + } + } + } + else + { + if (iNumWaves == 1) + { + auto src = rgWaveSrc[0]; + auto avgVolume = (volumeArr->L + volumeArr->R) / 2; + for (auto index = length; index; --index) + *lpDest++ = volume_table[avgVolume][*src++]; + } + else + { + for (unsigned srcOffset = 0u, index = length; index; index--) + { + auto sample = 128; + auto volumePtr = volumeArr; + for (auto channelIndex = 0; channelIndex < iNumWaves; channelIndex++) + { + auto src = rgWaveSrc[channelIndex] + srcOffset; + auto curSample = volume_table[(volumePtr->L + volumePtr->R) / 2][src[0]]; + sample += curSample - 128; + ++volumePtr; + } + + ++srcOffset; + *lpDest++ = min(max(sample, 0), 255); + } + } + } } LRESULT WaveMix::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) diff --git a/SpaceCadetPinball/WaveMix.h b/SpaceCadetPinball/WaveMix.h index 6f24469..0908c7f 100644 --- a/SpaceCadetPinball/WaveMix.h +++ b/SpaceCadetPinball/WaveMix.h @@ -24,7 +24,7 @@ struct MIXWAVE PCMWAVEFORMAT pcm; WAVEHDR wh; char szWaveFilename[16]; - short Unknown0; + short wMagic; }; struct MIXPLAYPARAMS @@ -112,25 +112,10 @@ struct GLOBALS int unknown29; int unknown30; WAVEOUTCAPSA WaveoutCaps; - int unknown44; - int unknown45; - int unknown46; - int unknown47; - int unknown48; - int unknown49; - int unknown50; - int unknown51; - int unknown52; - int unknown53; - int unknown54; - int unknown55; - int unknown56; - int unknown57; - int unknown58; - int unknown59; - int unknown60; + volume_struct DefaultVolume; + volume_struct ChannelVolume[MAXCHANNELS]; CHANNELNODE* aChannel[MAXCHANNELS]; - int unknown77; + int iChannels; int unknown78; int unknown79; int unknown80; @@ -247,7 +232,17 @@ private: static void FreeWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks); static int AllocWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks); static void ReleaseWaveDevice(GLOBALS* globals); - static void cmixit(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, int iNumWaves, + static HPSTR WaveFormatConvert(PCMWAVEFORMAT* lpOutWF, PCMWAVEFORMAT* lpInWF, HPSTR lpInData, DWORD* dwDataSize); + static HPSTR BitsPerSampleAlign(HPSTR lpInData, WORD nInBPS, WORD nOutBPS, DWORD* dwDataSize); + static HPSTR ChannelAlign(HPSTR lpInData, WORD nInChannels, WORD nOutChannels, WORD nBytesPerSample, + DWORD* dwDataSize); + static HPSTR SamplesPerSecAlign(HPSTR lpInData, DWORD nInSamplesPerSec, DWORD nOutSamplesPerSec, + WORD nBytesPerSample, WORD nChannels, DWORD* dwDataSize); + static void AvgSample(HPSTR lpOutData, HPSTR lpInData, unsigned nSkip, int nBytesPerSample, int nChannels); + static void RepSample(HPSTR lpOutData, HPSTR lpInData, unsigned nRep, int nBytesPerSample, int nChannels); + static bool IsValidLPMIXWAVE(MIXWAVE* lpMixWave); + static void FreePlayedBlocks(); + static void cmixit(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volumeArr, int iNumWaves, unsigned __int16 length); static LRESULT __stdcall WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static INT_PTR __stdcall SettingsDlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); @@ -256,7 +251,7 @@ private: static char FileName[276]; static CHANNELNODE channel_nodes[MAXQUEUEDWAVES]; static CHANNELNODE* free_channel_nodes; - static char volume_table[256 * 11]; + static unsigned char volume_table[11][256]; static int debug_flag; static void (*cmixit_ptr)(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, int iNumWaves, unsigned __int16 length);