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

weData.cpp (11789B)


      1 #include "weData.h"
      2 
      3 #include "xtController.h"
      4 
      5 #include "baseLib/filesystem.h"
      6 
      7 #include "synthLib/midiToSysex.h"
      8 
      9 #include "xtLib/xtState.h"
     10 
     11 namespace xtJucePlugin
     12 {
     13 	WaveEditorData::WaveEditorData(Controller& _controller, const std::string& _cacheDir) : m_controller(_controller), m_cacheDir(baseLib::filesystem::validatePath(_cacheDir))
     14 	{
     15 		loadRomCache();
     16 		loadUserData();
     17 	}
     18 
     19 	void WaveEditorData::requestData()
     20 	{
     21 		if(isWaitingForData())
     22 			return;
     23 
     24 		for(uint16_t i=0; i<static_cast<uint16_t>(m_tables.size()); ++i)
     25 		{
     26 			const auto id = xt::TableId(i);
     27 			if(!m_tables[i] && !xt::wave::isAlgorithmicTable(id))
     28 			{
     29 				requestTable(id);
     30 				return;
     31 			}
     32 		}
     33 
     34 		for(uint16_t i=0; i<static_cast<uint16_t>(m_romWaves.size()); ++i)
     35 		{
     36 			const auto id = xt::WaveId(i);
     37 			if(!m_romWaves[i])
     38 			{
     39 				requestWave(id);
     40 				return;
     41 			}
     42 		}
     43 
     44 		for(uint32_t i=0; i<m_ramWaves.size(); ++i)
     45 		{
     46 			if(!m_ramWaves[i])
     47 			{
     48 				requestWave(xt::WaveId(static_cast<uint16_t>(i + xt::wave::g_firstRamWaveIndex)));
     49 				return;
     50 			}
     51 		}
     52 
     53 		onAllDataReceived();
     54 	}
     55 
     56 	void WaveEditorData::onReceiveWave(const std::vector<uint8_t>& _msg, const bool _sendToDevice)
     57 	{
     58 		if(!parseMidi(_msg))
     59 			return;
     60 
     61 		const auto command = toCommand(_msg);
     62 		const auto id = xt::WaveId(toIndex(_msg));
     63 		
     64 		if(command == xt::SysexCommand::WaveDump &&  m_currentWaveRequestIndex == id)
     65 		{
     66 			m_currentWaveRequestIndex = g_invalidWaveIndex;
     67 			requestData();
     68 		}
     69 
     70 		if(_sendToDevice)
     71 			sendWaveToDevice(id);
     72 	}
     73 
     74 	void WaveEditorData::onReceiveTable(const std::vector<uint8_t>& _msg, const bool _sendToDevice)
     75 	{
     76 		if(!parseMidi(_msg))
     77 			return;
     78 
     79 		const auto command = toCommand(_msg);
     80 		const auto id = xt::TableId(toIndex(_msg));
     81 
     82 		if(command == xt::SysexCommand::WaveCtlDump && m_currentTableRequestIndex == id)
     83 		{
     84 			m_currentTableRequestIndex = g_invalidTableIndex;
     85 			requestData();
     86 		}
     87 
     88 		if(_sendToDevice)
     89 			sendTableToDevice(id);
     90 	}
     91 
     92 	std::optional<xt::WaveData> WaveEditorData::getWave(const xt::WaveId _waveId) const
     93 	{
     94 		auto i = _waveId.rawId();
     95 
     96 		if(i < m_romWaves.size())
     97 			return m_romWaves[i];
     98 
     99 		if(i < xt::wave::g_firstRamWaveIndex)
    100 			return {};
    101 		i -= xt::wave::g_firstRamWaveIndex;
    102 		if(i >= m_ramWaves.size())
    103 			return {};
    104 
    105 		return m_ramWaves[i];
    106 	}
    107 
    108 	xt::WaveId WaveEditorData::getWaveId(const xt::TableId _tableId, const xt::TableIndex _tableIndex) const
    109 	{
    110 		if(_tableId.rawId() >= m_tables.size())
    111 			return g_invalidWaveIndex;
    112 		if(_tableIndex.rawId() >= std::tuple_size<xt::TableData>())
    113 			return g_invalidWaveIndex;
    114 		const auto table = m_tables[_tableId.rawId()];
    115 		if(!table)
    116 			return g_invalidWaveIndex;
    117 		return (*table)[_tableIndex.rawId()];
    118 	}
    119 
    120 	std::optional<xt::TableData> WaveEditorData::getTable(const xt::TableId _tableId) const
    121 	{
    122 		if(_tableId.rawId() >= m_tables.size())
    123 			return {};
    124 		return m_tables[_tableId.rawId()];
    125 	}
    126 
    127 	bool WaveEditorData::swapTableEntries(const xt::TableId _tableId, const xt::TableIndex _indexA, const xt::TableIndex _indexB)
    128 	{
    129 		if(_indexA == _indexB)
    130 			return false;
    131 		if(_tableId.rawId() >= m_tables.size())
    132 			return false;
    133 		const auto& table = m_tables[_tableId.rawId()];
    134 		if(!table)
    135 			return false;
    136 		auto t = *table;
    137 		std::swap(t[_indexA.rawId()], t[_indexB.rawId()]);
    138 		m_tables[_tableId.rawId()] = t;
    139 		onTableChanged(_tableId);
    140 		saveTable(_tableId);
    141 		return true;
    142 	}
    143 
    144 	bool WaveEditorData::setTableWave(const xt::TableId _tableId, const xt::TableIndex _tableIndex, const xt::WaveId _waveId)
    145 	{
    146 		if(_tableId.rawId() >= m_tables.size())
    147 			return false;
    148 		const auto& table = m_tables[_tableId.rawId()];
    149 		if(!table)
    150 			return false;
    151 		auto t = *table;
    152 		if(_tableIndex.rawId() >= t.size())
    153 			return false;
    154 		if(t[_tableIndex.rawId()] == _waveId)
    155 			return false;
    156 		t[_tableIndex.rawId()] = _waveId;
    157 		m_tables[_tableId.rawId()] = t;
    158 		onTableChanged(_tableId);
    159 		saveTable(_tableId);
    160 		return true;
    161 	}
    162 
    163 	bool WaveEditorData::copyTable(const xt::TableId _dest, const xt::TableId _source)
    164 	{
    165 		const auto dst = _dest.rawId();
    166 		const auto src = _source.rawId();
    167 
    168 		if(dst >= m_tables.size() || src >= m_tables.size())
    169 			return false;
    170 
    171 		auto& srcTable = m_tables[src];
    172 		if(!srcTable)
    173 			return false;
    174 		m_tables[dst] = *srcTable;
    175 		onTableChanged(_dest);
    176 		saveTable(_dest);
    177 		return true;
    178 	}
    179 
    180 	bool WaveEditorData::copyWave(const xt::WaveId _dest, const xt::WaveId _source)
    181 	{
    182 		const auto sourceWave = getWave(_source);
    183 		if(!sourceWave)
    184 			return false;
    185 		return setWave(_dest, *sourceWave);
    186 	}
    187 
    188 	std::optional<xt::WaveData> WaveEditorData::getWave(const xt::TableId _tableIndex, const xt::TableIndex _indexInTable) const
    189 	{
    190 		return getWave(getWaveId(_tableIndex, _indexInTable));
    191 	}
    192 
    193 	bool WaveEditorData::setWave(xt::WaveId _id, const xt::WaveData& _data)
    194 	{
    195 		auto i = _id.rawId();
    196 
    197 		if(i < m_romWaves.size())
    198 		{
    199 			m_romWaves[i] = _data;
    200 			onWaveChanged(_id);
    201 			return true;
    202 		}
    203 
    204 		if(i < xt::wave::g_firstRamWaveIndex)
    205 			return false;
    206 
    207 		i -= xt::wave::g_firstRamWaveIndex;
    208 
    209 		if(i >= m_ramWaves.size())
    210 			return false;
    211 
    212 		m_ramWaves[i] = _data;
    213 		onWaveChanged(_id);
    214 		saveWave(_id);
    215 		return true;
    216 	}
    217 
    218 	bool WaveEditorData::setTable(const xt::TableId _id, const xt::TableData& _data)
    219 	{
    220 		if(_id.rawId() >= m_tables.size())
    221 			return false;
    222 
    223 		m_tables[_id.rawId()] = _data;
    224 		onTableChanged(_id);
    225 		saveTable(_id);
    226 		return true;
    227 	}
    228 
    229 	bool WaveEditorData::sendTableToDevice(const xt::TableId _id) const
    230 	{
    231 		const auto index = _id.rawId();
    232 		if(index >= m_tables.size())
    233 			return false;
    234 		auto& table = m_tables[index];
    235 		if(!table)
    236 			return false;
    237 		auto& t = *table;
    238 		const auto sysex = xt::State::createTableData(t, index, false);
    239 		m_controller.sendSysEx(sysex);
    240 		return true;
    241 	}
    242 
    243 	bool WaveEditorData::sendWaveToDevice(const xt::WaveId _id) const
    244 	{
    245 		const auto wave = getWave(_id);
    246 		if(!wave)
    247 			return false;
    248 		const auto sysex = xt::State::createWaveData(*wave, _id.rawId(), false);
    249 		m_controller.sendSysEx(sysex);
    250 		return true;
    251 	}
    252 
    253 	void WaveEditorData::getWaveDataForSingle(std::vector<xt::SysEx>& _results, const xt::SysEx& _single) const
    254 	{
    255 		const auto tableId = xt::State::getWavetableFromSingleDump(_single);
    256 
    257 		if(xt::wave::isReadOnly(tableId))
    258 			return;
    259 
    260 		const auto table = getTable(tableId);
    261 
    262 		if(!table)
    263 			return;
    264 
    265 		auto& t = *table;
    266 
    267 		auto waves = xt::State::getWavesForTable(t);
    268 
    269 		for (const auto waveId : waves)
    270 		{
    271 			if(!xt::wave::isValidWaveIndex(waveId.rawId()))
    272 				continue;
    273 
    274 			if(xt::wave::isReadOnly(waveId))
    275 				continue;
    276 
    277 			const auto wave = getWave(waveId);
    278 			if(!wave)
    279 				continue;
    280 
    281 			const auto& w = *wave;
    282 
    283 			_results.emplace_back(xt::State::createWaveData(w, waveId.rawId(), false));
    284 		}
    285 
    286 		_results.emplace_back(xt::State::createTableData(t, tableId.rawId(), false));
    287 	}
    288 
    289 	bool WaveEditorData::requestWave(const xt::WaveId _id)
    290 	{
    291 		if(isWaitingForData())
    292 			return false;
    293 
    294 		if(!m_controller.requestWave(_id.rawId()))
    295 			return false;
    296 		m_currentWaveRequestIndex = _id;
    297 		return true;
    298 	}
    299 
    300 	bool WaveEditorData::requestTable(const xt::TableId _id)
    301 	{
    302 		if(isWaitingForData())
    303 			return false;
    304 
    305 		if(!m_controller.requestTable(_id.rawId()))
    306 			return false;
    307 		m_currentTableRequestIndex = _id;
    308 		return true;
    309 	}
    310 
    311 	void WaveEditorData::onAllDataReceived() const
    312 	{
    313 		saveRomCache();
    314 	}
    315 
    316 	xt::SysexCommand WaveEditorData::toCommand(const std::vector<uint8_t>& _sysex)
    317 	{
    318 		return static_cast<xt::SysexCommand>(_sysex[4]);
    319 	}
    320 
    321 	uint16_t WaveEditorData::toIndex(const std::vector<uint8_t>& _sysex)
    322 	{
    323 		const uint32_t hh = _sysex[5];
    324 		const uint32_t ll = _sysex[6];
    325 
    326 		const uint16_t index = static_cast<uint16_t>((hh << 7) | ll);
    327 
    328 		return index;
    329 	}
    330 
    331 	bool WaveEditorData::parseMidi(const std::vector<uint8_t>& _sysex)
    332 	{
    333 		if(_sysex.size() < 10 || _sysex.front() != 0xf0 || _sysex.back() != 0xf7)
    334 			return false;
    335 		if(_sysex[1] != wLib::IdWaldorf)
    336 			return false;
    337 		if(_sysex[2] != xt::IdMw2)
    338 			return false;
    339 
    340 		const auto cmd = toCommand(_sysex);
    341 		const auto index = toIndex(_sysex);
    342 
    343 		switch (cmd)  // NOLINT(clang-diagnostic-switch-enum)
    344 		{
    345 		case xt::SysexCommand::WaveDump:
    346 			{
    347 				if(!xt::wave::isValidWaveIndex(index))
    348 					return false;
    349 
    350 				const auto id = xt::WaveId(index);
    351 
    352 				xt::WaveData data;
    353 				xt::State::parseWaveData(data, _sysex);
    354 
    355 				setWave(id, data);
    356 			}
    357 			return true;
    358 		case xt::SysexCommand::WaveCtlDump:
    359 			{
    360 				if(!xt::wave::isValidTableIndex(index))
    361 					return false;
    362 
    363 				const auto id = xt::TableId(index);
    364 
    365 				xt::TableData table;
    366 
    367 				xt::State::parseTableData(table, _sysex);
    368 
    369 				setTable(id, table);
    370 			}
    371 			return true;
    372 		default:
    373 			return false;
    374 		}
    375 	}
    376 
    377 	std::string WaveEditorData::getRomCacheFilename() const
    378 	{
    379 		return m_cacheDir + "romWaves.syx";
    380 	}
    381 
    382 	void WaveEditorData::saveRomCache() const
    383 	{
    384 		const auto romWaves = getRomCacheFilename();
    385 
    386 		std::vector<uint8_t> data;
    387 
    388 		for(uint16_t i=0; i<static_cast<uint16_t>(m_romWaves.size()); ++i)
    389 		{
    390 			auto& romWave = m_romWaves[i];
    391 			assert(romWave);
    392 			if(!romWave)
    393 				continue;
    394 			auto sysex = xt::State::createWaveData(*romWave, i, false);
    395 			data.insert(data.end(), sysex.begin(), sysex.end());
    396 		}
    397 
    398 		assert(xt::wave::g_firstRamTableIndex < m_tables.size());
    399 
    400 		for(uint16_t i=0; i<xt::wave::g_firstRamTableIndex; ++i)
    401 		{
    402 			auto& table = m_tables[i];
    403 			assert(table || xt::wave::isAlgorithmicTable(xt::TableId(i)));
    404 			if(!table)
    405 				continue;
    406 			auto sysex = xt::State::createTableData(*table, i, false);
    407 			data.insert(data.end(), sysex.begin(), sysex.end());
    408 		}
    409 
    410 		baseLib::filesystem::createDirectory(m_cacheDir);
    411 		baseLib::filesystem::writeFile(romWaves, data);
    412 	}
    413 
    414 	void WaveEditorData::loadRomCache()
    415 	{
    416 		std::vector<uint8_t> data;
    417 		if(!baseLib::filesystem::readFile(data, getRomCacheFilename()))
    418 			return;
    419 
    420 		std::vector<std::vector<uint8_t>> sysexMessages;
    421 		synthLib::MidiToSysex::splitMultipleSysex(sysexMessages, data);
    422 		for (const auto& sysex : sysexMessages)
    423 			parseMidi(sysex);
    424 	}
    425 
    426 	void WaveEditorData::saveTable(const xt::TableId _id) const
    427 	{
    428 		if (xt::wave::isReadOnly(_id))
    429 			return;	// we don't want to store rom tables
    430 
    431 		const auto table = getTable(_id);
    432 		if (!table)
    433 			return;
    434 
    435 		const auto filename = toFilename(_id);
    436 		const auto data = xt::State::createTableData(*table, _id.rawId(), true);
    437 		baseLib::filesystem::writeFile(m_cacheDir + filename, data);
    438 	}
    439 
    440 	void WaveEditorData::saveWave(const xt::WaveId _id) const
    441 	{
    442 		if (xt::wave::isReadOnly(_id))
    443 			return;	// we don't want to store rom waves
    444 
    445 		const auto wave = getWave(_id);
    446 		if (!wave)
    447 			return;
    448 
    449 		const auto filename = toFilename(_id);
    450 		const auto data = xt::State::createWaveData(*wave, _id.rawId(), true);
    451 		baseLib::filesystem::writeFile(m_cacheDir + filename, data);
    452 	}
    453 
    454 	void WaveEditorData::loadUserData()
    455 	{
    456 		for (uint16_t i = 0; i < static_cast<uint16_t>(m_ramWaves.size()); ++i)
    457 		{
    458 			const auto id = xt::WaveId(i + xt::wave::g_firstRamWaveIndex);
    459 			const auto filename = toFilename(id);
    460 			std::vector<uint8_t> data;
    461 			if (!baseLib::filesystem::readFile(data, m_cacheDir + filename))
    462 				continue;
    463 			xt::WaveData wave;
    464 			if (xt::State::parseWaveData(wave, data))
    465 				m_ramWaves[i] = wave;
    466 		}
    467 
    468 		for (uint16_t i = xt::wave::g_firstRamTableIndex; i < xt::wave::g_tableCount; ++i)
    469 		{
    470 			const auto id = xt::TableId(i);
    471 			const auto filename = toFilename(id);
    472 			std::vector<uint8_t> data;
    473 			if (!baseLib::filesystem::readFile(data, m_cacheDir + filename))
    474 				continue;
    475 			xt::TableData table;
    476 			if (xt::State::parseTableData(table, data))
    477 				m_tables[i] = table;
    478 		}
    479 	}
    480 
    481 	std::string WaveEditorData::toFilename(const xt::WaveId _id)
    482 	{
    483 		return "wave_" + std::to_string(_id.rawId()) + ".syx";
    484 	}
    485 
    486 	std::string WaveEditorData::toFilename(const xt::TableId _id)
    487 	{
    488 		std::stringstream ss;
    489 		ss << "table_" << std::setw(3) << std::setfill('0') << _id.rawId() << ".syx";
    490 		return ss.str();
    491 	}
    492 }