Ejemplo n.º 1
0
        public bool WriteFXP(string filePath)
        {
            FXP fxp = GenerateFXP(false);

            fxp.Write(filePath);
            return(true);
        }
Ejemplo n.º 2
0
        protected override byte[] ProcessFile(string fileName, PresetParserMetadata preset)
        {
            var fxp = new FXP();

            fxp.ReadFile(fileName);

            return(fxp.ChunkDataByteArray);
        }
        public bool Read(string filePath)
        {
            var fxp = new FXP();

            fxp.ReadFile(filePath);
            byte[] chunkDataByteArray = fxp.ChunkDataByteArray;
            return(ReadChunkData(chunkDataByteArray));
        }
Ejemplo n.º 4
0
        public void SaveFXP(string filePath)
        {
            bool UseChunk = false;

            if ((PluginContext.PluginInfo.Flags & VstPluginFlags.ProgramChunks) == 0)
            {
                // Chunks not supported.
                UseChunk = false;
            }
            else
            {
                // Chunks supported.
                UseChunk = true;
            }

            FXP fxp = new FXP();

            fxp.ChunkMagic = "CcnK";
            fxp.ByteSize   = 0;           // will be set correctly by FXP class

            if (UseChunk)
            {
                // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
                fxp.FxMagic      = "FPCh";       // FPCh = FXP (preset), FBCh = FXB (bank)
                fxp.Version      = 1;            // Format Version (should be 1)
                fxp.FxID         = PluginIDNumberToIDString(PluginContext.PluginInfo.PluginID);
                fxp.FxVersion    = PluginContext.PluginInfo.PluginVersion;
                fxp.ProgramCount = PluginContext.PluginInfo.ProgramCount;
                fxp.Name         = PluginContext.PluginCommandStub.GetProgramName();

                byte[] chunkData = PluginContext.PluginCommandStub.GetChunk(true);
                fxp.ChunkSize          = chunkData.Length;
                fxp.ChunkDataByteArray = chunkData;
            }
            else
            {
                // Preset (Program) (.fxp) without chunk (magic = 'FxCk')
                fxp.FxMagic        = "FxCk";     // FxCk = FXP (preset), FxBk = FXB (bank)
                fxp.Version        = 1;          // Format Version (should be 1)
                fxp.FxID           = PluginIDNumberToIDString(PluginContext.PluginInfo.PluginID);
                fxp.FxVersion      = PluginContext.PluginInfo.PluginVersion;
                fxp.ParameterCount = PluginContext.PluginInfo.ParameterCount;
                fxp.Name           = PluginContext.PluginCommandStub.GetProgramName();

                // variable no. of parameters
                float[] parameters = new float[fxp.ParameterCount];
                for (int i = 0; i < fxp.ParameterCount; i++)
                {
                    parameters[i] = PluginContext.PluginCommandStub.GetParameter(i);
                }
                fxp.Parameters = parameters;
            }
            fxp.WriteFile(filePath);
        }
