gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 69257e42ba951b33b7aaf836e3ce378e63e4b2e9
parent de35d682077fad28e41a3e5a33643f8695d5030d
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Tue,  6 Aug 2024 21:58:02 +0200

rework all/create rom loaders that verify that a found rom is for the correct synth

Diffstat:
Msource/mqLib/CMakeLists.txt | 1+
Msource/mqLib/microq.cpp | 10++++------
Msource/mqLib/mqhardware.cpp | 4++--
Msource/mqLib/mqhardware.h | 2+-
Msource/mqLib/rom.cpp | 11+++++++++++
Msource/mqLib/rom.h | 5++---
Asource/mqLib/romloader.cpp | 28++++++++++++++++++++++++++++
Asource/mqLib/romloader.h | 12++++++++++++
Msource/nord/n2x/n2xLib/CMakeLists.txt | 1+
Msource/nord/n2x/n2xLib/n2xhardware.cpp | 4+++-
Msource/nord/n2x/n2xLib/n2xrom.cpp | 17++++++++++++++---
Msource/nord/n2x/n2xLib/n2xrom.h | 3+++
Msource/nord/n2x/n2xLib/n2xromdata.cpp | 13++++++++-----
Msource/nord/n2x/n2xLib/n2xromdata.h | 2++
Asource/nord/n2x/n2xLib/n2xromloader.cpp | 20++++++++++++++++++++
Asource/nord/n2x/n2xLib/n2xromloader.h | 14++++++++++++++
Msource/nord/n2x/n2xTestConsole/n2xTestConsole.cpp | 9+++------
Msource/virusLib/romloader.cpp | 6++++--
Msource/wLib/wRom.cpp | 5++++-
Msource/wLib/wRom.h | 6++++++
20 files changed, 143 insertions(+), 30 deletions(-)

