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

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 }