Ejemplo n.º 5
0
        public bool ReadFXP(FXP fxp, string filePath = "")
        {
            if (fxp == null || fxp.ChunkDataByteArray == null)
            {
                return(false);
            }

            var bFile = new BinaryFile(fxp.ChunkDataByteArray, BinaryFile.ByteOrder.LittleEndian);

            // Read UAD Preset Header information
            PresetHeaderVar1 = bFile.ReadInt32();
            PresetHeaderVar2 = bFile.ReadInt32();
            PresetName       = bFile.ReadString(32).Trim('\0');

            // Read Parameters
            Input      = bFile.ReadSingle();
            Phase      = bFile.ReadSingle();
            HPFreq     = bFile.ReadSingle();
            LPFreq     = bFile.ReadSingle();
            HP_LPDynSC = bFile.ReadSingle();
            CMPRatio   = bFile.ReadSingle();
            CMPThresh  = bFile.ReadSingle();
            CMPRelease = bFile.ReadSingle();
            CMPAttack  = bFile.ReadSingle();
            StereoLink = bFile.ReadSingle();
            Select     = bFile.ReadSingle();
            EXPThresh  = bFile.ReadSingle();
            EXPRange   = bFile.ReadSingle();
            EXPRelease = bFile.ReadSingle();
            EXPAttack  = bFile.ReadSingle();
            DYNIn      = bFile.ReadSingle();
            CompIn     = bFile.ReadSingle();
            ExpIn      = bFile.ReadSingle();
            LFGain     = bFile.ReadSingle();
            LFFreq     = bFile.ReadSingle();
            LFBell     = bFile.ReadSingle();
            LMFGain    = bFile.ReadSingle();
            LMFFreq    = bFile.ReadSingle();
            LMFQ       = bFile.ReadSingle();
            HMFQ       = bFile.ReadSingle();
            HMFGain    = bFile.ReadSingle();
            HMFFreq    = bFile.ReadSingle();
            HFGain     = bFile.ReadSingle();
            HFFreq     = bFile.ReadSingle();
            HFBell     = bFile.ReadSingle();
            EQIn       = bFile.ReadSingle();
            EQDynSC    = bFile.ReadSingle();
            PreDyn     = bFile.ReadSingle();
            Output     = bFile.ReadSingle();
            EQType     = bFile.ReadSingle();
            Power      = bFile.ReadSingle();

            return(true);
        }
Ejemplo n.º 6
0
        public bool ReadFXP(string filePath)
        {
            // store filepath
            FilePath = filePath;

            FXP fxp = new FXP();

            fxp.ReadFile(filePath);

            if (!ReadFXP(fxp, filePath))
            {
                return(false);
            }
            return(true);
        }
Ejemplo n.º 7
0
        private FXP GenerateFXP(bool isBank)
        {
            FXP.FxContent fxpContent;
            FXP           fxp = new FXP();

            if (isBank)
            {
                // FBCh = FXB (bank)
                fxpContent = new FXP.FxChunkSet();
                ((FXP.FxChunkSet)fxpContent).NumPrograms = 1;                     // I.e. number of programs (number of presets in one file)
                ((FXP.FxChunkSet)fxpContent).Future      = new string('\0', 128); // 128 bytes long
            }
            else
            {
                // FPCh = FXP (preset)
                fxpContent = new FXP.FxProgramSet();
                ((FXP.FxProgramSet)fxpContent).NumPrograms = 1; // I.e. number of programs (number of presets in one file)
                ((FXP.FxProgramSet)fxpContent).Name        = PresetName;
            }

            fxp.Content           = fxpContent;
            fxpContent.ChunkMagic = "CcnK";
            fxpContent.ByteSize   = 0; // will be set correctly by FXP class

            // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
            fxpContent.FxMagic   = isBank ? "FBCh" : "FPCh";
            fxpContent.Version   = 1; //isBank ? 2 : 1; // Format Version (should be 1)
            fxpContent.FxID      = "J9AU";
            fxpContent.FxVersion = 1;

            byte[] chunkData = GetChunkData(fxpContent.FxMagic);

            if (fxp.Content is FXP.FxProgramSet)
            {
                ((FXP.FxProgramSet)fxp.Content).ChunkSize = chunkData.Length;
                ((FXP.FxProgramSet)fxp.Content).ChunkData = chunkData;
            }
            else if (fxp.Content is FXP.FxChunkSet)
            {
                ((FXP.FxChunkSet)fxp.Content).ChunkSize = chunkData.Length;
                ((FXP.FxChunkSet)fxp.Content).ChunkData = chunkData;
            }

            return(fxp);
        }
