vstpreset.cpp (6659B)
1 #include "vstpreset.h" 2 3 #include "baseLib/binarystream.h" 4 5 #include "dsp56kEmu/logging.h" 6 7 namespace synthLib 8 { 9 namespace 10 { 11 bool check4CC(const VstPreset::FourCC& _4CC, const char* _expected) 12 { 13 return 0 == strcmp(_4CC.data(), _expected); 14 } 15 bool check4CC(baseLib::BinaryStream& _stream, const char* _expected) 16 { 17 VstPreset::FourCC fourCC; 18 _stream.read4CC(fourCC); 19 return check4CC(fourCC, _expected); 20 } 21 template<VstPreset::Endian SourceEndian> 22 uint32_t readUint32(baseLib::BinaryStream& _s) 23 { 24 const auto i = _s.read<uint32_t>(); 25 26 if constexpr (VstPreset::hostEndian() == SourceEndian) 27 return i; 28 return 29 ((i & 0xFF000000) >> 24) | 30 ((i & 0x00FF0000) >> 8) | 31 ((i & 0x0000FF00) << 8) | 32 ((i & 0x000000FF) << 24); 33 } 34 template<VstPreset::Endian SourceEndian> 35 uint64_t readUint64(baseLib::BinaryStream& _s) 36 { 37 const auto i = _s.read<uint64_t>(); 38 39 if constexpr (VstPreset::hostEndian() == SourceEndian) 40 return i; 41 return 42 ((i & 0xFF00000000000000) >> 56) | 43 ((i & 0x00FF000000000000) >> 40) | 44 ((i & 0x0000FF0000000000) >> 24) | 45 ((i & 0x000000FF00000000) >> 8) | 46 ((i & 0x00000000FF000000) << 8) | 47 ((i & 0x0000000000FF0000) << 24) | 48 ((i & 0x000000000000FF00) << 40) | 49 ((i & 0x00000000000000FF) << 56); 50 } 51 uint32_t readUint32Vst2(baseLib::BinaryStream& _s) 52 { 53 return readUint32<VstPreset::Endian::Big>(_s); 54 } 55 uint32_t readUint32Vst3(baseLib::BinaryStream& _s) 56 { 57 return readUint32<VstPreset::Endian::Little>(_s); 58 } 59 uint64_t readUint64Vst3(baseLib::BinaryStream& _s) 60 { 61 return readUint64<VstPreset::Endian::Little>(_s); 62 } 63 } 64 65 std::optional<VstPreset::ChunkList> VstPreset::read(const std::vector<uint8_t>& _data) 66 { 67 try 68 { 69 baseLib::BinaryStream binaryStream(_data); 70 71 FourCC fourCC; 72 binaryStream.read4CC(fourCC); 73 74 if(check4CC(fourCC, "CcnK")) 75 { 76 binaryStream.setReadPos(0); 77 return readFxbFxp(binaryStream); 78 } 79 if(check4CC(fourCC, "VST3")) 80 { 81 binaryStream.setReadPos(0); 82 return readVst3(binaryStream); 83 } 84 } 85 catch (const std::exception& e) 86 { 87 LOG("Error reading VstPreset: " << e.what()); 88 } 89 return {}; 90 } 91 92 std::optional<VstPreset::ChunkList> VstPreset::readFxbFxp(baseLib::BinaryStream& _binaryStream) 93 { 94 if(!check4CC(_binaryStream, "CcnK")) 95 return {}; 96 /*const auto len = */readUint32Vst2(_binaryStream); 97 FourCC dataType; 98 _binaryStream.read4CC(dataType); 99 100 ChunkList chunkList; 101 102 // bank 103 const auto isRegularBank = check4CC(dataType, "FxBk"); 104 const auto isOpaqueBank = check4CC(dataType, "FBCh"); 105 106 if(isRegularBank || isOpaqueBank) 107 { 108 const auto version = readUint32Vst2(_binaryStream); 109 FourCC pluginId; 110 _binaryStream.read4CC(pluginId); 111 /*const auto pluginVersion = */readUint32Vst2(_binaryStream); 112 const auto numPrograms = readUint32Vst2(_binaryStream); 113 114 if(version >= 2) 115 { 116 /*const auto currentProgram = */(void)readUint32Vst2(_binaryStream); 117 char future[124]; 118 _binaryStream.read(future, sizeof(future)); 119 } 120 else 121 { 122 char future[128]; 123 _binaryStream.read(future, sizeof(future)); 124 } 125 126 for(uint32_t i=0; i<numPrograms; ++i) 127 { 128 if(isOpaqueBank) 129 { 130 const auto chunkSize = readUint32Vst2(_binaryStream); 131 if(!chunkSize) 132 continue; 133 134 Chunk c; 135 c.data.resize(chunkSize); 136 _binaryStream.read(c.data.data(), chunkSize); 137 chunkList.push_back(c); 138 } 139 else 140 { 141 auto programChunks = readFxbFxp(_binaryStream); 142 if(!programChunks) 143 return {}; 144 if(!programChunks->empty()) 145 chunkList.insert(chunkList.end(), programChunks->begin(), programChunks->end()); 146 } 147 } 148 return chunkList; 149 } 150 151 // program 152 const auto isRegularProgram = check4CC(dataType, "FxCk"); 153 const auto isOpaqueProgram = check4CC(dataType, "FPCh"); 154 155 if(isRegularProgram || isOpaqueProgram) 156 { 157 /*const auto version = */readUint32Vst2(_binaryStream); 158 FourCC pluginId; 159 _binaryStream.read4CC(pluginId); 160 /*const auto pluginVersion = */readUint32Vst2(_binaryStream); 161 162 const auto numParams = readUint32Vst2(_binaryStream); 163 164 char programName[29]{}; 165 _binaryStream.read(programName, sizeof(programName)-1); 166 167 if(isOpaqueProgram) 168 { 169 const auto chunkSize = readUint32Vst2(_binaryStream); 170 if(!chunkSize) 171 return {}; 172 173 Chunk c; 174 c.data.resize(chunkSize); 175 _binaryStream.read(c.data.data(), chunkSize); 176 chunkList.push_back(c); 177 } 178 else 179 { 180 for (size_t i = 0; i < numParams; i++) 181 _binaryStream.read<float>(); 182 } 183 return chunkList; 184 } 185 return {}; 186 } 187 188 std::optional<VstPreset::ChunkList> VstPreset::readVst3(baseLib::BinaryStream& _binaryStream) 189 { 190 if(!check4CC(_binaryStream, "VST3")) 191 return {}; 192 193 const auto version = readUint32Vst3(_binaryStream); 194 195 if(version != 1) 196 return {}; 197 198 std::array<char, 32> classId; 199 _binaryStream.read(classId); 200 201 const auto chunkListOffset = readUint32Vst3(_binaryStream); 202 203 // auto posChunkDataBegin = _binaryStream.getReadPos(); 204 205 _binaryStream.setReadPos(chunkListOffset); 206 207 if(!check4CC(_binaryStream, "List")) 208 return {}; 209 210 const auto chunkListEntryCount = readUint32Vst3(_binaryStream); 211 212 ChunkList chunkList; 213 214 for(uint32_t i=0; i<chunkListEntryCount; ++i) 215 { 216 Chunk c; 217 _binaryStream.read4CC(c.id); 218 219 const auto chunkOffset = readUint64Vst3(_binaryStream); 220 const auto chunkSize = readUint64Vst3(_binaryStream); 221 222 if(!chunkSize) 223 continue; 224 225 c.data.resize(chunkSize); 226 227 const auto readPos = _binaryStream.getReadPos(); 228 _binaryStream.setReadPos(static_cast<uint32_t>(chunkOffset)); 229 230 // posChunkDataBegin += chunkSize; 231 232 _binaryStream.read(c.data.data(), chunkSize); 233 _binaryStream.setReadPos(readPos); 234 235 // VST3 can embed a VST2 fxb/fxp, unpack it 236 baseLib::BinaryStream bs(c.data); 237 FourCC fourCC; 238 bs.read4CC(fourCC); 239 240 // according to vst2persistence.cpp of the VST3 SDK, this one is optional 241 if(check4CC(fourCC, "VstW")) 242 { 243 const auto len = readUint32Vst2(bs); 244 const auto vst2version = readUint32Vst2(bs); 245 /*const auto bypassed = */readUint32Vst2(bs); 246 247 assert(len == 8 && vst2version == 1); 248 249 const auto vst2Chunks = readFxbFxp(bs); 250 251 if(vst2Chunks) 252 chunkList.insert(chunkList.end(), vst2Chunks->begin(), vst2Chunks->end()); 253 } 254 else if(check4CC(fourCC, "CcnK")) 255 { 256 bs.setReadPos(0); 257 258 const auto vst2Chunks = readFxbFxp(bs); 259 260 if(vst2Chunks) 261 chunkList.insert(chunkList.end(), vst2Chunks->begin(), vst2Chunks->end()); 262 } 263 else 264 { 265 chunkList.push_back(c); 266 } 267 } 268 return chunkList; 269 } 270 }