diff --git a/source/mqLib/CMakeLists.txt b/source/mqLib/CMakeLists.txt @@ -24,6 +24,7 @@ set(SOURCES lcd.cpp lcd.h leds.cpp leds.h rom.cpp rom.h + romloader.cpp romloader.h microq.cpp microq.h mqbuildconfig.h mqdsp.cpp mqdsp.h diff --git a/source/mqLib/microq.cpp b/source/mqLib/microq.cpp @@ -7,6 +7,7 @@ #include "dsp56kEmu/threadtools.h" #include "mqhardware.h" +#include "romloader.h" #include "mc68k/logging.h" @@ -14,14 +15,11 @@ namespace mqLib { MicroQ::MicroQ(BootMode _bootMode/* = BootMode::Default*/) { - // create hardware, will use in-memory ROM if no ROM provided -// auto romFile = synthLib::findROM(512 * 1024); // TODO: validate the found ROMs before use, check if it starts with "2.23". Otherwise, a Virus ROM might be found and booted -// if(romFile.empty()) - const auto romFile = synthLib::findFile(".mid", 300 * 1024, 400 * 1024); - if(romFile.empty()) + const auto romFile = RomLoader::findROM(); + if(!romFile.isValid()) throw synthLib::DeviceException(synthLib::DeviceError::FirmwareMissing, "Failed to find device operating system file mq_2_23.mid."); - MCLOG("Boot using ROM " << romFile); + MCLOG("Boot using ROM " << romFile.getFilename()); m_hw.reset(new Hardware(romFile)); diff --git a/source/mqLib/mqhardware.cpp b/source/mqLib/mqhardware.cpp @@ -7,9 +7,9 @@ namespace mqLib { - Hardware::Hardware(const std::string& _romFilename) + Hardware::Hardware(const ROM& _rom) : wLib::Hardware(44100) - , m_rom(_romFilename) + , m_rom(_rom) , m_uc(m_rom) #if MQ_VOICE_EXPANSION , m_dsps{MqDsp(*this, m_uc.getHdi08A().getHdi08(), 0), MqDsp(*this, m_uc.getHdi08B().getHdi08(), 1) , MqDsp(*this, m_uc.getHdi08C().getHdi08(), 2)} diff --git a/source/mqLib/mqhardware.h b/source/mqLib/mqhardware.h @@ -21,7 +21,7 @@ namespace mqLib static constexpr uint32_t g_dspCount = g_useVoiceExpansion ? 3 : 1; public: - explicit Hardware(const std::string& _romFilename); + explicit Hardware(const ROM& _rom); ~Hardware(); void process(); diff --git a/source/mqLib/rom.cpp b/source/mqLib/rom.cpp @@ -2,4 +2,15 @@ namespace mqLib { + ROM::ROM(const std::string& _filename) : wLib::ROM(_filename, g_romSize) + { + if(getSize() < 5) + return; + + auto* d = reinterpret_cast<const char*>(getData()); + + // OS version is right at the start of the ROM, as zero-terminated ASCII + if(strstr(d, "2.23") != d) + clear(); + } } diff --git a/source/mqLib/rom.h b/source/mqLib/rom.h @@ -9,9 +9,8 @@ namespace mqLib public: static constexpr uint32_t g_romSize = 524288; - explicit ROM(const std::string& _filename) : wLib::ROM(_filename, g_romSize) - { - } + ROM() = default; + explicit ROM(const std::string& _filename); static constexpr uint32_t size() { return g_romSize; } diff --git a/source/mqLib/romloader.cpp b/source/mqLib/romloader.cpp @@ -0,0 +1,28 @@ +#include "romloader.h" + +#include "synthLib/os.h" + +namespace mqLib +{ + ROM RomLoader::findROM() + { + const auto midiFiles = findFiles(".mid", 300 * 1024, 400 * 1024); + + for (const auto& midiFile : midiFiles) + { + ROM rom(midiFile); + if(rom.isValid()) + return rom; + } + + const auto binFiles = findFiles(".bin", 512 * 1024, 512 * 1024); + + for (const auto& binFile : binFiles) + { + ROM rom(binFile); + if(rom.isValid()) + return rom; + } + return {}; + } +} diff --git a/source/mqLib/romloader.h b/source/mqLib/romloader.h @@ -0,0 +1,12 @@ +#pragma once +#include "rom.h" +#include "synthLib/romLoader.h" + +namespace mqLib +{ + class RomLoader : synthLib::RomLoader + { + public: + static ROM findROM(); + }; +} diff --git a/source/nord/n2x/n2xLib/CMakeLists.txt b/source/nord/n2x/n2xLib/CMakeLists.txt @@ -15,6 +15,7 @@ set(SOURCES n2xmiditypes.h n2xrom.cpp n2xrom.h n2xromdata.cpp n2xromdata.h + n2xromloader.cpp n2xromloader.h n2xstate.cpp n2xstate.h n2xtypes.h ) diff --git a/source/nord/n2x/n2xLib/n2xhardware.cpp b/source/nord/n2x/n2xLib/n2xhardware.cpp @@ -1,5 +1,6 @@ #include "n2xhardware.h" +#include "n2xromloader.h" #include "dsp56kEmu/threadtools.h" namespace n2x @@ -11,7 +12,8 @@ namespace n2x static_assert(g_syncHaltDspEsaiThreshold >= g_syncEsaiFrameRate * 2, "esai DSP halt threshold must be greater than two times the sync rate"); Hardware::Hardware() - : m_uc(*this, m_rom) + : m_rom(RomLoader::findROM()) + , m_uc(*this, m_rom) , m_dspA(*this, m_uc.getHdi08A(), 0) , m_dspB(*this, m_uc.getHdi08B(), 1) , m_samplerateInv(1.0 / g_samplerate) diff --git a/source/nord/n2x/n2xLib/n2xrom.cpp b/source/nord/n2x/n2xLib/n2xrom.cpp @@ -8,10 +8,21 @@ namespace n2x { Rom::Rom() : RomData() { - constexpr uint8_t key[] = {'n', 'r', '2', 0, 'n', 'L', '2', 0}; + if(!isValidRom(data())) + invalidate(); + } - const auto it = std::search(data().begin(), data().end(), std::begin(key), std::end(key)); - if(it == data().end()) + Rom::Rom(const std::string& _filename) : RomData(_filename) + { + if(!isValidRom(data())) invalidate(); } + + bool Rom::isValidRom(std::array<unsigned char, 524288>& _data) + { + constexpr uint8_t key[] = {'n', 'r', '2', 0, 'n', 'L', '2', 0}; + + const auto it = std::search(_data.begin(), _data.end(), std::begin(key), std::end(key)); + return it != _data.end(); + } } diff --git a/source/nord/n2x/n2xLib/n2xrom.h b/source/nord/n2x/n2xLib/n2xrom.h @@ -9,5 +9,8 @@ namespace n2x { public: Rom(); + Rom(const std::string& _filename); + + static bool isValidRom(std::array<uint8_t, g_romSize>& _data); }; } diff --git a/source/nord/n2x/n2xLib/n2xromdata.cpp b/source/nord/n2x/n2xLib/n2xromdata.cpp @@ -6,18 +6,21 @@ namespace n2x { - template <uint32_t Size> RomData<Size>::RomData() + template <uint32_t Size> RomData<Size>::RomData() : RomData(synthLib::findROM(MySize, MySize)) { - const auto filename = synthLib::findROM(m_data.size(), m_data.size()); - if(filename.empty()) + } + + template <uint32_t Size> RomData<Size>::RomData(const std::string& _filename) + { + if(_filename.empty()) return; std::vector<uint8_t> data; - if(!synthLib::readFile(data, filename)) + if(!synthLib::readFile(data, _filename)) return; if(data.size() != m_data.size()) return; std::copy(data.begin(), data.end(), m_data.begin()); - m_filename = filename; + m_filename = _filename; } template <uint32_t Size> void RomData<Size>::saveAs(const std::string& _filename) diff --git a/source/nord/n2x/n2xLib/n2xromdata.h b/source/nord/n2x/n2xLib/n2xromdata.h @@ -10,7 +10,9 @@ namespace n2x class RomData { public: + static constexpr uint32_t MySize = Size; RomData(); + RomData(const std::string& _filename); bool isValid() const { return !m_filename.empty(); } const auto& data() const { return m_data; } diff --git a/source/nord/n2x/n2xLib/n2xromloader.cpp b/source/nord/n2x/n2xLib/n2xromloader.cpp @@ -0,0 +1,20 @@ +#include "n2xromloader.h" + +namespace n2x +{ + Rom RomLoader::findROM() + { + const auto files = findFiles(".bin", g_romSize, g_romSize); + + if(files.empty()) + return {}; + + for (const auto& file : files) + { + auto rom = Rom(file); + if(rom.isValid()) + return rom; + } + return {}; + } +} diff --git a/source/nord/n2x/n2xLib/n2xromloader.h b/source/nord/n2x/n2xLib/n2xromloader.h @@ -0,0 +1,14 @@ +#pragma once + +#include "n2xrom.h" + +#include "synthLib/romLoader.h" + +namespace n2x +{ + class RomLoader : synthLib::RomLoader + { + public: + static Rom findROM(); + }; +} diff --git a/source/nord/n2x/n2xTestConsole/n2xTestConsole.cpp b/source/nord/n2x/n2xTestConsole/n2xTestConsole.cpp @@ -1,7 +1,6 @@ #include <iostream> #include "n2xLib/n2xhardware.h" -#include "n2xLib/n2xrom.h" #include "synthLib/wavWriter.h" @@ -14,17 +13,15 @@ namespace n2x int main() { - const n2x::Rom rom; + std::unique_ptr<n2x::Hardware> hw; + hw.reset(new n2x::Hardware()); - if(!rom.isValid()) + if(!hw->isValid()) { std::cout << "Failed to load rom file\n"; return -1; } - std::unique_ptr<n2x::Hardware> hw; - hw.reset(new n2x::Hardware()); - hw->getDSPA().getDSPThread().setLogToStdout(true); hw->getDSPB().getDSPThread().setLogToStdout(true); diff --git a/source/virusLib/romloader.cpp b/source/virusLib/romloader.cpp @@ -216,9 +216,11 @@ namespace virusLib if(model == DeviceModel::Invalid) { - assert(false && "retry model detection for debugging purposes below"); + // disable load if model is not detected, because we now have other synths that have roms of the same size +// assert(false && "retry model detection for debugging purposes below"); detectModel(fd.data); - model = _model; // Must be based on DSP 56362 or hell breaks loose + continue; +// model = _model; // Must be based on DSP 56362 or hell breaks loose } } diff --git a/source/wLib/wRom.cpp b/source/wLib/wRom.cpp @@ -27,7 +27,10 @@ namespace wLib m_buffer.resize(_expectedSize, 0xff); } - return m_buffer.size() == _expectedSize; + if(m_buffer.size() != _expectedSize) + return false; + m_filename = _filename; + return true; } bool ROM::loadFromMidi(std::vector<unsigned char>& _buffer, const std::string& _filename) diff --git a/source/wLib/wRom.h b/source/wLib/wRom.h @@ -9,6 +9,7 @@ namespace wLib class ROM { public: + ROM() = default; explicit ROM(const std::string& _filename, const uint32_t _expectedSize, std::vector<uint8_t> _data = {}) : m_buffer(std::move(_data)) { if (m_buffer.size() != _expectedSize) @@ -20,6 +21,10 @@ namespace wLib bool isValid() const { return !m_buffer.empty(); } virtual uint32_t getSize() const = 0; + void clear() { m_buffer.clear(); } + + const auto& getFilename() const { return m_filename; } + static bool loadFromMidi(std::vector<uint8_t>& _buffer, const std::string& _filename); static bool loadFromMidiData(std::vector<uint8_t>& _buffer, const std::vector<uint8_t>& _midiData); static bool loadFromSysExFile(std::vector<uint8_t>& _buffer, const std::string& _filename); @@ -29,5 +34,6 @@ namespace wLib bool loadFromFile(const std::string& _filename, uint32_t _expectedSize); std::vector<uint8_t> m_buffer; + std::string m_filename; }; }