Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSU-1: Add support for .ogg files, and the .msu1 zip-file format #58

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,6 @@
<ClCompile Include="NES\HdPacks\HdPackLoader.cpp" />
<ClCompile Include="NES\HdPacks\HdVideoFilter.cpp" />
<ClCompile Include="NES\HdPacks\OggMixer.cpp" />
<ClCompile Include="NES\HdPacks\OggReader.cpp" />
<ClCompile Include="NES\Loaders\FdsLoader.cpp" />
<ClCompile Include="NES\Loaders\iNesLoader.cpp" />
<ClCompile Include="NES\Loaders\NsfLoader.cpp" />
Expand Down Expand Up @@ -979,6 +978,7 @@
<ClCompile Include="SNES\SnesNtscFilter.cpp" />
<ClCompile Include="SNES\Coprocessors\OBC1\Obc1.cpp" />
<ClCompile Include="Shared\Audio\PcmReader.cpp" />
<ClCompile Include="Shared\Audio\OggReader.cpp" />
<ClCompile Include="SNES\SnesPpu.cpp" />
<ClCompile Include="Debugger\PpuTools.cpp" />
<ClCompile Include="Debugger\Profiler.cpp" />
Expand Down Expand Up @@ -1240,4 +1240,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
14 changes: 7 additions & 7 deletions Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -844,12 +844,6 @@
<ClInclude Include="NES\HdPacks\OggMixer.h">
<Filter>NES\HdPacks</Filter>
</ClInclude>
<ClCompile Include="NES\HdPacks\OggReader.cpp">
<Filter>NES\HdPacks</Filter>
</ClCompile>
<ClInclude Include="NES\HdPacks\OggReader.h">
<Filter>NES\HdPacks</Filter>
</ClInclude>
<ClInclude Include="NES\Input\ArkanoidController.h">
<Filter>NES\Input</Filter>
</ClInclude>
Expand Down Expand Up @@ -979,6 +973,12 @@
<ClInclude Include="Shared\Audio\PcmReader.h">
<Filter>Shared\Audio</Filter>
</ClInclude>
<ClCompile Include="Shared\Audio\OggReader.cpp">
<Filter>Shared\Audio</Filter>
</ClCompile>
<ClInclude Include="Shared\Audio\OggReader.h">
<Filter>Shared\Audio</Filter>
</ClInclude>
<ClCompile Include="Shared\Audio\SoundMixer.cpp">
<Filter>Shared\Audio</Filter>
</ClCompile>
Expand Down Expand Up @@ -3185,4 +3185,4 @@
<UniqueIdentifier>{4cc96bee-c354-4a9b-9947-85959ccc072f}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>
2 changes: 1 addition & 1 deletion Core/NES/HdPacks/OggMixer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "pch.h"
#include <algorithm>
#include "NES/HdPacks/OggReader.h"
#include "Shared/Audio/OggReader.h"
#include "NES/HdPacks/OggMixer.h"

enum class OggPlaybackOptions
Expand Down
111 changes: 95 additions & 16 deletions Core/SNES/Coprocessors/MSU1/Msu1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> 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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -71,7 +148,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;
}
Expand All @@ -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;

Expand All @@ -106,24 +183,26 @@ 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, _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);
if (_dataFile) {
_dataFile->seekg(_dataPointer, ios::beg);
}
LoadTrack(offset);
}
}
25 changes: 22 additions & 3 deletions Core/SNES/Coprocessors/MSU1/Msu1.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
#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"
#include "Utilities/StringUtilities.h"
#include "Utilities/ArchiveReader.h"

class Spc;
class Emulator;

class PcmOrOggReader final {
private:
PcmReader _pcmReader;
OggReader _oggReader;
bool _usingOgg = false;

public:
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
{
private:
Spc* _spc = nullptr;
Emulator* _emu = nullptr;
PcmReader _pcmReader;
PcmOrOggReader _soundReader;
uint8_t _volume = 100;
uint16_t _trackSelect = 0;
uint32_t _tmpDataPointer = 0;
Expand All @@ -28,7 +47,7 @@ class Msu1 final : public ISerializable, public IAudioProvider
bool _dataBusy = false; //Always false
bool _trackMissing = false;

ifstream _dataFile;
unique_ptr<istream> _dataFile;
uint32_t _dataSize;

void LoadTrack(uint32_t startOffset = 8);
Expand All @@ -45,4 +64,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;
};
};
15 changes: 13 additions & 2 deletions Core/SNES/SnesConsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -549,4 +560,4 @@ void SnesConsole::InitializeRam(void* data, uint32_t length)
state = settings->GetSnesConfig().RamPowerOnState;
}
settings->InitializeRam(state, data, length);
}
}
3 changes: 2 additions & 1 deletion Core/SNES/SnesConsole.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".spc" }; }
static vector<string> GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".spc", ".msu1" }; }
static vector<string> GetSupportedSignatures() { return { "SNES-SPC700 Sound File Data" }; }

void Initialize();
Expand Down