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

midipacket.cpp (10417B)


      1 #include "midipacket.h"
      2 
      3 #include <cassert>
      4 
      5 #include "parameterdescriptions.h"
      6 
      7 #include "dsp56kEmu/logging.h"
      8 
      9 namespace pluginLib
     10 {
     11 	MidiPacket::MidiPacket(std::string _name, std::vector<MidiDataDefinition>&& _bytes) : m_name(std::move(_name)), m_definitions(std::move(_bytes))
     12 	{
     13 		uint8_t usedMask = 0;
     14 		uint32_t byteIndex = 0;
     15 
     16 		m_byteToDefinitionIndex.reserve(m_definitions.size());
     17 
     18 		std::set<uint32_t> usedParts;
     19 
     20 		std::string lastParam;
     21 
     22 		for(uint32_t i=0; i<m_definitions.size(); ++i)
     23 		{
     24 			const auto& d = m_definitions[i];
     25 
     26 			if(d.paramPart != AnyPart)
     27 				usedParts.insert(d.paramPart);
     28 
     29 			bool isNewParam = true;
     30 
     31 			if(d.type == MidiDataType::Parameter)
     32 			{
     33 				isNewParam = d.paramName != lastParam;
     34 				lastParam = d.paramName;
     35 				m_hasParameters = true;
     36 			}
     37 
     38 			const auto masked = d.packValue(0xff);
     39 
     40 			if((usedMask & masked) || !isNewParam)
     41 			{
     42 				// next byte starts if the current mask overlaps with an existing one.
     43 				// next byte starts also if the parameter name is identical. In that case, multiple
     44 				// bytes form one parameter.
     45 				usedMask = 0;
     46 				++byteIndex;
     47 			}
     48 
     49 			m_definitionToByteIndex.insert(std::make_pair(i, byteIndex));
     50 
     51 			if(byteIndex >= m_byteToDefinitionIndex.size())
     52 				m_byteToDefinitionIndex.emplace_back();
     53 
     54 			m_byteToDefinitionIndex[byteIndex].push_back(i);
     55 
     56 			usedMask |= masked;
     57 		}
     58 
     59 		m_byteSize = byteIndex + 1;
     60 
     61 		m_numDifferentPartsUsedInParameters = static_cast<uint32_t>(usedParts.size());
     62 	}
     63 
     64 	bool MidiPacket::create(std::vector<uint8_t>& _dst, const Data& _data, const NamedParamValues& _paramValues) const
     65 	{
     66 		_dst.assign(size(), 0);
     67 
     68 		std::map<uint32_t, uint32_t> pendingChecksums;	// byte index => description index
     69 
     70 		for(size_t i=0; i<size(); ++i)
     71 		{
     72 			if(i >= m_byteToDefinitionIndex.size())
     73 				continue;
     74 
     75 			const auto& range = m_byteToDefinitionIndex[i];
     76 
     77 			for(auto itRange = range.begin(); itRange != range.end(); ++itRange)
     78 			{
     79 				const auto& d = m_definitions[*itRange];
     80 
     81 				switch (d.type)
     82 				{
     83 				case MidiDataType::Null:
     84 					_dst[i] = 0;
     85 					break;
     86 				case MidiDataType::Byte:
     87 					_dst[i] = d.byte;
     88 					break;
     89 				case MidiDataType::Parameter:
     90 					{
     91 						const auto it = _paramValues.find(std::make_pair(d.paramPart, d.paramName));
     92 						if(it == _paramValues.end())
     93 						{
     94 							LOG("Failed to find value for parameter " << d.paramName << ", part " << d.paramPart);
     95 							return false;
     96 						}
     97 						_dst[i] |= d.packValue(it->second);
     98 					}
     99 					break;
    100 				case MidiDataType::Checksum:
    101 					pendingChecksums.insert(std::make_pair(static_cast<uint32_t>(i), *itRange));
    102 					break;
    103 				default:
    104 					{
    105 						const auto it = _data.find(d.type);
    106 
    107 						if(it == _data.end())
    108 						{
    109 							LOG("Failed to find data of type " << static_cast<int>(d.type) << " to fill byte " << i << " of midi packet");
    110 							return false;
    111 						}
    112 
    113 						_dst[i] = it->second;
    114 					}
    115 				}
    116 			}
    117 		}
    118 
    119 		for (const auto& pendingChecksum : pendingChecksums)
    120 		{
    121 			const auto byteIndex = pendingChecksum.first;
    122 			const auto descIndex = pendingChecksum.second;
    123 
    124 			_dst[byteIndex] = calcChecksum(m_definitions[descIndex], _dst);
    125 		}
    126 
    127 		return true;
    128 	}
    129 
    130 	bool MidiPacket::create(std::vector<uint8_t>& _dst, const Data& _data) const
    131 	{
    132 		return create(_dst, _data, {});
    133 	}
    134 
    135 	bool MidiPacket::parse(Data& _data, AnyPartParamValues& _parameterValues, const ParameterDescriptions& _parameters, const Sysex& _src, bool _ignoreChecksumErrors) const
    136 	{
    137 		if(m_numDifferentPartsUsedInParameters > 0)
    138 		{
    139 			LOG("Failed to parse midi packet " << m_name << " with parameters for " << m_numDifferentPartsUsedInParameters << " different parts into parameter values that are not part-aware");
    140 			return false;
    141 		}
    142 
    143 		_parameterValues.reserve(_src.size());
    144 
    145 		return parse(_data, [&](ParamIndex _paramIndex, uint8_t _value)
    146 		{
    147 			const auto idx = _paramIndex.second;
    148 			if(_parameterValues.size() <= idx)
    149 				_parameterValues.resize(idx + 1);
    150 			_parameterValues[idx] = _value;
    151 		}, _parameters, _src, _ignoreChecksumErrors);
    152 	}
    153 
    154 	bool MidiPacket::parse(Data& _data, ParamValues& _parameterValues, const ParameterDescriptions& _parameters, const Sysex& _src, bool _ignoreChecksumErrors/* = true*/) const
    155 	{
    156 		_parameterValues.reserve(_src.size() << 1);
    157 
    158 		return parse(_data, [&](ParamIndex _paramIndex, uint8_t _value)
    159 		{
    160 			const auto itExisting = _parameterValues.find(_paramIndex);
    161 			if(itExisting != _parameterValues.end())
    162 				itExisting->second |= _value;
    163 			else
    164 				_parameterValues.insert(std::make_pair(_paramIndex, _value));
    165 		}, _parameters, _src, _ignoreChecksumErrors);
    166 	}
    167 	
    168 	bool MidiPacket::parse(Data& _data, const std::function<void(ParamIndex, ParamValue)>& _addParamValueCallback, const ParameterDescriptions& _parameters, const Sysex& _src, bool _ignoreChecksumErrors) const
    169 	{
    170 		if(_src.size() != size())
    171 			return false;
    172 
    173 		for(size_t i=0; i<_src.size(); ++i)
    174 		{
    175 			const auto s = _src[i];
    176 
    177 			if(i >= m_byteToDefinitionIndex.size())
    178 				continue;
    179 
    180 			const auto& range = m_byteToDefinitionIndex[i];
    181 
    182 			for(auto it = range.begin(); it != range.end(); ++it)
    183 			{
    184 				const auto& d = m_definitions[*it];
    185 
    186 				switch (d.type)
    187 				{
    188 				case MidiDataType::Null: 
    189 					continue;
    190 				case MidiDataType::Byte:
    191 					if(d.byte != s)
    192 						return false;
    193 					break;
    194 				case MidiDataType::Checksum:
    195 					{
    196 						const uint8_t checksum = calcChecksum(d, _src);
    197 
    198 						if(checksum != s)
    199 						{
    200 							LOG("Packet checksum error, calculated " << std::hex << static_cast<int>(checksum) << " but data contains " << static_cast<int>(s) << ", packet type " << m_name);
    201 							if(!_ignoreChecksumErrors)
    202 								return false;
    203 						}
    204 					}
    205 					continue;
    206 				case MidiDataType::DeviceId:
    207 				case MidiDataType::Bank:
    208 				case MidiDataType::Program:
    209 				case MidiDataType::ParameterIndex:
    210 				case MidiDataType::ParameterValue:
    211 				case MidiDataType::Page:
    212 				case MidiDataType::Part:
    213 					_data.insert(std::make_pair(d.type, s));
    214 					break;
    215 				case MidiDataType::Parameter:
    216 					{
    217 						uint32_t idx;
    218 						if(!_parameters.getIndexByName(idx, d.paramName))
    219 						{
    220 							LOG("Failed to find named parameter " << d.paramName << " while parsing midi packet, midi byte " << i);
    221 							return false;
    222 						}
    223 						const auto sUnpacked = d.unpackValue(s);
    224 						_addParamValueCallback(std::make_pair(d.paramPart, idx), sUnpacked);
    225 					}
    226 					break;
    227 				default:
    228 					assert(false && "unknown data type");
    229 					return false;
    230 				}
    231 			}
    232 		}
    233 		return true;
    234 	}
    235 
    236 	bool MidiPacket::getParameterIndices(ParamIndices& _indices, const ParameterDescriptions& _parameters) const
    237 	{
    238 		if(!m_hasParameters)
    239 			return true;
    240 
    241 		for (const auto & d : m_definitions)
    242 		{
    243 			if(d.type != MidiDataType::Parameter)
    244 				continue;
    245 
    246 			uint32_t index;
    247 			if(!_parameters.getIndexByName(index, d.paramName))
    248 			{
    249 				LOG("Failed to retrieve index for parameter " << d.paramName);
    250 				return false;
    251 			}
    252 
    253 			_indices.insert(std::make_pair(d.paramPart, index));
    254 		}
    255 		return true;
    256 	}
    257 
    258 	bool MidiPacket::getDefinitionsForByteIndex(std::vector<const MidiDataDefinition*>& _result, uint32_t _byteIndex) const
    259 	{
    260 		if (_byteIndex >= m_byteToDefinitionIndex.size())
    261 			return false;
    262 
    263 		const auto& defs = m_byteToDefinitionIndex[_byteIndex];
    264 
    265 		for (const auto idx : defs)
    266 		{
    267 			const auto &d = m_definitions[idx];
    268 			_result.emplace_back(&d);
    269 		}
    270 		return true;
    271 	}
    272 
    273 	bool MidiPacket::getParameterIndicesForByteIndex(std::vector<ParamIndex>& _result, const ParameterDescriptions& _parameters, const uint32_t _byteIndex) const
    274 	{
    275 		if (_byteIndex >= m_byteToDefinitionIndex.size())
    276 			return false;
    277 
    278 		const auto& defs = m_byteToDefinitionIndex[_byteIndex];
    279 
    280 		for (const auto idx : defs)
    281 		{
    282 			const auto &d = m_definitions[idx];
    283 
    284 			uint32_t paramIdx;
    285 
    286 			if(!_parameters.getIndexByName(paramIdx, d.paramName))
    287 			{
    288 				LOG("Failed to retrieve index for parameter " << d.paramName);
    289 				return false;
    290 			}
    291 
    292 			_result.emplace_back(d.paramPart, paramIdx);
    293 		}
    294 		return true;
    295 	}
    296 
    297 	uint32_t MidiPacket::getByteIndexForType(MidiDataType _type) const
    298 	{
    299 		for(uint32_t i=0; i<m_definitions.size(); ++i)
    300 		{
    301 			const auto& d = m_definitions[i];
    302 			if(d.type != _type)
    303 				continue;
    304 
    305 			return m_definitionToByteIndex.find(i)->second;
    306 		}
    307 		return InvalidIndex;
    308 	}
    309 
    310 	uint32_t MidiPacket::getByteIndexForParameterName(const std::string& _name) const
    311 	{
    312 		for(uint32_t i=0; i<m_definitions.size(); ++i)
    313 		{
    314 			const auto& d = m_definitions[i];
    315 
    316 			if(d.type != MidiDataType::Parameter)
    317 				continue;
    318 
    319 			if(d.paramName != _name)
    320 				continue;
    321 
    322 			return m_definitionToByteIndex.find(i)->second;
    323 		}
    324 		return InvalidIndex;
    325 	}
    326 
    327 	std::vector<uint32_t> MidiPacket::getDefinitionIndicesForParameterName(const std::string& _name) const
    328 	{
    329 		std::vector<uint32_t> res;
    330 
    331 		for(uint32_t i=0; i<m_definitions.size(); ++i)
    332 		{
    333 			const auto& d = m_definitions[i];
    334 
    335 			if(d.type != MidiDataType::Parameter)
    336 				continue;
    337 
    338 			if(d.paramName != _name)
    339 				continue;
    340 
    341 			res.push_back(i);
    342 		}
    343 
    344 		return res;
    345 	}
    346 
    347 	const MidiPacket::MidiDataDefinition* MidiPacket::getDefinitionByParameterName(const std::string& _name) const
    348 	{
    349 		for (const auto& definition : m_definitions)
    350 		{
    351 			if (definition.paramName == _name)
    352 				return &definition;
    353 		}
    354 
    355 		return nullptr;
    356 	}
    357 
    358 	ParamValue MidiPacket::getParameterValue(const Sysex& _sysex, const std::vector<uint32_t>& _definitionIndices) const
    359 	{
    360 		ParamValue res = 0;
    361 
    362 		bool valid = false;
    363 
    364 		for (uint32_t defIndex : _definitionIndices)
    365 		{
    366 			const auto& d = m_definitions[defIndex];
    367 
    368 			if (d.type != MidiDataType::Parameter)
    369 				continue;
    370 
    371 			const auto byteIndex = m_definitionToByteIndex.find(defIndex)->second;
    372 
    373 			res |= d.unpackValue(_sysex[byteIndex]);
    374 			valid = true;
    375 		}
    376 
    377 		return valid ? res : -1;
    378 	}
    379 
    380 	bool MidiPacket::updateChecksums(Sysex& _data) const
    381 	{
    382 		if (_data.size() != m_byteSize)
    383 			return false;
    384 
    385 		bool res = false;
    386 
    387 		for (uint32_t i=0; i<m_definitions.size(); ++i)
    388 		{
    389 			const auto& def = m_definitions[i];
    390 
    391 			if (def.type != MidiDataType::Checksum)
    392 				continue;
    393 
    394 			const auto byteIndex = m_definitionToByteIndex.find(i)->second;
    395 
    396 			const auto c = calcChecksum(def, _data);
    397 			_data[byteIndex] = c;
    398 			res = true;
    399 		}
    400 
    401 		return res;
    402 	}
    403 
    404 	uint8_t MidiPacket::calcChecksum(const MidiDataDefinition& _d, const Sysex& _src)
    405 	{
    406 		auto checksum = _d.checksumInitValue;
    407 
    408 		for(uint32_t c = _d.checksumFirstIndex; c <= _d.checksumLastIndex; ++c)
    409 			checksum += _src[c];
    410 
    411 		return checksum & 0x7f;
    412 	}
    413 }