commit edea1c30eaeff939d5cee3d4ad6c8078a671e3e0
parent 13e9b7163429cb90fb8e641b099e116ab9f6b0d6
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Sun, 19 May 2024 17:58:33 +0200
support extraction of multiple preset formats from a single file
Diffstat:
2 files changed, 111 insertions(+), 93 deletions(-)
diff --git a/source/virusJucePlugin/PatchManager.cpp b/source/virusJucePlugin/PatchManager.cpp
@@ -267,13 +267,13 @@ namespace genericVirusUI
return true;
}
- if (virusLib::Device::parsePowercorePreset(_results, _data))
+ if (virusLib::Device::parseVTIBackup(_results, _data))
return true;
- if(virusLib::Device::parseVTIBackup(_results, _data))
- return true;
+ bool res = virusLib::Device::parsePowercorePreset(_results, _data);
+ res |= synthLib::MidiToSysex::extractSysexFromData(_results, _data);
- if(!synthLib::MidiToSysex::extractSysexFromData(_results, _data))
+ if(!res)
return false;
if(!_results.empty())
diff --git a/source/virusLib/device.cpp b/source/virusLib/device.cpp
@@ -193,10 +193,10 @@ namespace virusLib
bool Device::find4CC(uint32_t& _offset, const std::vector<uint8_t>& _data, const std::string_view& _4cc)
{
- if(_data.size() < _4cc.size())
+ if(_data.size() < (_offset + _4cc.size()))
return false;
- for(uint32_t i=0; i<_data.size() - _4cc.size(); ++i)
+ for(uint32_t i=_offset; i<_data.size() - _4cc.size(); ++i)
{
bool valid = true;
for(size_t j=0; j<_4cc.size(); ++j)
@@ -222,124 +222,142 @@ namespace virusLib
uint32_t readPos = 0;
- if(!find4CC(readPos, _state, "MIDI"))
- return false;
-
- if(readPos >= _state.size())
- return false;
+ uint32_t numFound = 0;
- auto readLen = [&_state](const size_t _offset) -> uint32_t
+ while(readPos < _state.size() - 4)
{
- if(_offset + 4 > _state.size())
- return 0;
- const uint32_t o =
- (static_cast<uint32_t>(_state[_offset+0]) << 24) |
- (static_cast<uint32_t>(_state[_offset+1]) << 16) |
- (static_cast<uint32_t>(_state[_offset+2]) << 8) |
- (static_cast<uint32_t>(_state[_offset+3]));
- return o;
- };
-
- auto nextLen = [&readPos, &readLen]() -> uint32_t
- {
- const auto len = readLen(readPos);
- readPos += 4;
- return len;
- };
+ if(!find4CC(readPos, _state, "MIDI"))
+ break;
- const auto dataLen = nextLen();
+ if(readPos >= _state.size())
+ break;
- if(dataLen + readPos > _state.size())
- return false;
+ auto readLen = [&_state](const size_t _offset) -> uint32_t
+ {
+ if(_offset + 4 > _state.size())
+ return 0;
+ const uint32_t o =
+ (static_cast<uint32_t>(_state[_offset+0]) << 24) |
+ (static_cast<uint32_t>(_state[_offset+1]) << 16) |
+ (static_cast<uint32_t>(_state[_offset+2]) << 8) |
+ (static_cast<uint32_t>(_state[_offset+3]));
+ return o;
+ };
+
+ auto nextLen = [&readPos, &readLen]() -> uint32_t
+ {
+ const auto len = readLen(readPos);
+ readPos += 4;
+ return len;
+ };
- const auto controllerAssignmentsLen = nextLen();
+ const auto dataLen = nextLen();
- readPos += controllerAssignmentsLen;
-
- while(readPos < _state.size())
- {
- const auto midiDataLen = nextLen();
-
- if(!midiDataLen)
+ if(dataLen + readPos > _state.size())
break;
- if((readPos + midiDataLen) > _state.size())
- return false;
+ const auto controllerAssignmentsLen = nextLen();
- synthLib::SMidiEvent& e = _events.emplace_back();
+ readPos += controllerAssignmentsLen;
+
+ while(readPos < _state.size())
+ {
+ const auto midiDataLen = nextLen();
- e.sysex.assign(_state.begin() + readPos, _state.begin() + readPos + midiDataLen);
+ if(!midiDataLen)
+ break;
- if(e.sysex.front() != 0xf0)
- {
- assert(e.sysex.size() <= 3);
- e.a = e.sysex[0];
- if(e.sysex.size() > 1)
- e.b = e.sysex[1];
- if(e.sysex.size() > 2)
- e.c = e.sysex[2];
-
- e.sysex.clear();
- }
+ if((readPos + midiDataLen) > _state.size())
+ break;
+
+ synthLib::SMidiEvent& e = _events.emplace_back();
+
+ e.sysex.assign(_state.begin() + readPos, _state.begin() + readPos + midiDataLen);
+
+ if(e.sysex.front() != 0xf0)
+ {
+ assert(e.sysex.size() <= 3);
+ e.a = e.sysex[0];
+ if(e.sysex.size() > 1)
+ e.b = e.sysex[1];
+ if(e.sysex.size() > 2)
+ e.c = e.sysex[2];
+
+ e.sysex.clear();
+ }
- readPos += midiDataLen;
+ readPos += midiDataLen;
+
+ if(!e.sysex.empty())
+ ++numFound;
+ }
}
- return true;
+ return numFound > 0;
}
bool Device::parsePowercorePreset(std::vector<std::vector<uint8_t>>& _sysexPresets, const std::vector<uint8_t>& _data)
{
uint32_t off = 0;
- // VST2 fxp/fxb chunk must exist
- if(!find4CC(off, _data, "CcnK"))
- return false;
+ uint32_t numFound = 0;
- uint32_t pos = 0;
-
- // fxp or fxb?
- if(find4CC(off, _data, "FPCh"))
- pos = off + 0x34; // fxp
- else if(find4CC(off, _data, "FBCh"))
- pos = off + 0x98; // fxb
- else
- return false;
+ while(off < _data.size() - 4)
+ {
+ // VST2 fxp/fxb chunk must exist
+ if(!find4CC(off, _data, "CcnK"))
+ break;
- if(pos >= _data.size())
- return false;
+ off += 4;
- ++pos; // skip first byte, version?
+ uint32_t pos;
- constexpr uint32_t presetSize = 256; // presets seem to be stored without sysex packaging
- constexpr uint32_t padding = 5; // five unknown bytes betweeen two presets
+ // fxp or fxb?
+ if(find4CC(off, _data, "FPCh"))
+ pos = off + 0x34; // fxp
+ else if(find4CC(off, _data, "FBCh"))
+ pos = off + 0x98; // fxb
+ else
+ continue;
- uint8_t programIndex = 0;
+ if(pos >= _data.size())
+ break;
- while((pos + presetSize) <= static_cast<uint32_t>(_data.size()))
- {
- Microcontroller::TPreset p;
- memcpy(&p.front(), &_data[pos], presetSize);
+ ++pos; // skip first byte, version?
- const auto version = Microcontroller::getPresetVersion(p);
- if(version != C)
- break;
- const auto name = ROMFile::getSingleName(p);
- if(name.size() != 10)
- break;
+ constexpr uint32_t presetSize = 256; // presets seem to be stored without sysex packaging
+ constexpr uint32_t padding = 5; // five unknown bytes betweeen two presets
- // pack into sysex
- std::vector<uint8_t>& sysex = _sysexPresets.emplace_back(std::vector<uint8_t>{0xf0, 0x00, 0x20, 0x33, 0x01, OMNI_DEVICE_ID, 0x10, 0x01, programIndex});
- sysex.insert(sysex.end(), _data.begin() + pos, _data.begin() + pos + presetSize);
- sysex.push_back(Microcontroller::calcChecksum(sysex, 5));
- sysex.push_back(0xf7);
+ uint8_t programIndex = 0;
- ++programIndex;
- pos += presetSize;
- pos += padding;
+ while((pos + presetSize) <= static_cast<uint32_t>(_data.size()))
+ {
+ Microcontroller::TPreset p;
+ memcpy(&p.front(), &_data[pos], presetSize);
+
+ const auto version = Microcontroller::getPresetVersion(p);
+ if(version != C)
+ break;
+ const auto name = ROMFile::getSingleName(p);
+ if(name.size() != 10)
+ break;
+
+ // pack into sysex
+ std::vector<uint8_t>& sysex = _sysexPresets.emplace_back(std::vector<uint8_t>{0xf0, 0x00, 0x20, 0x33, 0x01, OMNI_DEVICE_ID, 0x10, 0x01, programIndex});
+ sysex.insert(sysex.end(), _data.begin() + pos, _data.begin() + pos + presetSize);
+ sysex.push_back(Microcontroller::calcChecksum(sysex, 5));
+ sysex.push_back(0xf7);
+
+ ++numFound;
+
+ ++programIndex;
+ pos += presetSize;
+ pos += padding;
+ }
+ off = pos;
}
- return !_sysexPresets.empty();
+ return numFound > 0;
}
bool Device::parseVTIBackup(std::vector<std::vector<uint8_t>>& _sysexPresets, const std::vector<uint8_t>& _data)