Ejemplo n.º 8
0
        public bool ReadFXP(string filePath)
        {
            var fxp = new FXP();

            fxp.ReadFile(filePath);

            if (fxp.Content != null)
            {
                if (fxp.Content is FXP.FxProgramSet)
                {
                    byte[] chunkDataByteArray = ((FXP.FxProgramSet)fxp.Content).ChunkData;
                    return(ReadChunkData(chunkDataByteArray));
                }
                else if (fxp.Content is FXP.FxChunkSet)
                {
                    byte[] chunkDataByteArray = ((FXP.FxChunkSet)fxp.Content).ChunkData;
                    return(ReadChunkData(chunkDataByteArray));
                }
            }
            return(false);
        }
        public bool WriteFXP(string filePath)
        {
            FXP fxp = new FXP();

            fxp.ChunkMagic = "CcnK";
            fxp.ByteSize   = 0;           // will be set correctly by FXP class

            // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
            fxp.FxMagic      = "FPCh";   // FPCh = FXP (preset), FBCh = FXB (bank)
            fxp.Version      = 1;        // Format Version (should be 1)
            fxp.FxID         = "J9AU";
            fxp.FxVersion    = 1;
            fxp.ProgramCount = 36;             // I.e. nummber of parameters
            fxp.Name         = PresetName;

            byte[] chunkData = GetChunkData();
            fxp.ChunkSize          = chunkData.Length;
            fxp.ChunkDataByteArray = chunkData;

            fxp.WriteFile(filePath);
            return(true);
        }
Ejemplo n.º 10
0
        public void LoadFXP(string filePath)
        {
            if (filePath == null || filePath == "")
            {
                return;
            }
            // How does the GetChunk/SetChunk interface work? What information should be in those chunks?
            // How does the BeginLoadProgram and BeginLoadBank work?
            // There doesn't seem to be any restriction on what data is put in the chunks.
            // The beginLoadBank/Program methods are also part of the persistence call sequence.
            // GetChunk returns a buffer with program information of either the current/active program
            // or all programs.
            // SetChunk should read this information back in and initialize either the current/active program
            // or all programs.
            // Before SetChunk is called, the beginLoadBank/Program method is called
            // passing information on the version of the plugin that wrote the data.
            // This will allow you to support older data versions of your plugin's data or
            // even support reading other plugin's data.
            // Some hosts will call GetChunk before calling beginLoadBakn/Program and SetChunk.
            // This is an optimazation of the host to determine if the information to load is
            // actually different than the state your plugin program(s) (are) in.

            bool UseChunk = false;

            if ((PluginContext.PluginInfo.Flags & VstPluginFlags.ProgramChunks) == 0)
            {
                // Chunks not supported.
                UseChunk = false;
            }
            else
            {
                // Chunks supported.
                UseChunk = true;
            }

            FXP fxp = new FXP();

            fxp.ReadFile(filePath);
            if (fxp.ChunkMagic != "CcnK")
            {
                // not a fxp or fxb file
                Console.Out.WriteLine("Error - Cannot Load. Loaded preset is not a fxp or fxb file");
                return;
            }

            int pluginUniqueID  = PluginIDStringToIDNumber(fxp.FxID);
            int currentPluginID = PluginContext.PluginInfo.PluginID;

            if (pluginUniqueID != currentPluginID)
            {
                Console.Out.WriteLine("Error - Cannot Load. Loaded preset has another ID!");
            }
            else
            {
                // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
                // Bank (.fxb) with chunk (magic = 'FBCh')
                if (fxp.FxMagic == "FPCh" || fxp.FxMagic == "FBCh")
                {
                    UseChunk = true;
                }
                else
                {
                    UseChunk = false;
                }
                if (UseChunk)
                {
                    // If your plug-in is configured to use chunks
                    // the Host will ask for a block of memory describing the current
                    // plug-in state for saving.
                    // To restore the state at a later stage, the same data is passed
                    // back to setChunk.
                    byte[] chunkData             = fxp.ChunkDataByteArray;
                    bool   beginSetProgramResult = PluginContext.PluginCommandStub.BeginSetProgram();
                    int    iResult             = PluginContext.PluginCommandStub.SetChunk(chunkData, true);
                    bool   endSetProgramResult = PluginContext.PluginCommandStub.EndSetProgram();
                }
                else
                {
                    // Alternatively, when not using chunk, the Host will simply
                    // save all parameter values.
                    float[] parameters            = fxp.Parameters;
                    bool    beginSetProgramResult = PluginContext.PluginCommandStub.BeginSetProgram();
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        PluginContext.PluginCommandStub.SetParameter(i, parameters[i]);
                    }
                    bool endSetProgramResult = PluginContext.PluginCommandStub.EndSetProgram();
                }
            }
        }
