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 }