VirusProcessor.cpp (7059B)
1 #include "VirusProcessor.h" 2 #include "VirusEditorState.h" 3 #include "ParameterNames.h" 4 #include "VirusController.h" 5 6 #include "baseLib/binarystream.h" 7 #include "baseLib/filesystem.h" 8 9 #include "juceUiLib/messageBox.h" 10 11 #include "synthLib/deviceException.h" 12 #include "synthLib/lv2PresetExport.h" 13 14 namespace virus 15 { 16 VirusProcessor::VirusProcessor(const BusesProperties& _busesProperties, const juce::PropertiesFile::Options& _configOptions, const pluginLib::Processor::Properties& _properties, const virusLib::DeviceModel _defaultModel) 17 : Processor(_busesProperties, _configOptions, _properties) 18 , m_defaultModel(_defaultModel) 19 { 20 } 21 22 VirusProcessor::~VirusProcessor() 23 { 24 destroyController(); 25 destroyEditorState(); 26 } 27 28 //============================================================================== 29 30 void VirusProcessor::processBpm(const float _bpm) 31 { 32 // clamp to virus range, 63-190 33 const auto bpmValue = juce::jmin(127, juce::jmax(0, static_cast<int>(_bpm)-63)); 34 const auto clockParam = getController().getParameter(m_clockTempoParam, 0); 35 36 if (clockParam == nullptr || clockParam->getUnnormalizedValue() == bpmValue) 37 return; 38 39 clockParam->setUnnormalizedValue(bpmValue, pluginLib::Parameter::Origin::HostAutomation); 40 } 41 42 bool VirusProcessor::setSelectedRom(const uint32_t _index) 43 { 44 if(_index >= m_roms.size()) 45 return false; 46 if(_index == m_selectedRom) 47 return true; 48 m_selectedRom = _index; 49 50 try 51 { 52 synthLib::Device* device = pluginLib::Processor::createDevice(getDeviceType()); 53 getPlugin().setDevice(device); 54 (void)m_device.release(); 55 m_device.reset(device); 56 57 evRomChanged.retain(getSelectedRom()); 58 59 zynthianExportLv2Presets(); 60 61 return true; 62 } 63 catch(const synthLib::DeviceException& e) 64 { 65 genericUI::MessageBox::showOk(juce::MessageBoxIconType::WarningIcon, 66 "Device creation failed:", 67 std::string("Failed to create device:\n\n") + 68 e.what() + "\n\n" 69 "Will continue using old ROM"); 70 return false; 71 } 72 } 73 74 void VirusProcessor::postConstruct(std::vector<virusLib::ROMFile>&& _roms) 75 { 76 m_roms = std::move(_roms); 77 78 evRomChanged.retain(getSelectedRom()); 79 80 m_clockTempoParam = getController().getParameterIndexByName(virus::g_paramClockTempo); 81 82 const auto latencyBlocks = getConfig().getIntValue("latencyBlocks", static_cast<int>(getPlugin().getLatencyBlocks())); 83 Processor::setLatencyBlocks(latencyBlocks); 84 85 zynthianExportLv2Presets(); 86 } 87 88 synthLib::Device* VirusProcessor::createDevice() 89 { 90 synthLib::DeviceCreateParams p; 91 getRemoteDeviceParams(p); 92 return new virusLib::Device(p, true); 93 } 94 95 void VirusProcessor::getRemoteDeviceParams(synthLib::DeviceCreateParams& _params) const 96 { 97 pluginLib::Processor::getRemoteDeviceParams(_params); 98 99 const auto* rom = getSelectedRom(); 100 101 if(!rom || !rom->isValid()) 102 { 103 if(isTIFamily(m_defaultModel)) 104 throw synthLib::DeviceException(synthLib::DeviceError::FirmwareMissing, "A Virus TI firmware (.bin) is required, but was not found."); 105 throw synthLib::DeviceException(synthLib::DeviceError::FirmwareMissing, "A Virus A/B/C operating system (.bin or .mid) is required, but was not found."); 106 } 107 108 _params.romName = rom->getFilename(); 109 _params.romData = rom->getRomFileData(); 110 _params.customData = static_cast<uint32_t>(rom->getModel()); 111 } 112 113 pluginLib::Controller* VirusProcessor::createController() 114 { 115 // force creation of device as the controller decides how to initialize based on the used ROM 116 getPlugin(); 117 118 return new virus::Controller(*this, m_defaultModel); 119 } 120 121 void VirusProcessor::saveChunkData(baseLib::BinaryStream& s) 122 { 123 auto* rom = getSelectedRom(); 124 if(rom) 125 { 126 baseLib::ChunkWriter cw(s, "ROM ", 2); 127 const auto romName = baseLib::filesystem::getFilenameWithoutPath(rom->getFilename()); 128 s.write<uint8_t>(static_cast<uint8_t>(rom->getModel())); 129 s.write(romName); 130 } 131 Processor::saveChunkData(s); 132 } 133 134 void VirusProcessor::loadChunkData(baseLib::ChunkReader& _cr) 135 { 136 _cr.add("ROM ", 2, [this](baseLib::BinaryStream& _binaryStream, unsigned _version) 137 { 138 auto model = virusLib::DeviceModel::ABC; 139 140 if(_version > 1) 141 model = static_cast<virusLib::DeviceModel>(_binaryStream.read<uint8_t>()); 142 143 const auto romName = _binaryStream.readString(); 144 145 const auto& roms = getRoms(); 146 for(uint32_t i=0; i<static_cast<uint32_t>(roms.size()); ++i) 147 { 148 const auto& rom = roms[i]; 149 if(rom.getModel() == model && baseLib::filesystem::getFilenameWithoutPath(rom.getFilename()) == romName) 150 setSelectedRom(i); 151 } 152 }); 153 154 Processor::loadChunkData(_cr); 155 } 156 157 void VirusProcessor::zynthianExportLv2Presets() const 158 { 159 const auto* rom = getSelectedRom(); 160 if(!rom) 161 return; 162 163 #ifdef ZYNTHIAN 164 constexpr const char* const rootPath = "/zynthian/zynthian-my-data/presets/lv2"; 165 exportLv2Presets(*rom, rootPath); 166 #elif defined(_WIN32) && defined(_DEBUG) 167 // const auto rootPath = synthLib::getModulePath(); 168 // exportLv2Presets(*rom, rootPath); 169 #endif 170 } 171 172 void VirusProcessor::exportLv2Presets(const virusLib::ROMFile& _rom, const std::string& _rootPath) const 173 { 174 const auto bankCount = virusLib::ROMFile::getRomBankCount(_rom.getModel()); 175 176 for(uint32_t b=0; b<bankCount; ++b) 177 { 178 synthLib::Lv2PresetExport::Bank bank; 179 180 switch (_rom.getModel()) 181 { 182 case virusLib::DeviceModel::A: 183 case virusLib::DeviceModel::B: 184 case virusLib::DeviceModel::C: bank.name = std::string("Rom " ) + static_cast<char>('C' + b); break; 185 case virusLib::DeviceModel::Snow: bank.name = std::string("Snow Rom ") + static_cast<char>('A' + b); break; 186 case virusLib::DeviceModel::TI: bank.name = std::string("TI Rom " ) + static_cast<char>('A' + b); break; 187 case virusLib::DeviceModel::TI2: bank.name = std::string("TI2 Rom " ) + static_cast<char>('A' + b); break; 188 case virusLib::DeviceModel::Invalid: bank.name = std::string("Unknown " ) + static_cast<char>('A' + b); assert(false); break; 189 } 190 191 const auto path = baseLib::filesystem::validatePath(_rootPath) + getProperties().name + '_' + synthLib::Lv2PresetExport::getBankFilename(bank.name) + ".lv2/"; 192 193 if(synthLib::Lv2PresetExport::manifestFileExists(path)) 194 continue; 195 196 for(uint8_t p=0; p<_rom.getPresetsPerBank(); ++p) 197 { 198 virusLib::ROMFile::TPreset preset; 199 200 if(!_rom.getSingle(static_cast<uint8_t>(b), p, preset)) 201 continue; 202 203 synthLib::Lv2PresetExport::Preset lv2Preset; 204 205 lv2Preset.data = {0xf0, 0x00, 0x20, 0x33, 01, virusLib::OMNI_DEVICE_ID, virusLib::DUMP_SINGLE, virusLib::toMidiByte(virusLib::BankNumber::EditBuffer), virusLib::SINGLE}; 206 lv2Preset.data.insert(lv2Preset.data.end(), preset.begin(), preset.begin() + virusLib::ROMFile::getSinglePresetSize(_rom.getModel())); 207 lv2Preset.data.push_back(virusLib::Microcontroller::calcChecksum(lv2Preset.data)); 208 lv2Preset.data.push_back(0xf7); 209 210 lv2Preset.name = virusLib::ROMFile::getSingleName(preset); 211 212 bank.presets.push_back(lv2Preset); 213 } 214 215 if(bank.presets.empty()) 216 continue; 217 218 synthLib::Lv2PresetExport::exportPresets(path, getProperties().lv2Uri, bank); 219 } 220 } 221 }