Ejemplo n.º 11
0
        public static bool Convert2ReaEQ(REWEQFilters filters, string filePath)
        {
            List <ReaEQBand> ReaEqBands = new List <ReaEQBand>();

            foreach (REWEQBand filter in filters)
            {
                ReaEQBand band = new ReaEQBand();
                band.LogScaleAutoFreq = true;
                band.FilterFreq       = filter.FilterFreq;
                band.FilterGain       = filter.FilterGain;
                band.FilterBWOct      = filter.FilterBWOct;
                band.Enabled          = filter.Enabled;
                switch (filter.FilterType)
                {
                case REWEQFilterType.PK:
                    band.FilterType = ReaEQFilterType.Band;
                    break;

                case REWEQFilterType.LP:
                    band.FilterType = ReaEQFilterType.LowPass;
                    break;

                case REWEQFilterType.HP:
                    band.FilterType = ReaEQFilterType.HighPass;
                    break;

                case REWEQFilterType.LS:
                    band.FilterType = ReaEQFilterType.LowShelf;
                    break;

                case REWEQFilterType.HS:
                    band.FilterType = ReaEQFilterType.HighShelf;
                    break;

                default:
                    band.FilterType = ReaEQFilterType.Band;
                    break;
                }
                ReaEqBands.Add(band);
            }

            // store to file
            FXP fxp = new FXP();

            FXP.FxProgramSet fxpContent = new FXP.FxProgramSet();
            fxp.Content            = fxpContent;
            fxpContent.ChunkMagic  = "CcnK";
            fxpContent.ByteSize    = 0;      // will be set correctly by FXP class
            fxpContent.FxMagic     = "FPCh"; // FPCh = FXP (preset), FBCh = FXB (bank)
            fxpContent.Version     = 1;      // Format Version (should be 1)
            fxpContent.FxID        = "reeq";
            fxpContent.FxVersion   = 1100;
            fxpContent.NumPrograms = 1;
            fxpContent.Name        = "";

            using (MemoryStream memStream = new MemoryStream(10))
            {
                BinaryFile binFile = new BinaryFile(memStream, BinaryFile.ByteOrder.LittleEndian);
                binFile.Write((int)33);
                binFile.Write((int)ReaEqBands.Count);
                foreach (ReaEQBand band in ReaEqBands)
                {
                    binFile.Write((int)band.FilterType);
                    binFile.Write((int)(band.Enabled ? 1 : 0));
                    binFile.Write((double)band.FilterFreq);
                    binFile.Write((double)Decibel2AmplitudeRatio(band.FilterGain));
                    binFile.Write((double)band.FilterBWOct);
                    binFile.Write((byte)1);
                }

                binFile.Write((int)1);
                binFile.Write((int)1);

                binFile.Write((double)Decibel2AmplitudeRatio(0.00));
                binFile.Write((int)0);

                memStream.Flush();
                byte[] chunkData = memStream.GetBuffer();
                fxpContent.ChunkSize = chunkData.Length;
                fxpContent.ChunkData = chunkData;
            }

            fxp.Write(filePath);
            return(true);
        }
