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 57312d1113faa1e8bf6d44de454b0b5803808803
parent f7c0fc41f1f618fc3f342f67e80104010d06f557
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sat, 18 May 2024 12:54:40 +0200

[Osirus] [OsTIrus] [Imp] added support for .vtibackup files

Diffstat:
Msource/virusJucePlugin/PatchManager.cpp | 3+++
Msource/virusLib/device.cpp | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msource/virusLib/device.h | 1+
3 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/source/virusJucePlugin/PatchManager.cpp b/source/virusJucePlugin/PatchManager.cpp @@ -270,6 +270,9 @@ namespace genericVirusUI if (virusLib::Device::parsePowercorePreset(_results, _data)) return true; + if(virusLib::Device::parseVTIBackup(_results, _data)) + return true; + if(!synthLib::MidiToSysex::extractSysexFromData(_results, _data)) return false; diff --git a/source/virusLib/device.cpp b/source/virusLib/device.cpp @@ -342,6 +342,61 @@ namespace virusLib return !_sysexPresets.empty(); } + bool Device::parseVTIBackup(std::vector<std::vector<uint8_t>>& _sysexPresets, const std::vector<uint8_t>& _data) + { + if(_data.size() < 512) + return false; + + // first 11 bytes are the serial number. Check if they're all ASCII + for(size_t i=0; i<11; ++i) + { + if(_data[i] < 32 || _data[i] > 127) + return false; + } + + constexpr size_t presetSize = sizeof(Microcontroller::TPreset); + Microcontroller::TPreset preset; + + constexpr uint32_t maxPresets = (4 + 26) * 128; // 4x RAM banks, 26x ROM banks, 128 patches per bank + + uint32_t presetIdx = 0; + + // presets start at $20 + // They are "raw" presets, i.e. 512 bytes or preset data each + // The sysex packaging is missing, i.e. the single dump header, the checksums and the sysex terminator + for(size_t i=0x20; i<_data.size() - presetSize; i += presetSize) + { + memcpy(preset.data(), &_data[i], presetSize); + + const auto name = ROMFile::getSingleName(preset); + + if(name.size() != 10) + break; + + auto& sysex = _sysexPresets.emplace_back(std::vector<uint8_t>{ + 0xf0, 0x00, 0x20, 0x33, 0x01, OMNI_DEVICE_ID, DUMP_SINGLE, + static_cast<uint8_t>((presetIdx >> 7) & 0x7f), + static_cast<uint8_t>(presetIdx & 0x7f)}); + + sysex.reserve(9 + 256 + 1 + 256 + 2); // header, 256 preset bytes, 1st checksum, 256 preset bytes, 2nd checksum, EOX + + for(size_t j=0; j<256; ++j) + sysex.push_back(preset[j]); + sysex.push_back(Microcontroller::calcChecksum(sysex, 5)); + for(size_t j=256; j<512; ++j) + sysex.push_back(preset[j]); + sysex.push_back(Microcontroller::calcChecksum(sysex, 5)); + sysex.push_back(0xf7); + + ++presetIdx; + + if(presetIdx == maxPresets) + break; + } + + return true; + } + uint32_t Device::getInternalLatencyMidiToOutput() const { // Note that this is an average value, midi latency drifts in a range of roughly +/- 61 samples diff --git a/source/virusLib/device.h b/source/virusLib/device.h @@ -39,6 +39,7 @@ namespace virusLib static bool find4CC(uint32_t& _offset, const std::vector<uint8_t>& _data, const std::string_view& _4cc); static bool parseTIcontrolPreset(std::vector<synthLib::SMidiEvent>& _events, const std::vector<uint8_t>& _state); static bool parsePowercorePreset(std::vector<std::vector<uint8_t>>& _sysexPresets, const std::vector<uint8_t>& _data); + static bool parseVTIBackup(std::vector<std::vector<uint8_t>>& _sysexPresets, const std::vector<uint8_t>& _data); uint32_t getInternalLatencyMidiToOutput() const override; uint32_t getInternalLatencyInputToOutput() const override;