From 72f5445aba64332a49a994ece31bc04199e613d7 Mon Sep 17 00:00:00 2001 From: Gutawer Date: Sun, 7 Apr 2024 21:07:32 +0100 Subject: [PATCH 1/2] add .ogg support to msu1 --- Core/Core.vcxproj | 4 +- Core/Core.vcxproj.filters | 14 +++--- Core/NES/HdPacks/OggMixer.cpp | 2 +- Core/SNES/Coprocessors/MSU1/Msu1.cpp | 12 ++--- Core/SNES/Coprocessors/MSU1/Msu1.h | 45 ++++++++++++++++++- Core/SNES/SnesConsole.cpp | 2 +- .../HdPacks => Shared/Audio}/OggReader.cpp | 31 +++++++++++-- .../{NES/HdPacks => Shared/Audio}/OggReader.h | 1 + 8 files changed, 89 insertions(+), 22 deletions(-) rename Core/{NES/HdPacks => Shared/Audio}/OggReader.cpp (71%) rename Core/{NES/HdPacks => Shared/Audio}/OggReader.h (97%) diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index f77c076bb..81336b517 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -799,7 +799,6 @@ - @@ -979,6 +978,7 @@ + @@ -1240,4 +1240,4 @@ - \ No newline at end of file + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 2af307f63..89e180216 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -844,12 +844,6 @@ NES\HdPacks - - NES\HdPacks - - - NES\HdPacks - NES\Input @@ -979,6 +973,12 @@ Shared\Audio + + Shared\Audio + + + Shared\Audio + Shared\Audio @@ -3185,4 +3185,4 @@ {4cc96bee-c354-4a9b-9947-85959ccc072f} - \ No newline at end of file + diff --git a/Core/NES/HdPacks/OggMixer.cpp b/Core/NES/HdPacks/OggMixer.cpp index e553af13b..7e1347bf4 100644 --- a/Core/NES/HdPacks/OggMixer.cpp +++ b/Core/NES/HdPacks/OggMixer.cpp @@ -1,6 +1,6 @@ #include "pch.h" #include -#include "NES/HdPacks/OggReader.h" +#include "Shared/Audio/OggReader.h" #include "NES/HdPacks/OggMixer.h" enum class OggPlaybackOptions diff --git a/Core/SNES/Coprocessors/MSU1/Msu1.cpp b/Core/SNES/Coprocessors/MSU1/Msu1.cpp index b7833ddb6..77e5ae504 100644 --- a/Core/SNES/Coprocessors/MSU1/Msu1.cpp +++ b/Core/SNES/Coprocessors/MSU1/Msu1.cpp @@ -71,7 +71,7 @@ void Msu1::Write(uint16_t addr, uint8_t value) if(!_audioBusy) { _repeat = (value & 0x02) != 0; _paused = (value & 0x01) == 0; - _pcmReader.SetLoopFlag(_repeat); + _soundReader.SetLoopFlag(_repeat); } break; } @@ -106,21 +106,21 @@ uint8_t Msu1::Read(uint16_t addr) void Msu1::MixAudio(int16_t* buffer, uint32_t sampleCount, uint32_t sampleRate) { if(!_paused) { - _pcmReader.SetSampleRate(sampleRate); - _pcmReader.ApplySamples(buffer, (size_t)sampleCount, _spc->IsMuted() ? 0 : _volume); + _soundReader.SetSampleRate(sampleRate); + _soundReader.ApplySamples(buffer, (size_t)sampleCount, _spc->IsMuted() ? 0 : _volume); - _paused |= _pcmReader.IsPlaybackOver(); + _paused |= _soundReader.IsPlaybackOver(); } } void Msu1::LoadTrack(uint32_t startOffset) { - _trackMissing = !_pcmReader.Init(_trackPath + "-" + std::to_string(_trackSelect) + ".pcm", _repeat, startOffset); + _trackMissing = !_soundReader.Init(_trackPath + "-" + std::to_string(_trackSelect), _repeat, startOffset); } void Msu1::Serialize(Serializer &s) { - uint32_t offset = _pcmReader.GetOffset(); + uint32_t offset = _soundReader.GetOffset(); SV(_trackSelect); SV(_tmpDataPointer); SV(_dataPointer); SV(_repeat); SV(_paused); SV(_volume); SV(_trackMissing); SV(_audioBusy); SV(_dataBusy); SV(offset); if(!s.IsSaving()) { _dataFile.seekg(_dataPointer, ios::beg); diff --git a/Core/SNES/Coprocessors/MSU1/Msu1.h b/Core/SNES/Coprocessors/MSU1/Msu1.h index 400fbdf9d..c56ae06cc 100644 --- a/Core/SNES/Coprocessors/MSU1/Msu1.h +++ b/Core/SNES/Coprocessors/MSU1/Msu1.h @@ -1,19 +1,60 @@ #pragma once #include "pch.h" #include "Shared/Interfaces/IAudioProvider.h" + #include "Shared/Audio/PcmReader.h" +#include "Shared/Audio/OggReader.h" #include "Utilities/ISerializable.h" #include "Utilities/VirtualFile.h" class Spc; class Emulator; +class PcmOrOggReader final { +private: + PcmReader _pcmReader; + OggReader _oggReader; + bool _usingOgg = false; + +public: + void SetLoopFlag(bool loop) { + if (_usingOgg) { _oggReader.SetLoopFlag(loop); } + else { _pcmReader.SetLoopFlag(loop); } + } + void SetSampleRate(uint32_t sampleRate) { + if (_usingOgg) { _oggReader.SetSampleRate(sampleRate); } + else { _pcmReader.SetSampleRate(sampleRate); } + } + void ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { + if (_usingOgg) { _oggReader.ApplySamples(buffer, sampleCount, volume); } + else { _pcmReader.ApplySamples(buffer, sampleCount, volume); } + } + bool IsPlaybackOver() { + return _usingOgg ? _oggReader.IsPlaybackOver() : _pcmReader.IsPlaybackOver(); + } + uint32_t GetOffset() { + return _usingOgg ? _oggReader.GetOffset() * 4 : _pcmReader.GetOffset(); + } + bool Init(string filenameNoExt, bool loop, uint32_t startOffset) { + if (_pcmReader.Init(filenameNoExt + ".pcm", loop, startOffset)) { + _usingOgg = false; + return true; + } + if (_oggReader.Init(filenameNoExt + ".ogg", loop, 44100, startOffset / 4)) { + _usingOgg = true; + return true; + } + _usingOgg = false; + return false; + } +}; + class Msu1 final : public ISerializable, public IAudioProvider { private: Spc* _spc = nullptr; Emulator* _emu = nullptr; - PcmReader _pcmReader; + PcmOrOggReader _soundReader; uint8_t _volume = 100; uint16_t _trackSelect = 0; uint32_t _tmpDataPointer = 0; @@ -45,4 +86,4 @@ class Msu1 final : public ISerializable, public IAudioProvider void MixAudio(int16_t* buffer, uint32_t sampleCount, uint32_t sampleRate) override; void Serialize(Serializer &s) override; -}; \ No newline at end of file +}; diff --git a/Core/SNES/SnesConsole.cpp b/Core/SNES/SnesConsole.cpp index 0dd65344f..0c8cb4fcf 100644 --- a/Core/SNES/SnesConsole.cpp +++ b/Core/SNES/SnesConsole.cpp @@ -549,4 +549,4 @@ void SnesConsole::InitializeRam(void* data, uint32_t length) state = settings->GetSnesConfig().RamPowerOnState; } settings->InitializeRam(state, data, length); -} \ No newline at end of file +} diff --git a/Core/NES/HdPacks/OggReader.cpp b/Core/Shared/Audio/OggReader.cpp similarity index 71% rename from Core/NES/HdPacks/OggReader.cpp rename to Core/Shared/Audio/OggReader.cpp index 844e450d2..2501004be 100644 --- a/Core/NES/HdPacks/OggReader.cpp +++ b/Core/Shared/Audio/OggReader.cpp @@ -1,6 +1,7 @@ #include "pch.h" -#include "NES/HdPacks/OggReader.h" +#include "Shared/Audio/OggReader.h" #include "Utilities/Audio/stb_vorbis.h" +#include "Utilities/StringUtilities.h" OggReader::OggReader() { @@ -21,12 +22,29 @@ OggReader::~OggReader() bool OggReader::Init(string filename, bool loop, uint32_t sampleRate, uint32_t startOffset, uint32_t loopPosition) { + _loaded = false; int error; VirtualFile file = filename; _fileData = vector(100000); if(file.ReadFile(_fileData)) { _vorbis = stb_vorbis_open_memory(_fileData.data(), (int)_fileData.size(), &error, nullptr); if(_vorbis) { + auto comments = stb_vorbis_get_comment(_vorbis); + for (int i = 0; i < comments.comment_list_length; i++) { + auto comment = comments.comment_list[i]; + vector commentParts = StringUtilities::Split(comment, '='); + if (commentParts.size() != 2) { continue; } + if (commentParts[0] != "LOOPSTART") { continue; } + uint32_t loopPositionFromFile; + try { + loopPositionFromFile = std::stoi(commentParts[1]); + } catch (std::invalid_argument const& _e) { + throw std::runtime_error("Mis-formatted loop start in .ogg"); + } catch (std::out_of_range const& _e) { + throw std::runtime_error("Out-of-range integer loop start in .ogg"); + } + loopPosition = loopPositionFromFile; + } _loop = loop; if(loopPosition > 0) { unsigned int sampleCount = stb_vorbis_stream_length_in_samples(_vorbis); @@ -38,6 +56,7 @@ bool OggReader::Init(string filename, bool loop, uint32_t sampleRate, uint32_t s if(startOffset > 0) { stb_vorbis_seek(_vorbis, startOffset); } + _loaded = true; return true; } } @@ -63,6 +82,9 @@ void OggReader::SetLoopFlag(bool loop) void OggReader::ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { + if (!_loaded) { + return; + } int32_t samplesNeeded = (int32_t)sampleCount - _resampler.GetPendingCount(); uint32_t samplesRead = 0; if(samplesNeeded > 0) { @@ -88,5 +110,8 @@ void OggReader::ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume uint32_t OggReader::GetOffset() { - return stb_vorbis_get_file_offset(_vorbis); -} \ No newline at end of file + if (!_loaded) { + return 0; + } + return stb_vorbis_get_sample_offset(_vorbis); +} diff --git a/Core/NES/HdPacks/OggReader.h b/Core/Shared/Audio/OggReader.h similarity index 97% rename from Core/NES/HdPacks/OggReader.h rename to Core/Shared/Audio/OggReader.h index ea199cdc7..f7b95a5bb 100644 --- a/Core/NES/HdPacks/OggReader.h +++ b/Core/Shared/Audio/OggReader.h @@ -14,6 +14,7 @@ class OggReader HermiteResampler _resampler; + bool _loaded = false; bool _loop = false; bool _done = false; From 2fddc8552790d976a75e5d3aff1863f34b5e1bf9 Mon Sep 17 00:00:00 2001 From: Gutawer Date: Thu, 11 Apr 2024 23:28:39 +0100 Subject: [PATCH 2/2] add support for the .msu1 rom-in-zip-file format --- Core/SNES/Coprocessors/MSU1/Msu1.cpp | 101 ++++++++++++++++++++++++--- Core/SNES/Coprocessors/MSU1/Msu1.h | 40 +++-------- Core/SNES/SnesConsole.cpp | 13 +++- Core/SNES/SnesConsole.h | 3 +- Core/Shared/Audio/PcmReader.cpp | 34 +++++---- Core/Shared/Audio/PcmReader.h | 2 +- UI/Localization/resources.en.xml | 2 +- UI/Utilities/FileDialogHelper.cs | 6 +- UI/Utilities/FolderHelper.cs | 4 +- Utilities/VirtualFile.cpp | 19 ++++- Utilities/VirtualFile.h | 4 +- 11 files changed, 156 insertions(+), 72 deletions(-) diff --git a/Core/SNES/Coprocessors/MSU1/Msu1.cpp b/Core/SNES/Coprocessors/MSU1/Msu1.cpp index 77e5ae504..448a93b1e 100644 --- a/Core/SNES/Coprocessors/MSU1/Msu1.cpp +++ b/Core/SNES/Coprocessors/MSU1/Msu1.cpp @@ -5,14 +5,80 @@ #include "Shared/Audio/SoundMixer.h" #include "Utilities/Serializer.h" #include "Utilities/FolderUtilities.h" +#include "Utilities/StringUtilities.h" + +bool ends_with(std::string const & value, std::string const & ending) +{ + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +std::optional GetFileForExt(std::string& base, std::string ext) { + if (base.back() == '\x1') { + auto withoutEnd = base; + withoutEnd.pop_back(); + auto reader = ArchiveReader::GetReader(withoutEnd); + for (const auto& f : reader->GetFileList()) { + if (ends_with(StringUtilities::ToLower(f), ext)) { + return base + f; + } + } + } else { + auto ret = base + ext; + if (VirtualFile(ret).IsValid()) { + return ret; + } + } + return std::nullopt; +} + +void PcmOrOggReader::SetLoopFlag(bool loop) { + if (_usingOgg) { _oggReader.SetLoopFlag(loop); } + else { _pcmReader.SetLoopFlag(loop); } +} +void PcmOrOggReader::SetSampleRate(uint32_t sampleRate) { + if (_usingOgg) { _oggReader.SetSampleRate(sampleRate); } + else { _pcmReader.SetSampleRate(sampleRate); } +} +void PcmOrOggReader::ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { + if (_usingOgg) { _oggReader.ApplySamples(buffer, sampleCount, volume); } + else { _pcmReader.ApplySamples(buffer, sampleCount, volume); } +} +bool PcmOrOggReader::IsPlaybackOver() { + return _usingOgg ? _oggReader.IsPlaybackOver() : _pcmReader.IsPlaybackOver(); +} +uint32_t PcmOrOggReader::GetOffset() { + return _usingOgg ? _oggReader.GetOffset() * 4 : _pcmReader.GetOffset(); +} +bool PcmOrOggReader::Init(string base, size_t track, bool loop, uint32_t startOffset) { + _usingOgg = false; + auto pcm = GetFileForExt(base, "-" + std::to_string(track) + ".pcm"); + if (pcm.has_value()) { + if (_pcmReader.Init(*pcm, loop, startOffset)) { + return true; + } + return false; + } + auto ogg = GetFileForExt(base, "-" + std::to_string(track) + ".ogg"); + if (ogg.has_value()) { + if (_oggReader.Init(*ogg, loop, 44100, startOffset / 4)) { + _usingOgg = true; + return true; + } + return false; + } + return false; +} Msu1* Msu1::Init(Emulator* emu, VirtualFile& romFile, Spc* spc) { string romFolder = romFile.GetFolderPath(); string romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); - if(ifstream(FolderUtilities::CombinePath(romFolder, romName + ".msu"))) { + if(romFile.IsArchive()) { return new Msu1(emu, romFile, spc); - } else if(ifstream(FolderUtilities::CombinePath(romFolder, "msu1.rom"))) { + } else if(VirtualFile(FolderUtilities::CombinePath(romFolder, romName + ".msu")).IsValid()) { + return new Msu1(emu, romFile, spc); + } else if(VirtualFile(FolderUtilities::CombinePath(romFolder, "msu1.rom")).IsValid()) { return new Msu1(emu, romFile, spc); } else { return nullptr; @@ -25,17 +91,28 @@ Msu1::Msu1(Emulator* emu, VirtualFile& romFile, Spc* spc) _spc = spc; _romFolder = romFile.GetFolderPath(); _romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); - _dataFile.open(FolderUtilities::CombinePath(_romFolder, _romName) + ".msu", ios::binary); - if(_dataFile) { + if (romFile.IsArchive()) { + _trackPath = romFile.GetFilePath() + "\x1"; + auto path = GetFileForExt(_trackPath, ".msu"); + if (path.has_value()) { + auto dataVirtualFileArchive = VirtualFile(*path); + _dataFile = dataVirtualFileArchive.Stream(); + } + } else if( + auto dataVirtualFile = VirtualFile(FolderUtilities::CombinePath(_romFolder, _romName) + ".msu"); + dataVirtualFile.IsValid() + ) { + _dataFile = dataVirtualFile.Stream(); _trackPath = FolderUtilities::CombinePath(_romFolder, _romName); } else { - _dataFile.open(FolderUtilities::CombinePath(_romFolder, "msu1.rom"), ios::binary); + auto dataVirtualFileRom = VirtualFile(FolderUtilities::CombinePath(_romFolder, "msu1.rom")); + _dataFile = dataVirtualFileRom.Stream(); _trackPath = FolderUtilities::CombinePath(_romFolder, "track"); } if(_dataFile) { - _dataFile.seekg(0, ios::end); - _dataSize = (uint32_t)_dataFile.tellg(); + _dataFile->seekg(0, ios::end); + _dataSize = (uint32_t)_dataFile->tellg(); } else { _dataSize = 0; } @@ -57,7 +134,7 @@ void Msu1::Write(uint16_t addr, uint8_t value) case 0x2003: _tmpDataPointer = (_tmpDataPointer & 0x00FFFFFF) | (value << 24); _dataPointer = _tmpDataPointer; - _dataFile.seekg(_dataPointer, ios::beg); + _dataFile->seekg(_dataPointer, ios::beg); break; case 0x2004: _trackSelect = (_trackSelect & 0xFF00) | value; break; @@ -88,7 +165,7 @@ uint8_t Msu1::Read(uint16_t addr) //data if(!_dataBusy && _dataPointer < _dataSize) { _dataPointer++; - return (uint8_t)_dataFile.get(); + return (uint8_t)_dataFile->get(); } return 0; @@ -115,7 +192,7 @@ void Msu1::MixAudio(int16_t* buffer, uint32_t sampleCount, uint32_t sampleRate) void Msu1::LoadTrack(uint32_t startOffset) { - _trackMissing = !_soundReader.Init(_trackPath + "-" + std::to_string(_trackSelect), _repeat, startOffset); + _trackMissing = !_soundReader.Init(_trackPath, _trackSelect, _repeat, startOffset); } void Msu1::Serialize(Serializer &s) @@ -123,7 +200,9 @@ void Msu1::Serialize(Serializer &s) uint32_t offset = _soundReader.GetOffset(); SV(_trackSelect); SV(_tmpDataPointer); SV(_dataPointer); SV(_repeat); SV(_paused); SV(_volume); SV(_trackMissing); SV(_audioBusy); SV(_dataBusy); SV(offset); if(!s.IsSaving()) { - _dataFile.seekg(_dataPointer, ios::beg); + if (_dataFile) { + _dataFile->seekg(_dataPointer, ios::beg); + } LoadTrack(offset); } } diff --git a/Core/SNES/Coprocessors/MSU1/Msu1.h b/Core/SNES/Coprocessors/MSU1/Msu1.h index c56ae06cc..a2c53d072 100644 --- a/Core/SNES/Coprocessors/MSU1/Msu1.h +++ b/Core/SNES/Coprocessors/MSU1/Msu1.h @@ -6,6 +6,8 @@ #include "Shared/Audio/OggReader.h" #include "Utilities/ISerializable.h" #include "Utilities/VirtualFile.h" +#include "Utilities/StringUtilities.h" +#include "Utilities/ArchiveReader.h" class Spc; class Emulator; @@ -17,36 +19,12 @@ class PcmOrOggReader final { bool _usingOgg = false; public: - void SetLoopFlag(bool loop) { - if (_usingOgg) { _oggReader.SetLoopFlag(loop); } - else { _pcmReader.SetLoopFlag(loop); } - } - void SetSampleRate(uint32_t sampleRate) { - if (_usingOgg) { _oggReader.SetSampleRate(sampleRate); } - else { _pcmReader.SetSampleRate(sampleRate); } - } - void ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { - if (_usingOgg) { _oggReader.ApplySamples(buffer, sampleCount, volume); } - else { _pcmReader.ApplySamples(buffer, sampleCount, volume); } - } - bool IsPlaybackOver() { - return _usingOgg ? _oggReader.IsPlaybackOver() : _pcmReader.IsPlaybackOver(); - } - uint32_t GetOffset() { - return _usingOgg ? _oggReader.GetOffset() * 4 : _pcmReader.GetOffset(); - } - bool Init(string filenameNoExt, bool loop, uint32_t startOffset) { - if (_pcmReader.Init(filenameNoExt + ".pcm", loop, startOffset)) { - _usingOgg = false; - return true; - } - if (_oggReader.Init(filenameNoExt + ".ogg", loop, 44100, startOffset / 4)) { - _usingOgg = true; - return true; - } - _usingOgg = false; - return false; - } + void SetLoopFlag(bool loop); + void SetSampleRate(uint32_t sampleRate); + void ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume); + bool IsPlaybackOver(); + uint32_t GetOffset(); + bool Init(string base, size_t track, bool loop, uint32_t startOffset); }; class Msu1 final : public ISerializable, public IAudioProvider @@ -69,7 +47,7 @@ class Msu1 final : public ISerializable, public IAudioProvider bool _dataBusy = false; //Always false bool _trackMissing = false; - ifstream _dataFile; + unique_ptr _dataFile; uint32_t _dataSize; void LoadTrack(uint32_t startOffset = 8); diff --git a/Core/SNES/SnesConsole.cpp b/Core/SNES/SnesConsole.cpp index 0c8cb4fcf..92de059aa 100644 --- a/Core/SNES/SnesConsole.cpp +++ b/Core/SNES/SnesConsole.cpp @@ -32,6 +32,7 @@ #include "Utilities/VirtualFile.h" #include "Utilities/PlatformUtilities.h" #include "Utilities/FolderUtilities.h" +#include "Utilities/StringUtilities.h" #include "Shared/EventType.h" #include "SNES/RegisterHandlerA.h" #include "SNES/RegisterHandlerB.h" @@ -100,7 +101,7 @@ void SnesConsole::Reset() _memoryManager->IncMasterClockStartup(); } -LoadRomResult SnesConsole::LoadRom(VirtualFile& romFile) +LoadRomResult SnesConsole::InnerLoadRom(VirtualFile& romFile) { SnesConfig config = _settings->GetSnesConfig(); LoadRomResult loadResult = LoadRomResult::UnknownType; @@ -144,6 +145,16 @@ LoadRomResult SnesConsole::LoadRom(VirtualFile& romFile) return loadResult; } +LoadRomResult SnesConsole::LoadRom(VirtualFile& romFile) +{ + if (StringUtilities::ToLower(romFile.GetFileExtension()) == ".msu1") { + auto r = VirtualFile(romFile.GetFilePath(), "program.rom"); + return this->InnerLoadRom(r); + } else { + return this->InnerLoadRom(romFile); + } +} + bool SnesConsole::LoadSpcFile(VirtualFile& romFile) { _spc->LoadSpcFile(_cart->GetSpcData()); diff --git a/Core/SNES/SnesConsole.h b/Core/SNES/SnesConsole.h index 2c66815ba..b91d43db4 100644 --- a/Core/SNES/SnesConsole.h +++ b/Core/SNES/SnesConsole.h @@ -66,13 +66,14 @@ class SnesConsole final : public IConsole bool _frameRunning = false; void UpdateRegion(); + LoadRomResult InnerLoadRom(VirtualFile& romFile); bool LoadSpcFile(VirtualFile& romFile); public: SnesConsole(Emulator* emu); ~SnesConsole(); - static vector GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".spc" }; } + static vector GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".spc", ".msu1" }; } static vector GetSupportedSignatures() { return { "SNES-SPC700 Sound File Data" }; } void Initialize(); diff --git a/Core/Shared/Audio/PcmReader.cpp b/Core/Shared/Audio/PcmReader.cpp index 5d5f1a733..179e73284 100644 --- a/Core/Shared/Audio/PcmReader.cpp +++ b/Core/Shared/Audio/PcmReader.cpp @@ -17,23 +17,21 @@ PcmReader::~PcmReader() bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) { - if(_file) { - _file.close(); - } + auto v = VirtualFile(filename); + _file = v.Stream(); - _file.open(filename, ios::binary); if(_file) { - _file.seekg(0, ios::end); - _fileSize = (uint32_t)_file.tellg(); + _file->seekg(0, ios::end); + _fileSize = (uint32_t)_file->tellg(); if(_fileSize < 12) { return false; } - _file.seekg(4, ios::beg); - uint32_t loopOffset = (uint8_t)_file.get(); - loopOffset |= ((uint8_t)_file.get()) << 8; - loopOffset |= ((uint8_t)_file.get()) << 16; - loopOffset |= ((uint8_t)_file.get()) << 24; + _file->seekg(4, ios::beg); + uint32_t loopOffset = (uint8_t)_file->get(); + loopOffset |= ((uint8_t)_file->get()) << 8; + loopOffset |= ((uint8_t)_file->get()) << 16; + loopOffset |= ((uint8_t)_file->get()) << 24; _loopOffset = (uint32_t)loopOffset; @@ -42,7 +40,7 @@ bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) _done = false; _loop = loop; _fileOffset = startOffset; - _file.seekg(_fileOffset, ios::beg); + _file->seekg(_fileOffset, ios::beg); _leftoverSampleCount = 0; _pcmBuffer.clear(); @@ -77,10 +75,10 @@ void PcmReader::SetLoopFlag(bool loop) void PcmReader::ReadSample(int16_t &left, int16_t &right) { uint8_t val[4]; - _file.get(((char*)val)[0]); - _file.get(((char*)val)[1]); - _file.get(((char*)val)[2]); - _file.get(((char*)val)[3]); + _file->get(((char*)val)[0]); + _file->get(((char*)val)[1]); + _file->get(((char*)val)[2]); + _file->get(((char*)val)[3]); left = val[0] | (val[1] << 8); right = val[2] | (val[3] << 8); @@ -108,7 +106,7 @@ void PcmReader::LoadSamples(uint32_t samplesToLoad) if(_loop) { i = _loopOffset * 4 + 8; _fileOffset = i; - _file.seekg(_fileOffset, ios::beg); + _file->seekg(_fileOffset, ios::beg); } else { _done = true; } @@ -140,4 +138,4 @@ void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume uint32_t PcmReader::GetOffset() { return _fileOffset; -} \ No newline at end of file +} diff --git a/Core/Shared/Audio/PcmReader.h b/Core/Shared/Audio/PcmReader.h index 6488bafb0..1f80ca429 100644 --- a/Core/Shared/Audio/PcmReader.h +++ b/Core/Shared/Audio/PcmReader.h @@ -11,7 +11,7 @@ class PcmReader int16_t* _outputBuffer = nullptr; - ifstream _file; + unique_ptr _file; uint32_t _fileOffset = 0; uint32_t _fileSize = 0; uint32_t _loopOffset = 0; diff --git a/UI/Localization/resources.en.xml b/UI/Localization/resources.en.xml index b51f233bb..481afb21e 100644 --- a/UI/Localization/resources.en.xml +++ b/UI/Localization/resources.en.xml @@ -582,7 +582,7 @@ Folders/Files File Associations - SNES roms: .sfc, .smc, .swc, .fig, .bs + SNES roms: .sfc, .smc, .swc, .fig, .bs, .msu1 SNES music: .spc NES roms: .nes, .unif, .fds, .studybox NES music: .nsf, .nsfe diff --git a/UI/Utilities/FileDialogHelper.cs b/UI/Utilities/FileDialogHelper.cs index 692f7177a..7305913e0 100644 --- a/UI/Utilities/FileDialogHelper.cs +++ b/UI/Utilities/FileDialogHelper.cs @@ -49,8 +49,8 @@ public class FileDialogHelper List filter = new List(); foreach(string ext in extensions) { if(ext == FileDialogHelper.RomExt) { - filter.Add(new FilePickerFileType("All ROM files") { Patterns = new List() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.spc", "*.nes", "*.fds", "*.unif", "*.unf", "*.studybox", "*.nsf", "*.nsfe", "*.gb", "*.gbc", "*.gbs", "*.pce", "*.sgx", "*.cue", "*.hes", "*.sms", "*.gg", "*.sg", "*.gba", "*.zip", "*.7z" } }); - filter.Add(new FilePickerFileType("SNES ROM files") { Patterns = new List() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.spc" } }); + filter.Add(new FilePickerFileType("All ROM files") { Patterns = new List() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.spc", "*.nes", "*.fds", "*.unif", "*.unf", "*.studybox", "*.nsf", "*.nsfe", "*.gb", "*.gbc", "*.gbs", "*.pce", "*.sgx", "*.cue", "*.hes", "*.sms", "*.gg", "*.sg", "*.gba", "*.zip", "*.7z", "*.msu1" } }); + filter.Add(new FilePickerFileType("SNES ROM files") { Patterns = new List() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.spc", "*.msu1" } }); filter.Add(new FilePickerFileType("NES ROM files") { Patterns = new List() { "*.nes", "*.fds", "*.unif", "*.unf", "*.studybox", "*.nsf", "*.nsfe" } }); filter.Add(new FilePickerFileType("GB ROM files") { Patterns = new List() { "*.gb", "*.gbc", "*.gbs" } }); filter.Add(new FilePickerFileType("GBA ROM files") { Patterns = new List() { "*.gba" } }); @@ -138,4 +138,4 @@ public class FileDialogHelper return null; } } -} +} \ No newline at end of file diff --git a/UI/Utilities/FolderHelper.cs b/UI/Utilities/FolderHelper.cs index cab80a2f2..a1494b69d 100644 --- a/UI/Utilities/FolderHelper.cs +++ b/UI/Utilities/FolderHelper.cs @@ -11,7 +11,7 @@ namespace Mesen.Utilities public static class FolderHelper { private static HashSet _romExtensions = new HashSet() { - ".sfc", ".smc", ".fig", ".swc", ".bs", + ".sfc", ".smc", ".fig", ".swc", ".bs", ".msu1", ".gb", ".gbc", ".nes", ".unif", ".unf", ".fds", ".studybox", ".pce", ".sgx", ".cue", @@ -55,4 +55,4 @@ public static bool CheckFolderPermissions(string folder, bool checkWritePermissi return true; } } -} +} \ No newline at end of file diff --git a/Utilities/VirtualFile.cpp b/Utilities/VirtualFile.cpp index 4a2d475ef..7ab1d1cd7 100644 --- a/Utilities/VirtualFile.cpp +++ b/Utilities/VirtualFile.cpp @@ -13,7 +13,7 @@ const std::initializer_list VirtualFile::RomExtensions = { ".nes", ".fds", ".unif", ".unf", ".nsf", ".nsfe", ".studybox", - ".sfc", ".swc", ".fig", ".smc", ".bs", ".spc", + ".sfc", ".swc", ".fig", ".smc", ".bs", ".spc", ".msu1", ".gb", ".gbc", ".gbs", ".pce", ".sgx", ".cue", ".hes", ".sms", ".gg", ".sg", @@ -265,6 +265,21 @@ bool VirtualFile::ReadFile(uint8_t* out, uint32_t expectedSize) return false; } +std::unique_ptr VirtualFile::Stream() +{ + if(!_innerFile.empty()) { + auto out = std::make_unique(); + ReadFile(*out); + return out; + } else { + auto ret = std::make_unique(_path, std::ios::in | std::ios::binary); + if(ret) { + return ret; + } + } + return std::make_unique(nullptr); +} + uint8_t VirtualFile::ReadByte(uint32_t offset) { InitChunks(); @@ -310,4 +325,4 @@ bool VirtualFile::ApplyPatch(VirtualFile& patch) } } return result; -} \ No newline at end of file +} diff --git a/Utilities/VirtualFile.h b/Utilities/VirtualFile.h index 4e5085115..415261cf7 100644 --- a/Utilities/VirtualFile.h +++ b/Utilities/VirtualFile.h @@ -48,6 +48,8 @@ class VirtualFile bool ReadFile(std::stringstream &out); bool ReadFile(uint8_t* out, uint32_t expectedSize); + std::unique_ptr Stream(); + uint8_t ReadByte(uint32_t offset); bool ApplyPatch(VirtualFile &patch); @@ -67,4 +69,4 @@ class VirtualFile return true; } -}; \ No newline at end of file +};