Ejemplo n.º 12
0
        public void LoadFXP(string filePath)
        {
            if (filePath == null || filePath == "") {
                return;
            }
            // How does the GetChunk/SetChunk interface work? What information should be in those chunks?
            // How does the BeginLoadProgram and BeginLoadBank work?
            // There doesn't seem to be any restriction on what data is put in the chunks.
            // The beginLoadBank/Program methods are also part of the persistence call sequence.
            // GetChunk returns a buffer with program information of either the current/active program
            // or all programs.
            // SetChunk should read this information back in and initialize either the current/active program
            // or all programs.
            // Before SetChunk is called, the beginLoadBank/Program method is called
            // passing information on the version of the plugin that wrote the data.
            // This will allow you to support older data versions of your plugin's data or
            // even support reading other plugin's data.
            // Some hosts will call GetChunk before calling beginLoadBakn/Program and SetChunk.
            // This is an optimazation of the host to determine if the information to load is
            // actually different than the state your plugin program(s) (are) in.

            bool UseChunk = false;
            if ((PluginContext.PluginInfo.Flags & VstPluginFlags.ProgramChunks) == 0) {
                // Chunks not supported.
                UseChunk = false;
            } else {
                // Chunks supported.
                UseChunk = true;
            }

            FXP fxp = new FXP();
            fxp.ReadFile(filePath);
            if (fxp.ChunkMagic != "CcnK") {
                // not a fxp or fxb file
                Console.Out.WriteLine("Error - Cannot Load. Loaded preset is not a fxp or fxb file");
                return;
            }

            int pluginUniqueID = PluginIDStringToIDNumber(fxp.FxID);
            int currentPluginID = PluginContext.PluginInfo.PluginID;
            if (pluginUniqueID != currentPluginID) {
                Console.Out.WriteLine("Error - Cannot Load. Loaded preset has another ID!");
            } else {
                // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
                // Bank (.fxb) with chunk (magic = 'FBCh')
                if (fxp.FxMagic == "FPCh" || fxp.FxMagic == "FBCh") {
                    UseChunk = true;
                } else {
                    UseChunk = false;
                }
                if (UseChunk) {
                    // If your plug-in is configured to use chunks
                    // the Host will ask for a block of memory describing the current
                    // plug-in state for saving.
                    // To restore the state at a later stage, the same data is passed
                    // back to setChunk.
                    byte[] chunkData = fxp.ChunkDataByteArray;
                    bool beginSetProgramResult = PluginContext.PluginCommandStub.BeginSetProgram();
                    int iResult = PluginContext.PluginCommandStub.SetChunk(chunkData, true);
                    bool endSetProgramResult = PluginContext.PluginCommandStub.EndSetProgram();
                } else {
                    // Alternatively, when not using chunk, the Host will simply
                    // save all parameter values.
                    float[] parameters = fxp.Parameters;
                    bool beginSetProgramResult = PluginContext.PluginCommandStub.BeginSetProgram();
                    for (int i = 0; i < parameters.Length; i++) {
                        PluginContext.PluginCommandStub.SetParameter(i, parameters[i]);
                    }
                    bool endSetProgramResult = PluginContext.PluginCommandStub.EndSetProgram();
                }
            }
        }
Ejemplo n.º 13
0
        public void SaveFXP(string filePath)
        {
            bool UseChunk = false;
            if ((PluginContext.PluginInfo.Flags & VstPluginFlags.ProgramChunks) == 0) {
                // Chunks not supported.
                UseChunk = false;
            } else {
                // Chunks supported.
                UseChunk = true;
            }

            FXP fxp = new FXP();
            fxp.ChunkMagic = "CcnK";
            fxp.ByteSize = 0; // will be set correctly by FXP class

            if (UseChunk) {
                // Preset (Program) (.fxp) with chunk (magic = 'FPCh')
                fxp.FxMagic = "FPCh"; // FPCh = FXP (preset), FBCh = FXB (bank)
                fxp.Version = 1; // Format Version (should be 1)
                fxp.FxID = PluginIDNumberToIDString(PluginContext.PluginInfo.PluginID);
                fxp.FxVersion = PluginContext.PluginInfo.PluginVersion;
                fxp.ProgramCount = PluginContext.PluginInfo.ProgramCount;
                fxp.Name = PluginContext.PluginCommandStub.GetProgramName();

                byte[] chunkData = PluginContext.PluginCommandStub.GetChunk(true);
                fxp.ChunkSize = chunkData.Length;
                fxp.ChunkDataByteArray = chunkData;
            } else {
                // Preset (Program) (.fxp) without chunk (magic = 'FxCk')
                fxp.FxMagic = "FxCk"; // FxCk = FXP (preset), FxBk = FXB (bank)
                fxp.Version = 1; // Format Version (should be 1)
                fxp.FxID = PluginIDNumberToIDString(PluginContext.PluginInfo.PluginID);
                fxp.FxVersion = PluginContext.PluginInfo.PluginVersion;
                fxp.ParameterCount = PluginContext.PluginInfo.ParameterCount;
                fxp.Name = PluginContext.PluginCommandStub.GetProgramName();

                // variable no. of parameters
                float[] parameters = new float[fxp.ParameterCount];
                for (int i = 0; i < fxp.ParameterCount; i++) {
                    parameters[i] = PluginContext.PluginCommandStub.GetParameter(i);
                }
                fxp.Parameters = parameters;
            }
            fxp.WriteFile(filePath);
        }
