From b937f571219b16475cfdec78029c054cc50deede Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Thu, 26 May 2022 11:18:09 +0300 Subject: [PATCH] Merge from V2: Added support for multiple music tracks in FT mode. Issue #129. --- CompileForDrMemory.bat | 6 +- SpaceCadetPinball/TPinballTable.cpp | 3 + SpaceCadetPinball/control.cpp | 7 + SpaceCadetPinball/midi.cpp | 572 ++++++++++++++-------------- SpaceCadetPinball/midi.h | 81 +++- SpaceCadetPinball/options.cpp | 2 +- SpaceCadetPinball/pb.cpp | 4 +- SpaceCadetPinball/winmain.cpp | 2 +- 8 files changed, 371 insertions(+), 306 deletions(-) diff --git a/CompileForDrMemory.bat b/CompileForDrMemory.bat index 421476e..ff2a014 100644 --- a/CompileForDrMemory.bat +++ b/CompileForDrMemory.bat @@ -1,3 +1,7 @@ +@echo off + +mkdir DrMem + rc /Fo.\DrMem\SpaceCadetPinball.res ".\SpaceCadetPinball\SpaceCadetPinball.rc" - cl /Zi /MT /MP /EHsc /O /Ob0 /cgthreads4 /Fo.\DrMem\ /Fe.\DrMem\myapp.exe ".\SpaceCadetPinball\*.cpp" Comctl32.lib Winmm.lib Htmlhelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ".\DrMem\SpaceCadetPinball.res" \ No newline at end of file + cl /Zi /MT /MP /EHsc /O /Ob0 /cgthreads4 /Fo.\DrMem\ /Fe.\DrMem\SpaceCadetPinball.exe ".\SpaceCadetPinball\*.cpp" Comctl32.lib Winmm.lib Htmlhelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Imm32.lib ".\DrMem\SpaceCadetPinball.res" \ No newline at end of file diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index 773ef3f..7d51f9f 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -40,6 +40,7 @@ #include "TPlunger.h" #include "TFlipper.h" #include "TDrain.h" +#include "midi.h" int TPinballTable::score_multipliers[5] = {1, 2, 3, 5, 10}; @@ -466,6 +467,8 @@ int TPinballTable::Message(int code, float value) auto time = loader::play_sound(SoundIndex1); LightShowTimer = timer::set(time, this, LightShow_timeout); } + + midi::play_track(MidiTracks::Track1, true); break; case 1018: if (ReplayTimer) diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 90b7d12..2051027 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -27,6 +27,7 @@ #include "TRamp.h" #include "TPlunger.h" #include "TWall.h" +#include "midi.h" int control_bump_scores1[] = {500, 1000, 1500, 2000}; int control_roll_scores1[] = {2000}; @@ -730,6 +731,7 @@ void control::table_set_flag_lights() void control::table_set_multiball() { control_info_text_box_tag.Component->Display(pinball::get_rc_Wstring(16, 0), 2.0); + midi::play_track(MidiTracks::Track3, true); } void control::table_bump_ball_sink_lock() @@ -2339,6 +2341,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) { control_lite200_tag.Component->Message(20, 0.0); control_lite199_tag.Component->Message(20, 0.0); + midi::play_track(MidiTracks::Track1, false); } if (light_on(&control_lite200_tag)) { @@ -2871,6 +2874,7 @@ void control::GameoverController(int code, TPinballComponent* caller) control_flip1_tag.Component->Message(1022, 0.0); control_flip2_tag.Component->Message(1022, 0.0); control_mission_text_box_tag.Component->MessageField = 0; + midi::play_track(MidiTracks::Track1, false); return; } if (code != 67) @@ -3777,6 +3781,7 @@ void control::SelectMissionController(int code, TPinballComponent* caller) int addedScore = SpecialAddScore(mission_select_scores[scoreId]); wsprintfW(Buffer, pinball::get_rc_Wstring(77, 0), addedScore); control_mission_text_box_tag.Component->Display(Buffer, 4.0); + midi::play_track(MidiTracks::Track2, true); } return; } @@ -3890,6 +3895,7 @@ void control::SelectMissionController(int code, TPinballComponent* caller) return; } case 66: + midi::play_track(MidiTracks::Track1, false); control_lite198_tag.Component->Message(20, 0.0); control_outer_circle_tag.Component->Message(34, 0.0); control_ramp_tgt_lights_tag.Component->Message(20, 0.0); @@ -4179,6 +4185,7 @@ void control::WaitingDeploymentController(int code, TPinballComponent* caller) case 66: control_mission_text_box_tag.Component->Clear(); waiting_deployment_flag = 0; + midi::play_track(MidiTracks::Track1, false); break; case 67: control_mission_text_box_tag.Component->Display(pinball::get_rc_Wstring(50, 0), -1.0); diff --git a/SpaceCadetPinball/midi.cpp b/SpaceCadetPinball/midi.cpp index 92f3e1a..cf467f4 100644 --- a/SpaceCadetPinball/midi.cpp +++ b/SpaceCadetPinball/midi.cpp @@ -1,155 +1,269 @@ #include "pch.h" #include "midi.h" - #include "pb.h" #include "pinball.h" -tagMCI_OPEN_PARMSA midi::mci_open_info; -char midi::midi_file_name[28]; HWND midi::midi_notify_hwnd; -int midi::midi_seq1_open, midi::midi_seq1_playing; +objlist_class* midi::TrackList; +BaseMidi* midi::track1, * midi::track2, * midi::track3; +MidiTracks midi::ActiveTrack, midi::NextTrack; +bool midi::IsPlaying; -MCIERROR midi::play_pb_theme(int flag) +void midi::music_play() { - if (pb::FullTiltMode) + if (!IsPlaying) { - return play_ft(track1); + IsPlaying = true; + play_track(NextTrack, true); + NextTrack = MidiTracks::None; } - - MCI_PLAY_PARMS playParams; - MCIERROR result = 0; - - music_stop(); - playParams.dwFrom = 0; - playParams.dwCallback = (DWORD_PTR)midi_notify_hwnd; - 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; } -MCIERROR midi::music_stop() +void midi::music_stop() { - if (pb::FullTiltMode) + if (IsPlaying) { - return stop_ft(); + IsPlaying = false; + NextTrack = ActiveTrack; + StopPlayback(); } - - MCIERROR result = 0; - if (midi_seq1_playing) - result = mciSendCommandA(mci_open_info.wDeviceID, MCI_STOP, 0, 0); - return result; } int midi::music_init(HWND hwnd) { - if (pb::FullTiltMode) + TrackList = new objlist_class(0, 1); + midi_notify_hwnd = hwnd; + ActiveTrack = NextTrack = MidiTracks::None; + track1 = track2 = track3 = nullptr; + if (!pb::FullTiltMode) { - return music_init_ft(hwnd); + track1 = LoadTrack("PINBALL.MID"); + } + else + { + track1 = LoadTrack("TABA1.MDS"); + track2 = LoadTrack("TABA2.MDS"); + track3 = LoadTrack("TABA3.MDS"); } - mci_open_info.wDeviceID = 0; - midi_notify_hwnd = hwnd; - 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; + return track1 != nullptr; } -MCIERROR midi::restart_midi_seq(LPARAM param) +void midi::restart_midi_seq(LPARAM param) { - if (pb::FullTiltMode) - { - return play_ft(active_track); - } - - MCI_PLAY_PARMS playParams; - MCIERROR result = 0; - - 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; + auto midi = TrackToMidi(ActiveTrack); + if (midi != nullptr) + midi->Play(); } void midi::music_shutdown() { - if (pb::FullTiltMode) - { - music_shutdown_ft(); - return; - } + music_stop(); - if (midi_seq1_open) - mciSendCommandA(mci_open_info.wDeviceID, MCI_CLOSE, 0, 0); - midi_seq1_open = 0; -} - - -objlist_class* midi::TrackList; -midi_struct *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::active_track2; -int midi::some_flag1; - -int midi::music_init_ft(HWND hwnd) -{ - midi_notify_hwnd = hwnd; - active_track = nullptr; - TrackList = new objlist_class(0, 1); - - track1 = load_track("taba1"); - track2 = load_track("taba2"); - track3 = load_track("taba3"); - if (!track2) - track2 = track1; - if (!track3) - track3 = track1; - return 1; -} - -void midi::music_shutdown_ft() -{ - if (active_track) - stream_close(active_track); - while (TrackList->GetCount()) - { - midi_struct* midi = TrackList->Get(0); - unload_track(midi); + while (TrackList->GetCount()) { + auto midi = TrackList->Get(0); TrackList->Delete(midi); + delete midi; } - active_track = nullptr; + delete TrackList; } -midi_struct* midi::load_track(LPCSTR fileName) +void midi::StopPlayback() +{ + auto midi = TrackToMidi(ActiveTrack); + if (midi != nullptr) + { + midi->Stop(); + ActiveTrack = MidiTracks::None; + } +} + +BaseMidi* midi::LoadTrack(LPCSTR fileName) +{ + BaseMidi* track; + if (pb::FullTiltMode) + { + track = new MdsMidi(fileName); + } + else + { + track = new MciMidi(fileName, midi_notify_hwnd); + } + if (track->IsOpen) + { + TrackList->Add(track); + return track; + } + + delete track; + return nullptr; +} + +BaseMidi* midi::TrackToMidi(MidiTracks track) +{ + BaseMidi* midi; + switch (track) + { + default: + case MidiTracks::None: + midi = nullptr; + break; + case MidiTracks::Track1: + midi = track1; + break; + case MidiTracks::Track2: + midi = track2; + break; + case MidiTracks::Track3: + midi = track3; + break; + } + return midi; +} + +bool midi::play_track(MidiTracks track, bool replay) +{ + auto midi = TrackToMidi(track); + if (!midi || (!replay && ActiveTrack == track)) + return false; + + StopPlayback(); + + if (!IsPlaying) + { + NextTrack = track; + return false; + } + + midi->Play(); + ActiveTrack = track; + return true; +} + +#pragma region MdsMidi +MdsMidi::MdsMidi(LPCSTR fileName) { - midi_struct* midi; char filePath[256]; char fileName2[256]; lstrcpyA(fileName2, "sound\\"); lstrcatA(fileName2, fileName); pinball::make_path_name(filePath, fileName2, 254u); - lstrcatA(filePath, ".MDS"); - if (load_file(&midi, filePath, 0, 1)) - return nullptr; - - if (midi) - TrackList->Add(midi); - return midi; + IsOpen = load_file(midi, filePath, 0, 1) == 0; } -int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags) +MdsMidi::~MdsMidi() +{ + if (midi.Magic == mmioFOURCC('M', 'D', 'S', 'I')) + { + if (midi.StreamHandle) + stream_close(midi); + if (midi.DataPtr1) + { + memory::free(midi.DataPtr1); + } + midi.Magic = mmioFOURCC('d', 'a', 't', 'a'); + } +} + +void MdsMidi::Play() +{ + Stop(); + stream_open(midi, 1); +} + +void MdsMidi::Stop() +{ + stream_close(midi); +} + +int MdsMidi::stream_close(midi_struct& midi) +{ + int returnCode; + + if (midi.Magic != mmioFOURCC('M', 'D', 'S', 'I')) + return 6; + if (!midi.StreamHandle) + return 7; + midi.SomeFlag2 |= 1u; + if (midiOutReset(reinterpret_cast(midi.StreamHandle))) + { + returnCode = 5; + midi.SomeFlag2 &= ~1; + } + else + { + midihdr_tag* blockPtr = midi.DataPtr1; + for (int i = midi.BlockCount; i; --i) + { + midiOutUnprepareHeader(reinterpret_cast(midi.StreamHandle), blockPtr, sizeof(MIDIHDR)); + blockPtr = reinterpret_cast(reinterpret_cast(&blockPtr[1]) + blockPtr->dwBufferLength); + } + midiStreamClose(midi.StreamHandle); + returnCode = 0; + midi.StreamHandle = nullptr; + midi.SomeFlag2 = 0; + } + return returnCode; +} + +int MdsMidi::stream_open(midi_struct& midi, char flags) +{ + auto returnCode = 0; + if (midi.Magic != mmioFOURCC('M', 'D', 'S', 'I')) + return 6; + + UINT puDeviceID = -1; + auto steamOpenedFg = !midi.StreamHandle; + MIDIPROPTIMEDIV propdata{ 8, midi.DwTimeFormat }; + if (steamOpenedFg && + !midiStreamOpen(&midi.StreamHandle, &puDeviceID, 1u, reinterpret_cast(midi_callback), 0, + CALLBACK_FUNCTION) && + !midiStreamProperty(midi.StreamHandle, reinterpret_cast(&propdata), MIDIPROP_TIMEDIV | MIDIPROP_SET)) + { + midihdr_tag* blockPtr = midi.DataPtr1; + for (auto blockIndex = midi.BlockCount; blockIndex; blockIndex--) + { + if (midiOutPrepareHeader(reinterpret_cast(midi.StreamHandle), blockPtr, sizeof(MIDIHDR)) || + midiStreamOut(midi.StreamHandle, blockPtr, sizeof(MIDIHDR))) + { + returnCode = 5; + break; + } + + ++midi.PreparedBlocksCount; + blockPtr = reinterpret_cast(reinterpret_cast(&blockPtr[1]) + blockPtr->dwBufferLength); + } + } + + if (!returnCode) + { + if (!steamOpenedFg && (midi.SomeFlag2 & 4) == 0) + return 7; + + midi.SomeFlag2 &= ~2; + if ((flags & 1) != 0) + midi.SomeFlag2 |= 2; + midi.SomeFlag2 &= ~4; + if (midiStreamRestart(midi.StreamHandle)) + returnCode = 5; + } + + if (returnCode && steamOpenedFg) + { + if (midi.StreamHandle) + stream_close(midi); + } + return returnCode; +} + +int MdsMidi::load_file(midi_struct& midi, void* filePtrOrPath, int fileSizeP, int flags) { int returnCode; unsigned int fileSize; HANDLE mapHandle = nullptr; - midi_struct* midi = nullptr; HANDLE fileHandle = INVALID_HANDLE_VALUE; int fileFlag = 0; @@ -161,15 +275,9 @@ int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, break; } - midi = static_cast(LocalAlloc(0x40u, sizeof(midi_struct))); - if (!midi) - { - returnCode = 1; - break; - } - midi->Magic = mmioFOURCC('M', 'D', 'S', 'I'); - midi->StreamHandle = nullptr; - midi->PreparedBlocksCount = 0; + midi.Magic = mmioFOURCC('M', 'D', 'S', 'I'); + midi.StreamHandle = nullptr; + midi.PreparedBlocksCount = 0; if ((flags & 2) != 0) { @@ -179,7 +287,7 @@ int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, { fileFlag = 1; fileHandle = CreateFileA(static_cast(filePtrOrPath), GENERIC_READ, 1u, nullptr, OPEN_EXISTING, - 0x80u, nullptr); + 0x80u, nullptr); if (fileHandle == INVALID_HANDLE_VALUE) { returnCode = 2; @@ -202,19 +310,7 @@ int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, } } returnCode = read_file(midi, static_cast(filePtrOrPath), fileSize); - } - while (false); - - - if (returnCode) - { - if (midi) - LocalFree(midi); - } - else - { - *midi_res = midi; - } + } while (false); if (fileFlag) { @@ -228,13 +324,13 @@ int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, return returnCode; } -int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) +int MdsMidi::read_file(midi_struct& midi, riff_header* filePtr, unsigned fileSize) { auto returnCode = 0; do { - midi->DataPtr1 = nullptr; + midi.DataPtr1 = nullptr; if (fileSize < 12) { returnCode = 3; @@ -276,9 +372,9 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) break; } - midi->DwTimeFormat = filePtr->dwTimeFormat; - midi->CbMaxBuffer = filePtr->cbMaxBuffer; - midi->DwFlagsFormat = filePtr->dwFlags; + midi.DwTimeFormat = filePtr->dwTimeFormat; + midi.CbMaxBuffer = filePtr->cbMaxBuffer; + midi.DwFlagsFormat = filePtr->dwFlags; auto blocksSize = fileSize - 20 - filePtr->FmtSize; if (blocksSize < 8) { @@ -287,8 +383,8 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) } auto dataChunk = reinterpret_cast(reinterpret_cast(&filePtr->dwTimeFormat) + filePtr->FmtSize - ); - if (dataChunk->Data != mmioFOURCC('d','a','t','a')) + ); + if (dataChunk->Data != mmioFOURCC('d', 'a', 't', 'a')) { returnCode = 3; break; @@ -299,15 +395,15 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) break; } - midi->BlockCount = dataChunk->BlocksPerChunk; - midi->DataPtr1 = reinterpret_cast(memory::allocate( - dataChunk->BlocksPerChunk * (midi->CbMaxBuffer + sizeof(midihdr_tag)))); - if (!midi->DataPtr1) + midi.BlockCount = dataChunk->BlocksPerChunk; + midi.DataPtr1 = reinterpret_cast(memory::allocate( + dataChunk->BlocksPerChunk * (midi.CbMaxBuffer + sizeof(midihdr_tag)))); + if (!midi.DataPtr1) { returnCode = 1; break; } - if (!midi->BlockCount) + if (!midi.BlockCount) { returnCode = 3; break; @@ -315,13 +411,13 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) auto blocksSizeIndex = blocksSize - 12; auto srcPtr = dataChunk->Blocks; - auto* dstPtr = midi->DataPtr1; - for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--) + auto* dstPtr = midi.DataPtr1; + for (auto blockIndex = midi.BlockCount; blockIndex; blockIndex--) { dstPtr->lpData = reinterpret_cast(&dstPtr[1]); - dstPtr->dwBufferLength = midi->CbMaxBuffer; + dstPtr->dwBufferLength = midi.CbMaxBuffer; dstPtr->dwFlags = 0; - dstPtr->dwUser = reinterpret_cast(midi); + dstPtr->dwUser = reinterpret_cast(&midi); dstPtr->lpNext = nullptr; if (blocksSizeIndex < 8) { @@ -330,17 +426,17 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) } auto blockSize = srcPtr->CbBuffer; - if (blockSize > midi->CbMaxBuffer || blockSize > blocksSizeIndex - 8) + if (blockSize > midi.CbMaxBuffer || blockSize > blocksSizeIndex - 8) { returnCode = 3; break; } - if ((midi->DwFlagsFormat & 1) != 0) + if ((midi.DwFlagsFormat & 1) != 0) { /*Not used in FT, some kind of compression*/ assertm(false, "Unimplemented code reached"); - /*int a1[16]; + /*int a1[16]; a1[0] = (int)blockDataPtr; a1[2] = blockSize; a1[1] = blockSize; @@ -356,148 +452,18 @@ int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize) } blocksSizeIndex -= blockSize + 8; srcPtr = reinterpret_cast(&srcPtr->AData[blockSize]); - dstPtr = reinterpret_cast(reinterpret_cast(&dstPtr[1]) + midi->CbMaxBuffer); + dstPtr = reinterpret_cast(reinterpret_cast(&dstPtr[1]) + midi.CbMaxBuffer); } - } - while (false); + } while (false); - if (returnCode && midi->DataPtr1) + if (returnCode && midi.DataPtr1) { - memory::free(midi->DataPtr1); + memory::free(midi.DataPtr1); } return returnCode; } -int midi::play_ft(midi_struct* midi) -{ - int result; - - stop_ft(); - if (!midi) - return 0; - if (some_flag1) - { - active_track2 = midi; - return 0; - } - if (stream_open(midi, 1)) - { - active_track = nullptr; - result = 0; - } - else - { - active_track = midi; - result = 1; - } - return result; -} - -int midi::stop_ft() -{ - int returnCode = 0; - if (active_track) - returnCode = stream_close(active_track); - active_track = nullptr; - return returnCode; -} - -int midi::unload_track(midi_struct* midi) -{ - if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I')) - return 6; - if (midi->StreamHandle) - stream_close(midi); - if (midi->DataPtr1) - { - memory::free(midi->DataPtr1); - } - midi->Magic = mmioFOURCC('d','a','t','a'); - LocalFree(midi); - return 0; -} - -int midi::stream_open(midi_struct* midi, char flags) -{ - auto returnCode = 0; - if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I')) - return 6; - - UINT puDeviceID = -1; - auto steamOpenedFg = !midi->StreamHandle; - MIDIPROPTIMEDIV propdata{8, midi->DwTimeFormat}; - if (steamOpenedFg && - !midiStreamOpen(&midi->StreamHandle, &puDeviceID, 1u, reinterpret_cast(midi_callback), 0, - CALLBACK_FUNCTION) && - !midiStreamProperty(midi->StreamHandle, reinterpret_cast(&propdata),MIDIPROP_TIMEDIV | MIDIPROP_SET)) - { - midihdr_tag* blockPtr = midi->DataPtr1; - for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--) - { - if (midiOutPrepareHeader(reinterpret_cast(midi->StreamHandle), blockPtr, sizeof(MIDIHDR)) || - midiStreamOut(midi->StreamHandle, blockPtr, sizeof(MIDIHDR))) - { - returnCode = 5; - break; - } - - ++midi->PreparedBlocksCount; - blockPtr = reinterpret_cast(reinterpret_cast(&blockPtr[1]) + blockPtr->dwBufferLength); - } - } - - if (!returnCode) - { - if (!steamOpenedFg && (midi->SomeFlag2 & 4) == 0) - return 7; - - midi->SomeFlag2 &= ~2; - if ((flags & 1) != 0) - midi->SomeFlag2 |= 2; - midi->SomeFlag2 &= ~4; - if (midiStreamRestart(midi->StreamHandle)) - returnCode = 5; - } - - if (returnCode && steamOpenedFg) - { - if (midi->StreamHandle) - stream_close(midi); - } - return returnCode; -} - -int midi::stream_close(midi_struct* midi) -{ - int returnCode; - - if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I')) - return 6; - if (!midi->StreamHandle) - return 7; - midi->SomeFlag2 |= 1u; - if (midiOutReset(reinterpret_cast(midi->StreamHandle))) - { - returnCode = 5; - midi->SomeFlag2 &= ~1; - } - else - { - midihdr_tag* blockPtr = midi->DataPtr1; - for (int i = midi->BlockCount; i; --i) - { - midiOutUnprepareHeader(reinterpret_cast(midi->StreamHandle), blockPtr, sizeof(MIDIHDR)); - blockPtr = reinterpret_cast(reinterpret_cast(&blockPtr[1]) + blockPtr->dwBufferLength); - } - midiStreamClose(midi->StreamHandle); - returnCode = 0; - midi->StreamHandle = nullptr; - midi->SomeFlag2 = 0; - } - return returnCode; -} - -void midi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +void MdsMidi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { if (wMsg == 969) { @@ -508,3 +474,49 @@ void midi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PT --midi->PreparedBlocksCount; } } + +#pragma endregion + +#pragma region MciMidi + +MciMidi::MciMidi(LPCSTR fileName, HWND notifyHwnd) +{ + char filePath[256]; + MCI_OPEN_PARMS mci_open_info{}; + midi_notify_hwnd = notifyHwnd; + + pinball::make_path_name(filePath, fileName, 254u); + mci_open_info.lpstrElementName = filePath; + auto result = mciSendCommandA(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_NOTIFY_SUPERSEDED, (DWORD_PTR)&mci_open_info); + IsOpen = result == 0; + DeviceId = mci_open_info.wDeviceID; +} + +MciMidi::~MciMidi() +{ + if (IsOpen) + mciSendCommandA(DeviceId, MCI_CLOSE, 0, 0); + IsOpen = false; +} + +void MciMidi::Play() +{ + MCI_PLAY_PARMS playParams{ (DWORD_PTR)midi_notify_hwnd, 0, 0 }; + + Stop(); + + if (IsOpen) + { + auto result = mciSendCommandA(DeviceId, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD_PTR)&playParams); + IsPlaying = result == 0; + } +} + +void MciMidi::Stop() +{ + if (IsPlaying) + mciSendCommandA(DeviceId, MCI_STOP, 0, 0); + IsPlaying = false; +} + +#pragma endregion diff --git a/SpaceCadetPinball/midi.h b/SpaceCadetPinball/midi.h index cecca49..caf91cf 100644 --- a/SpaceCadetPinball/midi.h +++ b/SpaceCadetPinball/midi.h @@ -49,33 +49,72 @@ static_assert(sizeof(riff_data) == 0x18, "Wrong size of riff_data"); static_assert(sizeof(riff_header) == 0x38, "Wrong size of riff_header"); #pragma pack(pop) +class BaseMidi +{ +public: + bool IsOpen = false, IsPlaying = false; + + virtual ~BaseMidi() = default; + virtual void Play() = 0; + virtual void Stop() = 0; +}; + +class MdsMidi : public BaseMidi +{ +public: + MdsMidi(LPCSTR fileName); + ~MdsMidi() override; + void Play() override; + void Stop() override; +private: + midi_struct midi{}; + + static int stream_open(midi_struct& midi, char flags); + static int stream_close(midi_struct& midi); + static int load_file(midi_struct& midi, void* filePtrOrPath, int fileSizeP, int flags); + static int read_file(midi_struct& midi, riff_header* filePtr, unsigned int fileSize); + static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2); +}; + +class MciMidi : public BaseMidi +{ +public: + MciMidi(LPCSTR fileName, HWND notifyHwnd); + ~MciMidi() override; + void Play() override; + void Stop() override; +private: + MCIDEVICEID DeviceId{}; + HWND midi_notify_hwnd; +}; + +enum class MidiTracks +{ + None, + Track1, + Track2, + Track3 +}; + + class midi { public: - static MCIERROR play_pb_theme(int flag); - static MCIERROR music_stop(); + static void music_play(); + static void music_stop(); static int music_init(HWND hwnd); - static MCIERROR restart_midi_seq(LPARAM param); + static void restart_midi_seq(LPARAM param); static void music_shutdown(); + static bool play_track(MidiTracks track, bool replay); private: - static tagMCI_OPEN_PARMSA mci_open_info; - static char midi_file_name[28]; static HWND midi_notify_hwnd; - static int midi_seq1_open, midi_seq1_playing; + static objlist_class* TrackList; + static BaseMidi* track1, * track2, * track3; + static MidiTracks ActiveTrack, NextTrack; + static bool IsPlaying; - static objlist_class* TrackList; - static midi_struct *track1, *track2, *track3, *active_track, *active_track2; - static int some_flag1; - static int music_init_ft(HWND hwnd); - static void music_shutdown_ft(); - static midi_struct* load_track(LPCSTR fileName); - static int load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags); - static int read_file(midi_struct* midi, riff_header* filePtr, unsigned int fileSize); - static int play_ft(midi_struct* midi); - static int stop_ft(); - static int unload_track(midi_struct* midi); - static int stream_open(midi_struct* midi, char flags); - static int stream_close(midi_struct* midi); - static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, - DWORD_PTR dwParam2); + static void StopPlayback(); + static BaseMidi* LoadTrack(LPCSTR fileName); + static BaseMidi* TrackToMidi(MidiTracks track); }; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index b5dfa06..75de9b7 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -427,7 +427,7 @@ void options::toggle(UINT uIDCheckItem) if (!newValue) midi::music_stop(); else - midi::play_pb_theme(0); + midi::music_play(); menu_check(uIDCheckItem, newValue); return; case Menu1_Full_Screen: diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 6a4282f..c456811 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -213,7 +213,7 @@ void pb::replay_level(int demoMode) demo_mode = demoMode; mode_change(1); if (options::Options.Music) - midi::play_pb_theme(0); + midi::music_play(); MainTable->Message(1014, static_cast(options::Options.Players)); } @@ -393,7 +393,7 @@ void pb::pause_continue() pinball::InfoTextBox->Display(text, textTime); } if (options::Options.Music && !winmain::single_step) - midi::play_pb_theme(0); + midi::music_play(); } } diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 41e7698..4b2a6ef 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -386,7 +386,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP activated = 1; Sound::Activate(); if (options::Options.Music && !single_step) - midi::play_pb_theme(0); + midi::music_play(); no_time_loss = 1; pinball::adjust_priority(options::Options.PriorityAdj); }