commit b15af7397cb631bd10c849b22c72bb0901c6ee2b parent 536104fcda25a224f4756949df44bad659900d5a Author: dsp56300 <dsp56300@users.noreply.github.com> Date: Sat, 20 Apr 2024 15:53:41 +0200 rename classes to have better names Diffstat:
25 files changed, 359 insertions(+), 360 deletions(-)
diff --git a/source/jucePluginEditorLib/pluginEditorState.h b/source/jucePluginEditorLib/pluginEditorState.h @@ -17,7 +17,7 @@ namespace juce class Component; } -class AudioPluginAudioProcessor; +class VirusProcessor; namespace jucePluginEditorLib { diff --git a/source/osTIrusJucePlugin/PluginEditorState.cpp b/source/osTIrusJucePlugin/PluginEditorState.cpp @@ -7,6 +7,6 @@ const std::vector<jucePluginEditorLib::PluginEditorState::Skin> g_includedSkins {"TI Trancy", "VirusTI_Trancy.json", ""} }; -OsTIrusEditorState::OsTIrusEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller) : PluginEditorState(_processor, _controller, g_includedSkins) +OsTIrusEditorState::OsTIrusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller) : VirusEditorState(_processor, _controller, g_includedSkins) { } diff --git a/source/osTIrusJucePlugin/PluginEditorState.h b/source/osTIrusJucePlugin/PluginEditorState.h @@ -1,11 +1,11 @@ #pragma once -#include "../virusJucePlugin/PluginEditorState.h" +#include "../virusJucePlugin/VirusEditorState.h" -class AudioPluginAudioProcessor; +class VirusProcessor; -class OsTIrusEditorState : public PluginEditorState +class OsTIrusEditorState : public VirusEditorState { public: - explicit OsTIrusEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller); + explicit OsTIrusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller); }; diff --git a/source/osTIrusJucePlugin/PluginProcessor.cpp b/source/osTIrusJucePlugin/PluginProcessor.cpp @@ -19,7 +19,7 @@ namespace //============================================================================== OsTIrusProcessor::OsTIrusProcessor() : - AudioPluginAudioProcessor(BusesProperties() + VirusProcessor(BusesProperties() .withInput("Input", juce::AudioChannelSet::stereo(), true) .withOutput("Output", juce::AudioChannelSet::stereo(), true) #if JucePlugin_IsSynth diff --git a/source/osTIrusJucePlugin/PluginProcessor.h b/source/osTIrusJucePlugin/PluginProcessor.h @@ -1,9 +1,8 @@ #pragma once -#include "../virusJucePlugin/PluginProcessor.h" +#include "../virusJucePlugin/VirusProcessor.h" -//============================================================================== -class OsTIrusProcessor : public AudioPluginAudioProcessor +class OsTIrusProcessor : public VirusProcessor { public: OsTIrusProcessor(); diff --git a/source/osirusJucePlugin/PluginEditorState.cpp b/source/osirusJucePlugin/PluginEditorState.cpp @@ -9,6 +9,6 @@ const std::vector<jucePluginEditorLib::PluginEditorState::Skin> g_includedSkins {"Galaxpel", "VirusC_Galaxpel.json", ""} }; -OsirusEditorState::OsirusEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller) : PluginEditorState(_processor, _controller, g_includedSkins) +OsirusEditorState::OsirusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller) : VirusEditorState(_processor, _controller, g_includedSkins) { } diff --git a/source/osirusJucePlugin/PluginEditorState.h b/source/osirusJucePlugin/PluginEditorState.h @@ -1,11 +1,11 @@ #pragma once -#include "../virusJucePlugin/pluginEditorState.h" +#include "../virusJucePlugin/VirusEditorState.h" -class AudioPluginAudioProcessor; +class VirusProcessor; -class OsirusEditorState : public PluginEditorState +class OsirusEditorState : public VirusEditorState { public: - explicit OsirusEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller); + explicit OsirusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller); }; diff --git a/source/osirusJucePlugin/PluginProcessor.cpp b/source/osirusJucePlugin/PluginProcessor.cpp @@ -19,7 +19,7 @@ namespace //============================================================================== OsirusProcessor::OsirusProcessor() : - AudioPluginAudioProcessor(BusesProperties() + VirusProcessor(BusesProperties() .withInput("Input", juce::AudioChannelSet::stereo(), true) .withOutput("Output", juce::AudioChannelSet::stereo(), true) #if JucePlugin_IsSynth diff --git a/source/osirusJucePlugin/PluginProcessor.h b/source/osirusJucePlugin/PluginProcessor.h @@ -1,8 +1,8 @@ #pragma once -#include "../virusJucePlugin/PluginProcessor.h" +#include "../virusJucePlugin/VirusProcessor.h" -class OsirusProcessor : public AudioPluginAudioProcessor +class OsirusProcessor : public VirusProcessor { public: OsirusProcessor(); diff --git a/source/virusJucePlugin/CMakeLists.txt b/source/virusJucePlugin/CMakeLists.txt @@ -19,16 +19,16 @@ set(SOURCES Parts.h PatchManager.cpp PatchManager.h - PluginEditorState.cpp - PluginEditorState.h - PluginProcessor.cpp - PluginProcessor.h Tabs.cpp Tabs.h VirusController.cpp VirusController.h VirusEditor.cpp VirusEditor.h + VirusEditorState.cpp + VirusEditorState.h + VirusProcessor.cpp + VirusProcessor.h ) add_library(virusJucePlugin STATIC) diff --git a/source/virusJucePlugin/Leds.cpp b/source/virusJucePlugin/Leds.cpp @@ -2,13 +2,13 @@ #include "VirusEditor.h" -#include "PluginProcessor.h" +#include "VirusProcessor.h" namespace genericVirusUI { constexpr const char* g_lfoNames[3] = {"Lfo1LedOn", "Lfo2LedOn", "Lfo3LedOn"}; - Leds::Leds(const genericUI::Editor& _editor, AudioPluginAudioProcessor& _processor) + Leds::Leds(const genericUI::Editor& _editor, VirusProcessor& _processor) { for(size_t i=0; i<m_lfos.size(); ++i) { diff --git a/source/virusJucePlugin/Leds.h b/source/virusJucePlugin/Leds.h @@ -5,7 +5,7 @@ #include "../../jucePluginEditorLib/led.h" -class AudioPluginAudioProcessor; +class VirusProcessor; namespace genericUI { @@ -17,7 +17,7 @@ namespace genericVirusUI class Leds { public: - Leds(const genericUI::Editor& _editor, AudioPluginAudioProcessor& _processor); + Leds(const genericUI::Editor& _editor, VirusProcessor& _processor); ~Leds(); private: diff --git a/source/virusJucePlugin/Parts.cpp b/source/virusJucePlugin/Parts.cpp @@ -4,7 +4,7 @@ #include "VirusEditor.h" #include "VirusController.h" -#include "PluginProcessor.h" +#include "VirusProcessor.h" #include "ParameterNames.h" #include "../jucePluginEditorLib/pluginProcessor.h" @@ -166,7 +166,7 @@ namespace genericVirusUI { const auto multiMode = m_editor.getController().isMultiMode(); - const auto partCount = multiMode ? static_cast<AudioPluginAudioProcessor&>(m_editor.getProcessor()).getPartCount() : 1; + const auto partCount = multiMode ? static_cast<VirusProcessor&>(m_editor.getProcessor()).getPartCount() : 1; for(size_t i=0; i<m_partSelect.size(); ++i) { diff --git a/source/virusJucePlugin/PluginEditorState.cpp b/source/virusJucePlugin/PluginEditorState.cpp @@ -1,106 +0,0 @@ -#include "PluginEditorState.h" - -#include "PluginProcessor.h" - -#include "VirusEditor.h" - -#include "../synthLib/os.h" - -PluginEditorState::PluginEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller, const std::vector<PluginEditorState::Skin>& _includedSkins) - : jucePluginEditorLib::PluginEditorState(_processor, _controller, _includedSkins) -{ - loadDefaultSkin(); -} - -genericUI::Editor* PluginEditorState::createEditor(const Skin& _skin, std::function<void()> _openMenuCallback) -{ - return new genericVirusUI::VirusEditor(m_parameterBinding, static_cast<AudioPluginAudioProcessor&>(m_processor), _skin.jsonFilename, _skin.folder, _openMenuCallback); -} - -void PluginEditorState::initContextMenu(juce::PopupMenu& _menu) -{ - jucePluginEditorLib::PluginEditorState::initContextMenu(_menu); - auto& p = m_processor; - - { - juce::PopupMenu gainMenu; - - const auto gain = m_processor.getOutputGain(); - - gainMenu.addItem("-12 db", true, gain == 0.25f, [&p] { p.setOutputGain(0.25f); }); - gainMenu.addItem("-6 db", true, gain == 0.5f, [&p] { p.setOutputGain(0.5f); }); - gainMenu.addItem("0 db (default)", true, gain == 1, [&p] { p.setOutputGain(1); }); - gainMenu.addItem("+6 db", true, gain == 2, [&p] { p.setOutputGain(2); }); - gainMenu.addItem("+12 db", true, gain == 4, [&p] { p.setOutputGain(4); }); - - _menu.addSubMenu("Output Gain", gainMenu); - } -} - -bool PluginEditorState::initAdvancedContextMenu(juce::PopupMenu& _menu, bool _enabled) -{ - jucePluginEditorLib::PluginEditorState::initAdvancedContextMenu(_menu, _enabled); - - const auto percent = m_processor.getDspClockPercent(); - const auto hz = m_processor.getDspClockHz(); - - juce::PopupMenu clockMenu; - - auto makeEntry = [&](const int _percent) - { - const auto mhz = hz * _percent / 100 / 1000000; - std::stringstream ss; - ss << _percent << "% (" << mhz << " MHz)"; - if(_percent == 100) - ss << " (Default)"; - clockMenu.addItem(ss.str(), _enabled, percent == _percent, [this, _percent] { m_processor.setDspClockPercent(_percent); }); - }; - - makeEntry(50); - makeEntry(75); - makeEntry(100); - makeEntry(125); - makeEntry(150); - makeEntry(200); - - _menu.addSubMenu("DSP Clock", clockMenu); - - const auto samplerates = m_processor.getDeviceSupportedSamplerates(); - - if(samplerates.size() > 1) - { - juce::PopupMenu srMenu; - - const auto current = m_processor.getPreferredDeviceSamplerate(); - - const auto preferred = m_processor.getDevicePreferredSamplerates(); - - srMenu.addItem("Automatic (Match with host)", true, current == 0.0f, [this] { m_processor.setPreferredDeviceSamplerate(0.0f); }); - srMenu.addSeparator(); - srMenu.addSectionHeader("Official, used automatically"); - - auto addSRs = [&](bool _usePreferred) - { - for (const float samplerate : samplerates) - { - const auto isPreferred = std::find(preferred.begin(), preferred.end(), samplerate) != preferred.end(); - - if(isPreferred != _usePreferred) - continue; - - const auto title = std::to_string(static_cast<int>(std::floor(samplerate + 0.5f))) + " Hz"; - - srMenu.addItem(title, _enabled, std::fabs(samplerate - current) < 1.0f, [this, samplerate] { m_processor.setPreferredDeviceSamplerate(samplerate); }); - } - }; - - addSRs(true); - srMenu.addSeparator(); - srMenu.addSectionHeader("Undocumented, use with care"); - addSRs(false); - - _menu.addSubMenu("Device Samplerate", srMenu); - } - - return true; -} diff --git a/source/virusJucePlugin/PluginEditorState.h b/source/virusJucePlugin/PluginEditorState.h @@ -1,16 +0,0 @@ -#pragma once - -#include "../jucePluginEditorLib/pluginEditorState.h" - -class AudioPluginAudioProcessor; - -class PluginEditorState : public jucePluginEditorLib::PluginEditorState -{ -public: - explicit PluginEditorState(AudioPluginAudioProcessor& _processor, pluginLib::Controller& _controller, const std::vector<PluginEditorState::Skin>& _includedSkins); - - genericUI::Editor* createEditor(const Skin& _skin, std::function<void()> _openMenuCallback) override; - - void initContextMenu(juce::PopupMenu& _menu) override; - bool initAdvancedContextMenu(juce::PopupMenu& _menu, bool _enabled) override; -}; diff --git a/source/virusJucePlugin/PluginProcessor.cpp b/source/virusJucePlugin/PluginProcessor.cpp @@ -1,121 +0,0 @@ -#include "PluginProcessor.h" -#include "PluginEditorState.h" -#include "ParameterNames.h" - -#include "../virusLib/romloader.h" - -#include "../synthLib/deviceException.h" -#include "../synthLib/binarystream.h" -#include "../synthLib/os.h" - -//============================================================================== -AudioPluginAudioProcessor::AudioPluginAudioProcessor(const BusesProperties& _busesProperties, const juce::PropertiesFile::Options& _configOptions, const pluginLib::Processor::Properties& _properties, const std::vector<virusLib::ROMFile>& _roms) - : jucePluginEditorLib::Processor(_busesProperties, _configOptions, _properties) - , m_roms(_roms) -{ - evRomChanged.retain(getSelectedRom()); - - m_clockTempoParam = getController().getParameterIndexByName(Virus::g_paramClockTempo); - - const auto latencyBlocks = getConfig().getIntValue("latencyBlocks", static_cast<int>(getPlugin().getLatencyBlocks())); - Processor::setLatencyBlocks(latencyBlocks); -} - -AudioPluginAudioProcessor::~AudioPluginAudioProcessor() -{ - destroyEditorState(); -} - -//============================================================================== - -void AudioPluginAudioProcessor::processBpm(const float _bpm) -{ - // clamp to virus range, 63-190 - const auto bpmValue = juce::jmin(127, juce::jmax(0, static_cast<int>(_bpm)-63)); - const auto clockParam = getController().getParameter(m_clockTempoParam, 0); - - if (clockParam == nullptr || static_cast<int>(clockParam->getValueObject().getValue()) == bpmValue) - return; - - clockParam->getValueObject().setValue(bpmValue); -} - -bool AudioPluginAudioProcessor::setSelectedRom(const uint32_t _index) -{ - if(_index >= m_roms.size()) - return false; - if(_index == m_selectedRom) - return true; - m_selectedRom = _index; - - try - { - synthLib::Device* device = createDevice(); - getPlugin().setDevice(device); - (void)m_device.release(); - m_device.reset(device); - - evRomChanged.retain(getSelectedRom()); - - return true; - } - catch(const synthLib::DeviceException& e) - { - juce::NativeMessageBox::showMessageBox(juce::MessageBoxIconType::WarningIcon, - "Device creation failed:", - std::string("Failed to create device:\n\n") + - e.what() + "\n\n" - "Will continue using old ROM"); - return false; - } -} - -synthLib::Device* AudioPluginAudioProcessor::createDevice() -{ - const auto* rom = getSelectedRom(); - return new virusLib::Device(rom ? *rom : virusLib::ROMFile::invalid(), getPreferredDeviceSamplerate(), getHostSamplerate(), true); -} - -pluginLib::Controller* AudioPluginAudioProcessor::createController() -{ - // force creation of device as the controller decides how to initialize based on the used ROM - getPlugin(); - - return new Virus::Controller(*this); -} - -void AudioPluginAudioProcessor::saveChunkData(synthLib::BinaryStream& s) -{ - auto* rom = getSelectedRom(); - if(rom) - { - synthLib::ChunkWriter cw(s, "ROM ", 2); - const auto romName = synthLib::getFilenameWithoutPath(rom->getFilename()); - s.write<uint8_t>(static_cast<uint8_t>(rom->getModel())); - s.write(romName); - } - Processor::saveChunkData(s); -} - -void AudioPluginAudioProcessor::loadChunkData(synthLib::ChunkReader& _cr) -{ - _cr.add("ROM ", 2, [this](synthLib::BinaryStream& _binaryStream, unsigned _version) - { - auto model = virusLib::DeviceModel::ABC; - - if(_version > 1) - model = static_cast<virusLib::DeviceModel>(_binaryStream.read<uint8_t>()); - - const auto romName = _binaryStream.readString(); - - const auto& roms = getRoms(); - for(uint32_t i=0; i<static_cast<uint32_t>(roms.size()); ++i) - { - const auto& rom = roms[i]; - if(rom.getModel() == model && synthLib::getFilenameWithoutPath(rom.getFilename()) == romName) - setSelectedRom(i); - } - }); - - Processor::loadChunkData(_cr); -} diff --git a/source/virusJucePlugin/PluginProcessor.h b/source/virusJucePlugin/PluginProcessor.h @@ -1,77 +0,0 @@ -#pragma once - -#include "../synthLib/plugin.h" -#include "../virusLib/device.h" - -#include "../jucePluginLib/event.h" - -#include "VirusController.h" - -#include "../jucePluginEditorLib/pluginProcessor.h" - -//============================================================================== -class AudioPluginAudioProcessor : public jucePluginEditorLib::Processor -{ -public: - AudioPluginAudioProcessor(const BusesProperties& _busesProperties, const juce::PropertiesFile::Options& _configOptions, const pluginLib::Processor::Properties& _properties, const std::vector<virusLib::ROMFile>& _roms); - ~AudioPluginAudioProcessor() override; - - void processBpm(float _bpm) override; - - // _____________ - // - - std::string getRomName() const - { - const auto* rom = getSelectedRom(); - if(!rom) - return "<invalid>"; - return juce::File(juce::String(rom->getFilename())).getFileNameWithoutExtension().toStdString(); - } - - const virusLib::ROMFile* getSelectedRom() const - { - if(m_selectedRom >= m_roms.size()) - return {}; - return &m_roms[m_selectedRom]; - } - - virusLib::DeviceModel getModel() const - { - auto* rom = getSelectedRom(); - return rom ? rom->getModel() : virusLib::DeviceModel::Invalid; - } - - const auto& getRoms() const { return m_roms; } - - bool setSelectedRom(uint32_t _index); - uint32_t getSelectedRomIndex() const { return m_selectedRom; } - - uint32_t getPartCount() const - { - return getModel() == virusLib::DeviceModel::Snow ? 4 : 16; - } - - virtual const char* findEmbeddedResource(const char* _name, uint32_t& _size) const = 0; - - // _____________ - // -private: - synthLib::Device* createDevice() override; - - pluginLib::Controller* createController() override; - - void saveChunkData(synthLib::BinaryStream& s) override; - void loadChunkData(synthLib::ChunkReader& _cr) override; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioPluginAudioProcessor) - - std::vector<virusLib::ROMFile> m_roms; - uint32_t m_selectedRom = 0; - - uint32_t m_clockTempoParam = 0xffffffff; - -public: - pluginLib::Event<const virusLib::ROMFile*> evRomChanged; -}; diff --git a/source/virusJucePlugin/VirusController.cpp b/source/virusJucePlugin/VirusController.cpp @@ -3,7 +3,7 @@ #include <fstream> #include "ParameterNames.h" -#include "PluginProcessor.h" +#include "VirusProcessor.h" #include "../virusLib/microcontrollerTypes.h" #include "../synthLib/os.h" @@ -37,7 +37,7 @@ namespace Virus return g_midiPacketNames[static_cast<uint32_t>(_type)]; } - Controller::Controller(AudioPluginAudioProcessor &p, unsigned char deviceId) : pluginLib::Controller(p, loadParameterDescriptions(p)), m_processor(p), m_deviceId(deviceId) + Controller::Controller(VirusProcessor &p, unsigned char deviceId) : pluginLib::Controller(p, loadParameterDescriptions(p)), m_processor(p), m_deviceId(deviceId) { switch(p.getModel()) { @@ -392,7 +392,7 @@ namespace Virus return parseMidiPacket(*m, _data, _parameterValues, _msg); } - std::string Controller::loadParameterDescriptions(const AudioPluginAudioProcessor& _processor) + std::string Controller::loadParameterDescriptions(const VirusProcessor& _processor) { const auto model = _processor.getModel(); const auto name = model == virusLib::DeviceModel::Invalid || isTIFamily(model) ? "parameterDescriptions_TI.json" : "parameterDescriptions_C.json"; diff --git a/source/virusJucePlugin/VirusController.h b/source/virusJucePlugin/VirusController.h @@ -8,7 +8,7 @@ #include "../synthLib/plugin.h" -class AudioPluginAudioProcessor; +class VirusProcessor; namespace Virus { @@ -65,7 +65,7 @@ namespace Virus PresetSource source = PresetSource::Unknown; }; - Controller(AudioPluginAudioProcessor &, unsigned char deviceId = 0x00); + Controller(VirusProcessor &, unsigned char deviceId = 0x00); ~Controller() override; std::vector<uint8_t> createSingleDump(uint8_t _part, uint8_t _bank, uint8_t _program); @@ -154,7 +154,7 @@ namespace Virus bool parseSingle(pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _parameterValues, const pluginLib::SysEx& _msg, MidiPacketType& usedPacketType) const; private: - static std::string loadParameterDescriptions(const AudioPluginAudioProcessor& _processor); + static std::string loadParameterDescriptions(const VirusProcessor& _processor); void timerCallback() override; @@ -171,7 +171,7 @@ namespace Virus void parseParamChange(const pluginLib::MidiPacket::Data& _data); void parseControllerDump(const synthLib::SMidiEvent&); - AudioPluginAudioProcessor& m_processor; + VirusProcessor& m_processor; unsigned char m_deviceId; virusLib::BankNumber m_currentBank[16]{}; uint8_t m_currentProgram[16]{}; diff --git a/source/virusJucePlugin/VirusEditor.cpp b/source/virusJucePlugin/VirusEditor.cpp @@ -4,7 +4,7 @@ #include "PartButton.h" #include "ParameterNames.h" -#include "PluginProcessor.h" +#include "VirusProcessor.h" #include "VirusController.h" #include "../jucePluginLib/parameterbinding.h" @@ -16,7 +16,7 @@ namespace genericVirusUI { - VirusEditor::VirusEditor(pluginLib::ParameterBinding& _binding, AudioPluginAudioProcessor& _processorRef, const std::string& _jsonFilename, std::string _skinFolder, std::function<void()> _openMenuCallback) : + VirusEditor::VirusEditor(pluginLib::ParameterBinding& _binding, VirusProcessor& _processorRef, const std::string& _jsonFilename, std::string _skinFolder, std::function<void()> _openMenuCallback) : Editor(_processorRef, _binding, std::move(_skinFolder)), m_processor(_processorRef), m_parameterBinding(_binding), diff --git a/source/virusJucePlugin/VirusEditor.h b/source/virusJucePlugin/VirusEditor.h @@ -29,7 +29,7 @@ namespace pluginLib class ParameterBinding; } -class AudioPluginAudioProcessor; +class VirusProcessor; namespace genericVirusUI { @@ -43,7 +43,7 @@ namespace genericVirusUI Arrangement }; - VirusEditor(pluginLib::ParameterBinding& _binding, AudioPluginAudioProcessor& _processorRef, const std::string& _jsonFilename, + VirusEditor(pluginLib::ParameterBinding& _binding, VirusProcessor& _processorRef, const std::string& _jsonFilename, std::string _skinFolder, std::function<void()> _openMenuCallback); ~VirusEditor() override; @@ -81,7 +81,7 @@ namespace genericVirusUI void savePresets(SaveType _saveType, jucePluginEditorLib::FileType _fileType, uint8_t _bankNumber = 0); bool savePresets(const std::string& _pathName, SaveType _saveType, jucePluginEditorLib::FileType _fileType, uint8_t _bankNumber = 0) const; - AudioPluginAudioProcessor& m_processor; + VirusProcessor& m_processor; pluginLib::ParameterBinding& m_parameterBinding; std::unique_ptr<Parts> m_parts; diff --git a/source/virusJucePlugin/VirusEditorState.cpp b/source/virusJucePlugin/VirusEditorState.cpp @@ -0,0 +1,106 @@ +#include "VirusEditorState.h" + +#include "VirusProcessor.h" + +#include "VirusEditor.h" + +#include "../synthLib/os.h" + +VirusEditorState::VirusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller, const std::vector<VirusEditorState::Skin>& _includedSkins) + : jucePluginEditorLib::PluginEditorState(_processor, _controller, _includedSkins) +{ + loadDefaultSkin(); +} + +genericUI::Editor* VirusEditorState::createEditor(const Skin& _skin, std::function<void()> _openMenuCallback) +{ + return new genericVirusUI::VirusEditor(m_parameterBinding, static_cast<VirusProcessor&>(m_processor), _skin.jsonFilename, _skin.folder, _openMenuCallback); +} + +void VirusEditorState::initContextMenu(juce::PopupMenu& _menu) +{ + jucePluginEditorLib::PluginEditorState::initContextMenu(_menu); + auto& p = m_processor; + + { + juce::PopupMenu gainMenu; + + const auto gain = m_processor.getOutputGain(); + + gainMenu.addItem("-12 db", true, gain == 0.25f, [&p] { p.setOutputGain(0.25f); }); + gainMenu.addItem("-6 db", true, gain == 0.5f, [&p] { p.setOutputGain(0.5f); }); + gainMenu.addItem("0 db (default)", true, gain == 1, [&p] { p.setOutputGain(1); }); + gainMenu.addItem("+6 db", true, gain == 2, [&p] { p.setOutputGain(2); }); + gainMenu.addItem("+12 db", true, gain == 4, [&p] { p.setOutputGain(4); }); + + _menu.addSubMenu("Output Gain", gainMenu); + } +} + +bool VirusEditorState::initAdvancedContextMenu(juce::PopupMenu& _menu, bool _enabled) +{ + jucePluginEditorLib::PluginEditorState::initAdvancedContextMenu(_menu, _enabled); + + const auto percent = m_processor.getDspClockPercent(); + const auto hz = m_processor.getDspClockHz(); + + juce::PopupMenu clockMenu; + + auto makeEntry = [&](const int _percent) + { + const auto mhz = hz * _percent / 100 / 1000000; + std::stringstream ss; + ss << _percent << "% (" << mhz << " MHz)"; + if(_percent == 100) + ss << " (Default)"; + clockMenu.addItem(ss.str(), _enabled, percent == _percent, [this, _percent] { m_processor.setDspClockPercent(_percent); }); + }; + + makeEntry(50); + makeEntry(75); + makeEntry(100); + makeEntry(125); + makeEntry(150); + makeEntry(200); + + _menu.addSubMenu("DSP Clock", clockMenu); + + const auto samplerates = m_processor.getDeviceSupportedSamplerates(); + + if(samplerates.size() > 1) + { + juce::PopupMenu srMenu; + + const auto current = m_processor.getPreferredDeviceSamplerate(); + + const auto preferred = m_processor.getDevicePreferredSamplerates(); + + srMenu.addItem("Automatic (Match with host)", true, current == 0.0f, [this] { m_processor.setPreferredDeviceSamplerate(0.0f); }); + srMenu.addSeparator(); + srMenu.addSectionHeader("Official, used automatically"); + + auto addSRs = [&](bool _usePreferred) + { + for (const float samplerate : samplerates) + { + const auto isPreferred = std::find(preferred.begin(), preferred.end(), samplerate) != preferred.end(); + + if(isPreferred != _usePreferred) + continue; + + const auto title = std::to_string(static_cast<int>(std::floor(samplerate + 0.5f))) + " Hz"; + + srMenu.addItem(title, _enabled, std::fabs(samplerate - current) < 1.0f, [this, samplerate] { m_processor.setPreferredDeviceSamplerate(samplerate); }); + } + }; + + addSRs(true); + srMenu.addSeparator(); + srMenu.addSectionHeader("Undocumented, use with care"); + addSRs(false); + + _menu.addSubMenu("Device Samplerate", srMenu); + } + + return true; +} diff --git a/source/virusJucePlugin/VirusEditorState.h b/source/virusJucePlugin/VirusEditorState.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../jucePluginEditorLib/pluginEditorState.h" + +class VirusProcessor; + +class VirusEditorState : public jucePluginEditorLib::PluginEditorState +{ +public: + explicit VirusEditorState(VirusProcessor& _processor, pluginLib::Controller& _controller, const std::vector<VirusEditorState::Skin>& _includedSkins); + + genericUI::Editor* createEditor(const Skin& _skin, std::function<void()> _openMenuCallback) override; + + void initContextMenu(juce::PopupMenu& _menu) override; + bool initAdvancedContextMenu(juce::PopupMenu& _menu, bool _enabled) override; +}; diff --git a/source/virusJucePlugin/VirusProcessor.cpp b/source/virusJucePlugin/VirusProcessor.cpp @@ -0,0 +1,121 @@ +#include "VirusProcessor.h" +#include "VirusEditorState.h" +#include "ParameterNames.h" + +#include "../virusLib/romloader.h" + +#include "../synthLib/deviceException.h" +#include "../synthLib/binarystream.h" +#include "../synthLib/os.h" + +//============================================================================== +VirusProcessor::VirusProcessor(const BusesProperties& _busesProperties, const juce::PropertiesFile::Options& _configOptions, const pluginLib::Processor::Properties& _properties, const std::vector<virusLib::ROMFile>& _roms) + : jucePluginEditorLib::Processor(_busesProperties, _configOptions, _properties) + , m_roms(_roms) +{ + evRomChanged.retain(getSelectedRom()); + + m_clockTempoParam = getController().getParameterIndexByName(Virus::g_paramClockTempo); + + const auto latencyBlocks = getConfig().getIntValue("latencyBlocks", static_cast<int>(getPlugin().getLatencyBlocks())); + Processor::setLatencyBlocks(latencyBlocks); +} + +VirusProcessor::~VirusProcessor() +{ + destroyEditorState(); +} + +//============================================================================== + +void VirusProcessor::processBpm(const float _bpm) +{ + // clamp to virus range, 63-190 + const auto bpmValue = juce::jmin(127, juce::jmax(0, static_cast<int>(_bpm)-63)); + const auto clockParam = getController().getParameter(m_clockTempoParam, 0); + + if (clockParam == nullptr || static_cast<int>(clockParam->getValueObject().getValue()) == bpmValue) + return; + + clockParam->getValueObject().setValue(bpmValue); +} + +bool VirusProcessor::setSelectedRom(const uint32_t _index) +{ + if(_index >= m_roms.size()) + return false; + if(_index == m_selectedRom) + return true; + m_selectedRom = _index; + + try + { + synthLib::Device* device = createDevice(); + getPlugin().setDevice(device); + (void)m_device.release(); + m_device.reset(device); + + evRomChanged.retain(getSelectedRom()); + + return true; + } + catch(const synthLib::DeviceException& e) + { + juce::NativeMessageBox::showMessageBox(juce::MessageBoxIconType::WarningIcon, + "Device creation failed:", + std::string("Failed to create device:\n\n") + + e.what() + "\n\n" + "Will continue using old ROM"); + return false; + } +} + +synthLib::Device* VirusProcessor::createDevice() +{ + const auto* rom = getSelectedRom(); + return new virusLib::Device(rom ? *rom : virusLib::ROMFile::invalid(), getPreferredDeviceSamplerate(), getHostSamplerate(), true); +} + +pluginLib::Controller* VirusProcessor::createController() +{ + // force creation of device as the controller decides how to initialize based on the used ROM + getPlugin(); + + return new Virus::Controller(*this); +} + +void VirusProcessor::saveChunkData(synthLib::BinaryStream& s) +{ + auto* rom = getSelectedRom(); + if(rom) + { + synthLib::ChunkWriter cw(s, "ROM ", 2); + const auto romName = synthLib::getFilenameWithoutPath(rom->getFilename()); + s.write<uint8_t>(static_cast<uint8_t>(rom->getModel())); + s.write(romName); + } + Processor::saveChunkData(s); +} + +void VirusProcessor::loadChunkData(synthLib::ChunkReader& _cr) +{ + _cr.add("ROM ", 2, [this](synthLib::BinaryStream& _binaryStream, unsigned _version) + { + auto model = virusLib::DeviceModel::ABC; + + if(_version > 1) + model = static_cast<virusLib::DeviceModel>(_binaryStream.read<uint8_t>()); + + const auto romName = _binaryStream.readString(); + + const auto& roms = getRoms(); + for(uint32_t i=0; i<static_cast<uint32_t>(roms.size()); ++i) + { + const auto& rom = roms[i]; + if(rom.getModel() == model && synthLib::getFilenameWithoutPath(rom.getFilename()) == romName) + setSelectedRom(i); + } + }); + + Processor::loadChunkData(_cr); +} diff --git a/source/virusJucePlugin/VirusProcessor.h b/source/virusJucePlugin/VirusProcessor.h @@ -0,0 +1,77 @@ +#pragma once + +#include "../synthLib/plugin.h" +#include "../virusLib/device.h" + +#include "../jucePluginLib/event.h" + +#include "VirusController.h" + +#include "../jucePluginEditorLib/pluginProcessor.h" + +//============================================================================== +class VirusProcessor : public jucePluginEditorLib::Processor +{ +public: + VirusProcessor(const BusesProperties& _busesProperties, const juce::PropertiesFile::Options& _configOptions, const pluginLib::Processor::Properties& _properties, const std::vector<virusLib::ROMFile>& _roms); + ~VirusProcessor() override; + + void processBpm(float _bpm) override; + + // _____________ + // + + std::string getRomName() const + { + const auto* rom = getSelectedRom(); + if(!rom) + return "<invalid>"; + return juce::File(juce::String(rom->getFilename())).getFileNameWithoutExtension().toStdString(); + } + + const virusLib::ROMFile* getSelectedRom() const + { + if(m_selectedRom >= m_roms.size()) + return {}; + return &m_roms[m_selectedRom]; + } + + virusLib::DeviceModel getModel() const + { + auto* rom = getSelectedRom(); + return rom ? rom->getModel() : virusLib::DeviceModel::Invalid; + } + + const auto& getRoms() const { return m_roms; } + + bool setSelectedRom(uint32_t _index); + uint32_t getSelectedRomIndex() const { return m_selectedRom; } + + uint32_t getPartCount() const + { + return getModel() == virusLib::DeviceModel::Snow ? 4 : 16; + } + + virtual const char* findEmbeddedResource(const char* _name, uint32_t& _size) const = 0; + + // _____________ + // +private: + synthLib::Device* createDevice() override; + + pluginLib::Controller* createController() override; + + void saveChunkData(synthLib::BinaryStream& s) override; + void loadChunkData(synthLib::ChunkReader& _cr) override; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VirusProcessor) + + std::vector<virusLib::ROMFile> m_roms; + uint32_t m_selectedRom = 0; + + uint32_t m_clockTempoParam = 0xffffffff; + +public: + pluginLib::Event<const virusLib::ROMFile*> evRomChanged; +};