Ejemplo n.º 14
0
        public static void Main(string[] args)
        {
            FrontendInitializer.RegisterTypes(ServiceLocator.Default);
            FrontendInitializer.Initialize(ServiceLocator.Default);
            var vendorPresetParserService = ServiceLocator.Default.ResolveType <VendorPresetParserService>();
            var logger = new RollingInMemoryLogListener();

            LogManager.AddListener(logger);

            var pluginTestDirectory = @"C:\Program Files\VSTPlugins";
            var testResults         = new List <PluginTestResult>();

            var presetParserDictionary = vendorPresetParserService.GetPresetHandlerListByPlugin();


            var testData       = ReadTestData();
            var ignoredPlugins = ReadIgnoredPlugins();

            List <string> IgnoredPresetParsers = new List <string>();

            IgnoredPresetParsers.Add("VoidPresetParser");

            var localLogger = new MiniConsoleLogger();
            var hasIgnored  = false;

            localLogger.SetConsoleLogLevelFilter(new HashSet <LogLevel> {
                LogLevel.Error, LogLevel.Warning
            });

            if (args.Length > 0)
            {
                foreach (var key in presetParserDictionary.Keys.ToList())
                {
                    if (!presetParserDictionary[key].PresetParserType.ToLower().Contains(args[0].ToLower()))
                    {
                        presetParserDictionary.Remove(key);
                        hasIgnored = true;
                    }
                }
            }

            foreach (var presetParserKeyValue in presetParserDictionary)
            {
                var presetParser = presetParserKeyValue.Value;
                var pluginId     = presetParserKeyValue.Key;

                if (IgnoredPresetParsers.Contains(presetParser.PresetParserType))
                {
                    continue;
                }

                if (IsIgnored(ignoredPlugins, presetParser.PresetParserType, pluginId))
                {
                    continue;
                }

                Console.Write(presetParser.PresetParserType + ": ");

                var start = DateTime.Now;

                var pluginLocation = new PluginLocation
                {
                    DllPath = @"C:\Program Files\VstPlugins\Foobar.dll", IsPresent = true
                };

                var plugin = new Plugin
                {
                    VstPluginId = pluginId, PluginLocation = pluginLocation,
                    PluginInfo  = new VstPluginInfoSurrogate
                    {
                        ProgramCount = 1, Flags = VstPluginFlags.ProgramChunks, PluginID = pluginId
                    }
                };

                var stubProcess = new StubVstHostProcess();
                stubProcess.PluginId = pluginId;

                var remoteInstance = new RemotePluginInstance(stubProcess, plugin);

                presetParser.DataPersistence = new NullPresetPersistence();
                presetParser.PluginInstance  = remoteInstance;
                presetParser.RootBank        = plugin.RootBank.First();
                presetParser.Logger.Clear();
                presetParser.Logger.MirrorTo(localLogger);

                var testResult = new PluginTestResult
                {
                    VendorPresetParser = presetParser.PresetParserType,
                    PluginId           = plugin.VstPluginId
                };

                double timeForNumPresets = 0;
                double timeForDoScan     = 0;
                double totalTime         = 0;
                try
                {
                    presetParser.Init();
                    testResult.ReportedPresets = presetParser.GetNumPresets();
                    timeForNumPresets          = (DateTime.Now - start).TotalSeconds;
                    start = DateTime.Now;
                    presetParser.DoScan().GetAwaiter().GetResult();
                    timeForDoScan = (DateTime.Now - start).TotalSeconds;
                    totalTime     = timeForNumPresets + timeForDoScan;
                }
                catch (Exception e)
                {
                    testResult.Error = "Errored";
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                }

                testResult.Presets = plugin.Presets.Count;

                var timePerPreset = (totalTime / testResult.Presets) * 1000;
                // ReSharper disable once LocalizableElement
                Console.WriteLine(
                    $"{testResult.Presets} parsed in {totalTime:F3}s (avg {timePerPreset:F3}ms / Preset, DoScan {timeForDoScan:F3}s, NumPresets {timeForNumPresets:F3}s");

                var testDataEntries    = GetTestDataEntries(testData, presetParser.PresetParserType, pluginId);
                var hasTestDataEntries = testDataEntries.Count > 0;
                var testDataOk         = true;
                foreach (var preset in plugin.Presets)
                {
                    if (preset.Metadata.BankPath == "")
                    {
                        testResult.BankMissing++;
                    }

                    foreach (var testDataEntry in testDataEntries.ToList())
                    {
                        if (preset.Metadata.PresetName == testDataEntry.ProgramName &&
                            preset.Metadata.BankPath == testDataEntry.BankPath)
                        {
                            var testFilename = PathUtils.SanitizeFilename(
                                testDataEntry.PresetParser + "." + preset.OriginalMetadata.PresetName +
                                ".testdata");
                            var myDocumentsTestDataFile = Path.Combine(GetPatchFilesDirectory(), testFilename);
                            var localTestDataFile       = Path.Combine("TestData", testFilename);


                            var presetHash = testDataEntry.Hash.TrimEnd();
                            if (preset.PresetHash != presetHash)
                            {
                                var fileMessage     = "";
                                var wrongPresetData = myDocumentsTestDataFile + ".wrong";
                                testDataOk = false;

                                if (File.Exists(myDocumentsTestDataFile))
                                {
                                    fileMessage = $"Original preset data in {myDocumentsTestDataFile}" +
                                                  Environment.NewLine +
                                                  $"Current (wrong) preset data in {wrongPresetData}";
                                }
                                else
                                {
                                    fileMessage =
                                        $"Original preset data not found (expected in {myDocumentsTestDataFile})" +
                                        Environment.NewLine +
                                        $"Current (wrong) preset data in {wrongPresetData}";
                                }

                                File.WriteAllBytes(wrongPresetData, LZ4Pickler.Unpickle(
                                                       NullPresetPersistence.PresetData[preset.OriginalMetadata.SourceFile]));
                                testResult.DetailedErrors.Add(
                                    $"Found preset {testDataEntry.ProgramName} with bank path " +
                                    $"{testDataEntry.BankPath} but the preset hashes were different. " +
                                    $"Expected hash {presetHash} but found hash {preset.PresetHash}" +
                                    Environment.NewLine + Environment.NewLine + $"{fileMessage}");
                            }
                            else
                            {
                                // Check if the file exists in the output directory
                                if (!File.Exists(myDocumentsTestDataFile))
                                {
                                    if (File.Exists(localTestDataFile))
                                    {
                                        File.Copy(localTestDataFile, myDocumentsTestDataFile);
                                    }
                                    else
                                    {
                                        File.WriteAllBytes(myDocumentsTestDataFile,
                                                           LZ4Pickler.Unpickle(
                                                               NullPresetPersistence.PresetData[preset.OriginalMetadata.SourceFile]));
                                    }
                                }
                                else
                                {
                                    if (!File.Exists(localTestDataFile))
                                    {
                                        testResult.DetailedErrors.Add(
                                            $"Warning: The preset data file {testFilename} exists in the documents " +
                                            "folder but not in the source folder. Copy from documents to git folder. " +
                                            "If already done, remember to clean the presetparsertest project.");
                                    }
                                }

                                var hash = HashUtils.getIxxHash(File.ReadAllBytes(myDocumentsTestDataFile));

                                if (hash != presetHash)
                                {
                                    testResult.DetailedErrors.Add(
                                        $"Warning: The preset data file {myDocumentsTestDataFile} exists but does not match the " +
                                        $"preset hash from the reference presets. Expected: {testDataEntry.Hash} found {hash}");
                                }
                            }

                            testDataEntries.Remove(testDataEntry);
                        }
                    }
                }

                if (testDataEntries.Count > 0)
                {
                    foreach (var missingTestDataEntry in testDataEntries)
                    {
                        var presetHash = missingTestDataEntry.Hash.TrimEnd();
                        testResult.DetailedErrors.Add(
                            $"Did not find preset {missingTestDataEntry.ProgramName} with bank path " +
                            $"{missingTestDataEntry.BankPath} and hash {presetHash}");
                    }

                    testResult.IsOK = false;
                }

                if (plugin.Presets.Count > 0)
                {
                    var randomPreset = plugin.Presets.OrderBy(qu => Guid.NewGuid()).First();
                    testResult.RndHash       = randomPreset.PresetHash;
                    testResult.RndPresetName = randomPreset.Metadata.PresetName;
                    testResult.RndBankPath   = randomPreset.Metadata.BankPath;
                }

                var mockFxp = Path.Combine(Directory.GetCurrentDirectory(), "mock.fxp");
                var fxp     = new FXP();
                fxp.ReadFile(Path.Combine(Directory.GetCurrentDirectory(), "test.fxp"));
                fxp.FxID = VstUtils.PluginIdNumberToIdString(pluginId);
                fxp.WriteFile(mockFxp);
                // Test additional banks
                var bankFile = new BankFile();
                bankFile.Path     = mockFxp;
                bankFile.BankName = "Default";

                plugin.AdditionalBankFiles.Clear();
                plugin.AdditionalBankFiles.Add(bankFile);

                bool additionalBankFileCountOk = false;


                if (presetParser.GetNumPresets() == testResult.ReportedPresets + 1)
                {
                    additionalBankFileCountOk = true;
                }
                else
                {
                    testResult.Error += " additionalBankFileCount failed";
                }

                plugin.Presets.Clear();
                NullPresetPersistence.PresetData.Clear();
                presetParser.DoScan().GetAwaiter().GetResult();

                var additionalBankFileScanOk = false;

                if (plugin.Presets.Count == testResult.Presets + 1)
                {
                    additionalBankFileScanOk = true;
                }
                else
                {
                    testResult.Error += " additionalBankFileScan failed";
                }

                bool bankMissingOk = false;
                if (NumBankMissingsOk.ContainsKey(testResult.PluginId))
                {
                    if (testResult.BankMissing <= NumBankMissingsOk[testResult.PluginId])
                    {
                        bankMissingOk = true;
                    }
                }
                else
                {
                    if (testResult.BankMissing < 2)
                    {
                        bankMissingOk = true;
                    }
                }

                if (hasTestDataEntries && testDataOk && testResult.Presets > 5 && bankMissingOk &&
                    testResult.Presets == testResult.ReportedPresets && additionalBankFileCountOk &&
                    additionalBankFileScanOk)
                {
                    testResult.IsOK = true;
                }

                testResults.Add(testResult);

                NullPresetPersistence.PresetData.Clear();
            }


            var consoleTable = ConsoleTable.From(from testRes in testResults
                                                 where testRes.IsOK == false
                                                 orderby testRes.Presets
                                                 select testRes);

            Console.WriteLine(consoleTable.ToMinimalString());

            foreach (var testRes in (from testRes in testResults
                                     where testRes.DetailedErrors.Count > 0
                                     orderby testRes.Presets
                                     select testRes))
            {
                Console.WriteLine(Environment.NewLine);
                Console.WriteLine($"Detailed Errors for {testRes.VendorPresetParser}");
                Console.WriteLine($"------------------------------------------------------------");

                foreach (var detailedError in testRes.DetailedErrors)
                {
                    Console.WriteLine($"Error #{testRes.DetailedErrors.IndexOf(detailedError)}: {detailedError}");
                }
            }

            Console.WriteLine($"Stuff left: {consoleTable.Rows.Count} / {presetParserDictionary.Count}");

            foreach (var data in GlobalMethodTimeLogger.GetTopMethods())
            {
                Console.WriteLine($"{data.Name}: {data.Duration.TotalSeconds.ToString()}ms");
            }

            if (hasIgnored)
            {
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
                Console.WriteLine("Warning: Filter active!!");
            }
        }