bool VSTPresets::SaveFile(std::ostream &f, CVstPlugin &plugin, bool bank) //----------------------------------------------------------------------- { if(!bank) { SaveProgram(f, plugin); } else { bool writeChunk = plugin.ProgramsAreChunks(); ChunkHeader header; header.chunkMagic = cMagic; header.version = 2; header.fxID = plugin.GetUID(); header.fxVersion = plugin.GetVersion(); // Write unfinished header... We need to update the size once we're done writing. Write(header, f); uint32 numProgs = std::max(plugin.GetNumPrograms(), VstInt32(1)), curProg = plugin.GetCurrentProgram(); WriteBE(numProgs, f); WriteBE(curProg, f); char reserved[124]; MemsetZero(reserved); Write(reserved, f); if(writeChunk) { char *chunk = nullptr; uint32 chunkSize = mpt::saturate_cast<uint32>(plugin.Dispatch(effGetChunk, 0, 0, &chunk, 0)); if(chunkSize && chunk) { WriteBE(chunkSize, f); f.write(chunk, chunkSize); } else { // The plugin returned no chunk! Gracefully go back and save parameters instead... writeChunk = false; } } if(!writeChunk) { for(uint32 p = 0; p < numProgs; p++) { plugin.SetCurrentProgram(p); SaveProgram(f, plugin); } plugin.SetCurrentProgram(curProg); } // Now we know the correct chunk size. std::streamoff end = f.tellp(); header.byteSize = static_cast<VstInt32>(end - 8); header.fxMagic = writeChunk ? chunkBankMagic : bankMagic; header.ConvertEndianness(); f.seekp(0); Write(header, f); } return true; }
VSTPresets::ErrorCode VSTPresets::LoadFile(FileReader &file, CVstPlugin &plugin) //------------------------------------------------------------------------------ { const bool firstChunk = file.GetPosition() == 0; ChunkHeader header; if(!file.ReadConvertEndianness(header) || header.chunkMagic != cMagic) { return invalidFile; } if(header.fxID != plugin.GetUID()) { return wrongPlugin; } if(header.fxMagic == fMagic || header.fxMagic == chunkPresetMagic) { // Program PlugParamIndex numParams = file.ReadUint32BE(); VstPatchChunkInfo info; info.version = 1; info.pluginUniqueID = header.fxID; info.pluginVersion = header.fxVersion; info.numElements = numParams; MemsetZero(info.future); plugin.Dispatch(effBeginLoadProgram, 0, 0, &info, 0.0f); plugin.Dispatch(effBeginSetProgram, 0, 0, nullptr, 0.0f); char prgName[28]; file.ReadString<mpt::String::maybeNullTerminated>(prgName, 28); plugin.Dispatch(effSetProgramName, 0, 0, prgName, 0.0f); if(header.fxMagic == fMagic) { if(plugin.GetNumParameters() != numParams) { return wrongParameters; } for(PlugParamIndex p = 0; p < numParams; p++) { plugin.SetParameter(p, file.ReadFloatBE()); } } else { FileReader chunk = file.ReadChunk(file.ReadUint32BE()); plugin.Dispatch(effSetChunk, 1, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0); } plugin.Dispatch(effEndSetProgram, 0, 0, nullptr, 0.0f); } else if((header.fxMagic == bankMagic || header.fxMagic == chunkBankMagic) && firstChunk) { // Bank - only read if it's the first chunk in the file, not if it's a sub chunk. uint32 numProgs = file.ReadUint32BE(); uint32 currentProgram = file.ReadUint32BE(); file.Skip(124); VstPatchChunkInfo info; info.version = 1; info.pluginUniqueID = header.fxID; info.pluginVersion = header.fxVersion; info.numElements = numProgs; MemsetZero(info.future); plugin.Dispatch(effBeginLoadBank, 0, 0, &info, 0.0f); if(header.fxMagic == bankMagic) { VstInt32 oldCurrentProgram = plugin.GetCurrentProgram(); for(uint32 p = 0; p < numProgs; p++) { plugin.Dispatch(effBeginSetProgram, 0, 0, nullptr, 0.0f); plugin.Dispatch(effSetProgram, 0, 0, nullptr, 0.0f); ErrorCode retVal = LoadFile(file, plugin); if(retVal != noError) { return retVal; } plugin.Dispatch(effEndSetProgram, 0, 0, nullptr, 0.0f); } plugin.SetCurrentProgram(oldCurrentProgram); } else { FileReader chunk = file.ReadChunk(file.ReadUint32BE()); plugin.Dispatch(effSetChunk, 0, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0); } if(header.version >= 2) { plugin.SetCurrentProgram(currentProgram); } } return noError; }