1
0
Fork 0
mirror of https://github.com/k4zmu2a/SpaceCadetPinball.git synced 2024-11-22 08:50:18 +01:00

WaveMix v4.

This commit is contained in:
oz 2021-01-27 18:50:24 +03:00
parent 2945069de0
commit 77f3f52e0d
3 changed files with 779 additions and 39 deletions

Binary file not shown.

View file

@ -7,7 +7,7 @@ int WaveMix::initialized_flag;
char WaveMix::FileName[276];
CHANNELNODE WaveMix::channel_nodes[MAXQUEUEDWAVES];
CHANNELNODE* WaveMix::free_channel_nodes;
char WaveMix::volume_table[256 * 11];
unsigned char WaveMix::volume_table[11][256];
int WaveMix::debug_flag;
void (*WaveMix::cmixit_ptr)(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, int iNumWaves,
unsigned __int16 length);
@ -71,7 +71,8 @@ HANDLE WaveMix::ConfigureInit(MIXCONFIG* lpConfig)
globals->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<CHANNELNODE*>(-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<CHANNELNODE*>(-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)
{
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<CHANNELNODE*>(-1))
{
*channelPtr = reinterpret_cast<CHANNELNODE*>(-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<MIXWAVE*>(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<HPSTR>(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<LPSTR>(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<HPSTR>(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<LONG>(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<CHANNELNODE*>(-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<char>(divSmth / 10 + 128);
divSmth += index2;
++index1;
tablePtr[sample] = static_cast<unsigned char>(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<short>((*src++ - 128) * 256);
}
else
{
auto dst = static_cast<char*>(dataBuf);
for (auto src = reinterpret_cast<__int16*>(lpInData); dwNumSamples; --dwNumSamples)
{
*dst++ = static_cast<char>(*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<HPSTR>(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<char*>(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<short*>(lpInData);
auto dst = reinterpret_cast<short*>(dataBuf);
for (; dwNumSamples; --dwNumSamples)
{
*dst++ = *src;
*dst++ = *src++;
}
}
}
else
{
if (nBytesPerSample == 1)
{
auto src = reinterpret_cast<unsigned char*>(lpInData);
auto dst = reinterpret_cast<unsigned char*>(dataBuf);
for (; dwNumSamples; --dwNumSamples, src += 2)
{
*dst++ = static_cast<unsigned char>((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<short>((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<char*>(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<unsigned __int8>(*src) - 128;
src += nChannels;
}
*dst++ = static_cast<char>(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<short>(average2 / nSkip); /*Was *dst = */
}
}
}
void WaveMix::RepSample(HPSTR lpOutData, HPSTR lpInData, unsigned nRep, int nBytesPerSample, int nChannels)
{
if (nBytesPerSample == 1)
{
auto src = reinterpret_cast<unsigned __int8*>(lpInData);
auto dst = reinterpret_cast<unsigned __int8*>(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<CHANNELNODE*>(-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<LPARAM>(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<CHANNELNODE*>(-1))
{
PostMessageA(Globals->hWndApp, 0x400u, 0, reinterpret_cast<LPARAM>(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)

View file

@ -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);