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

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 }