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 30febc27725a2b5bf2ca7e6a0c2c213633af49b3
parent 56e92242ade212a68e2cf389e6a69bc6fac52cf0
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Tue,  5 Nov 2024 18:29:49 +0100

support to import waves from mid/syx files via d&d

Diffstat:
Msource/xtJucePlugin/weWaveTreeItem.cpp | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msource/xtJucePlugin/weWaveTreeItem.h | 3+++
Msource/xtLib/xtState.cpp | 23+++++++++++++++++++++--
Msource/xtLib/xtState.h | 4++--
4 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/source/xtJucePlugin/weWaveTreeItem.cpp b/source/xtJucePlugin/weWaveTreeItem.cpp @@ -4,6 +4,8 @@ #include "weWaveDesc.h" #include "xtWaveEditor.h" +#include "synthLib/midiToSysex.h" + namespace xtJucePlugin { WaveTreeItem::WaveTreeItem(WaveEditor& _editor, const WaveCategory _category, const xt::WaveId _waveIndex) @@ -104,6 +106,59 @@ namespace xtJucePlugin } } + bool WaveTreeItem::isInterestedInFileDrag(const juce::StringArray& files) + { + if(xt::wave::isReadOnly(m_waveIndex)) + return false; + + if(files.size() == 1 && files[0].endsWithIgnoreCase(".mid") || files[1].endsWithIgnoreCase(".syx")) + return true; + + return TreeItem::isInterestedInFileDrag(files); + } + + void WaveTreeItem::filesDropped(const juce::StringArray& files, int insertIndex) + { + if(xt::wave::isReadOnly(m_waveIndex)) + return; + + if(files.size() != 1 || (!files[0].endsWithIgnoreCase(".mid") && !files[0].endsWithIgnoreCase(".syx"))) + { + TreeItem::filesDropped(files, insertIndex); + return; + } + + std::vector<std::vector<uint8_t>> sysex; + + synthLib::MidiToSysex::extractSysexFromFile(sysex, files[0].toStdString()); + + if(sysex.empty()) + return; + + std::vector<xt::WaveData> waves; + + for (const auto& s : sysex) + { + xt::WaveData wave; + if(xt::State::parseWaveData(wave, sysex.front())) + waves.push_back(wave); + } + + if(waves.empty()) + { + juce::NativeMessageBox::showMessageBoxAsync(juce::AlertWindow::WarningIcon, "Error", "No wave data found in file."); + return; + } + + if(waves.size() > 1) + { + juce::NativeMessageBox::showMessageBoxAsync(juce::AlertWindow::WarningIcon, "Error", "Multiple waves found in file."); + return; + } + + m_editor.getData().setWave(m_waveIndex, waves.front()); + } + void WaveTreeItem::onWaveChanged(const xt::WaveId _index) const { if(_index != m_waveIndex) diff --git a/source/xtJucePlugin/weWaveTreeItem.h b/source/xtJucePlugin/weWaveTreeItem.h @@ -30,6 +30,9 @@ namespace xtJucePlugin bool isInterestedInDragSource(const juce::DragAndDropTarget::SourceDetails& dragSourceDetails) override; void itemDropped(const juce::DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) override; + bool isInterestedInFileDrag(const juce::StringArray& files) override; + void filesDropped(const juce::StringArray& files, int insertIndex) override; + private: void onWaveChanged(xt::WaveId _index) const; void onWaveChanged() const; diff --git a/source/xtLib/xtState.cpp b/source/xtLib/xtState.cpp @@ -854,8 +854,16 @@ namespace xt */ } - void State::parseWaveData(WaveData& _wave, const SysEx& _sysex) + bool State::parseWaveData(WaveData& _wave, const SysEx& _sysex) { + if(_sysex.size() != std::tuple_size_v<Wave>) + return false; + + if(_sysex.front() != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw2) + return false; + + if(_sysex[4] != static_cast<uint8_t>(SysexCommand::WaveDump) && _sysex[4] != static_cast<uint8_t>(SysexCommand::WaveDumpP)) + return false; /* mw2_sysex.pdf: @@ -882,6 +890,7 @@ namespace xt _wave[i] = static_cast<int8_t>(sample); _wave[127-i] = static_cast<int8_t>(-sample); } + return true; } SysEx State::createWaveData(const WaveData& _wave, const uint16_t _waveIndex, const bool _preview) @@ -930,8 +939,17 @@ namespace xt return result; } - void State::parseTableData(TableData& _table, const SysEx& _sysex) + bool State::parseTableData(TableData& _table, const SysEx& _sysex) { + if(_sysex.size() != std::tuple_size_v<Table>) + return false; + + if(_sysex[0] != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw2) + return false; + + if(_sysex[4] != static_cast<uint8_t>(SysexCommand::WaveCtlDump) && _sysex[4] != static_cast<uint8_t>(SysexCommand::WaveCtlDumpP)) + return false; + constexpr uint32_t off = 7; for(uint32_t i=0; i<_table.size(); ++i) @@ -945,6 +963,7 @@ namespace xt _table[i] = WaveId(static_cast<uint16_t>(waveIdx)); } + return true; } SysEx State::createTableData(const TableData& _table, const uint32_t _tableIndex, const bool _preview) diff --git a/source/xtLib/xtState.h b/source/xtLib/xtState.h @@ -92,11 +92,11 @@ namespace xt static void createSequencerMultiData(std::vector<uint8_t>& _data); - static void parseWaveData(WaveData& _wave, const SysEx& _sysex); + static bool parseWaveData(WaveData& _wave, const SysEx& _sysex); static SysEx createWaveData(const WaveData& _wave, uint16_t _waveIndex, bool _preview); static WaveData createinterpolatedTable(const WaveData& _a, const WaveData& _b, uint16_t _indexA, uint16_t _indexB, uint16_t _indexTarget); - static void parseTableData(TableData& _table, const SysEx& _sysex); + static bool parseTableData(TableData& _table, const SysEx& _sysex); static SysEx createTableData(const TableData& _table, uint32_t _tableIndex, bool _preview); static SysEx createCombinedPatch(const std::vector<SysEx>& _dumps);