mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-11-24 01:40:18 +01:00
SDL port v1, Windows only for now.
Working: graphics, sound, music (3dpb only). Not working: GUI, user settings.
This commit is contained in:
parent
10c83e8bf5
commit
a09ea75d80
30 changed files with 872 additions and 4172 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -263,3 +263,9 @@ __pycache__/
|
||||||
/Export
|
/Export
|
||||||
/DrMem
|
/DrMem
|
||||||
/Doc private
|
/Doc private
|
||||||
|
# Windows local libraries
|
||||||
|
/Libs
|
||||||
|
|
||||||
|
#CMake generated
|
||||||
|
out/
|
||||||
|
/cmake-build-debug
|
||||||
|
|
145
CMakeLists.txt
Normal file
145
CMakeLists.txt
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(SpaceCadetPinball)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
|
||||||
|
set(SDL2_DIR "${CMAKE_CURRENT_LIST_DIR}/Libs/SDL2-2.0.16")
|
||||||
|
set(SDL2_mixer_DIR "${CMAKE_CURRENT_LIST_DIR}/Libs/SDL2_mixer-2.0.4")
|
||||||
|
|
||||||
|
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
FIND_PACKAGE(SDL2_mixer REQUIRED)
|
||||||
|
|
||||||
|
|
||||||
|
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_MIXER_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
set(SOURCE_FILES
|
||||||
|
SpaceCadetPinball/control.cpp
|
||||||
|
SpaceCadetPinball/control.h
|
||||||
|
SpaceCadetPinball/fullscrn.cpp
|
||||||
|
SpaceCadetPinball/fullscrn.h
|
||||||
|
SpaceCadetPinball/gdrv.cpp
|
||||||
|
SpaceCadetPinball/gdrv.h
|
||||||
|
SpaceCadetPinball/high_score.cpp
|
||||||
|
SpaceCadetPinball/high_score.h
|
||||||
|
SpaceCadetPinball/loader.cpp
|
||||||
|
SpaceCadetPinball/loader.h
|
||||||
|
SpaceCadetPinball/maths.cpp
|
||||||
|
SpaceCadetPinball/maths.h
|
||||||
|
SpaceCadetPinball/memory.cpp
|
||||||
|
SpaceCadetPinball/memory.h
|
||||||
|
SpaceCadetPinball/midi.cpp
|
||||||
|
SpaceCadetPinball/midi.h
|
||||||
|
SpaceCadetPinball/nudge.cpp
|
||||||
|
SpaceCadetPinball/nudge.h
|
||||||
|
SpaceCadetPinball/objlist_class.h
|
||||||
|
SpaceCadetPinball/options.cpp
|
||||||
|
SpaceCadetPinball/options.h
|
||||||
|
SpaceCadetPinball/partman.cpp
|
||||||
|
SpaceCadetPinball/partman.h
|
||||||
|
SpaceCadetPinball/pb.cpp
|
||||||
|
SpaceCadetPinball/pb.h
|
||||||
|
SpaceCadetPinball/pch.cpp
|
||||||
|
SpaceCadetPinball/pch.h
|
||||||
|
SpaceCadetPinball/pinball.cpp
|
||||||
|
SpaceCadetPinball/pinball.h
|
||||||
|
SpaceCadetPinball/proj.cpp
|
||||||
|
SpaceCadetPinball/proj.h
|
||||||
|
SpaceCadetPinball/render.cpp
|
||||||
|
SpaceCadetPinball/render.h
|
||||||
|
SpaceCadetPinball/resource.h
|
||||||
|
SpaceCadetPinball/score.cpp
|
||||||
|
SpaceCadetPinball/score.h
|
||||||
|
SpaceCadetPinball/Sound.cpp
|
||||||
|
SpaceCadetPinball/Sound.h
|
||||||
|
SpaceCadetPinball/SpaceCadetPinball.cpp
|
||||||
|
SpaceCadetPinball/splash.cpp
|
||||||
|
SpaceCadetPinball/splash.h
|
||||||
|
SpaceCadetPinball/TBall.cpp
|
||||||
|
SpaceCadetPinball/TBall.h
|
||||||
|
SpaceCadetPinball/TBlocker.cpp
|
||||||
|
SpaceCadetPinball/TBlocker.h
|
||||||
|
SpaceCadetPinball/TBumper.cpp
|
||||||
|
SpaceCadetPinball/TBumper.h
|
||||||
|
SpaceCadetPinball/TCircle.cpp
|
||||||
|
SpaceCadetPinball/TCircle.h
|
||||||
|
SpaceCadetPinball/TCollisionComponent.cpp
|
||||||
|
SpaceCadetPinball/TCollisionComponent.h
|
||||||
|
SpaceCadetPinball/TComponentGroup.cpp
|
||||||
|
SpaceCadetPinball/TComponentGroup.h
|
||||||
|
SpaceCadetPinball/TDemo.cpp
|
||||||
|
SpaceCadetPinball/TDemo.h
|
||||||
|
SpaceCadetPinball/TDrain.cpp
|
||||||
|
SpaceCadetPinball/TDrain.h
|
||||||
|
SpaceCadetPinball/TEdgeBox.cpp
|
||||||
|
SpaceCadetPinball/TEdgeBox.h
|
||||||
|
SpaceCadetPinball/TEdgeManager.cpp
|
||||||
|
SpaceCadetPinball/TEdgeManager.h
|
||||||
|
SpaceCadetPinball/TEdgeSegment.cpp
|
||||||
|
SpaceCadetPinball/TEdgeSegment.h
|
||||||
|
SpaceCadetPinball/TFlagSpinner.cpp
|
||||||
|
SpaceCadetPinball/TFlagSpinner.h
|
||||||
|
SpaceCadetPinball/TFlipper.cpp
|
||||||
|
SpaceCadetPinball/TFlipper.h
|
||||||
|
SpaceCadetPinball/TFlipperEdge.cpp
|
||||||
|
SpaceCadetPinball/TFlipperEdge.h
|
||||||
|
SpaceCadetPinball/TGate.cpp
|
||||||
|
SpaceCadetPinball/TGate.h
|
||||||
|
SpaceCadetPinball/THole.cpp
|
||||||
|
SpaceCadetPinball/THole.h
|
||||||
|
SpaceCadetPinball/timer.cpp
|
||||||
|
SpaceCadetPinball/timer.h
|
||||||
|
SpaceCadetPinball/TKickback.cpp
|
||||||
|
SpaceCadetPinball/TKickback.h
|
||||||
|
SpaceCadetPinball/TKickout.cpp
|
||||||
|
SpaceCadetPinball/TKickout.h
|
||||||
|
SpaceCadetPinball/TLight.cpp
|
||||||
|
SpaceCadetPinball/TLight.h
|
||||||
|
SpaceCadetPinball/TLightBargraph.cpp
|
||||||
|
SpaceCadetPinball/TLightBargraph.h
|
||||||
|
SpaceCadetPinball/TLightGroup.cpp
|
||||||
|
SpaceCadetPinball/TLightGroup.h
|
||||||
|
SpaceCadetPinball/TLightRollover.cpp
|
||||||
|
SpaceCadetPinball/TLightRollover.h
|
||||||
|
SpaceCadetPinball/TLine.cpp
|
||||||
|
SpaceCadetPinball/TLine.h
|
||||||
|
SpaceCadetPinball/TOneway.cpp
|
||||||
|
SpaceCadetPinball/TOneway.h
|
||||||
|
SpaceCadetPinball/TPinballComponent.cpp
|
||||||
|
SpaceCadetPinball/TPinballComponent.h
|
||||||
|
SpaceCadetPinball/TPinballTable.cpp
|
||||||
|
SpaceCadetPinball/TPinballTable.h
|
||||||
|
SpaceCadetPinball/TPlunger.cpp
|
||||||
|
SpaceCadetPinball/TPlunger.h
|
||||||
|
SpaceCadetPinball/TPopupTarget.cpp
|
||||||
|
SpaceCadetPinball/TPopupTarget.h
|
||||||
|
SpaceCadetPinball/TRamp.cpp
|
||||||
|
SpaceCadetPinball/TRamp.h
|
||||||
|
SpaceCadetPinball/TRollover.cpp
|
||||||
|
SpaceCadetPinball/TRollover.h
|
||||||
|
SpaceCadetPinball/TSink.cpp
|
||||||
|
SpaceCadetPinball/TSink.h
|
||||||
|
SpaceCadetPinball/TSoloTarget.cpp
|
||||||
|
SpaceCadetPinball/TSoloTarget.h
|
||||||
|
SpaceCadetPinball/TSound.cpp
|
||||||
|
SpaceCadetPinball/TSound.h
|
||||||
|
SpaceCadetPinball/TTableLayer.cpp
|
||||||
|
SpaceCadetPinball/TTableLayer.h
|
||||||
|
SpaceCadetPinball/TTextBox.cpp
|
||||||
|
SpaceCadetPinball/TTextBox.h
|
||||||
|
SpaceCadetPinball/TTextBoxMessage.cpp
|
||||||
|
SpaceCadetPinball/TTextBoxMessage.h
|
||||||
|
SpaceCadetPinball/TTimer.cpp
|
||||||
|
SpaceCadetPinball/TTimer.h
|
||||||
|
SpaceCadetPinball/TTripwire.cpp
|
||||||
|
SpaceCadetPinball/TTripwire.h
|
||||||
|
SpaceCadetPinball/TWall.cpp
|
||||||
|
SpaceCadetPinball/TWall.h
|
||||||
|
SpaceCadetPinball/winmain.cpp
|
||||||
|
SpaceCadetPinball/winmain.h
|
||||||
|
SpaceCadetPinball/zdrv.cpp
|
||||||
|
SpaceCadetPinball/zdrv.h)
|
||||||
|
|
||||||
|
add_executable(SpaceCadetPinball ${SOURCE_FILES})
|
||||||
|
|
||||||
|
target_link_libraries(SpaceCadetPinball ${SDL2_LIBRARIES} ${SDL2_MIXER_LIBRARIES})
|
27
CMakeSettings.json
Normal file
27
CMakeSettings.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "x64-Debug",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"configurationType": "Debug",
|
||||||
|
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||||
|
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||||
|
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||||
|
"cmakeCommandArgs": "",
|
||||||
|
"buildCommandArgs": "",
|
||||||
|
"ctestCommandArgs": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x86-Debug",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"configurationType": "Debug",
|
||||||
|
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||||
|
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||||
|
"cmakeCommandArgs": "",
|
||||||
|
"buildCommandArgs": "",
|
||||||
|
"ctestCommandArgs": "",
|
||||||
|
"inheritEnvironments": [ "msvc_x86" ],
|
||||||
|
"variables": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -28,9 +28,9 @@ Compile with Visual Studio; tested with 2017 and 2019.
|
||||||
* ~~Resizable window, scaled graphics~~
|
* ~~Resizable window, scaled graphics~~
|
||||||
* ~~Loader for high-res sprites from CADET.DAT~~
|
* ~~Loader for high-res sprites from CADET.DAT~~
|
||||||
* Misc features of Full Tilt: 3 music tracs, multiball, centered textboxes, etc.
|
* Misc features of Full Tilt: 3 music tracs, multiball, centered textboxes, etc.
|
||||||
* Maybe: cross-platform port
|
* Cross-platform port
|
||||||
* Needs UI framework with menu bar and dialog windows, like QT or Avalonia
|
* Using SDL2, SDL2_mixer, ImGui
|
||||||
* Needs a way play sounds and midi
|
* Maybe: Android port
|
||||||
* Maybe x2: support for other two tables
|
* Maybe x2: support for other two tables
|
||||||
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
|
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 15
|
|
||||||
VisualStudioVersion = 15.0.28307.705
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpaceCadetPinball", "SpaceCadetPinball\SpaceCadetPinball.vcxproj", "{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x64.Build.0 = Release|x64
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x86.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {4B620E0B-FD42-4AEC-BC4A-261C1669A1B5}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -3,268 +3,54 @@
|
||||||
|
|
||||||
|
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
#include "pinball.h"
|
|
||||||
#include "WaveMix.h"
|
|
||||||
#include "winmain.h"
|
|
||||||
|
|
||||||
int Sound::num_channels;
|
int Sound::num_channels;
|
||||||
HWND Sound::wavemix_window;
|
|
||||||
HANDLE Sound::pMem;
|
|
||||||
unsigned int Sound::enabled_flag;
|
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(int voices)
|
||||||
int Sound::Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int))
|
|
||||||
{
|
{
|
||||||
WNDCLASSA WndClass;
|
|
||||||
char FileName[300];
|
|
||||||
|
|
||||||
int channelCount = voices;
|
int channelCount = voices;
|
||||||
if (voices > 8)
|
if (voices > 8)
|
||||||
channelCount = 8;
|
channelCount = 8;
|
||||||
num_channels = channelCount;
|
num_channels = channelCount;
|
||||||
if (wavemix_window || pMem)
|
|
||||||
return 0;
|
|
||||||
enabled_flag = -1;
|
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);
|
return Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) == -1;
|
||||||
FILE* wavemixIniFile = nullptr;
|
|
||||||
fopen_s(&wavemixIniFile, FileName, "r");
|
|
||||||
if (wavemixIniFile)
|
|
||||||
{
|
|
||||||
fclose(wavemixIniFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*FT does not have the file, defaults work OK*/
|
|
||||||
if (!pb::FullTiltMode)
|
|
||||||
MessageBoxA(winmain::hwnd_frame, pinball::get_rc_string(42, 0), "", 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 channelFrom, int channelTo, int enableFlag)
|
void Sound::Enable(int channelFrom, int channelTo, int enableFlag)
|
||||||
{
|
{
|
||||||
if (pMem)
|
enabled_flag = enableFlag;
|
||||||
{
|
|
||||||
if (channelTo >= num_channels)
|
|
||||||
channelTo = num_channels - 1;
|
|
||||||
|
|
||||||
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()
|
void Sound::Activate()
|
||||||
{
|
{
|
||||||
if (pMem)
|
Mix_Resume(-1);
|
||||||
WaveMix::Activate(pMem, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Deactivate()
|
void Sound::Deactivate()
|
||||||
{
|
{
|
||||||
if (pMem)
|
Mix_Pause(-1);
|
||||||
WaveMix::Activate(pMem, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Close()
|
void Sound::Close()
|
||||||
{
|
{
|
||||||
if (wavemix_window)
|
Mix_Quit();
|
||||||
{
|
|
||||||
DestroyWindow(wavemix_window);
|
|
||||||
wavemix_window = nullptr;
|
|
||||||
}
|
|
||||||
if (pMem)
|
|
||||||
{
|
|
||||||
WaveMix::CloseChannel(pMem, 0, 1);
|
|
||||||
WaveMix::CloseSession(pMem);
|
|
||||||
pMem = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops)
|
void Sound::PlaySound(Mix_Chunk* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops)
|
||||||
{
|
{
|
||||||
MIXPLAYPARAMS mixParams{};
|
if (enabled_flag)
|
||||||
|
Mix_PlayChannel(-1, wavePtr, loops);
|
||||||
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)
|
Mix_Chunk* Sound::LoadWaveFile(LPCSTR lpName)
|
||||||
{
|
{
|
||||||
return pMem ? WaveMix::OpenWave(pMem, lpName, HInstance, 1u) : nullptr;
|
return Mix_LoadWAV(lpName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::FreeSound(MIXWAVE* wave)
|
void Sound::FreeSound(Mix_Chunk* wave)
|
||||||
{
|
{
|
||||||
if (wave && pMem)
|
if (wave)
|
||||||
WaveMix::FreeWave(pMem, wave);
|
Mix_FreeChunk(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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT Sound::SoundCallBackWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
if (Msg != MM_WOM_DONE)
|
|
||||||
return DefWindowProcA(hWnd, Msg, wParam, lParam);
|
|
||||||
|
|
||||||
auto wavePtr = reinterpret_cast<MIXWAVE*>(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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "WaveMix.h"
|
|
||||||
|
|
||||||
class Sound
|
class Sound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static int Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int));
|
static int Init(int voices);
|
||||||
static void Enable(int channelFrom, int channelTo, int enableFlag);
|
static void Enable(int channelFrom, int channelTo, int enableFlag);
|
||||||
static void Idle();
|
|
||||||
static void Activate();
|
static void Activate();
|
||||||
static void Deactivate();
|
static void Deactivate();
|
||||||
static void Close();
|
static void Close();
|
||||||
static void PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops);
|
static void PlaySound(Mix_Chunk* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops);
|
||||||
static MIXWAVE* LoadWaveFile(LPCSTR lpName);
|
static Mix_Chunk* LoadWaveFile(LPCSTR lpName);
|
||||||
static void FreeSound(MIXWAVE* wave);
|
static void FreeSound(Mix_Chunk* 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:
|
private:
|
||||||
static int num_channels;
|
static int num_channels;
|
||||||
static HWND wavemix_window;
|
|
||||||
static HANDLE pMem;
|
|
||||||
static unsigned int enabled_flag;
|
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;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,7 @@ int main()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Hello World!\n";
|
std::cout << "Hello World!\n";
|
||||||
gdrv::init(nullptr, nullptr);
|
gdrv::init(nullptr,0,0);
|
||||||
auto dib = gdrv::DibCreate(8, 1, 1);
|
auto dib = gdrv::DibCreate(8, 1, 1);
|
||||||
gdrv::DibSetUsage(dib, nullptr, 1);
|
gdrv::DibSetUsage(dib, nullptr, 1);
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ int main()
|
||||||
auto xx = sizeof(datFileHeader);
|
auto xx = sizeof(datFileHeader);
|
||||||
|
|
||||||
lstrcpyA(winmain::DatFileName, "PINBALL.DAT");
|
lstrcpyA(winmain::DatFileName, "PINBALL.DAT");
|
||||||
pb::init();
|
pb::init(nullptr);
|
||||||
auto datFile = pb::record_table;
|
auto datFile = pb::record_table;
|
||||||
|
|
||||||
assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43);
|
assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43);
|
||||||
|
|
|
@ -1,316 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<VCProjectVersion>15.0</VCProjectVersion>
|
|
||||||
<ProjectGuid>{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}</ProjectGuid>
|
|
||||||
<Keyword>Win32Proj</Keyword>
|
|
||||||
<RootNamespace>SpaceCadetPinball</RootNamespace>
|
|
||||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<ImportGroup Label="ExtensionSettings">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="Shared">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>true</ConformanceMode>
|
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
|
||||||
<PreprocessToFile>false</PreprocessToFile>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>true</ConformanceMode>
|
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>true</ConformanceMode>
|
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>true</ConformanceMode>
|
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="control.h" />
|
|
||||||
<ClInclude Include="fullscrn.h" />
|
|
||||||
<ClInclude Include="gdrv.h" />
|
|
||||||
<ClInclude Include="high_score.h" />
|
|
||||||
<ClInclude Include="loader.h" />
|
|
||||||
<ClInclude Include="maths.h" />
|
|
||||||
<ClInclude Include="memory.h" />
|
|
||||||
<ClInclude Include="midi.h" />
|
|
||||||
<ClInclude Include="nudge.h" />
|
|
||||||
<ClInclude Include="objlist_class.h" />
|
|
||||||
<ClInclude Include="options.h" />
|
|
||||||
<ClInclude Include="partman.h" />
|
|
||||||
<ClInclude Include="pb.h" />
|
|
||||||
<ClInclude Include="pch.h" />
|
|
||||||
<ClInclude Include="pinball.h" />
|
|
||||||
<ClInclude Include="proj.h" />
|
|
||||||
<ClInclude Include="render.h" />
|
|
||||||
<ClInclude Include="resource.h" />
|
|
||||||
<ClInclude Include="score.h" />
|
|
||||||
<ClInclude Include="Sound.h" />
|
|
||||||
<ClInclude Include="splash.h" />
|
|
||||||
<ClInclude Include="TBall.h" />
|
|
||||||
<ClInclude Include="TBlocker.h" />
|
|
||||||
<ClInclude Include="TBumper.h" />
|
|
||||||
<ClInclude Include="TCircle.h" />
|
|
||||||
<ClInclude Include="TCollisionComponent.h" />
|
|
||||||
<ClInclude Include="TComponentGroup.h" />
|
|
||||||
<ClInclude Include="TDemo.h" />
|
|
||||||
<ClInclude Include="TDrain.h" />
|
|
||||||
<ClInclude Include="TEdgeBox.h" />
|
|
||||||
<ClInclude Include="TEdgeManager.h" />
|
|
||||||
<ClInclude Include="TEdgeSegment.h" />
|
|
||||||
<ClInclude Include="TFlagSpinner.h" />
|
|
||||||
<ClInclude Include="TFlipper.h" />
|
|
||||||
<ClInclude Include="TFlipperEdge.h" />
|
|
||||||
<ClInclude Include="TGate.h" />
|
|
||||||
<ClInclude Include="THole.h" />
|
|
||||||
<ClInclude Include="timer.h" />
|
|
||||||
<ClInclude Include="TKickback.h" />
|
|
||||||
<ClInclude Include="TKickout.h" />
|
|
||||||
<ClInclude Include="TLight.h" />
|
|
||||||
<ClInclude Include="TLightBargraph.h" />
|
|
||||||
<ClInclude Include="TLightGroup.h" />
|
|
||||||
<ClInclude Include="TLightRollover.h" />
|
|
||||||
<ClInclude Include="TLine.h" />
|
|
||||||
<ClInclude Include="TOneway.h" />
|
|
||||||
<ClInclude Include="TPinballComponent.h" />
|
|
||||||
<ClInclude Include="TPinballTable.h" />
|
|
||||||
<ClInclude Include="TPlunger.h" />
|
|
||||||
<ClInclude Include="TPopupTarget.h" />
|
|
||||||
<ClInclude Include="TRamp.h" />
|
|
||||||
<ClInclude Include="TRollover.h" />
|
|
||||||
<ClInclude Include="TSink.h" />
|
|
||||||
<ClInclude Include="TSoloTarget.h" />
|
|
||||||
<ClInclude Include="TSound.h" />
|
|
||||||
<ClInclude Include="TTableLayer.h" />
|
|
||||||
<ClInclude Include="TTextBox.h" />
|
|
||||||
<ClInclude Include="TTextBoxMessage.h" />
|
|
||||||
<ClInclude Include="TTimer.h" />
|
|
||||||
<ClInclude Include="TTripwire.h" />
|
|
||||||
<ClInclude Include="TWall.h" />
|
|
||||||
<ClInclude Include="WaveMix.h" />
|
|
||||||
<ClInclude Include="winmain.h" />
|
|
||||||
<ClInclude Include="zdrv.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="control.cpp" />
|
|
||||||
<ClCompile Include="fullscrn.cpp" />
|
|
||||||
<ClCompile Include="gdrv.cpp" />
|
|
||||||
<ClCompile Include="high_score.cpp" />
|
|
||||||
<ClCompile Include="loader.cpp" />
|
|
||||||
<ClCompile Include="maths.cpp" />
|
|
||||||
<ClCompile Include="memory.cpp" />
|
|
||||||
<ClCompile Include="midi.cpp" />
|
|
||||||
<ClCompile Include="nudge.cpp" />
|
|
||||||
<ClCompile Include="options.cpp" />
|
|
||||||
<ClCompile Include="partman.cpp" />
|
|
||||||
<ClCompile Include="pb.cpp" />
|
|
||||||
<ClCompile Include="pch.cpp">
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="pinball.cpp" />
|
|
||||||
<ClCompile Include="proj.cpp" />
|
|
||||||
<ClCompile Include="render.cpp" />
|
|
||||||
<ClCompile Include="score.cpp" />
|
|
||||||
<ClCompile Include="Sound.cpp" />
|
|
||||||
<ClCompile Include="SpaceCadetPinball.cpp" />
|
|
||||||
<ClCompile Include="splash.cpp" />
|
|
||||||
<ClCompile Include="TBall.cpp" />
|
|
||||||
<ClCompile Include="TBlocker.cpp" />
|
|
||||||
<ClCompile Include="TBumper.cpp" />
|
|
||||||
<ClCompile Include="TCircle.cpp" />
|
|
||||||
<ClCompile Include="TCollisionComponent.cpp" />
|
|
||||||
<ClCompile Include="TComponentGroup.cpp" />
|
|
||||||
<ClCompile Include="TDemo.cpp" />
|
|
||||||
<ClCompile Include="TDrain.cpp" />
|
|
||||||
<ClCompile Include="TEdgeBox.cpp" />
|
|
||||||
<ClCompile Include="TEdgeManager.cpp" />
|
|
||||||
<ClCompile Include="TEdgeSegment.cpp" />
|
|
||||||
<ClCompile Include="TFlagSpinner.cpp" />
|
|
||||||
<ClCompile Include="TFlipper.cpp" />
|
|
||||||
<ClCompile Include="TFlipperEdge.cpp" />
|
|
||||||
<ClCompile Include="TGate.cpp" />
|
|
||||||
<ClCompile Include="THole.cpp" />
|
|
||||||
<ClCompile Include="timer.cpp" />
|
|
||||||
<ClCompile Include="TKickback.cpp" />
|
|
||||||
<ClCompile Include="TKickout.cpp" />
|
|
||||||
<ClCompile Include="TLight.cpp" />
|
|
||||||
<ClCompile Include="TLightBargraph.cpp" />
|
|
||||||
<ClCompile Include="TLightGroup.cpp" />
|
|
||||||
<ClCompile Include="TLightRollover.cpp" />
|
|
||||||
<ClCompile Include="TLine.cpp" />
|
|
||||||
<ClCompile Include="TOneway.cpp" />
|
|
||||||
<ClCompile Include="TPinballComponent.cpp" />
|
|
||||||
<ClCompile Include="TPinballTable.cpp" />
|
|
||||||
<ClCompile Include="TPlunger.cpp" />
|
|
||||||
<ClCompile Include="TPopupTarget.cpp" />
|
|
||||||
<ClCompile Include="TRamp.cpp" />
|
|
||||||
<ClCompile Include="TRollover.cpp" />
|
|
||||||
<ClCompile Include="TSink.cpp" />
|
|
||||||
<ClCompile Include="TSoloTarget.cpp" />
|
|
||||||
<ClCompile Include="TSound.cpp" />
|
|
||||||
<ClCompile Include="TTableLayer.cpp" />
|
|
||||||
<ClCompile Include="TTextBox.cpp" />
|
|
||||||
<ClCompile Include="TTextBoxMessage.cpp" />
|
|
||||||
<ClCompile Include="TTimer.cpp" />
|
|
||||||
<ClCompile Include="TTripwire.cpp" />
|
|
||||||
<ClCompile Include="TWall.cpp" />
|
|
||||||
<ClCompile Include="WaveMix.cpp" />
|
|
||||||
<ClCompile Include="winmain.cpp" />
|
|
||||||
<ClCompile Include="zdrv.cpp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Natvis Include="NatvisFile.natvis" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="SpaceCadetPinball.rc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="PB_MSGFT.bin" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Image Include="Icon_1.ico" />
|
|
||||||
<Image Include="splash_bitmap.bmp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
<ImportGroup Label="ExtensionTargets">
|
|
||||||
</ImportGroup>
|
|
||||||
</Project>
|
|
|
@ -1,441 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\TEdgeSegment">
|
|
||||||
<UniqueIdentifier>{0aa40751-a44a-400e-8809-ee817161e8e0}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\TEdgeSegment">
|
|
||||||
<UniqueIdentifier>{d70e7fca-2294-41a4-9cf8-78052bdb9aa4}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\TCollisionComponent">
|
|
||||||
<UniqueIdentifier>{01aed326-d2ec-457a-b99f-08ef32ed97fa}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\TCollisionComponent">
|
|
||||||
<UniqueIdentifier>{7ed2796a-da4b-4edd-8783-53e45d8d1c88}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\TPinballComponent">
|
|
||||||
<UniqueIdentifier>{9ee086c2-1a95-48fb-92d8-4b7e7f6682ff}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\TPinballComponent">
|
|
||||||
<UniqueIdentifier>{33813da8-81ac-449c-b19a-9756272519b9}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="pch.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="objlist_class.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="partman.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="loader.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="pinball.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="score.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TPinballComponent.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TBall.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="resource.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TComponentGroup.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TLight.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TLightBargraph.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TLightGroup.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TSound.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TTextBox.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TTimer.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="memory.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="winmain.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="options.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Sound.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="pb.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="render.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="fullscrn.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="gdrv.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="maths.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="zdrv.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TEdgeSegment.h">
|
|
||||||
<Filter>Header Files\TEdgeSegment</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TCollisionComponent.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TCircle.h">
|
|
||||||
<Filter>Header Files\TEdgeSegment</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TLine.h">
|
|
||||||
<Filter>Header Files\TEdgeSegment</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TWall.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TBumper.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TBlocker.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TDemo.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TDrain.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TFlagSpinner.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TFlipper.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TGate.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="THole.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TKickback.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TKickout.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TOneway.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TPlunger.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TPopupTarget.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TRamp.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TRollover.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TSink.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TSoloTarget.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TTableLayer.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TPinballTable.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TTripwire.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TLightRollover.h">
|
|
||||||
<Filter>Header Files\TCollisionComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="proj.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="timer.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="midi.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="nudge.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TTextBoxMessage.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="high_score.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="control.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TEdgeManager.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TEdgeBox.h">
|
|
||||||
<Filter>Header Files\TPinballComponent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="TFlipperEdge.h">
|
|
||||||
<Filter>Header Files\TEdgeSegment</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="WaveMix.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="splash.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="pch.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="SpaceCadetPinball.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="partman.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="loader.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="pinball.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="score.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TPinballComponent.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TPinballTable.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TBall.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TComponentGroup.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TLight.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TLightBargraph.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TLightGroup.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TSound.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TTextBox.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TTimer.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="memory.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="winmain.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="options.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Sound.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="pb.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="render.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="fullscrn.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="gdrv.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="maths.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="zdrv.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TEdgeSegment.cpp">
|
|
||||||
<Filter>Source Files\TEdgeSegment</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TCollisionComponent.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TCircle.cpp">
|
|
||||||
<Filter>Source Files\TEdgeSegment</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TLine.cpp">
|
|
||||||
<Filter>Source Files\TEdgeSegment</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TWall.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TBlocker.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TBumper.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TDemo.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TDrain.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TFlagSpinner.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TFlipper.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TGate.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="THole.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TKickback.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TKickout.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TOneway.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TPlunger.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TPopupTarget.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TRamp.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TRollover.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TSink.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TSoloTarget.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TTableLayer.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TTripwire.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TLightRollover.cpp">
|
|
||||||
<Filter>Source Files\TCollisionComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="proj.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="timer.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="midi.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="nudge.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TTextBoxMessage.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="high_score.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="control.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TEdgeManager.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TEdgeBox.cpp">
|
|
||||||
<Filter>Source Files\TPinballComponent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TFlipperEdge.cpp">
|
|
||||||
<Filter>Source Files\TEdgeSegment</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="WaveMix.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="splash.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Natvis Include="NatvisFile.natvis" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="SpaceCadetPinball.rc">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</ResourceCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="PB_MSGFT.bin">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Image Include="Icon_1.ico">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</Image>
|
|
||||||
<Image Include="splash_bitmap.bmp">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</Image>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -443,25 +443,20 @@ int TPinballTable::Message(int code, float value)
|
||||||
}
|
}
|
||||||
|
|
||||||
BallCount = MaxBallCount;
|
BallCount = MaxBallCount;
|
||||||
Sound::Idle();
|
|
||||||
ChangeBallCount(BallCount);
|
ChangeBallCount(BallCount);
|
||||||
score::set(ScorePlayerNumber1, CurrentPlayer + 1);
|
score::set(ScorePlayerNumber1, CurrentPlayer + 1);
|
||||||
score::update(ScorePlayerNumber1);
|
score::update(ScorePlayerNumber1);
|
||||||
Sound::Idle();
|
|
||||||
|
|
||||||
for (auto scoreIndex = 4 - PlayerCount; scoreIndex > 0; scoreIndex--)
|
for (auto scoreIndex = 4 - PlayerCount; scoreIndex > 0; scoreIndex--)
|
||||||
{
|
{
|
||||||
score::set(PlayerScores[scoreIndex].ScoreStruct, -1);
|
score::set(PlayerScores[scoreIndex].ScoreStruct, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound::Idle();
|
|
||||||
ScoreSpecial3Flag = 0;
|
ScoreSpecial3Flag = 0;
|
||||||
ScoreSpecial2Flag = 0;
|
ScoreSpecial2Flag = 0;
|
||||||
UnknownP71 = 0;
|
UnknownP71 = 0;
|
||||||
pinball::InfoTextBox->Clear();
|
pinball::InfoTextBox->Clear();
|
||||||
Sound::Idle();
|
|
||||||
pinball::MissTextBox->Clear();
|
pinball::MissTextBox->Clear();
|
||||||
Sound::Idle();
|
|
||||||
LightGroup->Message(28, 0.2f);
|
LightGroup->Message(28, 0.2f);
|
||||||
auto time = loader::play_sound(SoundIndex1);
|
auto time = loader::play_sound(SoundIndex1);
|
||||||
LightShowTimer = timer::set(time, this, LightShow_timeout);
|
LightShowTimer = timer::set(time, this, LightShow_timeout);
|
||||||
|
|
|
@ -1,2627 +0,0 @@
|
||||||
#include "pch.h"
|
|
||||||
#include "WaveMix.h"
|
|
||||||
|
|
||||||
#include "pinball.h"
|
|
||||||
|
|
||||||
int WaveMix::initialized_flag;
|
|
||||||
char WaveMix::FileName[276];
|
|
||||||
CHANNELNODE WaveMix::channel_nodes[MAXQUEUEDWAVES];
|
|
||||||
CHANNELNODE* WaveMix::free_channel_nodes;
|
|
||||||
unsigned char WaveMix::volume_table[11][256];
|
|
||||||
int WaveMix::debug_flag;
|
|
||||||
void (*WaveMix::cmixit_ptr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume, int iNumWaves,
|
|
||||||
uint16_t length);
|
|
||||||
HMODULE WaveMix::HModule;
|
|
||||||
PCMWAVEFORMAT WaveMix::gpFormat = {{1u, 1u, 11025u, 11025u, 1u}, 8u};
|
|
||||||
char WaveMix::string_buffer[256] = "WaveMix V 2.3 by Angel M. Diaz, Jr. (c) Microsoft 1993-1995";
|
|
||||||
GLOBALS *WaveMix::Globals, *WaveMix::GlobalsActive;
|
|
||||||
int WaveMix::ShowDebugDialogs;
|
|
||||||
PLAYQUEUE WaveMix::play_queue;
|
|
||||||
CHANNELNODE* WaveMix::play_channel_array[MAXCHANNELS];
|
|
||||||
XWAVEHDR* WaveMix::block_array1[10];
|
|
||||||
XWAVEHDR* WaveMix::block_array2[10];
|
|
||||||
unsigned char* WaveMix::play_data[MAXCHANNELS];
|
|
||||||
volume_struct WaveMix::play_volume[MAXCHANNELS];
|
|
||||||
int WaveMix::play_counter = 0;
|
|
||||||
|
|
||||||
HANDLE WaveMix::Init()
|
|
||||||
{
|
|
||||||
return ConfigureInit(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE WaveMix::ConfigureInit(MIXCONFIG* lpConfig)
|
|
||||||
{
|
|
||||||
MIXCONFIG mixConfig{};
|
|
||||||
|
|
||||||
memset(&mixConfig, 0, sizeof(MIXCONFIG));
|
|
||||||
unsigned int copySize = sizeof(MIXCONFIG);
|
|
||||||
mixConfig.RegistryKey = nullptr;
|
|
||||||
mixConfig.wSize = sizeof(MIXCONFIG);
|
|
||||||
if (lpConfig)
|
|
||||||
{
|
|
||||||
if (lpConfig->wSize < sizeof(MIXCONFIG))
|
|
||||||
copySize = lpConfig->wSize;
|
|
||||||
memcpy(&mixConfig, lpConfig, copySize);
|
|
||||||
}
|
|
||||||
if (initialized_flag || Startup(GetModuleHandleA(nullptr)) != 0)
|
|
||||||
{
|
|
||||||
bool showDebugDialogs;
|
|
||||||
if ((mixConfig.dwFlags & 0x100) != 0)
|
|
||||||
showDebugDialogs = mixConfig.ShowDebugDialogs != 0;
|
|
||||||
else
|
|
||||||
showDebugDialogs = GetPrivateProfileIntA("general", "ShowDebugDialogs", 0, FileName) != 0;
|
|
||||||
ShowDebugDialogs = showDebugDialogs;
|
|
||||||
if (!waveOutGetNumDevs())
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "This system does not have a valid wave output device.");
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetPrivateProfileIntA("general", "ShowDevices", 0, FileName))
|
|
||||||
ShowWaveOutDevices();
|
|
||||||
auto globals = static_cast<GLOBALS*>(LocalAlloc(LMEM_ZEROINIT, sizeof(GLOBALS)));
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return nullptr;
|
|
||||||
globals->CmixPtr = cmixit_ptr;
|
|
||||||
globals->wMagic2 = 21554;
|
|
||||||
globals->wMagic1 = 21554;
|
|
||||||
globals->WaveBlockArray = nullptr;
|
|
||||||
globals->SettingsDialogActiveFlag = 0;
|
|
||||||
globals->DefaultVolume.L = 10;
|
|
||||||
globals->DefaultVolume.R = 10;
|
|
||||||
memset(globals->aChannel, 0xFFu, sizeof globals->aChannel);
|
|
||||||
memmove(&globals->PCM, &gpFormat, sizeof(PCMWAVEFORMAT));
|
|
||||||
if (!ReadConfigSettings(&mixConfig))
|
|
||||||
{
|
|
||||||
Globals->wMagic2 = 0;
|
|
||||||
Globals->wMagic1 = 0;
|
|
||||||
LocalFree(Globals);
|
|
||||||
Globals = nullptr;
|
|
||||||
}
|
|
||||||
return Globals;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
int channelId;
|
|
||||||
int lastChannel;
|
|
||||||
|
|
||||||
int remixFlag = 0;
|
|
||||||
auto globals = SessionToGlobalDataPtr(hMixSession);
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
if ((dwFlags & 1) != 0)
|
|
||||||
{
|
|
||||||
channelId = 0;
|
|
||||||
lastChannel = 16;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
channelId = iChannel;
|
|
||||||
if (iChannel < 0 || iChannel >= 16)
|
|
||||||
return 11;
|
|
||||||
if (globals->aChannel[iChannel] == reinterpret_cast<CHANNELNODE*>(-1))
|
|
||||||
return 5;
|
|
||||||
lastChannel = iChannel + 1;
|
|
||||||
if (iChannel >= lastChannel)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto index = channelId; index < lastChannel; index++)
|
|
||||||
{
|
|
||||||
auto curChannel = globals->aChannel[index];
|
|
||||||
if (curChannel != reinterpret_cast<CHANNELNODE*>(-1))
|
|
||||||
{
|
|
||||||
globals->aChannel[index] = nullptr;
|
|
||||||
remixFlag |= curChannel != nullptr;
|
|
||||||
while (curChannel)
|
|
||||||
{
|
|
||||||
auto tmp = curChannel->next;
|
|
||||||
FreeChannelNode(curChannel);
|
|
||||||
curChannel = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remixFlag && (dwFlags & 2) == 0 && globals->fActive)
|
|
||||||
{
|
|
||||||
globals->pfnRemix(MyWaveOutGetPosition(globals->hWaveOut, globals->fGoodGetPos), nullptr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MIXWAVE* WaveMix::OpenWave(HANDLE hMixSession, LPCSTR szWaveFilename, HINSTANCE hInst, unsigned dwFlags)
|
|
||||||
{
|
|
||||||
_MMIOINFO pmmioinfo;
|
|
||||||
_MMCKINFO pmmcki, pmmFmt;
|
|
||||||
HWAVEOUT phwo;
|
|
||||||
WAVEFORMATEX pwfx;
|
|
||||||
HMMIO hMmio = nullptr;
|
|
||||||
HGLOBAL hResData = nullptr;
|
|
||||||
HPSTR lpData = 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", MB_ICONWARNING);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mixWave = static_cast<MIXWAVE*>(GlobalLock(GlobalAlloc(GMEM_SHARE | GMEM_ZEROINIT, sizeof(MIXWAVE))));
|
|
||||||
if (!mixWave)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(
|
|
||||||
nullptr,
|
|
||||||
"Unable to allocate memory for waveform data. Try making more memory available by closing other applications.",
|
|
||||||
"WavMix32",
|
|
||||||
MB_ICONINFORMATION);
|
|
||||||
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", MB_ICONWARNING);
|
|
||||||
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", MB_ICONWARNING);
|
|
||||||
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", MB_ICONWARNING);
|
|
||||||
}
|
|
||||||
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", MB_ICONWARNING);
|
|
||||||
}
|
|
||||||
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", MB_ICONWARNING);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pmmcki.fccType = mmioFOURCC('W', 'A', 'V', 'E');
|
|
||||||
if (mmioDescend(hMmio, &pmmcki, nullptr, MMIO_FINDRIFF))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "This is not a WAVE file.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pmmFmt.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
|
||||||
if (mmioDescend(hMmio, &pmmFmt, &pmmcki, MMIO_FINDCHUNK))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "WAVE file is corrupted.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (mmioRead(hMmio, (HPSTR)mixWave, 16) != 16)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to read format chunk.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (mixWave->pcm.wf.wFormatTag != 1)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "The file is not a PCM file.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mmioAscend(hMmio, &pmmFmt, 0);
|
|
||||||
pmmFmt.ckid = mmioFOURCC('d', 'a', 't', 'a');
|
|
||||||
if (mmioDescend(hMmio, &pmmFmt, &pmmcki, MMIO_FINDCHUNK))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "WAVE file has no data chunk.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto dataSize = pmmFmt.cksize;
|
|
||||||
if (!pmmFmt.cksize)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "The data chunk has no data.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpData = static_cast<HPSTR>(GlobalLock(GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, 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",
|
|
||||||
MB_ICONINFORMATION);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto readCount = mmioRead(hMmio, lpData, dataSize);
|
|
||||||
if (readCount != static_cast<LONG>(dataSize))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to read data chunk.", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lpData = WaveFormatConvert(&Globals->PCM, &mixWave->pcm, lpData, &dataSize);
|
|
||||||
if (!lpData)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to convert wave format.", "WavMix32", MB_ICONWARNING);
|
|
||||||
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->pcm, &Globals->PCM, sizeof(PCMWAVEFORMAT));
|
|
||||||
|
|
||||||
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 (lpData)
|
|
||||||
{
|
|
||||||
GlobalUnlock(GlobalHandle(lpData));
|
|
||||||
GlobalFree(GlobalHandle(lpData));
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::Activate(HANDLE hMixSession, bool fActivate)
|
|
||||||
{
|
|
||||||
GLOBALS* globals = SessionToGlobalDataPtr(hMixSession);
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return 5;
|
|
||||||
if (fActivate)
|
|
||||||
{
|
|
||||||
if (GlobalsActive)
|
|
||||||
return GlobalsActive != globals ? 4 : 0;
|
|
||||||
if (globals->SettingsDialogActiveFlag)
|
|
||||||
return 12;
|
|
||||||
GlobalsActive = globals;
|
|
||||||
sndPlaySoundA(nullptr, 0);
|
|
||||||
auto result = GetWaveDevice();
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
GlobalsActive = nullptr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
Globals->fActive = 1;
|
|
||||||
SetWaveOutPosition(Globals->dwCurrentSample);
|
|
||||||
XWAVEHDR* xHDR;
|
|
||||||
do
|
|
||||||
xHDR = GetWaveBlock();
|
|
||||||
while (MixerPlay(xHDR, 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (globals->fActive)
|
|
||||||
{
|
|
||||||
Globals->dwCurrentSample = MyWaveOutGetPosition(globals->hWaveOut, globals->fGoodGetPos);
|
|
||||||
}
|
|
||||||
ReleaseWaveDevice(globals);
|
|
||||||
Globals->fActive = 0;
|
|
||||||
if (Globals == GlobalsActive)
|
|
||||||
GlobalsActive = nullptr;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
++play_counter;
|
|
||||||
auto result = 12;
|
|
||||||
auto remixFlag = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (play_counter > 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!lpMixPlayParams)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "NULL parameters pointer passed to WaveMixPlay!", "WavMix32", MB_ICONWARNING);
|
|
||||||
result = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto globals = SessionToGlobalDataPtr(lpMixPlayParams->hMixSession);
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Invalid session handle passed to WaveMixPlay", "WavMix32", MB_ICONWARNING);
|
|
||||||
result = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsValidLPMIXWAVE(lpMixPlayParams->lpMixWave))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Invalid or NULL wave pointer passed to WaveMixPlay!", "WavMix32", MB_ICONWARNING);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasCurrentOutputFormat(lpMixPlayParams->lpMixWave))
|
|
||||||
{
|
|
||||||
wsprintfA(
|
|
||||||
string_buffer,
|
|
||||||
"The LPMIXWAVE 0x%lx is not in the current output format, close the wave and reopen it.",
|
|
||||||
lpMixPlayParams->lpMixWave);
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONWARNING);
|
|
||||||
result = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!globals->fActive)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Wave device not allocated, call WaveMixActivate(hMixSession,TRUE)", "WavMix32",
|
|
||||||
MB_ICONWARNING);
|
|
||||||
result = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!globals->iChannels)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "You must open a channel before you can play a wave!", "WavMix32", MB_ICONWARNING);
|
|
||||||
result = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int iChannel;
|
|
||||||
if ((lpMixPlayParams->dwFlags & WMIX_USELRUCHANNEL) != 0)
|
|
||||||
{
|
|
||||||
iChannel = 0;
|
|
||||||
for (auto channelIndex = 0; channelIndex < 16; ++channelIndex)
|
|
||||||
{
|
|
||||||
if (globals->aChannel[channelIndex] != reinterpret_cast<CHANNELNODE*>(-1))
|
|
||||||
{
|
|
||||||
if (!globals->aChannel[iChannel])
|
|
||||||
break;
|
|
||||||
if (channelIndex != iChannel && globals->MRUChannel[channelIndex] < globals->MRUChannel[iChannel])
|
|
||||||
iChannel = channelIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lpMixPlayParams->iChannel = iChannel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iChannel = lpMixPlayParams->iChannel;
|
|
||||||
}
|
|
||||||
++globals->dwMRU;
|
|
||||||
globals->MRUChannel[iChannel] = globals->dwMRU;
|
|
||||||
if (globals->aChannel[iChannel] == reinterpret_cast<CHANNELNODE*>(-1))
|
|
||||||
{
|
|
||||||
result = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto channel = GetChannelNode();
|
|
||||||
if (!channel)
|
|
||||||
break;
|
|
||||||
|
|
||||||
memcpy(&channel->PlayParams, lpMixPlayParams, sizeof channel->PlayParams);
|
|
||||||
channel->lpMixWave = channel->PlayParams.lpMixWave;
|
|
||||||
channel->dwNumSamples = channel->PlayParams.lpMixWave->wh.dwBufferLength;
|
|
||||||
auto lpData = (uint8_t*)channel->PlayParams.lpMixWave->wh.lpData;
|
|
||||||
channel->lpPos = lpData;
|
|
||||||
channel->lpEnd = &lpData[channel->dwNumSamples - globals->PCM.wf.nBlockAlign];
|
|
||||||
channel->PlayParams.iChannel = iChannel;
|
|
||||||
if (globals->pWaitList)
|
|
||||||
{
|
|
||||||
channel->next = globals->pWaitList->next;
|
|
||||||
globals->pWaitList->next = channel;
|
|
||||||
globals->pWaitList = channel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
globals->pWaitList = channel;
|
|
||||||
channel->next = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((channel->PlayParams.dwFlags & WMIX_WAIT) != 0)
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResetWavePosIfNoChannelData();
|
|
||||||
auto globals2 = Globals;
|
|
||||||
unsigned wavePosition;
|
|
||||||
if (Globals->pfnRemix == ResetRemix)
|
|
||||||
{
|
|
||||||
wavePosition = MyWaveOutGetPosition(Globals->hWaveOut, Globals->fGoodGetPos);
|
|
||||||
globals2 = Globals;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wavePosition = Globals->dwCurrentSample;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (globals2->pWaitList)
|
|
||||||
{
|
|
||||||
auto curChannel = globals2->pWaitList->next;
|
|
||||||
if (globals2->pWaitList->next == globals2->pWaitList)
|
|
||||||
globals2->pWaitList = nullptr;
|
|
||||||
else
|
|
||||||
globals2->pWaitList->next = curChannel->next;
|
|
||||||
|
|
||||||
iChannel = curChannel->PlayParams.iChannel;
|
|
||||||
curChannel->next = nullptr;
|
|
||||||
if ((curChannel->PlayParams.dwFlags & WMIX_CustomVolume) != 0)
|
|
||||||
{
|
|
||||||
curChannel->Volume.L = curChannel->PlayParams.Volume.L;
|
|
||||||
curChannel->Volume.R = curChannel->PlayParams.Volume.R;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
curChannel->Volume.L = globals2->ChannelVolume[iChannel].L;
|
|
||||||
curChannel->Volume.R = globals2->ChannelVolume[iChannel].R;
|
|
||||||
}
|
|
||||||
if (curChannel->Volume.L > 10u)
|
|
||||||
curChannel->Volume.L = 10;
|
|
||||||
if (curChannel->Volume.R > 10u)
|
|
||||||
curChannel->Volume.R = 10;
|
|
||||||
|
|
||||||
if ((curChannel->PlayParams.dwFlags & WMIX_CLEARQUEUE) != 0)
|
|
||||||
{
|
|
||||||
for (auto tmpCh = globals2->aChannel[iChannel]; tmpCh;)
|
|
||||||
{
|
|
||||||
auto nextChannel = tmpCh->next;
|
|
||||||
FreeChannelNode(tmpCh);
|
|
||||||
tmpCh = nextChannel;
|
|
||||||
}
|
|
||||||
globals2->aChannel[iChannel] = curChannel;
|
|
||||||
if (play_queue.first != nullptr)
|
|
||||||
remixFlag = 1;
|
|
||||||
if ((curChannel->PlayParams.dwFlags & WMIX_HIPRIORITY) != 0)
|
|
||||||
curChannel->dwStartPos = wavePosition;
|
|
||||||
else
|
|
||||||
curChannel->dwStartPos = globals2->dwCurrentSample;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD dwStartPos;
|
|
||||||
if (globals2->aChannel[iChannel])
|
|
||||||
{
|
|
||||||
auto tmpCh = globals2->aChannel[iChannel];
|
|
||||||
while (tmpCh->next)
|
|
||||||
tmpCh = tmpCh->next;
|
|
||||||
tmpCh->next = curChannel;
|
|
||||||
dwStartPos = tmpCh->dwEndPos;
|
|
||||||
|
|
||||||
if ((curChannel->PlayParams.dwFlags & WMIX_HIPRIORITY) != 0)
|
|
||||||
{
|
|
||||||
if (dwStartPos <= wavePosition)
|
|
||||||
dwStartPos = wavePosition;
|
|
||||||
}
|
|
||||||
else if (globals2->dwCurrentSample > dwStartPos)
|
|
||||||
{
|
|
||||||
dwStartPos = globals2->dwCurrentSample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dwStartPos = wavePosition;
|
|
||||||
globals2->aChannel[iChannel] = curChannel;
|
|
||||||
if ((curChannel->PlayParams.dwFlags & WMIX_HIPRIORITY) == 0)
|
|
||||||
dwStartPos = globals2->dwCurrentSample;
|
|
||||||
}
|
|
||||||
curChannel->dwStartPos = dwStartPos;
|
|
||||||
if (globals2->dwCurrentSample > curChannel->dwStartPos)
|
|
||||||
remixFlag = 1;
|
|
||||||
}
|
|
||||||
if (curChannel->PlayParams.wLoops == 0xFFFF)
|
|
||||||
curChannel->dwEndPos = -1;
|
|
||||||
else
|
|
||||||
curChannel->dwEndPos = curChannel->dwStartPos + curChannel->dwNumSamples * (curChannel->PlayParams.
|
|
||||||
wLoops + 1) - globals2->PCM.wf.nBlockAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!remixFlag || !globals2->pfnRemix(wavePosition, nullptr))
|
|
||||||
{
|
|
||||||
int pauseFlag;
|
|
||||||
if (play_queue.first || globals2->PauseBlocks <= 0)
|
|
||||||
{
|
|
||||||
pauseFlag = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
waveOutPause(globals2->hWaveOut);
|
|
||||||
pauseFlag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pauseCounter = 0;
|
|
||||||
while (MixerPlay(GetWaveBlock(), 1))
|
|
||||||
{
|
|
||||||
if (pauseFlag)
|
|
||||||
{
|
|
||||||
if (++pauseCounter >= Globals->PauseBlocks)
|
|
||||||
{
|
|
||||||
waveOutRestart(Globals->hWaveOut);
|
|
||||||
pauseFlag = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pauseFlag)
|
|
||||||
waveOutRestart(Globals->hWaveOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
while (false);
|
|
||||||
|
|
||||||
--play_counter;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLOBALS* WaveMix::SessionToGlobalDataPtr(HANDLE hMixSession)
|
|
||||||
{
|
|
||||||
auto globals = static_cast<GLOBALS*>(hMixSession);
|
|
||||||
if (hMixSession && globals->wMagic1 == 21554 && globals->wMagic2 == 21554)
|
|
||||||
return globals;
|
|
||||||
MessageBeep(0xFFFFFFFF);
|
|
||||||
wsprintfA(string_buffer, "Invalid session handle 0x%04X passed to WaveMix API", hMixSession);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONWARNING);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::Startup(HMODULE hModule)
|
|
||||||
{
|
|
||||||
WNDCLASSA WndClass;
|
|
||||||
|
|
||||||
if (initialized_flag)
|
|
||||||
return 1;
|
|
||||||
if (!SetIniFileName(hModule))
|
|
||||||
return 0;
|
|
||||||
InitVolumeTable();
|
|
||||||
debug_flag = GetPrivateProfileIntA("general", "debug", 0, FileName);
|
|
||||||
cmixit_ptr = cmixit;
|
|
||||||
HModule = hModule;
|
|
||||||
|
|
||||||
WndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW);
|
|
||||||
WndClass.hIcon = nullptr;
|
|
||||||
WndClass.lpszMenuName = nullptr;
|
|
||||||
WndClass.lpszClassName = "WavMix32";
|
|
||||||
WndClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(1));
|
|
||||||
WndClass.hInstance = HModule;
|
|
||||||
WndClass.style = 0;
|
|
||||||
WndClass.lpfnWndProc = WndProc;
|
|
||||||
WndClass.cbWndExtra = 0;
|
|
||||||
WndClass.cbClsExtra = 0;
|
|
||||||
if (!RegisterClassA(&WndClass))
|
|
||||||
return 0;
|
|
||||||
InitChannelNodes();
|
|
||||||
initialized_flag = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::SetIniFileName(HMODULE hModule)
|
|
||||||
{
|
|
||||||
int result = GetModuleFileNameA(hModule, FileName, 0x104u);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
char* i;
|
|
||||||
for (i = &FileName[result]; *i != '\\'; --i)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*i = 0;
|
|
||||||
lstrcpyA(i, "\\WAVEMIX.INF");
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::InitChannelNodes()
|
|
||||||
{
|
|
||||||
CHANNELNODE* channelPtr = channel_nodes;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
channelPtr->next = channelPtr + 1;
|
|
||||||
++channelPtr;
|
|
||||||
}
|
|
||||||
while (channelPtr < &channel_nodes[MAXQUEUEDWAVES - 2]);
|
|
||||||
channel_nodes[MAXQUEUEDWAVES - 1].next = nullptr;
|
|
||||||
free_channel_nodes = channel_nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::InitVolumeTable()
|
|
||||||
{
|
|
||||||
int index3Sub = 0;
|
|
||||||
for (auto volume = 0; volume < 11; volume++)
|
|
||||||
{
|
|
||||||
auto tablePtr = &volume_table[volume][0];
|
|
||||||
for (auto divSmth = index3Sub, sample = 0; sample < 256; ++sample)
|
|
||||||
{
|
|
||||||
tablePtr[sample] = static_cast<unsigned char>(divSmth / 10 + 128);
|
|
||||||
divSmth += volume;
|
|
||||||
}
|
|
||||||
index3Sub -= 128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::ShowWaveOutDevices()
|
|
||||||
{
|
|
||||||
tagWAVEOUTCAPSA pwoc{};
|
|
||||||
|
|
||||||
auto deviceCount = waveOutGetNumDevs();
|
|
||||||
if (deviceCount)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d waveOut Devices have been detected on your system.", deviceCount);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
for (auto uDeviceID = 0u; uDeviceID < deviceCount; ++uDeviceID)
|
|
||||||
{
|
|
||||||
if (!waveOutGetDevCapsA(uDeviceID, &pwoc, 0x34u) && RemoveInvalidIniNameCharacters(pwoc.szPname))
|
|
||||||
wsprintfA(
|
|
||||||
string_buffer,
|
|
||||||
"Device %i: %s\n\tVersion %u.%u",
|
|
||||||
uDeviceID,
|
|
||||||
pwoc.szPname,
|
|
||||||
HIBYTE(pwoc.vDriverVersion),
|
|
||||||
LOBYTE(pwoc.vDriverVersion));
|
|
||||||
else
|
|
||||||
wsprintfA(string_buffer, "waveOutGetDevCaps failed (err %u) for device %d", 1, uDeviceID);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::RemoveInvalidIniNameCharacters(char* lpString)
|
|
||||||
{
|
|
||||||
auto stringPtr = lpString;
|
|
||||||
if (!lpString || !*lpString)
|
|
||||||
return 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!isalnum(*stringPtr) && !isspace(*stringPtr))
|
|
||||||
break;
|
|
||||||
++stringPtr;
|
|
||||||
}
|
|
||||||
while (*stringPtr);
|
|
||||||
|
|
||||||
do
|
|
||||||
*stringPtr-- = 0;
|
|
||||||
while (stringPtr >= lpString && isspace(*stringPtr));
|
|
||||||
return lstrlenA(lpString);
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::ReadConfigSettings(MIXCONFIG* lpConfig)
|
|
||||||
{
|
|
||||||
auto waveDeviceCount = waveOutGetNumDevs();
|
|
||||||
if (!waveDeviceCount)
|
|
||||||
return 0;
|
|
||||||
if ((lpConfig->dwFlags & 0x400) != 0 && ReadRegistryForAppSpecificConfigs(lpConfig))
|
|
||||||
{
|
|
||||||
Configure(Globals, nullptr, lpConfig, nullptr, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT deviceId;
|
|
||||||
if (static_cast<char>(lpConfig->dwFlags) >= 0)
|
|
||||||
{
|
|
||||||
deviceId = GetPrivateProfileIntA("general", "WaveOutDevice", 0, FileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deviceId = lpConfig->wDeviceID;
|
|
||||||
}
|
|
||||||
Globals->wDeviceID = deviceId;
|
|
||||||
if (Globals->wDeviceID >= waveDeviceCount)
|
|
||||||
Globals->wDeviceID = 0;
|
|
||||||
|
|
||||||
if (waveOutGetDevCapsA(Globals->wDeviceID, &Globals->WaveoutCaps, 0x34u)
|
|
||||||
|| !RemoveInvalidIniNameCharacters(Globals->WaveoutCaps.szPname))
|
|
||||||
{
|
|
||||||
lstrcpyA(Globals->WaveoutCaps.szPname, "Unkown Device");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ReadRegistryToGetMachineSpecificInfSection(Globals->wDeviceID, Globals->szDevicePName, 96))
|
|
||||||
{
|
|
||||||
lstrcpyA(Globals->szDevicePName, GetOperatingSystemPrefix());
|
|
||||||
lstrcatA(Globals->szDevicePName, Globals->WaveoutCaps.szPname);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto remix = GetPrivateProfileIntA("default", "Remix", 1, FileName);
|
|
||||||
auto goodWavePos = GetPrivateProfileIntA("default", "GoodWavePos", DefaultGoodWavePos(Globals->wDeviceID),
|
|
||||||
FileName);
|
|
||||||
auto waveBlocks = GetPrivateProfileIntA("default", "WaveBlocks", 3, FileName);
|
|
||||||
auto samplesPerSec = GetPrivateProfileIntA("default", "SamplesPerSec", 11, FileName);
|
|
||||||
if ((Globals->WaveoutCaps.dwSupport & 0x10) != 0)
|
|
||||||
{
|
|
||||||
if (!ShowDebugDialogs)
|
|
||||||
return 0;
|
|
||||||
wsprintfA(string_buffer,
|
|
||||||
"%s is a syncronous (blocking) wave output device. This will not permit audio to play while other applications are running.",
|
|
||||||
Globals->WaveoutCaps.szPname);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (GetPrivateProfileIntA("not compatible", Globals->szDevicePName, 0, FileName))
|
|
||||||
{
|
|
||||||
if (!ShowDebugDialogs)
|
|
||||||
return 0;
|
|
||||||
wsprintfA(string_buffer, "%s is not compatible with the realtime wavemixer.", Globals->szDevicePName);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Globals->pfnRemix = GetPrivateProfileIntA(Globals->szDevicePName, "Remix", remix, FileName) != 2
|
|
||||||
? ResetRemix
|
|
||||||
: NoResetRemix;
|
|
||||||
Globals->fGoodGetPos = GetPrivateProfileIntA(Globals->szDevicePName, "GoodWavePos", goodWavePos, FileName) != 0;
|
|
||||||
Globals->WaveBlockCount = GetPrivateProfileIntA(Globals->szDevicePName, "WaveBlocks", waveBlocks, FileName);
|
|
||||||
if (Globals->WaveBlockCount < 2)
|
|
||||||
Globals->WaveBlockCount = 2;
|
|
||||||
else if (Globals->WaveBlockCount > 10)
|
|
||||||
Globals->WaveBlockCount = 10;
|
|
||||||
|
|
||||||
Globals->PauseBlocks = GetPrivateProfileIntA(Globals->szDevicePName, "PauseBlocks",
|
|
||||||
DefaultPauseBlocks(Globals->WaveBlockCount), FileName);
|
|
||||||
if (Globals->PauseBlocks >= 0)
|
|
||||||
{
|
|
||||||
if (Globals->PauseBlocks > Globals->WaveBlockCount)
|
|
||||||
Globals->PauseBlocks = Globals->WaveBlockCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Globals->PauseBlocks = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto samplesPerSec2 = GetPrivateProfileIntA(Globals->szDevicePName, "SamplesPerSec", samplesPerSec, FileName);
|
|
||||||
auto channels = GetPrivateProfileIntA(Globals->szDevicePName, "Channels", 1, FileName);
|
|
||||||
Globals->PCM.wf.nChannels = channels;
|
|
||||||
if (channels)
|
|
||||||
{
|
|
||||||
if (channels > 2u)
|
|
||||||
Globals->PCM.wf.nChannels = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Globals->PCM.wf.nChannels = 1;
|
|
||||||
}
|
|
||||||
DWORD nAvgBytesPerSec;
|
|
||||||
if (samplesPerSec2 == 22)
|
|
||||||
{
|
|
||||||
Globals->PCM.wf.nSamplesPerSec = 22050;
|
|
||||||
nAvgBytesPerSec = 22050 * Globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
else if (samplesPerSec2 == 44)
|
|
||||||
{
|
|
||||||
Globals->PCM.wf.nSamplesPerSec = 44100;
|
|
||||||
nAvgBytesPerSec = 44100 * Globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nAvgBytesPerSec = 11025 * Globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
Globals->PCM.wf.nAvgBytesPerSec = nAvgBytesPerSec;
|
|
||||||
auto waveBlockLen2 = GetPrivateProfileIntA("default", "WaveBlockLen", 0, FileName);
|
|
||||||
Globals->dwWaveBlockLen = FigureOutDMABufferSize(waveBlockLen2, &Globals->PCM);
|
|
||||||
Configure(Globals, nullptr, lpConfig, nullptr, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::ReadRegistryForAppSpecificConfigs(MIXCONFIG* lpConfig)
|
|
||||||
{
|
|
||||||
HKEY phkResult;
|
|
||||||
CHAR SubKey[52];
|
|
||||||
|
|
||||||
DWORD dwFlags = lpConfig->dwFlags;
|
|
||||||
if ((dwFlags & 0x400) == 0 || !lpConfig->RegistryKey)
|
|
||||||
return 0;
|
|
||||||
if ((dwFlags & 0x80u) == 0)
|
|
||||||
{
|
|
||||||
lpConfig->wDeviceID = Globals->wDeviceID;
|
|
||||||
}
|
|
||||||
else if (lpConfig->wDeviceID >= waveOutGetNumDevs())
|
|
||||||
{
|
|
||||||
lpConfig->wDeviceID = 0;
|
|
||||||
}
|
|
||||||
wsprintfA(SubKey, "WaveMix\\Device%u", lpConfig->wDeviceID);
|
|
||||||
if (RegOpenKeyA(lpConfig->RegistryKey, SubKey, &phkResult))
|
|
||||||
return 0;
|
|
||||||
if ((dwFlags & 1) == 0)
|
|
||||||
lpConfig->wChannels = ReadRegistryInt(phkResult, "Channels", 1);
|
|
||||||
if ((dwFlags & 2) == 0)
|
|
||||||
lpConfig->wSamplingRate = ReadRegistryInt(phkResult, "SamplesPerSec", 11);
|
|
||||||
if ((dwFlags & 4) == 0)
|
|
||||||
lpConfig->WaveBlockCount = static_cast<short>(ReadRegistryInt(phkResult, "WaveBlocks", 3));
|
|
||||||
if ((dwFlags & 8) == 0)
|
|
||||||
lpConfig->WaveBlockLen = static_cast<short>(ReadRegistryInt(phkResult, "WaveBlockLen", 0));
|
|
||||||
lpConfig->CmixPtrDefaultFlag = 1;
|
|
||||||
if ((dwFlags & 0x20) == 0)
|
|
||||||
lpConfig->ResetMixDefaultFlag = static_cast<uint16_t>(ReadRegistryInt(phkResult, "Remix", 1)) != 2;
|
|
||||||
if ((dwFlags & 0x40) == 0)
|
|
||||||
{
|
|
||||||
int defaultGoodWavePos = DefaultGoodWavePos(lpConfig->wDeviceID);
|
|
||||||
lpConfig->GoodWavePos = static_cast<uint16_t>(ReadRegistryInt(
|
|
||||||
phkResult, "GoodWavePos", defaultGoodWavePos)) != 0;
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x100) == 0)
|
|
||||||
lpConfig->ShowDebugDialogs = static_cast<short>(ReadRegistryInt(phkResult, "ShowDebugDialogs", 0));
|
|
||||||
if ((dwFlags & 0x200) == 0)
|
|
||||||
{
|
|
||||||
int defaultPauseBlocks = DefaultPauseBlocks(static_cast<uint16_t>(lpConfig->WaveBlockCount));
|
|
||||||
lpConfig->PauseBlocks = static_cast<short>(ReadRegistryInt(phkResult, "PauseBlocks", defaultPauseBlocks));
|
|
||||||
}
|
|
||||||
lpConfig->dwFlags = 1023;
|
|
||||||
waveOutGetDevCapsA(lpConfig->wDeviceID, &Globals->WaveoutCaps, 0x34u);
|
|
||||||
RegCloseKey(phkResult);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::ReadRegistryInt(HKEY hKey, LPCSTR lpSubKey, int defaultValue)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
LONG cbData = 10;
|
|
||||||
char Data[12];
|
|
||||||
|
|
||||||
if (!hKey || RegQueryValueA(hKey, lpSubKey, Data, &cbData))
|
|
||||||
result = defaultValue;
|
|
||||||
else
|
|
||||||
result = atol(Data);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::DefaultGoodWavePos(unsigned uDeviceID)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
struct tagWAVEOUTCAPSA pwoc{};
|
|
||||||
|
|
||||||
auto deviceCount = waveOutGetNumDevs();
|
|
||||||
if (uDeviceID > deviceCount || (uDeviceID & 0x80000000) != 0 ||
|
|
||||||
!deviceCount || waveOutGetDevCapsA(uDeviceID, &pwoc, 0x34u))
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = LOBYTE(pwoc.dwSupport) >> 5 & 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning (disable : 4996)/*Original uses GetVersion*/
|
|
||||||
int WaveMix::DefaultPauseBlocks(int waveBlocks)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if (GetVersion() < 0x80000000 || static_cast<uint8_t>(GetVersion()) < 4u)
|
|
||||||
result = waveBlocks;
|
|
||||||
else
|
|
||||||
result = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#pragma warning (default : 4996)
|
|
||||||
|
|
||||||
int WaveMix::Configure(GLOBALS* hMixSession, HWND hWndParent, MIXCONFIG* lpConfig, int* flag1Ptr, int saveConfigFlag)
|
|
||||||
{
|
|
||||||
MIXCONFIG mixConfigLocal{};
|
|
||||||
tagWAVEOUTCAPSA pwoc{};
|
|
||||||
|
|
||||||
auto mixConfig = lpConfig;
|
|
||||||
auto someFlag1 = 0;
|
|
||||||
auto globals = SessionToGlobalDataPtr(hMixSession);
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return 5;
|
|
||||||
if (globals->fActive)
|
|
||||||
return 4;
|
|
||||||
if (globals->SettingsDialogActiveFlag)
|
|
||||||
return 12;
|
|
||||||
FlushChannel(hMixSession, -1, 1u);
|
|
||||||
|
|
||||||
if (!mixConfig)
|
|
||||||
{
|
|
||||||
mixConfigLocal.wSize = sizeof(MIXCONFIG);
|
|
||||||
mixConfigLocal.dwFlags = 1023;
|
|
||||||
GetConfig(static_cast<GLOBALS*>(hMixSession), &mixConfigLocal);
|
|
||||||
auto dialog = MakeSettingsDlgTemplate();
|
|
||||||
if (!dialog)
|
|
||||||
return 1;
|
|
||||||
Globals->SettingsDialogActiveFlag = 1;
|
|
||||||
auto dlgResult = DialogBoxIndirectParamA(HModule, &dialog->Dialog, hWndParent, SettingsDlgProc,
|
|
||||||
(LPARAM)&mixConfigLocal);
|
|
||||||
DestroySettingsDlgTemplate(dialog);
|
|
||||||
Globals->SettingsDialogActiveFlag = 0;
|
|
||||||
if (dlgResult != 1)
|
|
||||||
return 1;
|
|
||||||
if (Globals->dwWaveBlockLen == mixConfigLocal.WaveBlockLen)
|
|
||||||
mixConfigLocal.dwFlags &= 0xFFFFFFF7;
|
|
||||||
|
|
||||||
mixConfig = &mixConfigLocal;
|
|
||||||
}
|
|
||||||
if (!mixConfig->dwFlags)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
globals = SessionToGlobalDataPtr(hMixSession);
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
auto dwFlags = mixConfig->dwFlags;
|
|
||||||
if ((dwFlags & 0x100) != 0)
|
|
||||||
ShowDebugDialogs = mixConfig->ShowDebugDialogs != 0;
|
|
||||||
if ((dwFlags & 0x80u) != 0)
|
|
||||||
{
|
|
||||||
if (mixConfig->wDeviceID != globals->wDeviceID)
|
|
||||||
{
|
|
||||||
auto result = waveOutGetDevCapsA(mixConfig->wDeviceID, &pwoc, 0x34u);
|
|
||||||
if (result)
|
|
||||||
return result;
|
|
||||||
memcpy(&Globals->WaveoutCaps, &pwoc, sizeof Globals->WaveoutCaps);
|
|
||||||
Globals->wDeviceID = mixConfig->wDeviceID;
|
|
||||||
if (Globals->WaveoutCaps.wChannels == 1 && Globals->PCM.wf.nChannels == 2)
|
|
||||||
{
|
|
||||||
Globals->PCM.wf.nChannels = 1;
|
|
||||||
someFlag1 = 1;
|
|
||||||
Globals->PCM.wf.nBlockAlign = 1;
|
|
||||||
Globals->PCM.wf.nAvgBytesPerSec = Globals->PCM.wf.nSamplesPerSec;
|
|
||||||
}
|
|
||||||
lstrcpyA(globals->szDevicePName, pwoc.szPname);
|
|
||||||
if (!RemoveInvalidIniNameCharacters(Globals->szDevicePName))
|
|
||||||
lstrcpyA(Globals->szDevicePName, "Unkown Device");
|
|
||||||
if (!ReadRegistryToGetMachineSpecificInfSection(Globals->wDeviceID, Globals->szDevicePName, 96))
|
|
||||||
{
|
|
||||||
lstrcpyA(Globals->szDevicePName, GetOperatingSystemPrefix());
|
|
||||||
lstrcatA(Globals->szDevicePName, Globals->WaveoutCaps.szPname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dwFlags & 1) != 0)
|
|
||||||
{
|
|
||||||
if (mixConfig->wChannels <= 1u)
|
|
||||||
{
|
|
||||||
if (globals->PCM.wf.nChannels == 2)
|
|
||||||
someFlag1 = 1;
|
|
||||||
globals->PCM.wf.nChannels = 1;
|
|
||||||
globals->PCM.wf.nBlockAlign = 1;
|
|
||||||
globals->PCM.wf.nAvgBytesPerSec = globals->PCM.wf.nSamplesPerSec;
|
|
||||||
}
|
|
||||||
if (globals->WaveoutCaps.wChannels > 1u)
|
|
||||||
{
|
|
||||||
if (globals->PCM.wf.nChannels == 1)
|
|
||||||
someFlag1 = 1;
|
|
||||||
globals->PCM.wf.nChannels = 2;
|
|
||||||
globals->PCM.wf.nBlockAlign = 2;
|
|
||||||
globals->PCM.wf.nAvgBytesPerSec = 2 * globals->PCM.wf.nSamplesPerSec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dwFlags & 2) != 0)
|
|
||||||
{
|
|
||||||
auto nAvgBytesPerSec = 0u;
|
|
||||||
if (mixConfig->wSamplingRate == 22)
|
|
||||||
{
|
|
||||||
if (globals->PCM.wf.nSamplesPerSec != 22050)
|
|
||||||
someFlag1 = 1;
|
|
||||||
globals->PCM.wf.nSamplesPerSec = 22050;
|
|
||||||
nAvgBytesPerSec = 22050 * globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mixConfig->wSamplingRate == 44)
|
|
||||||
{
|
|
||||||
if (globals->PCM.wf.nSamplesPerSec != 44100)
|
|
||||||
someFlag1 = 1;
|
|
||||||
globals->PCM.wf.nSamplesPerSec = 44100;
|
|
||||||
nAvgBytesPerSec = 44100 * globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (globals->PCM.wf.nSamplesPerSec != 11025)
|
|
||||||
someFlag1 = 1;
|
|
||||||
globals->PCM.wf.nSamplesPerSec = 11025;
|
|
||||||
nAvgBytesPerSec = 11025 * globals->PCM.wf.nChannels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
globals->PCM.wf.nAvgBytesPerSec = nAvgBytesPerSec;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dwFlags & 4) != 0)
|
|
||||||
{
|
|
||||||
auto v24 = 2;
|
|
||||||
globals->WaveBlockCount = mixConfig->WaveBlockCount;
|
|
||||||
if (mixConfig->WaveBlockCount < 2)
|
|
||||||
globals->WaveBlockCount = 2;
|
|
||||||
else if (mixConfig->WaveBlockCount > 10)
|
|
||||||
globals->WaveBlockCount = 10;
|
|
||||||
if (globals->PauseBlocks >= 0)
|
|
||||||
{
|
|
||||||
if (globals->PauseBlocks > globals->WaveBlockCount)
|
|
||||||
globals->PauseBlocks = globals->WaveBlockCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
globals->PauseBlocks = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (someFlag1)
|
|
||||||
globals->dwWaveBlockLen = FigureOutDMABufferSize(0, &globals->PCM);
|
|
||||||
|
|
||||||
if ((dwFlags & 8) != 0)
|
|
||||||
{
|
|
||||||
if (mixConfig->WaveBlockLen)
|
|
||||||
globals->dwWaveBlockLen = mixConfig->WaveBlockLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globals->dwWaveBlockLen < 344)
|
|
||||||
globals->dwWaveBlockLen = 344;
|
|
||||||
else if (globals->dwWaveBlockLen > 11025)
|
|
||||||
globals->dwWaveBlockLen = 11025;
|
|
||||||
|
|
||||||
auto dwFlags2 = dwFlags;
|
|
||||||
if ((dwFlags & 0x10) != 0)
|
|
||||||
globals->CmixPtr = cmixit;
|
|
||||||
|
|
||||||
if ((dwFlags2 & 0x20) != 0)
|
|
||||||
{
|
|
||||||
globals->pfnRemix = !mixConfig->ResetMixDefaultFlag ? NoResetRemix : ResetRemix;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dwFlags2 & 0x40) != 0)
|
|
||||||
globals->fGoodGetPos = mixConfig->GoodWavePos != 0;
|
|
||||||
|
|
||||||
if ((dwFlags2 & 0x200) != 0)
|
|
||||||
{
|
|
||||||
globals->PauseBlocks = mixConfig->PauseBlocks;
|
|
||||||
if (mixConfig->PauseBlocks > globals->WaveBlockCount)
|
|
||||||
globals->PauseBlocks = globals->WaveBlockCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetConfig(hMixSession, mixConfig);
|
|
||||||
if (flag1Ptr)
|
|
||||||
*flag1Ptr = someFlag1;
|
|
||||||
if (saveConfigFlag)
|
|
||||||
SaveConfigSettings(dwFlags);
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
ShowCurrentSettings();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::GetConfig(HANDLE hMixSession, MIXCONFIG* lpConfig)
|
|
||||||
{
|
|
||||||
GLOBALS* globals = SessionToGlobalDataPtr(static_cast<GLOBALS*>(hMixSession));
|
|
||||||
Globals = globals;
|
|
||||||
if (!globals)
|
|
||||||
return 5;
|
|
||||||
if (!lpConfig)
|
|
||||||
return 11;
|
|
||||||
|
|
||||||
DWORD dwFlags = lpConfig->dwFlags;
|
|
||||||
if ((dwFlags & 1) != 0)
|
|
||||||
lpConfig->wChannels = globals->PCM.wf.nChannels;
|
|
||||||
if ((dwFlags & 2) != 0)
|
|
||||||
lpConfig->wSamplingRate = static_cast<WORD>(11 * (globals->PCM.wf.nSamplesPerSec / 0x2B11));
|
|
||||||
if ((dwFlags & 4) != 0)
|
|
||||||
lpConfig->WaveBlockCount = globals->WaveBlockCount;
|
|
||||||
if ((dwFlags & 8) != 0)
|
|
||||||
lpConfig->WaveBlockLen = static_cast<WORD>(globals->dwWaveBlockLen);
|
|
||||||
if ((dwFlags & 0x10) != 0)
|
|
||||||
lpConfig->CmixPtrDefaultFlag = globals->CmixPtr == cmixit;
|
|
||||||
if ((dwFlags & 0x20) != 0)
|
|
||||||
lpConfig->ResetMixDefaultFlag = globals->pfnRemix == ResetRemix;
|
|
||||||
if ((dwFlags & 0x40) != 0)
|
|
||||||
lpConfig->GoodWavePos = globals->fGoodGetPos;
|
|
||||||
if ((dwFlags & 0x80u) != 0)
|
|
||||||
lpConfig->wDeviceID = globals->wDeviceID;
|
|
||||||
if ((dwFlags & 0x100) != 0)
|
|
||||||
lpConfig->ShowDebugDialogs = ShowDebugDialogs != 0;
|
|
||||||
if ((dwFlags & 0x200) != 0)
|
|
||||||
lpConfig->PauseBlocks = globals->PauseBlocks;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned WaveMix::MyWaveOutGetPosition(HWAVEOUT hWaveOut, int fGoodGetPos)
|
|
||||||
{
|
|
||||||
mmtime_tag pmmt{};
|
|
||||||
|
|
||||||
if (!fGoodGetPos)
|
|
||||||
return (timeGetTime() - Globals->dwBaseTime) * Globals->PCM.wf.nAvgBytesPerSec / 0x3E8 & 0xFFFFFFF8;
|
|
||||||
pmmt.wType = TIME_BYTES;
|
|
||||||
waveOutGetPosition(hWaveOut, &pmmt, 0xCu);
|
|
||||||
return Globals->pfnSampleAdjust(pmmt.u.ms, Globals->dwWaveOutPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::FreeChannelNode(CHANNELNODE* channel)
|
|
||||||
{
|
|
||||||
if (channel)
|
|
||||||
{
|
|
||||||
channel->next = free_channel_nodes;
|
|
||||||
free_channel_nodes = channel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::ResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel)
|
|
||||||
{
|
|
||||||
Globals->dwCurrentSample = dwRemixSamplePos;
|
|
||||||
DestroyPlayQueue();
|
|
||||||
SwapWaveBlocks();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
auto block = GetWaveBlock();
|
|
||||||
if (!block)
|
|
||||||
break;
|
|
||||||
if (!MixerPlay(block, 0))
|
|
||||||
{
|
|
||||||
block->fAvailable = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
AddToPlayingQueue(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dwCurrentSamplePrev = Globals->dwCurrentSample;
|
|
||||||
MyWaveOutReset(Globals->hWaveOut);
|
|
||||||
Globals->dwCurrentSample = dwCurrentSamplePrev;
|
|
||||||
auto pauseFlag = 0;
|
|
||||||
if (Globals->PauseBlocks > 0)
|
|
||||||
{
|
|
||||||
waveOutPause(Globals->hWaveOut);
|
|
||||||
pauseFlag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pauseCount = 0;
|
|
||||||
for (auto xHDR = play_queue.first; xHDR; xHDR = xHDR->QNext)
|
|
||||||
{
|
|
||||||
if (waveOutWrite(Globals->hWaveOut, &xHDR->wh, sizeof(WAVEHDR)))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to write block to device", "WavMix32", MB_ICONWARNING);
|
|
||||||
xHDR->fAvailable = 1;
|
|
||||||
RemoveFromPlayingQueue(xHDR);
|
|
||||||
}
|
|
||||||
if (pauseFlag)
|
|
||||||
{
|
|
||||||
if (++pauseCount >= Globals->PauseBlocks)
|
|
||||||
{
|
|
||||||
waveOutRestart(Globals->hWaveOut);
|
|
||||||
pauseFlag = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pauseFlag)
|
|
||||||
waveOutRestart(Globals->hWaveOut);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
XWAVEHDR* WaveMix::RemoveFromPlayingQueue(XWAVEHDR* lpXWH)
|
|
||||||
{
|
|
||||||
if (!play_queue.first)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (lpXWH != play_queue.first)
|
|
||||||
{
|
|
||||||
XWAVEHDR* prev = play_queue.first;
|
|
||||||
XWAVEHDR* current = play_queue.first->QNext;
|
|
||||||
while (current)
|
|
||||||
{
|
|
||||||
if (current == lpXWH)
|
|
||||||
break;
|
|
||||||
prev = current;
|
|
||||||
current = current->QNext;
|
|
||||||
}
|
|
||||||
if (!current)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
prev->QNext = current->QNext;
|
|
||||||
if (current == play_queue.last)
|
|
||||||
play_queue.last = prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
play_queue.first = lpXWH->QNext;
|
|
||||||
if (!play_queue.first)
|
|
||||||
play_queue.last = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpXWH->QNext = nullptr;
|
|
||||||
return lpXWH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::DestroyPlayQueue()
|
|
||||||
{
|
|
||||||
while (play_queue.first)
|
|
||||||
{
|
|
||||||
play_queue.first->fAvailable = 1;
|
|
||||||
RemoveFromPlayingQueue(play_queue.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::SwapWaveBlocks()
|
|
||||||
{
|
|
||||||
if (Globals->WaveBlockArray == block_array1)
|
|
||||||
Globals->WaveBlockArray = block_array2;
|
|
||||||
else
|
|
||||||
Globals->WaveBlockArray = block_array1;
|
|
||||||
}
|
|
||||||
|
|
||||||
XWAVEHDR* WaveMix::GetWaveBlock()
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
for (; index < Globals->WaveBlockCount; index++)
|
|
||||||
if (Globals->WaveBlockArray[index]->fAvailable)
|
|
||||||
break;
|
|
||||||
if (index >= Globals->WaveBlockCount)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
XWAVEHDR* result = Globals->WaveBlockArray[index];
|
|
||||||
result->fAvailable = 0;
|
|
||||||
result->wh.dwBufferLength = Globals->dwWaveBlockLen;
|
|
||||||
result->wh.lpData = reinterpret_cast<LPSTR>(&result[1]);
|
|
||||||
result->g = GlobalsActive;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::MixerPlay(XWAVEHDR* lpXWH, int fWriteBlocks)
|
|
||||||
{
|
|
||||||
if (!lpXWH)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned minStartPos = -1;
|
|
||||||
auto playChannelCount = 0;
|
|
||||||
auto channelPtr = Globals->aChannel;
|
|
||||||
for (auto channelIndex = 16; channelIndex; --channelIndex)
|
|
||||||
{
|
|
||||||
auto channel = *channelPtr;
|
|
||||||
if (channel != reinterpret_cast<CHANNELNODE*>(-1) && channel)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (channel->dwEndPos > Globals->dwCurrentSample)
|
|
||||||
break;
|
|
||||||
channel = channel->next;
|
|
||||||
}
|
|
||||||
while (channel);
|
|
||||||
if (channel)
|
|
||||||
{
|
|
||||||
if (channel->dwStartPos < minStartPos)
|
|
||||||
minStartPos = channel->dwStartPos;
|
|
||||||
play_channel_array[playChannelCount++] = channel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++channelPtr;
|
|
||||||
}
|
|
||||||
if (!playChannelCount)
|
|
||||||
{
|
|
||||||
if (fWriteBlocks)
|
|
||||||
lpXWH->fAvailable = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentSample = Globals->dwCurrentSample;
|
|
||||||
auto dataPtr = reinterpret_cast<unsigned char*>(lpXWH->wh.lpData);
|
|
||||||
auto waveBlockLen = Globals->dwWaveBlockLen;
|
|
||||||
while (waveBlockLen)
|
|
||||||
{
|
|
||||||
if (currentSample >= minStartPos)
|
|
||||||
{
|
|
||||||
auto waveCount = 0;
|
|
||||||
auto endBlockPosition = currentSample + waveBlockLen;
|
|
||||||
|
|
||||||
for (auto channelIndex = 0; channelIndex < playChannelCount; ++channelIndex)
|
|
||||||
{
|
|
||||||
auto channel = play_channel_array[channelIndex];
|
|
||||||
if (channel->dwStartPos <= currentSample)
|
|
||||||
{
|
|
||||||
if (channel->dwEndPos < endBlockPosition)
|
|
||||||
endBlockPosition = channel->dwEndPos;
|
|
||||||
auto dataOffset = currentSample - channel->dwStartPos;
|
|
||||||
if (channel->PlayParams.wLoops)
|
|
||||||
{
|
|
||||||
dataOffset %= channel->dwNumSamples;
|
|
||||||
auto endBlockPosition2 = currentSample + (channel->dwNumSamples - dataOffset);
|
|
||||||
if (endBlockPosition2 < endBlockPosition)
|
|
||||||
endBlockPosition = endBlockPosition2;
|
|
||||||
}
|
|
||||||
play_data[waveCount] = &channel->lpPos[dataOffset];
|
|
||||||
play_volume[waveCount].L = channel->Volume.L;
|
|
||||||
play_volume[waveCount].R = channel->Volume.R;
|
|
||||||
waveCount++;
|
|
||||||
}
|
|
||||||
else if (channel->dwStartPos < endBlockPosition)
|
|
||||||
{
|
|
||||||
endBlockPosition = channel->dwStartPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waveCount)
|
|
||||||
{
|
|
||||||
auto dataLength = endBlockPosition - currentSample;
|
|
||||||
Globals->CmixPtr(dataPtr, play_data, play_volume, waveCount, static_cast<WORD>(dataLength));
|
|
||||||
|
|
||||||
dataPtr += dataLength;
|
|
||||||
waveBlockLen -= dataLength;
|
|
||||||
minStartPos = -1;
|
|
||||||
currentSample += dataLength;
|
|
||||||
|
|
||||||
|
|
||||||
auto playChPtr = play_channel_array;
|
|
||||||
for (auto channelIndex = 0; channelIndex < playChannelCount;)
|
|
||||||
{
|
|
||||||
while (*playChPtr)
|
|
||||||
{
|
|
||||||
if ((*playChPtr)->dwEndPos > currentSample)
|
|
||||||
break;
|
|
||||||
*playChPtr = (*playChPtr)->next;
|
|
||||||
}
|
|
||||||
if (*playChPtr)
|
|
||||||
{
|
|
||||||
if ((*playChPtr)->dwStartPos < minStartPos)
|
|
||||||
minStartPos = (*playChPtr)->dwStartPos;
|
|
||||||
++channelIndex;
|
|
||||||
++playChPtr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
playChannelCount--;
|
|
||||||
*playChPtr = play_channel_array[playChannelCount];
|
|
||||||
if (!playChannelCount)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto length = waveBlockLen;
|
|
||||||
if (waveBlockLen + currentSample >= minStartPos)
|
|
||||||
length = minStartPos - currentSample;
|
|
||||||
memset(dataPtr, 0x80u, length);
|
|
||||||
dataPtr += length;
|
|
||||||
currentSample += length;
|
|
||||||
waveBlockLen -= length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lpXWH->dwWavePos = Globals->dwCurrentSample;
|
|
||||||
Globals->dwCurrentSample += Globals->dwWaveBlockLen;
|
|
||||||
if (fWriteBlocks)
|
|
||||||
{
|
|
||||||
AddToPlayingQueue(lpXWH);
|
|
||||||
if (waveOutWrite(Globals->hWaveOut, &lpXWH->wh, sizeof(WAVEHDR)))
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to write block to device", "WavMix32", MB_ICONWARNING);
|
|
||||||
lpXWH->fAvailable = 1;
|
|
||||||
RemoveFromPlayingQueue(lpXWH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
XWAVEHDR* WaveMix::AddToPlayingQueue(XWAVEHDR* lpXWH)
|
|
||||||
{
|
|
||||||
lpXWH->QNext = nullptr;
|
|
||||||
if (play_queue.first)
|
|
||||||
{
|
|
||||||
play_queue.last->QNext = lpXWH;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
play_queue.first = lpXWH;
|
|
||||||
}
|
|
||||||
play_queue.last = lpXWH;
|
|
||||||
return play_queue.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::MyWaveOutReset(HWAVEOUT hWaveOut)
|
|
||||||
{
|
|
||||||
auto position = MyWaveOutGetPosition(hWaveOut, Globals->fGoodGetPos);
|
|
||||||
waveOutReset(hWaveOut);
|
|
||||||
SetWaveOutPosition(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::SetWaveOutPosition(unsigned newPosition)
|
|
||||||
{
|
|
||||||
DWORD position;
|
|
||||||
mmtime_tag pmmt{};
|
|
||||||
|
|
||||||
pmmt.wType = TIME_BYTES;
|
|
||||||
if (Globals->hWaveOut)
|
|
||||||
{
|
|
||||||
waveOutGetPosition(Globals->hWaveOut, &pmmt, 0xCu);
|
|
||||||
position = pmmt.u.ms; /*Todo: check union ms vs sample with TIME_BYTES*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position < newPosition)
|
|
||||||
{
|
|
||||||
Globals->dwWaveOutPos = newPosition - position;
|
|
||||||
Globals->pfnSampleAdjust = AddFactor;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Globals->dwWaveOutPos = position - newPosition;
|
|
||||||
Globals->pfnSampleAdjust = SubFactor;
|
|
||||||
}
|
|
||||||
Globals->dwCurrentSample = newPosition;
|
|
||||||
Globals->dwBaseTime = timeGetTime() - 1000 * newPosition / Globals->PCM.wf.nAvgBytesPerSec;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD WaveMix::SubFactor(DWORD a1, DWORD a2)
|
|
||||||
{
|
|
||||||
return a1 - a2;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD WaveMix::AddFactor(DWORD a1, DWORD a2)
|
|
||||||
{
|
|
||||||
return a1 + a2;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog_template* WaveMix::MakeSettingsDlgTemplate()
|
|
||||||
{
|
|
||||||
size_t size = 0u;
|
|
||||||
dialog_template* temp = MakeDlgTemplate(&size, 0x80C80080, 0, 0, 212, 132, L"WavMix32 Settings (Ver %X.%X Static)");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 65537, 1, 155, 5, 50, 14, L"&Ok");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 0x10000, 2, 155, 25, 50, 14, L"&Cancel");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 1012, 5, 5, 115, 8, L"Number of WaveBlocks (%d-%d):");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 1013, 5, 20, 115, 8, L"Size of WaveBlocks (%d-%d):");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 0xFFFF, 5, 35, 102, 8, L"Playback Frequency (11,22,44):");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 0xFFFF, 5, 80, 57, 8, L"Playback Device:");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 1014, 5, 50, 115, 8, L"Number of Pause Blocks (%d-%d):");
|
|
||||||
temp = AddDlgControl(&size, temp, 130, 0, 1015, 5, 65, 63, 8, L"Max Channels = %d");
|
|
||||||
temp = AddDlgControl(&size, temp, 129, 8454272, 1003, 125, 5, 25, 12, L"-1");
|
|
||||||
temp = AddDlgControl(&size, temp, 129, 8454272, 1007, 125, 20, 25, 12, L"-1");
|
|
||||||
temp = AddDlgControl(&size, temp, 129, 8454272, 1008, 125, 35, 25, 12, L"-1");
|
|
||||||
temp = AddDlgControl(&size, temp, 129, 8454272, 1011, 125, 50, 25, 12, L"-1");
|
|
||||||
temp = AddDlgControl(&size, temp, 133, 2162946, 1009, 65, 80, 140, 60, L"No Devices");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 65539, 1000, 5, 101, 40, 10, L"Stereo");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 65539, 1001, 55, 101, 60, 10, L"Reset Remix");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 65539, 1010, 125, 101, 78, 10, L"Show Debug Dialogs");
|
|
||||||
temp = AddDlgControl(&size, temp, 128, 65539, 1005, 5, 117, 40, 10, L"CMixit");
|
|
||||||
return AddDlgControl(&size, temp, 128, 65539, 1004, 55, 117, 75, 10, L"Good Get Position");
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog_template* WaveMix::MakeDlgTemplate(size_t* totalSize, unsigned style, short x, short y, short cx, short cy,
|
|
||||||
const wchar_t* String)
|
|
||||||
{
|
|
||||||
auto dlgSize = 2 * wcslen(String) + 24;
|
|
||||||
*totalSize = dlgSize;
|
|
||||||
if ((dlgSize & 3) != 0)
|
|
||||||
*totalSize = dlgSize - (dlgSize & 3) + 4;
|
|
||||||
|
|
||||||
auto hGlobal = GlobalAlloc(GHND, *totalSize);
|
|
||||||
auto dlgTemplate = static_cast<dialog_template*>(GlobalLock(hGlobal));
|
|
||||||
if (dlgTemplate)
|
|
||||||
{
|
|
||||||
dlgTemplate->Dialog.dwExtendedStyle = 0;
|
|
||||||
dlgTemplate->Dialog.cdit = 0;
|
|
||||||
dlgTemplate->Dialog.style = style | 0x10000000;
|
|
||||||
dlgTemplate->Dialog.x = x;
|
|
||||||
dlgTemplate->Dialog.y = y;
|
|
||||||
dlgTemplate->Dialog.cx = cx;
|
|
||||||
dlgTemplate->Dialog.cy = cy;
|
|
||||||
memcpy(dlgTemplate->Header, String, 2 * wcslen(String) + 2);
|
|
||||||
}
|
|
||||||
return dlgTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog_template* WaveMix::AddDlgControl(size_t* totalSize, dialog_template* dlgTemplate, short idClass,
|
|
||||||
unsigned style, WORD id, short x, short y, short cx, short cy,
|
|
||||||
const wchar_t* String)
|
|
||||||
{
|
|
||||||
dialog_template* dlgTemplate2 = dlgTemplate;
|
|
||||||
if (dlgTemplate)
|
|
||||||
{
|
|
||||||
auto prevSize = *totalSize;
|
|
||||||
*totalSize += 2 * wcslen(String) + 25;
|
|
||||||
if ((*totalSize & 3) != 0)
|
|
||||||
*totalSize = *totalSize - (*totalSize & 3) + 4;
|
|
||||||
|
|
||||||
GlobalUnlock(GlobalHandle(dlgTemplate2));
|
|
||||||
auto newSize = *totalSize;
|
|
||||||
HGLOBAL hGlobal = GlobalReAlloc(GlobalHandle(dlgTemplate2), newSize, 0x42u);
|
|
||||||
dlgTemplate2 = static_cast<dialog_template*>(GlobalLock(hGlobal));
|
|
||||||
if (dlgTemplate2)
|
|
||||||
{
|
|
||||||
auto dlgItem = (dialog_item_template*)((char*)dlgTemplate2 + prevSize);
|
|
||||||
dlgItem->Item.dwExtendedStyle = 0;
|
|
||||||
dlgItem->Item.style = style | 0x50000000;
|
|
||||||
dlgItem->Item.x = x;
|
|
||||||
dlgItem->Item.y = y;
|
|
||||||
dlgItem->Item.cx = cx;
|
|
||||||
dlgItem->Item.cy = cy;
|
|
||||||
dlgItem->Item.id = id;
|
|
||||||
dlgItem->sysClass = 0xFFFF;
|
|
||||||
dlgItem->idClass = idClass;
|
|
||||||
wcscpy_s(dlgItem->Header, wcslen(String) + 1, String);
|
|
||||||
++dlgTemplate2->Dialog.cdit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dlgTemplate2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::DestroySettingsDlgTemplate(LPCVOID pMem)
|
|
||||||
{
|
|
||||||
if (pMem)
|
|
||||||
{
|
|
||||||
GlobalUnlock(GlobalHandle(pMem));
|
|
||||||
GlobalFree(GlobalHandle(pMem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::Settings_OnInitDialog(HWND hWnd, WPARAM wParam, MIXCONFIG* lpMixconfig)
|
|
||||||
{
|
|
||||||
tagWAVEOUTCAPSA pwoc{};
|
|
||||||
CHAR String[256];
|
|
||||||
|
|
||||||
GetWindowTextA(hWnd, String, 256);
|
|
||||||
wsprintfA(string_buffer, String, 2, 81);
|
|
||||||
SetWindowTextA(hWnd, string_buffer);
|
|
||||||
SetWindowLongPtr(hWnd, -21, reinterpret_cast<LONG_PTR>(lpMixconfig));
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1000), 0xF1u, lpMixconfig->wChannels > 1u, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1001), 0xF1u, lpMixconfig->ResetMixDefaultFlag != 0, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1004), 0xF1u, lpMixconfig->GoodWavePos != 0, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1005), 0xF1u, lpMixconfig->CmixPtrDefaultFlag != 0, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1010), 0xF1u, lpMixconfig->ShowDebugDialogs != 0, 0);
|
|
||||||
EnableWindow(GetDlgItem(hWnd, 1005), 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1003), 0xC5u, 2u, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1007), 0xC5u, 4u, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1008), 0xC5u, 2u, 0);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1011), 0xC5u, 2u, 0);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1012), String, 100);
|
|
||||||
wsprintfA(string_buffer, String, 2, 10);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1012), string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1013), String, 100);
|
|
||||||
wsprintfA(string_buffer, String, 344, 11025);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1013), string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1014), String, 100);
|
|
||||||
wsprintfA(string_buffer, String, 0, 10);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1014), string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1015), String, 100);
|
|
||||||
wsprintfA(string_buffer, String, 16);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1015), string_buffer);
|
|
||||||
wsprintfA(string_buffer, "%d", lpMixconfig->WaveBlockCount);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1003), string_buffer);
|
|
||||||
wsprintfA(string_buffer, "%d", lpMixconfig->WaveBlockLen);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1007), string_buffer);
|
|
||||||
wsprintfA(string_buffer, "%d", lpMixconfig->wSamplingRate);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1008), string_buffer);
|
|
||||||
wsprintfA(string_buffer, "%d", lpMixconfig->PauseBlocks);
|
|
||||||
SetWindowTextA(GetDlgItem(hWnd, 1011), string_buffer);
|
|
||||||
|
|
||||||
signed int uDeviceID = 0;
|
|
||||||
signed int deviceCount = waveOutGetNumDevs();
|
|
||||||
if (deviceCount > 0)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
MMRESULT getResult = waveOutGetDevCapsA(uDeviceID, &pwoc, 0x34u);
|
|
||||||
if (getResult)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "waveOutGetDevCaps failed (err %u) for device %d", getResult, uDeviceID);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d: %s", uDeviceID, pwoc.szPname);
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1009), 0x143u, 0, (LPARAM)string_buffer);
|
|
||||||
}
|
|
||||||
++uDeviceID;
|
|
||||||
}
|
|
||||||
while (uDeviceID < deviceCount);
|
|
||||||
}
|
|
||||||
SendMessageA(GetDlgItem(hWnd, 1009), 0x14Eu, lpMixconfig->wDeviceID, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::Settings_OnCommand(HWND hWnd, int command, LPARAM lParam, int wParam)
|
|
||||||
{
|
|
||||||
auto userData = reinterpret_cast<MIXCONFIG*>(GetWindowLongPtrA(hWnd, -21));
|
|
||||||
if (command == 1)
|
|
||||||
{
|
|
||||||
if (userData)
|
|
||||||
{
|
|
||||||
userData->wChannels = (SendMessageA(GetDlgItem(hWnd, 1000), 0xF0u, 0, 0) != 0) + 1;
|
|
||||||
userData->ResetMixDefaultFlag = SendMessageA(GetDlgItem(hWnd, 1001), 0xF0u, 0, 0) != 0;
|
|
||||||
userData->GoodWavePos = SendMessageA(GetDlgItem(hWnd, 1004), 0xF0u, 0, 0) != 0;
|
|
||||||
userData->ShowDebugDialogs = SendMessageA(GetDlgItem(hWnd, 1010), 0xF0u, 0, 0) != 0;
|
|
||||||
userData->CmixPtrDefaultFlag = SendMessageA(GetDlgItem(hWnd, 1005), 0xF0u, 0, 0) != 0;
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1003), string_buffer, 10);
|
|
||||||
userData->WaveBlockCount = atoi(string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1007), string_buffer, 10);
|
|
||||||
userData->WaveBlockLen = atoi(string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1008), string_buffer, 10);
|
|
||||||
userData->wSamplingRate = atoi(string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1011), string_buffer, 10);
|
|
||||||
userData->PauseBlocks = atoi(string_buffer);
|
|
||||||
GetWindowTextA(GetDlgItem(hWnd, 1009), string_buffer, 10);
|
|
||||||
userData->wDeviceID = isdigit(string_buffer[0]) ? atoi(string_buffer) : 0;
|
|
||||||
EndDialog(hWnd, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (command != 2)
|
|
||||||
return 0;
|
|
||||||
EndDialog(hWnd, 0);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::ReadRegistryToGetMachineSpecificInfSection(unsigned wDeviceId, LPSTR lpString1, int maxLength)
|
|
||||||
{
|
|
||||||
HKEY phkResult;
|
|
||||||
CHAR SubKey[52];
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
int osPrefixLength = lstrlenA(GetOperatingSystemPrefix());
|
|
||||||
if (maxLength < osPrefixLength + 10)
|
|
||||||
return 0;
|
|
||||||
wsprintfA(SubKey, "Device%u", wDeviceId);
|
|
||||||
if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\WaveMix", &phkResult))
|
|
||||||
return 0;
|
|
||||||
lstrcpyA(lpString1, GetOperatingSystemPrefix());
|
|
||||||
LONG cbData = maxLength - osPrefixLength;
|
|
||||||
if (!RegQueryValueA(phkResult, SubKey, &lpString1[osPrefixLength], &cbData) && cbData > 0)
|
|
||||||
result = 1;
|
|
||||||
RegCloseKey(phkResult);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning (disable : 4996)/*Original uses GetVersion*/
|
|
||||||
const char* WaveMix::GetOperatingSystemPrefix()
|
|
||||||
{
|
|
||||||
if (GetVersion() < 0x80000000)
|
|
||||||
return "WinNT:";
|
|
||||||
if (GetVersion() >= 0x80000000 && static_cast<uint8_t>(GetVersion()) >= 4u)
|
|
||||||
return "Win95:";
|
|
||||||
if (GetVersion() >= 0x80000000 && static_cast<uint8_t>(GetVersion()) < 4u)
|
|
||||||
return "Win31:";
|
|
||||||
return "OS_X"; /*The next big thing: waveOut on OSX*/
|
|
||||||
}
|
|
||||||
#pragma warning (default : 4996)/*Original uses GetVersion*/
|
|
||||||
|
|
||||||
unsigned WaveMix::FigureOutDMABufferSize(unsigned waveBlockLen, PCMWAVEFORMAT* pcm)
|
|
||||||
{
|
|
||||||
unsigned int result = waveBlockLen;
|
|
||||||
if (!waveBlockLen)
|
|
||||||
result = pcm->wf.nSamplesPerSec * pcm->wf.nChannels * (pcm->wBitsPerSample >> 3) >> 4;
|
|
||||||
if (result < 344)
|
|
||||||
result = 344;
|
|
||||||
if (result > 11025)
|
|
||||||
result = 11025;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::NoResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel)
|
|
||||||
{
|
|
||||||
Pump();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::SaveConfigSettings(unsigned dwFlags)
|
|
||||||
{
|
|
||||||
if ((dwFlags & 0x80u) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->wDeviceID);
|
|
||||||
WritePrivateProfileStringA("general", "WaveOutDevice", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 1) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->PCM.wf.nChannels);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "Channels", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 2) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", static_cast<uint16_t>(11 * (Globals->PCM.wf.nSamplesPerSec / 0x2B11)));
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "SamplesPerSec", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 4) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->WaveBlockCount);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "WaveBlocks", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 8) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", LOWORD(WaveMix::Globals->dwWaveBlockLen));
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "WaveBlockLen", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x10) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->CmixPtr == cmixit);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "CMixit", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x20) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", (Globals->pfnRemix != ResetRemix) + 1);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "Remix", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x40) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->fGoodGetPos == 0);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "GoodWavePos", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x100) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", ShowDebugDialogs != 0);
|
|
||||||
WritePrivateProfileStringA("general", "ShowDebugDialogs", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
if ((dwFlags & 0x200) != 0)
|
|
||||||
{
|
|
||||||
wsprintfA(string_buffer, "%d", Globals->PauseBlocks);
|
|
||||||
WritePrivateProfileStringA(Globals->szDevicePName, "PauseBlocks", string_buffer, FileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::ShowCurrentSettings()
|
|
||||||
{
|
|
||||||
tagWAVEOUTCAPSA pwoc{};
|
|
||||||
|
|
||||||
if (waveOutGetDevCapsA(Globals->wDeviceID, &pwoc, 0x34u) || !RemoveInvalidIniNameCharacters(pwoc.szPname))
|
|
||||||
lstrcpyA(pwoc.szPname, "Unknown Device");
|
|
||||||
auto cmixitType = "cmixit";
|
|
||||||
if (Globals->CmixPtr != cmixit)
|
|
||||||
cmixitType = "386 mixit";
|
|
||||||
auto getGood = "TRUE";
|
|
||||||
if (!Globals->fGoodGetPos)
|
|
||||||
getGood = "FALSE";
|
|
||||||
auto remixType = "Reset";
|
|
||||||
if (Globals->pfnRemix != ResetRemix)
|
|
||||||
remixType = "NoReset";
|
|
||||||
wsprintfA(
|
|
||||||
string_buffer,
|
|
||||||
"Using:\t%s.\n"
|
|
||||||
"\tRemix = %s\n"
|
|
||||||
"\tGoodGetPos=%s\n"
|
|
||||||
"\t%d ping pong wave blocks\n"
|
|
||||||
"\tWave block len = %lu bytes\n"
|
|
||||||
"\tpfnMixit=%s\n"
|
|
||||||
"\tSamplesPerSec=%lu,\n"
|
|
||||||
"\tChannels=%d\n"
|
|
||||||
"\tPauseBlocks=%d",
|
|
||||||
pwoc.szPname,
|
|
||||||
remixType,
|
|
||||||
getGood,
|
|
||||||
Globals->WaveBlockCount,
|
|
||||||
Globals->dwWaveBlockLen,
|
|
||||||
cmixitType,
|
|
||||||
Globals->PCM.wf.nSamplesPerSec,
|
|
||||||
Globals->PCM.wf.nChannels,
|
|
||||||
Globals->PauseBlocks);
|
|
||||||
MessageBoxA(nullptr, string_buffer, "WavMix32", MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned WaveMix::GetWaveDevice()
|
|
||||||
{
|
|
||||||
WAVEFORMATEX pwfx{};
|
|
||||||
|
|
||||||
if (Globals->hWaveOut)
|
|
||||||
return 0;
|
|
||||||
HWND window = CreateWindowExA(0, "WavMix32", "", 0x8000000u, 0, 0, 0, 0, nullptr, nullptr, HModule,
|
|
||||||
nullptr);
|
|
||||||
GLOBALS* globals = Globals;
|
|
||||||
Globals->hWndApp = window;
|
|
||||||
if (!window)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Failed to create callback window.", "WavMix32", MB_ICONWARNING);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
pwfx.wFormatTag = globals->PCM.wf.wFormatTag;
|
|
||||||
pwfx.nChannels = globals->PCM.wf.nChannels;
|
|
||||||
pwfx.nSamplesPerSec = globals->PCM.wf.nSamplesPerSec;
|
|
||||||
pwfx.nAvgBytesPerSec = globals->PCM.wf.nAvgBytesPerSec;
|
|
||||||
pwfx.nBlockAlign = globals->PCM.wf.nBlockAlign;
|
|
||||||
pwfx.wBitsPerSample = globals->PCM.wBitsPerSample;
|
|
||||||
pwfx.cbSize = 0;
|
|
||||||
unsigned int openResult = waveOutOpen(&globals->hWaveOut, 0xFFFFFFFF, &pwfx,
|
|
||||||
reinterpret_cast<DWORD_PTR>(globals->hWndApp), 0,
|
|
||||||
0x10000u);
|
|
||||||
if (openResult)
|
|
||||||
{
|
|
||||||
DestroyWindow(Globals->hWndApp);
|
|
||||||
Globals->hWndApp = nullptr;
|
|
||||||
return openResult;
|
|
||||||
}
|
|
||||||
if (AllocWaveBlocks(Globals->hWaveOut, block_array1)
|
|
||||||
&& AllocWaveBlocks(Globals->hWaveOut, block_array2))
|
|
||||||
{
|
|
||||||
Globals->WaveBlockArray = block_array1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
FreeWaveBlocks(Globals->hWaveOut, block_array1);
|
|
||||||
FreeWaveBlocks(Globals->hWaveOut, block_array2);
|
|
||||||
waveOutClose(Globals->hWaveOut);
|
|
||||||
Globals->hWaveOut = nullptr;
|
|
||||||
DestroyWindow(Globals->hWndApp);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::FreeWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
{
|
|
||||||
auto blockPtr = &waveBlocks[i];
|
|
||||||
if (*blockPtr)
|
|
||||||
{
|
|
||||||
waveOutUnprepareHeader(hwo, &(*blockPtr)->wh, sizeof(WAVEHDR));
|
|
||||||
GlobalUnlock(GlobalHandle(*blockPtr));
|
|
||||||
GlobalFree(GlobalHandle(*blockPtr));
|
|
||||||
*blockPtr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::AllocWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
{
|
|
||||||
auto xHDR = static_cast<XWAVEHDR*>(GlobalLock(GlobalAlloc(GMEM_SHARE, 0x2B41u)));
|
|
||||||
waveBlocks[i] = xHDR;
|
|
||||||
if (!xHDR)
|
|
||||||
{
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(
|
|
||||||
nullptr,
|
|
||||||
"Unable to allocate memory for waveform data. Try making more memory available by closing other applications.",
|
|
||||||
"WavMix32",
|
|
||||||
MB_ICONWARNING);
|
|
||||||
for (int j = i - 1; j >= 0; --j)
|
|
||||||
{
|
|
||||||
GlobalUnlock(GlobalHandle(waveBlocks[j]));
|
|
||||||
GlobalFree(GlobalHandle(waveBlocks[j]));
|
|
||||||
waveBlocks[j] = nullptr;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
xHDR->wh.lpData = (LPSTR)&xHDR[1];
|
|
||||||
xHDR->wh.dwBufferLength = Globals->dwWaveBlockLen;
|
|
||||||
xHDR->wh.dwFlags = 0;
|
|
||||||
xHDR->wh.dwLoops = 0;
|
|
||||||
xHDR->fAvailable = 1;
|
|
||||||
xHDR->dwWavePos = 0;
|
|
||||||
}
|
|
||||||
int index = 0;
|
|
||||||
while (!waveOutPrepareHeader(hwo, &waveBlocks[index]->wh, sizeof(WAVEHDR)))
|
|
||||||
{
|
|
||||||
waveBlocks[index++]->wh.dwFlags |= 1u;
|
|
||||||
if (index >= 10)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (ShowDebugDialogs)
|
|
||||||
MessageBoxA(nullptr, "Unable to prepare wave header.", "WavMix32", MB_ICONWARNING);
|
|
||||||
FreeWaveBlocks(hwo, waveBlocks);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::ReleaseWaveDevice(GLOBALS* globals)
|
|
||||||
{
|
|
||||||
if (globals->fActive)
|
|
||||||
{
|
|
||||||
if (globals->hWaveOut)
|
|
||||||
{
|
|
||||||
MyWaveOutReset(globals->hWaveOut);
|
|
||||||
DestroyPlayQueue();
|
|
||||||
FreeWaveBlocks(globals->hWaveOut, block_array1);
|
|
||||||
FreeWaveBlocks(globals->hWaveOut, block_array2);
|
|
||||||
waveOutClose(globals->hWaveOut);
|
|
||||||
globals->hWaveOut = nullptr;
|
|
||||||
DestroyWindow(globals->hWndApp);
|
|
||||||
globals->hWndApp = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(GMEM_SHARE | GMEM_MOVEABLE, *dwDataSize));
|
|
||||||
if (dataBuf)
|
|
||||||
{
|
|
||||||
if (nInBPS / 8u <= nOutBPS / 8u)
|
|
||||||
{
|
|
||||||
auto dst = static_cast<int16_t*>(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_t*>(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",
|
|
||||||
MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(GMEM_SHARE | GMEM_MOVEABLE, *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_t*>(lpInData);
|
|
||||||
auto dst = reinterpret_cast<int16_t*>(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",
|
|
||||||
MB_ICONINFORMATION);
|
|
||||||
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(GMEM_SHARE | GMEM_MOVEABLE, 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",
|
|
||||||
MB_ICONINFORMATION);
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump raw PCM for analysis.
|
|
||||||
/*FILE* file;
|
|
||||||
fopen_s(&file,"wav1_dump.raw", "w");
|
|
||||||
fwrite(dataBufBup, 1, sampleSize * dwNumSamples2, file);
|
|
||||||
fclose(file);*/
|
|
||||||
|
|
||||||
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<uint8_t>(*src) - 128;
|
|
||||||
src += nChannels;
|
|
||||||
}
|
|
||||||
*dst++ = static_cast<char>(average / nSkip + 128);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto src = reinterpret_cast<int16_t*>(lpInData);
|
|
||||||
auto dst = reinterpret_cast<int16_t*>(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<uint8_t*>(lpInData);
|
|
||||||
auto dst = reinterpret_cast<uint8_t*>(lpOutData);
|
|
||||||
for (auto channelIndex = nChannels; channelIndex; --channelIndex)
|
|
||||||
{
|
|
||||||
auto sample = *src;
|
|
||||||
auto dst2 = &dst[nChannels];
|
|
||||||
auto delta = (src[nChannels] - src[0]) / static_cast<int>(nRep);
|
|
||||||
*dst = *src;
|
|
||||||
dst++;
|
|
||||||
for (auto repeatIndex = nRep - 1; repeatIndex; repeatIndex--)
|
|
||||||
{
|
|
||||||
sample += delta;
|
|
||||||
*dst2 = sample;
|
|
||||||
dst2 += nChannels;
|
|
||||||
}
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto src = reinterpret_cast<int16_t*>(lpInData);
|
|
||||||
auto dst = reinterpret_cast<int16_t*>(lpOutData);
|
|
||||||
for (auto channelIndex2 = nChannels; channelIndex2; channelIndex2--)
|
|
||||||
{
|
|
||||||
auto sample = *src;
|
|
||||||
auto dst2 = &dst[nChannels];
|
|
||||||
auto delta = (src[nChannels] - src[0]) / static_cast<int>(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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaveMix::HasCurrentOutputFormat(MIXWAVE* lpMixWave)
|
|
||||||
{
|
|
||||||
return memcmp(&lpMixWave->pcm, &Globals->PCM, sizeof(PCMWAVEFORMAT)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHANNELNODE* WaveMix::GetChannelNode()
|
|
||||||
{
|
|
||||||
CHANNELNODE* result = free_channel_nodes;
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
free_channel_nodes = free_channel_nodes->next;
|
|
||||||
result->next = nullptr;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::ResetWavePosIfNoChannelData()
|
|
||||||
{
|
|
||||||
if (!play_queue.first)
|
|
||||||
{
|
|
||||||
int channelIndex = 0;
|
|
||||||
for (CHANNELNODE** i = Globals->aChannel; !*i || *i == reinterpret_cast<CHANNELNODE*>(-1); ++i)
|
|
||||||
{
|
|
||||||
if (++channelIndex >= 16)
|
|
||||||
{
|
|
||||||
SetWaveOutPosition(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveMix::cmixit(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volumeArr, int iNumWaves,
|
|
||||||
uint16_t 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)
|
|
||||||
{
|
|
||||||
if (Msg != MM_WOM_DONE && Msg != WM_USER)
|
|
||||||
return DefWindowProcA(hWnd, Msg, wParam, lParam);
|
|
||||||
Pump();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT_PTR WaveMix::SettingsDlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
if (Msg == WM_INITDIALOG)
|
|
||||||
return Settings_OnInitDialog(hWnd, wParam, reinterpret_cast<MIXCONFIG*>(lParam));
|
|
||||||
if (Msg != WM_COMMAND)
|
|
||||||
return 0;
|
|
||||||
Settings_OnCommand(hWnd, LOWORD(wParam), lParam, HIWORD(wParam));
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -1,244 +0,0 @@
|
||||||
#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 WMIX_CustomVolume 0x10
|
|
||||||
|
|
||||||
#define MAXCHANNELS 16
|
|
||||||
#define MAXQUEUEDWAVES 100
|
|
||||||
|
|
||||||
struct GLOBALS;
|
|
||||||
|
|
||||||
struct volume_struct
|
|
||||||
{
|
|
||||||
uint16_t L;
|
|
||||||
uint16_t R;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct MIXWAVE
|
|
||||||
{
|
|
||||||
PCMWAVEFORMAT pcm;
|
|
||||||
WAVEHDR wh;
|
|
||||||
char szWaveFilename[16];
|
|
||||||
short wMagic;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MIXPLAYPARAMS
|
|
||||||
{
|
|
||||||
WORD wSize;
|
|
||||||
HANDLE hMixSession;
|
|
||||||
int iChannel;
|
|
||||||
MIXWAVE* lpMixWave;
|
|
||||||
HWND hWndNotify;
|
|
||||||
DWORD dwFlags;
|
|
||||||
WORD wLoops;
|
|
||||||
volume_struct Volume;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CHANNELNODE
|
|
||||||
{
|
|
||||||
CHANNELNODE* next;
|
|
||||||
MIXPLAYPARAMS PlayParams;
|
|
||||||
MIXWAVE* lpMixWave;
|
|
||||||
DWORD dwNumSamples;
|
|
||||||
DWORD dwStartPos;
|
|
||||||
DWORD dwEndPos;
|
|
||||||
unsigned char* lpPos;
|
|
||||||
unsigned char* lpEnd;
|
|
||||||
volume_struct Volume;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MIXCONFIG
|
|
||||||
{
|
|
||||||
WORD wSize;
|
|
||||||
DWORD dwFlags;
|
|
||||||
WORD wChannels;
|
|
||||||
WORD wSamplingRate;
|
|
||||||
uint16_t WaveBlockCount;
|
|
||||||
uint16_t WaveBlockLen;
|
|
||||||
int16_t CmixPtrDefaultFlag;
|
|
||||||
uint16_t ResetMixDefaultFlag;
|
|
||||||
uint16_t GoodWavePos;
|
|
||||||
uint16_t wDeviceID;
|
|
||||||
uint16_t PauseBlocks;
|
|
||||||
int16_t ShowDebugDialogs;
|
|
||||||
HKEY RegistryKey;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct XWAVEHDR
|
|
||||||
{
|
|
||||||
WAVEHDR wh;
|
|
||||||
BOOL fAvailable;
|
|
||||||
DWORD dwWavePos;
|
|
||||||
GLOBALS* g;
|
|
||||||
struct XWAVEHDR* QNext;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PLAYQUEUE
|
|
||||||
{
|
|
||||||
XWAVEHDR* first;
|
|
||||||
XWAVEHDR* last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GLOBALS
|
|
||||||
{
|
|
||||||
WORD wMagic1;
|
|
||||||
int16_t unknown0;
|
|
||||||
HWND hWndApp;
|
|
||||||
int unknown2;
|
|
||||||
HWAVEOUT hWaveOut;
|
|
||||||
int fActive;
|
|
||||||
int SettingsDialogActiveFlag;
|
|
||||||
unsigned int wDeviceID;
|
|
||||||
char szDevicePName[96];
|
|
||||||
WAVEOUTCAPSA WaveoutCaps;
|
|
||||||
volume_struct DefaultVolume;
|
|
||||||
volume_struct ChannelVolume[MAXCHANNELS];
|
|
||||||
CHANNELNODE* aChannel[MAXCHANNELS];
|
|
||||||
int iChannels;
|
|
||||||
DWORD MRUChannel[MAXCHANNELS];
|
|
||||||
DWORD dwMRU;
|
|
||||||
PCMWAVEFORMAT PCM;
|
|
||||||
DWORD dwWaveBlockLen;
|
|
||||||
int WaveBlockCount;
|
|
||||||
int PauseBlocks;
|
|
||||||
XWAVEHDR** WaveBlockArray;
|
|
||||||
DWORD dwCurrentSample;
|
|
||||||
DWORD dwBaseTime;
|
|
||||||
int fGoodGetPos;
|
|
||||||
DWORD dwWaveOutPos;
|
|
||||||
void (*CmixPtr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume, int iNumWaves,
|
|
||||||
uint16_t length);
|
|
||||||
int (* pfnRemix)(DWORD, CHANNELNODE*);
|
|
||||||
DWORD (* pfnSampleAdjust)(DWORD, DWORD);
|
|
||||||
CHANNELNODE* pWaitList;
|
|
||||||
int16_t wMagic2;
|
|
||||||
int16_t unknown112;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dialog_template
|
|
||||||
{
|
|
||||||
DLGTEMPLATE Dialog;
|
|
||||||
WORD menu;
|
|
||||||
WORD windowClass;
|
|
||||||
WCHAR Header[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dialog_item_template
|
|
||||||
{
|
|
||||||
DLGITEMTEMPLATE Item;
|
|
||||||
WORD sysClass;
|
|
||||||
WORD idClass;
|
|
||||||
WCHAR Header[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class WaveMix
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static HANDLE Init();
|
|
||||||
static HANDLE ConfigureInit(MIXCONFIG* lpConfig);
|
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static GLOBALS* SessionToGlobalDataPtr(HANDLE hMixSession);
|
|
||||||
static int Startup(HMODULE hModule);
|
|
||||||
static int SetIniFileName(HMODULE hModule);
|
|
||||||
static void InitChannelNodes();
|
|
||||||
static void InitVolumeTable();
|
|
||||||
static void ShowWaveOutDevices();
|
|
||||||
static int RemoveInvalidIniNameCharacters(char* lpString);
|
|
||||||
static int ReadConfigSettings(MIXCONFIG* lpConfig);
|
|
||||||
static int ReadRegistryForAppSpecificConfigs(MIXCONFIG* lpConfig);
|
|
||||||
static int ReadRegistryInt(HKEY hKey, LPCSTR lpSubKey, int defaultValue);
|
|
||||||
static int DefaultGoodWavePos(unsigned int uDeviceID);
|
|
||||||
static int DefaultPauseBlocks(int waveBlocks);
|
|
||||||
static int Configure(GLOBALS* hMixSession, HWND hWndParent, MIXCONFIG* lpConfig, int* flag1Ptr, int saveConfigFlag);
|
|
||||||
static int GetConfig(HANDLE hMixSession, MIXCONFIG* lpConfig);
|
|
||||||
static unsigned MyWaveOutGetPosition(HWAVEOUT hWaveOut, int fGoodGetPos);
|
|
||||||
static void FreeChannelNode(CHANNELNODE* channel);
|
|
||||||
static int ResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel);
|
|
||||||
static XWAVEHDR* RemoveFromPlayingQueue(XWAVEHDR* lpXWH);
|
|
||||||
static void DestroyPlayQueue();
|
|
||||||
static void SwapWaveBlocks();
|
|
||||||
static XWAVEHDR* GetWaveBlock();
|
|
||||||
static int MixerPlay(XWAVEHDR* lpXWH, int fWriteBlocks);
|
|
||||||
static XWAVEHDR* AddToPlayingQueue(XWAVEHDR* lpXWH);
|
|
||||||
static void MyWaveOutReset(HWAVEOUT hWaveOut);
|
|
||||||
static void SetWaveOutPosition(unsigned int newPosition);
|
|
||||||
static DWORD SubFactor(DWORD a1, DWORD a2);
|
|
||||||
static DWORD AddFactor(DWORD a1, DWORD a2);
|
|
||||||
static dialog_template* MakeSettingsDlgTemplate();
|
|
||||||
static dialog_template* MakeDlgTemplate(size_t* totalSize, unsigned style, int16_t x, int16_t y, int16_t cx,
|
|
||||||
int16_t cy,
|
|
||||||
const wchar_t* String);
|
|
||||||
static dialog_template* AddDlgControl(size_t* totalSize, dialog_template* dlgTemplate, int16_t idClass,
|
|
||||||
unsigned style,
|
|
||||||
WORD id, int16_t x, int16_t y, int16_t cx, int16_t cy,
|
|
||||||
const wchar_t* String);
|
|
||||||
static void DestroySettingsDlgTemplate(LPCVOID pMem);
|
|
||||||
static int Settings_OnInitDialog(HWND hWnd, WPARAM wParam, MIXCONFIG* lpMixconfig);
|
|
||||||
static int Settings_OnCommand(HWND hWnd, int command, LPARAM lParam, int wParam);
|
|
||||||
static int ReadRegistryToGetMachineSpecificInfSection(unsigned wDeviceId, LPSTR lpString1, int maxLength);
|
|
||||||
static const char* GetOperatingSystemPrefix();
|
|
||||||
static unsigned int FigureOutDMABufferSize(unsigned int waveBlockLen, PCMWAVEFORMAT* pcm);
|
|
||||||
static int NoResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel);
|
|
||||||
static void SaveConfigSettings(unsigned dwFlags);
|
|
||||||
static void ShowCurrentSettings();
|
|
||||||
static unsigned int GetWaveDevice();
|
|
||||||
static void FreeWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks);
|
|
||||||
static int AllocWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks);
|
|
||||||
static void ReleaseWaveDevice(GLOBALS* globals);
|
|
||||||
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 int HasCurrentOutputFormat(MIXWAVE* lpMixWave);
|
|
||||||
static CHANNELNODE* GetChannelNode();
|
|
||||||
static void ResetWavePosIfNoChannelData();
|
|
||||||
static void cmixit(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volumeArr, int iNumWaves,
|
|
||||||
uint16_t 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);
|
|
||||||
|
|
||||||
static int initialized_flag;
|
|
||||||
static char FileName[276];
|
|
||||||
static CHANNELNODE channel_nodes[MAXQUEUEDWAVES];
|
|
||||||
static CHANNELNODE* free_channel_nodes;
|
|
||||||
static unsigned char volume_table[11][256];
|
|
||||||
static int debug_flag;
|
|
||||||
static void (*cmixit_ptr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume,
|
|
||||||
int iNumWaves, uint16_t length);
|
|
||||||
static HMODULE HModule;
|
|
||||||
static GLOBALS *Globals, *GlobalsActive;
|
|
||||||
static PCMWAVEFORMAT gpFormat;
|
|
||||||
static int ShowDebugDialogs;
|
|
||||||
static char string_buffer[256];
|
|
||||||
static PLAYQUEUE play_queue;
|
|
||||||
static CHANNELNODE* play_channel_array[MAXCHANNELS];
|
|
||||||
static XWAVEHDR* block_array1[10];
|
|
||||||
static XWAVEHDR* block_array2[10];
|
|
||||||
static unsigned char* play_data[MAXCHANNELS];
|
|
||||||
static volume_struct play_volume[MAXCHANNELS];
|
|
||||||
static int play_counter;
|
|
||||||
};
|
|
|
@ -639,9 +639,9 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
|
|
||||||
if (!control_lite198_tag.Component->MessageField)
|
if (!control_lite198_tag.Component->MessageField)
|
||||||
{
|
{
|
||||||
if (key <= 'M')
|
if (key <= 'm')
|
||||||
{
|
{
|
||||||
if (key == 'M')
|
if (key == 'm')
|
||||||
{
|
{
|
||||||
v2 = pbctrl_state;
|
v2 = pbctrl_state;
|
||||||
if (pbctrl_state == 4 || pbctrl_state == 61 || pbctrl_state == 81 || pbctrl_state == 101)
|
if (pbctrl_state == 4 || pbctrl_state == 61 || pbctrl_state == 81 || pbctrl_state == 101)
|
||||||
|
@ -650,9 +650,9 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (key <= 'D')
|
if (key <= 'd')
|
||||||
{
|
{
|
||||||
if (key != 'D')
|
if (key != 'd')
|
||||||
{
|
{
|
||||||
if (key == ' ')
|
if (key == ' ')
|
||||||
{
|
{
|
||||||
|
@ -665,11 +665,11 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
if (key != '1')
|
if (key != '1')
|
||||||
{
|
{
|
||||||
if (key != 'A')
|
if (key != 'a')
|
||||||
{
|
{
|
||||||
if (key != 'B')
|
if (key != 'b')
|
||||||
{
|
{
|
||||||
if (key == 'C')
|
if (key == 'c')
|
||||||
{
|
{
|
||||||
if (!pbctrl_state)
|
if (!pbctrl_state)
|
||||||
{
|
{
|
||||||
|
@ -704,17 +704,17 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
++pbctrl_state;
|
++pbctrl_state;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key != 'E')
|
if (key != 'e')
|
||||||
{
|
{
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case 'G':
|
case 'g':
|
||||||
v1 = pbctrl_state != 0 ? 0 : 101;
|
v1 = pbctrl_state != 0 ? 0 : 101;
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'h':
|
||||||
v1 = pbctrl_state != 0 ? 0 : 21;
|
v1 = pbctrl_state != 0 ? 0 : 21;
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'i':
|
||||||
v2 = pbctrl_state;
|
v2 = pbctrl_state;
|
||||||
if (pbctrl_state == 1 || pbctrl_state == 10)
|
if (pbctrl_state == 1 || pbctrl_state == 10)
|
||||||
goto LABEL_87;
|
goto LABEL_87;
|
||||||
|
@ -732,9 +732,9 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
goto LABEL_86;
|
goto LABEL_86;
|
||||||
}
|
}
|
||||||
if (key <= 'S')
|
if (key <= 's')
|
||||||
{
|
{
|
||||||
if (key == 'S')
|
if (key == 's')
|
||||||
{
|
{
|
||||||
v2 = pbctrl_state;
|
v2 = pbctrl_state;
|
||||||
if (pbctrl_state == 12 || pbctrl_state == 29)
|
if (pbctrl_state == 12 || pbctrl_state == 29)
|
||||||
|
@ -743,13 +743,13 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (key != 'N')
|
if (key != 'n')
|
||||||
{
|
{
|
||||||
if (key != 'O')
|
if (key != 'o')
|
||||||
{
|
{
|
||||||
if (key != 'Q')
|
if (key != 'q')
|
||||||
{
|
{
|
||||||
if (key == 'R')
|
if (key == 'r')
|
||||||
{
|
{
|
||||||
if (!pbctrl_state)
|
if (!pbctrl_state)
|
||||||
{
|
{
|
||||||
|
@ -789,7 +789,7 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case 'T':
|
case 't':
|
||||||
v2 = pbctrl_state;
|
v2 = pbctrl_state;
|
||||||
if (pbctrl_state != 30)
|
if (pbctrl_state != 30)
|
||||||
{
|
{
|
||||||
|
@ -800,14 +800,14 @@ void control::pbctrl_bdoor_controller(int key)
|
||||||
}
|
}
|
||||||
pb::cheat_mode = 1;
|
pb::cheat_mode = 1;
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'u':
|
||||||
if (pbctrl_state == 41)
|
if (pbctrl_state == 41)
|
||||||
{
|
{
|
||||||
pbctrl_state = 42;
|
pbctrl_state = 42;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto LABEL_77;
|
goto LABEL_77;
|
||||||
case 'X':
|
case 'x':
|
||||||
if (pbctrl_state == 63)
|
if (pbctrl_state == 63)
|
||||||
{
|
{
|
||||||
table_add_extra_ball(2.0);
|
table_add_extra_ball(2.0);
|
||||||
|
|
|
@ -66,7 +66,7 @@ void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HME
|
||||||
fullscrn_flag1 = 0;
|
fullscrn_flag1 = 0;
|
||||||
|
|
||||||
window_size_changed();
|
window_size_changed();
|
||||||
assertm(ScaleX == 1 && ScaleY == 1, "Wrong default client size");
|
//assertm(ScaleX == 1 && ScaleY == 1, "Wrong default client size");
|
||||||
}
|
}
|
||||||
|
|
||||||
void fullscrn::shutdown()
|
void fullscrn::shutdown()
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
#include "winmain.h"
|
#include "winmain.h"
|
||||||
|
|
||||||
HPALETTE gdrv::palette_handle = nullptr;
|
HPALETTE gdrv::palette_handle = nullptr;
|
||||||
HINSTANCE gdrv::hinst;
|
SDL_Renderer* gdrv::renderer;
|
||||||
HWND gdrv::hwnd;
|
|
||||||
int gdrv::sequence_handle;
|
int gdrv::sequence_handle;
|
||||||
HDC gdrv::sequence_hdc;
|
HDC gdrv::sequence_hdc;
|
||||||
int gdrv::use_wing = 0;
|
int gdrv::use_wing = 0;
|
||||||
|
@ -16,13 +15,26 @@ int gdrv::grtext_blue = 0;
|
||||||
int gdrv::grtext_green = 0;
|
int gdrv::grtext_green = 0;
|
||||||
int gdrv::grtext_red = -1;
|
int gdrv::grtext_red = -1;
|
||||||
|
|
||||||
|
HWND hwnd = 0;
|
||||||
|
SDL_Texture* vScreenTex = nullptr;
|
||||||
|
char* pixels = nullptr;
|
||||||
|
int Width, Height;
|
||||||
|
LOGPALETTEx256 current_palette{};
|
||||||
|
|
||||||
int gdrv::init(HINSTANCE hInst, HWND hWnd)
|
int gdrv::init(SDL_Renderer* render, int width, int height)
|
||||||
{
|
{
|
||||||
LOGPALETTEx256 current_palette{};
|
renderer = render;
|
||||||
|
vScreenTex = SDL_CreateTexture
|
||||||
|
(
|
||||||
|
renderer,
|
||||||
|
SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
width, height
|
||||||
|
);
|
||||||
|
pixels = memory::allocate(width * height * 4);
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
|
||||||
hinst = hInst;
|
|
||||||
hwnd = hWnd;
|
|
||||||
if (!palette_handle)
|
if (!palette_handle)
|
||||||
palette_handle = CreatePalette(¤t_palette);
|
palette_handle = CreatePalette(¤t_palette);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -32,6 +44,7 @@ int gdrv::uninit()
|
||||||
{
|
{
|
||||||
if (palette_handle)
|
if (palette_handle)
|
||||||
DeleteObject(palette_handle);
|
DeleteObject(palette_handle);
|
||||||
|
memory::free(pixels);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +198,8 @@ int gdrv::create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int si
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int gdrv::display_palette(PALETTEENTRY* plt)
|
int gdrv::display_palette(PALETTEENTRY* plt)
|
||||||
{
|
{
|
||||||
LOGPALETTEx256 current_palette{};
|
|
||||||
|
|
||||||
if (palette_handle)
|
if (palette_handle)
|
||||||
DeleteObject(palette_handle);
|
DeleteObject(palette_handle);
|
||||||
palette_handle = CreatePalette(¤t_palette);
|
palette_handle = CreatePalette(¤t_palette);
|
||||||
|
@ -212,9 +222,9 @@ int gdrv::display_palette(PALETTEENTRY* plt)
|
||||||
{
|
{
|
||||||
if (plt)
|
if (plt)
|
||||||
{
|
{
|
||||||
pltDst->peRed = pltSrc->peBlue;
|
pltDst->peRed = pltSrc->peRed;
|
||||||
pltDst->peGreen = pltSrc->peGreen;
|
pltDst->peGreen = pltSrc->peGreen;
|
||||||
pltDst->peBlue = pltSrc->peRed;
|
pltDst->peBlue = pltSrc->peBlue;
|
||||||
}
|
}
|
||||||
pltDst->peFlags = 4;
|
pltDst->peFlags = 4;
|
||||||
pltSrc++;
|
pltSrc++;
|
||||||
|
@ -426,7 +436,7 @@ int gdrv::StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int
|
||||||
{
|
{
|
||||||
/*Scaled partial updates may leave 1px border artifacts around update area.
|
/*Scaled partial updates may leave 1px border artifacts around update area.
|
||||||
* Pad update area to compensate.*/
|
* Pad update area to compensate.*/
|
||||||
const int pad = 1, padX2 = pad * 2;
|
/*const int pad = 1, padX2 = pad * 2;
|
||||||
if (fullscrn::ScaleX > 1 && xSrc > pad && xSrc + pad < bmp->Width)
|
if (fullscrn::ScaleX > 1 && xSrc > pad && xSrc + pad < bmp->Width)
|
||||||
{
|
{
|
||||||
xSrc -= pad;
|
xSrc -= pad;
|
||||||
|
@ -443,7 +453,7 @@ int gdrv::StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int
|
||||||
DestHeight += padX2;
|
DestHeight += padX2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return StretchDIBits(
|
StretchDIBits(
|
||||||
hdc,
|
hdc,
|
||||||
static_cast<int>(round(xDest * fullscrn::ScaleX + fullscrn::OffsetX)),
|
static_cast<int>(round(xDest * fullscrn::ScaleX + fullscrn::OffsetX)),
|
||||||
static_cast<int>(round(yDest * fullscrn::ScaleY + fullscrn::OffsetY)),
|
static_cast<int>(round(yDest * fullscrn::ScaleY + fullscrn::OffsetY)),
|
||||||
|
@ -456,5 +466,60 @@ int gdrv::StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int
|
||||||
bmp->BmpBufPtr1,
|
bmp->BmpBufPtr1,
|
||||||
bmp->Dib,
|
bmp->Dib,
|
||||||
iUsage,
|
iUsage,
|
||||||
rop);
|
rop);*/
|
||||||
|
|
||||||
|
//auto srcPtr = reinterpret_cast<uint8_t*>(bmp->BmpBufPtr1);
|
||||||
|
//auto dstPtr = reinterpret_cast<uint32_t*>(pixels);
|
||||||
|
//for (int y = Height; y > 0; --y)
|
||||||
|
//{
|
||||||
|
// for (int x = Width; x > 0; --x)
|
||||||
|
// *dstPtr++ = *(uint32_t*)¤t_palette.palPalEntry[*srcPtr++];
|
||||||
|
|
||||||
|
// //srcPtr += srcBmp->Stride - width;
|
||||||
|
// //dstPtr += dstBmp->Stride - width;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Clamp out of bounds rectangles
|
||||||
|
ySrc = max(0, min(ySrc, bmp->Height));
|
||||||
|
xSrc = max(0, min(xSrc, bmp->Height));
|
||||||
|
if (ySrc + SrcHeight > Height)
|
||||||
|
SrcHeight = Height - ySrc;
|
||||||
|
if (xSrc + SrcWidth > Width)
|
||||||
|
SrcWidth = Width - xSrc;
|
||||||
|
|
||||||
|
auto srcPtr = reinterpret_cast<uint8_t*>(&bmp->BmpBufPtr1[bmp->Stride * (ySrc)+xSrc]);
|
||||||
|
auto dstPtr = &reinterpret_cast<uint32_t*>(pixels)[Width * (ySrc)+xSrc];
|
||||||
|
for (int y = SrcHeight; y > 0; --y)
|
||||||
|
{
|
||||||
|
for (int x = SrcWidth; x > 0; --x)
|
||||||
|
{
|
||||||
|
if ((char*)dstPtr >= (pixels + Width * Height * 4) || (char*)srcPtr >= (bmp->BmpBufPtr1 + bmp->Stride * bmp->Width))
|
||||||
|
{
|
||||||
|
dstPtr = dstPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dstPtr++ = *(uint32_t*)¤t_palette.palPalEntry[*srcPtr++];
|
||||||
|
}
|
||||||
|
|
||||||
|
srcPtr += bmp->Stride - SrcWidth;
|
||||||
|
dstPtr += Width - SrcWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* lockedPixels = nullptr;
|
||||||
|
int pitch = 0;
|
||||||
|
SDL_LockTexture
|
||||||
|
(
|
||||||
|
vScreenTex,
|
||||||
|
nullptr,
|
||||||
|
reinterpret_cast<void**>(&lockedPixels),
|
||||||
|
&pitch
|
||||||
|
);
|
||||||
|
std::memcpy(lockedPixels, pixels, Width * Height * 4);
|
||||||
|
SDL_UnlockTexture(vScreenTex);
|
||||||
|
|
||||||
|
SDL_Rect dstRect
|
||||||
|
{ xDest,yDest,Width,Height };
|
||||||
|
SDL_RenderCopyEx(renderer, vScreenTex, nullptr, nullptr, 0, 0, SDL_FLIP_VERTICAL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
static HDC sequence_hdc;
|
static HDC sequence_hdc;
|
||||||
static int use_wing;
|
static int use_wing;
|
||||||
|
|
||||||
static int init(HINSTANCE hInst, HWND hWnd);
|
static int init(SDL_Renderer* renderer, int width, int height);
|
||||||
static int uninit();
|
static int uninit();
|
||||||
static void get_focus();
|
static void get_focus();
|
||||||
static BITMAPINFO* DibCreate(int16_t bpp, int width, int height);
|
static BITMAPINFO* DibCreate(int16_t bpp, int width, int height);
|
||||||
|
@ -68,8 +68,7 @@ public:
|
||||||
private:
|
private:
|
||||||
/*COLORONCOLOR or HALFTONE*/
|
/*COLORONCOLOR or HALFTONE*/
|
||||||
static const int stretchMode = COLORONCOLOR;
|
static const int stretchMode = COLORONCOLOR;
|
||||||
static HWND hwnd;
|
static SDL_Renderer* renderer;
|
||||||
static HINSTANCE hinst;
|
|
||||||
static int grtext_blue;
|
static int grtext_blue;
|
||||||
static int grtext_green;
|
static int grtext_green;
|
||||||
static int grtext_red;
|
static int grtext_red;
|
||||||
|
|
|
@ -177,9 +177,9 @@ void high_score::show_and_set_high_score_dialog(high_score_struct* table, int sc
|
||||||
dlg_hst = table;
|
dlg_hst = table;
|
||||||
dlg_enter_name = 1;
|
dlg_enter_name = 1;
|
||||||
default_name = defaultName;
|
default_name = defaultName;
|
||||||
while (DialogBoxParamA(winmain::hinst, "dlg_highscores", winmain::hwnd_frame, HighScore, 0))
|
/*while (DialogBoxParamA(winmain::hinst, "dlg_highscores", winmain::hwnd_frame, HighScore, 0))
|
||||||
{
|
{
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
INT_PTR high_score::HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
INT_PTR high_score::HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
|
@ -320,7 +320,7 @@ float loader::play_sound(int soundIndex)
|
||||||
{
|
{
|
||||||
if (soundIndex <= 0)
|
if (soundIndex <= 0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
Sound::PlaySound(sound_list[soundIndex].WavePtr, 0, 7, WMIX_HIPRIORITY | WMIX_CLEARQUEUE, 0);
|
Sound::PlaySound(sound_list[soundIndex].WavePtr, 0, 7, 0, 0);
|
||||||
return sound_list[soundIndex].Duration;
|
return sound_list[soundIndex].Duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "gdrv.h"
|
#include "gdrv.h"
|
||||||
#include "maths.h"
|
#include "maths.h"
|
||||||
#include "WaveMix.h"
|
|
||||||
#include "zdrv.h"
|
#include "zdrv.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ struct errorMsg
|
||||||
|
|
||||||
struct soundListStruct
|
struct soundListStruct
|
||||||
{
|
{
|
||||||
MIXWAVE* WavePtr;
|
Mix_Chunk* WavePtr;
|
||||||
int GroupIndex;
|
int GroupIndex;
|
||||||
int Loaded;
|
int Loaded;
|
||||||
float Duration;
|
float Duration;
|
||||||
|
|
|
@ -5,10 +5,7 @@
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
#include "pinball.h"
|
#include "pinball.h"
|
||||||
|
|
||||||
tagMCI_OPEN_PARMSA midi::mci_open_info;
|
Mix_Music* midi::currentMidi;
|
||||||
char midi::midi_file_name[28];
|
|
||||||
HWND midi::midi_notify_hwnd;
|
|
||||||
int midi::midi_seq1_open, midi::midi_seq1_playing;
|
|
||||||
|
|
||||||
MCIERROR midi::play_pb_theme(int flag)
|
MCIERROR midi::play_pb_theme(int flag)
|
||||||
{
|
{
|
||||||
|
@ -17,17 +14,11 @@ MCIERROR midi::play_pb_theme(int flag)
|
||||||
return play_ft(track1);
|
return play_ft(track1);
|
||||||
}
|
}
|
||||||
|
|
||||||
MCI_PLAY_PARMS playParams;
|
|
||||||
MCIERROR result = 0;
|
MCIERROR result = 0;
|
||||||
|
|
||||||
music_stop();
|
music_stop();
|
||||||
playParams.dwFrom = 0;
|
if (currentMidi)
|
||||||
playParams.dwCallback = (DWORD_PTR)midi_notify_hwnd;
|
result = Mix_PlayMusic(currentMidi, -1);
|
||||||
if (!flag && midi_seq1_open)
|
|
||||||
{
|
|
||||||
result = mciSendCommandA(mci_open_info.wDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD_PTR)&playParams);
|
|
||||||
midi_seq1_playing = result == 0;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +29,7 @@ MCIERROR midi::music_stop()
|
||||||
return stop_ft();
|
return stop_ft();
|
||||||
}
|
}
|
||||||
|
|
||||||
MCIERROR result = 0;
|
return Mix_HaltMusic();
|
||||||
if (midi_seq1_playing)
|
|
||||||
result = mciSendCommandA(mci_open_info.wDeviceID, MCI_STOP, 0, 0);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int midi::music_init(HWND hwnd)
|
int midi::music_init(HWND hwnd)
|
||||||
|
@ -51,14 +39,8 @@ int midi::music_init(HWND hwnd)
|
||||||
return music_init_ft(hwnd);
|
return music_init_ft(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
mci_open_info.wDeviceID = 0;
|
currentMidi = Mix_LoadMUS(pinball::get_rc_string(156, 0));
|
||||||
midi_notify_hwnd = hwnd;
|
return currentMidi != nullptr;
|
||||||
lstrcpyA(midi_file_name, pinball::get_rc_string(156, 0));
|
|
||||||
mci_open_info.lpstrElementName = midi_file_name;
|
|
||||||
mci_open_info.lpstrDeviceType = nullptr;
|
|
||||||
auto result = mciSendCommandA(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_NOTIFY_SUPERSEDED, (DWORD_PTR)&mci_open_info);
|
|
||||||
midi_seq1_open = result == 0;
|
|
||||||
return midi_seq1_open;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MCIERROR midi::restart_midi_seq(LPARAM param)
|
MCIERROR midi::restart_midi_seq(LPARAM param)
|
||||||
|
@ -68,13 +50,11 @@ MCIERROR midi::restart_midi_seq(LPARAM param)
|
||||||
return play_ft(active_track);
|
return play_ft(active_track);
|
||||||
}
|
}
|
||||||
|
|
||||||
MCI_PLAY_PARMS playParams;
|
|
||||||
MCIERROR result = 0;
|
MCIERROR result = 0;
|
||||||
|
music_stop();
|
||||||
|
if (currentMidi)
|
||||||
|
result = Mix_PlayMusic(currentMidi, -1);
|
||||||
|
|
||||||
playParams.dwFrom = 0;
|
|
||||||
playParams.dwCallback = (DWORD_PTR)midi_notify_hwnd;
|
|
||||||
if (midi_seq1_playing)
|
|
||||||
result = mciSendCommandA(mci_open_info.wDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD_PTR)&playParams);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +66,7 @@ void midi::music_shutdown()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (midi_seq1_open)
|
Mix_FreeMusic(currentMidi);
|
||||||
mciSendCommandA(mci_open_info.wDeviceID, MCI_CLOSE, 0, 0);
|
|
||||||
midi_seq1_open = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +76,6 @@ int midi::some_flag1;
|
||||||
|
|
||||||
int midi::music_init_ft(HWND hwnd)
|
int midi::music_init_ft(HWND hwnd)
|
||||||
{
|
{
|
||||||
midi_notify_hwnd = hwnd;
|
|
||||||
active_track = nullptr;
|
active_track = nullptr;
|
||||||
TrackList = new objlist_class<midi_struct>(0, 1);
|
TrackList = new objlist_class<midi_struct>(0, 1);
|
||||||
|
|
||||||
|
@ -423,7 +400,7 @@ int midi::stream_open(midi_struct* midi, char flags)
|
||||||
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
||||||
return 6;
|
return 6;
|
||||||
|
|
||||||
UINT puDeviceID = -1;
|
/*UINT puDeviceID = -1;
|
||||||
auto steamOpenedFg = !midi->StreamHandle;
|
auto steamOpenedFg = !midi->StreamHandle;
|
||||||
MIDIPROPTIMEDIV propdata{8, midi->DwTimeFormat};
|
MIDIPROPTIMEDIV propdata{8, midi->DwTimeFormat};
|
||||||
if (steamOpenedFg &&
|
if (steamOpenedFg &&
|
||||||
|
@ -463,15 +440,15 @@ int midi::stream_open(midi_struct* midi, char flags)
|
||||||
{
|
{
|
||||||
if (midi->StreamHandle)
|
if (midi->StreamHandle)
|
||||||
stream_close(midi);
|
stream_close(midi);
|
||||||
}
|
}*/
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int midi::stream_close(midi_struct* midi)
|
int midi::stream_close(midi_struct* midi)
|
||||||
{
|
{
|
||||||
int returnCode;
|
int returnCode = 0;
|
||||||
|
|
||||||
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
/*if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
||||||
return 6;
|
return 6;
|
||||||
if (!midi->StreamHandle)
|
if (!midi->StreamHandle)
|
||||||
return 7;
|
return 7;
|
||||||
|
@ -493,7 +470,7 @@ int midi::stream_close(midi_struct* midi)
|
||||||
returnCode = 0;
|
returnCode = 0;
|
||||||
midi->StreamHandle = nullptr;
|
midi->StreamHandle = nullptr;
|
||||||
midi->SomeFlag2 = 0;
|
midi->SomeFlag2 = 0;
|
||||||
}
|
}*/
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,8 +480,8 @@ void midi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PT
|
||||||
{
|
{
|
||||||
auto mhdr = reinterpret_cast<LPMIDIHDR>(dwParam1);
|
auto mhdr = reinterpret_cast<LPMIDIHDR>(dwParam1);
|
||||||
auto midi = reinterpret_cast<midi_struct*>(mhdr->dwUser);
|
auto midi = reinterpret_cast<midi_struct*>(mhdr->dwUser);
|
||||||
if ((midi->SomeFlag2 & 2) == 0 || (midi->SomeFlag2 & 1) != 0 || midiStreamOut(
|
/*if ((midi->SomeFlag2 & 2) == 0 || (midi->SomeFlag2 & 1) != 0 || midiStreamOut(
|
||||||
midi->StreamHandle, mhdr, sizeof(MIDIHDR)))
|
midi->StreamHandle, mhdr, sizeof(MIDIHDR)))
|
||||||
--midi->PreparedBlocksCount;
|
--midi->PreparedBlocksCount;*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,7 @@ public:
|
||||||
static MCIERROR restart_midi_seq(LPARAM param);
|
static MCIERROR restart_midi_seq(LPARAM param);
|
||||||
static void music_shutdown();
|
static void music_shutdown();
|
||||||
private:
|
private:
|
||||||
static tagMCI_OPEN_PARMSA mci_open_info;
|
static Mix_Music* currentMidi;
|
||||||
static char midi_file_name[28];
|
|
||||||
static HWND midi_notify_hwnd;
|
|
||||||
static int midi_seq1_open, midi_seq1_playing;
|
|
||||||
|
|
||||||
static objlist_class<midi_struct>* TrackList;
|
static objlist_class<midi_struct>* TrackList;
|
||||||
static midi_struct *track1, *track2, *track3, *active_track, *active_track2;
|
static midi_struct *track1, *track2, *track3, *active_track, *active_track2;
|
||||||
|
|
|
@ -76,18 +76,18 @@ void options::init(HMENU menuHandle)
|
||||||
Options.FullScreen = 0;
|
Options.FullScreen = 0;
|
||||||
Options.Average = 5;
|
Options.Average = 5;
|
||||||
Options.PriorityAdj = 2;
|
Options.PriorityAdj = 2;
|
||||||
Options.LeftFlipperKeyDft = 90;
|
Options.LeftFlipperKeyDft = SDLK_z;
|
||||||
Options.RightFlipperKeyDft = 191;
|
Options.RightFlipperKeyDft = SDLK_SLASH;
|
||||||
Options.PlungerKeyDft = 32;
|
Options.PlungerKeyDft = SDLK_SPACE;
|
||||||
Options.LeftTableBumpKeyDft = 88;
|
Options.LeftTableBumpKeyDft = SDLK_x;
|
||||||
Options.RightTableBumpKeyDft = 190;
|
Options.RightTableBumpKeyDft = SDLK_GREATER;
|
||||||
Options.BottomTableBumpKeyDft = 38;
|
Options.BottomTableBumpKeyDft = SDLK_UP;
|
||||||
pinball::get_rc_int(159, &Options.LeftFlipperKeyDft);
|
/*pinball::get_rc_int(159, &Options.LeftFlipperKeyDft);
|
||||||
pinball::get_rc_int(160, &Options.RightFlipperKeyDft);
|
pinball::get_rc_int(160, &Options.RightFlipperKeyDft);
|
||||||
pinball::get_rc_int(161, &Options.PlungerKeyDft);
|
pinball::get_rc_int(161, &Options.PlungerKeyDft);
|
||||||
pinball::get_rc_int(162, &Options.LeftTableBumpKeyDft);
|
pinball::get_rc_int(162, &Options.LeftTableBumpKeyDft);
|
||||||
pinball::get_rc_int(163, &Options.RightTableBumpKeyDft);
|
pinball::get_rc_int(163, &Options.RightTableBumpKeyDft);
|
||||||
pinball::get_rc_int(164, &Options.BottomTableBumpKeyDft);
|
pinball::get_rc_int(164, &Options.BottomTableBumpKeyDft);*/
|
||||||
Options.LeftFlipperKey = Options.LeftFlipperKeyDft;
|
Options.LeftFlipperKey = Options.LeftFlipperKeyDft;
|
||||||
Options.RightFlipperKey = Options.RightFlipperKeyDft;
|
Options.RightFlipperKey = Options.RightFlipperKeyDft;
|
||||||
Options.PlungerKey = Options.PlungerKeyDft;
|
Options.PlungerKey = Options.PlungerKeyDft;
|
||||||
|
@ -95,7 +95,7 @@ void options::init(HMENU menuHandle)
|
||||||
Options.RightTableBumpKey = Options.RightTableBumpKeyDft;
|
Options.RightTableBumpKey = Options.RightTableBumpKeyDft;
|
||||||
Options.Players = 1;
|
Options.Players = 1;
|
||||||
Options.BottomTableBumpKey = Options.BottomTableBumpKeyDft;
|
Options.BottomTableBumpKey = Options.BottomTableBumpKeyDft;
|
||||||
Options.Sounds = get_int(nullptr, "Sounds", Options.Sounds);
|
/*Options.Sounds = get_int(nullptr, "Sounds", Options.Sounds);
|
||||||
Options.Music = get_int(nullptr, "Music", Options.Music);
|
Options.Music = get_int(nullptr, "Music", Options.Music);
|
||||||
Options.Average = get_int(nullptr, "Average", Options.Average);
|
Options.Average = get_int(nullptr, "Average", Options.Average);
|
||||||
Options.FullScreen = get_int(nullptr, "FullScreen", Options.FullScreen);
|
Options.FullScreen = get_int(nullptr, "FullScreen", Options.FullScreen);
|
||||||
|
@ -107,7 +107,7 @@ void options::init(HMENU menuHandle)
|
||||||
Options.LeftTableBumpKey = get_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey);
|
Options.LeftTableBumpKey = get_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey);
|
||||||
Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
||||||
Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
||||||
Options.UniformScaling = get_int(nullptr, "Uniform scaling", true);
|
Options.UniformScaling = get_int(nullptr, "Uniform scaling", true);*/
|
||||||
menu_check(Menu1_Sounds, Options.Sounds);
|
menu_check(Menu1_Sounds, Options.Sounds);
|
||||||
Sound::Enable(0, 7, Options.Sounds);
|
Sound::Enable(0, 7, Options.Sounds);
|
||||||
menu_check(Menu1_Music, Options.Music);
|
menu_check(Menu1_Music, Options.Music);
|
||||||
|
@ -137,7 +137,7 @@ void options::init(HMENU menuHandle)
|
||||||
|
|
||||||
void options::uninit()
|
void options::uninit()
|
||||||
{
|
{
|
||||||
set_int(nullptr, "Sounds", Options.Sounds);
|
/*set_int(nullptr, "Sounds", Options.Sounds);
|
||||||
set_int(nullptr, "Music", Options.Music);
|
set_int(nullptr, "Music", Options.Music);
|
||||||
set_int(nullptr, "FullScreen", Options.FullScreen);
|
set_int(nullptr, "FullScreen", Options.FullScreen);
|
||||||
set_int(nullptr, "Players", Options.Players);
|
set_int(nullptr, "Players", Options.Players);
|
||||||
|
@ -148,7 +148,7 @@ void options::uninit()
|
||||||
set_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
set_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
||||||
set_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
set_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
||||||
set_int(nullptr, "Screen Resolution", Options.Resolution);
|
set_int(nullptr, "Screen Resolution", Options.Resolution);
|
||||||
set_int(nullptr, "Uniform scaling", Options.UniformScaling);
|
set_int(nullptr, "Uniform scaling", Options.UniformScaling);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::path_init(LPCSTR regPath)
|
void options::path_init(LPCSTR regPath)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "winmain.h"
|
#include "winmain.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "Sound.h"
|
||||||
#include "TBall.h"
|
#include "TBall.h"
|
||||||
#include "TDemo.h"
|
#include "TDemo.h"
|
||||||
#include "TEdgeSegment.h"
|
#include "TEdgeSegment.h"
|
||||||
|
@ -32,7 +33,7 @@ high_score_struct pb::highscore_table[5];
|
||||||
bool pb::FullTiltMode = false;
|
bool pb::FullTiltMode = false;
|
||||||
|
|
||||||
|
|
||||||
int pb::init()
|
int pb::init(SDL_Renderer* render)
|
||||||
{
|
{
|
||||||
float projMat[12], zMin = 0, zScaler = 0;
|
float projMat[12], zMin = 0, zScaler = 0;
|
||||||
CHAR datFileName[300];
|
CHAR datFileName[300];
|
||||||
|
@ -74,6 +75,7 @@ int pb::init()
|
||||||
zScaler = cameraInfo[2];
|
zScaler = cameraInfo[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdrv::init(render, resInfo->TableWidth, resInfo->TableHeight);
|
||||||
render::init(nullptr, zMin, zScaler, resInfo->TableWidth, resInfo->TableHeight);
|
render::init(nullptr, zMin, zScaler, resInfo->TableWidth, resInfo->TableHeight);
|
||||||
gdrv::copy_bitmap(
|
gdrv::copy_bitmap(
|
||||||
&render::vscreen,
|
&render::vscreen,
|
||||||
|
@ -332,6 +334,7 @@ void pb::pause_continue()
|
||||||
MainTable->Message(1008, time_now);
|
MainTable->Message(1008, time_now);
|
||||||
pinball::InfoTextBox->Display(pinball::get_rc_string(22, 0), -1.0);
|
pinball::InfoTextBox->Display(pinball::get_rc_string(22, 0), -1.0);
|
||||||
midi::music_stop();
|
midi::music_stop();
|
||||||
|
Sound::Deactivate();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -355,6 +358,7 @@ void pb::pause_continue()
|
||||||
}
|
}
|
||||||
if (options::Options.Music && !winmain::single_step)
|
if (options::Options.Music && !winmain::single_step)
|
||||||
midi::play_pb_theme(0);
|
midi::play_pb_theme(0);
|
||||||
|
Sound::Activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
static high_score_struct highscore_table[5];
|
static high_score_struct highscore_table[5];
|
||||||
static bool FullTiltMode;
|
static bool FullTiltMode;
|
||||||
|
|
||||||
static int init();
|
static int init(SDL_Renderer* render);
|
||||||
static int uninit();
|
static int uninit();
|
||||||
static void reset_table();
|
static void reset_table();
|
||||||
static void firsttime_setup();
|
static void firsttime_setup();
|
||||||
|
|
|
@ -18,8 +18,15 @@
|
||||||
#include <htmlhelp.h>
|
#include <htmlhelp.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits> /*For control template*/
|
#include <type_traits> /*For control template*/
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
//#include <cstdlib>
|
//#include <cstdlib>
|
||||||
|
|
||||||
|
#define SDL_MAIN_HANDLED
|
||||||
|
#include "SDL.h"
|
||||||
|
#include <SDL_mixer.h>
|
||||||
|
|
||||||
/*Use (void) to silent unused warnings.*/
|
/*Use (void) to silent unused warnings.*/
|
||||||
#define assertm(exp, msg) assert(((void)msg, exp))
|
#define assertm(exp, msg) assert(((void)msg, exp))
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,220 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "winmain.h"
|
#include "winmain.h"
|
||||||
|
|
||||||
|
// Todo: load translations from file
|
||||||
|
std::map<uint32_t, LPCSTR> rc_strings
|
||||||
|
{
|
||||||
|
{0, "Replay Awarded"},
|
||||||
|
{1, "Ball Locked"},
|
||||||
|
{2, "Center Post\n%ld"},
|
||||||
|
{3, "Bonus Awarded\n%ld"},
|
||||||
|
{4, "Bonus Activated"},
|
||||||
|
{5, "Weapons Upgraded"},
|
||||||
|
{6, "Engine Upgraded"},
|
||||||
|
{7, "Bonus up 1 Million"},
|
||||||
|
{8, "Extra Ball Available\n%ld"},
|
||||||
|
{9, "Extra Ball"},
|
||||||
|
{10, "Reflex Shot Award\n%ld"},
|
||||||
|
{11, "Final Battle Won"},
|
||||||
|
{12, "Hyperspace Bonus\n%ld"},
|
||||||
|
{13, "Hyperspace Bonus Available"},
|
||||||
|
{14, "Jackpot Awarded\n%ld"},
|
||||||
|
{15, "Jackpot Activated"},
|
||||||
|
{16, "Multiball"},
|
||||||
|
{17, "Ramp Bonus Awarded"},
|
||||||
|
{18, "Light Added"},
|
||||||
|
{19, "Ramp Bonus On"},
|
||||||
|
{20, "Light Reset Off"},
|
||||||
|
{21, "Skill Shot\n%ld"},
|
||||||
|
{22, "Game Paused\nF3 to Resume"},
|
||||||
|
{23, "Continue Play"},
|
||||||
|
{24, "F2 Starts New Game"},
|
||||||
|
{25, "Careful..."},
|
||||||
|
{26, "Player 1"},
|
||||||
|
{27, "Player 2"},
|
||||||
|
{28, "Player 3"},
|
||||||
|
{29, "Player 4"},
|
||||||
|
{30, "Demo\nPlayer 1"},
|
||||||
|
{31, "Demo\nPlayer 2"},
|
||||||
|
{32, "Demo\nPlayer 3"},
|
||||||
|
{33, "Demo\nPlayer 4"},
|
||||||
|
{34, "Game Over"},
|
||||||
|
{35, "TILT!"},
|
||||||
|
{36, "This program requires an 80386 or later CPU."},
|
||||||
|
{37, "80386 Required"},
|
||||||
|
{38, "3D Pinball for Windows - Space Cadet"},
|
||||||
|
{
|
||||||
|
39,
|
||||||
|
"One or more of the player controls is set to the same key,\nfor best performance use unique keys for each control."
|
||||||
|
},
|
||||||
|
{40, "Clear High Scores?"},
|
||||||
|
{41, "Confirm"},
|
||||||
|
{42, "WAVEMIX.INF is missing - it must be in the pinball directory!"},
|
||||||
|
{43, "Warning:"},
|
||||||
|
{44, "Ship Re-Fueled"},
|
||||||
|
{45, "Gravity Well"},
|
||||||
|
{46, "Time Warp Forward"},
|
||||||
|
{47, "Time Warp Backward"},
|
||||||
|
{48, "Maelstrom!"},
|
||||||
|
{49, "Wormhole"},
|
||||||
|
{50, "Awaiting Deployment"},
|
||||||
|
{51, "Flags Upgraded"},
|
||||||
|
{52, "Bonus Hold"},
|
||||||
|
{53, "Level One Commation"},
|
||||||
|
{54, "Level Two Commation"},
|
||||||
|
{55, "Level Three Commation"},
|
||||||
|
{56, "Field Multiplier 2x"},
|
||||||
|
{57, "Field Multiplier 3x"},
|
||||||
|
{58, "Field Multiplier 5x"},
|
||||||
|
{59, "Field Multiplier 10x"},
|
||||||
|
{60, "Target Practice"},
|
||||||
|
{61, "Launch Training"},
|
||||||
|
{62, "Re-Entry Training"},
|
||||||
|
{63, "Science"},
|
||||||
|
{64, "Stray Comet"},
|
||||||
|
{65, "Black Hole"},
|
||||||
|
{66, "Space Radiation"},
|
||||||
|
{67, "Bug Hunt"},
|
||||||
|
{68, "Alien Menace"},
|
||||||
|
{69, "Rescue"},
|
||||||
|
{70, "Satellite Retrieval"},
|
||||||
|
{71, "Recon"},
|
||||||
|
{72, "Doomsday Machine"},
|
||||||
|
{73, "Cosmic Plague"},
|
||||||
|
{74, "Secret"},
|
||||||
|
{75, "Time Warp"},
|
||||||
|
{76, "Maelstrom"},
|
||||||
|
{77, "Mission Accepted\n%ld"},
|
||||||
|
{78, "Mission Completed\n%ld"},
|
||||||
|
{79, "%s Mission Selected"},
|
||||||
|
{80, "Black Hole\n%ld"},
|
||||||
|
{81, "Gravity Normalized\n%ld"},
|
||||||
|
{82, "Gravity Well\n%ld"},
|
||||||
|
{83, "Promotion to %s"},
|
||||||
|
{84, "Cadet"},
|
||||||
|
{85, "Ensign"},
|
||||||
|
{86, "Lieutenant"},
|
||||||
|
{87, "Captain"},
|
||||||
|
{88, "Lt Commander"},
|
||||||
|
{89, "Commander"},
|
||||||
|
{90, "Commodore"},
|
||||||
|
{91, "Admiral"},
|
||||||
|
{92, "Fleet Admiral"},
|
||||||
|
{93, "Wormhole Opened"},
|
||||||
|
{94, "Crash Bonus\n%ld"},
|
||||||
|
{95, "Replay Ball"},
|
||||||
|
{96, "Re-Deploy"},
|
||||||
|
{97, "Player 1 Shoot Again"},
|
||||||
|
{98, "Player 2 Shoot Again"},
|
||||||
|
{99, "Player 3 Shoot Again"},
|
||||||
|
{100, "Player 4 Shoot Again"},
|
||||||
|
{
|
||||||
|
101,
|
||||||
|
"This 3D Pinball Table was created for Microsoft by Maxis.\nFor more information call (800)-336-2947\n(US and Canadian customers only).\nCopyright (c) 1995 Maxis."
|
||||||
|
},
|
||||||
|
{102, "3D Pinball Table created for Microsoft by Maxis. Copyright (c) 1995 Maxis."},
|
||||||
|
{103, "About 3D Pinball"},
|
||||||
|
{104, "Hit Mission Targets To Select Mission"},
|
||||||
|
{105, "Re-Fuel Ship"},
|
||||||
|
{106, "Launch Ramp To Accept %s Mission"},
|
||||||
|
{107, "Attack Bumpers Hits\nLeft: %d"},
|
||||||
|
{108, "Target Training Passed"},
|
||||||
|
{109, "Mission Aborted"},
|
||||||
|
{110, "Launches Left: %d"},
|
||||||
|
{111, "Launch Training Passed"},
|
||||||
|
{112, "Re-Entries Left: %d"},
|
||||||
|
{113, "Re-Entry Training Passed"},
|
||||||
|
{114, "Drop Targets\nLeft: %d"},
|
||||||
|
{115, "Science Mission Completed"},
|
||||||
|
{116, "Warning -- Low Fuel"},
|
||||||
|
{117, "Fill Right Hazard Banks"},
|
||||||
|
{118, "Hyperspace Launch"},
|
||||||
|
{119, "Comet Destroyed"},
|
||||||
|
{120, "Enter Wormhole"},
|
||||||
|
{121, "Radiation Eliminated"},
|
||||||
|
{122, "Upgrade Launch Bumpers"},
|
||||||
|
{123, "Enter Black Hole"},
|
||||||
|
{124, "Black Hole Eliminated"},
|
||||||
|
{125, "Targets\nLeft: %d"},
|
||||||
|
{126, "Xenomorphs Destroyed"},
|
||||||
|
{127, "Upgrade Flags"},
|
||||||
|
{128, "Hyperspace Launch"},
|
||||||
|
{129, "Survivors Rescued"},
|
||||||
|
{130, "Aliens Repelled"},
|
||||||
|
{131, "Hit Fuel Targets"},
|
||||||
|
{132, "Remote Attack Bumper Hits\nLeft: %d"},
|
||||||
|
{133, "Satellite Repaired"},
|
||||||
|
{134, "Lane Passes\nLeft: %d"},
|
||||||
|
{135, "Shoot Ball Up Fuel Chute"},
|
||||||
|
{136, "Survey Complete"},
|
||||||
|
{137, "Out Lane Passes\nLeft: %d"},
|
||||||
|
{138, "Doomsday Machine Destroyed"},
|
||||||
|
{139, "Roll Flags: %d"},
|
||||||
|
{140, "Hit Space Warp Rollover"},
|
||||||
|
{141, "Plague Eliminated"},
|
||||||
|
{142, "Hit Yellow Wormhole"},
|
||||||
|
{143, "Hit Red Wormhole"},
|
||||||
|
{144, "Hit Green Wormhole"},
|
||||||
|
{145, "Plans Recovered"},
|
||||||
|
{146, "Rebound Hits\nLeft: %d"},
|
||||||
|
{147, "Hit Hyperspace Chute or Launch Ramp"},
|
||||||
|
{148, "Drop Target Hits\nLeft: %d"},
|
||||||
|
{149, "Spot Target Hits\nLeft: %d"},
|
||||||
|
{150, "Lanes Passes\nLeft: %d"},
|
||||||
|
{151, "Shoot Ball Up Fuel Chute"},
|
||||||
|
{152, "Hit Launch Ramp"},
|
||||||
|
{153, "Hit Flags"},
|
||||||
|
{154, "Hit Worm Hole"},
|
||||||
|
{155, "Hyperspace Chute to Maelstrom"},
|
||||||
|
{156, "pinball.mid"},
|
||||||
|
{158, "1 UseBitmapFont"},
|
||||||
|
{159, "90 Left Flipper Key"},
|
||||||
|
{160, "191 Right Flipper Key"},
|
||||||
|
{161, "32 Plunger Key"},
|
||||||
|
{162, "88 Bump Left Key"},
|
||||||
|
{163, "190 Bump Right Key"},
|
||||||
|
{164, "38 Bump Bottom Key"},
|
||||||
|
{165, "Software\\Microsoft\\Plus!\\Pinball"},
|
||||||
|
{166, "SpaceCadet"},
|
||||||
|
{167, "1c7c22a0-9576-11ce-bf80-444553540000"},
|
||||||
|
{168, "PINBALL.DAT"},
|
||||||
|
{169, "Space Cadet"},
|
||||||
|
{170, "Error:"},
|
||||||
|
{171, "Unable to find other tables."},
|
||||||
|
{172, "3D Pinball\nSpace Cadet"},
|
||||||
|
{173, "Promotion to %s"},
|
||||||
|
{174, "Demotion to %s"},
|
||||||
|
{175, "Upgrade Attack Bumpers"},
|
||||||
|
{176, "Fill Left Hazard Banks"},
|
||||||
|
{177, "HIGH SCORE"},
|
||||||
|
{178, "pinball.chm"},
|
||||||
|
{179, "Not enough memory to run 3D Pinball."},
|
||||||
|
{180, "Player 1's Score\n%ld"},
|
||||||
|
{181, "Player 2's Score\n%ld"},
|
||||||
|
{182, "Player 3's Score\n%ld"},
|
||||||
|
{183, "Player 4's Score\n%ld"},
|
||||||
|
{184, "High Score 1\n%ld"},
|
||||||
|
{185, "High Score 2\n%ld"},
|
||||||
|
{186, "High Score 3\n%ld"},
|
||||||
|
{187, "High Score 4\n%ld"},
|
||||||
|
{188, "High Score 5\n%ld"},
|
||||||
|
{189, "255 255 255 (R G B default font color)"},
|
||||||
|
{2030, "Use &Maximum Resolution (640 x 480)"},
|
||||||
|
{2031, "Use &Maximum Resolution (800 x 600)"},
|
||||||
|
{2032, "Use &Maximum Resolution (1024 x 768)"}
|
||||||
|
};
|
||||||
|
|
||||||
|
int LoadStringL(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax)
|
||||||
|
{
|
||||||
|
auto str = rc_strings.find(uID);
|
||||||
|
if (str == rc_strings.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstrcpyA(lpBuffer, str->second);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int pinball::quickFlag = 0;
|
int pinball::quickFlag = 0;
|
||||||
TTextBox* pinball::InfoTextBox;
|
TTextBox* pinball::InfoTextBox;
|
||||||
|
@ -15,7 +229,7 @@ int pinball::RightShift = -1;
|
||||||
char* pinball::get_rc_string(int uID, int a2)
|
char* pinball::get_rc_string(int uID, int a2)
|
||||||
{
|
{
|
||||||
char* result = &getRcBuffer[256 * rc_string_slot];
|
char* result = &getRcBuffer[256 * rc_string_slot];
|
||||||
if (!LoadStringA(winmain::hinst, uID, &getRcBuffer[256 * rc_string_slot], 255))
|
if (!LoadStringL(winmain::hinst, uID, &getRcBuffer[256 * rc_string_slot], 255))
|
||||||
*result = 0;
|
*result = 0;
|
||||||
if (++rc_string_slot >= 6)
|
if (++rc_string_slot >= 6)
|
||||||
rc_string_slot = 0;
|
rc_string_slot = 0;
|
||||||
|
@ -25,7 +239,7 @@ char* pinball::get_rc_string(int uID, int a2)
|
||||||
int pinball::get_rc_int(int uID, int* dst)
|
int pinball::get_rc_int(int uID, int* dst)
|
||||||
{
|
{
|
||||||
char buffer[255];
|
char buffer[255];
|
||||||
int result = LoadStringA(winmain::hinst, uID, buffer, 255);
|
int result = LoadStringL(winmain::hinst, uID, buffer, 255);
|
||||||
if (!result)
|
if (!result)
|
||||||
return result;
|
return result;
|
||||||
*dst = atoi(buffer);
|
*dst = atoi(buffer);
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -11,9 +11,12 @@
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "splash.h"
|
#include "splash.h"
|
||||||
|
|
||||||
|
const double TargetFps = 60, TargetFrameTime = 1000 / TargetFps;
|
||||||
|
|
||||||
HINSTANCE winmain::hinst = nullptr;
|
HINSTANCE winmain::hinst = nullptr;
|
||||||
HWND winmain::hwnd_frame = nullptr;
|
HWND winmain::hwnd_frame = nullptr;
|
||||||
HCURSOR winmain::mouse_hsave;
|
HCURSOR winmain::mouse_hsave;
|
||||||
|
SDL_Window* winmain::MainWindow = nullptr;
|
||||||
|
|
||||||
int winmain::return_value = 0;
|
int winmain::return_value = 0;
|
||||||
int winmain::bQuit = 0;
|
int winmain::bQuit = 0;
|
||||||
|
@ -36,6 +39,15 @@ gdrv_bitmap8 winmain::gfr_display{};
|
||||||
char winmain::DatFileName[300]{};
|
char winmain::DatFileName[300]{};
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t timeGetTimeAlt()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
auto duration = now.time_since_epoch();
|
||||||
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
||||||
|
return static_cast<uint32_t>(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||||
{
|
{
|
||||||
return winmain::WinMain(hInstance, hPrevInstance, lpCmdLine, nShowCmd);
|
return winmain::WinMain(hInstance, hPrevInstance, lpCmdLine, nShowCmd);
|
||||||
|
@ -47,74 +59,19 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
++memory::critical_allocation;
|
++memory::critical_allocation;
|
||||||
auto optionsRegPath = pinball::get_rc_string(165, 0);
|
auto optionsRegPath = pinball::get_rc_string(165, 0);
|
||||||
options::path_init(optionsRegPath);
|
options::path_init(optionsRegPath);
|
||||||
auto regSpaceCadet = pinball::get_rc_string(166, 0);
|
|
||||||
|
|
||||||
if (options::get_int(regSpaceCadet, "Table Version", 1) <= 1)
|
|
||||||
{
|
|
||||||
auto tmpBuf = memory::allocate(0x1F4u);
|
|
||||||
if (!tmpBuf)
|
|
||||||
{
|
|
||||||
options::path_uninit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
options::set_int(regSpaceCadet, "Table Version", 1u);
|
|
||||||
GetModuleFileNameA(hinst, tmpBuf, 0x1F4u);
|
|
||||||
options::set_string(regSpaceCadet, "Table Exe", tmpBuf);
|
|
||||||
options::set_string(regSpaceCadet, "Table Name", pinball::get_rc_string(169, 0));
|
|
||||||
options::set_string(nullptr, "Last Table Played", regSpaceCadet);
|
|
||||||
memory::free(static_cast<void*>(tmpBuf));
|
|
||||||
tmpBuf = memory::allocate(0x1F4u);
|
|
||||||
if (tmpBuf)
|
|
||||||
{
|
|
||||||
auto tmpBuf2 = memory::allocate(0x1F4u);
|
|
||||||
if (tmpBuf2)
|
|
||||||
{
|
|
||||||
char Buffer[40];
|
|
||||||
bool setOption = false;
|
|
||||||
for (int i = 0; i < 32700; ++i)
|
|
||||||
{
|
|
||||||
sprintf_s(Buffer, "Table%d", i);
|
|
||||||
options::get_string(nullptr, Buffer, tmpBuf, "", 500);
|
|
||||||
if (!*tmpBuf)
|
|
||||||
break;
|
|
||||||
options::get_string(tmpBuf, "Table Name", tmpBuf2, "", 500);
|
|
||||||
if (!lstrcmpA(tmpBuf2, pinball::get_rc_string(169, 0)))
|
|
||||||
{
|
|
||||||
setOption = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!*tmpBuf2)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (setOption)
|
|
||||||
options::set_string(nullptr, Buffer, regSpaceCadet);
|
|
||||||
memory::free(tmpBuf2);
|
|
||||||
}
|
|
||||||
memory::free(tmpBuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto tmpBuf = memory::allocate(0x1F4u);
|
|
||||||
if (!tmpBuf)
|
|
||||||
{
|
|
||||||
options::path_uninit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
options::get_string(regSpaceCadet, "Shell Exe", tmpBuf, "", 500);
|
|
||||||
auto execRes = WinExec(tmpBuf, 5u);
|
|
||||||
memory::free(tmpBuf);
|
|
||||||
if (execRes >= 32)
|
|
||||||
{
|
|
||||||
options::path_uninit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--memory::critical_allocation;
|
--memory::critical_allocation;
|
||||||
|
|
||||||
|
// SDL init
|
||||||
|
SDL_SetMainReady();
|
||||||
|
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
||||||
|
{
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not initialize SDL2", SDL_GetError(), nullptr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
pinball::quickFlag = strstr(lpCmdLine, "-quick") != nullptr;
|
pinball::quickFlag = strstr(lpCmdLine, "-quick") != nullptr;
|
||||||
hinst = hInstance;
|
hinst = hInstance;
|
||||||
|
auto regSpaceCadet = pinball::get_rc_string(166, 0);
|
||||||
options::get_string(regSpaceCadet, "Pinball Data", DatFileName, pinball::get_rc_string(168, 0), 300);
|
options::get_string(regSpaceCadet, "Pinball Data", DatFileName, pinball::get_rc_string(168, 0), 300);
|
||||||
|
|
||||||
/*Check for full tilt .dat file and switch to it automatically*/
|
/*Check for full tilt .dat file and switch to it automatically*/
|
||||||
|
@ -141,38 +98,66 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
if (check_expiration_date())
|
if (check_expiration_date())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
INITCOMMONCONTROLSEX picce;
|
|
||||||
picce.dwSize = 8;
|
|
||||||
picce.dwICC = 5885;
|
|
||||||
InitCommonControlsEx(&picce);
|
|
||||||
|
|
||||||
WNDCLASSEXA wndClass{};
|
|
||||||
wndClass.cbSize = sizeof wndClass;
|
|
||||||
wndClass.style = CS_DBLCLKS | CS_BYTEALIGNCLIENT;
|
|
||||||
wndClass.lpfnWndProc = message_handler;
|
|
||||||
wndClass.cbClsExtra = 0;
|
|
||||||
wndClass.cbWndExtra = 0;
|
|
||||||
wndClass.hInstance = hInstance;
|
|
||||||
wndClass.hIcon = LoadIconA(hInstance, "ICON_1");
|
|
||||||
wndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW);
|
|
||||||
wndClass.hbrBackground = (HBRUSH)16;
|
|
||||||
wndClass.lpszMenuName = "MENU_1";
|
|
||||||
wndClass.lpszClassName = windowClass;
|
|
||||||
auto splash = splash::splash_screen(hInstance, "splash_bitmap", "splash_bitmap");
|
auto splash = splash::splash_screen(hInstance, "splash_bitmap", "splash_bitmap");
|
||||||
RegisterClassExA(&wndClass);
|
|
||||||
|
|
||||||
pinball::FindShiftKeys();
|
pinball::FindShiftKeys();
|
||||||
options::init_resolution();
|
options::init_resolution();
|
||||||
|
|
||||||
char windowName[40];
|
// SDL window
|
||||||
lstrcpyA(windowName, pinball::get_rc_string(38, 0));
|
SDL_Window* window = SDL_CreateWindow
|
||||||
windowHandle = CreateWindowExA(0, windowClass, windowName, WndStyle, 0, 0, 640, 480, nullptr, nullptr, hInstance,
|
(
|
||||||
nullptr);
|
pinball::get_rc_string(38, 0),
|
||||||
hwnd_frame = windowHandle;
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
if (!windowHandle)
|
800, 600,
|
||||||
|
SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE
|
||||||
|
);
|
||||||
|
MainWindow = window;
|
||||||
|
if (!window)
|
||||||
{
|
{
|
||||||
PostQuitMessage(0);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not create window", SDL_GetError(), nullptr);
|
||||||
return 0;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Renderer* renderer = SDL_CreateRenderer
|
||||||
|
(
|
||||||
|
window,
|
||||||
|
-1,
|
||||||
|
SDL_RENDERER_ACCELERATED
|
||||||
|
);
|
||||||
|
if (!renderer)
|
||||||
|
{
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not create renderer", SDL_GetError(), window);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PB init from message handler
|
||||||
|
{
|
||||||
|
RECT rect{};
|
||||||
|
++memory::critical_allocation;
|
||||||
|
|
||||||
|
auto prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT));
|
||||||
|
|
||||||
|
auto voiceCount = options::get_int(nullptr, "Voices", 8);
|
||||||
|
if (!Sound::Init(voiceCount))
|
||||||
|
options::menu_set(Menu1_Sounds, 0);
|
||||||
|
Sound::Activate();
|
||||||
|
|
||||||
|
if (!pinball::quickFlag && !midi::music_init((HWND)window))
|
||||||
|
options::menu_set(Menu1_Music, 0);
|
||||||
|
|
||||||
|
if (pb::init(renderer))
|
||||||
|
_exit(0);
|
||||||
|
SetCursor(prevCursor);
|
||||||
|
auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1);
|
||||||
|
auto menuHandle = GetMenu((HWND)window);
|
||||||
|
|
||||||
|
GetWindowRect(GetDesktopWindow(), &rect);
|
||||||
|
int width = rect.right - rect.left;
|
||||||
|
int height = rect.bottom - rect.top;
|
||||||
|
pb::window_size(&width, &height);
|
||||||
|
fullscrn::init(width, height, options::Options.FullScreen, (HWND)window, menuHandle,
|
||||||
|
changeDisplayFg);
|
||||||
|
|
||||||
|
--memory::critical_allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto menuHandle = GetMenu(windowHandle);
|
auto menuHandle = GetMenu(windowHandle);
|
||||||
|
@ -186,9 +171,8 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
options::menu_check(Menu1_Full_Screen, 1);
|
options::menu_check(Menu1_Full_Screen, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowWindow(hwnd_frame, nShowCmd);
|
SDL_ShowWindow(window);
|
||||||
fullscrn::set_screen_mode(options::Options.FullScreen);
|
fullscrn::set_screen_mode(options::Options.FullScreen);
|
||||||
UpdateWindow(hwnd_frame);
|
|
||||||
|
|
||||||
if (splash)
|
if (splash)
|
||||||
{
|
{
|
||||||
|
@ -197,9 +181,9 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
}
|
}
|
||||||
|
|
||||||
pinball::adjust_priority(options::Options.PriorityAdj);
|
pinball::adjust_priority(options::Options.PriorityAdj);
|
||||||
const auto startTime = timeGetTime();
|
const auto startTime = timeGetTimeAlt();
|
||||||
MSG wndMessage{};
|
MSG wndMessage{};
|
||||||
while (timeGetTime() >= startTime && timeGetTime() - startTime < 0) // Don't wait for now, was 2000
|
while (timeGetTimeAlt() >= startTime && timeGetTimeAlt() - startTime < 0) // Don't wait for now, was 2000
|
||||||
PeekMessageA(&wndMessage, hwnd_frame, 0, 0, 1u);
|
PeekMessageA(&wndMessage, hwnd_frame, 0, 0, 1u);
|
||||||
|
|
||||||
if (strstr(lpCmdLine, "-demo"))
|
if (strstr(lpCmdLine, "-demo"))
|
||||||
|
@ -207,21 +191,27 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
else
|
else
|
||||||
pb::replay_level(0);
|
pb::replay_level(0);
|
||||||
|
|
||||||
DWORD someTimeCounter = 300u, prevTime = 0u;
|
DWORD updateCounter = 300u, frameCounter = 0, prevTime = 0u;
|
||||||
then = timeGetTime();
|
then = timeGetTimeAlt();
|
||||||
|
|
||||||
|
double sdlTimerResMs = 1000.0 / static_cast<double>(SDL_GetPerformanceFrequency());
|
||||||
|
auto frameStart = static_cast<double>(SDL_GetPerformanceCounter());
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!someTimeCounter)
|
if (!updateCounter)
|
||||||
{
|
{
|
||||||
someTimeCounter = 300;
|
updateCounter = 300;
|
||||||
if (DispFrameRate)
|
if (DispFrameRate)
|
||||||
{
|
{
|
||||||
auto curTime = timeGetTime();
|
auto curTime = timeGetTimeAlt();
|
||||||
if (prevTime)
|
if (prevTime)
|
||||||
{
|
{
|
||||||
char buf[60];
|
char buf[60];
|
||||||
sprintf_s(buf, "Frames/sec = %02.02f", 300.0f / (static_cast<float>(curTime - prevTime) * 0.001f));
|
auto elapsedSec = static_cast<float>(curTime - prevTime) * 0.001f;
|
||||||
SetWindowTextA(hwnd_frame, buf);
|
sprintf_s(buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
|
||||||
|
300.0f / elapsedSec, frameCounter / elapsedSec);
|
||||||
|
SDL_SetWindowTitle(window, buf);
|
||||||
|
frameCounter = 0;
|
||||||
|
|
||||||
if (DispGRhistory)
|
if (DispGRhistory)
|
||||||
{
|
{
|
||||||
|
@ -257,7 +247,6 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound::Idle();
|
|
||||||
if (!ProcessWindowMessages() || bQuit)
|
if (!ProcessWindowMessages() || bQuit)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -265,22 +254,18 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
{
|
{
|
||||||
if (mouse_down)
|
if (mouse_down)
|
||||||
{
|
{
|
||||||
now = timeGetTime();
|
now = timeGetTimeAlt();
|
||||||
if (now - then >= 2)
|
if (now - then >= 2)
|
||||||
{
|
{
|
||||||
/*last_mouse_n is in client coordinates*/
|
int x, y;
|
||||||
POINT Point;
|
SDL_GetMouseState(&x, &y);
|
||||||
GetCursorPos(&Point);
|
pb::ballset(last_mouse_x - x, y - last_mouse_y);
|
||||||
ScreenToClient(hwnd_frame, &Point);
|
SDL_WarpMouseInWindow(window, last_mouse_x, last_mouse_y);
|
||||||
pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y);
|
|
||||||
Point = POINT{last_mouse_x, last_mouse_y};
|
|
||||||
ClientToScreen(hwnd_frame, &Point);
|
|
||||||
SetCursorPos(Point.x, Point.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!single_step)
|
if (!single_step)
|
||||||
{
|
{
|
||||||
auto curTime = timeGetTime();
|
auto curTime = timeGetTimeAlt();
|
||||||
now = curTime;
|
now = curTime;
|
||||||
if (no_time_loss)
|
if (no_time_loss)
|
||||||
{
|
{
|
||||||
|
@ -302,10 +287,20 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
||||||
{
|
{
|
||||||
fillChar = -7;
|
fillChar = -7;
|
||||||
}
|
}
|
||||||
gdrv::fill_bitmap(&gfr_display, 1, 10, 299 - someTimeCounter, 0, fillChar);
|
gdrv::fill_bitmap(&gfr_display, 1, 10, 299 - updateCounter, 0, fillChar);
|
||||||
}
|
}
|
||||||
--someTimeCounter;
|
--updateCounter;
|
||||||
then = now;
|
then = now;
|
||||||
|
|
||||||
|
auto frameEnd = static_cast<double>(SDL_GetPerformanceCounter());
|
||||||
|
auto elapsedMs = (frameEnd - frameStart) * sdlTimerResMs;
|
||||||
|
if (elapsedMs >= TargetFrameTime)
|
||||||
|
{
|
||||||
|
// Keep track of remainder, limited to one frame time.
|
||||||
|
frameStart = frameEnd - min(elapsedMs - TargetFrameTime, TargetFrameTime) / sdlTimerResMs;
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
frameCounter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,17 +385,17 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
|
||||||
++memory::critical_allocation;
|
++memory::critical_allocation;
|
||||||
|
|
||||||
auto prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT));
|
auto prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT));
|
||||||
gdrv::init(hinst, hWnd);
|
gdrv::init(nullptr,0,0);
|
||||||
|
|
||||||
auto voiceCount = options::get_int(nullptr, "Voices", 8);
|
auto voiceCount = options::get_int(nullptr, "Voices", 8);
|
||||||
if (!Sound::Init(hinst, voiceCount, nullptr))
|
if (!Sound::Init(voiceCount))
|
||||||
options::menu_set(Menu1_Sounds, 0);
|
options::menu_set(Menu1_Sounds, 0);
|
||||||
Sound::Activate();
|
Sound::Activate();
|
||||||
|
|
||||||
if (!pinball::quickFlag && !midi::music_init(hWnd))
|
if (!pinball::quickFlag && !midi::music_init(hWnd))
|
||||||
options::menu_set(Menu1_Music, 0);
|
options::menu_set(Menu1_Music, 0);
|
||||||
|
|
||||||
if (pb::init())
|
if (pb::init(nullptr))
|
||||||
_exit(0);
|
_exit(0);
|
||||||
SetCursor(prevCursor);
|
SetCursor(prevCursor);
|
||||||
auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1);
|
auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1);
|
||||||
|
@ -725,33 +720,187 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
|
||||||
return DefWindowProcA(hWnd, Msg, wParam, lParam);
|
return DefWindowProcA(hWnd, Msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int winmain::event_handler(const SDL_Event* event)
|
||||||
|
{
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case SDL_QUIT:
|
||||||
|
end_pause();
|
||||||
|
bQuit = 1;
|
||||||
|
PostQuitMessage(0);
|
||||||
|
fullscrn::shutdown();
|
||||||
|
return_value = 0;
|
||||||
|
return 0;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
pb::keyup(event->key.keysym.sym);
|
||||||
|
break;
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
if (!event->key.repeat)
|
||||||
|
pb::keydown(event->key.keysym.sym);
|
||||||
|
switch (event->key.keysym.sym)
|
||||||
|
{
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
if (options::Options.FullScreen)
|
||||||
|
options::toggle(Menu1_Full_Screen);
|
||||||
|
SDL_MinimizeWindow(MainWindow);
|
||||||
|
break;
|
||||||
|
case SDLK_F1:
|
||||||
|
help_introduction(hinst, (HWND)MainWindow);
|
||||||
|
break;
|
||||||
|
case SDLK_F2:
|
||||||
|
new_game();
|
||||||
|
break;
|
||||||
|
case SDLK_F3:
|
||||||
|
pause();
|
||||||
|
break;
|
||||||
|
case SDLK_F4:
|
||||||
|
options::toggle(Menu1_Full_Screen);
|
||||||
|
break;
|
||||||
|
case SDLK_F5:
|
||||||
|
options::toggle(Menu1_Sounds);
|
||||||
|
break;
|
||||||
|
case SDLK_F6:
|
||||||
|
options::toggle(Menu1_Music);
|
||||||
|
break;
|
||||||
|
case SDLK_F8:
|
||||||
|
if (!single_step)
|
||||||
|
pause();
|
||||||
|
options::keyboard();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb::cheat_mode)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (event->key.keysym.sym)
|
||||||
|
{
|
||||||
|
case SDLK_h:
|
||||||
|
DispGRhistory = 1;
|
||||||
|
break;
|
||||||
|
case SDLK_y:
|
||||||
|
SDL_SetWindowTitle(MainWindow, "Pinball");
|
||||||
|
DispFrameRate = DispFrameRate == 0;
|
||||||
|
break;
|
||||||
|
case SDLK_F1:
|
||||||
|
pb::frame(10);
|
||||||
|
break;
|
||||||
|
case SDLK_F10:
|
||||||
|
single_step = single_step == 0;
|
||||||
|
if (single_step == 0)
|
||||||
|
no_time_loss = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
switch (event->button.button)
|
||||||
|
{
|
||||||
|
case SDL_BUTTON_LEFT:
|
||||||
|
if (pb::cheat_mode)
|
||||||
|
{
|
||||||
|
mouse_down = 1;
|
||||||
|
last_mouse_x = event->button.x;
|
||||||
|
last_mouse_y = event->button.y;
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
SDL_SetWindowGrab(MainWindow, SDL_TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pb::keydown(options::Options.LeftFlipperKey);
|
||||||
|
break;
|
||||||
|
case SDL_BUTTON_RIGHT:
|
||||||
|
if (!pb::cheat_mode)
|
||||||
|
pb::keydown(options::Options.RightFlipperKey);
|
||||||
|
break;
|
||||||
|
case SDL_BUTTON_MIDDLE:
|
||||||
|
pb::keydown(options::Options.PlungerKey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
switch (event->button.button)
|
||||||
|
{
|
||||||
|
case SDL_BUTTON_LEFT:
|
||||||
|
if (mouse_down)
|
||||||
|
{
|
||||||
|
mouse_down = 0;
|
||||||
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
SDL_SetWindowGrab(MainWindow, SDL_FALSE);
|
||||||
|
}
|
||||||
|
if (!pb::cheat_mode)
|
||||||
|
pb::keyup(options::Options.LeftFlipperKey);
|
||||||
|
break;
|
||||||
|
case SDL_BUTTON_RIGHT:
|
||||||
|
if (!pb::cheat_mode)
|
||||||
|
pb::keyup(options::Options.RightFlipperKey);
|
||||||
|
break;
|
||||||
|
case SDL_BUTTON_MIDDLE:
|
||||||
|
pb::keyup(options::Options.PlungerKey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
switch (event->window.event)
|
||||||
|
{
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
|
case SDL_WINDOWEVENT_TAKE_FOCUS:
|
||||||
|
case SDL_WINDOWEVENT_EXPOSED:
|
||||||
|
case SDL_WINDOWEVENT_SHOWN:
|
||||||
|
activated = 1;
|
||||||
|
Sound::Activate();
|
||||||
|
if (options::Options.Music && !single_step)
|
||||||
|
midi::play_pb_theme(0);
|
||||||
|
no_time_loss = 1;
|
||||||
|
pinball::adjust_priority(options::Options.PriorityAdj);
|
||||||
|
has_focus = 1;
|
||||||
|
gdrv::get_focus();
|
||||||
|
fullscrn::force_redraw();
|
||||||
|
pb::paint();
|
||||||
|
break;
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
|
case SDL_WINDOWEVENT_HIDDEN:
|
||||||
|
activated = 0;
|
||||||
|
fullscrn::activate(0);
|
||||||
|
options::menu_check(Menu1_Full_Screen, 0);
|
||||||
|
options::Options.FullScreen = 0;
|
||||||
|
SetThreadPriority(GetCurrentThread(), 0);
|
||||||
|
Sound::Deactivate();
|
||||||
|
midi::music_stop();
|
||||||
|
has_focus = 0;
|
||||||
|
gdrv::get_focus();
|
||||||
|
pb::loose_focus();
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int winmain::ProcessWindowMessages()
|
int winmain::ProcessWindowMessages()
|
||||||
{
|
{
|
||||||
MSG Msg{};
|
SDL_Event event;
|
||||||
|
|
||||||
if (has_focus && !single_step)
|
if (has_focus && !single_step)
|
||||||
{
|
{
|
||||||
while (PeekMessageA(&Msg, nullptr, 0, 0, 1u))
|
while (SDL_PollEvent(&event))
|
||||||
{
|
{
|
||||||
TranslateMessage(&Msg);
|
if (!event_handler(&event))
|
||||||
DispatchMessageA(&Msg);
|
|
||||||
if (Msg.message == 18)
|
|
||||||
{
|
|
||||||
return_value = static_cast<int>(Msg.wParam);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
GetMessageA(&Msg, hwnd_frame, 0, 0);
|
|
||||||
TranslateMessage(&Msg);
|
SDL_WaitEvent(&event);
|
||||||
DispatchMessageA(&Msg);
|
return event_handler(&event);
|
||||||
if (Msg.message == 18)
|
|
||||||
{
|
|
||||||
return_value = static_cast<int>(Msg.wParam);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void winmain::memalloc_failure()
|
void winmain::memalloc_failure()
|
||||||
|
@ -842,7 +991,7 @@ void winmain::help_introduction(HINSTANCE a1, HWND a2)
|
||||||
options::get_string(pinball::get_rc_string(166, 0), "HelpFile", buf1, buf1, 500);
|
options::get_string(pinball::get_rc_string(166, 0), "HelpFile", buf1, buf1, 500);
|
||||||
lstrcpyA(buf2, buf1);
|
lstrcpyA(buf2, buf1);
|
||||||
memory::free(buf1);
|
memory::free(buf1);
|
||||||
HtmlHelpA(GetDesktopWindow(), buf2, 0, 0);
|
//HtmlHelpA(GetDesktopWindow(), buf2, 0, 0);
|
||||||
memory::free(buf2);
|
memory::free(buf2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,6 +13,7 @@ public:
|
||||||
|
|
||||||
static int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
|
static int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
|
||||||
static LRESULT CALLBACK message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
static int event_handler(const SDL_Event* event);
|
||||||
static void memalloc_failure();
|
static void memalloc_failure();
|
||||||
static int ProcessWindowMessages();
|
static int ProcessWindowMessages();
|
||||||
static int check_expiration_date();
|
static int check_expiration_date();
|
||||||
|
@ -31,6 +32,7 @@ private:
|
||||||
static gdrv_bitmap8 gfr_display;
|
static gdrv_bitmap8 gfr_display;
|
||||||
static HCURSOR mouse_hsave;
|
static HCURSOR mouse_hsave;
|
||||||
static bool restart;
|
static bool restart;
|
||||||
|
static SDL_Window* MainWindow;
|
||||||
|
|
||||||
static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
|
static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue