diff --git a/.gitignore b/.gitignore index 77cf21f..0e6b0e2 100644 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,4 @@ __pycache__/ /Ida /Export /DrMem +/Doc private diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 44a23b5..fb21803 100644 Binary files a/Doc/FuncStats.xlsx and b/Doc/FuncStats.xlsx differ diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index c7c3b38..6097d31 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -1,33 +1,146 @@ #include "pch.h" #include "Sound.h" -int Sound::Init(HINSTANCE hInstance, int voices, void (__stdcall* someFuncPtr)(int, int, int)) +#include "pinball.h" +#include "WaveMix.h" +#include "winmain.h" + +int Sound::num_channels; +HWND Sound::wavemix_window; +HANDLE Sound::pMem; +unsigned int Sound::enabled_flag; +int Sound::channel_time[8]; +MIXWAVE* Sound::channel_wavePtr[8]; +void (*Sound::callback_ptr)(int, MIXWAVE*, int); +HMODULE Sound::HInstance; + + +int Sound::Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int)) { + WNDCLASSA WndClass; + char FileName[300]; + + int channelCount = voices; + if (voices > 8) + channelCount = 8; + num_channels = channelCount; + if (wavemix_window || pMem) + return 0; + enabled_flag = -1; + for (int i = 0; i < channelCount; ++i) + { + channel_time[i] = 0; + channel_wavePtr[i] = nullptr; + } + callback_ptr = someFuncPtr; + if (!someFuncPtr) + callback_ptr = NullCallback; + + pinball::make_path_name(FileName, "wavemix.inf", 300); + FILE* wavemixIniFile = nullptr; + fopen_s(&wavemixIniFile, FileName, "r"); + if (wavemixIniFile) + { + fclose(wavemixIniFile); + } + else + { + MessageBoxA(winmain::hwnd_frame, pinball::get_rc_string(42, 0), pinball::WindowName, 0x2000u); + } + + WndClass.style = 0; + WndClass.lpfnWndProc = SoundCallBackWndProc; + WndClass.cbClsExtra = 0; + WndClass.cbWndExtra = 0; + WndClass.hInstance = hInstance; + WndClass.hIcon = nullptr; + WndClass.hCursor = nullptr; + WndClass.hbrBackground = nullptr; + WndClass.lpszMenuName = nullptr; + WndClass.lpszClassName = "WaveMixSoundGuy"; + RegisterClassA(&WndClass); + wavemix_window = CreateWindowExA( + 0, + "WaveMixSoundGuy", + nullptr, + 0x80000000, + 0x80000000, + 0, + 0x80000000, + 0, + nullptr, + nullptr, + hInstance, + nullptr); + if (!wavemix_window) + return 0; + + HInstance = hInstance; + HANDLE hMixSession = WaveMix::Init(); + pMem = hMixSession; + if (!hMixSession) + return 0; + WaveMix::OpenChannel(hMixSession, num_channels, 2u); return 1; } -void Sound::Enable(int a1, int a2, int a3) +void Sound::Enable(int channelFrom, int channelTo, int enableFlag) { -} + if (pMem) + { + if (channelTo >= num_channels) + channelTo = num_channels - 1; -void Sound::nullsub_1(int a1, int a2, int a3) -{ + if (channelFrom >= 0 && channelTo < num_channels) + { + for (int index = channelFrom; index <= channelTo; ++index) + { + int channelFlag = 1 << index; + if (enableFlag) + { + enabled_flag |= channelFlag; + } + else + { + enabled_flag &= ~channelFlag; + Flush(index, index); + } + } + } + } } void Sound::Idle() { + if (pMem) + WaveMix::Pump(); } void Sound::Activate() { + if (pMem) + WaveMix::Activate(pMem, true); } void Sound::Deactivate() { + if (pMem) + WaveMix::Activate(pMem, false); } void Sound::Close() { + if (wavemix_window) + { + DestroyWindow(wavemix_window); + wavemix_window = nullptr; + } + if (pMem) + { + WaveMix::CloseChannel(pMem, 0, 1); + WaveMix::CloseSession(pMem); + pMem = nullptr; + } } int Sound::SubFactor(int a1, int a2) @@ -40,16 +153,124 @@ int Sound::AddFactor(int a1, int a2) return a1 + a2; } -void Sound::PlaySoundA(int a1, int a2, int a3, unsigned short a4, short a5) +void Sound::PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, __int16 loops) +{ + MIXPLAYPARAMS mixParams{}; + + if (!pMem) + return; + + if (maxChannel >= num_channels) + maxChannel = num_channels - 1; + if (!wavePtr || minChannel < 0 || maxChannel >= num_channels) + return; + + if ((dwFlags & 0x8000) != 0 && num_channels > 0) + { + int index2 = 0; + bool ok = false; + while (channel_wavePtr[index2] != wavePtr) + { + if (++index2 >= num_channels) + { + ok = true; + break; + } + } + if (!ok) + return; + } + + + int playChannel = minChannel; + if (minChannel < maxChannel) + { + int curChannel = minChannel; + do + { + ++curChannel; + if ((1 << curChannel) & enabled_flag && + channel_time[curChannel] < channel_time[playChannel]) + { + playChannel = curChannel; + } + } + while (curChannel < maxChannel); + } + + if ((1 << playChannel) & enabled_flag) + { + mixParams.hMixSession = pMem; + mixParams.hWndNotify = wavemix_window; + mixParams.dwFlags = dwFlags; + mixParams.wSize = 28; + mixParams.wLoops = loops; + mixParams.iChannel = playChannel; + mixParams.lpMixWave = wavePtr; + + callback_ptr(1, wavePtr, playChannel); + channel_time[playChannel] = timeGetTime(); + channel_wavePtr[playChannel] = wavePtr; + WaveMix::Play(&mixParams); + } +} + +MIXWAVE* Sound::LoadWaveFile(LPCSTR lpName) +{ + return pMem ? WaveMix::OpenWave(pMem, lpName, HInstance, 1u) : nullptr; +} + +void Sound::FreeSound(MIXWAVE* wave) +{ + if (wave && pMem) + WaveMix::FreeWave(pMem, wave); +} + +void Sound::Flush(int channelFrom, int channelTo) +{ + if (pMem) + { + if (channelTo >= num_channels) + channelTo = num_channels - 1; + + if (channelFrom >= 0 && channelTo < num_channels) + { + for (auto index = channelFrom; index <= channelTo; index++) + { + WaveMix::FlushChannel(pMem, index, 0); + channel_time[index] = 0; + channel_wavePtr[index] = nullptr; + } + } + } +} + +void Sound::NullCallback(int a1, MIXWAVE* a2, int a3) { } -CHAR* Sound::LoadWaveFile(LPCSTR lpName) +LRESULT Sound::SoundCallBackWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - return nullptr; -} + if (Msg != 957) + return DefWindowProcA(hWnd, Msg, wParam, lParam); -LPCVOID Sound::FreeSound(LPCVOID pMem) -{ - return nullptr; + auto wavePtr = reinterpret_cast(lParam); + int channel = -1; + for (auto index = 0; index < num_channels; ++index) + { + if (channel_wavePtr[index] == wavePtr && + (channel < 0 || channel_time[index] < channel_time[channel])) + { + channel = index; + } + } + + if (channel >= 0) + { + channel_time[channel] = 0; + channel_wavePtr[channel] = nullptr; + } + + callback_ptr(2, wavePtr, channel); + return 0; } diff --git a/SpaceCadetPinball/Sound.h b/SpaceCadetPinball/Sound.h index 00951bc..5eea4dd 100644 --- a/SpaceCadetPinball/Sound.h +++ b/SpaceCadetPinball/Sound.h @@ -1,17 +1,30 @@ #pragma once +#include "WaveMix.h" + class Sound { public: - static int Init(HINSTANCE hInstance, int voices, void (__stdcall* someFuncPtr)(int, int, int)); - static void Enable(int a1, int a2, int a3); - static void nullsub_1(int a1, int a2, int a3); + static int Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int)); + static void Enable(int channelFrom, int channelTo, int enableFlag); static void Idle(); static void Activate(); static void Deactivate(); static void Close(); static int SubFactor(int a1, int a2); static int AddFactor(int a1, int a2); - static void PlaySound(int a1, int a2, int a3, unsigned __int16 a4, __int16 a5); - static CHAR* LoadWaveFile(LPCSTR lpName); - static LPCVOID FreeSound(LPCVOID pMem); + static void PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, __int16 loops); + static MIXWAVE* LoadWaveFile(LPCSTR lpName); + static void FreeSound(MIXWAVE* wave); + static void Flush(int channelFrom, int channelTo); + static void NullCallback(int a1, MIXWAVE* a2, int a3); + static LRESULT __stdcall SoundCallBackWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +private: + static int num_channels; + static HWND wavemix_window; + static HANDLE pMem; + static unsigned int enabled_flag; + static int channel_time[8]; + static MIXWAVE* channel_wavePtr[8]; + static void (* callback_ptr)(int, MIXWAVE*, int); + static HMODULE HInstance; }; diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index 87e3db8..170af74 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -217,6 +217,7 @@ + @@ -286,6 +287,7 @@ + diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index 7317e0e..6fcaf37 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -222,6 +222,9 @@ Header Files\TEdgeSegment + + Header Files + @@ -410,6 +413,9 @@ Source Files\TEdgeSegment + + Source Files + diff --git a/SpaceCadetPinball/WaveMix.cpp b/SpaceCadetPinball/WaveMix.cpp new file mode 100644 index 0000000..8af1ff6 --- /dev/null +++ b/SpaceCadetPinball/WaveMix.cpp @@ -0,0 +1,51 @@ +#include "pch.h" +#include "WaveMix.h" + +HANDLE WaveMix::Init() +{ + return (HANDLE)1; +} + +int WaveMix::CloseSession(HANDLE hMixSession) +{ + return 0; +} + +int WaveMix::OpenChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) +{ + return 0; +} + +int WaveMix::CloseChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) +{ + return 0; +} + +int WaveMix::FlushChannel(HANDLE hMixSession, int iChannel, unsigned dwFlags) +{ + return 0; +} + +MIXWAVE* WaveMix::OpenWave(HANDLE hMixSession, LPCSTR szWaveFilename, HINSTANCE hInst, unsigned dwFlags) +{ + return new MIXWAVE{}; +} + +int WaveMix::FreeWave(HANDLE hMixSession, MIXWAVE* lpMixWave) +{ + return 0; +} + +int WaveMix::Activate(HANDLE hMixSession, bool fActivate) +{ + return 0; +} + +void WaveMix::Pump() +{ +} + +int WaveMix::Play(MIXPLAYPARAMS* lpMixPlayParams) +{ + return 0; +} diff --git a/SpaceCadetPinball/WaveMix.h b/SpaceCadetPinball/WaveMix.h new file mode 100644 index 0000000..38f028f --- /dev/null +++ b/SpaceCadetPinball/WaveMix.h @@ -0,0 +1,44 @@ +#pragma once + +/* flag values for play params */ +#define WMIX_QUEUEWAVE 0x00 +#define WMIX_CLEARQUEUE 0x01 +#define WMIX_USELRUCHANNEL 0x02 +#define WMIX_HIPRIORITY 0x04 +#define WMIX_WAIT 0x08 + +#define MAXCHANNELS 16 + +struct MIXWAVE +{ + PCMWAVEFORMAT pcm; + WAVEHDR wh; + char szWaveFilename[16]; + short Unknown0; +}; + +struct MIXPLAYPARAMS +{ + WORD wSize; + HANDLE hMixSession; + int iChannel; + MIXWAVE* lpMixWave; + HWND hWndNotify; + DWORD dwFlags; + WORD wLoops; +}; + +class WaveMix +{ +public: + static HANDLE Init(); + static int CloseSession(HANDLE hMixSession); + static int OpenChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags); + static int CloseChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags); + static int FlushChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags); + static MIXWAVE* OpenWave(HANDLE hMixSession, LPCSTR szWaveFilename, HINSTANCE hInst, unsigned int dwFlags); + static int FreeWave(HANDLE hMixSession, MIXWAVE* lpMixWave); + static int Activate(HANDLE hMixSession, bool fActivate); + static void Pump(); + static int Play(MIXPLAYPARAMS* lpMixPlayParams); +}; diff --git a/SpaceCadetPinball/loader.cpp b/SpaceCadetPinball/loader.cpp index 8e0b581..7f1a0f9 100644 --- a/SpaceCadetPinball/loader.cpp +++ b/SpaceCadetPinball/loader.cpp @@ -325,7 +325,7 @@ float loader::play_sound(int soundIndex) { if (soundIndex <= 0) return 0.0; - Sound::PlaySound((int)sound_list[soundIndex].WavePtr, 0, 7, 5, 0); + Sound::PlaySound(sound_list[soundIndex].WavePtr, 0, 7, WMIX_HIPRIORITY | WMIX_CLEARQUEUE, 0); return sound_list[soundIndex].Duration; } diff --git a/SpaceCadetPinball/loader.h b/SpaceCadetPinball/loader.h index b8e6ba7..0c24529 100644 --- a/SpaceCadetPinball/loader.h +++ b/SpaceCadetPinball/loader.h @@ -1,6 +1,7 @@ #pragma once #include "gdrv.h" #include "maths.h" +#include "WaveMix.h" #include "zdrv.h" @@ -14,7 +15,7 @@ struct errorMsg struct soundListStruct { - char* WavePtr; + MIXWAVE* WavePtr; int GroupIndex; int Loaded; float Duration; diff --git a/SpaceCadetPinball/pch.h b/SpaceCadetPinball/pch.h index e0ebb64..7c74e54 100644 --- a/SpaceCadetPinball/pch.h +++ b/SpaceCadetPinball/pch.h @@ -19,7 +19,10 @@ #include /*For control template*/ //#include -// Use (void) to silent unused warnings. +/*Use (void) to silent unused warnings.*/ #define assertm(exp, msg) assert(((void)msg, exp)) +/*Sound uses PlaySound*/ +#undef PlaySound + #endif //PCH_H