From 03deda2f9db1a43f673eceb5fe306bdf9576088e Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:53:49 +0300 Subject: [PATCH] Added event wait timeout when idle. Added show menu button to prevent lockout; this somewhat ruins no menu aesthetic. Cleaned up 3DPB vs. FT methods in midi. --- SpaceCadetPinball/midi.cpp | 203 ++++++++++++++-------------------- SpaceCadetPinball/midi.h | 21 ++-- SpaceCadetPinball/options.cpp | 2 +- SpaceCadetPinball/pb.cpp | 4 +- SpaceCadetPinball/winmain.cpp | 59 +++++++--- 5 files changed, 138 insertions(+), 151 deletions(-) diff --git a/SpaceCadetPinball/midi.cpp b/SpaceCadetPinball/midi.cpp index 9cb8ed0..19de140 100644 --- a/SpaceCadetPinball/midi.cpp +++ b/SpaceCadetPinball/midi.cpp @@ -5,7 +5,10 @@ #include "pb.h" #include "pinball.h" -Mix_Music* midi::currentMidi; + +objlist_class* midi::LoadedTracks; +Mix_Music *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::NextTrack; +bool midi::SetNextTrackFlag; constexpr uint32_t FOURCC(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { @@ -27,160 +30,127 @@ int ToVariableLen(uint32_t value, uint32_t& dst) return count; } -int midi::play_pb_theme(int flag) +int midi::play_pb_theme() { - if (pb::FullTiltMode) - { - return play_ft(track1); - } - - int result = 0; - music_stop(); - if (currentMidi) - result = Mix_PlayMusic(currentMidi, -1); - - return result; + // Todo: add support for tracks 2 and 3 + return play_track(track1); } int midi::music_stop() { - if (pb::FullTiltMode) + if (active_track) { - return stop_ft(); + active_track = nullptr; + Mix_HaltMusic(); } - return Mix_HaltMusic(); + return true; } int midi::music_init() -{ - if (pb::FullTiltMode) - { - return music_init_ft(); - } - - // File name is in lower case, while game data is in upper case. - std::string fileName = pinball::get_rc_string(156, 0); - std::transform(fileName.begin(), fileName.end(), fileName.begin(), [](unsigned char c) { return std::toupper(c); }); - auto midiPath = pinball::make_path_name(fileName); - currentMidi = Mix_LoadMUS(midiPath.c_str()); - return currentMidi != nullptr; -} - -void midi::music_shutdown() -{ - if (pb::FullTiltMode) - { - music_shutdown_ft(); - return; - } - - Mix_FreeMusic(currentMidi); -} - - -objlist_class* midi::TrackList; -Mix_Music *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::active_track2; -int midi::some_flag1; - -int midi::music_init_ft() { active_track = nullptr; - TrackList = new objlist_class(0, 1); + LoadedTracks = new objlist_class(0, 1); + + if (pb::FullTiltMode) + { + track1 = load_track("TABA1.MDS", true); + track2 = load_track("TABA2.MDS", true); + track3 = load_track("TABA3.MDS", true); + } + else + { + // 3DPB has only one music track. PINBALL2.MID is a bitmap font, in the same format as PB_MSGFT.bin + track1 = load_track("PINBALL.MID", false); + } - track1 = load_track("taba1"); - track2 = load_track("taba2"); - track3 = load_track("taba3"); if (!track2) track2 = track1; if (!track3) track3 = track1; - return 1; + return track1 != nullptr; } -void midi::music_shutdown_ft() +void midi::music_shutdown() { if (active_track) Mix_HaltMusic(); - while (TrackList->GetCount()) + + while (LoadedTracks->GetCount()) { - auto midi = TrackList->Get(0); + auto midi = LoadedTracks->Get(0); Mix_FreeMusic(midi); - TrackList->Delete(midi); + LoadedTracks->Delete(midi); } active_track = nullptr; - delete TrackList; + delete LoadedTracks; } -Mix_Music* midi::load_track(std::string fileName) +Mix_Music* midi::load_track(std::string fileName, bool isMds) { + Mix_Music* audio; auto origFile = fileName; - // File name is in lower case, while game data is in upper case. - std::transform(fileName.begin(), fileName.end(), fileName.begin(), [](unsigned char c) { return std::toupper(c); }); if (pb::FullTiltMode) { // FT sounds are in SOUND subfolder fileName.insert(0, 1, PathSeparator); fileName.insert(0, "SOUND"); } - fileName += ".MDS"; auto filePath = pinball::make_path_name(fileName); - auto midi = MdsToMidi(filePath); - if (!midi) - return nullptr; - - // Dump converted MIDI file - /*origFile += ".midi"; - FILE* fileHandle = fopen(origFile.c_str(), "wb"); - fwrite(midi->data(), 1, midi->size(), fileHandle); - fclose(fileHandle);*/ - - auto rw = SDL_RWFromMem(midi->data(), static_cast(midi->size())); - auto audio = Mix_LoadMUS_RW(rw, 1); // This call seems to leak memory no matter what. - delete midi; - if (!audio) - return nullptr; - - TrackList->Add(audio); - return audio; -} - -int midi::play_ft(Mix_Music* midi) -{ - int result; - - stop_ft(); - if (!midi) - return 0; - if (some_flag1) + if (isMds) { - active_track2 = midi; - return 0; - } - if (Mix_PlayMusic(midi, -1)) - { - active_track = nullptr; - result = 0; + auto midi = MdsToMidi(filePath); + if (!midi) + return nullptr; + + // Dump converted MIDI file + /*origFile += ".midi"; + FILE* fileHandle = fopen(origFile.c_str(), "wb"); + fwrite(midi->data(), 1, midi->size(), fileHandle); + fclose(fileHandle);*/ + + auto rw = SDL_RWFromMem(midi->data(), static_cast(midi->size())); + audio = Mix_LoadMUS_RW(rw, 1); // This call seems to leak memory no matter what. + delete midi; } else { - active_track = midi; - result = 1; + audio = Mix_LoadMUS(filePath.c_str()); } - return result; + + if (!audio) + return nullptr; + + LoadedTracks->Add(audio); + return audio; } -int midi::stop_ft() +bool midi::play_track(Mix_Music* midi) { - int returnCode = 0; - if (active_track) - returnCode = Mix_HaltMusic(); - active_track = nullptr; - return returnCode; + music_stop(); + if (!midi) + return false; + + if (SetNextTrackFlag) + { + NextTrack = midi; + SetNextTrackFlag = false; + return true; + } + + if (Mix_PlayMusic(midi, -1)) + { + active_track = nullptr; + return false; + } + + active_track = midi; + return true; } + /// /// SDL_mixed does not support MIDS. To support FT music, a conversion to MIDI is required. /// @@ -194,9 +164,9 @@ std::vector* midi::MdsToMidi(std::string file) fseek(fileHandle, 0, SEEK_END); auto fileSize = static_cast(ftell(fileHandle)); - auto filePtr = reinterpret_cast(memory::allocate(fileSize)); + auto fileBuf = reinterpret_cast(new uint8_t [fileSize]); fseek(fileHandle, 0, SEEK_SET); - fread(filePtr, 1, fileSize, fileHandle); + fread(fileBuf, 1, fileSize, fileHandle); fclose(fileHandle); int returnCode = 0; @@ -208,14 +178,14 @@ std::vector* midi::MdsToMidi(std::string file) returnCode = 3; break; } - if (filePtr->Riff != FOURCC('R', 'I', 'F', 'F') || - filePtr->Mids != FOURCC('M', 'I', 'D', 'S') || - filePtr->Fmt != FOURCC('f', 'm', 't', ' ')) + if (fileBuf->Riff != FOURCC('R', 'I', 'F', 'F') || + fileBuf->Mids != FOURCC('M', 'I', 'D', 'S') || + fileBuf->Fmt != FOURCC('f', 'm', 't', ' ')) { returnCode = 3; break; } - if (filePtr->FileSize > fileSize - 8) + if (fileBuf->FileSize > fileSize - 8) { returnCode = 3; break; @@ -225,14 +195,14 @@ std::vector* midi::MdsToMidi(std::string file) returnCode = 3; break; } - if (filePtr->FmtSize < 12 || filePtr->FmtSize > fileSize - 12) + if (fileBuf->FmtSize < 12 || fileBuf->FmtSize > fileSize - 12) { returnCode = 3; break; } - auto streamIdUsed = filePtr->dwFlags == 0; - auto dataChunk = reinterpret_cast(reinterpret_cast(&filePtr->dwTimeFormat) + filePtr-> + auto streamIdUsed = fileBuf->dwFlags == 0; + auto dataChunk = reinterpret_cast(reinterpret_cast(&fileBuf->dwTimeFormat) + fileBuf-> FmtSize); if (dataChunk->Data != FOURCC('d', 'a', 't', 'a')) { @@ -274,7 +244,7 @@ std::vector* midi::MdsToMidi(std::string file) // MThd chunk std::vector& midiBytes = *new std::vector(); midiOut = &midiBytes; - midi_header header(SwapByteOrderShort(static_cast(filePtr->dwTimeFormat))); + midi_header header(SwapByteOrderShort(static_cast(fileBuf->dwTimeFormat))); auto headerData = reinterpret_cast(&header); midiBytes.insert(midiBytes.end(), headerData, headerData + sizeof header); @@ -339,8 +309,7 @@ std::vector* midi::MdsToMidi(std::string file) } while (false); - if (filePtr) - memory::free(filePtr); + delete[] fileBuf; if (returnCode && midiOut) delete midiOut; return midiOut; diff --git a/SpaceCadetPinball/midi.h b/SpaceCadetPinball/midi.h index b263e5b..82bfde6 100644 --- a/SpaceCadetPinball/midi.h +++ b/SpaceCadetPinball/midi.h @@ -57,7 +57,7 @@ struct midi_header { } - const char MThd[4]{ 'M','T','h','d' }; + const char MThd[4]{'M', 'T', 'h', 'd'}; const uint32_t chunklen = SwapByteOrderInt(6); const int16_t format = SwapByteOrderShort(0); const uint16_t ntracks = SwapByteOrderShort(1); @@ -71,7 +71,7 @@ struct midi_track { } - const char MTrk[4]{ 'M','T','r','k' }; + const char MTrk[4]{'M', 'T', 'r', 'k'}; uint32_t chunklen; }; @@ -87,20 +87,15 @@ static_assert(sizeof(midi_track) == 8, "Wrong size of midi_track"); class midi { public: - static int play_pb_theme(int flag); + static int play_pb_theme(); static int music_stop(); static int music_init(); static void music_shutdown(); private: - static Mix_Music* currentMidi; - - static objlist_class* TrackList; - static Mix_Music *track1, *track2, *track3, *active_track, *active_track2; - static int some_flag1; - static int music_init_ft(); - static void music_shutdown_ft(); - static Mix_Music* load_track(std::string fileName); - static int play_ft(Mix_Music* midi); - static int stop_ft(); + static objlist_class* LoadedTracks; + static Mix_Music *track1, *track2, *track3, *active_track, *NextTrack; + static bool SetNextTrackFlag; + static Mix_Music* load_track(std::string fileName, bool isMds); + static bool play_track(Mix_Music* midi); static std::vector* MdsToMidi(std::string file); }; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index 138a0a2..8005b34 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -188,7 +188,7 @@ void options::toggle(Menu1 uIDCheckItem) if (!newValue) midi::music_stop(); else - midi::play_pb_theme(0); + midi::play_pb_theme(); return; case Menu1::Show_Menu: Options.ShowMenu = Options.ShowMenu == 0; diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 4b7f036..bf90f99 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -202,7 +202,7 @@ void pb::replay_level(int demoMode) demo_mode = demoMode; mode_change(1); if (options::Options.Music) - midi::play_pb_theme(0); + midi::play_pb_theme(); MainTable->Message(1014, static_cast(options::Options.Players)); } @@ -350,7 +350,7 @@ void pb::pause_continue() pinball::InfoTextBox->Display(text, textTime); } if (options::Options.Music && !winmain::single_step) - midi::play_pb_theme(0); + midi::play_pb_theme(); Sound::Activate(); } } diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 5b8a526..7084243 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -243,28 +243,19 @@ int winmain::WinMain(LPCSTR lpCmdLine) if (UpdateToFrameCounter >= UpdateToFrameRatio) { - UpdateToFrameCounter -= UpdateToFrameRatio; - - // Option might be changed in RenderUi, unpairing NewFrame from EndFrame. - auto showMenu = options::Options.ShowMenu; - if (showMenu) - { - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); - RenderUi(); - } + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + RenderUi(); SDL_RenderClear(renderer); render::PresentVScreen(); - if (showMenu) - { - ImGui::Render(); - ImGuiSDL::Render(ImGui::GetDrawData()); - } + ImGui::Render(); + ImGuiSDL::Render(ImGui::GetDrawData()); SDL_RenderPresent(renderer); frameCounter++; + UpdateToFrameCounter -= UpdateToFrameRatio; } auto sdlError = SDL_GetError(); @@ -315,6 +306,30 @@ int winmain::WinMain(LPCSTR lpCmdLine) void winmain::RenderUi() { + // A minimal window with a button to prevent menu lockout. + if (!options::Options.ShowMenu) + { + ImGui::SetNextWindowPos(ImVec2{}); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{10, 0}); + if (ImGui::Begin("main", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoMove)) + { + ImGui::PushID(1); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{}); + if (ImGui::Button("Menu")) + { + options::toggle(Menu1::Show_Menu); + } + ImGui::PopStyleColor(1); + ImGui::PopID(); + ImGui::End(); + } + ImGui::PopStyleVar(); + return; + } + // No demo window in release to save space #ifndef NDEBUG if (ShowImGuiDemo) @@ -675,7 +690,7 @@ int winmain::event_handler(const SDL_Event* event) activated = 1; Sound::Activate(); if (options::Options.Music && !single_step) - midi::play_pb_theme(0); + midi::play_pb_theme(); no_time_loss = 1; has_focus = 1; break; @@ -704,9 +719,11 @@ int winmain::event_handler(const SDL_Event* event) int winmain::ProcessWindowMessages() { + static auto idleWait = 0; SDL_Event event; if (has_focus && !single_step) { + idleWait = static_cast(TargetFrameTime.count()); while (SDL_PollEvent(&event)) { if (!event_handler(&event)) @@ -716,8 +733,14 @@ int winmain::ProcessWindowMessages() return 1; } - SDL_WaitEvent(&event); - return event_handler(&event); + // Progressively wait longer when transitioning to idle + idleWait = std::min(idleWait + static_cast(TargetFrameTime.count()), 500); + if (SDL_WaitEventTimeout(&event, idleWait)) + { + idleWait = static_cast(TargetFrameTime.count()); + return event_handler(&event); + } + return 1; } void winmain::memalloc_failure()