From 1994445ca9f8bb55a9f04ec50de11c1bbe9d531f Mon Sep 17 00:00:00 2001 From: Marc Jacobi Date: Sat, 9 Mar 2024 11:25:29 +0100 Subject: [PATCH] Net8 support (#69) net8 support --- Source/Code/Jacobi.Vst.CLI/CommandLineArgs.cs | 1 + Source/Code/Jacobi.Vst.CLI/FindFiles.cs | 62 +- .../Code/Jacobi.Vst.CLI/Jacobi.Vst.CLI.csproj | 8 +- Source/Code/Jacobi.Vst.CLI/Program.cs | 2 +- Source/Code/Jacobi.Vst.CLI/PublishCommand.cs | 15 +- .../Jacobi.Vst.Core/Jacobi.Vst.Core.csproj | 19 +- .../Code/Jacobi.Vst.Core/Jacobi.Vst.Core.xml | 2 +- Source/Code/Jacobi.Vst.Deployment/.gitignore | 7 - .../VstNetDeploy.targets | 8 +- .../host/VST.NET-Host.nuspec | 76 +- .../host/VST.NET2-Host.props | 15 +- .../host/VST.NET2-Host.targets | 14 +- .../plugin/VST.NET-Plugin.nuspec | 95 ++- .../plugin/VST.NET2-Plugin.props | 24 +- .../plugin/VST.NET2-Plugin.targets | 13 +- .../Code/Jacobi.Vst.Deployment/push-nuget.cmd | 4 +- .../Code/Jacobi.Vst.Deployment/push-test.cmd | 4 +- Source/Code/Jacobi.Vst.Deployment/readme.md | 2 + .../Jacobi.Vst.Host.Interop.vcxproj | 11 +- .../Jacobi.Vst.Plugin.Interop.vcxproj | 8 + .../Properties/AssemblyInfo.cpp | 2 +- .../Common/WinFormsControlWrapper.cs | 2 + .../Jacobi.Vst.Plugin.Framework.csproj | 37 +- .../CLI/NugetConfigTests.cs | 31 +- .../Core/FourCharacterCodeTest.cs | 63 +- .../Jacobi.Vst.UnitTest/Core/MaxLengthTest.cs | 463 ++++++----- .../Core/VstCanDoHelperTest.cs | 10 +- .../Jacobi.Vst.UnitTest/Core/VstEventTest.cs | 29 +- .../Core/VstPatchChunkInfoTest.cs | 12 +- .../Framework/MaxLengthTest.cs | 352 ++++---- .../Framework/VstEventCollectionTest.cs | 179 ++--- .../Framework/VstParameterCollectionTest.cs | 61 +- .../VstParameterNormalizationInfoTest.cs | 109 ++- .../Framework/VstProductInfoTest.cs | 39 +- .../Code/Jacobi.Vst.UnitTest/GlobalUsings.cs | 1 + .../Interop/Host/VstAudioBufferManagerTest.cs | 143 ++-- .../VstAudioPrecisionBufferManagerTest.cs | 143 ++-- .../Interop/Host/VstPluginContextTest.cs | 27 +- .../Jacobi.Vst.UnitTest.csproj | 28 +- Source/Code/Jacobi.Vst.sln | 21 +- Source/Code/readme.md | 4 +- .../AudioProcessor.cs | 127 ++- .../Jacobi.Vst.Samples.Delay/Dsp/Delay.cs | 131 ++- .../Dsp/DelayParameters.cs | 191 +++-- .../Jacobi.Vst.Samples.Delay.csproj | 4 +- .../Jacobi.Vst.Samples.Delay/Plugin.cs | 81 +- .../PluginCommandStub.cs | 35 +- .../Jacobi.Vst.Samples.Delay/PluginEditor.cs | 101 ++- .../PluginParameters.cs | 109 ++- .../PluginPrograms.cs | 105 ++- .../UI/PluginEditorView.cs | 183 ++--- .../DummyHostCommandStub.cs | 483 ++++++----- .../Jacobi.Vst.Samples.Host/EditorFrame.cs | 99 ++- .../Jacobi.Vst.Samples.Host.csproj | 4 +- .../Jacobi.Vst.Samples.Host/MainForm.cs | 205 +++-- .../Jacobi.Vst.Samples.Host/PluginForm.cs | 423 +++++----- .../Jacobi.Vst.Samples.Host/Program.cs | 25 +- .../AudioProcessor.cs | 73 +- .../Jacobi.Vst.Samples.MidiNoteMapper.csproj | 6 +- .../MapNoteItem.cs | 61 +- .../MidiProcessor.cs | 137 ++-- .../Plugin.cs | 39 +- .../PluginCommandStub.cs | 27 +- .../PluginEditor.cs | 105 ++- .../PluginPersistence.cs | 91 ++- .../UI/MapNoteDetails.cs | 77 +- .../UI/MidiNoteMapperView.cs | 261 +++--- .../AudioProcessor.cs | 55 +- .../Jacobi.Vst.Samples.MidiNoteSampler.csproj | 6 +- .../MidiProcessor.cs | 93 ++- .../Plugin.cs | 35 +- .../PluginCommandStub.cs | 21 +- .../SampleManager.cs | 261 +++--- .../HostCommandStubAdapter.cs | 81 +- .../Jacobi.Vst.Samples.WrapperPlugin.csproj | 6 +- .../PluginCommandStubAdapter.cs | 37 +- .../PluginCommands.cs | 753 +++++++++--------- .../UI/PluginFrame.cs | 83 +- .../Templates/CSharp/Jacobi.Vst.Templates.sln | 12 +- .../VstNetAudioPlugin/AudioProcessor.cs | 197 +++-- .../CSharp/VstNetAudioPlugin/Dsp/Delay.cs | 131 ++- .../VstNetAudioPlugin/Dsp/DelayParameters.cs | 191 +++-- .../CSharp/VstNetAudioPlugin/Plugin.cs | 111 ++- .../VstNetAudioPlugin/PluginCommandStub.cs | 35 +- .../CSharp/VstNetAudioPlugin/PluginEditor.cs | 101 ++- .../VstNetAudioPlugin/PluginParameters.cs | 109 ++- .../VstNetAudioPlugin/PluginPrograms.cs | 99 ++- .../VstNetAudioPlugin/UI/PluginEditorView.cs | 181 +++-- .../VstNetAudioPlugin.csproj | 6 +- .../VstNetAudioPlugin/VstNetAudioPlugin.zip | Bin 18880 -> 18750 bytes .../CSharp/VstNetMidiPlugin/AudioProcessor.cs | 61 +- .../CSharp/VstNetMidiPlugin/Dmp/Gain.cs | 73 +- .../VstNetMidiPlugin/Dmp/GainParameters.cs | 77 +- .../CSharp/VstNetMidiPlugin/Dmp/MidiHelper.cs | 35 +- .../CSharp/VstNetMidiPlugin/Dmp/Transpose.cs | 67 +- .../Dmp/TransposeParameters.cs | 75 +- .../CSharp/VstNetMidiPlugin/MidiProcessor.cs | 173 ++-- .../CSharp/VstNetMidiPlugin/Plugin.cs | 113 ++- .../VstNetMidiPlugin/PluginCommandStub.cs | 35 +- .../CSharp/VstNetMidiPlugin/PluginEditor.cs | 101 ++- .../VstNetMidiPlugin/PluginParameters.cs | 101 ++- .../CSharp/VstNetMidiPlugin/PluginPrograms.cs | 89 +-- .../VstNetMidiPlugin/UI/PluginEditorView.cs | 177 ++-- .../VstNetMidiPlugin/VstNetMidiPlugin.csproj | 6 +- .../VstNetMidiPlugin/VstNetMidiPlugin.zip | Bin 19862 -> 19727 bytes docs/GettingStarted.md | 6 +- docs/cli.md | 3 +- docs/media/VstNetAudioPlugin.zip | Bin 18880 -> 18750 bytes docs/media/VstNetMidiPlugin.zip | Bin 19862 -> 19727 bytes 109 files changed, 4543 insertions(+), 4582 deletions(-) delete mode 100644 Source/Code/Jacobi.Vst.Deployment/.gitignore create mode 100644 Source/Code/Jacobi.Vst.UnitTest/GlobalUsings.cs diff --git a/Source/Code/Jacobi.Vst.CLI/CommandLineArgs.cs b/Source/Code/Jacobi.Vst.CLI/CommandLineArgs.cs index d1320c54..fdb2707f 100644 --- a/Source/Code/Jacobi.Vst.CLI/CommandLineArgs.cs +++ b/Source/Code/Jacobi.Vst.CLI/CommandLineArgs.cs @@ -12,6 +12,7 @@ internal sealed class CommandLineArgs Arguments = new[] { new ArgumentInfo { Property = nameof(PublishCommand.FilePath), Description="The file to publish." }, new ArgumentInfo { Property = nameof(PublishCommand.DeployPath), Name = "-o", Description="The output directory that will receive all the files." }, + new ArgumentInfo { Property = nameof(PublishCommand.Platform), Name = "-p", Description="The CPU architecture platform (x64/x86)." }, } } }; diff --git a/Source/Code/Jacobi.Vst.CLI/FindFiles.cs b/Source/Code/Jacobi.Vst.CLI/FindFiles.cs index afb41c20..ac85b791 100644 --- a/Source/Code/Jacobi.Vst.CLI/FindFiles.cs +++ b/Source/Code/Jacobi.Vst.CLI/FindFiles.cs @@ -25,31 +25,33 @@ internal sealed class FindFiles // scan dependency files for these framework monikers. [hack] private static readonly string[] TargetFrameworkMonikers = { - "net6.0", - "net5.0", - "netcoreapp3.1", + "net8.0-windows", + "net7.0-windows", + "net6.0-windows", + //"net5.0", + //"netcoreapp3.1", "netstandard2.1", "netstandard2.0", - "netstandard1.6", - "netstandard1.5", - "netstandard1.4", - "netstandard1.3", - "netstandard1.2", - "netstandard1.1", - "netstandard1.0" + //"netstandard1.6", + //"netstandard1.5", + //"netstandard1.4", + //"netstandard1.3", + //"netstandard1.2", + //"netstandard1.1", + //"netstandard1.0" }; private readonly string _nugetPath; private readonly string _binPath; + public string Platform { get; set; } + public FindFiles(string nugetPath, string binPath) { _nugetPath = nugetPath ?? throw new ArgumentNullException(nameof(nugetPath)); _binPath = binPath ?? throw new ArgumentNullException(nameof(binPath)); } - public ProcessorArchitecture ProcessorArchitecture { get; set; } - public IEnumerable GetFilePaths(TargetName targetName) { var paths = new List(); @@ -77,14 +79,15 @@ public IEnumerable GetFilePaths(TargetName targetName) } else { - var platform = ToString(ProcessorArchitecture); - var dependencies = FindDependencyFiles(kvp.Key, platform); + var dependencies = FindDependencyFiles(kvp.Key, Platform); paths.AddRange(dependencies); - var rt = kvp.Value.RuntimeTargets?.Keys.FirstOrDefault(rt => rt.Contains(platform)); + var rt = kvp.Value.RuntimeTargets?.Keys.FirstOrDefault(rt => rt.Contains(Platform)); if (rt != null) { - paths.Add(Path.Combine(_nugetPath, kvp.Key, rt)); + var path = Path.Combine(_nugetPath, kvp.Key, rt); + if (File.Exists(path)) + paths.Add(path); } } } @@ -109,29 +112,22 @@ private IEnumerable FindDependencyFiles(string dependency, string platfo if (files.Any()) return files; } - path = Path.Combine(path, platform); - if (Directory.Exists(path)) + + if (!String.IsNullOrEmpty(platform)) { - var files = Directory.EnumerateFiles(path, fileExt); - if (files.Any()) - return files; + path = Path.Combine(path, platform); + if (Directory.Exists(path)) + { + var files = Directory.EnumerateFiles(path, fileExt); + if (files.Any()) + return files; + } } } ConsoleOutput.Warning( - $"No library files (*.dll) could be found for: {dependency}!"); + $"No library files (*.dll) could be found for: '{dependency}' ({platform})!"); return Enumerable.Empty(); } - - private static string ToString(ProcessorArchitecture processorArchitecture) - { - return processorArchitecture switch - { - ProcessorArchitecture.Amd64 => "x64", - ProcessorArchitecture.X86 => "x86", - ProcessorArchitecture.MSIL => "AnyCPU", - _ => string.Empty - }; - } } } diff --git a/Source/Code/Jacobi.Vst.CLI/Jacobi.Vst.CLI.csproj b/Source/Code/Jacobi.Vst.CLI/Jacobi.Vst.CLI.csproj index 7afef851..1e551d0a 100644 --- a/Source/Code/Jacobi.Vst.CLI/Jacobi.Vst.CLI.csproj +++ b/Source/Code/Jacobi.Vst.CLI/Jacobi.Vst.CLI.csproj @@ -2,14 +2,15 @@ Exe - net6.0 + net6.0-windows;net7.0-windows;net8.0-windows + latest vstnet - 2.0.2 + 2.0.3 Marc Jacobi Jacobi Software VST.NET VST.NET 2 Command Line Interface - Copyright © 2008-2021 Jacobi Software + Copyright © 2008-2024 Jacobi Software vst vstnet cli false LGPL-2.1-only @@ -19,6 +20,7 @@ VST.NET2-CLI 2.0.3.0 2.0.3.0 + AnyCPU diff --git a/Source/Code/Jacobi.Vst.CLI/Program.cs b/Source/Code/Jacobi.Vst.CLI/Program.cs index acc82570..6691e667 100644 --- a/Source/Code/Jacobi.Vst.CLI/Program.cs +++ b/Source/Code/Jacobi.Vst.CLI/Program.cs @@ -57,7 +57,7 @@ private static void DisplayVersion() var assembly = Assembly.GetExecutingAssembly(); ConsoleOutput.Information($"VST.NET Command Line Interface. Version {assembly.GetName().Version}."); - ConsoleOutput.Information("Copyright © 2008-2021 Jacobi Software."); + ConsoleOutput.Information("Copyright © 2008-2024 Jacobi Software."); ConsoleOutput.NewLine(); } } diff --git a/Source/Code/Jacobi.Vst.CLI/PublishCommand.cs b/Source/Code/Jacobi.Vst.CLI/PublishCommand.cs index 076e2172..9af913e7 100644 --- a/Source/Code/Jacobi.Vst.CLI/PublishCommand.cs +++ b/Source/Code/Jacobi.Vst.CLI/PublishCommand.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Linq; -using System.Reflection; using System.Text.Json; namespace Jacobi.Vst.CLI @@ -27,7 +26,8 @@ public bool Execute() DeployPath = @".\deploy"; } FileExtensions.EnsureDirectoryExists(DeployPath); - DeployBinPath = Path.Combine(DeployPath, "bin"); + //DeployBinPath = Path.Combine(DeployPath, "bin"); + DeployBinPath = DeployPath; FileExtensions.EnsureDirectoryExists(DeployBinPath); var depsFile = GetDepsFile(); @@ -40,18 +40,16 @@ public bool Execute() var plugin = GetPluginFile(); var host = GetHostFile(); - var assemblyName = AssemblyName.GetAssemblyName(plugin ?? host); - if (host != null) { - CopyDependencies(depsFile, DeployPath, assemblyName.ProcessorArchitecture); + CopyDependencies(depsFile, DeployPath); PublishHost(host); return true; } if (plugin != null) { - CopyDependencies(depsFile, DeployBinPath, assemblyName.ProcessorArchitecture); + CopyDependencies(depsFile, DeployBinPath); PublishPlugin(plugin); return true; } @@ -64,8 +62,9 @@ public bool Execute() public string DeployPath { get; set; } public string DeployBinPath { get; set; } public string FilePath { get; set; } + public string Platform { get; set; } - private void CopyDependencies(string depsFile, string deployPath, ProcessorArchitecture processorArchitecture) + private void CopyDependencies(string depsFile, string deployPath) { ConsoleOutput.Progress($"Copying dependencies to: {deployPath}"); using var stream = File.OpenRead(depsFile); @@ -73,7 +72,7 @@ private void CopyDependencies(string depsFile, string deployPath, ProcessorArchi var finder = new FindFiles(NuGetPath, Path.GetDirectoryName(FilePath)) { - ProcessorArchitecture = processorArchitecture + Platform = Platform }; var paths = finder.GetFilePaths(json.Targets.First().Value); diff --git a/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.csproj b/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.csproj index fcb02c3f..3dc38cc0 100644 --- a/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.csproj +++ b/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.csproj @@ -1,16 +1,17 @@  - net6.0 - 2.0.0.0 - 2.0.0.0 - 2.0.0 + net6.0-windows;net7.0-windows;net8.0-windows + latest + 2.0.1.0 + 2.0.1.0 + 2.0.1 Marc Jacobi Jacobi Software VST.NET x64;x86 enable - Jacobi Software © 2008-2021 + Copyright © 2008-2024 Jacobi Software LGPL-2.1-only https://github.com/obiwanjacobi/vst.net https://github.com/obiwanjacobi/vst.net @@ -45,9 +46,15 @@ Jacobi.Vst.Core.xml - + + + + + + + diff --git a/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.xml b/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.xml index 896dea86..89f0f7ef 100644 --- a/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.xml +++ b/Source/Code/Jacobi.Vst.Core/Jacobi.Vst.Core.xml @@ -1316,7 +1316,7 @@ Thrown when the is empty. Thrown when no suitable managed Plugin assembly could be found. Note that the managed plugin assembly must be named exactly the same as the - but with a .net.dll or a .net.vstdll extension. + but with a .net.vst2 extension. diff --git a/Source/Code/Jacobi.Vst.Deployment/.gitignore b/Source/Code/Jacobi.Vst.Deployment/.gitignore deleted file mode 100644 index 59de6d9e..00000000 --- a/Source/Code/Jacobi.Vst.Deployment/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -lib -ref -runtimes -content -tools -.nupkg -.zip \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/VstNetDeploy.targets b/Source/Code/Jacobi.Vst.Deployment/VstNetDeploy.targets index 515df3a6..3cbaecb8 100644 --- a/Source/Code/Jacobi.Vst.Deployment/VstNetDeploy.targets +++ b/Source/Code/Jacobi.Vst.Deployment/VstNetDeploy.targets @@ -1,16 +1,16 @@ - "$(MSBuildThisFileDirectory)/../tools/net6.0/vstnet.exe" + "$(MSBuildThisFileDirectory)..\tools\$(TargetFramework)\vstnet.exe" "$(TargetDir)deploy" - - + + - + diff --git a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET-Host.nuspec b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET-Host.nuspec index efc8d8d0..3cf80f5b 100644 --- a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET-Host.nuspec +++ b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET-Host.nuspec @@ -3,7 +3,7 @@ VST.NET2-Host VST.NET 2.0 Library for Hosts - 2.1.0 + 2.1.1 Marc Jacobi Jacobi Software LGPL-2.1-only @@ -11,37 +11,73 @@ false - VST.NET dotnet 6 primary assemblies for building a VST2 host application. - - - Copyright © 2008-2022 Jacobi Software + VST.NET dotnet 6, 7 and 8 primary assemblies for building a VST2 host application in Windows. + + Copyright © 2008-2024 Jacobi Software vst vstnet - + + + + + + + + + + + + + + + + - - - - - - - - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.props b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.props index 30994c19..d7ea313f 100644 --- a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.props +++ b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.props @@ -1,18 +1,11 @@  - - $(MSBuildThisFileDirectory)..\lib\net6.0\x86\Jacobi.Vst.Core.dll + + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Core.dll - - $(MSBuildThisFileDirectory)..\lib\net6.0\x86\Jacobi.Vst.Host.Interop.dll - - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x64\Jacobi.Vst.Core.dll - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x64\Jacobi.Vst.Host.Interop.dll + + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Host.Interop.dll \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.targets b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.targets index cc734b26..a55b7957 100644 --- a/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.targets +++ b/Source/Code/Jacobi.Vst.Deployment/host/VST.NET2-Host.targets @@ -2,23 +2,23 @@ - + - - - + + + - $(MSBuildThisFileDirectory)..\lib\net6.0\$(Platform)\Jacobi.Vst.Core.dll + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Core.dll - $(MSBuildThisFileDirectory)..\lib\net6.0\$(Platform)\Jacobi.Vst.Host.Interop.dll + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Host.Interop.dll - + Ijwhost.dll PreserveNewest diff --git a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET-Plugin.nuspec b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET-Plugin.nuspec index e28c6f45..9cb99b3b 100644 --- a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET-Plugin.nuspec +++ b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET-Plugin.nuspec @@ -3,7 +3,7 @@ VST.NET2-Plugin VST.NET 2.0 Library for Plugins - 2.1.0 + 2.1.1 Marc Jacobi Jacobi Software LGPL-2.1-only @@ -11,43 +11,92 @@ false - VST.NET dotnet 6 primary assemblies for building a VST2 plugin. + VST.NET dotnet 6, 7 and 8 primary assemblies for building a VST2 plugin in Windows. - Copyright © 2008-2022 Jacobi Software + Copyright © 2008-2024 Jacobi Software vst vstnet - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.props b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.props index c9622301..d593ffc5 100644 --- a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.props +++ b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.props @@ -1,24 +1,14 @@  - - $(MSBuildThisFileDirectory)..\lib\net6.0\x86\Jacobi.Vst.Core.dll + + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Core.dll - - $(MSBuildThisFileDirectory)..\lib\net6.0\x86\Jacobi.Vst.Plugin.Interop.dll - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x86\Jacobi.Vst.Plugin.Framework.dll - - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x64\Jacobi.Vst.Core.dll - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x64\Jacobi.Vst.Plugin.Interop.dll - - - $(MSBuildThisFileDirectory)..\lib\net6.0\x64\Jacobi.Vst.Plugin.Framework.dll + + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Plugin.Interop.dll + + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Plugin.Framework.dll + \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.targets b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.targets index 29287648..76f299fb 100644 --- a/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.targets +++ b/Source/Code/Jacobi.Vst.Deployment/plugin/VST.NET2-Plugin.targets @@ -2,19 +2,20 @@ - + - - + + + - $(MSBuildThisFileDirectory)..\lib\net6.0\$(Platform)\Jacobi.Vst.Core.dll + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Core.dll - $(MSBuildThisFileDirectory)..\lib\net6.0\$(Platform)\Jacobi.Vst.Plugin.Framework.dll + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Plugin.Framework.dll - $(MSBuildThisFileDirectory)..\lib\net6.0\$(Platform)\Jacobi.Vst.Plugin.Interop.dll + $(MSBuildThisFileDirectory)..\lib\$(TargetFramework)\$(Platform)\Jacobi.Vst.Plugin.Interop.dll diff --git a/Source/Code/Jacobi.Vst.Deployment/push-nuget.cmd b/Source/Code/Jacobi.Vst.Deployment/push-nuget.cmd index 057ac575..45ac52f1 100644 --- a/Source/Code/Jacobi.Vst.Deployment/push-nuget.cmd +++ b/Source/Code/Jacobi.Vst.Deployment/push-nuget.cmd @@ -1,2 +1,2 @@ -nuget push VST.NET2-Host.2.1.0.nupkg -src https://api.nuget.org/v3/index.json -nuget push VST.NET2-Plugin.2.1.0.nupkg -src https://api.nuget.org/v3/index.json +nuget push VST.NET2-Host.2.1.1.nupkg -src https://api.nuget.org/v3/index.json +nuget push VST.NET2-Plugin.2.1.1.nupkg -src https://api.nuget.org/v3/index.json diff --git a/Source/Code/Jacobi.Vst.Deployment/push-test.cmd b/Source/Code/Jacobi.Vst.Deployment/push-test.cmd index 15e67dee..68992470 100644 --- a/Source/Code/Jacobi.Vst.Deployment/push-test.cmd +++ b/Source/Code/Jacobi.Vst.Deployment/push-test.cmd @@ -1,2 +1,2 @@ -nuget push VST.NET2-Host.2.1.0.nupkg -src LocalPackageTest -nuget push VST.NET2-Plugin.2.1.0.nupkg -src LocalPackageTest \ No newline at end of file +nuget push VST.NET2-Host.2.1.1.nupkg -src LocalPackageTest +nuget push VST.NET2-Plugin.2.1.1.nupkg -src LocalPackageTest \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Deployment/readme.md b/Source/Code/Jacobi.Vst.Deployment/readme.md index 32afe248..57a99df9 100644 --- a/Source/Code/Jacobi.Vst.Deployment/readme.md +++ b/Source/Code/Jacobi.Vst.Deployment/readme.md @@ -6,3 +6,5 @@ ## Resources https://natemcmaster.com/blog/2017/11/11/build-tools-in-nuget/ + +Create a build bin log: `dotnet build /bl` Use [MSBuild Structured log viewer](https://www.msbuildlog.com/) \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Host.Interop.vcxproj b/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Host.Interop.vcxproj index 06c411eb..58d66e05 100644 --- a/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Host.Interop.vcxproj +++ b/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Host.Interop.vcxproj @@ -25,7 +25,8 @@ Win32Proj JacobiVstInterop 10.0 - .NET6.0 + net6.0 + 7.0 @@ -124,6 +125,8 @@ Properties\Resources.resx;%(EmbedManagedResourceFile) MTAThreadingAttribute + + manifest.xml @@ -154,6 +157,8 @@ Properties\Resources.resx;%(EmbedManagedResourceFile) MTAThreadingAttribute + + manifest.xml @@ -191,6 +196,8 @@ MTAThreadingAttribute + + manifest.xml @@ -228,6 +235,8 @@ MTAThreadingAttribute + + manifest.xml diff --git a/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Plugin.Interop.vcxproj b/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Plugin.Interop.vcxproj index 31440f92..7d01057c 100644 --- a/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Plugin.Interop.vcxproj +++ b/Source/Code/Jacobi.Vst.Interop/Jacobi.Vst.Plugin.Interop.vcxproj @@ -121,6 +121,8 @@ Properties\Resources.resx;%(EmbedManagedResourceFile) MTAThreadingAttribute + + @@ -152,6 +154,8 @@ Properties\Resources.resx;%(EmbedManagedResourceFile) MTAThreadingAttribute + + @@ -190,6 +194,8 @@ MTAThreadingAttribute + + manifest.xml @@ -224,6 +230,8 @@ MTAThreadingAttribute + + manifest.xml diff --git a/Source/Code/Jacobi.Vst.Interop/Properties/AssemblyInfo.cpp b/Source/Code/Jacobi.Vst.Interop/Properties/AssemblyInfo.cpp index 92031c8e..ebe99c05 100644 --- a/Source/Code/Jacobi.Vst.Interop/Properties/AssemblyInfo.cpp +++ b/Source/Code/Jacobi.Vst.Interop/Properties/AssemblyInfo.cpp @@ -16,7 +16,7 @@ using namespace System::Runtime::InteropServices; // legal stuff [assembly:AssemblyCompany("Jacobi Software")]; -[assembly:AssemblyCopyright("Copyright © 2008-2021 Jacobi Software")] ; +[assembly:AssemblyCopyright("Copyright © 2008-2024 Jacobi Software")] ; [assembly:AssemblyTrademark("obiwanjacobi")] ; [assembly:AssemblyInformationalVersionAttribute("2.0.3")] diff --git a/Source/Code/Jacobi.Vst.Plugin.Framework/Common/WinFormsControlWrapper.cs b/Source/Code/Jacobi.Vst.Plugin.Framework/Common/WinFormsControlWrapper.cs index 88be2383..ef5af6ad 100644 --- a/Source/Code/Jacobi.Vst.Plugin.Framework/Common/WinFormsControlWrapper.cs +++ b/Source/Code/Jacobi.Vst.Plugin.Framework/Common/WinFormsControlWrapper.cs @@ -2,12 +2,14 @@ { using System; using System.Drawing; + using System.Runtime.Versioning; using System.Windows.Forms; /// /// This wrapper class makes it easy to use a WinForms (User) Control as an Editor UI. /// /// The type of WinForms (User) Control. + [SupportedOSPlatform("windows")] public sealed class WinFormsControlWrapper : IDisposable where T : Control, new() { diff --git a/Source/Code/Jacobi.Vst.Plugin.Framework/Jacobi.Vst.Plugin.Framework.csproj b/Source/Code/Jacobi.Vst.Plugin.Framework/Jacobi.Vst.Plugin.Framework.csproj index 029c8d0b..94a53785 100644 --- a/Source/Code/Jacobi.Vst.Plugin.Framework/Jacobi.Vst.Plugin.Framework.csproj +++ b/Source/Code/Jacobi.Vst.Plugin.Framework/Jacobi.Vst.Plugin.Framework.csproj @@ -1,13 +1,14 @@  - net6.0 - 2.0.0.0 - 2.0.0.0 + net6.0-windows;net7.0-windows;net8.0-windows + latest + 2.0.1.0 + 2.0.1.0 Marc Jacobi Jacobi Software VST.NET - 2.0.0 + 2.0.1 x64;x86 enable LGPL-2.1-only @@ -15,7 +16,7 @@ https://github.com/obiwanjacobi/vst.net git vst vstnet - Copyright © 2008-2021 Jacobi Software + Copyright © 2008-2024 Jacobi Software VST.NET 2 Plugin Framework @@ -40,27 +41,27 @@ Jacobi.Vst.Plugin.Framework.xml - + - - + + - - - + + + + + + + - + - - True - True - Resources.resx - + @@ -77,5 +78,5 @@ Resources.Designer.cs - + diff --git a/Source/Code/Jacobi.Vst.UnitTest/CLI/NugetConfigTests.cs b/Source/Code/Jacobi.Vst.UnitTest/CLI/NugetConfigTests.cs index acbaadb6..c1f0a622 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/CLI/NugetConfigTests.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/CLI/NugetConfigTests.cs @@ -1,26 +1,23 @@ using FluentAssertions; using Jacobi.Vst.CLI; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.CLI +namespace Jacobi.Vst.UnitTest.CLI; + +public class NugetConfigTests { - [TestClass] - public class NugetConfigTests + [Fact] + public void ReadConfig() { - [TestMethod] - public void ReadConfig() - { - var configPath = TestFile.FullPath("CLI", "TestNuGet.config.xml"); - var cfg = NugetConfig.Load(configPath); + var configPath = TestFile.FullPath("CLI", "TestNuGet.config.xml"); + var cfg = NugetConfig.Load(configPath); - cfg.PackagePath.Should().Be("PathToGlobalPackages"); - } + cfg.PackagePath.Should().Be("PathToGlobalPackages"); + } - [TestMethod] - public void GetNuGetLocation() - { - var location = FileExtensions.GetNuGetLocation(); - location.Should().NotBeNullOrEmpty(); - } + [Fact] + public void GetNuGetLocation() + { + var location = FileExtensions.GetNuGetLocation(); + location.Should().NotBeNullOrEmpty(); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Core/FourCharacterCodeTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Core/FourCharacterCodeTest.cs index beabd762..6157aa28 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Core/FourCharacterCodeTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Core/FourCharacterCodeTest.cs @@ -1,43 +1,40 @@ using FluentAssertions; using Jacobi.Vst.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Core +namespace Jacobi.Vst.UnitTest.Core; + +/// +/// This is a test class for FourCharacterCodeTest and is intended +/// to contain all FourCharacterCodeTest Unit Tests +/// +public class FourCharacterCodeTest { - /// - /// This is a test class for FourCharacterCodeTest and is intended - /// to contain all FourCharacterCodeTest Unit Tests - /// - [TestClass()] - public class FourCharacterCodeTest + [Fact] + public void Test_FourCharacterCode_Value() { - [TestMethod()] - public void Test_FourCharacterCode_Value() - { - var fcc = new FourCharacterCode("ABCD"); - fcc.Value.Should().Be("ABCD"); - fcc.ToString().Should().Be("ABCD"); - } + var fcc = new FourCharacterCode("ABCD"); + fcc.Value.Should().Be("ABCD"); + fcc.ToString().Should().Be("ABCD"); + } - [TestMethod()] - public void Test_FourCharacterCode_ToInt32() - { - var fcc = new FourCharacterCode("ABCD"); - fcc.ToInt32().Should().Be(0x41424344); - } + [Fact] + public void Test_FourCharacterCode_ToInt32() + { + var fcc = new FourCharacterCode("ABCD"); + fcc.ToInt32().Should().Be(0x41424344); + } - [TestMethod()] - public void Test_FourCharacterCode_ConstructChars() - { - var fcc = new FourCharacterCode('A', 'B', 'C', 'D'); - fcc.ToString().Should().Be("ABCD"); - } + [Fact] + public void Test_FourCharacterCode_ConstructChars() + { + var fcc = new FourCharacterCode('A', 'B', 'C', 'D'); + fcc.ToString().Should().Be("ABCD"); + } - [TestMethod()] - public void Test_FourCharacterCode_ConstructString() - { - var fcc = new FourCharacterCode("ABCD"); - fcc.ToString().Should().Be("ABCD"); - } + [Fact] + public void Test_FourCharacterCode_ConstructString() + { + var fcc = new FourCharacterCode("ABCD"); + fcc.ToString().Should().Be("ABCD"); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Core/MaxLengthTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Core/MaxLengthTest.cs index 57143395..0beabcdc 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Core/MaxLengthTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Core/MaxLengthTest.cs @@ -1,247 +1,232 @@ using FluentAssertions; using Jacobi.Vst.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -namespace Jacobi.Vst.UnitTest.Core +namespace Jacobi.Vst.UnitTest.Core; + +/// +/// Summary description for MaxLengthTest +/// +public class MaxLengthTest { - /// - /// Summary description for MaxLengthTest - /// - [TestClass] - public class MaxLengthTest + private string CreateString(int length) + { + return new string('x', length); + } + + [Fact] + public void Test_MaxLength_VstFileSelect_Title() + { + var fs = new VstFileSelect(); + fs.Title.Should().BeEmpty(); + + fs.Title = String.Empty; + fs.Title.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxFileSelectorTitle); + fs.Title = testData; + fs.Title.Should().Be(testData); + + testData += "X"; + Action err = () => fs.Title = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstFileType_Name() { - private string CreateString(int length) - { - return new string('x', length); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstFileSelect_Title() - { - var fs = new VstFileSelect(); - fs.Title.Should().BeEmpty(); - - fs.Title = String.Empty; - fs.Title.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxFileSelectorTitle); - fs.Title = testData; - fs.Title.Should().Be(testData); - - testData += "X"; - fs.Title = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstFileType_Name() - { - var ft = new VstFileType(); - ft.Name.Should().BeEmpty(); - - ft.Name = String.Empty; - ft.Name.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxFileTypeName); - ft.Name = testData; - ft.Name.Should().Be(testData); - - testData += "X"; - ft.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstFileType_Extension() - { - var ft = new VstFileType(); - ft.Extension.Should().BeEmpty(); - - ft.Extension = String.Empty; - ft.Extension.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxFileTypeExtension); - ft.Extension = testData; - ft.Extension.Should().Be(testData); - - testData += "X"; - ft.Extension = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstVstMidiKeyName_Name() - { - var mkn = new VstMidiKeyName(); - mkn.Name.Should().BeEmpty(); - - mkn.Name = String.Empty; - mkn.Name.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxMidiNameLength); - mkn.Name = testData; - mkn.Name.Should().Be(testData); - - testData += "X"; - mkn.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstMidiProgramCategory_Name() - { - var mpc = new VstMidiProgramCategory(); - mpc.Name.Should().BeEmpty(); - - mpc.Name = String.Empty; - mpc.Name.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxMidiNameLength); - mpc.Name = testData; - mpc.Name.Should().Be(testData); - - testData += "X"; - mpc.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstMidiProgramName_Name() - { - var mpn = new VstMidiProgramName(); - mpn.Name.Should().BeEmpty(); - - mpn.Name = String.Empty; - mpn.Name.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxMidiNameLength); - mpn.Name = testData; - mpn.Name.Should().Be(testData); - - testData += "X"; - mpn.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterProperties_Label() - { - var mpn = new VstParameterProperties(); - mpn.Label.Should().BeEmpty(); - - mpn.Label = String.Empty; - mpn.Label.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxLabelLength); - mpn.Label = testData; - mpn.Label.Should().Be(testData); - - testData += "X"; - mpn.Label = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterProperties_ShortLabel() - { - var mpn = new VstParameterProperties(); - mpn.ShortLabel.Should().BeEmpty(); - - mpn.ShortLabel = String.Empty; - mpn.ShortLabel.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxShortLabelLength); - mpn.ShortLabel = testData; - mpn.ShortLabel.Should().Be(testData); - - testData += "X"; - mpn.ShortLabel = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterProperties_CategoryLabel() - { - var mpn = new VstParameterProperties(); - mpn.CategoryLabel.Should().BeEmpty(); - - mpn.CategoryLabel = String.Empty; - mpn.CategoryLabel.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxLabelLength); - mpn.CategoryLabel = testData; - mpn.CategoryLabel.Should().Be(testData); - - testData += "X"; - mpn.CategoryLabel = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstPinProperties_Label() - { - var pp = new VstPinProperties(); - pp.Label.Should().BeEmpty(); - - pp.Label = String.Empty; - pp.Label.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxLabelLength); - pp.Label = testData; - pp.Label.Should().Be(testData); - - testData += "X"; - pp.Label = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstPinProperties_ShortLabel() - { - var mpn = new VstPinProperties(); - mpn.ShortLabel.Should().BeEmpty(); - - mpn.ShortLabel = String.Empty; - mpn.ShortLabel.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxShortLabelLength); - mpn.ShortLabel = testData; - mpn.ShortLabel.Should().Be(testData); - - testData += "X"; - mpn.ShortLabel = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstSpeakerProperties_Name() - { - var mpn = new VstSpeakerProperties(); - mpn.Name.Should().BeEmpty(); - - mpn.Name = String.Empty; - mpn.Name.Should().BeEmpty(); - - string testData = CreateString(Constants.MaxMidiNameLength); - mpn.Name = testData; - mpn.Name.Should().Be(testData); - - testData += "X"; - mpn.Name = testData; - Assert.Fail("should have thrown an exception."); - } + var ft = new VstFileType(); + ft.Name.Should().BeEmpty(); + + ft.Name = String.Empty; + ft.Name.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxFileTypeName); + ft.Name = testData; + ft.Name.Should().Be(testData); + + testData += "X"; + Action err = () => ft.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstFileType_Extension() + { + var ft = new VstFileType(); + ft.Extension.Should().BeEmpty(); + + ft.Extension = String.Empty; + ft.Extension.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxFileTypeExtension); + ft.Extension = testData; + ft.Extension.Should().Be(testData); + + testData += "X"; + Action err = () => ft.Extension = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstVstMidiKeyName_Name() + { + var mkn = new VstMidiKeyName(); + mkn.Name.Should().BeEmpty(); + + mkn.Name = String.Empty; + mkn.Name.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxMidiNameLength); + mkn.Name = testData; + mkn.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mkn.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstMidiProgramCategory_Name() + { + var mpc = new VstMidiProgramCategory(); + mpc.Name.Should().BeEmpty(); + + mpc.Name = String.Empty; + mpc.Name.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxMidiNameLength); + mpc.Name = testData; + mpc.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mpc.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstMidiProgramName_Name() + { + var mpn = new VstMidiProgramName(); + mpn.Name.Should().BeEmpty(); + + mpn.Name = String.Empty; + mpn.Name.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxMidiNameLength); + mpn.Name = testData; + mpn.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterProperties_Label() + { + var mpn = new VstParameterProperties(); + mpn.Label.Should().BeEmpty(); + + mpn.Label = String.Empty; + mpn.Label.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxLabelLength); + mpn.Label = testData; + mpn.Label.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.Label = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterProperties_ShortLabel() + { + var mpn = new VstParameterProperties(); + mpn.ShortLabel.Should().BeEmpty(); + + mpn.ShortLabel = String.Empty; + mpn.ShortLabel.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxShortLabelLength); + mpn.ShortLabel = testData; + mpn.ShortLabel.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.ShortLabel = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterProperties_CategoryLabel() + { + var mpn = new VstParameterProperties(); + mpn.CategoryLabel.Should().BeEmpty(); + + mpn.CategoryLabel = String.Empty; + mpn.CategoryLabel.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxLabelLength); + mpn.CategoryLabel = testData; + mpn.CategoryLabel.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.CategoryLabel = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstPinProperties_Label() + { + var pp = new VstPinProperties(); + pp.Label.Should().BeEmpty(); + + pp.Label = String.Empty; + pp.Label.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxLabelLength); + pp.Label = testData; + pp.Label.Should().Be(testData); + + testData += "X"; + Action err = () => pp.Label = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstPinProperties_ShortLabel() + { + var mpn = new VstPinProperties(); + mpn.ShortLabel.Should().BeEmpty(); + + mpn.ShortLabel = String.Empty; + mpn.ShortLabel.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxShortLabelLength); + mpn.ShortLabel = testData; + mpn.ShortLabel.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.ShortLabel = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstSpeakerProperties_Name() + { + var mpn = new VstSpeakerProperties(); + mpn.Name.Should().BeEmpty(); + + mpn.Name = String.Empty; + mpn.Name.Should().BeEmpty(); + + string testData = CreateString(Constants.MaxMidiNameLength); + mpn.Name = testData; + mpn.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mpn.Name = testData; + err.Should().Throw(); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Core/VstCanDoHelperTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Core/VstCanDoHelperTest.cs index a52bab1c..45c05a03 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Core/VstCanDoHelperTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Core/VstCanDoHelperTest.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Jacobi.Vst.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Jacobi.Vst.UnitTest.Core { @@ -8,10 +7,9 @@ namespace Jacobi.Vst.UnitTest.Core ///This is a test class for VstCanDoHelperTest and is intended ///to contain all VstCanDoHelperTest Unit Tests /// - [TestClass()] public class VstCanDoHelperTest { - [TestMethod()] + [Fact] public void Test_VstCanDoHelper_HostCanDo_ToString() { VstHostCanDo cando = VstHostCanDo.EditFile; @@ -23,7 +21,7 @@ public void Test_VstCanDoHelper_HostCanDo_ToString() actual.Should().Be("supplyIdle"); } - [TestMethod()] + [Fact] public void Test_VstCanDoHelper_PluginCanDo_ToString() { VstPluginCanDo cando = VstPluginCanDo.Bypass; @@ -35,7 +33,7 @@ public void Test_VstCanDoHelper_PluginCanDo_ToString() actual.Should().Be("1in1out"); } - [TestMethod()] + [Fact] public void Test_VstCanDoHelper_ParsePluginCanDo() { string cando = "1in1out"; @@ -47,7 +45,7 @@ public void Test_VstCanDoHelper_ParsePluginCanDo() actual.Should().Be(VstPluginCanDo.Bypass); } - [TestMethod()] + [Fact] public void Test_VstCanDoHelper_ParseHostCanDo() { string cando = "editFile"; diff --git a/Source/Code/Jacobi.Vst.UnitTest/Core/VstEventTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Core/VstEventTest.cs index 59ec550c..4ba7cf94 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Core/VstEventTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Core/VstEventTest.cs @@ -1,7 +1,6 @@ using FluentAssertions; using Jacobi.Vst.Core; using Jacobi.Vst.Core.Legacy; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; namespace Jacobi.Vst.UnitTest.Core @@ -10,10 +9,9 @@ namespace Jacobi.Vst.UnitTest.Core ///This is a test class for VstMidiEventTest and is intended ///to contain all VstMidiEventTest Unit Tests /// - [TestClass()] public class VstEventTest { - [TestMethod()] + [Fact] public void Test_VstMidiEvent_Constructor() { int deltaFrames = 12; @@ -37,7 +35,7 @@ public void Test_VstMidiEvent_Constructor() me.NoteOffVelocity.Should().Be(noteOffVelocity); } - [TestMethod()] + [Fact] public void Test_VstMidiSysExEvent_Constructor() { int deltaFrames = 12; @@ -53,7 +51,7 @@ public void Test_VstMidiSysExEvent_Constructor() me.Data[2].Should().Be(sysexData[2]); } - [TestMethod()] + [Fact] public void Test_VstGenericEvent_Constructor() { var eventType = VstEventTypes.LegacyAudioEvent; @@ -71,43 +69,40 @@ public void Test_VstGenericEvent_Constructor() ge.Data[2].Should().Be(data[2]); } - [TestMethod()] - [ExpectedException(typeof(ArgumentException))] + [Fact] public void Test_VstGenericEvent_MidiEvent() { VstEventTypes eventType = VstEventTypes.MidiEvent; int deltaFrames = 12; byte[] data = new byte[] { 0x9C, 0x7F, 0x40 }; - new VstGenericEvent(eventType, deltaFrames, data); + Action err = () => new VstGenericEvent(eventType, deltaFrames, data); - Assert.Fail("Should have thrown an excepction."); + err.Should().Throw(); } - [TestMethod()] - [ExpectedException(typeof(ArgumentException))] + [Fact] public void Test_VstGenericEvent_MidiSysExEvent() { VstEventTypes eventType = VstEventTypes.MidiSysExEvent; int deltaFrames = 12; byte[] data = new byte[] { 0x9C, 0x7F, 0x40 }; - new VstGenericEvent(eventType, deltaFrames, data); + Action err = () => new VstGenericEvent(eventType, deltaFrames, data); - Assert.Fail("Should have thrown an excepction."); + err.Should().Throw(); } - [TestMethod()] - [ExpectedException(typeof(ArgumentException))] + [Fact] public void Test_VstGenericEvent_Unknown() { VstEventTypes eventType = VstEventTypes.Unknown; int deltaFrames = 12; byte[] data = new byte[] { 0x9C, 0x7F, 0x40 }; - new VstGenericEvent(eventType, deltaFrames, data); + Action err = () => new VstGenericEvent(eventType, deltaFrames, data); - Assert.Fail("Should have thrown an excepction."); + err.Should().Throw(); } } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Core/VstPatchChunkInfoTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Core/VstPatchChunkInfoTest.cs index 67b20aae..9101f97c 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Core/VstPatchChunkInfoTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Core/VstPatchChunkInfoTest.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Jacobi.Vst.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Jacobi.Vst.UnitTest.Core { @@ -8,16 +7,15 @@ namespace Jacobi.Vst.UnitTest.Core ///This is a test class for VstPatchChunkInfoTest and is intended ///to contain all VstPatchChunkInfoTest Unit Tests /// - [TestClass()] public class VstPatchChunkInfoTest { - [TestMethod()] + [Fact] public void Test_VstPatchChunkInfoConstructor() { - int version = 1000; - int pluginId = 0x41424344; - int pluginVersion = 1234; - int elementCount = 56; + const int version = 1000; + const int pluginId = 0x41424344; + const int pluginVersion = 1234; + const int elementCount = 56; var pci = new VstPatchChunkInfo(version, pluginId, pluginVersion, elementCount); diff --git a/Source/Code/Jacobi.Vst.UnitTest/Framework/MaxLengthTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Framework/MaxLengthTest.cs index bf1b35a5..6875d5c0 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Framework/MaxLengthTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Framework/MaxLengthTest.cs @@ -1,191 +1,179 @@ using FluentAssertions; using Jacobi.Vst.Core; using Jacobi.Vst.Plugin.Framework; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -namespace Jacobi.Vst.UnitTest.Framework +namespace Jacobi.Vst.UnitTest.Framework; + +/// +/// Summary description for MaxLengthTest +/// +public class MaxLengthTest { - /// - /// Summary description for MaxLengthTest - /// - [TestClass] - public class MaxLengthTest + private string CreateString(int length) + { + return new string('x', length); + } + + [Fact] + public void Test_MaxLength_VstConnectionInfo_Label() + { + var ci = new VstConnectionInfo(); + ci.Label.Should().BeEmpty(); + + ci.Label = String.Empty; + ci.Label.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxLabelLength); + ci.Label = testData; + ci.Label.Should().Be(testData); + + testData += "X"; + Action err = () => ci.Label = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstConnectionInfo_ShortLabel() + { + var ci = new VstConnectionInfo(); + ci.ShortLabel.Should().BeEmpty(); + + ci.ShortLabel = String.Empty; + ci.ShortLabel.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxShortLabelLength); + ci.ShortLabel = testData; + ci.ShortLabel.Should().Be(testData); + + testData += "X"; + Action err = () => ci.ShortLabel = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstMidiCategory_Name() + { + var mc = new VstMidiCategory(); + mc.Name.Should().BeEmpty(); + + mc.Name = String.Empty; + mc.Name.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxMidiNameLength); + mc.Name = testData; + mc.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mc.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstMidiProgram_Name() + { + var mp = new VstMidiProgram(); + mp.Name.Should().BeEmpty(); + + mp.Name = String.Empty; + mp.Name.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxMidiNameLength); + mp.Name = testData; + mp.Name.Should().Be(testData); + + testData += "X"; + Action err = () => mp.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterCategory_Name() { - private string CreateString(int length) - { - return new string('x', length); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstConnectionInfo_Label() - { - var ci = new VstConnectionInfo(); - ci.Label.Should().BeEmpty(); - - ci.Label = String.Empty; - ci.Label.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxLabelLength); - ci.Label = testData; - ci.Label.Should().Be(testData); - - testData += "X"; - ci.Label = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstConnectionInfo_ShortLabel() - { - var ci = new VstConnectionInfo(); - ci.ShortLabel.Should().BeEmpty(); - - ci.ShortLabel = String.Empty; - ci.ShortLabel.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxShortLabelLength); - ci.ShortLabel = testData; - ci.ShortLabel.Should().Be(testData); - - testData += "X"; - ci.ShortLabel = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstMidiCategory_Name() - { - var mc = new VstMidiCategory(); - mc.Name.Should().BeEmpty(); - - mc.Name = String.Empty; - mc.Name.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxMidiNameLength); - mc.Name = testData; - mc.Name.Should().Be(testData); - - testData += "X"; - mc.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstMidiProgram_Name() - { - var mp = new VstMidiProgram(); - mp.Name.Should().BeEmpty(); - - mp.Name = String.Empty; - mp.Name.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxMidiNameLength); - mp.Name = testData; - mp.Name.Should().Be(testData); - - testData += "X"; - mp.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterCategory_Name() - { - var pc = new VstParameterCategory(); - pc.Name.Should().BeEmpty(); - - pc.Name = String.Empty; - pc.Name.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxCategoryLabelLength); - pc.Name = testData; - pc.Name.Should().Be(testData); - - testData += "X"; - pc.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterInfo_Name() - { - var pi = new VstParameterInfo(); - pi.Name.Should().BeEmpty(); - - pi.Name = String.Empty; - pi.Name.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxParameterStringLength); - pi.Name = testData; - pi.Name.Should().Be(testData); - - testData += "X"; - pi.Name = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterInfo_Label() - { - var pi = new VstParameterInfo(); - pi.Label.Should().BeEmpty(); - - pi.Label = String.Empty; - pi.Label.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxLabelLength); - pi.Label = testData; - pi.Label.Should().Be(testData); - - testData += "X"; - pi.Label = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstParameterInfo_ShortLabel() - { - var pi = new VstParameterInfo(); - pi.ShortLabel.Should().BeEmpty(); - - pi.ShortLabel = String.Empty; - pi.ShortLabel.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxShortLabelLength); - pi.ShortLabel = testData; - pi.ShortLabel.Should().Be(testData); - - testData += "X"; - pi.ShortLabel = testData; - Assert.Fail("should have thrown an exception."); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void Test_MaxLength_VstProgram_Name() - { - var p = new VstProgram(); - p.Name.Should().BeEmpty(); - - p.Name = String.Empty; - p.Name.Should().BeEmpty(); - - var testData = CreateString(Constants.MaxProgramNameLength); - p.Name = testData; - p.Name.Should().Be(testData); - - testData += "X"; - p.Name = testData; - Assert.Fail("should have thrown an exception."); - } + var pc = new VstParameterCategory(); + pc.Name.Should().BeEmpty(); + + pc.Name = String.Empty; + pc.Name.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxCategoryLabelLength); + pc.Name = testData; + pc.Name.Should().Be(testData); + + testData += "X"; + Action err = () => pc.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterInfo_Name() + { + var pi = new VstParameterInfo(); + pi.Name.Should().BeEmpty(); + + pi.Name = String.Empty; + pi.Name.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxParameterStringLength); + pi.Name = testData; + pi.Name.Should().Be(testData); + + testData += "X"; + Action err = () => pi.Name = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterInfo_Label() + { + var pi = new VstParameterInfo(); + pi.Label.Should().BeEmpty(); + + pi.Label = String.Empty; + pi.Label.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxLabelLength); + pi.Label = testData; + pi.Label.Should().Be(testData); + + testData += "X"; + Action err = () => pi.Label = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstParameterInfo_ShortLabel() + { + var pi = new VstParameterInfo(); + pi.ShortLabel.Should().BeEmpty(); + + pi.ShortLabel = String.Empty; + pi.ShortLabel.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxShortLabelLength); + pi.ShortLabel = testData; + pi.ShortLabel.Should().Be(testData); + + testData += "X"; + Action err = () => pi.ShortLabel = testData; + err.Should().Throw(); + } + + [Fact] + public void Test_MaxLength_VstProgram_Name() + { + var p = new VstProgram(); + p.Name.Should().BeEmpty(); + + p.Name = String.Empty; + p.Name.Should().BeEmpty(); + + var testData = CreateString(Constants.MaxProgramNameLength); + p.Name = testData; + p.Name.Should().Be(testData); + + testData += "X"; + Action err = () => p.Name = testData; + err.Should().Throw(); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstEventCollectionTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstEventCollectionTest.cs index 665d708b..fea111ec 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstEventCollectionTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstEventCollectionTest.cs @@ -1,127 +1,124 @@ using FluentAssertions; using Jacobi.Vst.Core; using Jacobi.Vst.Plugin.Framework; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Specialized; -namespace Jacobi.Vst.UnitTest.Framework +namespace Jacobi.Vst.UnitTest.Framework; + +/// +///This is a test class for VstEventCollectionTest and is intended +///to contain all VstEventCollectionTest Unit Tests +/// +public class VstEventCollectionTest { - /// - ///This is a test class for VstEventCollectionTest and is intended - ///to contain all VstEventCollectionTest Unit Tests - /// - [TestClass()] - public class VstEventCollectionTest + [Fact] + public void Test_VstEventCollection_ReadOnlyConstructor() { - [TestMethod()] - public void Test_VstEventCollection_ReadOnlyConstructor() - { - var events = new VstEvent[2]; - events[0] = new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0); - events[1] = new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0); + var events = new VstEvent[2]; + events[0] = new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0); + events[1] = new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0); - var target = new VstEventCollection(events); + var target = new VstEventCollection(events); - target.Should().HaveCount(events.Length); - target.IsReadOnly.Should().BeTrue(); - target[0].Should().Be(events[0]); - target[1].Should().Be(events[1]); - } + target.Should().HaveCount(events.Length); + target.IsReadOnly.Should().BeTrue(); + target[0].Should().Be(events[0]); + target[1].Should().Be(events[1]); + } - [TestMethod()] - public void Test_VstEventCollection_Constructor() - { - var target = new VstEventCollection(); - target.IsReadOnly.Should().BeFalse(); + [Fact] + public void Test_VstEventCollection_Constructor() + { + var target = new VstEventCollection(); + target.IsReadOnly.Should().BeFalse(); - target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); - target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); - target.Should().HaveCount(2); + target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); + target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); + target.Should().HaveCount(2); - target.Clear(); - target.Should().BeEmpty(); - } + target.Clear(); + target.Should().BeEmpty(); + } - [TestMethod()] - public void Test_VstEventCollection_CollectionChanged_Add() - { - var target = new VstEventCollection(); - int callCount = 0; + [Fact] + public void Test_VstEventCollection_CollectionChanged_Add() + { + var target = new VstEventCollection(); + int callCount = 0; - target.CollectionChanged += (sender, e) => - { - e.Action.Should().Be(NotifyCollectionChangedAction.Add); - e.NewItems.Should().NotBeNull(); //.NotBeNullOrEmpty(); - e.NewItems[0].Should().NotBeNull(); + target.CollectionChanged += (sender, e) => + { + e.Action.Should().Be(NotifyCollectionChangedAction.Add); + e.NewItems.Should().NotBeNull(); + e.NewItems[0].Should().NotBeNull(); - callCount++; - }; + callCount++; + }; - target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); - target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); + target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); + target.Add(new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0)); - callCount.Should().Be(2); - } + callCount.Should().Be(2); + } - [TestMethod()] - public void Test_VstEventCollection_CollectionChanged_RemoveAt() + [Fact] + public void Test_VstEventCollection_CollectionChanged_RemoveAt() + { + var target = new VstEventCollection { - var target = new VstEventCollection - { - new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0), - new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0) - }; + new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0), + new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0) + }; - target.Should().HaveCount(2); + target.Should().HaveCount(2); - int callCount = 0; + int callCount = 0; - target.CollectionChanged += (sender, e) => - { - e.Action.Should().Be(NotifyCollectionChangedAction.Remove); - e.OldItems.Should().NotBeNull(); //OrEmpty(); - e.OldItems[0].Should().NotBeNull(); + target.CollectionChanged += (sender, e) => + { + e.Action.Should().Be(NotifyCollectionChangedAction.Remove); + e.OldItems.Should().NotBeNull(); + e.OldItems[0].Should().NotBeNull(); - callCount++; - }; + callCount++; + }; - target.RemoveAt(0); - target.RemoveAt(0); + target.RemoveAt(0); + target.RemoveAt(0); - callCount.Should().Be(2); - target.Should().BeEmpty(); - } + callCount.Should().Be(2); + target.Should().BeEmpty(); + } - [TestMethod()] - public void Test_VstEventCollection_CollectionChanged_Replace() + [Fact] + public void Test_VstEventCollection_CollectionChanged_Replace() + { + var target = new VstEventCollection { - var target = new VstEventCollection - { - new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0), - new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0) - }; + new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0), + new VstMidiEvent(0, 100, 0, new byte[] { 100, 110, 120 }, 0, 0) + }; - target.Should().HaveCount(2); + target.Should().HaveCount(2); - int callCount = 0; + int callCount = 0; - target.CollectionChanged += (sender, e) => - { - e.Action.Should().Be(NotifyCollectionChangedAction.Replace); - e.NewItems.Should().NotBeNull(); //OrEmpty(); - e.NewItems[0].Should().NotBeNull(); - e.OldItems.Should().NotBeNull(); //OrEmpty(); - e.OldItems[0].Should().NotBeNull(); + target.CollectionChanged += (sender, e) => + { + e.Action.Should().Be(NotifyCollectionChangedAction.Replace); + e.NewItems.Should().NotBeNull(); + e.NewItems[0].Should().NotBeNull(); + e.OldItems.Should().NotBeNull(); + e.OldItems[0].Should().NotBeNull(); - callCount++; - }; + callCount++; + }; - VstEvent @event = target[0]; + VstEvent @event = target[0]; - target[0] = target[1]; - target[1] = @event; + target[0] = target[1]; + target[1] = @event; - callCount.Should().Be(2); - } + callCount.Should().Be(2); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterCollectionTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterCollectionTest.cs index c1ce8810..aa3196a8 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterCollectionTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterCollectionTest.cs @@ -1,45 +1,42 @@ using FluentAssertions; using Jacobi.Vst.Plugin.Framework; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Framework +namespace Jacobi.Vst.UnitTest.Framework; + +/// +/// This is a test class for VstParameterCollectionTest and is intended +/// to contain all VstParameterCollectionTest Unit Tests +/// +public class VstParameterCollectionTest { - /// - /// This is a test class for VstParameterCollectionTest and is intended - /// to contain all VstParameterCollectionTest Unit Tests - /// - [TestClass()] - public class VstParameterCollectionTest + [Fact] + public void Test_VstParameterCollection_Index() { - [TestMethod()] - public void Test_VstParameterCollection_Index() - { - var target = new VstParameterCollection(); + var target = new VstParameterCollection(); - var paramInfo1 = new VstParameterInfo - { - Name = "Test1", - ShortLabel = "Tst1", - MaxInteger = 10 - }; + var paramInfo1 = new VstParameterInfo + { + Name = "Test1", + ShortLabel = "Tst1", + MaxInteger = 10 + }; - var param1 = new VstParameter(paramInfo1); - target.Add(param1); + var param1 = new VstParameter(paramInfo1); + target.Add(param1); - param1.Index.Should().Be(0); + param1.Index.Should().Be(0); - var paramInfo2 = new VstParameterInfo - { - Name = "Test2", - ShortLabel = "Tst2", - MaxInteger = 10 - }; + var paramInfo2 = new VstParameterInfo + { + Name = "Test2", + ShortLabel = "Tst2", + MaxInteger = 10 + }; - var param2 = new VstParameter(paramInfo2); - target.Insert(0, param2); + var param2 = new VstParameter(paramInfo2); + target.Insert(0, param2); - param1.Index.Should().Be(1); - param2.Index.Should().Be(0); - } + param1.Index.Should().Be(1); + param2.Index.Should().Be(0); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterNormalizationInfoTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterNormalizationInfoTest.cs index bbe14a4a..5afc83c3 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterNormalizationInfoTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstParameterNormalizationInfoTest.cs @@ -1,78 +1,77 @@ using FluentAssertions; using Jacobi.Vst.Plugin.Framework; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Framework +namespace Jacobi.Vst.UnitTest.Framework; + +/// +/// This test class verifies the correct normalization of different Parameter value ranges. +/// +public class VstParameterNormalizationInfoTest { - /// - /// This test class verifies the correct normalization of different Parameter value ranges. - /// - [TestClass] - public class VstParameterNormalizationInfoTest + private void AssertNormalizationInfo(VstParameterInfo paramInfo) { - private void AssertNormalizationInfo(VstParameterInfo paramInfo) - { - VstParameterNormalizationInfo.AttachTo(paramInfo); + VstParameterNormalizationInfo.AttachTo(paramInfo); + + paramInfo.NormalizationInfo.Should().NotBeNull(); - float actual = paramInfo.NormalizationInfo.GetRawValue(0); - actual.Should().Be(paramInfo.MinInteger); + float actual = paramInfo.NormalizationInfo!.GetRawValue(0); + actual.Should().Be(paramInfo.MinInteger); - actual = paramInfo.NormalizationInfo.GetRawValue(1); - actual.Should().Be(paramInfo.MaxInteger); + actual = paramInfo.NormalizationInfo.GetRawValue(1); + actual.Should().Be(paramInfo.MaxInteger); - actual = paramInfo.NormalizationInfo.GetNormalizedValue(paramInfo.MinInteger); - actual.Should().Be(0); + actual = paramInfo.NormalizationInfo.GetNormalizedValue(paramInfo.MinInteger); + actual.Should().Be(0); - actual = paramInfo.NormalizationInfo.GetNormalizedValue(paramInfo.MaxInteger); - actual.Should().Be(1); - } + actual = paramInfo.NormalizationInfo.GetNormalizedValue(paramInfo.MaxInteger); + actual.Should().Be(1); + } - [TestMethod] - public void Test_VstParameterNormalizationInfo_ZeroMinInteger() + [Fact] + public void Test_VstParameterNormalizationInfo_ZeroMinInteger() + { + var paramInfo = new VstParameterInfo { - var paramInfo = new VstParameterInfo - { - MinInteger = 0, - MaxInteger = 10 - }; + MinInteger = 0, + MaxInteger = 10 + }; - AssertNormalizationInfo(paramInfo); - } + AssertNormalizationInfo(paramInfo); + } - [TestMethod] - public void Test_VstParameterNormalizationInfo_PositiveRange() + [Fact] + public void Test_VstParameterNormalizationInfo_PositiveRange() + { + var paramInfo = new VstParameterInfo { - var paramInfo = new VstParameterInfo - { - MinInteger = 10, - MaxInteger = 20 - }; + MinInteger = 10, + MaxInteger = 20 + }; - AssertNormalizationInfo(paramInfo); - } + AssertNormalizationInfo(paramInfo); + } - [TestMethod] - public void Test_VstParameterNormalizationInfo_NegativeMinInteger() + [Fact] + public void Test_VstParameterNormalizationInfo_NegativeMinInteger() + { + var paramInfo = new VstParameterInfo { - var paramInfo = new VstParameterInfo - { - MinInteger = -10, - MaxInteger = 10 - }; + MinInteger = -10, + MaxInteger = 10 + }; - AssertNormalizationInfo(paramInfo); - } + AssertNormalizationInfo(paramInfo); + } - [TestMethod] - public void Test_VstParameterNormalizationInfo_NegativeRange() + [Fact] + public void Test_VstParameterNormalizationInfo_NegativeRange() + { + var paramInfo = new VstParameterInfo { - var paramInfo = new VstParameterInfo - { - MinInteger = -20, - MaxInteger = -10 - }; + MinInteger = -20, + MaxInteger = -10 + }; - AssertNormalizationInfo(paramInfo); - } + AssertNormalizationInfo(paramInfo); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstProductInfoTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstProductInfoTest.cs index 423c2c09..7bfd4184 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Framework/VstProductInfoTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Framework/VstProductInfoTest.cs @@ -1,30 +1,27 @@ using FluentAssertions; using Jacobi.Vst.Plugin.Framework; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Framework +namespace Jacobi.Vst.UnitTest.Framework; + +/// +///This is a test class for VstProductInfoTest and is intended +///to contain all VstProductInfoTest Unit Tests +/// +public class VstProductInfoTest { - /// - ///This is a test class for VstProductInfoTest and is intended - ///to contain all VstProductInfoTest Unit Tests - /// - [TestClass()] - public class VstProductInfoTest + [Fact] + public void Test_VstProductInfoConstructor() { - [TestMethod()] - public void Test_VstProductInfoConstructor() - { - string product = "UnitTestProduct"; - string vendor = "UnitTestVendor"; - int version = 1200; + string product = "UnitTestProduct"; + string vendor = "UnitTestVendor"; + int version = 1200; - var pi = new VstProductInfo(product, vendor, version); + var pi = new VstProductInfo(product, vendor, version); - pi.IsValid.Should().BeTrue(); - pi.Product.Should().Be(product); - pi.Vendor.Should().Be(vendor); - pi.Version.Should().Be(version); - pi.FormattedVersion.Should().Be("1.2.0.0"); - } + pi.IsValid.Should().BeTrue(); + pi.Product.Should().Be(product); + pi.Vendor.Should().Be(vendor); + pi.Version.Should().Be(version); + pi.FormattedVersion.Should().Be("1.2.0.0"); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/GlobalUsings.cs b/Source/Code/Jacobi.Vst.UnitTest/GlobalUsings.cs new file mode 100644 index 00000000..8c927eb7 --- /dev/null +++ b/Source/Code/Jacobi.Vst.UnitTest/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioBufferManagerTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioBufferManagerTest.cs index c5d302af..32cb3c95 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioBufferManagerTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioBufferManagerTest.cs @@ -2,109 +2,106 @@ using FluentAssertions; using Jacobi.Vst.Core; using Jacobi.Vst.Host.Interop; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Interop.Host +namespace Jacobi.Vst.UnitTest.Interop.Host; + +/// +/// Summary description for VstAudioBufferManagerTest +/// +public class VstAudioBufferManagerTest { - /// - /// Summary description for VstAudioBufferManagerTest - /// - [TestClass] - public class VstAudioBufferManagerTest + private const int _bufferCount = 24; + private const int _bufferSize = 1024; + private const float _testValue = 0xFF; + + private VstAudioBufferManager CreateNew() { - private const int _bufferCount = 24; - private const int _bufferSize = 1024; - private const float _testValue = 0xFF; + var bufferMgr = new VstAudioBufferManager(_bufferCount, _bufferSize); - private VstAudioBufferManager CreateNew() - { - var bufferMgr = new VstAudioBufferManager(_bufferCount, _bufferSize); + bufferMgr.BufferCount.Should().Be(_bufferCount); + bufferMgr.BufferSize.Should().Be(_bufferSize); - bufferMgr.BufferCount.Should().Be(_bufferCount); - bufferMgr.BufferSize.Should().Be(_bufferSize); + return bufferMgr; + } - return bufferMgr; - } + private VstAudioBufferManager CreateNew(float value) + { + var bufferMgr = CreateNew(); - private VstAudioBufferManager CreateNew(float value) + foreach (VstAudioBuffer buffer in bufferMgr.Buffers) { - var bufferMgr = CreateNew(); - - foreach (VstAudioBuffer buffer in bufferMgr.Buffers) + for (int i = 0; i < buffer.SampleCount; i++) { - for (int i = 0; i < buffer.SampleCount; i++) - { - buffer[i] = value; - } + buffer[i] = value; } - - return bufferMgr; } - private void AssertAllBuffersHasValue(VstAudioBufferManager bufferMgr, float value) - { - foreach (VstAudioBuffer buffer in bufferMgr.Buffers) - { - AssertBufferHasValue(buffer, value); - } - } + return bufferMgr; + } - private void AssertBufferHasValue(VstAudioBuffer buffer, float value) + private void AssertAllBuffersHasValue(VstAudioBufferManager bufferMgr, float value) + { + foreach (VstAudioBuffer buffer in bufferMgr.Buffers) { - for (int i = 0; i < buffer.SampleCount; i++) - { - buffer[i].Should().Be(value); - } + AssertBufferHasValue(buffer, value); } + } - [TestMethod] - public void Test_VstAudioBufferManager_Construction() + private void AssertBufferHasValue(VstAudioBuffer buffer, float value) + { + for (int i = 0; i < buffer.SampleCount; i++) { - var bufferMgr = CreateNew(_testValue); - - AssertAllBuffersHasValue(bufferMgr, _testValue); + buffer[i].Should().Be(value); } + } - [TestMethod] - public void Test_VstAudioBufferManager_ClearAllBuffers() - { - var bufferMgr = CreateNew(_testValue); + [Fact] + public void Test_VstAudioBufferManager_Construction() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, _testValue); + AssertAllBuffersHasValue(bufferMgr, _testValue); + } - bufferMgr.ClearAllBuffers(); + [Fact] + public void Test_VstAudioBufferManager_ClearAllBuffers() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, 0); - } + AssertAllBuffersHasValue(bufferMgr, _testValue); - [TestMethod] - public void Test_VstAudioBufferManager_ClearIndividualBuffers() - { - var bufferMgr = CreateNew(_testValue); + bufferMgr.ClearAllBuffers(); - AssertAllBuffersHasValue(bufferMgr, _testValue); + AssertAllBuffersHasValue(bufferMgr, 0); + } - foreach (VstAudioBuffer buffer in bufferMgr.Buffers) - { - bufferMgr.ClearBuffer(buffer); - } + [Fact] + public void Test_VstAudioBufferManager_ClearIndividualBuffers() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, 0); - } + AssertAllBuffersHasValue(bufferMgr, _testValue); - [TestMethod] - public void Test_VstAudioBufferManager_EnumerateBuffers() + foreach (VstAudioBuffer buffer in bufferMgr.Buffers) { - var bufferMgr = CreateNew(_testValue); + bufferMgr.ClearBuffer(buffer); + } - int counter = 0; - foreach (VstAudioBuffer buffer in bufferMgr.Buffers) - { - counter++; - } + AssertAllBuffersHasValue(bufferMgr, 0); + } + + [Fact] + public void Test_VstAudioBufferManager_EnumerateBuffers() + { + var bufferMgr = CreateNew(_testValue); - counter.Should().Be(_bufferCount); - bufferMgr.Buffers.Should().HaveCount(_bufferCount); + int counter = 0; + foreach (VstAudioBuffer buffer in bufferMgr.Buffers) + { + counter++; } + + counter.Should().Be(_bufferCount); + bufferMgr.Buffers.Should().HaveCount(_bufferCount); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioPrecisionBufferManagerTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioPrecisionBufferManagerTest.cs index e6c22334..9291bd82 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioPrecisionBufferManagerTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstAudioPrecisionBufferManagerTest.cs @@ -2,109 +2,106 @@ using FluentAssertions; using Jacobi.Vst.Core; using Jacobi.Vst.Host.Interop; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Jacobi.Vst.UnitTest.Interop.Host +namespace Jacobi.Vst.UnitTest.Interop.Host; + +/// +/// Summary description for VstAudioPrecisionBufferManagerTest +/// +public class VstAudioPrecisionBufferManagerTest { - /// - /// Summary description for VstAudioPrecisionBufferManagerTest - /// - [TestClass] - public class VstAudioPrecisionBufferManagerTest + private const int _bufferCount = 24; + private const int _bufferSize = 1024; + private const float _testValue = 0xFF; + + private VstAudioPrecisionBufferManager CreateNew() { - private const int _bufferCount = 24; - private const int _bufferSize = 1024; - private const float _testValue = 0xFF; + var bufferMgr = new VstAudioPrecisionBufferManager(_bufferCount, _bufferSize); - private VstAudioPrecisionBufferManager CreateNew() - { - var bufferMgr = new VstAudioPrecisionBufferManager(_bufferCount, _bufferSize); + bufferMgr.BufferCount.Should().Be(_bufferCount); + bufferMgr.BufferSize.Should().Be(_bufferSize); - bufferMgr.BufferCount.Should().Be(_bufferCount); - bufferMgr.BufferSize.Should().Be(_bufferSize); + return bufferMgr; + } - return bufferMgr; - } + private VstAudioPrecisionBufferManager CreateNew(float value) + { + var bufferMgr = CreateNew(); - private VstAudioPrecisionBufferManager CreateNew(float value) + foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) { - var bufferMgr = CreateNew(); - - foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) + for (int i = 0; i < buffer.SampleCount; i++) { - for (int i = 0; i < buffer.SampleCount; i++) - { - buffer[i] = value; - } + buffer[i] = value; } - - return bufferMgr; } - private void AssertAllBuffersHasValue(VstAudioPrecisionBufferManager bufferMgr, float value) - { - foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) - { - AssertBufferHasValue(buffer, value); - } - } + return bufferMgr; + } - private void AssertBufferHasValue(VstAudioPrecisionBuffer buffer, float value) + private void AssertAllBuffersHasValue(VstAudioPrecisionBufferManager bufferMgr, float value) + { + foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) { - for (int i = 0; i < buffer.SampleCount; i++) - { - buffer[i].Should().Be(value); - } + AssertBufferHasValue(buffer, value); } + } - [TestMethod] - public void Test_VstAudioPrecisionBufferManager_Construction() + private void AssertBufferHasValue(VstAudioPrecisionBuffer buffer, float value) + { + for (int i = 0; i < buffer.SampleCount; i++) { - var bufferMgr = CreateNew(_testValue); - - AssertAllBuffersHasValue(bufferMgr, _testValue); + buffer[i].Should().Be(value); } + } - [TestMethod] - public void Test_VstAudioPrecisionBufferManager_ClearAllBuffers() - { - var bufferMgr = CreateNew(_testValue); + [Fact] + public void Test_VstAudioPrecisionBufferManager_Construction() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, _testValue); + AssertAllBuffersHasValue(bufferMgr, _testValue); + } - bufferMgr.ClearAllBuffers(); + [Fact] + public void Test_VstAudioPrecisionBufferManager_ClearAllBuffers() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, 0); - } + AssertAllBuffersHasValue(bufferMgr, _testValue); - [TestMethod] - public void Test_VstAudioPrecisionBufferManager_ClearIndividualBuffers() - { - var bufferMgr = CreateNew(_testValue); + bufferMgr.ClearAllBuffers(); - AssertAllBuffersHasValue(bufferMgr, _testValue); + AssertAllBuffersHasValue(bufferMgr, 0); + } - foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) - { - bufferMgr.ClearBuffer(buffer); - } + [Fact] + public void Test_VstAudioPrecisionBufferManager_ClearIndividualBuffers() + { + var bufferMgr = CreateNew(_testValue); - AssertAllBuffersHasValue(bufferMgr, 0); - } + AssertAllBuffersHasValue(bufferMgr, _testValue); - [TestMethod] - public void Test_VstAudioBufferManager_EnumerateBuffers() + foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) { - var bufferMgr = CreateNew(_testValue); + bufferMgr.ClearBuffer(buffer); + } - int counter = 0; - foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) - { - counter++; - } + AssertAllBuffersHasValue(bufferMgr, 0); + } + + [Fact] + public void Test_VstAudioBufferManager_EnumerateBuffers() + { + var bufferMgr = CreateNew(_testValue); - counter.Should().Be(_bufferCount); - bufferMgr.Buffers.Should().HaveCount(_bufferCount); + int counter = 0; + foreach (VstAudioPrecisionBuffer buffer in bufferMgr.Buffers) + { + counter++; } + + counter.Should().Be(_bufferCount); + bufferMgr.Buffers.Should().HaveCount(_bufferCount); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstPluginContextTest.cs b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstPluginContextTest.cs index f84a6966..476d86a9 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstPluginContextTest.cs +++ b/Source/Code/Jacobi.Vst.UnitTest/Interop/Host/VstPluginContextTest.cs @@ -1,27 +1,22 @@ using FluentAssertions; using Jacobi.Vst.Host.Interop; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Reflection; -namespace Jacobi.Vst.UnitTest.Interop.Host +namespace Jacobi.Vst.UnitTest.Interop.Host; + +public class VstPluginContextTest { - [TestClass] - public class VstPluginContextTest + //[WorkItem(10484)] + //[WorkItem(8488)] + [Fact] + public void Create_InvalidPluginFile_ThrowsExpectedException() { - public TestContext TestContext; - - [WorkItem(10484)] - [WorkItem(8488)] - [TestMethod] - public void Create_InvalidPluginFile_ThrowsExpectedException() - { - var hostCmdStub = new StubHostCommandStub(); - var notaPluginFile = Assembly.GetExecutingAssembly().Location; + var hostCmdStub = new StubHostCommandStub(); + var notaPluginFile = Assembly.GetExecutingAssembly().Location; - Action target = () => VstPluginContext.Create(notaPluginFile, hostCmdStub); + Action target = () => VstPluginContext.Create(notaPluginFile, hostCmdStub); - target.Should().Throw(); - } + target.Should().Throw(); } } diff --git a/Source/Code/Jacobi.Vst.UnitTest/Jacobi.Vst.UnitTest.csproj b/Source/Code/Jacobi.Vst.UnitTest/Jacobi.Vst.UnitTest.csproj index 1ae05efa..710d5e9a 100644 --- a/Source/Code/Jacobi.Vst.UnitTest/Jacobi.Vst.UnitTest.csproj +++ b/Source/Code/Jacobi.Vst.UnitTest/Jacobi.Vst.UnitTest.csproj @@ -1,24 +1,23 @@  - net6.0-windows + net8.0-windows false - 2.0.0.0 - 2.0.0 - Marc Jacobi - Jacobi Software - VST.NET + true x64;x86 - - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all + + runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -26,14 +25,7 @@ - - - - - PreserveNewest - - diff --git a/Source/Code/Jacobi.Vst.sln b/Source/Code/Jacobi.Vst.sln index 46e8ee00..d389ad01 100644 --- a/Source/Code/Jacobi.Vst.sln +++ b/Source/Code/Jacobi.Vst.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32804.467 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jacobi.Vst.UnitTest", "Jacobi.Vst.UnitTest\Jacobi.Vst.UnitTest.csproj", "{D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{78E1AA3A-44D0-4A1E-860A-0EF5048ED6F9}" ProjectSection(SolutionItems) = preProject readme.md = readme.md @@ -15,7 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jacobi.Vst.Core", "Jacobi.V EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deployment", "Deployment", "{7CBB90A0-0CBB-4380-AC6D-B9686CC17724}" ProjectSection(SolutionItems) = preProject - Jacobi.Vst.Deployment\.gitignore = Jacobi.Vst.Deployment\.gitignore Jacobi.Vst.Deployment\buildall.cmd = Jacobi.Vst.Deployment\buildall.cmd Jacobi.Vst.Deployment\pack.cmd = Jacobi.Vst.Deployment\pack.cmd Jacobi.Vst.Deployment\push-nuget.cmd = Jacobi.Vst.Deployment\push-nuget.cmd @@ -52,6 +49,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{0E8BB654-7 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jacobi.Vst.Plugin.Framework", "Jacobi.Vst.Plugin.Framework\Jacobi.Vst.Plugin.Framework.csproj", "{7A7D5B04-5120-4DBE-9DD5-C8C0E2C17DF5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jacobi.Vst.UnitTest", "Jacobi.Vst.UnitTest\Jacobi.Vst.UnitTest.csproj", "{9A616DCC-6247-4D5E-AD5B-EA063F269103}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -60,14 +59,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Debug|x64.ActiveCfg = Debug|x64 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Debug|x64.Build.0 = Debug|x64 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Debug|x86.ActiveCfg = Debug|x86 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Debug|x86.Build.0 = Debug|x86 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Release|x64.ActiveCfg = Release|x64 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Release|x64.Build.0 = Release|x64 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Release|x86.ActiveCfg = Release|x86 - {D7B622E6-A789-4BBB-B189-7C5A2E8FDF7C}.Release|x86.Build.0 = Release|x86 {045C7E3F-F200-43FE-9F7D-FEA7695D2E5F}.Debug|x64.ActiveCfg = Debug|x64 {045C7E3F-F200-43FE-9F7D-FEA7695D2E5F}.Debug|x64.Build.0 = Debug|x64 {045C7E3F-F200-43FE-9F7D-FEA7695D2E5F}.Debug|x86.ActiveCfg = Debug|x86 @@ -108,6 +99,14 @@ Global {7A7D5B04-5120-4DBE-9DD5-C8C0E2C17DF5}.Release|x64.Build.0 = Release|x64 {7A7D5B04-5120-4DBE-9DD5-C8C0E2C17DF5}.Release|x86.ActiveCfg = Release|x86 {7A7D5B04-5120-4DBE-9DD5-C8C0E2C17DF5}.Release|x86.Build.0 = Release|x86 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Debug|x64.ActiveCfg = Debug|x64 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Debug|x64.Build.0 = Debug|x64 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Debug|x86.ActiveCfg = Debug|x86 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Debug|x86.Build.0 = Debug|x86 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Release|x64.ActiveCfg = Release|x64 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Release|x64.Build.0 = Release|x64 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Release|x86.ActiveCfg = Release|x86 + {9A616DCC-6247-4D5E-AD5B-EA063F269103}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Code/readme.md b/Source/Code/readme.md index 5b83bf81..0a75b8d1 100644 --- a/Source/Code/readme.md +++ b/Source/Code/readme.md @@ -1,6 +1,6 @@ -# VST.NET 2 for .NET 6 +# VST.NET 2 for .NET 6, 7 and 8 -The dotnet 6 version of VST.NET. +The dotnet 6, 7 and 8 version of VST.NET. ## Issues diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/AudioProcessor.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/AudioProcessor.cs index db20ac21..3a9e2f5e 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/AudioProcessor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/AudioProcessor.cs @@ -3,89 +3,88 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using System.Diagnostics; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// This object performs audio processing for your plugin. +/// +internal sealed class AudioProcessor : VstPluginAudioProcessor, IVstPluginBypass { + /// Stereo inputs. + private const int AudioInputCount = 2; + /// Stereo outputs. + private const int AudioOutputCount = 2; + /// No tail size. + private const int InitialTailSize = 0; + + private const VstTimeInfoFlags _defaultTimeInfoFlags = VstTimeInfoFlags.ClockValid; + /// - /// This object performs audio processing for your plugin. + /// Default constructor. /// - internal sealed class AudioProcessor : VstPluginAudioProcessor, IVstPluginBypass + public AudioProcessor(PluginParameters parameters) + : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: false) { - /// Stereo inputs. - private const int AudioInputCount = 2; - /// Stereo outputs. - private const int AudioOutputCount = 2; - /// No tail size. - private const int InitialTailSize = 0; - - private const VstTimeInfoFlags _defaultTimeInfoFlags = VstTimeInfoFlags.ClockValid; + Throw.IfArgumentIsNull(parameters, nameof(parameters)); - /// - /// Default constructor. - /// - public AudioProcessor(PluginParameters parameters) - : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: false) - { - Throw.IfArgumentIsNull(parameters, nameof(parameters)); - - // one set of parameters is shared for both channels. - Left = new Dsp.Delay(parameters.DelayParameters); - Right = new Dsp.Delay(parameters.DelayParameters); - } + // one set of parameters is shared for both channels. + Left = new Dsp.Delay(parameters.DelayParameters); + Right = new Dsp.Delay(parameters.DelayParameters); + } - internal Dsp.Delay Left { get; private set; } - internal Dsp.Delay Right { get; private set; } + internal Dsp.Delay Left { get; private set; } + internal Dsp.Delay Right { get; private set; } - /// - /// Override the default implementation to pass it through to the delay. - /// - public override float SampleRate + /// + /// Override the default implementation to pass it through to the delay. + /// + public override float SampleRate + { + get { return Left.SampleRate; } + set { - get { return Left.SampleRate; } - set - { - Left.SampleRate = value; - Right.SampleRate = value; - } + Left.SampleRate = value; + Right.SampleRate = value; } + } - /// - /// Called by the host to allow the plugin to process audio samples. - /// - /// Never null. - /// Never null. - public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + /// + /// Called by the host to allow the plugin to process audio samples. + /// + /// Never null. + /// Never null. + public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + { + if (!Bypass) { - if (!Bypass) - { - // check assumptions - Debug.Assert(outChannels.Length == inChannels.Length); + // check assumptions + Debug.Assert(outChannels.Length == inChannels.Length); - for (int i = 0; i < outChannels.Length; i++) - { - Process(i % 2 == 0 ? Left : Right, - inChannels[i], outChannels[i]); - } - } - else + for (int i = 0; i < outChannels.Length; i++) { - // calling the base class transfers input samples to the output channels unchanged (bypass). - base.Process(inChannels, outChannels); + Process(i % 2 == 0 ? Left : Right, + inChannels[i], outChannels[i]); } } + else + { + // calling the base class transfers input samples to the output channels unchanged (bypass). + base.Process(inChannels, outChannels); + } + } - // process a single audio channel - private void Process(Dsp.Delay delay, VstAudioBuffer input, VstAudioBuffer output) + // process a single audio channel + private void Process(Dsp.Delay delay, VstAudioBuffer input, VstAudioBuffer output) + { + for (int i = 0; i < input.SampleCount; i++) { - for (int i = 0; i < input.SampleCount; i++) - { - output[i] = delay.ProcessSample(input[i]); - } + output[i] = delay.ProcessSample(input[i]); } + } - #region IVstPluginBypass Members + #region IVstPluginBypass Members - public bool Bypass { get; set; } + public bool Bypass { get; set; } - #endregion - } + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/Delay.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/Delay.cs index 8e9687ff..72f12006 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/Delay.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/Delay.cs @@ -1,91 +1,90 @@ using System; using System.ComponentModel; -namespace Jacobi.Vst.Samples.Delay.Dsp +namespace Jacobi.Vst.Samples.Delay.Dsp; + +/// +/// This is an example of a Digital Sound Processing component you could have in your plugin. +/// +internal sealed class Delay { + private float[] _delayBuffer; + private int _bufferIndex; + private int _bufferLength; + + private readonly DelayParameters _parameters; + /// - /// This is an example of a Digital Sound Processing component you could have in your plugin. + /// Constructs a new instance. /// - internal sealed class Delay + public Delay(DelayParameters parameters) { - private float[] _delayBuffer; - private int _bufferIndex; - private int _bufferLength; - - private readonly DelayParameters _parameters; + _delayBuffer = Array.Empty(); + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - /// - /// Constructs a new instance. - /// - public Delay(DelayParameters parameters) - { - _delayBuffer = Array.Empty(); - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - - // when the delay time parameter value changes, we like to know about it. - _parameters.DelayTimeMgr.PropertyChanged += DelayTimeMgr_PropertyChanged; - } + // when the delay time parameter value changes, we like to know about it. + _parameters.DelayTimeMgr.PropertyChanged += DelayTimeMgr_PropertyChanged; + } - private void DelayTimeMgr_PropertyChanged(object? sender, PropertyChangedEventArgs e) + private void DelayTimeMgr_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (Object.ReferenceEquals(_parameters.DelayTimeMgr, sender)) { - if (Object.ReferenceEquals(_parameters.DelayTimeMgr, sender)) - { - SetBufferLength(); - } + SetBufferLength(); } + } - private void SetBufferLength() - { - // logical buffer length - _bufferLength = (int)(_parameters.DelayTimeMgr.CurrentValue * _sampleRate / 1000); - } + private void SetBufferLength() + { + // logical buffer length + _bufferLength = (int)(_parameters.DelayTimeMgr.CurrentValue * _sampleRate / 1000); + } - private float _sampleRate; - /// - /// Gets or sets the sample rate. - /// - public float SampleRate + private float _sampleRate; + /// + /// Gets or sets the sample rate. + /// + public float SampleRate + { + get { return _sampleRate; } + set { - get { return _sampleRate; } - set - { - _sampleRate = value; + _sampleRate = value; - // allocate buffer for max delay time - int bufferLength = (int)(_parameters.DelayTimeMgr.ParameterInfo.MaxInteger * _sampleRate / 1000); - _delayBuffer = new float[bufferLength]; + // allocate buffer for max delay time + int bufferLength = (int)(_parameters.DelayTimeMgr.ParameterInfo.MaxInteger * _sampleRate / 1000); + _delayBuffer = new float[bufferLength]; - SetBufferLength(); - } + SetBufferLength(); } + } - /// - /// Processes the using a delay effect. - /// - /// A single sample. - /// Returns the new value for the sample. - public float ProcessSample(float sample) - { - if (_delayBuffer == null) - return sample; - - // process output - float output = (_parameters.DryLevelMgr.CurrentValue * sample) + - (_parameters.WetLevelMgr.CurrentValue * _delayBuffer[_bufferIndex]); + /// + /// Processes the using a delay effect. + /// + /// A single sample. + /// Returns the new value for the sample. + public float ProcessSample(float sample) + { + if (_delayBuffer == null) + return sample; - // process delay buffer - _delayBuffer[_bufferIndex] = sample + - (_parameters.FeedbackMgr.CurrentValue * _delayBuffer[_bufferIndex]); + // process output + float output = (_parameters.DryLevelMgr.CurrentValue * sample) + + (_parameters.WetLevelMgr.CurrentValue * _delayBuffer[_bufferIndex]); - _bufferIndex++; + // process delay buffer + _delayBuffer[_bufferIndex] = sample + + (_parameters.FeedbackMgr.CurrentValue * _delayBuffer[_bufferIndex]); - // manage current buffer position - if (_bufferIndex >= _bufferLength) - { - _bufferIndex = 0; - } + _bufferIndex++; - return output; + // manage current buffer position + if (_bufferIndex >= _bufferLength) + { + _bufferIndex = 0; } + + return output; } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/DelayParameters.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/DelayParameters.cs index ea63a592..efdee2ea 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/DelayParameters.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/Dsp/DelayParameters.cs @@ -1,117 +1,116 @@ using Jacobi.Vst.Core; using Jacobi.Vst.Plugin.Framework; -namespace Jacobi.Vst.Samples.Delay.Dsp +namespace Jacobi.Vst.Samples.Delay.Dsp; + +/// +/// Encapsulated delay parameters. +/// +internal sealed class DelayParameters { + private const string ParameterCategoryName = "Delay"; + /// - /// Encapsulated delay parameters. + /// Initializes the parameters for the Delay component. /// - internal sealed class DelayParameters + /// + public DelayParameters(PluginParameters parameters) { - private const string ParameterCategoryName = "Delay"; - - /// - /// Initializes the parameters for the Delay component. - /// - /// - public DelayParameters(PluginParameters parameters) - { - Throw.IfArgumentIsNull(parameters, nameof(parameters)); + Throw.IfArgumentIsNull(parameters, nameof(parameters)); - InitializeParameters(parameters); - } + InitializeParameters(parameters); + } - public VstParameterManager DelayTimeMgr { get; private set; } - public VstParameterManager FeedbackMgr { get; private set; } - public VstParameterManager DryLevelMgr { get; private set; } - public VstParameterManager WetLevelMgr { get; private set; } + public VstParameterManager DelayTimeMgr { get; private set; } + public VstParameterManager FeedbackMgr { get; private set; } + public VstParameterManager DryLevelMgr { get; private set; } + public VstParameterManager WetLevelMgr { get; private set; } - // This method initializes the plugin parameters this Dsp component owns. - private void InitializeParameters(PluginParameters parameters) - { - // all parameter definitions are added to a central list. - VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; + // This method initializes the plugin parameters this Dsp component owns. + private void InitializeParameters(PluginParameters parameters) + { + // all parameter definitions are added to a central list. + VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; - // retrieve the category for all delay parameters. - VstParameterCategory paramCategory = - parameters.GetParameterCategory(ParameterCategoryName); + // retrieve the category for all delay parameters. + VstParameterCategory paramCategory = + parameters.GetParameterCategory(ParameterCategoryName); - // delay time parameter - var paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Time", - Label = "MilSecs", - ShortLabel = "ms", - MinInteger = 0, - MaxInteger = 1000, - LargeStepInteger = 100, - StepInteger = 10, - DefaultValue = 200f - }; - DelayTimeMgr = paramInfo - .Normalize() - .ToManager(); + // delay time parameter + var paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Time", + Label = "MilSecs", + ShortLabel = "ms", + MinInteger = 0, + MaxInteger = 1000, + LargeStepInteger = 100, + StepInteger = 10, + DefaultValue = 200f + }; + DelayTimeMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // feedback parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Feedbck", - Label = "Factor", - ShortLabel = "*", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.4f - }; - FeedbackMgr = paramInfo - .Normalize() - .ToManager(); + // feedback parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Feedbck", + Label = "Factor", + ShortLabel = "*", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.4f + }; + FeedbackMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // dry Level parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Dry Lvl", - Label = "Decibel", - ShortLabel = "Db", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.8f - }; - DryLevelMgr = paramInfo - .Normalize() - .ToManager(); + // dry Level parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Dry Lvl", + Label = "Decibel", + ShortLabel = "Db", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.8f + }; + DryLevelMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // wet Level parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Wet Lvl", - Label = "Decibel", - ShortLabel = "Db", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.4f - }; - WetLevelMgr = paramInfo - .Normalize() - .ToManager(); + // wet Level parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Wet Lvl", + Label = "Decibel", + ShortLabel = "Db", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.4f + }; + WetLevelMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); - } + parameterInfos.Add(paramInfo); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/Jacobi.Vst.Samples.Delay.csproj b/Source/Samples/Jacobi.Vst.Samples.Delay/Jacobi.Vst.Samples.Delay.csproj index bf3f60c1..991f07d6 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/Jacobi.Vst.Samples.Delay.csproj +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/Jacobi.Vst.Samples.Delay.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0-windows 2.1.0 Marc Jacobi Jacobi Software @@ -17,7 +17,7 @@ - + diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/Plugin.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/Plugin.cs index 7b1d98cd..7a5bbd6a 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/Plugin.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/Plugin.cs @@ -3,51 +3,50 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using Microsoft.Extensions.DependencyInjection; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// The Plugin root object. +/// +internal sealed class Plugin : VstPluginWithServices { + /// A unique plugin id. + private static readonly int UniquePluginId = 0x3A3A3A3A; + /// The plugin name. + private const string PluginName = "VST.NET 2 Delay Sample Plugin"; + /// The product name. + private const string ProductName = "VST.NET 2 Code Samples"; + /// The vendor name. + private const string VendorName = "Jacobi Software © 2008-2024"; + /// The plugin version. + private const int PluginVersion = 2000; + /// Delay => Room Effect + private const VstPluginCategory PluginCategory = VstPluginCategory.RoomFx; + /// Need nothing special. + private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.None; /// - /// The Plugin root object. + /// The number of samples the Delay plugin lags behind. /// - internal sealed class Plugin : VstPluginWithServices - { - /// A unique plugin id. - private static readonly int UniquePluginId = 0x3A3A3A3A; - /// The plugin name. - private const string PluginName = "VST.NET 2 Delay Sample Plugin"; - /// The product name. - private const string ProductName = "VST.NET 2 Code Samples"; - /// The vendor name. - private const string VendorName = "Jacobi Software © 2008-2020"; - /// The plugin version. - private const int PluginVersion = 2000; - /// Delay => Room Effect - private const VstPluginCategory PluginCategory = VstPluginCategory.RoomFx; - /// Need nothing special. - private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.None; - /// - /// The number of samples the Delay plugin lags behind. - /// - private const int InitialDelayInSamples = 0; + private const int InitialDelayInSamples = 0; - /// - /// Initializes the one an only instance of the Plugin root object. - /// - public Plugin() - : base(PluginName, UniquePluginId, - new VstProductInfo(ProductName, VendorName, PluginVersion), - PluginCategory, InitialDelayInSamples, PluginCapabilities) - { } + /// + /// Initializes the one an only instance of the Plugin root object. + /// + public Plugin() + : base(PluginName, UniquePluginId, + new VstProductInfo(ProductName, VendorName, PluginVersion), + PluginCategory, InitialDelayInSamples, PluginCapabilities) + { } - /// - /// Called once to get all the plugin components. - /// - /// Is never null. - protected override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll(); - } + /// + /// Called once to get all the plugin components. + /// + /// Is never null. + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginCommandStub.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginCommandStub.cs index 7d7a2af4..576159f2 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginCommandStub.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginCommandStub.cs @@ -1,27 +1,26 @@ using Jacobi.Vst.Plugin.Framework; using Jacobi.Vst.Plugin.Framework.Plugin; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// This object receives all calls from the (unmanaged) host. +/// +/// +/// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly +/// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ +/// to this object. +/// +public class PluginCommandStub : StdPluginCommandStub { /// - /// This object receives all calls from the (unmanaged) host. + /// Returns an instance of the VST.NET Plugin root object. /// - /// - /// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly - /// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ - /// to this object. - /// - public class PluginCommandStub : StdPluginCommandStub + /// Must never return null. + protected override IVstPlugin CreatePluginInstance() { - /// - /// Returns an instance of the VST.NET Plugin root object. - /// - /// Must never return null. - protected override IVstPlugin CreatePluginInstance() - { - // StdPluginCommandStub implements all the VST2 methods, - // all you have to do is give the Framework your plugin root. - return new Plugin(); - } + // StdPluginCommandStub implements all the VST2 methods, + // all you have to do is give the Framework your plugin root. + return new Plugin(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginEditor.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginEditor.cs index efebf957..b1542465 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginEditor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginEditor.cs @@ -6,67 +6,66 @@ using System.Linq; using Jacobi.Vst.Samples.Delay.UI; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// This object manages the custom editor (UI) for your plugin. +/// +/// +/// When you do not implement a custom editor, +/// your Parameters will be displayed in an editor provided by the host. +/// +internal sealed class PluginEditor : IVstPluginEditor { - /// - /// This object manages the custom editor (UI) for your plugin. - /// - /// - /// When you do not implement a custom editor, - /// your Parameters will be displayed in an editor provided by the host. - /// - internal sealed class PluginEditor : IVstPluginEditor - { - private readonly PluginParameters _parameters; - private readonly WinFormsControlWrapper _view; + private readonly PluginParameters _parameters; + private readonly WinFormsControlWrapper _view; - public PluginEditor(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - _view = new WinFormsControlWrapper(); - } + public PluginEditor(PluginParameters parameters) + { + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + _view = new WinFormsControlWrapper(); + } - public Rectangle Bounds - { - get { return _view.Bounds; } - } + public Rectangle Bounds + { + get { return _view.Bounds; } + } - public void Close() - { - _view.Close(); - } + public void Close() + { + _view.Close(); + } - public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public VstKnobMode KnobMode { get; set; } + public VstKnobMode KnobMode { get; set; } - public void Open(IntPtr hWnd) - { - // make a list of parameters to pass to the dlg. - var paramList = _parameters.ParameterInfos - .Where(p => p.ParameterManager != null) - .Select(p => p.ParameterManager!) - .ToList(); + public void Open(IntPtr hWnd) + { + // make a list of parameters to pass to the dlg. + var paramList = _parameters.ParameterInfos + .Where(p => p.ParameterManager != null) + .Select(p => p.ParameterManager!) + .ToList(); - _view.SafeInstance.InitializeParameters(paramList); + _view.SafeInstance.InitializeParameters(paramList); - _view.Open(hWnd); - } + _view.Open(hWnd); + } - public void ProcessIdle() - { - // keep your processing short! - _view.SafeInstance.ProcessIdle(); - } + public void ProcessIdle() + { + // keep your processing short! + _view.SafeInstance.ProcessIdle(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginParameters.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginParameters.cs index 3978c9d0..24cd5b62 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginParameters.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginParameters.cs @@ -3,77 +3,76 @@ using System.Linq; using Jacobi.Vst.Samples.Delay.Dsp; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// A central location for all plugin parameters +/// +internal sealed class PluginParameters { /// - /// A central location for all plugin parameters + /// Initializes all plugin parameters (one component at a time). /// - internal sealed class PluginParameters + public PluginParameters(IVstPluginEvents pluginEvents) { - /// - /// Initializes all plugin parameters (one component at a time). - /// - public PluginParameters(IVstPluginEvents pluginEvents) - { - // register the parameters of all plugin (sub) components - DelayParameters = new DelayParameters(this); + // register the parameters of all plugin (sub) components + DelayParameters = new DelayParameters(this); - pluginEvents.Opened += Plugin_Opened; - } + pluginEvents.Opened += Plugin_Opened; + } - private void Plugin_Opened(object? sender, System.EventArgs e) - { - var plugin = (VstPlugin?)sender; - SetHostAutomation(plugin?.Host?.GetInstance()); - } + private void Plugin_Opened(object? sender, System.EventArgs e) + { + var plugin = (VstPlugin?)sender; + SetHostAutomation(plugin?.Host?.GetInstance()); + } - public DelayParameters DelayParameters { get; private set; } + public DelayParameters DelayParameters { get; private set; } - /// - /// Gets the central list of parameter categories. - /// - public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); + /// + /// Gets the central list of parameter categories. + /// + public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); - /// - /// Gets the central list of parameter definitions. - /// - public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); + /// + /// Gets the central list of parameter definitions. + /// + public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); - /// - /// Retrieves a parameter category object for the specified . - /// - /// The name of the parameter category. - /// Typically the name of a Dsp component, an effect or function. - /// Never returns null. - public VstParameterCategory GetParameterCategory(string categoryName) + /// + /// Retrieves a parameter category object for the specified . + /// + /// The name of the parameter category. + /// Typically the name of a Dsp component, an effect or function. + /// Never returns null. + public VstParameterCategory GetParameterCategory(string categoryName) + { + if (Categories.Contains(categoryName)) { - if (Categories.Contains(categoryName)) - { - return Categories[categoryName]; - } + return Categories[categoryName]; + } - // create a new parameter category object - var paramCategory = new VstParameterCategory - { - Name = categoryName - }; + // create a new parameter category object + var paramCategory = new VstParameterCategory + { + Name = categoryName + }; - Categories.Add(paramCategory); + Categories.Add(paramCategory); - return paramCategory; - } + return paramCategory; + } - /// - /// Assigns the to all s. - /// - /// - private void SetHostAutomation(IVstHostAutomation? hostAutomation) + /// + /// Assigns the to all s. + /// + /// + private void SetHostAutomation(IVstHostAutomation? hostAutomation) + { + foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) { - foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) - { - if (paramMgr != null) - paramMgr.HostAutomation = hostAutomation; - } + if (paramMgr != null) + paramMgr.HostAutomation = hostAutomation; } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginPrograms.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginPrograms.cs index 7a7dc091..e4a49399 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/PluginPrograms.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/PluginPrograms.cs @@ -2,73 +2,72 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using System; -namespace Jacobi.Vst.Samples.Delay +namespace Jacobi.Vst.Samples.Delay; + +/// +/// This object manages the Plugin programs and its parameters. +/// +internal sealed class PluginPrograms : VstPluginPrograms { + private readonly PluginParameters _parameters; + /// - /// This object manages the Plugin programs and its parameters. + /// Constructs an instance on the plugin parameter factory /// - internal sealed class PluginPrograms : VstPluginPrograms + /// Must not be null. + public PluginPrograms(PluginParameters parameters) { - private readonly PluginParameters _parameters; - - /// - /// Constructs an instance on the plugin parameter factory - /// - /// Must not be null. - public PluginPrograms(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - } + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + } - /// - /// Called to initialize the collection of programs for the plugin. - /// - /// Never returns null or an empty collection. - protected override VstProgramCollection CreateProgramCollection() - { - var programs = new VstProgramCollection(); + /// + /// Called to initialize the collection of programs for the plugin. + /// + /// Never returns null or an empty collection. + protected override VstProgramCollection CreateProgramCollection() + { + var programs = new VstProgramCollection(); - var prog = CreateProgram("Program 1"); - programs.Add(prog); - prog = CreateProgram("Program 2"); - programs.Add(prog); - prog = CreateProgram("Program 3"); - programs.Add(prog); + var prog = CreateProgram("Program 1"); + programs.Add(prog); + prog = CreateProgram("Program 2"); + programs.Add(prog); + prog = CreateProgram("Program 3"); + programs.Add(prog); - return programs; - } + return programs; + } - private VstProgram CreateProgram(string name) - { - var program = CreateProgram(); - program.Name = name; - return program; - } + private VstProgram CreateProgram(string name) + { + var program = CreateProgram(); + program.Name = name; + return program; + } - // create a program with all parameters. - private VstProgram CreateProgram() - { - var program = new VstProgram(_parameters.Categories); + // create a program with all parameters. + private VstProgram CreateProgram() + { + var program = new VstProgram(_parameters.Categories); - CreateParameters(program.Parameters, _parameters.ParameterInfos); + CreateParameters(program.Parameters, _parameters.ParameterInfos); - return program; - } + return program; + } - // create all parameters - private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + // create all parameters + private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + { + foreach (VstParameterInfo paramInfo in parameterInfos) { - foreach (VstParameterInfo paramInfo in parameterInfos) - { - desitnation.Add(CreateParameter(paramInfo)); - } + desitnation.Add(CreateParameter(paramInfo)); } + } - // create one parameter - private VstParameter CreateParameter(VstParameterInfo parameterInfo) - { - // Advanced: you can derive from VstParameter and add your own properties and logic. - return new VstParameter(parameterInfo); - } + // create one parameter + private VstParameter CreateParameter(VstParameterInfo parameterInfo) + { + // Advanced: you can derive from VstParameter and add your own properties and logic. + return new VstParameter(parameterInfo); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Delay/UI/PluginEditorView.cs b/Source/Samples/Jacobi.Vst.Samples.Delay/UI/PluginEditorView.cs index 48910554..2d846c1f 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Delay/UI/PluginEditorView.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Delay/UI/PluginEditorView.cs @@ -1,122 +1,123 @@ using Jacobi.Vst.Plugin.Framework; using System.Collections.Generic; +using System.Runtime.Versioning; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.Delay.UI +namespace Jacobi.Vst.Samples.Delay.UI; + +[SupportedOSPlatform("windows")] +public partial class PluginEditorView : UserControl { - public partial class PluginEditorView : UserControl + public PluginEditorView() { - public PluginEditorView() - { - InitializeComponent(); - } - - internal bool InitializeParameters(IList parameters) - { - if (parameters == null || parameters.Count < 4) - return false; - - BindParameter(parameters[0], label1, trackBar1, label5); - BindParameter(parameters[1], label2, trackBar2, label6); - BindParameter(parameters[2], label3, trackBar3, label7); - BindParameter(parameters[3], label4, trackBar4, label8); - - return true; - } + InitializeComponent(); + } - private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) - { - label.Text = paramMgr.ParameterInfo.Name; - shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; + internal bool InitializeParameters(IList parameters) + { + if (parameters == null || parameters.Count < 4) + return false; - var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); - var paramState = new ParameterControlState(paramMgr, factor); + BindParameter(parameters[0], label1, trackBar1, label5); + BindParameter(parameters[1], label2, trackBar2, label6); + BindParameter(parameters[2], label3, trackBar3, label7); + BindParameter(parameters[3], label4, trackBar4, label8); - // use databinding for VstParameter/Manager changed notifications. - trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); - trackBar.ValueChanged += TrackBar_ValueChanged; - trackBar.Tag = paramState; - } + return true; + } - private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) - { - // A multiplication factor to convert floats (0.0-1.0) - // to an integer range for the TrackBar to work with. - float factor = 1.0f; + private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) + { + label.Text = paramMgr.ParameterInfo.Name; + shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; - if (parameterInfo.IsSwitch) - { - trackBar.Minimum = 0; - trackBar.Maximum = 1; - trackBar.LargeChange = 1; - trackBar.SmallChange = 1; - return factor; - } + var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); + var paramState = new ParameterControlState(paramMgr, factor); - if (parameterInfo.IsStepIntegerValid) - { - trackBar.LargeChange = parameterInfo.LargeStepInteger; - trackBar.SmallChange = parameterInfo.StepInteger; - } - else if (parameterInfo.IsStepFloatValid) - { - factor = 1 / parameterInfo.StepFloat; - trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); - trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); - } + // use databinding for VstParameter/Manager changed notifications. + trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); + trackBar.ValueChanged += TrackBar_ValueChanged; + trackBar.Tag = paramState; + } - if (parameterInfo.IsMinMaxIntegerValid) - { - trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); - trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); - } - else - { - trackBar.Minimum = 0; - trackBar.Maximum = (int)factor; - } + private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) + { + // A multiplication factor to convert floats (0.0-1.0) + // to an integer range for the TrackBar to work with. + float factor = 1.0f; + if (parameterInfo.IsSwitch) + { + trackBar.Minimum = 0; + trackBar.Maximum = 1; + trackBar.LargeChange = 1; + trackBar.SmallChange = 1; return factor; } - private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + if (parameterInfo.IsStepIntegerValid) { - var trackBar = (TrackBar?)sender; - var paramState = (ParameterControlState?)trackBar?.Tag; + trackBar.LargeChange = parameterInfo.LargeStepInteger; + trackBar.SmallChange = parameterInfo.StepInteger; + } + else if (parameterInfo.IsStepFloatValid) + { + factor = 1 / parameterInfo.StepFloat; + trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); + trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); + } - if (trackBar != null && - paramState?.ParameterManager.ActiveParameter != null) - { - paramState.ParameterManager.ActiveParameter.Value = - trackBar.Value / paramState.ValueFactor; - } + if (parameterInfo.IsMinMaxIntegerValid) + { + trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); + trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); } + else + { + trackBar.Minimum = 0; + trackBar.Maximum = (int)factor; + } + + return factor; + } + + private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + { + var trackBar = (TrackBar?)sender; + var paramState = (ParameterControlState?)trackBar?.Tag; - internal void ProcessIdle() + if (trackBar != null && + paramState?.ParameterManager.ActiveParameter != null) { - // TODO: short idle processing here + paramState.ParameterManager.ActiveParameter.Value = + trackBar.Value / paramState.ValueFactor; } + } + + internal void ProcessIdle() + { + // TODO: short idle processing here + } - /// - /// This class converts the parameter value range to a compatible (integer) TrackBar value range. - /// - private sealed class ParameterControlState + /// + /// This class converts the parameter value range to a compatible (integer) TrackBar value range. + /// + private sealed class ParameterControlState + { + public ParameterControlState(VstParameterManager parameterManager, float valueFactor) { - public ParameterControlState(VstParameterManager parameterManager, float valueFactor) - { - ParameterManager = parameterManager; - ValueFactor = valueFactor; - } + ParameterManager = parameterManager; + ValueFactor = valueFactor; + } - public VstParameterManager ParameterManager { get; } - public float ValueFactor { get; } + public VstParameterManager ParameterManager { get; } + public float ValueFactor { get; } - public int Value + public int Value + { + get { - get - { - return (int)(ParameterManager.CurrentValue * ValueFactor); - } + return (int)(ParameterManager.CurrentValue * ValueFactor); } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/DummyHostCommandStub.cs b/Source/Samples/Jacobi.Vst.Samples.Host/DummyHostCommandStub.cs index 87a0b60d..25c7e349 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/DummyHostCommandStub.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Host/DummyHostCommandStub.cs @@ -2,280 +2,279 @@ using Jacobi.Vst.Core.Host; using System; -namespace Jacobi.Vst.Samples.Host +namespace Jacobi.Vst.Samples.Host; + +/// +/// The HostCommandStub class represents the part of the host that a plugin can call. +/// This is a dummy implementation that simply logs each call to a delegate. +/// +internal sealed class DummyHostCommandStub : IVstHostCommandStub { + public DummyHostCommandStub() + { + Commands = new DummyHostCommands(this); + } + + /// + /// Only there to show a log on the screen. + /// You would not normally do this, instead handle each call directly. + /// + public event EventHandler PluginCalled; + + private void RaisePluginCalled(string message) + { + PluginCalled?.Invoke(this, new PluginCalledEventArgs(message)); + } + /// - /// The HostCommandStub class represents the part of the host that a plugin can call. - /// This is a dummy implementation that simply logs each call to a delegate. + /// Attached to the EditorFrame for a plugin. /// - internal sealed class DummyHostCommandStub : IVstHostCommandStub + public event EventHandler SizeWindow; + + private void RaiseSizeWindow(int width, int height) { - public DummyHostCommandStub() + SizeWindow?.Invoke(this, new SizeWindowEventArgs(width, height)); + } + + #region IVstHostCommandsStub Members + + /// + public IVstPluginContext PluginContext { get; set; } + + public IVstHostCommands20 Commands { get; private set; } + + #endregion + + private sealed class DummyHostCommands : IVstHostCommands20 + { + private readonly DummyHostCommandStub _cmdStub; + + public DummyHostCommands(DummyHostCommandStub cmdStub) + { + _cmdStub = cmdStub; + } + + #region IVstHostCommands20 Members + + /// + public bool BeginEdit(int index) + { + _cmdStub.RaisePluginCalled("BeginEdit(" + index + ")"); + return false; + } + + /// + public Jacobi.Vst.Core.VstCanDoResult CanDo(string cando) + { + _cmdStub.RaisePluginCalled("CanDo(" + cando + ")"); + return Jacobi.Vst.Core.VstCanDoResult.Unknown; + } + + /// + public bool CloseFileSelector(Jacobi.Vst.Core.VstFileSelect fileSelect) + { + _cmdStub.RaisePluginCalled("CloseFileSelector(" + fileSelect.Command + ")"); + return false; + } + + /// + public bool EndEdit(int index) + { + _cmdStub.RaisePluginCalled("EndEdit(" + index + ")"); + return false; + } + + /// + public Jacobi.Vst.Core.VstAutomationStates GetAutomationState() + { + _cmdStub.RaisePluginCalled("GetAutomationState()"); + return Jacobi.Vst.Core.VstAutomationStates.Off; + } + + /// + public int GetBlockSize() + { + _cmdStub.RaisePluginCalled("GetBlockSize()"); + return 1024; + } + + /// + public string GetDirectory() + { + _cmdStub.RaisePluginCalled("GetDirectory()"); + return null; + } + + /// + public int GetInputLatency() + { + _cmdStub.RaisePluginCalled("GetInputLatency()"); + return 0; + } + + /// + public Jacobi.Vst.Core.VstHostLanguage GetLanguage() + { + _cmdStub.RaisePluginCalled("GetLanguage()"); + return Jacobi.Vst.Core.VstHostLanguage.NotSupported; + } + + /// + public int GetOutputLatency() + { + _cmdStub.RaisePluginCalled("GetOutputLatency()"); + return 0; + } + + /// + public Jacobi.Vst.Core.VstProcessLevels GetProcessLevel() { - Commands = new DummyHostCommands(this); + _cmdStub.RaisePluginCalled("GetProcessLevel()"); + return Jacobi.Vst.Core.VstProcessLevels.Unknown; } - /// - /// Only there to show a log on the screen. - /// You would not normally do this, instead handle each call directly. - /// - public event EventHandler PluginCalled; + /// + public string GetProductString() + { + _cmdStub.RaisePluginCalled("GetProductString()"); + return "VST.NET"; + } - private void RaisePluginCalled(string message) + /// + public float GetSampleRate() { - PluginCalled?.Invoke(this, new PluginCalledEventArgs(message)); + _cmdStub.RaisePluginCalled("GetSampleRate()"); + return 44.8f; } - /// - /// Attached to the EditorFrame for a plugin. - /// - public event EventHandler SizeWindow; + /// + public Jacobi.Vst.Core.VstTimeInfo GetTimeInfo(Jacobi.Vst.Core.VstTimeInfoFlags filterFlags) + { + _cmdStub.RaisePluginCalled("GetTimeInfo(" + filterFlags + ")"); + return null; + } - private void RaiseSizeWindow(int width, int height) + /// + public string GetVendorString() { - SizeWindow?.Invoke(this, new SizeWindowEventArgs(width, height)); + _cmdStub.RaisePluginCalled("GetVendorString()"); + return "Jacobi Software"; } - #region IVstHostCommandsStub Members + /// + public int GetVendorVersion() + { + _cmdStub.RaisePluginCalled("GetVendorVersion()"); + return 1000; + } /// - public IVstPluginContext PluginContext { get; set; } + public bool IoChanged() + { + _cmdStub.RaisePluginCalled("IoChanged()"); + return false; + } - public IVstHostCommands20 Commands { get; private set; } + /// + public bool OpenFileSelector(Jacobi.Vst.Core.VstFileSelect fileSelect) + { + _cmdStub.RaisePluginCalled("OpenFileSelector(" + fileSelect.Command + ")"); + return false; + } + + /// + public bool ProcessEvents(Jacobi.Vst.Core.VstEvent[] events) + { + _cmdStub.RaisePluginCalled("ProcessEvents(" + events.Length + ")"); + return false; + } + + /// + public bool SizeWindow(int width, int height) + { + _cmdStub.RaisePluginCalled("SizeWindow(" + width + ", " + height + ")"); + _cmdStub.RaiseSizeWindow(width, height); + return false; + } + + /// + public bool UpdateDisplay() + { + _cmdStub.RaisePluginCalled("UpdateDisplay()"); + return false; + } #endregion - private sealed class DummyHostCommands : IVstHostCommands20 + #region IVstHostCommands10 Members + + /// + public int GetCurrentPluginID() { - private readonly DummyHostCommandStub _cmdStub; - - public DummyHostCommands(DummyHostCommandStub cmdStub) - { - _cmdStub = cmdStub; - } - - #region IVstHostCommands20 Members - - /// - public bool BeginEdit(int index) - { - _cmdStub.RaisePluginCalled("BeginEdit(" + index + ")"); - return false; - } - - /// - public Jacobi.Vst.Core.VstCanDoResult CanDo(string cando) - { - _cmdStub.RaisePluginCalled("CanDo(" + cando + ")"); - return Jacobi.Vst.Core.VstCanDoResult.Unknown; - } - - /// - public bool CloseFileSelector(Jacobi.Vst.Core.VstFileSelect fileSelect) - { - _cmdStub.RaisePluginCalled("CloseFileSelector(" + fileSelect.Command + ")"); - return false; - } - - /// - public bool EndEdit(int index) - { - _cmdStub.RaisePluginCalled("EndEdit(" + index + ")"); - return false; - } - - /// - public Jacobi.Vst.Core.VstAutomationStates GetAutomationState() - { - _cmdStub.RaisePluginCalled("GetAutomationState()"); - return Jacobi.Vst.Core.VstAutomationStates.Off; - } - - /// - public int GetBlockSize() - { - _cmdStub.RaisePluginCalled("GetBlockSize()"); - return 1024; - } - - /// - public string GetDirectory() - { - _cmdStub.RaisePluginCalled("GetDirectory()"); - return null; - } - - /// - public int GetInputLatency() - { - _cmdStub.RaisePluginCalled("GetInputLatency()"); - return 0; - } - - /// - public Jacobi.Vst.Core.VstHostLanguage GetLanguage() - { - _cmdStub.RaisePluginCalled("GetLanguage()"); - return Jacobi.Vst.Core.VstHostLanguage.NotSupported; - } - - /// - public int GetOutputLatency() - { - _cmdStub.RaisePluginCalled("GetOutputLatency()"); - return 0; - } - - /// - public Jacobi.Vst.Core.VstProcessLevels GetProcessLevel() - { - _cmdStub.RaisePluginCalled("GetProcessLevel()"); - return Jacobi.Vst.Core.VstProcessLevels.Unknown; - } - - /// - public string GetProductString() - { - _cmdStub.RaisePluginCalled("GetProductString()"); - return "VST.NET"; - } - - /// - public float GetSampleRate() - { - _cmdStub.RaisePluginCalled("GetSampleRate()"); - return 44.8f; - } - - /// - public Jacobi.Vst.Core.VstTimeInfo GetTimeInfo(Jacobi.Vst.Core.VstTimeInfoFlags filterFlags) - { - _cmdStub.RaisePluginCalled("GetTimeInfo(" + filterFlags + ")"); - return null; - } - - /// - public string GetVendorString() - { - _cmdStub.RaisePluginCalled("GetVendorString()"); - return "Jacobi Software"; - } - - /// - public int GetVendorVersion() - { - _cmdStub.RaisePluginCalled("GetVendorVersion()"); - return 1000; - } - - /// - public bool IoChanged() - { - _cmdStub.RaisePluginCalled("IoChanged()"); - return false; - } - - /// - public bool OpenFileSelector(Jacobi.Vst.Core.VstFileSelect fileSelect) - { - _cmdStub.RaisePluginCalled("OpenFileSelector(" + fileSelect.Command + ")"); - return false; - } - - /// - public bool ProcessEvents(Jacobi.Vst.Core.VstEvent[] events) - { - _cmdStub.RaisePluginCalled("ProcessEvents(" + events.Length + ")"); - return false; - } - - /// - public bool SizeWindow(int width, int height) - { - _cmdStub.RaisePluginCalled("SizeWindow(" + width + ", " + height + ")"); - _cmdStub.RaiseSizeWindow(width, height); - return false; - } - - /// - public bool UpdateDisplay() - { - _cmdStub.RaisePluginCalled("UpdateDisplay()"); - return false; - } - - #endregion - - #region IVstHostCommands10 Members - - /// - public int GetCurrentPluginID() - { - _cmdStub.RaisePluginCalled("GetCurrentPluginID()"); - // this is the plugin Id the host wants to load - // for shell plugins (a plugin that hosts other plugins) - return 0; - } - - /// - public int GetVersion() - { - _cmdStub.RaisePluginCalled("GetVersion()"); - return 1000; - } - - /// - public void ProcessIdle() - { - _cmdStub.RaisePluginCalled("ProcessIdle()"); - } - - /// - public void SetParameterAutomated(int index, float value) - { - _cmdStub.RaisePluginCalled("SetParameterAutomated(" + index + ", " + value + ")"); - } - - #endregion + _cmdStub.RaisePluginCalled("GetCurrentPluginID()"); + // this is the plugin Id the host wants to load + // for shell plugins (a plugin that hosts other plugins) + return 0; } - } - /// - /// Event arguments used when one of the methods is called. - /// - internal sealed class PluginCalledEventArgs : EventArgs - { - /// - /// Constructs a new instance with a . - /// - /// - public PluginCalledEventArgs(string message) + /// + public int GetVersion() + { + _cmdStub.RaisePluginCalled("GetVersion()"); + return 1000; + } + + /// + public void ProcessIdle() + { + _cmdStub.RaisePluginCalled("ProcessIdle()"); + } + + /// + public void SetParameterAutomated(int index, float value) { - Message = message; + _cmdStub.RaisePluginCalled("SetParameterAutomated(" + index + ", " + value + ")"); } - /// - /// Gets the message. - /// - public string Message { get; private set; } + #endregion } +} +/// +/// Event arguments used when one of the methods is called. +/// +internal sealed class PluginCalledEventArgs : EventArgs +{ /// - /// Event arguments used when the SizeWindow method is called. + /// Constructs a new instance with a . /// - internal sealed class SizeWindowEventArgs : EventArgs + /// + public PluginCalledEventArgs(string message) { - /// - /// Constructs a new instance with a . - /// - /// - public SizeWindowEventArgs(int width, int height) - { - Width = width; - Height = height; - } + Message = message; + } - public int Width { get; } - public int Height { get; } + /// + /// Gets the message. + /// + public string Message { get; private set; } +} + +/// +/// Event arguments used when the SizeWindow method is called. +/// +internal sealed class SizeWindowEventArgs : EventArgs +{ + /// + /// Constructs a new instance with a . + /// + /// + public SizeWindowEventArgs(int width, int height) + { + Width = width; + Height = height; } + + public int Width { get; } + public int Height { get; } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/EditorFrame.cs b/Source/Samples/Jacobi.Vst.Samples.Host/EditorFrame.cs index a3d61bd3..4bdf06ee 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/EditorFrame.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Host/EditorFrame.cs @@ -2,74 +2,73 @@ using System.Windows.Forms; using Jacobi.Vst.Core.Host; -namespace Jacobi.Vst.Samples.Host +namespace Jacobi.Vst.Samples.Host; + +/// +/// The frame in which a custom plugin editor UI is displayed. +/// +public partial class EditorFrame : Form { /// - /// The frame in which a custom plugin editor UI is displayed. + /// Default ctor. /// - public partial class EditorFrame : Form + public EditorFrame() { - /// - /// Default ctor. - /// - public EditorFrame() - { - InitializeComponent(); - } + InitializeComponent(); + } - /// - /// Gets or sets the Plugin Command Stub. - /// - public IVstPluginCommandStub PluginCommandStub { get; set; } + /// + /// Gets or sets the Plugin Command Stub. + /// + public IVstPluginCommandStub PluginCommandStub { get; set; } - internal DummyHostCommandStub HostCommandStub { get; set; } + internal DummyHostCommandStub HostCommandStub { get; set; } - /// - /// Shows the custom plugin editor UI. - /// - /// - /// - public new DialogResult ShowDialog(IWin32Window owner) - { - HostCommandStub.SizeWindow += this.OnSizeWindow; + /// + /// Shows the custom plugin editor UI. + /// + /// + /// + public new DialogResult ShowDialog(IWin32Window owner) + { + HostCommandStub.SizeWindow += this.OnSizeWindow; - PluginCommandStub.Commands.EditorGetRect(out var rect); - this.Size = this.SizeFromClientSize(rect.Size); + PluginCommandStub.Commands.EditorGetRect(out var rect); + this.Size = this.SizeFromClientSize(rect.Size); - this.Text = PluginCommandStub.Commands.GetEffectName(); - PluginCommandStub.Commands.EditorOpen(this.Handle); + this.Text = PluginCommandStub.Commands.GetEffectName(); + PluginCommandStub.Commands.EditorOpen(this.Handle); - var result = base.ShowDialog(owner); + var result = base.ShowDialog(owner); - // to show a plugin UI without blocking the rest of the Host UI. - //base.Show(owner); - //result = DialogResult.OK; + // to show a plugin UI without blocking the rest of the Host UI. + //base.Show(owner); + //result = DialogResult.OK; - HostCommandStub.SizeWindow -= this.OnSizeWindow; - return result; - } + HostCommandStub.SizeWindow -= this.OnSizeWindow; + return result; + } - internal void OnSizeWindow(object sender, SizeWindowEventArgs args) - { - this.Size = this.SizeFromClientSize(new Size(args.Width, args.Height)); - } + internal void OnSizeWindow(object sender, SizeWindowEventArgs args) + { + this.Size = this.SizeFromClientSize(new Size(args.Width, args.Height)); + } - protected override void OnClosing(System.ComponentModel.CancelEventArgs e) - { - base.OnClosing(e); + protected override void OnClosing(System.ComponentModel.CancelEventArgs e) + { + base.OnClosing(e); - if (!e.Cancel) - { - PluginCommandStub.Commands.EditorClose(); - } + if (!e.Cancel) + { + PluginCommandStub.Commands.EditorClose(); } + } - private void EditorFrame_Load(object sender, System.EventArgs e) + private void EditorFrame_Load(object sender, System.EventArgs e) + { + if (PluginCommandStub.Commands.EditorGetRect(out Rectangle wndRect)) { - if (PluginCommandStub.Commands.EditorGetRect(out Rectangle wndRect)) - { - this.Size = this.SizeFromClientSize(wndRect.Size); - } + this.Size = this.SizeFromClientSize(wndRect.Size); } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/Jacobi.Vst.Samples.Host.csproj b/Source/Samples/Jacobi.Vst.Samples.Host/Jacobi.Vst.Samples.Host.csproj index 2e85d63a..6f96dc82 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/Jacobi.Vst.Samples.Host.csproj +++ b/Source/Samples/Jacobi.Vst.Samples.Host/Jacobi.Vst.Samples.Host.csproj @@ -2,7 +2,7 @@ WinExe - net6.0-windows + net8.0-windows true 2.1.0 Marc Jacobi @@ -13,7 +13,7 @@ - + \ No newline at end of file diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/MainForm.cs b/Source/Samples/Jacobi.Vst.Samples.Host/MainForm.cs index 74cebced..e21cb15d 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/MainForm.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Host/MainForm.cs @@ -4,149 +4,148 @@ using System.Diagnostics; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.Host +namespace Jacobi.Vst.Samples.Host; + +partial class MainForm : Form { - partial class MainForm : Form + private List _plugins = new List(); + + public MainForm() { - private List _plugins = new List(); + InitializeComponent(); + Text = "VST.NET 2 Dummy Host Sample"; + } - public MainForm() - { - InitializeComponent(); - Text = "VST.NET 2 Dummy Host Sample"; - } + private void FillPluginList() + { + PluginListVw.Items.Clear(); - private void FillPluginList() + foreach (VstPluginContext ctx in _plugins) { - PluginListVw.Items.Clear(); - - foreach (VstPluginContext ctx in _plugins) - { - var lvItem = new ListViewItem(ctx.PluginCommandStub.Commands.GetEffectName()); - lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetProductString()); - lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetVendorString()); - lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetVendorVersion().ToString()); - lvItem.SubItems.Add(ctx.Find("PluginPath")); - lvItem.Tag = ctx; - - PluginListVw.Items.Add(lvItem); - } + var lvItem = new ListViewItem(ctx.PluginCommandStub.Commands.GetEffectName()); + lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetProductString()); + lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetVendorString()); + lvItem.SubItems.Add(ctx.PluginCommandStub.Commands.GetVendorVersion().ToString()); + lvItem.SubItems.Add(ctx.Find("PluginPath")); + lvItem.Tag = ctx; + + PluginListVw.Items.Add(lvItem); } + } - private VstPluginContext OpenPlugin(string pluginPath) + private VstPluginContext OpenPlugin(string pluginPath) + { + try { - try - { - var hostCmdStub = new DummyHostCommandStub(); - hostCmdStub.PluginCalled += new EventHandler(HostCmdStub_PluginCalled); - - var ctx = VstPluginContext.Create(pluginPath, hostCmdStub); + var hostCmdStub = new DummyHostCommandStub(); + hostCmdStub.PluginCalled += new EventHandler(HostCmdStub_PluginCalled); - // add custom data to the context - ctx.Set("PluginPath", pluginPath); - ctx.Set("HostCmdStub", hostCmdStub); + var ctx = VstPluginContext.Create(pluginPath, hostCmdStub); - // actually open the plugin itself - ctx.PluginCommandStub.Commands.Open(); + // add custom data to the context + ctx.Set("PluginPath", pluginPath); + ctx.Set("HostCmdStub", hostCmdStub); - return ctx; - } - catch (Exception e) - { - MessageBox.Show(this, e.ToString(), Text, MessageBoxButtons.OK, MessageBoxIcon.Error); - } + // actually open the plugin itself + ctx.PluginCommandStub.Commands.Open(); - return null; + return ctx; } - - private void ReleaseAllPlugins() + catch (Exception e) { - foreach (VstPluginContext ctx in _plugins) - { - // dispose of all (unmanaged) resources - ctx.Dispose(); - } - - _plugins.Clear(); + MessageBox.Show(this, e.ToString(), Text, MessageBoxButtons.OK, MessageBoxIcon.Error); } - private VstPluginContext SelectedPluginContext - { - get - { - if (PluginListVw.SelectedItems.Count > 0) - { - return (VstPluginContext)PluginListVw.SelectedItems[0].Tag; - } + return null; + } - return null; - } + private void ReleaseAllPlugins() + { + foreach (VstPluginContext ctx in _plugins) + { + // dispose of all (unmanaged) resources + ctx.Dispose(); } - private void HostCmdStub_PluginCalled(object sender, PluginCalledEventArgs e) - { - var hostCmdStub = (DummyHostCommandStub)sender; + _plugins.Clear(); + } - // can be null when called from inside the plugin main entry point. - if (hostCmdStub.PluginContext.PluginInfo != null) - { - Debug.WriteLine("Plugin " + hostCmdStub.PluginContext.PluginInfo.PluginID + " called:" + e.Message); - } - else + private VstPluginContext SelectedPluginContext + { + get + { + if (PluginListVw.SelectedItems.Count > 0) { - Debug.WriteLine("The loading Plugin called:" + e.Message); + return (VstPluginContext)PluginListVw.SelectedItems[0].Tag; } + + return null; } + } - private void BrowseBtn_Click(object sender, EventArgs e) - { - OpenFileDlg.FileName = PluginPathTxt.Text; + private void HostCmdStub_PluginCalled(object sender, PluginCalledEventArgs e) + { + var hostCmdStub = (DummyHostCommandStub)sender; - if (OpenFileDlg.ShowDialog(this) == DialogResult.OK) - { - PluginPathTxt.Text = OpenFileDlg.FileName; - } + // can be null when called from inside the plugin main entry point. + if (hostCmdStub.PluginContext.PluginInfo != null) + { + Debug.WriteLine("Plugin " + hostCmdStub.PluginContext.PluginInfo.PluginID + " called:" + e.Message); } - - private void AddBtn_Click(object sender, EventArgs e) + else { - VstPluginContext ctx = OpenPlugin(PluginPathTxt.Text); - - if (ctx != null) - { - _plugins.Add(ctx); - - FillPluginList(); - } + Debug.WriteLine("The loading Plugin called:" + e.Message); } + } + + private void BrowseBtn_Click(object sender, EventArgs e) + { + OpenFileDlg.FileName = PluginPathTxt.Text; - private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + if (OpenFileDlg.ShowDialog(this) == DialogResult.OK) { - ReleaseAllPlugins(); + PluginPathTxt.Text = OpenFileDlg.FileName; } + } + + private void AddBtn_Click(object sender, EventArgs e) + { + VstPluginContext ctx = OpenPlugin(PluginPathTxt.Text); - private void ViewPluginBtn_Click(object sender, EventArgs e) + if (ctx != null) { - var dlg = new PluginForm - { - PluginContext = SelectedPluginContext - }; + _plugins.Add(ctx); - dlg.ShowDialog(this); + FillPluginList(); } + } + + private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + { + ReleaseAllPlugins(); + } - private void DeleteBtn_Click(object sender, EventArgs e) + private void ViewPluginBtn_Click(object sender, EventArgs e) + { + var dlg = new PluginForm { - VstPluginContext ctx = SelectedPluginContext; + PluginContext = SelectedPluginContext + }; - if (ctx != null) - { - ctx.Dispose(); + dlg.ShowDialog(this); + } + + private void DeleteBtn_Click(object sender, EventArgs e) + { + VstPluginContext ctx = SelectedPluginContext; + + if (ctx != null) + { + ctx.Dispose(); - _plugins.Remove(ctx); + _plugins.Remove(ctx); - FillPluginList(); - } + FillPluginList(); } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/PluginForm.cs b/Source/Samples/Jacobi.Vst.Samples.Host/PluginForm.cs index 5ecf27e9..de9b4db9 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/PluginForm.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Host/PluginForm.cs @@ -5,278 +5,277 @@ using System.Linq; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.Host +namespace Jacobi.Vst.Samples.Host; + +partial class PluginForm : Form { - partial class PluginForm : Form + public PluginForm() { - public PluginForm() - { - InitializeComponent(); - } - - public VstPluginContext PluginContext { get; set; } + InitializeComponent(); + } - private void DataToForm() - { - FillPropertyList(); - FillProgramList(); - FillProgram(); - FillParameterList(); - } + public VstPluginContext PluginContext { get; set; } - private void FillPropertyList() - { - PluginPropertyListVw.Items.Clear(); - - // plugin product - AddProperty("Plugin Name", PluginContext.PluginCommandStub.Commands.GetEffectName()); - AddProperty("Product", PluginContext.PluginCommandStub.Commands.GetProductString()); - AddProperty("Vendor", PluginContext.PluginCommandStub.Commands.GetVendorString()); - AddProperty("Vendor Version", PluginContext.PluginCommandStub.Commands.GetVendorVersion().ToString()); - AddProperty("Vst Support", PluginContext.PluginCommandStub.Commands.GetVstVersion().ToString()); - AddProperty("Plugin Category", PluginContext.PluginCommandStub.Commands.GetCategory().ToString()); - - // plugin info - AddProperty("Flags", PluginContext.PluginInfo.Flags.ToString()); - AddProperty("Plugin ID", PluginContext.PluginInfo.PluginID.ToString()); - AddProperty("Plugin Version", PluginContext.PluginInfo.PluginVersion.ToString()); - AddProperty("Audio Input Count", PluginContext.PluginInfo.AudioInputCount.ToString()); - AddProperty("Audio Output Count", PluginContext.PluginInfo.AudioOutputCount.ToString()); - AddProperty("Initial Delay", PluginContext.PluginInfo.InitialDelay.ToString()); - AddProperty("Program Count", PluginContext.PluginInfo.ProgramCount.ToString()); - AddProperty("Parameter Count", PluginContext.PluginInfo.ParameterCount.ToString()); - AddProperty("Tail Size", PluginContext.PluginCommandStub.Commands.GetTailSize().ToString()); - - // can do - AddProperty("CanDo:" + VstPluginCanDo.Bypass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Bypass)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.MidiProgramNames, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.MidiProgramNames)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.Offline, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Offline)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstEvents, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstEvents)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstMidiEvent, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstMidiEvent)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstTimeInfo, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstTimeInfo)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.SendVstEvents, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstEvents)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.SendVstMidiEvent, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstMidiEvent)).ToString()); - - AddProperty("CanDo:" + VstPluginCanDo.ConformsToWindowRules, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ConformsToWindowRules)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.Metapass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Metapass)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.MixDryWet, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.MixDryWet)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.Multipass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Multipass)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.NoRealTime, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.NoRealTime)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.PlugAsChannelInsert, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.PlugAsChannelInsert)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.PlugAsSend, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.PlugAsSend)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.SendVstTimeInfo, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstTimeInfo)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x1in1out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x1in1out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x1in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x1in2out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x2in1out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in1out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x2in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in2out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x2in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in4out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x4in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in2out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x4in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in4out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x4in8out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in8out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x8in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x8in4out)).ToString()); - AddProperty("CanDo:" + VstPluginCanDo.x8in8out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x8in8out)).ToString()); - } + private void DataToForm() + { + FillPropertyList(); + FillProgramList(); + FillProgram(); + FillParameterList(); + } - private void AddProperty(string propName, string propValue) - { - var lvItem = new ListViewItem(propName); - lvItem.SubItems.Add(propValue); + private void FillPropertyList() + { + PluginPropertyListVw.Items.Clear(); + + // plugin product + AddProperty("Plugin Name", PluginContext.PluginCommandStub.Commands.GetEffectName()); + AddProperty("Product", PluginContext.PluginCommandStub.Commands.GetProductString()); + AddProperty("Vendor", PluginContext.PluginCommandStub.Commands.GetVendorString()); + AddProperty("Vendor Version", PluginContext.PluginCommandStub.Commands.GetVendorVersion().ToString()); + AddProperty("Vst Support", PluginContext.PluginCommandStub.Commands.GetVstVersion().ToString()); + AddProperty("Plugin Category", PluginContext.PluginCommandStub.Commands.GetCategory().ToString()); + + // plugin info + AddProperty("Flags", PluginContext.PluginInfo.Flags.ToString()); + AddProperty("Plugin ID", PluginContext.PluginInfo.PluginID.ToString()); + AddProperty("Plugin Version", PluginContext.PluginInfo.PluginVersion.ToString()); + AddProperty("Audio Input Count", PluginContext.PluginInfo.AudioInputCount.ToString()); + AddProperty("Audio Output Count", PluginContext.PluginInfo.AudioOutputCount.ToString()); + AddProperty("Initial Delay", PluginContext.PluginInfo.InitialDelay.ToString()); + AddProperty("Program Count", PluginContext.PluginInfo.ProgramCount.ToString()); + AddProperty("Parameter Count", PluginContext.PluginInfo.ParameterCount.ToString()); + AddProperty("Tail Size", PluginContext.PluginCommandStub.Commands.GetTailSize().ToString()); + + // can do + AddProperty("CanDo:" + VstPluginCanDo.Bypass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Bypass)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.MidiProgramNames, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.MidiProgramNames)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.Offline, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Offline)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstEvents, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstEvents)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstMidiEvent, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstMidiEvent)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.ReceiveVstTimeInfo, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstTimeInfo)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.SendVstEvents, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstEvents)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.SendVstMidiEvent, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstMidiEvent)).ToString()); + + AddProperty("CanDo:" + VstPluginCanDo.ConformsToWindowRules, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.ConformsToWindowRules)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.Metapass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Metapass)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.MixDryWet, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.MixDryWet)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.Multipass, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.Multipass)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.NoRealTime, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.NoRealTime)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.PlugAsChannelInsert, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.PlugAsChannelInsert)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.PlugAsSend, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.PlugAsSend)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.SendVstTimeInfo, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.SendVstTimeInfo)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x1in1out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x1in1out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x1in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x1in2out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x2in1out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in1out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x2in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in2out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x2in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x2in4out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x4in2out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in2out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x4in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in4out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x4in8out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x4in8out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x8in4out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x8in4out)).ToString()); + AddProperty("CanDo:" + VstPluginCanDo.x8in8out, PluginContext.PluginCommandStub.Commands.CanDo(VstCanDoHelper.ToString(VstPluginCanDo.x8in8out)).ToString()); + } - PluginPropertyListVw.Items.Add(lvItem); - } + private void AddProperty(string propName, string propValue) + { + var lvItem = new ListViewItem(propName); + lvItem.SubItems.Add(propValue); - private void FillProgramList() - { - ProgramListCmb.Items.Clear(); + PluginPropertyListVw.Items.Add(lvItem); + } - for (int index = 0; index < PluginContext.PluginInfo.ProgramCount; index++) - { - ProgramListCmb.Items.Add( - PluginContext.PluginCommandStub.Commands.GetProgramNameIndexed(index)); - } - } + private void FillProgramList() + { + ProgramListCmb.Items.Clear(); - private void FillProgram() + for (int index = 0; index < PluginContext.PluginInfo.ProgramCount; index++) { - ProgramIndexNud.Value = PluginContext.PluginCommandStub.Commands.GetProgram(); - ProgramListCmb.Text = PluginContext.PluginCommandStub.Commands.GetProgramName(); + ProgramListCmb.Items.Add( + PluginContext.PluginCommandStub.Commands.GetProgramNameIndexed(index)); } + } - private void FillParameterList() - { - PluginParameterListVw.Items.Clear(); - - for (int i = 0; i < PluginContext.PluginInfo.ParameterCount; i++) - { - string name = PluginContext.PluginCommandStub.Commands.GetParameterName(i); - string label = PluginContext.PluginCommandStub.Commands.GetParameterLabel(i); - string display = PluginContext.PluginCommandStub.Commands.GetParameterDisplay(i); + private void FillProgram() + { + ProgramIndexNud.Value = PluginContext.PluginCommandStub.Commands.GetProgram(); + ProgramListCmb.Text = PluginContext.PluginCommandStub.Commands.GetProgramName(); + } - AddParameter(name, display, label, String.Empty); - } - } + private void FillParameterList() + { + PluginParameterListVw.Items.Clear(); - private void AddParameter(string paramName, string paramValue, string label, string shortLabel) + for (int i = 0; i < PluginContext.PluginInfo.ParameterCount; i++) { - var lvItem = new ListViewItem(paramName); - lvItem.SubItems.Add(paramValue); - lvItem.SubItems.Add(label); - lvItem.SubItems.Add(shortLabel); + string name = PluginContext.PluginCommandStub.Commands.GetParameterName(i); + string label = PluginContext.PluginCommandStub.Commands.GetParameterLabel(i); + string display = PluginContext.PluginCommandStub.Commands.GetParameterDisplay(i); - PluginParameterListVw.Items.Add(lvItem); + AddParameter(name, display, label, String.Empty); } + } + + private void AddParameter(string paramName, string paramValue, string label, string shortLabel) + { + var lvItem = new ListViewItem(paramName); + lvItem.SubItems.Add(paramValue); + lvItem.SubItems.Add(label); + lvItem.SubItems.Add(shortLabel); - private void PluginForm_Load(object sender, EventArgs e) + PluginParameterListVw.Items.Add(lvItem); + } + + private void PluginForm_Load(object sender, EventArgs e) + { + if (PluginContext == null) { - if (PluginContext == null) - { - Close(); - } - else - { - DataToForm(); - } + Close(); + } + else + { + DataToForm(); } + } - private void ProgramIndexNud_ValueChanged(object sender, EventArgs e) + private void ProgramIndexNud_ValueChanged(object sender, EventArgs e) + { + if (ProgramIndexNud.Value < PluginContext.PluginInfo.ProgramCount && + ProgramIndexNud.Value >= 0) { - if (ProgramIndexNud.Value < PluginContext.PluginInfo.ProgramCount && - ProgramIndexNud.Value >= 0) - { - PluginContext.PluginCommandStub.Commands.SetProgram((int)ProgramIndexNud.Value); + PluginContext.PluginCommandStub.Commands.SetProgram((int)ProgramIndexNud.Value); - FillProgram(); - FillParameterList(); - } + FillProgram(); + FillParameterList(); } + } - private void GenerateNoiseBtn_Click(object sender, EventArgs e) + private void GenerateNoiseBtn_Click(object sender, EventArgs e) + { + // plugin does not support processing audio + if ((PluginContext.PluginInfo.Flags & VstPluginFlags.CanReplacing) == 0) { - // plugin does not support processing audio - if ((PluginContext.PluginInfo.Flags & VstPluginFlags.CanReplacing) == 0) - { - MessageBox.Show(this, "This plugin does not process any audio.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - return; - } + MessageBox.Show(this, "This plugin does not process any audio.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } - int inputCount = PluginContext.PluginInfo.AudioInputCount; - int outputCount = PluginContext.PluginInfo.AudioOutputCount; - int blockSize = 1024; + int inputCount = PluginContext.PluginInfo.AudioInputCount; + int outputCount = PluginContext.PluginInfo.AudioOutputCount; + int blockSize = 1024; - // wrap these in using statements to automatically call Dispose and cleanup the unmanaged memory. - using var inputMgr = new VstAudioBufferManager(inputCount, blockSize); - using var outputMgr = new VstAudioBufferManager(outputCount, blockSize); + // wrap these in using statements to automatically call Dispose and cleanup the unmanaged memory. + using var inputMgr = new VstAudioBufferManager(inputCount, blockSize); + using var outputMgr = new VstAudioBufferManager(outputCount, blockSize); - var rnd = new Random((int)DateTime.Now.Ticks); + var rnd = new Random((int)DateTime.Now.Ticks); - foreach (VstAudioBuffer buffer in inputMgr.Buffers) + foreach (VstAudioBuffer buffer in inputMgr.Buffers) + { + var span = buffer.AsSpan(); + for (int i = 0; i < blockSize; i++) { - var span = buffer.AsSpan(); - for (int i = 0; i < blockSize; i++) - { - // generate a value between -1.0 and 1.0 - //buffer[i] = (float)((rnd.NextDouble() * 2.0) - 1.0); - span[i] = (float)((rnd.NextDouble() * 2.0) - 1.0); - } + // generate a value between -1.0 and 1.0 + //buffer[i] = (float)((rnd.NextDouble() * 2.0) - 1.0); + span[i] = (float)((rnd.NextDouble() * 2.0) - 1.0); } + } - PluginContext.PluginCommandStub.Commands.SetBlockSize(blockSize); - PluginContext.PluginCommandStub.Commands.SetSampleRate(44100f); + PluginContext.PluginCommandStub.Commands.SetBlockSize(blockSize); + PluginContext.PluginCommandStub.Commands.SetSampleRate(44100f); - VstAudioBuffer[] inputBuffers = inputMgr.Buffers.ToArray(); - VstAudioBuffer[] outputBuffers = outputMgr.Buffers.ToArray(); + VstAudioBuffer[] inputBuffers = inputMgr.Buffers.ToArray(); + VstAudioBuffer[] outputBuffers = outputMgr.Buffers.ToArray(); - PluginContext.PluginCommandStub.Commands.MainsChanged(true); - PluginContext.PluginCommandStub.Commands.StartProcess(); - PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); - PluginContext.PluginCommandStub.Commands.StopProcess(); - PluginContext.PluginCommandStub.Commands.MainsChanged(false); + PluginContext.PluginCommandStub.Commands.MainsChanged(true); + PluginContext.PluginCommandStub.Commands.StartProcess(); + PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); + PluginContext.PluginCommandStub.Commands.StopProcess(); + PluginContext.PluginCommandStub.Commands.MainsChanged(false); - for (int i = 0; i < inputBuffers.Length && i < outputBuffers.Length; i++) + for (int i = 0; i < inputBuffers.Length && i < outputBuffers.Length; i++) + { + for (int j = 0; j < blockSize; j++) { - for (int j = 0; j < blockSize; j++) + if (inputBuffers[i][j] != outputBuffers[i][j]) { - if (inputBuffers[i][j] != outputBuffers[i][j]) + if (outputBuffers[i][j] != 0.0) { - if (outputBuffers[i][j] != 0.0) - { - MessageBox.Show(this, "The plugin has processed the audio.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); - return; - } + MessageBox.Show(this, "The plugin has processed the audio.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; } } } - - MessageBox.Show(this, "The plugin has passed the audio unchanged to its outputs.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); } - private void GenerateMidiBtn_Click(object sender, EventArgs e) + MessageBox.Show(this, "The plugin has passed the audio unchanged to its outputs.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void GenerateMidiBtn_Click(object sender, EventArgs e) + { + // plugin does not support processing midi + if (PluginContext.PluginCommandStub.Commands.CanDo( + VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstMidiEvent)) != VstCanDoResult.Yes) { - // plugin does not support processing midi - if (PluginContext.PluginCommandStub.Commands.CanDo( - VstCanDoHelper.ToString(VstPluginCanDo.ReceiveVstMidiEvent)) != VstCanDoResult.Yes) - { - MessageBox.Show(this, "This plugin does not process any midi.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - return; - } + MessageBox.Show(this, "This plugin does not process any midi.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } - var noteCount = 10; - var midiNoteOns = - Enumerable.Range(60, noteCount).Select(n => new byte[] { 0x81, (byte)n, 100 }); - var midiNoteOffs = - Enumerable.Range(60, noteCount).Select(n => new byte[] { 0x80, (byte)n, 0 }); + var noteCount = 10; + var midiNoteOns = + Enumerable.Range(60, noteCount).Select(n => new byte[] { 0x81, (byte)n, 100 }); + var midiNoteOffs = + Enumerable.Range(60, noteCount).Select(n => new byte[] { 0x80, (byte)n, 0 }); - int inputCount = PluginContext.PluginInfo.AudioInputCount; - int outputCount = PluginContext.PluginInfo.AudioOutputCount; - int blockSize = 256; + int inputCount = PluginContext.PluginInfo.AudioInputCount; + int outputCount = PluginContext.PluginInfo.AudioOutputCount; + int blockSize = 256; - // Most MIDI plugins also implement a (dummy) audio processor. - // So we allocate (dummy) audio buffers too... - using var inputMgr = new VstAudioBufferManager(inputCount, blockSize); - using var outputMgr = new VstAudioBufferManager(outputCount, blockSize); + // Most MIDI plugins also implement a (dummy) audio processor. + // So we allocate (dummy) audio buffers too... + using var inputMgr = new VstAudioBufferManager(inputCount, blockSize); + using var outputMgr = new VstAudioBufferManager(outputCount, blockSize); - PluginContext.PluginCommandStub.Commands.SetBlockSize(blockSize); - PluginContext.PluginCommandStub.Commands.SetSampleRate(44100f); + PluginContext.PluginCommandStub.Commands.SetBlockSize(blockSize); + PluginContext.PluginCommandStub.Commands.SetSampleRate(44100f); - VstAudioBuffer[] inputBuffers = inputMgr.Buffers.ToArray(); - VstAudioBuffer[] outputBuffers = outputMgr.Buffers.ToArray(); + VstAudioBuffer[] inputBuffers = inputMgr.Buffers.ToArray(); + VstAudioBuffer[] outputBuffers = outputMgr.Buffers.ToArray(); - PluginContext.PluginCommandStub.Commands.MainsChanged(true); - PluginContext.PluginCommandStub.Commands.StartProcess(); + PluginContext.PluginCommandStub.Commands.MainsChanged(true); + PluginContext.PluginCommandStub.Commands.StartProcess(); - var events = midiNoteOns.Select(note => new VstMidiEvent(0, 20, 0, note, 0, 0)); + var events = midiNoteOns.Select(note => new VstMidiEvent(0, 20, 0, note, 0, 0)); - if (!PluginContext.PluginCommandStub.Commands.ProcessEvents(events.ToArray())) - MessageBox.Show(this, "The plugin returned false on ProcessEvents of note-on messages.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - - PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); + if (!PluginContext.PluginCommandStub.Commands.ProcessEvents(events.ToArray())) + MessageBox.Show(this, "The plugin returned false on ProcessEvents of note-on messages.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + + PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); - events = midiNoteOffs.Select(note => new VstMidiEvent(0, 0, 0, note, 0, 0)); + events = midiNoteOffs.Select(note => new VstMidiEvent(0, 0, 0, note, 0, 0)); - if (!PluginContext.PluginCommandStub.Commands.ProcessEvents(events.ToArray())) - MessageBox.Show(this, "The plugin returned false on ProcessEvents of note-off messages.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - - PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); + if (!PluginContext.PluginCommandStub.Commands.ProcessEvents(events.ToArray())) + MessageBox.Show(this, "The plugin returned false on ProcessEvents of note-off messages.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + + PluginContext.PluginCommandStub.Commands.ProcessReplacing(inputBuffers, outputBuffers); - PluginContext.PluginCommandStub.Commands.StopProcess(); - PluginContext.PluginCommandStub.Commands.MainsChanged(false); + PluginContext.PluginCommandStub.Commands.StopProcess(); + PluginContext.PluginCommandStub.Commands.MainsChanged(false); - MessageBox.Show(this, "The plugin has processed the midi events.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); - } + MessageBox.Show(this, "The plugin has processed the midi events.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + } - private void EditorBtn_Click(object sender, EventArgs e) + private void EditorBtn_Click(object sender, EventArgs e) + { + var dlg = new EditorFrame { - var dlg = new EditorFrame - { - PluginCommandStub = PluginContext.PluginCommandStub, - HostCommandStub = (DummyHostCommandStub)PluginContext.HostCommandStub - }; + PluginCommandStub = PluginContext.PluginCommandStub, + HostCommandStub = (DummyHostCommandStub)PluginContext.HostCommandStub + }; - + - //PluginContext.PluginCommandStub.Commands.MainsChanged(true); - dlg.ShowDialog(this); - //PluginContext.PluginCommandStub.Commands.MainsChanged(false); - } + //PluginContext.PluginCommandStub.Commands.MainsChanged(true); + dlg.ShowDialog(this); + //PluginContext.PluginCommandStub.Commands.MainsChanged(false); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.Host/Program.cs b/Source/Samples/Jacobi.Vst.Samples.Host/Program.cs index 2fe22ecc..51c7da67 100644 --- a/Source/Samples/Jacobi.Vst.Samples.Host/Program.cs +++ b/Source/Samples/Jacobi.Vst.Samples.Host/Program.cs @@ -1,20 +1,19 @@ using System; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.Host +namespace Jacobi.Vst.Samples.Host; + +static class Program { - static class Program + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.SetHighDpiMode(HighDpiMode.SystemAware); - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); - } + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/AudioProcessor.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/AudioProcessor.cs index e8083d93..9a936268 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/AudioProcessor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/AudioProcessor.cs @@ -1,49 +1,48 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework; +using Jacobi.Vst.Plugin.Framework.Plugin; + +/// +/// A dummy audio processor only used for the timing of midi processing. +/// +internal sealed class AudioProcessor : VstPluginAudioProcessor { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework; - using Jacobi.Vst.Plugin.Framework.Plugin; + private MidiProcessor? _midiProcessor; + private IVstMidiProcessor? _hostProcessor; /// - /// A dummy audio processor only used for the timing of midi processing. + /// Constructs a new instance. /// - internal sealed class AudioProcessor : VstPluginAudioProcessor + /// Must not be null. + public AudioProcessor(IVstPluginEvents pluginEvents) + : base(0, 0, 0, noSoundInStop: true) { - private MidiProcessor? _midiProcessor; - private IVstMidiProcessor? _hostProcessor; + pluginEvents.Opened += Plugin_Opened; + } - /// - /// Constructs a new instance. - /// - /// Must not be null. - public AudioProcessor(IVstPluginEvents pluginEvents) - : base(0, 0, 0, noSoundInStop: true) - { - pluginEvents.Opened += Plugin_Opened; - } + private void Plugin_Opened(object? sender, System.EventArgs e) + { + var plugin = (VstPlugin?)sender; + _midiProcessor = plugin?.GetInstance(); + _hostProcessor = plugin?.Host?.GetInstance(); + } - private void Plugin_Opened(object? sender, System.EventArgs e) + /// + /// This method is used to push midi events to the host. + public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + { + if (_hostProcessor != null && + _midiProcessor != null && + _midiProcessor.Events.Count > 0) { - var plugin = (VstPlugin?)sender; - _midiProcessor = plugin?.GetInstance(); - _hostProcessor = plugin?.Host?.GetInstance(); + // we use the AudioProcessor as a trigger to process Midi + _hostProcessor.Process(_midiProcessor.Events); + _midiProcessor.Events.Clear(); } - /// - /// This method is used to push midi events to the host. - public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) - { - if (_hostProcessor != null && - _midiProcessor != null && - _midiProcessor.Events.Count > 0) - { - // we use the AudioProcessor as a trigger to process Midi - _hostProcessor.Process(_midiProcessor.Events); - _midiProcessor.Events.Clear(); - } - - // perform audio-through - base.Process(inChannels, outChannels); - } + // perform audio-through + base.Process(inChannels, outChannels); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Jacobi.Vst.Samples.MidiNoteMapper.csproj b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Jacobi.Vst.Samples.MidiNoteMapper.csproj index 862d051a..8f86415d 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Jacobi.Vst.Samples.MidiNoteMapper.csproj +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Jacobi.Vst.Samples.MidiNoteMapper.csproj @@ -1,7 +1,7 @@ - + - net6.0-windows + net8.0-windows 2.1.0 Marc Jacobi Jacobi Software @@ -18,6 +18,6 @@ - + diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MapNoteItem.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MapNoteItem.cs index b8450357..d250988b 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MapNoteItem.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MapNoteItem.cs @@ -1,42 +1,41 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper -{ - using System; - using System.Collections.ObjectModel; +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using System; +using System.Collections.ObjectModel; +/// +/// Represents one note mapping. +/// +internal sealed class MapNoteItem +{ /// - /// Represents one note mapping. + /// Gets or sets a readable name for this mapping item. /// - internal sealed class MapNoteItem - { - /// - /// Gets or sets a readable name for this mapping item. - /// - public string KeyName { get; set; } = String.Empty; + public string KeyName { get; set; } = String.Empty; - /// - /// Gets or sets the note number that triggers this mapping item. - /// - public byte TriggerNoteNumber { get; set; } + /// + /// Gets or sets the note number that triggers this mapping item. + /// + public byte TriggerNoteNumber { get; set; } - /// - /// Gets or sets the note number that is sent to the output when this item is triggered. - /// - public byte OutputNoteNumber { get; set; } - } + /// + /// Gets or sets the note number that is sent to the output when this item is triggered. + /// + public byte OutputNoteNumber { get; set; } +} +/// +/// Manages a list of instances. +/// +internal sealed class MapNoteItemList : KeyedCollection +{ /// - /// Manages a list of instances. + /// Returns . /// - internal sealed class MapNoteItemList : KeyedCollection + /// Must not be null. + /// Returns the key for the . + protected override byte GetKeyForItem(MapNoteItem item) { - /// - /// Returns . - /// - /// Must not be null. - /// Returns the key for the . - protected override byte GetKeyForItem(MapNoteItem item) - { - return item.TriggerNoteNumber; - } + return item.TriggerNoteNumber; } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MidiProcessor.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MidiProcessor.cs index f96e6793..888d5130 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MidiProcessor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/MidiProcessor.cs @@ -1,99 +1,98 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework; +using System; +using System.Collections; +using System.Collections.Generic; + +/// +/// Implements the incoming Midi event handling for the plugin. +/// +internal sealed class MidiProcessor : IVstMidiProcessor, IVstPluginMidiSource { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework; - using System; - using System.Collections; - using System.Collections.Generic; + private readonly MapNoteItemList _noteMap; /// - /// Implements the incoming Midi event handling for the plugin. + /// Constructs a new instance. /// - internal sealed class MidiProcessor : IVstMidiProcessor, IVstPluginMidiSource + /// Must not be null. + public MidiProcessor(MapNoteItemList noteMap) { - private readonly MapNoteItemList _noteMap; - - /// - /// Constructs a new instance. - /// - /// Must not be null. - public MidiProcessor(MapNoteItemList noteMap) - { - _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); - } + _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); + } - /// - /// Gets the midi events that should be processed in the current cycle. - /// - public VstEventCollection Events { get; } = new VstEventCollection(); + /// + /// Gets the midi events that should be processed in the current cycle. + /// + public VstEventCollection Events { get; } = new VstEventCollection(); - /// - /// Gets or sets a value indicating wether non-mapped midi events should be passed to the output. - /// - public bool MidiThru { get; set; } + /// + /// Gets or sets a value indicating wether non-mapped midi events should be passed to the output. + /// + public bool MidiThru { get; set; } - /// - /// The raw note on note numbers. - /// - public Queue NoteOnEvents { get; } = new Queue(); + /// + /// The raw note on note numbers. + /// + public Queue NoteOnEvents { get; } = new Queue(); - #region IVstMidiProcessor Members + #region IVstMidiProcessor Members - public int ChannelCount - { - get { return 16; } - } + public int ChannelCount + { + get { return 16; } + } - public void Process(VstEventCollection events) + public void Process(VstEventCollection events) + { + foreach (VstEvent evnt in events) { - foreach (VstEvent evnt in events) - { - if (evnt.EventType != VstEventTypes.MidiEvent) - continue; + if (evnt.EventType != VstEventTypes.MidiEvent) + continue; - var midiEvent = (VstMidiEvent)evnt; + var midiEvent = (VstMidiEvent)evnt; - if (((midiEvent.Data[0] & 0xF0) == 0x80 || (midiEvent.Data[0] & 0xF0) == 0x90)) + if (((midiEvent.Data[0] & 0xF0) == 0x80 || (midiEvent.Data[0] & 0xF0) == 0x90)) + { + if (_noteMap.Contains(midiEvent.Data[1])) { - if (_noteMap.Contains(midiEvent.Data[1])) - { - byte[] midiData = new byte[4]; - midiData[0] = midiEvent.Data[0]; - midiData[1] = _noteMap[midiEvent.Data[1]].OutputNoteNumber; - midiData[2] = midiEvent.Data[2]; + byte[] midiData = new byte[4]; + midiData[0] = midiEvent.Data[0]; + midiData[1] = _noteMap[midiEvent.Data[1]].OutputNoteNumber; + midiData[2] = midiEvent.Data[2]; - var mappedEvent = new VstMidiEvent(midiEvent.DeltaFrames, - midiEvent.NoteLength, - midiEvent.NoteOffset, - midiData, - midiEvent.Detune, - midiEvent.NoteOffVelocity); + var mappedEvent = new VstMidiEvent(midiEvent.DeltaFrames, + midiEvent.NoteLength, + midiEvent.NoteOffset, + midiData, + midiEvent.Detune, + midiEvent.NoteOffVelocity); - Events.Add(mappedEvent); + Events.Add(mappedEvent); - // add raw note-on note numbers to the queue - if ((midiEvent.Data[0] & 0xF0) == 0x90) + // add raw note-on note numbers to the queue + if ((midiEvent.Data[0] & 0xF0) == 0x90) + { + lock (((ICollection)NoteOnEvents).SyncRoot) { - lock (((ICollection)NoteOnEvents).SyncRoot) - { - NoteOnEvents.Enqueue(midiEvent.Data[1]); - } + NoteOnEvents.Enqueue(midiEvent.Data[1]); } } - else if (MidiThru) - { - // add original note event - Events.Add(evnt); - } } else if (MidiThru) { - // add original (non-note) event + // add original note event Events.Add(evnt); } } + else if (MidiThru) + { + // add original (non-note) event + Events.Add(evnt); + } } - - #endregion } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Plugin.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Plugin.cs index f3dced52..bfab9a90 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Plugin.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/Plugin.cs @@ -3,29 +3,28 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using Microsoft.Extensions.DependencyInjection; -namespace Jacobi.Vst.Samples.MidiNoteMapper +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +/// +/// The Plugin root class that implements the interface manager and the plugin midi source. +/// +internal sealed class Plugin : VstPluginWithServices { /// - /// The Plugin root class that implements the interface manager and the plugin midi source. + /// Constructs a new instance. /// - internal sealed class Plugin : VstPluginWithServices - { - /// - /// Constructs a new instance. - /// - public Plugin() - : base("VST.NET 2 Midi Note Mapper", 0x30313233, - new VstProductInfo("VST.NET 2 Code Samples", "Jacobi Software © 2008-2020", 2000), - VstPluginCategory.Synth) - { } + public Plugin() + : base("VST.NET 2 Midi Note Mapper", 0x30313233, + new VstProductInfo("VST.NET 2 Code Samples", "Jacobi Software © 2008-2024", 2000), + VstPluginCategory.Synth) + { } - protected override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll(); - } + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginCommandStub.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginCommandStub.cs index 343b9c83..7a35ae38 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginCommandStub.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginCommandStub.cs @@ -1,20 +1,19 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper -{ - using Jacobi.Vst.Plugin.Framework; - using Jacobi.Vst.Plugin.Framework.Plugin; +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using Jacobi.Vst.Plugin.Framework; +using Jacobi.Vst.Plugin.Framework.Plugin; +/// +/// The public Plugin Command Stub implementation derived from the framework provided . +/// +public sealed class PluginCommandStub : StdPluginCommandStub +{ /// - /// The public Plugin Command Stub implementation derived from the framework provided . + /// Called by the framework to create the plugin root object. /// - public sealed class PluginCommandStub : StdPluginCommandStub + /// Never returns null. + protected override IVstPlugin CreatePluginInstance() { - /// - /// Called by the framework to create the plugin root object. - /// - /// Never returns null. - protected override IVstPlugin CreatePluginInstance() - { - return new Plugin(); - } + return new Plugin(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginEditor.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginEditor.cs index 65638db3..3e486499 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginEditor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginEditor.cs @@ -1,68 +1,67 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework; +using Jacobi.Vst.Plugin.Framework.Common; +using System; + +/// +/// Implements the custom UI editor for the plugin. +/// +internal sealed class PluginEditor : IVstPluginEditor { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework; - using Jacobi.Vst.Plugin.Framework.Common; - using System; + private readonly MidiProcessor _midiProcessor; + private readonly MapNoteItemList _noteMap; + private readonly WinFormsControlWrapper _uiWrapper = + new WinFormsControlWrapper(); /// - /// Implements the custom UI editor for the plugin. + /// Constructs a new instance. /// - internal sealed class PluginEditor : IVstPluginEditor + /// Must not be null. + public PluginEditor(MidiProcessor midiProcessor, MapNoteItemList noteMap) { - private readonly MidiProcessor _midiProcessor; - private readonly MapNoteItemList _noteMap; - private readonly WinFormsControlWrapper _uiWrapper = - new WinFormsControlWrapper(); - - /// - /// Constructs a new instance. - /// - /// Must not be null. - public PluginEditor(MidiProcessor midiProcessor, MapNoteItemList noteMap) - { - _midiProcessor = midiProcessor ?? throw new ArgumentNullException(nameof(midiProcessor)); - _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); - } - - #region IVstPluginEditor Members + _midiProcessor = midiProcessor ?? throw new ArgumentNullException(nameof(midiProcessor)); + _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); + } - public System.Drawing.Rectangle Bounds - { - get { return _uiWrapper.Bounds; } - } + #region IVstPluginEditor Members - public void Close() - { - _uiWrapper.Close(); - } + public System.Drawing.Rectangle Bounds + { + get { return _uiWrapper.Bounds; } + } - public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // no-op - return false; - } + public void Close() + { + _uiWrapper.Close(); + } - public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // no-op - return false; - } + public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // no-op + return false; + } - public VstKnobMode KnobMode { get; set; } + public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // no-op + return false; + } - public void Open(IntPtr hWnd) - { - _uiWrapper.SafeInstance.NoteMap = _noteMap; - _uiWrapper.SafeInstance.NoteOnEvents = _midiProcessor.NoteOnEvents; - _uiWrapper.Open(hWnd); - } + public VstKnobMode KnobMode { get; set; } - public void ProcessIdle() - { - _uiWrapper.SafeInstance.ProcessIdle(); - } + public void Open(IntPtr hWnd) + { + _uiWrapper.SafeInstance.NoteMap = _noteMap; + _uiWrapper.SafeInstance.NoteOnEvents = _midiProcessor.NoteOnEvents; + _uiWrapper.Open(hWnd); + } - #endregion + public void ProcessIdle() + { + _uiWrapper.SafeInstance.ProcessIdle(); } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginPersistence.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginPersistence.cs index c0a69720..56002532 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginPersistence.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/PluginPersistence.cs @@ -1,62 +1,61 @@ -namespace Jacobi.Vst.Samples.MidiNoteMapper +namespace Jacobi.Vst.Samples.MidiNoteMapper; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework; +using System; +using System.IO; +using System.Text; + +internal sealed class PluginPersistence : IVstPluginPersistence { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework; - using System; - using System.IO; - using System.Text; + private readonly MapNoteItemList _noteMap; + private readonly Encoding _encoding = Encoding.ASCII; - internal sealed class PluginPersistence : IVstPluginPersistence + public PluginPersistence(MapNoteItemList noteMap) { - private readonly MapNoteItemList _noteMap; - private readonly Encoding _encoding = Encoding.ASCII; - - public PluginPersistence(MapNoteItemList noteMap) - { - _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); - } + _noteMap = noteMap ?? throw new ArgumentNullException(nameof(noteMap)); + } - #region IVstPluginPersistence Members + #region IVstPluginPersistence Members - public bool CanLoadChunk(VstPatchChunkInfo chunkInfo) - { - return true; - } + public bool CanLoadChunk(VstPatchChunkInfo chunkInfo) + { + return true; + } - public void ReadPrograms(Stream stream, VstProgramCollection programs) - { - var reader = new BinaryReader(stream, _encoding); + public void ReadPrograms(Stream stream, VstProgramCollection programs) + { + var reader = new BinaryReader(stream, _encoding); - _noteMap.Clear(); - int count = reader.ReadInt32(); + _noteMap.Clear(); + int count = reader.ReadInt32(); - for (int n = 0; n < count; n++) + for (int n = 0; n < count; n++) + { + var item = new MapNoteItem { - var item = new MapNoteItem - { - KeyName = reader.ReadString(), - TriggerNoteNumber = reader.ReadByte(), - OutputNoteNumber = reader.ReadByte() - }; - - _noteMap.Add(item); - } + KeyName = reader.ReadString(), + TriggerNoteNumber = reader.ReadByte(), + OutputNoteNumber = reader.ReadByte() + }; + + _noteMap.Add(item); } + } - public void WritePrograms(Stream stream, VstProgramCollection programs) - { - var writer = new BinaryWriter(stream, _encoding); + public void WritePrograms(Stream stream, VstProgramCollection programs) + { + var writer = new BinaryWriter(stream, _encoding); - writer.Write(_noteMap.Count); + writer.Write(_noteMap.Count); - foreach (MapNoteItem item in _noteMap) - { - writer.Write(item.KeyName); - writer.Write(item.TriggerNoteNumber); - writer.Write(item.OutputNoteNumber); - } + foreach (MapNoteItem item in _noteMap) + { + writer.Write(item.KeyName); + writer.Write(item.TriggerNoteNumber); + writer.Write(item.OutputNoteNumber); } - - #endregion } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MapNoteDetails.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MapNoteDetails.cs index 33100db0..f736a2e4 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MapNoteDetails.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MapNoteDetails.cs @@ -1,57 +1,56 @@ using System; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.MidiNoteMapper.UI +namespace Jacobi.Vst.Samples.MidiNoteMapper.UI; + +/// +/// A form that allows the user to edit the details of a note map item. +/// +internal sealed partial class MapNoteDetails : Form { /// - /// A form that allows the user to edit the details of a note map item. + /// Constructs a new instance. /// - internal sealed partial class MapNoteDetails : Form + public MapNoteDetails() { - /// - /// Constructs a new instance. - /// - public MapNoteDetails() - { - InitializeComponent(); - } + InitializeComponent(); + } - /// - /// Gets or sets the note map item that is edited in the form. - /// - public MapNoteItem? MapNoteItem { get; set; } + /// + /// Gets or sets the note map item that is edited in the form. + /// + public MapNoteItem? MapNoteItem { get; set; } - private void EntityToForm() - { - if (MapNoteItem == null) - return; + private void EntityToForm() + { + if (MapNoteItem == null) + return; - this.KeyNameTxt.Text = MapNoteItem.KeyName; - this.TriggerNoteNoTxt.Value = MapNoteItem.TriggerNoteNumber; - this.OutputNoteNoTxt.Value = MapNoteItem.OutputNoteNumber; - } + this.KeyNameTxt.Text = MapNoteItem.KeyName; + this.TriggerNoteNoTxt.Value = MapNoteItem.TriggerNoteNumber; + this.OutputNoteNoTxt.Value = MapNoteItem.OutputNoteNumber; + } - private void FormToEntity() - { - if (MapNoteItem == null) - return; + private void FormToEntity() + { + if (MapNoteItem == null) + return; - MapNoteItem.KeyName = this.KeyNameTxt.Text; - MapNoteItem.TriggerNoteNumber = (byte)this.TriggerNoteNoTxt.Value; - MapNoteItem.OutputNoteNumber = (byte)this.OutputNoteNoTxt.Value; - } + MapNoteItem.KeyName = this.KeyNameTxt.Text; + MapNoteItem.TriggerNoteNumber = (byte)this.TriggerNoteNoTxt.Value; + MapNoteItem.OutputNoteNumber = (byte)this.OutputNoteNoTxt.Value; + } - private void MapNoteDetails_Load(object sender, EventArgs e) - { - EntityToForm(); - } + private void MapNoteDetails_Load(object sender, EventArgs e) + { + EntityToForm(); + } - private void MapNoteDetails_FormClosed(object sender, FormClosedEventArgs e) + private void MapNoteDetails_FormClosed(object sender, FormClosedEventArgs e) + { + if (this.DialogResult == DialogResult.OK) { - if (this.DialogResult == DialogResult.OK) - { - FormToEntity(); - } + FormToEntity(); } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MidiNoteMapperView.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MidiNoteMapperView.cs index 6e8d894f..750da769 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MidiNoteMapperView.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteMapper/UI/MidiNoteMapperView.cs @@ -3,190 +3,189 @@ using System.Collections.Generic; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.MidiNoteMapper.UI +namespace Jacobi.Vst.Samples.MidiNoteMapper.UI; + +/// +/// The plugin custom editor UI. +/// +internal sealed partial class MidiNoteMapperView : UserControl { /// - /// The plugin custom editor UI. + /// Constructs a new instance. /// - internal sealed partial class MidiNoteMapperView : UserControl + public MidiNoteMapperView() { - /// - /// Constructs a new instance. - /// - public MidiNoteMapperView() - { - InitializeComponent(); - } + InitializeComponent(); + } - private MapNoteItemList? _noteMap; - /// - /// Gets or sets the list of note map items that are shown in the editor. - /// - public MapNoteItemList? NoteMap - { - get { return _noteMap; } - set { _noteMap = value; FillList(); } - } + private MapNoteItemList? _noteMap; + /// + /// Gets or sets the list of note map items that are shown in the editor. + /// + public MapNoteItemList? NoteMap + { + get { return _noteMap; } + set { _noteMap = value; FillList(); } + } - /// - /// Contains a queue with note-on note numbers currently playing. - /// - public Queue? NoteOnEvents { get; set; } + /// + /// Contains a queue with note-on note numbers currently playing. + /// + public Queue? NoteOnEvents { get; set; } - /// - /// Updates the UI with the . - /// - public void ProcessIdle() + /// + /// Updates the UI with the . + /// + public void ProcessIdle() + { + if (NoteOnEvents != null && + NoteOnEvents.Count > 0) { - if (NoteOnEvents != null && - NoteOnEvents.Count > 0) + byte noteNo; + + lock (((ICollection)NoteOnEvents).SyncRoot) { - byte noteNo; + noteNo = NoteOnEvents.Dequeue(); + } - lock (((ICollection)NoteOnEvents).SyncRoot) - { - noteNo = NoteOnEvents.Dequeue(); - } + SelectNoteMapItem(noteNo); + } + } - SelectNoteMapItem(noteNo); - } + private void SelectNoteMapItem(byte noteNo) + { + MapListVw.SelectedIndices.Clear(); + + if (MapListVw.Items.ContainsKey(noteNo.ToString())) + { + MapListVw.Items[noteNo.ToString()].Selected = true; } + } + + private void FillList() + { + if (!this.Created || NoteMap == null) + return; - private void SelectNoteMapItem(byte noteNo) + MapNoteItem? selectedItem = null; + + if (MapListVw.SelectedItems.Count > 0) { - MapListVw.SelectedIndices.Clear(); + selectedItem = (MapNoteItem?)MapListVw.SelectedItems[0].Tag; + } - if (MapListVw.Items.ContainsKey(noteNo.ToString())) - { - MapListVw.Items[noteNo.ToString()].Selected = true; - } + MapListVw.Items.Clear(); + + foreach (MapNoteItem item in NoteMap) + { + ListViewItem lvItem = new ListViewItem(item.TriggerNoteNumber.ToString()); + lvItem.SubItems.Add(item.KeyName); + lvItem.SubItems.Add(item.OutputNoteNumber.ToString()); + lvItem.Tag = item; + lvItem.Selected = (selectedItem == item); + lvItem.Name = item.TriggerNoteNumber.ToString(); + + MapListVw.Items.Add(lvItem); } - private void FillList() + if ((selectedItem == null || MapListVw.SelectedItems.Count == 0) + && MapListVw.Items.Count > 0) { - if (!this.Created || NoteMap == null) - return; + MapListVw.Items[0].Selected = true; + } + } - MapNoteItem? selectedItem = null; + private void AddBtn_Click(object sender, EventArgs e) + { + if (NoteMap == null) + return; - if (MapListVw.SelectedItems.Count > 0) + MapNoteDetails dlg = new MapNoteDetails + { + MapNoteItem = new MapNoteItem() { - selectedItem = (MapNoteItem?)MapListVw.SelectedItems[0].Tag; + KeyName = "New Note Map", + TriggerNoteNumber = 64, + OutputNoteNumber = 64 } + }; - MapListVw.Items.Clear(); - - foreach (MapNoteItem item in NoteMap) + if (dlg.ShowDialog(this) == DialogResult.OK) + { + if (NoteMap.Contains(dlg.MapNoteItem.TriggerNoteNumber)) { - ListViewItem lvItem = new ListViewItem(item.TriggerNoteNumber.ToString()); - lvItem.SubItems.Add(item.KeyName); - lvItem.SubItems.Add(item.OutputNoteNumber.ToString()); - lvItem.Tag = item; - lvItem.Selected = (selectedItem == item); - lvItem.Name = item.TriggerNoteNumber.ToString(); - - MapListVw.Items.Add(lvItem); + NoteMap.Remove(NoteMap[dlg.MapNoteItem.TriggerNoteNumber]); } - if ((selectedItem == null || MapListVw.SelectedItems.Count == 0) - && MapListVw.Items.Count > 0) - { - MapListVw.Items[0].Selected = true; - } + NoteMap.Add(dlg.MapNoteItem); + FillList(); } + } - private void AddBtn_Click(object sender, EventArgs e) - { - if (NoteMap == null) - return; + private void EditBtn_Click(object sender, EventArgs e) + { + if (NoteMap == null) + return; + if (MapListVw.SelectedItems.Count > 0) + { MapNoteDetails dlg = new MapNoteDetails { - MapNoteItem = new MapNoteItem() - { - KeyName = "New Note Map", - TriggerNoteNumber = 64, - OutputNoteNumber = 64 - } + MapNoteItem = (MapNoteItem)MapListVw.SelectedItems[0].Tag }; if (dlg.ShowDialog(this) == DialogResult.OK) { - if (NoteMap.Contains(dlg.MapNoteItem.TriggerNoteNumber)) - { - NoteMap.Remove(NoteMap[dlg.MapNoteItem.TriggerNoteNumber]); - } - - NoteMap.Add(dlg.MapNoteItem); FillList(); } } + } - private void EditBtn_Click(object sender, EventArgs e) + private void DeleteBtn_Click(object sender, EventArgs e) + { + if (NoteMap == null) + return; + + if (MapListVw.SelectedItems.Count > 0) { - if (NoteMap == null) - return; + MapNoteItem item = (MapNoteItem)MapListVw.SelectedItems[0].Tag; - if (MapListVw.SelectedItems.Count > 0) + if (MessageBox.Show(this, + String.Format("Are you sure you want to delete {0}.", item.KeyName), + "Delete a Note Map Item.", + MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { - MapNoteDetails dlg = new MapNoteDetails - { - MapNoteItem = (MapNoteItem)MapListVw.SelectedItems[0].Tag - }; - - if (dlg.ShowDialog(this) == DialogResult.OK) - { - FillList(); - } + NoteMap.Remove(item); + FillList(); } } + } - private void DeleteBtn_Click(object sender, EventArgs e) - { - if (NoteMap == null) - return; + private void MapListVw_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (NoteMap == null) + return; - if (MapListVw.SelectedItems.Count > 0) - { - MapNoteItem item = (MapNoteItem)MapListVw.SelectedItems[0].Tag; - - if (MessageBox.Show(this, - String.Format("Are you sure you want to delete {0}.", item.KeyName), - "Delete a Note Map Item.", - MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) - { - NoteMap.Remove(item); - FillList(); - } - } - } + ListViewHitTestInfo hitInfo = MapListVw.HitTest(e.Location); - private void MapListVw_MouseDoubleClick(object sender, MouseEventArgs e) + if (hitInfo.Item != null) { - if (NoteMap == null) - return; + hitInfo.Item.Selected = true; - ListViewHitTestInfo hitInfo = MapListVw.HitTest(e.Location); - - if (hitInfo.Item != null) + MapNoteDetails dlg = new MapNoteDetails { - hitInfo.Item.Selected = true; - - MapNoteDetails dlg = new MapNoteDetails - { - MapNoteItem = (MapNoteItem)hitInfo.Item.Tag - }; + MapNoteItem = (MapNoteItem)hitInfo.Item.Tag + }; - if (dlg.ShowDialog(this) == DialogResult.OK) - { - FillList(); - } + if (dlg.ShowDialog(this) == DialogResult.OK) + { + FillList(); } } + } - private void MidiNoteMapperUI_Load(object sender, EventArgs e) - { - FillList(); - } + private void MidiNoteMapperUI_Load(object sender, EventArgs e) + { + FillList(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/AudioProcessor.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/AudioProcessor.cs index 459549ab..77731fd9 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/AudioProcessor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/AudioProcessor.cs @@ -1,41 +1,40 @@ -namespace Jacobi.Vst.Samples.MidiNoteSampler +namespace Jacobi.Vst.Samples.MidiNoteSampler; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework.Plugin; +using System; + +/// +/// Implements the audio processing of the plugin using the . +/// +internal sealed class AudioProcessor : VstPluginAudioProcessor { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework.Plugin; - using System; + private readonly SampleManager _sampleManager; /// - /// Implements the audio processing of the plugin using the . + /// Constructs a new instance. /// - internal sealed class AudioProcessor : VstPluginAudioProcessor + /// Must not be null. + public AudioProcessor(SampleManager sampleManager) + : base(2, 2, 0, noSoundInStop: true) { - private readonly SampleManager _sampleManager; + _sampleManager = sampleManager ?? throw new ArgumentNullException(nameof(sampleManager)); + } - /// - /// Constructs a new instance. - /// - /// Must not be null. - public AudioProcessor(SampleManager sampleManager) - : base(2, 2, 0, noSoundInStop: true) + public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + { + if (_sampleManager.IsPlaying) { - _sampleManager = sampleManager ?? throw new ArgumentNullException(nameof(sampleManager)); + _sampleManager.PlayAudio(outChannels); } - - public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + else // audio thru { - if (_sampleManager.IsPlaying) - { - _sampleManager.PlayAudio(outChannels); - } - else // audio thru - { - base.Process(inChannels, outChannels); - } + base.Process(inChannels, outChannels); + } - if (_sampleManager.IsRecording) - { - _sampleManager.RecordAudio(inChannels); - } + if (_sampleManager.IsRecording) + { + _sampleManager.RecordAudio(inChannels); } } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Jacobi.Vst.Samples.MidiNoteSampler.csproj b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Jacobi.Vst.Samples.MidiNoteSampler.csproj index a5c8d7aa..4d3efc7e 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Jacobi.Vst.Samples.MidiNoteSampler.csproj +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Jacobi.Vst.Samples.MidiNoteSampler.csproj @@ -1,7 +1,7 @@ - + - net6.0-windows + net8.0-windows 2.1.0 Marc Jacobi Jacobi Software @@ -18,6 +18,6 @@ - + diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/MidiProcessor.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/MidiProcessor.cs index 2b2ac343..177b91e3 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/MidiProcessor.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/MidiProcessor.cs @@ -1,69 +1,68 @@ -namespace Jacobi.Vst.Samples.MidiNoteSampler +namespace Jacobi.Vst.Samples.MidiNoteSampler; + +using Jacobi.Vst.Core; +using Jacobi.Vst.Plugin.Framework; +using System; + +/// +/// Manages incoming midi events and sents them to the . +/// +internal sealed class MidiProcessor : IVstMidiProcessor { - using Jacobi.Vst.Core; - using Jacobi.Vst.Plugin.Framework; - using System; + private readonly SampleManager _sampleManager; /// - /// Manages incoming midi events and sents them to the . + /// Constructs a new instance. /// - internal sealed class MidiProcessor : IVstMidiProcessor + /// + public MidiProcessor(SampleManager sampleManager) { - private readonly SampleManager _sampleManager; - - /// - /// Constructs a new instance. - /// - /// - public MidiProcessor(SampleManager sampleManager) - { - _sampleManager = sampleManager ?? throw new ArgumentNullException(nameof(sampleManager)); - } + _sampleManager = sampleManager ?? throw new ArgumentNullException(nameof(sampleManager)); + } - #region IVstMidiProcessor Members + #region IVstMidiProcessor Members - /// - /// Always returns 16. - /// - public int ChannelCount - { - get { return 16; } - } + /// + /// Always returns 16. + /// + public int ChannelCount + { + get { return 16; } + } - /// - /// Handles and filters the incoming midi events. - /// - /// The midi events for the current cycle. - public void Process(VstEventCollection events) + /// + /// Handles and filters the incoming midi events. + /// + /// The midi events for the current cycle. + public void Process(VstEventCollection events) + { + foreach (VstEvent evnt in events) { - foreach (VstEvent evnt in events) + if (evnt.EventType == VstEventTypes.MidiEvent) { - if (evnt.EventType == VstEventTypes.MidiEvent) + var midiEvent = (VstMidiEvent)evnt; + + // pass note on and note off to the sample manager + if ((midiEvent.Data[0] & 0xF0) == 0x80) { - var midiEvent = (VstMidiEvent)evnt; + _sampleManager.ProcessNoteOffEvent(midiEvent.Data[1]); + } - // pass note on and note off to the sample manager - if ((midiEvent.Data[0] & 0xF0) == 0x80) + if ((midiEvent.Data[0] & 0xF0) == 0x90) + { + // note on with velocity = 0 is a note off + if (midiEvent.Data[2] == 0) { _sampleManager.ProcessNoteOffEvent(midiEvent.Data[1]); } - - if ((midiEvent.Data[0] & 0xF0) == 0x90) + else { - // note on with velocity = 0 is a note off - if (midiEvent.Data[2] == 0) - { - _sampleManager.ProcessNoteOffEvent(midiEvent.Data[1]); - } - else - { - _sampleManager.ProcessNoteOnEvent(midiEvent.Data[1]); - } + _sampleManager.ProcessNoteOnEvent(midiEvent.Data[1]); } } } } - - #endregion } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Plugin.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Plugin.cs index 1798e1e4..6c353502 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Plugin.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/Plugin.cs @@ -3,27 +3,26 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using Microsoft.Extensions.DependencyInjection; -namespace Jacobi.Vst.Samples.MidiNoteSampler +namespace Jacobi.Vst.Samples.MidiNoteSampler; + +/// +/// The Plugin root class that derives from the framework provided base class that also include the interface manager. +/// +internal sealed class Plugin : VstPluginWithServices { /// - /// The Plugin root class that derives from the framework provided base class that also include the interface manager. + /// Constructs a new instance. /// - internal sealed class Plugin : VstPluginWithServices - { - /// - /// Constructs a new instance. - /// - public Plugin() - : base("VST.NET 2 Midi Note Sampler", 36373435, - new VstProductInfo("VST.NET 2 Code Samples", "Jacobi Software © 2008-2020", 2000), - VstPluginCategory.Synth) - { } + public Plugin() + : base("VST.NET 2 Midi Note Sampler", 36373435, + new VstProductInfo("VST.NET 2 Code Samples", "Jacobi Software © 2008-2024", 2000), + VstPluginCategory.Synth) + { } - protected override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton() - .AddSingletonAll() - .AddSingletonAll(); - } + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton() + .AddSingletonAll() + .AddSingletonAll(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/PluginCommandStub.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/PluginCommandStub.cs index bf0d69ef..4aeab677 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/PluginCommandStub.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/PluginCommandStub.cs @@ -1,20 +1,19 @@ using Jacobi.Vst.Plugin.Framework; using Jacobi.Vst.Plugin.Framework.Plugin; -namespace Jacobi.Vst.Samples.MidiNoteSampler +namespace Jacobi.Vst.Samples.MidiNoteSampler; + +/// +/// The public Plugin Command Stub implementation derived from the framework provided . +/// +public sealed class PluginCommandStub : StdPluginCommandStub { /// - /// The public Plugin Command Stub implementation derived from the framework provided . + /// Called by the framework to create the plugin root object. /// - public sealed class PluginCommandStub : StdPluginCommandStub + /// Never returns null. + protected override IVstPlugin CreatePluginInstance() { - /// - /// Called by the framework to create the plugin root object. - /// - /// Never returns null. - protected override IVstPlugin CreatePluginInstance() - { - return new Plugin(); - } + return new Plugin(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/SampleManager.cs b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/SampleManager.cs index 87400c5b..469a6a7c 100644 --- a/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/SampleManager.cs +++ b/Source/Samples/Jacobi.Vst.Samples.MidiNoteSampler/SampleManager.cs @@ -1,182 +1,181 @@ -namespace Jacobi.Vst.Samples.MidiNoteSampler +namespace Jacobi.Vst.Samples.MidiNoteSampler; + +using Jacobi.Vst.Core; +using System; +using System.Collections.Generic; + +/// +/// Manages playback, recording and storing audio samples. +/// +internal sealed class SampleManager { - using Jacobi.Vst.Core; - using System; - using System.Collections.Generic; + private readonly Dictionary _noteMap = new Dictionary(); /// - /// Manages playback, recording and storing audio samples. + /// Starts recording the current audio or playing back the sample buffer. /// - internal sealed class SampleManager + /// The midi note number. + public void ProcessNoteOnEvent(byte noteNo) { - private readonly Dictionary _noteMap = new Dictionary(); - - /// - /// Starts recording the current audio or playing back the sample buffer. - /// - /// The midi note number. - public void ProcessNoteOnEvent(byte noteNo) + if (_noteMap.ContainsKey(noteNo)) { - if (_noteMap.ContainsKey(noteNo)) - { - _player = new SamplePlayer(_noteMap[noteNo]); - } - else if (_recorder == null) - { - _recorder = new SampleRecorder(noteNo); - } + _player = new SamplePlayer(_noteMap[noteNo]); } - - /// - /// Stops recording the current audio or playing back the the sample buffer. - /// - /// The midi note number. - public void ProcessNoteOffEvent(byte noteNo) + else if (_recorder == null) { - if (_recorder != null && _recorder.Buffer.NoteNo == noteNo) - { - _noteMap.Add(noteNo, _recorder.Buffer); - _recorder = null; - } - - if (_player != null && _player.Buffer.NoteNo == noteNo) - { - _player = null; - } + _recorder = new SampleRecorder(noteNo); } + } - private SampleRecorder? _recorder; - /// - /// Indicates if the current audio stream is being recorded. - /// - public bool IsRecording + /// + /// Stops recording the current audio or playing back the the sample buffer. + /// + /// The midi note number. + public void ProcessNoteOffEvent(byte noteNo) + { + if (_recorder != null && _recorder.Buffer.NoteNo == noteNo) { - get { return _recorder != null; } + _noteMap.Add(noteNo, _recorder.Buffer); + _recorder = null; } - /// - /// Copies out the audio samples from the . - /// - /// Input buffers. Must not be null. - public void RecordAudio(VstAudioBuffer[] channels) + if (_player != null && _player.Buffer.NoteNo == noteNo) { - if (_recorder != null) - { - _recorder.Record(channels[0], channels[1]); - } + _player = null; } + } - private SamplePlayer? _player; - /// - /// Indicates if a recorded sample buffer is being played back. - /// - public bool IsPlaying + private SampleRecorder? _recorder; + /// + /// Indicates if the current audio stream is being recorded. + /// + public bool IsRecording + { + get { return _recorder != null; } + } + + /// + /// Copies out the audio samples from the . + /// + /// Input buffers. Must not be null. + public void RecordAudio(VstAudioBuffer[] channels) + { + if (_recorder != null) { - get { return _player != null; } + _recorder.Record(channels[0], channels[1]); } + } - /// - /// Plays back the current sample buffer - /// - /// Output buffers. Must not be null. - public void PlayAudio(VstAudioBuffer[] channels) + private SamplePlayer? _player; + /// + /// Indicates if a recorded sample buffer is being played back. + /// + public bool IsPlaying + { + get { return _player != null; } + } + + /// + /// Plays back the current sample buffer + /// + /// Output buffers. Must not be null. + public void PlayAudio(VstAudioBuffer[] channels) + { + if (_player != null) { - if (_player != null) - { - _player.Play(channels[0], channels[1]); + _player.Play(channels[0], channels[1]); - if (_player.IsFinished) - { - _player = null; - } + if (_player.IsFinished) + { + _player = null; } } + } - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- - /// - /// Manages recording audio samples. - /// - private class SampleRecorder + /// + /// Manages recording audio samples. + /// + private class SampleRecorder + { + public SampleRecorder(byte noteNo) { - public SampleRecorder(byte noteNo) - { - Buffer = new StereoBuffer(noteNo); - } + Buffer = new StereoBuffer(noteNo); + } - public StereoBuffer Buffer { get; private set; } + public StereoBuffer Buffer { get; private set; } - public void Record(VstAudioBuffer left, VstAudioBuffer right) + public void Record(VstAudioBuffer left, VstAudioBuffer right) + { + for (int index = 0; index < left.SampleCount; index++) { - for (int index = 0; index < left.SampleCount; index++) - { - Buffer.LeftSamples.Add(left[index]); - } - - for (int index = 0; index < right.SampleCount; index++) - { - Buffer.RightSamples.Add(right[index]); - } + Buffer.LeftSamples.Add(left[index]); } - } - //--------------------------------------------------------------------- - - /// - /// Manages playing back a sample buffer - /// - private class SamplePlayer - { - public SamplePlayer(StereoBuffer buffer) + for (int index = 0; index < right.SampleCount; index++) { - Buffer = buffer; + Buffer.RightSamples.Add(right[index]); } + } + } - private int _bufferIndex; + //--------------------------------------------------------------------- - public StereoBuffer Buffer { get; private set; } + /// + /// Manages playing back a sample buffer + /// + private class SamplePlayer + { + public SamplePlayer(StereoBuffer buffer) + { + Buffer = buffer; + } - public void Play(VstAudioBuffer left, VstAudioBuffer right) - { - if (IsFinished) - return; + private int _bufferIndex; - int count = Math.Min(left.SampleCount, Buffer.LeftSamples.Count - _bufferIndex); + public StereoBuffer Buffer { get; private set; } - for (int index = 0; index < count; index++) - { - left[index] = Buffer.LeftSamples[_bufferIndex + index]; - } + public void Play(VstAudioBuffer left, VstAudioBuffer right) + { + if (IsFinished) + return; - for (int index = 0; index < count; index++) - { - right[index] = Buffer.RightSamples[_bufferIndex + index]; - } + int count = Math.Min(left.SampleCount, Buffer.LeftSamples.Count - _bufferIndex); - _bufferIndex += left.SampleCount; + for (int index = 0; index < count; index++) + { + left[index] = Buffer.LeftSamples[_bufferIndex + index]; } - public bool IsFinished + for (int index = 0; index < count; index++) { - get { return (_bufferIndex >= Buffer.LeftSamples.Count); } + right[index] = Buffer.RightSamples[_bufferIndex + index]; } - } - //--------------------------------------------------------------------- + _bufferIndex += left.SampleCount; + } - /// - /// Manages a stereo sample buffer for a specific note number. - /// - private class StereoBuffer + public bool IsFinished { - public StereoBuffer(byte noteNo) - { - NoteNo = noteNo; - } + get { return (_bufferIndex >= Buffer.LeftSamples.Count); } + } + } - public byte NoteNo; - public List LeftSamples = new List(); - public List RightSamples = new List(); + //--------------------------------------------------------------------- + + /// + /// Manages a stereo sample buffer for a specific note number. + /// + private class StereoBuffer + { + public StereoBuffer(byte noteNo) + { + NoteNo = noteNo; } + + public byte NoteNo; + public List LeftSamples = new List(); + public List RightSamples = new List(); } } diff --git a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/HostCommandStubAdapter.cs b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/HostCommandStubAdapter.cs index b7eaa808..336edf46 100644 --- a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/HostCommandStubAdapter.cs +++ b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/HostCommandStubAdapter.cs @@ -3,62 +3,61 @@ using Jacobi.Vst.Core.Plugin; using Jacobi.Vst.Host.Interop; -namespace Jacobi.Vst.Samples.WrapperPlugin.Host +namespace Jacobi.Vst.Samples.WrapperPlugin.Host; + +public class HostCommandStubAdapter : IVstHostCommandStub { - public class HostCommandStubAdapter : IVstHostCommandStub + // wrapper plugin info (cannot do much on its own) + private readonly VstPluginInfo _pluginInfo = new VstPluginInfo { - // wrapper plugin info (cannot do much on its own) - private readonly VstPluginInfo _pluginInfo = new VstPluginInfo - { - Flags = VstPluginFlags.HasEditor | VstPluginFlags.CanReplacing, - PluginID = 0x42424242, - PluginVersion = 2000 - }; + Flags = VstPluginFlags.HasEditor | VstPluginFlags.CanReplacing, + PluginID = 0x42424242, + PluginVersion = 2000 + }; - private readonly IVstHostCommandProxy _hostCmdProxy; + private readonly IVstHostCommandProxy _hostCmdProxy; - public HostCommandStubAdapter(IVstHostCommandProxy hostCmdProxy) - { - _hostCmdProxy = hostCmdProxy; - } + public HostCommandStubAdapter(IVstHostCommandProxy hostCmdProxy) + { + _hostCmdProxy = hostCmdProxy; + } - public IVstPluginCommands24 OnLoadPlugin(string pluginPath) - { - LoadPlugin(pluginPath); - return PluginContext.PluginCommandStub.Commands; - } + public IVstPluginCommands24 OnLoadPlugin(string pluginPath) + { + LoadPlugin(pluginPath); + return PluginContext.PluginCommandStub.Commands; + } - public VstPluginInfo PluginInfo + public VstPluginInfo PluginInfo + { + get { - get + if (PluginContext != null) { - if (PluginContext != null) - { - return PluginContext.PluginInfo; - } - return _pluginInfo; + return PluginContext.PluginInfo; } + return _pluginInfo; } + } - public VstPluginContext? LoadedPluginContext { get; private set; } - - public void LoadPlugin(string pluginPath) - { - LoadedPluginContext = VstPluginContext.Create(pluginPath, this); + public VstPluginContext? LoadedPluginContext { get; private set; } - // update plugin info to loaded plugin - _hostCmdProxy.UpdatePluginInfo(LoadedPluginContext.PluginInfo); - } + public void LoadPlugin(string pluginPath) + { + LoadedPluginContext = VstPluginContext.Create(pluginPath, this); - #region IVstHostCommandStub Members + // update plugin info to loaded plugin + _hostCmdProxy.UpdatePluginInfo(LoadedPluginContext.PluginInfo); + } - public IVstPluginContext PluginContext { get; set; } + #region IVstHostCommandStub Members - public IVstHostCommands20 Commands - { - get { return _hostCmdProxy.Commands; } - } + public IVstPluginContext PluginContext { get; set; } - #endregion + public IVstHostCommands20 Commands + { + get { return _hostCmdProxy.Commands; } } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/Jacobi.Vst.Samples.WrapperPlugin.csproj b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/Jacobi.Vst.Samples.WrapperPlugin.csproj index 1a74bed2..886126e2 100644 --- a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/Jacobi.Vst.Samples.WrapperPlugin.csproj +++ b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/Jacobi.Vst.Samples.WrapperPlugin.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net8.0-windows 2.1.0 Marc Jacobi Jacobi Software @@ -18,8 +18,8 @@ - - + + diff --git a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommandStubAdapter.cs b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommandStubAdapter.cs index b7a39428..05d386d9 100644 --- a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommandStubAdapter.cs +++ b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommandStubAdapter.cs @@ -2,29 +2,28 @@ using Jacobi.Vst.Core.Plugin; using Microsoft.Extensions.Configuration; -namespace Jacobi.Vst.Samples.WrapperPlugin -{ - public class PluginCommandStubAdapter : IVstPluginCommandStub - { - private readonly PluginCommands _commands = new PluginCommands(); - private Host.HostCommandStubAdapter? _hostAdapter; +namespace Jacobi.Vst.Samples.WrapperPlugin; - #region IVstPluginCommandStub Members +public class PluginCommandStubAdapter : IVstPluginCommandStub +{ + private readonly PluginCommands _commands = new PluginCommands(); + private Host.HostCommandStubAdapter? _hostAdapter; - public VstPluginInfo GetPluginInfo(IVstHostCommandProxy hostCmdProxy) - { - _hostAdapter = new Host.HostCommandStubAdapter(hostCmdProxy); - _commands.OnLoadPlugin = _hostAdapter.OnLoadPlugin; - return _hostAdapter.PluginInfo; - } + #region IVstPluginCommandStub Members - public IConfiguration? PluginConfiguration { get; set; } + public VstPluginInfo GetPluginInfo(IVstHostCommandProxy hostCmdProxy) + { + _hostAdapter = new Host.HostCommandStubAdapter(hostCmdProxy); + _commands.OnLoadPlugin = _hostAdapter.OnLoadPlugin; + return _hostAdapter.PluginInfo; + } - public IVstPluginCommands24 Commands - { - get { return _commands; } - } + public IConfiguration? PluginConfiguration { get; set; } - #endregion + public IVstPluginCommands24 Commands + { + get { return _commands; } } + + #endregion } diff --git a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommands.cs b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommands.cs index 872c29be..f6bcff07 100644 --- a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommands.cs +++ b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/PluginCommands.cs @@ -3,501 +3,500 @@ using System; using System.Drawing; -namespace Jacobi.Vst.Samples.WrapperPlugin +namespace Jacobi.Vst.Samples.WrapperPlugin; + +internal class PluginCommands : IVstPluginCommands24 { - internal class PluginCommands : IVstPluginCommands24 - { - private readonly WinFormsControlWrapper _uiWrapper = - new WinFormsControlWrapper(); + private readonly WinFormsControlWrapper _uiWrapper = + new WinFormsControlWrapper(); - // commands to the loaded plugin - private IVstPluginCommands24? _commands; - // path of the loaded plugin - private string _pluginPath = String.Empty; + // commands to the loaded plugin + private IVstPluginCommands24? _commands; + // path of the loaded plugin + private string _pluginPath = String.Empty; - public delegate IVstPluginCommands24 LoadPlugin(string pluginPath); + public delegate IVstPluginCommands24 LoadPlugin(string pluginPath); - public PluginCommands() - { - _uiWrapper.SafeInstance.OnLoadPlugin += Plugin_OnLoadPlugin; - } + public PluginCommands() + { + _uiWrapper.SafeInstance.OnLoadPlugin += Plugin_OnLoadPlugin; + } - private void Plugin_OnLoadPlugin(string pluginPath) - { - _pluginPath = pluginPath; + private void Plugin_OnLoadPlugin(string pluginPath) + { + _pluginPath = pluginPath; - if (OnLoadPlugin != null) + if (OnLoadPlugin != null) + { + _commands = OnLoadPlugin(pluginPath); + if (_commands != null) { - _commands = OnLoadPlugin(pluginPath); - if (_commands != null) - { - _commands.EditorOpen(_uiWrapper.SafeInstance.PluginWnd); - } + _commands.EditorOpen(_uiWrapper.SafeInstance.PluginWnd); } } + } - // callback to trigger plugin load logic - public LoadPlugin? OnLoadPlugin { get; set; } + // callback to trigger plugin load logic + public LoadPlugin? OnLoadPlugin { get; set; } - public VstCanDoResult BeginLoadBank(VstPatchChunkInfo chunkInfo) - { - if (_commands != null) - _commands.BeginLoadBank(chunkInfo); + public VstCanDoResult BeginLoadBank(VstPatchChunkInfo chunkInfo) + { + if (_commands != null) + _commands.BeginLoadBank(chunkInfo); - return VstCanDoResult.No; - } + return VstCanDoResult.No; + } - public VstCanDoResult BeginLoadProgram(VstPatchChunkInfo chunkInfo) - { - if (_commands != null) - _commands.BeginLoadProgram(chunkInfo); + public VstCanDoResult BeginLoadProgram(VstPatchChunkInfo chunkInfo) + { + if (_commands != null) + _commands.BeginLoadProgram(chunkInfo); - return VstCanDoResult.No; - } + return VstCanDoResult.No; + } - public bool BeginSetProgram() - { - if (_commands != null) - return _commands.BeginSetProgram(); + public bool BeginSetProgram() + { + if (_commands != null) + return _commands.BeginSetProgram(); - return false; - } + return false; + } - public VstCanDoResult CanDo(string cando) - { - if (_commands != null) - return _commands.CanDo(cando); + public VstCanDoResult CanDo(string cando) + { + if (_commands != null) + return _commands.CanDo(cando); - return VstCanDoResult.No; - } + return VstCanDoResult.No; + } - public bool CanParameterBeAutomated(int index) - { - if (_commands != null) - return _commands.CanParameterBeAutomated(index); + public bool CanParameterBeAutomated(int index) + { + if (_commands != null) + return _commands.CanParameterBeAutomated(index); - return false; - } + return false; + } - public void Close() - { - if (_commands != null) - _commands.Close(); - } + public void Close() + { + if (_commands != null) + _commands.Close(); + } - public void EditorClose() + public void EditorClose() + { + if (_commands != null) { - if (_commands != null) - { - _uiWrapper.SafeInstance.DetachPluginUI(); - _commands.EditorClose(); - } - _uiWrapper.Close(); + _uiWrapper.SafeInstance.DetachPluginUI(); + _commands.EditorClose(); } + _uiWrapper.Close(); + } - public bool EditorGetRect(out Rectangle rect) + public bool EditorGetRect(out Rectangle rect) + { + if (_commands != null && + _commands.EditorGetRect(out Rectangle pluginRect)) { - if (_commands != null && - _commands.EditorGetRect(out Rectangle pluginRect)) - { - _uiWrapper.SafeInstance.SizeForPlugin(ref pluginRect); - } - - rect = _uiWrapper.Bounds; - return true; + _uiWrapper.SafeInstance.SizeForPlugin(ref pluginRect); } - public void EditorIdle() - { - if (_commands != null) - _commands.EditorIdle(); - } + rect = _uiWrapper.Bounds; + return true; + } - public bool EditorKeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - if (_commands != null) - return _commands.EditorKeyDown(ascii, virtualKey, modifers); + public void EditorIdle() + { + if (_commands != null) + _commands.EditorIdle(); + } - return false; - } + public bool EditorKeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + if (_commands != null) + return _commands.EditorKeyDown(ascii, virtualKey, modifers); - public bool EditorKeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - if (_commands != null) - return _commands.EditorKeyUp(ascii, virtualKey, modifers); + return false; + } - return false; - } + public bool EditorKeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + if (_commands != null) + return _commands.EditorKeyUp(ascii, virtualKey, modifers); - public bool EditorOpen(IntPtr hWnd) - { - if (_commands != null) - _commands.EditorOpen(_uiWrapper.SafeInstance.PluginWnd); + return false; + } - _uiWrapper.SafeInstance.LoadedPluginPath = _pluginPath; - _uiWrapper.Open(hWnd); - return true; - } + public bool EditorOpen(IntPtr hWnd) + { + if (_commands != null) + _commands.EditorOpen(_uiWrapper.SafeInstance.PluginWnd); - public bool EndSetProgram() - { - if (_commands != null) - return _commands.EndSetProgram(); + _uiWrapper.SafeInstance.LoadedPluginPath = _pluginPath; + _uiWrapper.Open(hWnd); + return true; + } - return false; - } + public bool EndSetProgram() + { + if (_commands != null) + return _commands.EndSetProgram(); - public VstPluginCategory GetCategory() - { - if (_commands != null) - return _commands.GetCategory(); + return false; + } - return VstPluginCategory.Unknown; - } + public VstPluginCategory GetCategory() + { + if (_commands != null) + return _commands.GetCategory(); - public byte[] GetChunk(bool isPreset) - { - if (_commands != null) - return _commands.GetChunk(isPreset); + return VstPluginCategory.Unknown; + } - return Array.Empty(); - } + public byte[] GetChunk(bool isPreset) + { + if (_commands != null) + return _commands.GetChunk(isPreset); - public int GetCurrentMidiProgramName(VstMidiProgramName midiProgramName, int channel) - { - if (_commands != null) - return _commands.GetCurrentMidiProgramName(midiProgramName, channel); + return Array.Empty(); + } - return 0; - } + public int GetCurrentMidiProgramName(VstMidiProgramName midiProgramName, int channel) + { + if (_commands != null) + return _commands.GetCurrentMidiProgramName(midiProgramName, channel); - public string GetEffectName() - { - if (_commands != null) - return _commands.GetEffectName(); + return 0; + } - return "VST.NET Hot-Reload Plugin Wrapper"; - } + public string GetEffectName() + { + if (_commands != null) + return _commands.GetEffectName(); - public VstPinProperties? GetInputProperties(int index) - { - if (_commands != null) - return _commands.GetInputProperties(index); + return "VST.NET Hot-Reload Plugin Wrapper"; + } - return null; - } + public VstPinProperties? GetInputProperties(int index) + { + if (_commands != null) + return _commands.GetInputProperties(index); - public bool GetMidiKeyName(VstMidiKeyName midiKeyName, int channel) - { - if (_commands != null) - return _commands.GetMidiKeyName(midiKeyName, channel); + return null; + } - return false; - } + public bool GetMidiKeyName(VstMidiKeyName midiKeyName, int channel) + { + if (_commands != null) + return _commands.GetMidiKeyName(midiKeyName, channel); - public int GetMidiProgramCategory(VstMidiProgramCategory midiCat, int channel) - { - if (_commands != null) - return _commands.GetMidiProgramCategory(midiCat, channel); + return false; + } - return 0; - } + public int GetMidiProgramCategory(VstMidiProgramCategory midiCat, int channel) + { + if (_commands != null) + return _commands.GetMidiProgramCategory(midiCat, channel); - public int GetMidiProgramName(VstMidiProgramName midiProgramName, int channel) - { - if (_commands != null) - return _commands.GetMidiProgramName(midiProgramName, channel); + return 0; + } - return 0; - } + public int GetMidiProgramName(VstMidiProgramName midiProgramName, int channel) + { + if (_commands != null) + return _commands.GetMidiProgramName(midiProgramName, channel); - public int GetNextPlugin(out string name) - { - if (_commands != null) - return _commands.GetNextPlugin(out name); + return 0; + } - name = String.Empty; - return 0; - } + public int GetNextPlugin(out string name) + { + if (_commands != null) + return _commands.GetNextPlugin(out name); - public int GetNumberOfMidiInputChannels() - { - if (_commands != null) - return _commands.GetNumberOfMidiInputChannels(); + name = String.Empty; + return 0; + } - return 0; - } + public int GetNumberOfMidiInputChannels() + { + if (_commands != null) + return _commands.GetNumberOfMidiInputChannels(); - public int GetNumberOfMidiOutputChannels() - { - if (_commands != null) - return _commands.GetNumberOfMidiOutputChannels(); + return 0; + } - return 0; - } + public int GetNumberOfMidiOutputChannels() + { + if (_commands != null) + return _commands.GetNumberOfMidiOutputChannels(); - public VstPinProperties? GetOutputProperties(int index) - { - if (_commands != null) - return _commands.GetOutputProperties(index); + return 0; + } - return null; - } + public VstPinProperties? GetOutputProperties(int index) + { + if (_commands != null) + return _commands.GetOutputProperties(index); - public float GetParameter(int index) - { - if (_commands != null) - return _commands.GetParameter(index); + return null; + } - return 0.0f; - } + public float GetParameter(int index) + { + if (_commands != null) + return _commands.GetParameter(index); - public string GetParameterDisplay(int index) - { - if (_commands != null) - return _commands.GetParameterDisplay(index); + return 0.0f; + } - return String.Empty; - } + public string GetParameterDisplay(int index) + { + if (_commands != null) + return _commands.GetParameterDisplay(index); - public string GetParameterLabel(int index) - { - if (_commands != null) - return _commands.GetParameterLabel(index); + return String.Empty; + } - return String.Empty; - } + public string GetParameterLabel(int index) + { + if (_commands != null) + return _commands.GetParameterLabel(index); - public string GetParameterName(int index) - { - if (_commands != null) - return _commands.GetParameterName(index); + return String.Empty; + } - return String.Empty; - } + public string GetParameterName(int index) + { + if (_commands != null) + return _commands.GetParameterName(index); - public VstParameterProperties? GetParameterProperties(int index) - { - if (_commands != null) - return _commands.GetParameterProperties(index); + return String.Empty; + } - return null; - } + public VstParameterProperties? GetParameterProperties(int index) + { + if (_commands != null) + return _commands.GetParameterProperties(index); - public string GetProductString() - { - if (_commands != null) - return _commands.GetProductString(); + return null; + } - return "VST.NET 2"; - } + public string GetProductString() + { + if (_commands != null) + return _commands.GetProductString(); - public int GetProgram() - { - if (_commands != null) - return _commands.GetProgram(); + return "VST.NET 2"; + } - return 0; - } + public int GetProgram() + { + if (_commands != null) + return _commands.GetProgram(); - public string GetProgramName() - { - if (_commands != null) - return _commands.GetProgramName(); + return 0; + } - return String.Empty; - } + public string GetProgramName() + { + if (_commands != null) + return _commands.GetProgramName(); - public string GetProgramNameIndexed(int index) - { - if (_commands != null) - return _commands.GetProgramNameIndexed(index); + return String.Empty; + } - return String.Empty; - } + public string GetProgramNameIndexed(int index) + { + if (_commands != null) + return _commands.GetProgramNameIndexed(index); - public bool GetSpeakerArrangement(out VstSpeakerArrangement? input, out VstSpeakerArrangement? output) - { - if (_commands != null) - return _commands.GetSpeakerArrangement(out input, out output); + return String.Empty; + } - input = null; - output = null; - return false; - } + public bool GetSpeakerArrangement(out VstSpeakerArrangement? input, out VstSpeakerArrangement? output) + { + if (_commands != null) + return _commands.GetSpeakerArrangement(out input, out output); - public int GetTailSize() - { - if (_commands != null) - return _commands.GetTailSize(); + input = null; + output = null; + return false; + } - return 0; - } + public int GetTailSize() + { + if (_commands != null) + return _commands.GetTailSize(); - public string GetVendorString() - { - if (_commands != null) - return _commands.GetVendorString(); + return 0; + } - return "Jacobi Software"; - } + public string GetVendorString() + { + if (_commands != null) + return _commands.GetVendorString(); - public int GetVendorVersion() - { - if (_commands != null) - return _commands.GetVendorVersion(); + return "Jacobi Software"; + } - return 2000; - } + public int GetVendorVersion() + { + if (_commands != null) + return _commands.GetVendorVersion(); - public int GetVstVersion() - { - if (_commands != null) - return _commands.GetVstVersion(); + return 2000; + } - return 2400; - } + public int GetVstVersion() + { + if (_commands != null) + return _commands.GetVstVersion(); - public bool HasMidiProgramsChanged(int channel) - { - if (_commands != null) - return _commands.HasMidiProgramsChanged(channel); + return 2400; + } - return false; - } + public bool HasMidiProgramsChanged(int channel) + { + if (_commands != null) + return _commands.HasMidiProgramsChanged(channel); - public void MainsChanged(bool onoff) - { - if (_commands != null) - _commands.MainsChanged(onoff); - } + return false; + } - public void Open() - { - if (_commands != null) - _commands.Open(); - } + public void MainsChanged(bool onoff) + { + if (_commands != null) + _commands.MainsChanged(onoff); + } - public bool ProcessEvents(VstEvent[] events) - { - if (_commands != null) - return _commands.ProcessEvents(events); + public void Open() + { + if (_commands != null) + _commands.Open(); + } - return false; - } + public bool ProcessEvents(VstEvent[] events) + { + if (_commands != null) + return _commands.ProcessEvents(events); - public void ProcessReplacing(VstAudioBuffer[] inputs, VstAudioBuffer[] outputs) - { - if (_commands != null) - _commands.ProcessReplacing(inputs, outputs); - } + return false; + } - public void ProcessReplacing(VstAudioPrecisionBuffer[] inputs, VstAudioPrecisionBuffer[] outputs) - { - if (_commands != null) - _commands.ProcessReplacing(inputs, outputs); - } + public void ProcessReplacing(VstAudioBuffer[] inputs, VstAudioBuffer[] outputs) + { + if (_commands != null) + _commands.ProcessReplacing(inputs, outputs); + } - public void SetBlockSize(int blockSize) - { - if (_commands != null) - _commands.SetBlockSize(blockSize); - } + public void ProcessReplacing(VstAudioPrecisionBuffer[] inputs, VstAudioPrecisionBuffer[] outputs) + { + if (_commands != null) + _commands.ProcessReplacing(inputs, outputs); + } - public bool SetBypass(bool bypass) - { - if (_commands != null) - return _commands.SetBypass(bypass); + public void SetBlockSize(int blockSize) + { + if (_commands != null) + _commands.SetBlockSize(blockSize); + } - return false; - } + public bool SetBypass(bool bypass) + { + if (_commands != null) + return _commands.SetBypass(bypass); - public int SetChunk(byte[] data, bool isPreset) - { - if (_commands != null) - return _commands.SetChunk(data, isPreset); + return false; + } - return 0; - } + public int SetChunk(byte[] data, bool isPreset) + { + if (_commands != null) + return _commands.SetChunk(data, isPreset); - public bool SetEditorKnobMode(VstKnobMode mode) - { - if (_commands != null) - return _commands.SetEditorKnobMode(mode); + return 0; + } - return false; - } + public bool SetEditorKnobMode(VstKnobMode mode) + { + if (_commands != null) + return _commands.SetEditorKnobMode(mode); - public bool SetPanLaw(VstPanLaw type, float gain) - { - if (_commands != null) - return _commands.SetPanLaw(type, gain); + return false; + } - return false; - } + public bool SetPanLaw(VstPanLaw type, float gain) + { + if (_commands != null) + return _commands.SetPanLaw(type, gain); - public void SetParameter(int index, float value) - { - if (_commands != null) - _commands.SetParameter(index, value); - } + return false; + } - public bool SetProcessPrecision(VstProcessPrecision precision) - { - if (_commands != null) - return _commands.SetProcessPrecision(precision); + public void SetParameter(int index, float value) + { + if (_commands != null) + _commands.SetParameter(index, value); + } - return false; - } + public bool SetProcessPrecision(VstProcessPrecision precision) + { + if (_commands != null) + return _commands.SetProcessPrecision(precision); - public void SetProgram(int programNumber) - { - if (_commands != null) - _commands.SetProgram(programNumber); - } + return false; + } - public void SetProgramName(string name) - { - if (_commands != null) - _commands.SetProgramName(name); - } + public void SetProgram(int programNumber) + { + if (_commands != null) + _commands.SetProgram(programNumber); + } - public void SetSampleRate(float sampleRate) - { - if (_commands != null) - _commands.SetSampleRate(sampleRate); - } + public void SetProgramName(string name) + { + if (_commands != null) + _commands.SetProgramName(name); + } - public bool SetSpeakerArrangement(VstSpeakerArrangement saInput, VstSpeakerArrangement saOutput) - { - if (_commands != null) - return _commands.SetSpeakerArrangement(saInput, saOutput); + public void SetSampleRate(float sampleRate) + { + if (_commands != null) + _commands.SetSampleRate(sampleRate); + } - return false; - } + public bool SetSpeakerArrangement(VstSpeakerArrangement saInput, VstSpeakerArrangement saOutput) + { + if (_commands != null) + return _commands.SetSpeakerArrangement(saInput, saOutput); - public int StartProcess() - { - if (_commands != null) - return _commands.StartProcess(); + return false; + } - return 0; - } + public int StartProcess() + { + if (_commands != null) + return _commands.StartProcess(); - public int StopProcess() - { - if (_commands != null) - return _commands.StopProcess(); + return 0; + } - return 0; - } + public int StopProcess() + { + if (_commands != null) + return _commands.StopProcess(); - public bool String2Parameter(int index, string str) - { - if (_commands != null) - return _commands.String2Parameter(index, str); + return 0; + } - return false; - } + public bool String2Parameter(int index, string str) + { + if (_commands != null) + return _commands.String2Parameter(index, str); + + return false; } } diff --git a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/UI/PluginFrame.cs b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/UI/PluginFrame.cs index 18acc870..60972180 100644 --- a/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/UI/PluginFrame.cs +++ b/Source/Samples/Jacobi.Vst.Samples.WrapperPlugin/UI/PluginFrame.cs @@ -2,62 +2,61 @@ using System.Drawing; using System.Windows.Forms; -namespace Jacobi.Vst.Samples.WrapperPlugin.UI +namespace Jacobi.Vst.Samples.WrapperPlugin.UI; + +internal partial class PluginFrame : UserControl { - internal partial class PluginFrame : UserControl - { - public delegate void LoadEvent(string pluginPath); + public delegate void LoadEvent(string pluginPath); - public event LoadEvent? OnLoadPlugin; + public event LoadEvent? OnLoadPlugin; - public IntPtr PluginWnd { get; internal set; } + public IntPtr PluginWnd { get; internal set; } - public PluginFrame() - { - InitializeComponent(); + public PluginFrame() + { + InitializeComponent(); - PluginWnd = PluginPanel.Handle; - } + PluginWnd = PluginPanel.Handle; + } - private void Browse_Click(object sender, EventArgs e) + private void Browse_Click(object sender, EventArgs e) + { + if (OpenFileDialog.ShowDialog(this) == DialogResult.OK) { - if (OpenFileDialog.ShowDialog(this) == DialogResult.OK) - { - PluginPath.Text = OpenFileDialog.FileName; - RaiseOnReload(); - } + PluginPath.Text = OpenFileDialog.FileName; + RaiseOnReload(); } + } - public string LoadedPluginPath - { - get { return PluginPath.Text; } - set { PluginPath.Text = value; } - } + public string LoadedPluginPath + { + get { return PluginPath.Text; } + set { PluginPath.Text = value; } + } - public void SizeForPlugin(ref Rectangle pluginRect) - { - SetBounds(0, 0, pluginRect.Width, pluginRect.Height, BoundsSpecified.Size); - } + public void SizeForPlugin(ref Rectangle pluginRect) + { + SetBounds(0, 0, pluginRect.Width, pluginRect.Height, BoundsSpecified.Size); + } - public void DetachPluginUI() + public void DetachPluginUI() + { + PluginPanel.Controls.Clear(); + } + + private void RaiseOnReload() + { + try { - PluginPanel.Controls.Clear(); + OnLoadPlugin?.Invoke(PluginPath.Text); } - - private void RaiseOnReload() + catch (Exception e) { - try - { - OnLoadPlugin?.Invoke(PluginPath.Text); - } - catch (Exception e) - { - MessageBox.Show(this, - e.ToString(), - "VST.NET 2 Wrapper Plugin", - MessageBoxButtons.OK, - MessageBoxIcon.Error); - } + MessageBox.Show(this, + e.ToString(), + "VST.NET 2 Wrapper Plugin", + MessageBoxButtons.OK, + MessageBoxIcon.Error); } } } diff --git a/Source/Templates/CSharp/Jacobi.Vst.Templates.sln b/Source/Templates/CSharp/Jacobi.Vst.Templates.sln index 108fb406..b564dd70 100644 --- a/Source/Templates/CSharp/Jacobi.Vst.Templates.sln +++ b/Source/Templates/CSharp/Jacobi.Vst.Templates.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30128.74 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34316.72 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VstNetAudioPlugin", "VstNetAudioPlugin\VstNetAudioPlugin.csproj", "{018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}" EndProject @@ -14,32 +14,24 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Debug|Any CPU.ActiveCfg = Debug|x86 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Debug|x64.ActiveCfg = Debug|x64 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Debug|x64.Build.0 = Debug|x64 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Debug|x86.ActiveCfg = Debug|x86 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Debug|x86.Build.0 = Debug|x86 - {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Release|Any CPU.ActiveCfg = Release|x86 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Release|x64.ActiveCfg = Release|x64 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Release|x64.Build.0 = Release|x64 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Release|x86.ActiveCfg = Release|x86 {018BD11B-E0EF-475C-BDB0-2C1AD11D76E8}.Release|x86.Build.0 = Release|x86 - {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|Any CPU.Build.0 = Debug|Any CPU {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|x64.ActiveCfg = Debug|x64 {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|x64.Build.0 = Debug|x64 {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|x86.ActiveCfg = Debug|x86 {B9564665-112B-4FAE-9267-96FE5344B22A}.Debug|x86.Build.0 = Debug|x86 - {B9564665-112B-4FAE-9267-96FE5344B22A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B9564665-112B-4FAE-9267-96FE5344B22A}.Release|Any CPU.Build.0 = Release|Any CPU {B9564665-112B-4FAE-9267-96FE5344B22A}.Release|x64.ActiveCfg = Release|x64 {B9564665-112B-4FAE-9267-96FE5344B22A}.Release|x64.Build.0 = Release|x64 {B9564665-112B-4FAE-9267-96FE5344B22A}.Release|x86.ActiveCfg = Release|x86 diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/AudioProcessor.cs b/Source/Templates/CSharp/VstNetAudioPlugin/AudioProcessor.cs index 9f3d7b41..0a07a988 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/AudioProcessor.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/AudioProcessor.cs @@ -5,133 +5,132 @@ using System.Diagnostics; using VstNetAudioPlugin.Dsp; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// This object performs audio processing for your plugin. +/// +internal sealed class AudioProcessor : VstPluginAudioProcessor, IVstPluginBypass { /// - /// This object performs audio processing for your plugin. + /// TODO: assign the input count. + /// + private const int AudioInputCount = 2; + /// + /// TODO: assign the output count. /// - internal sealed class AudioProcessor : VstPluginAudioProcessor, IVstPluginBypass + private const int AudioOutputCount = 2; + /// + /// TODO: assign the tail size. + /// + private const int InitialTailSize = 0; + + // TODO: change this to your specific needs. + private readonly VstTimeInfoFlags _defaultTimeInfoFlags = VstTimeInfoFlags.ClockValid; + // set after the plugin is opened + private IVstHostSequencer? _sequencer; + + /// + /// Default constructor. + /// + public AudioProcessor(IVstPluginEvents pluginEvents, PluginParameters parameters) + : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: false) { - /// - /// TODO: assign the input count. - /// - private const int AudioInputCount = 2; - /// - /// TODO: assign the output count. - /// - private const int AudioOutputCount = 2; - /// - /// TODO: assign the tail size. - /// - private const int InitialTailSize = 0; - - // TODO: change this to your specific needs. - private readonly VstTimeInfoFlags _defaultTimeInfoFlags = VstTimeInfoFlags.ClockValid; - // set after the plugin is opened - private IVstHostSequencer? _sequencer; - - /// - /// Default constructor. - /// - public AudioProcessor(IVstPluginEvents pluginEvents, PluginParameters parameters) - : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: false) - { - Throw.IfArgumentIsNull(pluginEvents, nameof(pluginEvents)); - Throw.IfArgumentIsNull(parameters, nameof(parameters)); + Throw.IfArgumentIsNull(pluginEvents, nameof(pluginEvents)); + Throw.IfArgumentIsNull(parameters, nameof(parameters)); - // one set of parameters is shared for both channels. - Left = new Delay(parameters.DelayParameters); - Right = new Delay(parameters.DelayParameters); + // one set of parameters is shared for both channels. + Left = new Delay(parameters.DelayParameters); + Right = new Delay(parameters.DelayParameters); - pluginEvents.Opened += Plugin_Opened; - } + pluginEvents.Opened += Plugin_Opened; + } - internal Delay Left { get; private set; } - internal Delay Right { get; private set; } + internal Delay Left { get; private set; } + internal Delay Right { get; private set; } - /// - /// Override the default implementation to pass it through to the delay. - /// - public override float SampleRate + /// + /// Override the default implementation to pass it through to the delay. + /// + public override float SampleRate + { + get { return Left.SampleRate; } + set { - get { return Left.SampleRate; } - set - { - Left.SampleRate = value; - Right.SampleRate = value; - } + Left.SampleRate = value; + Right.SampleRate = value; } + } - private VstTimeInfo? _timeInfo; - /// - /// Gets the current time info. - /// - /// The Time Info is refreshed with each call to Process. - internal VstTimeInfo? TimeInfo + private VstTimeInfo? _timeInfo; + /// + /// Gets the current time info. + /// + /// The Time Info is refreshed with each call to Process. + internal VstTimeInfo? TimeInfo + { + get { - get + if (_timeInfo == null && _sequencer != null) { - if (_timeInfo == null && _sequencer != null) - { - _timeInfo = _sequencer.GetTime(_defaultTimeInfoFlags); - } - - return _timeInfo; + _timeInfo = _sequencer.GetTime(_defaultTimeInfoFlags); } + + return _timeInfo; } + } - private void Plugin_Opened(object? sender, EventArgs e) - { - var plugin = (VstPlugin?)sender; + private void Plugin_Opened(object? sender, EventArgs e) + { + var plugin = (VstPlugin?)sender; - // A reference to the host is only available after - // the plugin has been loaded and opened by the host. - _sequencer = plugin?.Host?.GetInstance(); - } + // A reference to the host is only available after + // the plugin has been loaded and opened by the host. + _sequencer = plugin?.Host?.GetInstance(); + } - /// - /// Called by the host to allow the plugin to process audio samples. - /// - /// Never null. - /// Never null. - public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) - { - // by resetting the time info each cycle, accessing the TimeInfo property will fetch new info. - _timeInfo = null; + /// + /// Called by the host to allow the plugin to process audio samples. + /// + /// Never null. + /// Never null. + public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + { + // by resetting the time info each cycle, accessing the TimeInfo property will fetch new info. + _timeInfo = null; - if (!Bypass) - { - // check assumptions - Debug.Assert(outChannels.Length == inChannels.Length); + if (!Bypass) + { + // check assumptions + Debug.Assert(outChannels.Length == inChannels.Length); - // TODO: Implement your audio (effect) processing here. + // TODO: Implement your audio (effect) processing here. - for (int i = 0; i < outChannels.Length; i++) - { - Process(i % 2 == 0 ? Left : Right, - inChannels[i], outChannels[i]); - } - } - else + for (int i = 0; i < outChannels.Length; i++) { - // calling the base class transfers input samples to the output channels unchanged (bypass). - base.Process(inChannels, outChannels); + Process(i % 2 == 0 ? Left : Right, + inChannels[i], outChannels[i]); } } + else + { + // calling the base class transfers input samples to the output channels unchanged (bypass). + base.Process(inChannels, outChannels); + } + } - // process a single audio channel - private void Process(Delay delay, VstAudioBuffer input, VstAudioBuffer output) + // process a single audio channel + private void Process(Delay delay, VstAudioBuffer input, VstAudioBuffer output) + { + for (int i = 0; i < input.SampleCount; i++) { - for (int i = 0; i < input.SampleCount; i++) - { - output[i] = delay.ProcessSample(input[i]); - } + output[i] = delay.ProcessSample(input[i]); } + } - #region IVstPluginBypass Members + #region IVstPluginBypass Members - public bool Bypass { get; set; } + public bool Bypass { get; set; } - #endregion - } + #endregion } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/Delay.cs b/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/Delay.cs index 435bdb71..5144c1e9 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/Delay.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/Delay.cs @@ -1,91 +1,90 @@ using System; using System.ComponentModel; -namespace VstNetAudioPlugin.Dsp +namespace VstNetAudioPlugin.Dsp; + +/// +/// This is an example of a Digital Sound Processing component you could have in your plugin. +/// +internal sealed class Delay { + private float[] _delayBuffer; + private int _bufferIndex; + private int _bufferLength; + + private readonly DelayParameters _parameters; + /// - /// This is an example of a Digital Sound Processing component you could have in your plugin. + /// Constructs a new instance. /// - internal sealed class Delay + public Delay(DelayParameters parameters) { - private float[] _delayBuffer; - private int _bufferIndex; - private int _bufferLength; - - private readonly DelayParameters _parameters; + _delayBuffer = Array.Empty(); + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - /// - /// Constructs a new instance. - /// - public Delay(DelayParameters parameters) - { - _delayBuffer = Array.Empty(); - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - - // when the delay time parameter value changes, we like to know about it. - _parameters.DelayTimeMgr.PropertyChanged += DelayTimeMgr_PropertyChanged; - } + // when the delay time parameter value changes, we like to know about it. + _parameters.DelayTimeMgr.PropertyChanged += DelayTimeMgr_PropertyChanged; + } - private void DelayTimeMgr_PropertyChanged(object sender, PropertyChangedEventArgs e) + private void DelayTimeMgr_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (Object.ReferenceEquals(_parameters.DelayTimeMgr, sender)) { - if (Object.ReferenceEquals(_parameters.DelayTimeMgr, sender)) - { - SetBufferLength(); - } + SetBufferLength(); } + } - private void SetBufferLength() - { - // logical buffer length - _bufferLength = (int)(_parameters.DelayTimeMgr.CurrentValue * _sampleRate / 1000); - } + private void SetBufferLength() + { + // logical buffer length + _bufferLength = (int)(_parameters.DelayTimeMgr.CurrentValue * _sampleRate / 1000); + } - private float _sampleRate; - /// - /// Gets or sets the sample rate. - /// - public float SampleRate + private float _sampleRate; + /// + /// Gets or sets the sample rate. + /// + public float SampleRate + { + get { return _sampleRate; } + set { - get { return _sampleRate; } - set - { - _sampleRate = value; + _sampleRate = value; - // allocate buffer for max delay time - int bufferLength = (int)(_parameters.DelayTimeMgr.ParameterInfo.MaxInteger * _sampleRate / 1000); - _delayBuffer = new float[bufferLength]; + // allocate buffer for max delay time + int bufferLength = (int)(_parameters.DelayTimeMgr.ParameterInfo.MaxInteger * _sampleRate / 1000); + _delayBuffer = new float[bufferLength]; - SetBufferLength(); - } + SetBufferLength(); } + } - /// - /// Processes the using a delay effect. - /// - /// A single sample. - /// Returns the new value for the sample. - public float ProcessSample(float sample) - { - if (_delayBuffer == null) - return sample; - - // process output - float output = (_parameters.DryLevelMgr.CurrentValue * sample) + - (_parameters.WetLevelMgr.CurrentValue * _delayBuffer[_bufferIndex]); + /// + /// Processes the using a delay effect. + /// + /// A single sample. + /// Returns the new value for the sample. + public float ProcessSample(float sample) + { + if (_delayBuffer == null) + return sample; - // process delay buffer - _delayBuffer[_bufferIndex] = sample + - (_parameters.FeedbackMgr.CurrentValue * _delayBuffer[_bufferIndex]); + // process output + float output = (_parameters.DryLevelMgr.CurrentValue * sample) + + (_parameters.WetLevelMgr.CurrentValue * _delayBuffer[_bufferIndex]); - _bufferIndex++; + // process delay buffer + _delayBuffer[_bufferIndex] = sample + + (_parameters.FeedbackMgr.CurrentValue * _delayBuffer[_bufferIndex]); - // manage current buffer position - if (_bufferIndex >= _bufferLength) - { - _bufferIndex = 0; - } + _bufferIndex++; - return output; + // manage current buffer position + if (_bufferIndex >= _bufferLength) + { + _bufferIndex = 0; } + + return output; } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/DelayParameters.cs b/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/DelayParameters.cs index e88b6f57..0c0f93d3 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/DelayParameters.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/Dsp/DelayParameters.cs @@ -1,117 +1,116 @@ using Jacobi.Vst.Core; using Jacobi.Vst.Plugin.Framework; -namespace VstNetAudioPlugin.Dsp +namespace VstNetAudioPlugin.Dsp; + +/// +/// Encapsulated delay parameters. +/// +internal sealed class DelayParameters { + private const string ParameterCategoryName = "Delay"; + /// - /// Encapsulated delay parameters. + /// Initializes the paramaters for the Delay component. /// - internal sealed class DelayParameters + /// + public DelayParameters(PluginParameters parameters) { - private const string ParameterCategoryName = "Delay"; - - /// - /// Initializes the paramaters for the Delay component. - /// - /// - public DelayParameters(PluginParameters parameters) - { - Throw.IfArgumentIsNull(parameters, nameof(parameters)); + Throw.IfArgumentIsNull(parameters, nameof(parameters)); - InitializeParameters(parameters); - } + InitializeParameters(parameters); + } - public VstParameterManager DelayTimeMgr { get; private set; } - public VstParameterManager FeedbackMgr { get; private set; } - public VstParameterManager DryLevelMgr { get; private set; } - public VstParameterManager WetLevelMgr { get; private set; } + public VstParameterManager DelayTimeMgr { get; private set; } + public VstParameterManager FeedbackMgr { get; private set; } + public VstParameterManager DryLevelMgr { get; private set; } + public VstParameterManager WetLevelMgr { get; private set; } - // This method initializes the plugin parameters this Dsp component owns. - private void InitializeParameters(PluginParameters parameters) - { - // all parameter definitions are added to a central list. - VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; + // This method initializes the plugin parameters this Dsp component owns. + private void InitializeParameters(PluginParameters parameters) + { + // all parameter definitions are added to a central list. + VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; - // retrieve the category for all delay parameters. - VstParameterCategory paramCategory = - parameters.GetParameterCategory(ParameterCategoryName); + // retrieve the category for all delay parameters. + VstParameterCategory paramCategory = + parameters.GetParameterCategory(ParameterCategoryName); - // delay time parameter - var paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Time", - Label = "MilSecs", - ShortLabel = "ms", - MinInteger = 0, - MaxInteger = 1000, - LargeStepInteger = 100, - StepInteger = 10, - DefaultValue = 200f - }; - DelayTimeMgr = paramInfo - .Normalize() - .ToManager(); + // delay time parameter + var paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Time", + Label = "MilSecs", + ShortLabel = "ms", + MinInteger = 0, + MaxInteger = 1000, + LargeStepInteger = 100, + StepInteger = 10, + DefaultValue = 200f + }; + DelayTimeMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // feedback parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Feedbck", - Label = "Factor", - ShortLabel = "*", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.4f - }; - FeedbackMgr = paramInfo - .Normalize() - .ToManager(); + // feedback parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Feedbck", + Label = "Factor", + ShortLabel = "*", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.4f + }; + FeedbackMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // dry Level parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Dry Lvl", - Label = "Decibel", - ShortLabel = "Db", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.8f - }; - DryLevelMgr = paramInfo - .Normalize() - .ToManager(); + // dry Level parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Dry Lvl", + Label = "Decibel", + ShortLabel = "Db", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.8f + }; + DryLevelMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); + parameterInfos.Add(paramInfo); - // wet Level parameter - paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Wet Lvl", - Label = "Decibel", - ShortLabel = "Db", - LargeStepFloat = 0.1f, - SmallStepFloat = 0.01f, - StepFloat = 0.05f, - DefaultValue = 0.4f - }; - WetLevelMgr = paramInfo - .Normalize() - .ToManager(); + // wet Level parameter + paramInfo = new VstParameterInfo + { + Category = paramCategory, + CanBeAutomated = true, + Name = "Wet Lvl", + Label = "Decibel", + ShortLabel = "Db", + LargeStepFloat = 0.1f, + SmallStepFloat = 0.01f, + StepFloat = 0.05f, + DefaultValue = 0.4f + }; + WetLevelMgr = paramInfo + .Normalize() + .ToManager(); - parameterInfos.Add(paramInfo); - } + parameterInfos.Add(paramInfo); } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/Plugin.cs b/Source/Templates/CSharp/VstNetAudioPlugin/Plugin.cs index 4846544a..79fdb28a 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/Plugin.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/Plugin.cs @@ -3,66 +3,65 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using Microsoft.Extensions.DependencyInjection; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// The Plugin root object. +/// +internal sealed class Plugin : VstPluginWithServices { /// - /// The Plugin root object. + /// TODO: assign a unique plugin id. /// - internal sealed class Plugin : VstPluginWithServices - { - /// - /// TODO: assign a unique plugin id. - /// - private static readonly int UniquePluginId = new FourCharacterCode("1234").ToInt32(); - /// - /// TODO: assign a plugin name. - /// - private const string PluginName = "MyAudioPluginName"; - /// - /// TODO: assign a product name. - /// - private const string ProductName = "MyProduct"; - /// - /// TODO: assign a vendor name. - /// - private const string VendorName = "MyVendor"; - /// - /// TODO: assign a plugin version. - /// - private const int PluginVersion = 0000; - /// - /// TODO: what type of plugin are your making? - /// - private const VstPluginCategory PluginCategory = VstPluginCategory.RoomFx; - /// - /// TODO: what can your plugin do? - /// - private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.ReceiveTimeInfo; - /// - /// The number of samples your plugin lags behind. - /// - private const int InitialDelayInSamples = 0; + private static readonly int UniquePluginId = new FourCharacterCode("1234").ToInt32(); + /// + /// TODO: assign a plugin name. + /// + private const string PluginName = "MyAudioPluginName"; + /// + /// TODO: assign a product name. + /// + private const string ProductName = "MyProduct"; + /// + /// TODO: assign a vendor name. + /// + private const string VendorName = "MyVendor"; + /// + /// TODO: assign a plugin version. + /// + private const int PluginVersion = 0000; + /// + /// TODO: what type of plugin are your making? + /// + private const VstPluginCategory PluginCategory = VstPluginCategory.RoomFx; + /// + /// TODO: what can your plugin do? + /// + private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.ReceiveTimeInfo; + /// + /// The number of samples your plugin lags behind. + /// + private const int InitialDelayInSamples = 0; - /// - /// Initializes the one an only instance of the Plugin root object. - /// - public Plugin() - : base(PluginName, UniquePluginId, - new VstProductInfo(ProductName, VendorName, PluginVersion), - PluginCategory, InitialDelayInSamples, PluginCapabilities) - { } + /// + /// Initializes the one an only instance of the Plugin root object. + /// + public Plugin() + : base(PluginName, UniquePluginId, + new VstProductInfo(ProductName, VendorName, PluginVersion), + PluginCategory, InitialDelayInSamples, PluginCapabilities) + { } - /// - /// Called once to get all the plugin components. - /// Add components for the IVstXxxx interfaces you want to support. - /// - /// Is never null. - protected override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll(); - } + /// + /// Called once to get all the plugin components. + /// Add components for the IVstXxxx interfaces you want to support. + /// + /// Is never null. + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll(); } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/PluginCommandStub.cs b/Source/Templates/CSharp/VstNetAudioPlugin/PluginCommandStub.cs index a8e76079..a3c9fa47 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/PluginCommandStub.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/PluginCommandStub.cs @@ -1,27 +1,26 @@ using Jacobi.Vst.Plugin.Framework; using Jacobi.Vst.Plugin.Framework.Plugin; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// This object receives all calls from the (unmanaged) host. +/// +/// +/// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly +/// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ +/// to this object. +/// +public class PluginCommandStub : StdPluginCommandStub { /// - /// This object receives all calls from the (unmanaged) host. + /// Returns an instance of the VST.NET Plugin root object. /// - /// - /// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly - /// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ - /// to this object. - /// - public class PluginCommandStub : StdPluginCommandStub + /// Must never return null. + protected override IVstPlugin CreatePluginInstance() { - /// - /// Returns an instance of the VST.NET Plugin root object. - /// - /// Must never return null. - protected override IVstPlugin CreatePluginInstance() - { - // StdPluginCommandStub implements all the VST2 methods, - // all you have to do is give the Framework your plugin root. - return new Plugin(); - } + // StdPluginCommandStub implements all the VST2 methods, + // all you have to do is give the Framework your plugin root. + return new Plugin(); } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/PluginEditor.cs b/Source/Templates/CSharp/VstNetAudioPlugin/PluginEditor.cs index 1c7a6118..a93d28d9 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/PluginEditor.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/PluginEditor.cs @@ -6,67 +6,66 @@ using System.Linq; using VstNetAudioPlugin.UI; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// This object manages the custom editor (UI) for your plugin. +/// +/// +/// When you do not implement a custom editor, +/// your Parameters will be displayed in an editor provided by the host. +/// +internal sealed class PluginEditor : IVstPluginEditor { - /// - /// This object manages the custom editor (UI) for your plugin. - /// - /// - /// When you do not implement a custom editor, - /// your Parameters will be displayed in an editor provided by the host. - /// - internal sealed class PluginEditor : IVstPluginEditor - { - private readonly PluginParameters _parameters; - private readonly WinFormsControlWrapper _view; + private readonly PluginParameters _parameters; + private readonly WinFormsControlWrapper _view; - public PluginEditor(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - _view = new WinFormsControlWrapper(); - } + public PluginEditor(PluginParameters parameters) + { + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + _view = new WinFormsControlWrapper(); + } - public Rectangle Bounds - { - get { return _view.Bounds; } - } + public Rectangle Bounds + { + get { return _view.Bounds; } + } - public void Close() - { - _view.Close(); - } + public void Close() + { + _view.Close(); + } - public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public VstKnobMode KnobMode { get; set; } + public VstKnobMode KnobMode { get; set; } - public void Open(IntPtr hWnd) - { - // make a list of parameters to pass to the dlg. - var paramList = _parameters.ParameterInfos - .Where(p => p.ParameterManager != null) - .Select(p => p.ParameterManager!) - .ToList(); + public void Open(IntPtr hWnd) + { + // make a list of parameters to pass to the dlg. + var paramList = _parameters.ParameterInfos + .Where(p => p.ParameterManager != null) + .Select(p => p.ParameterManager!) + .ToList(); - _view.SafeInstance.InitializeParameters(paramList); + _view.SafeInstance.InitializeParameters(paramList); - _view.Open(hWnd); - } + _view.Open(hWnd); + } - public void ProcessIdle() - { - // keep your processing short! - _view.SafeInstance.ProcessIdle(); - } + public void ProcessIdle() + { + // keep your processing short! + _view.SafeInstance.ProcessIdle(); } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/PluginParameters.cs b/Source/Templates/CSharp/VstNetAudioPlugin/PluginParameters.cs index 4c669770..2971ca1c 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/PluginParameters.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/PluginParameters.cs @@ -3,77 +3,76 @@ using System.Linq; using VstNetAudioPlugin.Dsp; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// A central location for all plugin parameters +/// +internal sealed class PluginParameters { /// - /// A central location for all plugin parameters + /// Initializes all plugin parameters (one component at a time). /// - internal sealed class PluginParameters + public PluginParameters(IVstPluginEvents pluginEvents) { - /// - /// Initializes all plugin parameters (one component at a time). - /// - public PluginParameters(IVstPluginEvents pluginEvents) - { - // register the parameters of all plugin (sub) components - DelayParameters = new DelayParameters(this); + // register the parameters of all plugin (sub) components + DelayParameters = new DelayParameters(this); - pluginEvents.Opened += Plugin_Opened; - } + pluginEvents.Opened += Plugin_Opened; + } - private void Plugin_Opened(object? sender, System.EventArgs e) - { - var plugin = (VstPlugin?)sender; - SetHostAutomation(plugin?.Host?.GetInstance()); - } + private void Plugin_Opened(object? sender, System.EventArgs e) + { + var plugin = (VstPlugin?)sender; + SetHostAutomation(plugin?.Host?.GetInstance()); + } - public DelayParameters DelayParameters { get; private set; } + public DelayParameters DelayParameters { get; private set; } - /// - /// Gets the central list of parameter categories. - /// - public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); + /// + /// Gets the central list of parameter categories. + /// + public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); - /// - /// Gets the central list of parameter definitions. - /// - public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); + /// + /// Gets the central list of parameter definitions. + /// + public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); - /// - /// Retrieves a parameter category object for the specified . - /// - /// The name of the parameter category. - /// Typically the name of a Dsp component, an effect or function. - /// Never returns null. - public VstParameterCategory GetParameterCategory(string categoryName) + /// + /// Retrieves a parameter category object for the specified . + /// + /// The name of the parameter category. + /// Typically the name of a Dsp component, an effect or function. + /// Never returns null. + public VstParameterCategory GetParameterCategory(string categoryName) + { + if (Categories.Contains(categoryName)) { - if (Categories.Contains(categoryName)) - { - return Categories[categoryName]; - } + return Categories[categoryName]; + } - // create a new parameter category object - var paramCategory = new VstParameterCategory - { - Name = categoryName - }; + // create a new parameter category object + var paramCategory = new VstParameterCategory + { + Name = categoryName + }; - Categories.Add(paramCategory); + Categories.Add(paramCategory); - return paramCategory; - } + return paramCategory; + } - /// - /// Assigns the to all s. - /// - /// - private void SetHostAutomation(IVstHostAutomation? hostAutomation) + /// + /// Assigns the to all s. + /// + /// + private void SetHostAutomation(IVstHostAutomation? hostAutomation) + { + foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) { - foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) - { - if (paramMgr != null) - paramMgr.HostAutomation = hostAutomation; - } + if (paramMgr != null) + paramMgr.HostAutomation = hostAutomation; } } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/PluginPrograms.cs b/Source/Templates/CSharp/VstNetAudioPlugin/PluginPrograms.cs index f038fded..a92965fb 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/PluginPrograms.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/PluginPrograms.cs @@ -2,71 +2,70 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using System; -namespace VstNetAudioPlugin +namespace VstNetAudioPlugin; + +/// +/// This object manages the Plugin programs and its parameters. +/// +internal sealed class PluginPrograms : VstPluginPrograms { + private readonly PluginParameters _parameters; + /// - /// This object manages the Plugin programs and its parameters. + /// Constructs an instance on the plugin parameter factory /// - internal sealed class PluginPrograms : VstPluginPrograms + /// Must not be null. + public PluginPrograms(PluginParameters parameters) { - private readonly PluginParameters _parameters; - - /// - /// Constructs an instance on the plugin parameter factory - /// - /// Must not be null. - public PluginPrograms(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - } + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + } - /// - /// Called to initialize the collection of programs for the plugin. - /// - /// Never returns null or an empty collection. - protected override VstProgramCollection CreateProgramCollection() - { - var programs = new VstProgramCollection(); + /// + /// Called to initialize the collection of programs for the plugin. + /// + /// Never returns null or an empty collection. + protected override VstProgramCollection CreateProgramCollection() + { + var programs = new VstProgramCollection(); - // TODO: add a number of programs for your plugin. + // TODO: add a number of programs for your plugin. - var program = CreateProgram("Default"); - programs.Add(program); + var program = CreateProgram("Default"); + programs.Add(program); - return programs; - } + return programs; + } - private VstProgram CreateProgram(string name) - { - var program = CreateProgram(); - program.Name = name; - return program; - } + private VstProgram CreateProgram(string name) + { + var program = CreateProgram(); + program.Name = name; + return program; + } - // create a program with all parameters. - private VstProgram CreateProgram() - { - var program = new VstProgram(_parameters.Categories); + // create a program with all parameters. + private VstProgram CreateProgram() + { + var program = new VstProgram(_parameters.Categories); - CreateParameters(program.Parameters, _parameters.ParameterInfos); + CreateParameters(program.Parameters, _parameters.ParameterInfos); - return program; - } + return program; + } - // create all parameters - private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + // create all parameters + private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + { + foreach (VstParameterInfo paramInfo in parameterInfos) { - foreach (VstParameterInfo paramInfo in parameterInfos) - { - desitnation.Add(CreateParameter(paramInfo)); - } + desitnation.Add(CreateParameter(paramInfo)); } + } - // create one parameter - private VstParameter CreateParameter(VstParameterInfo parameterInfo) - { - // Advanced: you can derive from VstParameter and add your own properties and logic. - return new VstParameter(parameterInfo); - } + // create one parameter + private VstParameter CreateParameter(VstParameterInfo parameterInfo) + { + // Advanced: you can derive from VstParameter and add your own properties and logic. + return new VstParameter(parameterInfo); } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/UI/PluginEditorView.cs b/Source/Templates/CSharp/VstNetAudioPlugin/UI/PluginEditorView.cs index 0ce6f06b..fcfd9bf3 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/UI/PluginEditorView.cs +++ b/Source/Templates/CSharp/VstNetAudioPlugin/UI/PluginEditorView.cs @@ -2,121 +2,120 @@ using System.Collections.Generic; using System.Windows.Forms; -namespace VstNetAudioPlugin.UI +namespace VstNetAudioPlugin.UI; + +public partial class PluginEditorView : UserControl { - public partial class PluginEditorView : UserControl + public PluginEditorView() { - public PluginEditorView() - { - InitializeComponent(); - } - - internal bool InitializeParameters(IList parameters) - { - if (parameters == null || parameters.Count < 4) - return false; - - BindParameter(parameters[0], label1, trackBar1, label5); - BindParameter(parameters[1], label2, trackBar2, label6); - BindParameter(parameters[2], label3, trackBar3, label7); - BindParameter(parameters[3], label4, trackBar4, label8); - - return true; - } + InitializeComponent(); + } - private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) - { - label.Text = paramMgr.ParameterInfo.Name; - shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; + internal bool InitializeParameters(IList parameters) + { + if (parameters == null || parameters.Count < 4) + return false; - var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); - var paramState = new ParameterControlState(paramMgr, factor); + BindParameter(parameters[0], label1, trackBar1, label5); + BindParameter(parameters[1], label2, trackBar2, label6); + BindParameter(parameters[2], label3, trackBar3, label7); + BindParameter(parameters[3], label4, trackBar4, label8); - // use databinding for VstParameter/Manager changed notifications. - trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); - trackBar.ValueChanged += TrackBar_ValueChanged; - trackBar.Tag = paramState; - } + return true; + } - private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) - { - // A multiplication factor to convert floats (0.0-1.0) - // to an integer range for the TrackBar to work with. - float factor = 1.0f; + private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) + { + label.Text = paramMgr.ParameterInfo.Name; + shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; - if (parameterInfo.IsSwitch) - { - trackBar.Minimum = 0; - trackBar.Maximum = 1; - trackBar.LargeChange = 1; - trackBar.SmallChange = 1; - return factor; - } + var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); + var paramState = new ParameterControlState(paramMgr, factor); - if (parameterInfo.IsStepIntegerValid) - { - trackBar.LargeChange = parameterInfo.LargeStepInteger; - trackBar.SmallChange = parameterInfo.StepInteger; - } - else if (parameterInfo.IsStepFloatValid) - { - factor = 1 / parameterInfo.StepFloat; - trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); - trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); - } + // use databinding for VstParameter/Manager changed notifications. + trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); + trackBar.ValueChanged += TrackBar_ValueChanged; + trackBar.Tag = paramState; + } - if (parameterInfo.IsMinMaxIntegerValid) - { - trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); - trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); - } - else - { - trackBar.Minimum = 0; - trackBar.Maximum = (int)factor; - } + private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) + { + // A multiplication factor to convert floats (0.0-1.0) + // to an integer range for the TrackBar to work with. + float factor = 1.0f; + if (parameterInfo.IsSwitch) + { + trackBar.Minimum = 0; + trackBar.Maximum = 1; + trackBar.LargeChange = 1; + trackBar.SmallChange = 1; return factor; } - private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + if (parameterInfo.IsStepIntegerValid) { - var trackBar = (TrackBar?)sender; - var paramState = (ParameterControlState?)trackBar?.Tag; + trackBar.LargeChange = parameterInfo.LargeStepInteger; + trackBar.SmallChange = parameterInfo.StepInteger; + } + else if (parameterInfo.IsStepFloatValid) + { + factor = 1 / parameterInfo.StepFloat; + trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); + trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); + } - if (trackBar != null && - paramState?.ParameterManager.ActiveParameter != null) - { - paramState.ParameterManager.ActiveParameter.Value = - trackBar.Value / paramState.ValueFactor; - } + if (parameterInfo.IsMinMaxIntegerValid) + { + trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); + trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); } + else + { + trackBar.Minimum = 0; + trackBar.Maximum = (int)factor; + } + + return factor; + } + + private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + { + var trackBar = (TrackBar?)sender; + var paramState = (ParameterControlState?)trackBar?.Tag; - internal void ProcessIdle() + if (trackBar != null && + paramState?.ParameterManager.ActiveParameter != null) { - // TODO: short idle processing here + paramState.ParameterManager.ActiveParameter.Value = + trackBar.Value / paramState.ValueFactor; } + } + + internal void ProcessIdle() + { + // TODO: short idle processing here + } - /// - /// This class converts the parameter value range to a compatible (integer) TrackBar value range. - /// - private sealed class ParameterControlState + /// + /// This class converts the parameter value range to a compatible (integer) TrackBar value range. + /// + private sealed class ParameterControlState + { + public ParameterControlState(VstParameterManager parameterManager, float valueFactor) { - public ParameterControlState(VstParameterManager parameterManager, float valueFactor) - { - ParameterManager = parameterManager; - ValueFactor = valueFactor; - } + ParameterManager = parameterManager; + ValueFactor = valueFactor; + } - public VstParameterManager ParameterManager { get; } - public float ValueFactor { get; } + public VstParameterManager ParameterManager { get; } + public float ValueFactor { get; } - public int Value + public int Value + { + get { - get - { - return (int)(ParameterManager.CurrentValue * ValueFactor); - } + return (int)(ParameterManager.CurrentValue * ValueFactor); } } } diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.csproj b/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.csproj index 43f31be0..b391d15c 100644 --- a/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.csproj +++ b/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0-windows x64;x86 enable @@ -10,9 +10,9 @@ - + - + diff --git a/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.zip b/Source/Templates/CSharp/VstNetAudioPlugin/VstNetAudioPlugin.zip index d9e1903ee00fa9f0b248f6a815d198b49d39931f..87e919fdd9a4d3a60eda96dae9f5abc5e47aa86d 100644 GIT binary patch delta 8926 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 azWLYsd`V>y{HwwP2$~!dJihdw!v6#7keI{( diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/AudioProcessor.cs b/Source/Templates/CSharp/VstNetMidiPlugin/AudioProcessor.cs index c8c8f588..c8dbb33e 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/AudioProcessor.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/AudioProcessor.cs @@ -2,44 +2,43 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using System; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// This object is a dummy AudioProcessor only to be able to output Midi during the Audio processing cycle. +/// +internal sealed class AudioProcessor : VstPluginAudioProcessor { + // TODO: set some defaults + private const int AudioInputCount = 2; + private const int AudioOutputCount = 2; + private const int InitialTailSize = 0; + + private readonly MidiProcessor _midiProcessor; + /// - /// This object is a dummy AudioProcessor only to be able to output Midi during the Audio processing cycle. + /// Default constructor. /// - internal sealed class AudioProcessor : VstPluginAudioProcessor + public AudioProcessor(MidiProcessor midiProcessor) + : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: true) { - // TODO: set some defaults - private const int AudioInputCount = 2; - private const int AudioOutputCount = 2; - private const int InitialTailSize = 0; - - private readonly MidiProcessor _midiProcessor; + _midiProcessor = midiProcessor ?? throw new ArgumentNullException(nameof(midiProcessor)); + } - /// - /// Default constructor. - /// - public AudioProcessor(MidiProcessor midiProcessor) - : base(AudioInputCount, AudioOutputCount, InitialTailSize, noSoundInStop: true) - { - _midiProcessor = midiProcessor ?? throw new ArgumentNullException(nameof(midiProcessor)); - } + /// + /// Called by the host to allow the plugin to process audio samples. + /// + /// Never null. + /// Never null. + public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + { + // calling the base class transfers input samples to the output channels unchanged (bypass). + base.Process(inChannels, outChannels); - /// - /// Called by the host to allow the plugin to process audio samples. - /// - /// Never null. - /// Never null. - public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels) + // check to see if we need to output midi here + if (_midiProcessor.SyncWithAudioProcessor) { - // calling the base class transfers input samples to the output channels unchanged (bypass). - base.Process(inChannels, outChannels); - - // check to see if we need to output midi here - if (_midiProcessor.SyncWithAudioProcessor) - { - _midiProcessor.ProcessCurrentEvents(); - } + _midiProcessor.ProcessCurrentEvents(); } } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Gain.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Gain.cs index d1620e78..57450f36 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Gain.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Gain.cs @@ -1,50 +1,49 @@ using Jacobi.Vst.Core; using System; -namespace VstNetMidiPlugin.Dmp +namespace VstNetMidiPlugin.Dmp; + +/// +/// Change the velocity of MIDI notes. +/// +internal sealed class Gain { - /// - /// Change the velocity of MIDI notes. - /// - internal sealed class Gain + private readonly GainParameters _parameters; + + public Gain(GainParameters parameters) { - private readonly GainParameters _parameters; + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + } - public Gain(GainParameters parameters) + public VstMidiEvent ProcessEvent(VstMidiEvent inEvent) + { + if (!MidiHelper.IsNoteOff(inEvent.Data) && + !MidiHelper.IsNoteOn(inEvent.Data)) { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + return inEvent; } - public VstMidiEvent ProcessEvent(VstMidiEvent inEvent) + byte[] outData = new byte[4]; + inEvent.Data.CopyTo(outData, 0); + + outData[2] += (byte)_parameters.GainMgr.CurrentValue; + + if (outData[2] > 127) { - if (!MidiHelper.IsNoteOff(inEvent.Data) && - !MidiHelper.IsNoteOn(inEvent.Data)) - { - return inEvent; - } - - byte[] outData = new byte[4]; - inEvent.Data.CopyTo(outData, 0); - - outData[2] += (byte)_parameters.GainMgr.CurrentValue; - - if (outData[2] > 127) - { - outData[2] = 127; - } - - if (outData[2] < 0) - { - outData[2] = 0; - } - - // MidiEvents are immutable, - // so we create a new object for the new data. - VstMidiEvent outEvent = new VstMidiEvent( - inEvent.DeltaFrames, inEvent.NoteLength, inEvent.NoteOffset, - outData, inEvent.Detune, inEvent.NoteOffVelocity); - - return outEvent; + outData[2] = 127; } + + if (outData[2] < 0) + { + outData[2] = 0; + } + + // MidiEvents are immutable, + // so we create a new object for the new data. + VstMidiEvent outEvent = new VstMidiEvent( + inEvent.DeltaFrames, inEvent.NoteLength, inEvent.NoteOffset, + outData, inEvent.Detune, inEvent.NoteOffVelocity); + + return outEvent; } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/GainParameters.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/GainParameters.cs index 1f65971b..c34150c6 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/GainParameters.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/GainParameters.cs @@ -1,48 +1,47 @@ using Jacobi.Vst.Plugin.Framework; -namespace VstNetMidiPlugin.Dmp +namespace VstNetMidiPlugin.Dmp; + +internal sealed class GainParameters { - internal sealed class GainParameters + private const string ParameterCategoryName = "Gain"; + + public GainParameters(PluginParameters parameters) { - private const string ParameterCategoryName = "Gain"; + InitializeParameters(parameters); + } - public GainParameters(PluginParameters parameters) - { - InitializeParameters(parameters); - } + private void InitializeParameters(PluginParameters parameters) + { + // all parameter definitions are added to a central list. + VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; + + // retrieve the category for all delay parameters. + VstParameterCategory paramCategory = + parameters.GetParameterCategory(ParameterCategoryName); - private void InitializeParameters(PluginParameters parameters) + // delay time parameter + var paramInfo = new VstParameterInfo { - // all parameter definitions are added to a central list. - VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; - - // retrieve the category for all delay parameters. - VstParameterCategory paramCategory = - parameters.GetParameterCategory(ParameterCategoryName); - - // delay time parameter - var paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Gain", - Label = "Db", - ShortLabel = "Db", - MinInteger = -100, - MaxInteger = 100, - LargeStepFloat = 20.0f, - SmallStepFloat = 1.0f, - StepFloat = 10.0f, - DefaultValue = 0.0f - }; - - GainMgr = paramInfo - .Normalize() - .ToManager(); - - parameterInfos.Add(paramInfo); - } - - public VstParameterManager GainMgr { get; private set; } + Category = paramCategory, + CanBeAutomated = true, + Name = "Gain", + Label = "Db", + ShortLabel = "Db", + MinInteger = -100, + MaxInteger = 100, + LargeStepFloat = 20.0f, + SmallStepFloat = 1.0f, + StepFloat = 10.0f, + DefaultValue = 0.0f + }; + + GainMgr = paramInfo + .Normalize() + .ToManager(); + + parameterInfos.Add(paramInfo); } + + public VstParameterManager GainMgr { get; private set; } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/MidiHelper.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/MidiHelper.cs index 73da9e39..23f77f09 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/MidiHelper.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/MidiHelper.cs @@ -1,25 +1,24 @@ -namespace VstNetMidiPlugin.Dmp +namespace VstNetMidiPlugin.Dmp; + +internal static class MidiHelper { - internal static class MidiHelper + public static bool IsNoteOn(byte[] dataBuffer) { - public static bool IsNoteOn(byte[] dataBuffer) - { - return IsNoteOn(dataBuffer[0]); - } + return IsNoteOn(dataBuffer[0]); + } - public static bool IsNoteOn(byte data) - { - return ((data & 0xF0) == 0x90); - } + public static bool IsNoteOn(byte data) + { + return ((data & 0xF0) == 0x90); + } - public static bool IsNoteOff(byte[] dataBuffer) - { - return IsNoteOff(dataBuffer[0]); - } + public static bool IsNoteOff(byte[] dataBuffer) + { + return IsNoteOff(dataBuffer[0]); + } - public static bool IsNoteOff(byte data) - { - return ((data & 0xF0) == 0x80); - } + public static bool IsNoteOff(byte data) + { + return ((data & 0xF0) == 0x80); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Transpose.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Transpose.cs index 43cf09b4..a27a5e10 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Transpose.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/Transpose.cs @@ -1,47 +1,46 @@ using Jacobi.Vst.Core; using System; -namespace VstNetMidiPlugin.Dmp +namespace VstNetMidiPlugin.Dmp; + +/// +/// Change the Note Number of MIDI notes. +/// +internal sealed class Transpose { - /// - /// Change the Note Number of MIDI notes. - /// - internal sealed class Transpose + private readonly TransposeParameters _parameters; + + public Transpose(TransposeParameters parameters) + { + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + } + + public VstMidiEvent ProcessEvent(VstMidiEvent inEvent) { - private readonly TransposeParameters _parameters; + if (!MidiHelper.IsNoteOff(inEvent.Data) && !MidiHelper.IsNoteOn(inEvent.Data)) + { + return inEvent; + } + + byte[] outData = new byte[4]; + inEvent.Data.CopyTo(outData, 0); - public Transpose(TransposeParameters parameters) + outData[1] += (byte)_parameters.TransposeMgr.CurrentValue; + + if (outData[1] > 127) { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + outData[1] = 127; } - public VstMidiEvent ProcessEvent(VstMidiEvent inEvent) + if (outData[1] < 0) { - if (!MidiHelper.IsNoteOff(inEvent.Data) && !MidiHelper.IsNoteOn(inEvent.Data)) - { - return inEvent; - } - - byte[] outData = new byte[4]; - inEvent.Data.CopyTo(outData, 0); - - outData[1] += (byte)_parameters.TransposeMgr.CurrentValue; - - if (outData[1] > 127) - { - outData[1] = 127; - } - - if (outData[1] < 0) - { - outData[1] = 0; - } - - // MidiEvents are immutable, - // so we create a new object for the new data. - return new VstMidiEvent( - inEvent.DeltaFrames, inEvent.NoteLength, inEvent.NoteOffset, - outData, inEvent.Detune, inEvent.NoteOffVelocity); + outData[1] = 0; } + + // MidiEvents are immutable, + // so we create a new object for the new data. + return new VstMidiEvent( + inEvent.DeltaFrames, inEvent.NoteLength, inEvent.NoteOffset, + outData, inEvent.Detune, inEvent.NoteOffVelocity); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/TransposeParameters.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/TransposeParameters.cs index 3729931c..0cf63b44 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/TransposeParameters.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Dmp/TransposeParameters.cs @@ -1,48 +1,47 @@ using Jacobi.Vst.Plugin.Framework; -namespace VstNetMidiPlugin.Dmp +namespace VstNetMidiPlugin.Dmp; + +internal sealed class TransposeParameters { - internal sealed class TransposeParameters + private const string ParameterCategoryName = "Transpose"; + + public TransposeParameters(PluginParameters parameters) { - private const string ParameterCategoryName = "Transpose"; + InitializeParameters(parameters); + } - public TransposeParameters(PluginParameters parameters) - { - InitializeParameters(parameters); - } + public VstParameterManager TransposeMgr { get; private set; } + + private void InitializeParameters(PluginParameters parameters) + { + // all parameter definitions are added to a central list. + VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; - public VstParameterManager TransposeMgr { get; private set; } + // retrieve the category for all delay parameters. + VstParameterCategory paramCategory = + parameters.GetParameterCategory(ParameterCategoryName); - private void InitializeParameters(PluginParameters parameters) + // delay time parameter + var paramInfo = new VstParameterInfo { - // all parameter definitions are added to a central list. - VstParameterInfoCollection parameterInfos = parameters.ParameterInfos; - - // retrieve the category for all delay parameters. - VstParameterCategory paramCategory = - parameters.GetParameterCategory(ParameterCategoryName); - - // delay time parameter - var paramInfo = new VstParameterInfo - { - Category = paramCategory, - CanBeAutomated = true, - Name = "Transp.", - Label = "Halfs", - ShortLabel = "#", - MinInteger = -100, - MaxInteger = 100, - LargeStepFloat = 5.0f, - SmallStepFloat = 1.0f, - StepFloat = 2.0f, - DefaultValue = 0.0f - }; - - TransposeMgr = paramInfo - .Normalize() - .ToManager(); - - parameterInfos.Add(paramInfo); - } + Category = paramCategory, + CanBeAutomated = true, + Name = "Transp.", + Label = "Halfs", + ShortLabel = "#", + MinInteger = -100, + MaxInteger = 100, + LargeStepFloat = 5.0f, + SmallStepFloat = 1.0f, + StepFloat = 2.0f, + DefaultValue = 0.0f + }; + + TransposeMgr = paramInfo + .Normalize() + .ToManager(); + + parameterInfos.Add(paramInfo); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/MidiProcessor.cs b/Source/Templates/CSharp/VstNetMidiPlugin/MidiProcessor.cs index a9228d5f..26c83cd3 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/MidiProcessor.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/MidiProcessor.cs @@ -3,120 +3,119 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using VstNetMidiPlugin.Dmp; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// This object performs midi processing for your plugin. +/// +internal sealed class MidiProcessor : IVstMidiProcessor, IVstPluginMidiSource { + private IVstMidiProcessor? _midiHost; + /// - /// This object performs midi processing for your plugin. + /// Constructs a new Midi Processor. /// - internal sealed class MidiProcessor : IVstMidiProcessor, IVstPluginMidiSource + /// Must not be null. + public MidiProcessor(IVstPluginEvents pluginEvents, PluginParameters parameters) { - private IVstMidiProcessor? _midiHost; + Gain = new Gain(parameters.GainParameters); + Transpose = new Transpose(parameters.TransposeParameters); - /// - /// Constructs a new Midi Processor. - /// - /// Must not be null. - public MidiProcessor(IVstPluginEvents pluginEvents, PluginParameters parameters) - { - Gain = new Gain(parameters.GainParameters); - Transpose = new Transpose(parameters.TransposeParameters); + // for most hosts, midi output is expected during the audio processing cycle. + SyncWithAudioProcessor = true; - // for most hosts, midi output is expected during the audio processing cycle. - SyncWithAudioProcessor = true; + pluginEvents.Opened += Plugin_Opened; + } - pluginEvents.Opened += Plugin_Opened; - } + private void Plugin_Opened(object? sender, System.EventArgs e) + { + var plugin = (VstPlugin?)sender; - private void Plugin_Opened(object? sender, System.EventArgs e) - { - var plugin = (VstPlugin?)sender; + // a plugin must implement IVstPluginMidiSource or this call will throw an exception. + _midiHost = plugin?.Host?.GetInstance(); + } - // a plugin must implement IVstPluginMidiSource or this call will throw an exception. - _midiHost = plugin?.Host?.GetInstance(); - } + internal Gain Gain { get; private set; } + internal Transpose Transpose { get; private set; } - internal Gain Gain { get; private set; } - internal Transpose Transpose { get; private set; } + /// + /// Gets or sets a value indicating to sync with audio processing. + /// + /// + /// False: will output midi to the host in the MidiProcessor. + /// True: will output midi to the host in the AudioProcessor. + /// + public bool SyncWithAudioProcessor { get; set; } - /// - /// Gets or sets a value indicating to sync with audio processing. - /// - /// - /// False: will output midi to the host in the MidiProcessor. - /// True: will output midi to the host in the AudioProcessor. - /// - public bool SyncWithAudioProcessor { get; set; } + public int ChannelCount + { + get { return 16; } + } - public int ChannelCount - { - get { return 16; } - } + /// + /// Midi events are received from the host on this method. + /// + /// A collection with midi events. Never null. + /// + /// Note that some hosts will only receieve midi events during audio processing. + /// See also . + /// + public void Process(VstEventCollection events) + { + CurrentEvents = events; - /// - /// Midi events are received from the host on this method. - /// - /// A collection with midi events. Never null. - /// - /// Note that some hosts will only receieve midi events during audio processing. - /// See also . - /// - public void Process(VstEventCollection events) + if (!SyncWithAudioProcessor) { - CurrentEvents = events; - - if (!SyncWithAudioProcessor) - { - ProcessCurrentEvents(); - } + ProcessCurrentEvents(); } + } - // cache of events (for when syncing up with the AudioProcessor). - public VstEventCollection? CurrentEvents { get; private set; } + // cache of events (for when syncing up with the AudioProcessor). + public VstEventCollection? CurrentEvents { get; private set; } + + public void ProcessCurrentEvents() + { + if (CurrentEvents == null || CurrentEvents.Count == 0) + return; - public void ProcessCurrentEvents() + // always expect some hosts not to support this. + if (_midiHost != null) { - if (CurrentEvents == null || CurrentEvents.Count == 0) - return; + VstEventCollection outEvents = new VstEventCollection(); - // always expect some hosts not to support this. - if (_midiHost != null) + // NOTE: other types of events could be in the collection! + foreach (VstEvent evnt in CurrentEvents) { - VstEventCollection outEvents = new VstEventCollection(); - - // NOTE: other types of events could be in the collection! - foreach (VstEvent evnt in CurrentEvents) + switch (evnt.EventType) { - switch (evnt.EventType) - { - case VstEventTypes.MidiEvent: - VstMidiEvent midiEvent = (VstMidiEvent)evnt; - - midiEvent = Gain.ProcessEvent(midiEvent); - midiEvent = Transpose.ProcessEvent(midiEvent); - - outEvents.Add(midiEvent); - break; - default: - // non VstMidiEvent - outEvents.Add(evnt); - break; - } + case VstEventTypes.MidiEvent: + VstMidiEvent midiEvent = (VstMidiEvent)evnt; + + midiEvent = Gain.ProcessEvent(midiEvent); + midiEvent = Transpose.ProcessEvent(midiEvent); + + outEvents.Add(midiEvent); + break; + default: + // non VstMidiEvent + outEvents.Add(evnt); + break; } - - _midiHost.Process(outEvents); } - // Clear the cache, we've processed the events. - CurrentEvents = null; + _midiHost.Process(outEvents); } - #region IVstPluginMidiSource Members + // Clear the cache, we've processed the events. + CurrentEvents = null; + } - int IVstPluginMidiSource.ChannelCount - { - get { return 16; } - } + #region IVstPluginMidiSource Members - #endregion + int IVstPluginMidiSource.ChannelCount + { + get { return 16; } } + + #endregion } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/Plugin.cs b/Source/Templates/CSharp/VstNetMidiPlugin/Plugin.cs index d2fd6f3b..fe09b671 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/Plugin.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/Plugin.cs @@ -3,67 +3,66 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using Microsoft.Extensions.DependencyInjection; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// The Plugin root object. +/// +internal sealed class Plugin : VstPluginWithServices { /// - /// The Plugin root object. + /// TODO: assign a unique plugin. /// - internal sealed class Plugin : VstPluginWithServices - { - /// - /// TODO: assign a unique plugin. - /// - private static readonly int UniquePluginId = new FourCharacterCode("2345").ToInt32(); - /// - /// TODO: assign a plugin name. - /// - private const string PluginName = "MyMidiPluginName"; - /// - /// TODO: assign a product name. - /// - private const string ProductName = "MyProduct"; - /// - /// TODO: assign a vendor name. - /// - private const string VendorName = "MyVendor"; - /// - /// TODO: assign a plugin version. - /// - private const int PluginVersion = 0000; - /// - /// TODO: what type of plugin are your making? - /// - private const VstPluginCategory PluginCategory = VstPluginCategory.Effect; - /// - /// TODO: what can your plugin do? - /// - private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.None; - /// - /// The number of samples your plugin lags behind. - /// - private const int InitialDelayInSamples = 0; + private static readonly int UniquePluginId = new FourCharacterCode("2345").ToInt32(); + /// + /// TODO: assign a plugin name. + /// + private const string PluginName = "MyMidiPluginName"; + /// + /// TODO: assign a product name. + /// + private const string ProductName = "MyProduct"; + /// + /// TODO: assign a vendor name. + /// + private const string VendorName = "MyVendor"; + /// + /// TODO: assign a plugin version. + /// + private const int PluginVersion = 0000; + /// + /// TODO: what type of plugin are your making? + /// + private const VstPluginCategory PluginCategory = VstPluginCategory.Effect; + /// + /// TODO: what can your plugin do? + /// + private const VstPluginCapabilities PluginCapabilities = VstPluginCapabilities.None; + /// + /// The number of samples your plugin lags behind. + /// + private const int InitialDelayInSamples = 0; - /// - /// Initializes the one an only instance of the Plugin root object. - /// - public Plugin() - : base(PluginName, UniquePluginId, - new VstProductInfo(ProductName, VendorName, PluginVersion), - PluginCategory, InitialDelayInSamples, PluginCapabilities) - { } + /// + /// Initializes the one an only instance of the Plugin root object. + /// + public Plugin() + : base(PluginName, UniquePluginId, + new VstProductInfo(ProductName, VendorName, PluginVersion), + PluginCategory, InitialDelayInSamples, PluginCapabilities) + { } - /// - /// Called once to get all the plugin components. - /// Add components for the IVstXxxx interfaces you want to support. - /// - /// Is never null. - protected override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll() - .AddSingletonAll(); - } + /// + /// Called once to get all the plugin components. + /// Add components for the IVstXxxx interfaces you want to support. + /// + /// Is never null. + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll() + .AddSingletonAll(); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/PluginCommandStub.cs b/Source/Templates/CSharp/VstNetMidiPlugin/PluginCommandStub.cs index 80e77b4b..dc2806c4 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/PluginCommandStub.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/PluginCommandStub.cs @@ -1,27 +1,26 @@ using Jacobi.Vst.Plugin.Framework; using Jacobi.Vst.Plugin.Framework.Plugin; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// This object receives all calls from the (unmanaged) host. +/// +/// +/// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly +/// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ +/// to this object. +/// +public class PluginCommandStub : StdPluginCommandStub { /// - /// This object receives all calls from the (unmanaged) host. + /// Returns an instance of the VST.NET Plugin root object. /// - /// - /// An instance of this object is created automatically by the Jacobi.Vst.Plugin.Interop assembly - /// when the plugin is loaded into the host. Interop marshals all calls from unmanaged C++ - /// to this object. - /// - public class PluginCommandStub : StdPluginCommandStub + /// Must never return null. + protected override IVstPlugin CreatePluginInstance() { - /// - /// Returns an instance of the VST.NET Plugin root object. - /// - /// Must never return null. - protected override IVstPlugin CreatePluginInstance() - { - // StdPluginCommandStub implements all the VST2 methods, - // all you have to do is give the Framework your plugin root. - return new Plugin(); - } + // StdPluginCommandStub implements all the VST2 methods, + // all you have to do is give the Framework your plugin root. + return new Plugin(); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/PluginEditor.cs b/Source/Templates/CSharp/VstNetMidiPlugin/PluginEditor.cs index 8a1d36fc..c9a448d8 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/PluginEditor.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/PluginEditor.cs @@ -6,67 +6,66 @@ using System.Linq; using VstNetMidiPlugin.UI; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// This object manages the custom editor (UI) for your plugin. +/// +/// +/// When you do not implement a custom editor, +/// your Parameters will be displayed in an editor provided by the host. +/// +internal sealed class PluginEditor : IVstPluginEditor { - /// - /// This object manages the custom editor (UI) for your plugin. - /// - /// - /// When you do not implement a custom editor, - /// your Parameters will be displayed in an editor provided by the host. - /// - internal sealed class PluginEditor : IVstPluginEditor - { - private readonly PluginParameters _parameters; - private readonly WinFormsControlWrapper _view; + private readonly PluginParameters _parameters; + private readonly WinFormsControlWrapper _view; - public PluginEditor(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - _view = new WinFormsControlWrapper(); - } + public PluginEditor(PluginParameters parameters) + { + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + _view = new WinFormsControlWrapper(); + } - public Rectangle Bounds - { - get { return _view.Bounds; } - } + public Rectangle Bounds + { + get { return _view.Bounds; } + } - public void Close() - { - _view.Close(); - } + public void Close() + { + _view.Close(); + } - public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyDown(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) - { - // empty by design - return false; - } + public bool KeyUp(byte ascii, VstVirtualKey virtualKey, VstModifierKeys modifers) + { + // empty by design + return false; + } - public VstKnobMode KnobMode { get; set; } + public VstKnobMode KnobMode { get; set; } - public void Open(IntPtr hWnd) - { - // make a list of parameters to pass to the dlg. - var paramList = _parameters.ParameterInfos - .Where(p => p.ParameterManager != null) - .Select(p => p.ParameterManager!) - .ToList(); + public void Open(IntPtr hWnd) + { + // make a list of parameters to pass to the dlg. + var paramList = _parameters.ParameterInfos + .Where(p => p.ParameterManager != null) + .Select(p => p.ParameterManager!) + .ToList(); - _view.SafeInstance.InitializeParameters(paramList); + _view.SafeInstance.InitializeParameters(paramList); - _view.Open(hWnd); - } + _view.Open(hWnd); + } - public void ProcessIdle() - { - // keep your processing short! - _view.SafeInstance.ProcessIdle(); - } + public void ProcessIdle() + { + // keep your processing short! + _view.SafeInstance.ProcessIdle(); } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/PluginParameters.cs b/Source/Templates/CSharp/VstNetMidiPlugin/PluginParameters.cs index 254c2e8d..dcd1162a 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/PluginParameters.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/PluginParameters.cs @@ -2,71 +2,70 @@ using System.Linq; using VstNetMidiPlugin.Dmp; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// A central location for all plugin parameters +/// +internal sealed class PluginParameters { /// - /// A central location for all plugin parameters + /// Initializes all plugin parameters (one component at a time). /// - internal sealed class PluginParameters + public PluginParameters() { - /// - /// Initializes all plugin parameters (one component at a time). - /// - public PluginParameters() - { - // register the parameters of all plugin (sub) components - GainParameters = new GainParameters(this); - TransposeParameters = new TransposeParameters(this); - } + // register the parameters of all plugin (sub) components + GainParameters = new GainParameters(this); + TransposeParameters = new TransposeParameters(this); + } - public GainParameters GainParameters { get; private set; } - public TransposeParameters TransposeParameters { get; private set; } + public GainParameters GainParameters { get; private set; } + public TransposeParameters TransposeParameters { get; private set; } - /// - /// Gets the central list of parameter categories. - /// - public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); + /// + /// Gets the central list of parameter categories. + /// + public VstParameterCategoryCollection Categories { get; } = new VstParameterCategoryCollection(); - /// - /// Gets the central list of parameter definitions. - /// - public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); + /// + /// Gets the central list of parameter definitions. + /// + public VstParameterInfoCollection ParameterInfos { get; } = new VstParameterInfoCollection(); - /// - /// Retrieves a parameter category object for the specified . - /// - /// The name of the parameter category. - /// Typically the name of a Dsp component, an effect or function. - /// Never returns null. - public VstParameterCategory GetParameterCategory(string categoryName) + /// + /// Retrieves a parameter category object for the specified . + /// + /// The name of the parameter category. + /// Typically the name of a Dsp component, an effect or function. + /// Never returns null. + public VstParameterCategory GetParameterCategory(string categoryName) + { + if (Categories.Contains(categoryName)) { - if (Categories.Contains(categoryName)) - { - return Categories[categoryName]; - } + return Categories[categoryName]; + } - // create a new parameter category object - var paramCategory = new VstParameterCategory - { - Name = categoryName - }; + // create a new parameter category object + var paramCategory = new VstParameterCategory + { + Name = categoryName + }; - Categories.Add(paramCategory); + Categories.Add(paramCategory); - return paramCategory; - } + return paramCategory; + } - /// - /// Assigns the to all s. - /// - /// - public void SetHostAutomation(IVstHostAutomation? hostAutomation) + /// + /// Assigns the to all s. + /// + /// + public void SetHostAutomation(IVstHostAutomation? hostAutomation) + { + foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) { - foreach (var paramMgr in ParameterInfos.Select(p => p.ParameterManager)) - { - if (paramMgr != null) - paramMgr.HostAutomation = hostAutomation; - } + if (paramMgr != null) + paramMgr.HostAutomation = hostAutomation; } } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/PluginPrograms.cs b/Source/Templates/CSharp/VstNetMidiPlugin/PluginPrograms.cs index a317b121..c8e4dee4 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/PluginPrograms.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/PluginPrograms.cs @@ -2,65 +2,64 @@ using Jacobi.Vst.Plugin.Framework.Plugin; using System; -namespace VstNetMidiPlugin +namespace VstNetMidiPlugin; + +/// +/// This object manages the Plugin programs and its parameters. +/// +internal sealed class PluginPrograms : VstPluginPrograms { + private readonly PluginParameters _parameters; + /// - /// This object manages the Plugin programs and its parameters. + /// Constructs a new instance. /// - internal sealed class PluginPrograms : VstPluginPrograms + /// A reference to the plugin root object. + public PluginPrograms(PluginParameters parameters) { - private readonly PluginParameters _parameters; - - /// - /// Constructs a new instance. - /// - /// A reference to the plugin root object. - public PluginPrograms(PluginParameters parameters) - { - _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); - } + _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + } - /// - /// Called to initialize the collection of programs for the plugin. - /// - /// Never returns null or an empty collection. - protected override VstProgramCollection CreateProgramCollection() - { - var programs = new VstProgramCollection(); + /// + /// Called to initialize the collection of programs for the plugin. + /// + /// Never returns null or an empty collection. + protected override VstProgramCollection CreateProgramCollection() + { + var programs = new VstProgramCollection(); - // TODO: add a number of programs for your plugin. + // TODO: add a number of programs for your plugin. - VstProgram program = CreateProgram(_parameters.ParameterInfos); - program.Name = "Default"; - programs.Add(program); + VstProgram program = CreateProgram(_parameters.ParameterInfos); + program.Name = "Default"; + programs.Add(program); - return programs; - } + return programs; + } - // create a program with all parameters. - private VstProgram CreateProgram(VstParameterInfoCollection parameterInfos) - { - var program = new VstProgram(_parameters.Categories); + // create a program with all parameters. + private VstProgram CreateProgram(VstParameterInfoCollection parameterInfos) + { + var program = new VstProgram(_parameters.Categories); - CreateParameters(program.Parameters, parameterInfos); + CreateParameters(program.Parameters, parameterInfos); - return program; - } + return program; + } - // create all parameters - private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + // create all parameters + private void CreateParameters(VstParameterCollection desitnation, VstParameterInfoCollection parameterInfos) + { + foreach (VstParameterInfo paramInfo in parameterInfos) { - foreach (VstParameterInfo paramInfo in parameterInfos) - { - desitnation.Add(CreateParameter(paramInfo)); - } + desitnation.Add(CreateParameter(paramInfo)); } + } - // create one parameter - private VstParameter CreateParameter(VstParameterInfo parameterInfo) - { - var parameter = new VstParameter(parameterInfo); - return parameter; - } + // create one parameter + private VstParameter CreateParameter(VstParameterInfo parameterInfo) + { + var parameter = new VstParameter(parameterInfo); + return parameter; } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/UI/PluginEditorView.cs b/Source/Templates/CSharp/VstNetMidiPlugin/UI/PluginEditorView.cs index 740e70cc..85b5e82f 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/UI/PluginEditorView.cs +++ b/Source/Templates/CSharp/VstNetMidiPlugin/UI/PluginEditorView.cs @@ -2,119 +2,118 @@ using System.Collections.Generic; using System.Windows.Forms; -namespace VstNetMidiPlugin.UI +namespace VstNetMidiPlugin.UI; + +public partial class PluginEditorView : UserControl { - public partial class PluginEditorView : UserControl + public PluginEditorView() { - public PluginEditorView() - { - InitializeComponent(); - } - - internal bool InitializeParameters(List parameters) - { - if (parameters == null || parameters.Count < 2) - return false; - - BindParameter(parameters[0], label1, trackBar1, label3); - BindParameter(parameters[1], label2, trackBar2, label4); - - return true; - } + InitializeComponent(); + } - private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) - { - label.Text = paramMgr.ParameterInfo.Name; - shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; + internal bool InitializeParameters(List parameters) + { + if (parameters == null || parameters.Count < 2) + return false; - var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); - var paramState = new ParameterControlState(paramMgr, factor); + BindParameter(parameters[0], label1, trackBar1, label3); + BindParameter(parameters[1], label2, trackBar2, label4); - // use databinding for VstParameter/Manager changed notifications. - trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); - trackBar.ValueChanged += TrackBar_ValueChanged; - trackBar.Tag = paramState; - } + return true; + } - private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) - { - // A multiplication factor to convert floats (0.0-1.0) - // to an integer range for the TrackBar to work with. - float factor = 1.0f; + private void BindParameter(VstParameterManager paramMgr, Label label, TrackBar trackBar, Label shortLabel) + { + label.Text = paramMgr.ParameterInfo.Name; + shortLabel.Text = paramMgr.ParameterInfo.ShortLabel; - if (parameterInfo.IsSwitch) - { - trackBar.Minimum = 0; - trackBar.Maximum = 1; - trackBar.LargeChange = 1; - trackBar.SmallChange = 1; - return factor; - } + var factor = InitTrackBar(trackBar, paramMgr.ParameterInfo); + var paramState = new ParameterControlState(paramMgr, factor); - if (parameterInfo.IsStepIntegerValid) - { - trackBar.LargeChange = parameterInfo.LargeStepInteger; - trackBar.SmallChange = parameterInfo.StepInteger; - } - else if (parameterInfo.IsStepFloatValid) - { - factor = 1 / parameterInfo.StepFloat; - trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); - trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); - } + // use databinding for VstParameter/Manager changed notifications. + trackBar.DataBindings.Add("Value", paramState, nameof(ParameterControlState.Value)); + trackBar.ValueChanged += TrackBar_ValueChanged; + trackBar.Tag = paramState; + } - if (parameterInfo.IsMinMaxIntegerValid) - { - trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); - trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); - } - else - { - trackBar.Minimum = 0; - trackBar.Maximum = (int)factor; - } + private float InitTrackBar(TrackBar trackBar, VstParameterInfo parameterInfo) + { + // A multiplication factor to convert floats (0.0-1.0) + // to an integer range for the TrackBar to work with. + float factor = 1.0f; + if (parameterInfo.IsSwitch) + { + trackBar.Minimum = 0; + trackBar.Maximum = 1; + trackBar.LargeChange = 1; + trackBar.SmallChange = 1; return factor; } - private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + if (parameterInfo.IsStepIntegerValid) { - var trackBar = (TrackBar?)sender; - var paramState = (ParameterControlState?)trackBar?.Tag; + trackBar.LargeChange = parameterInfo.LargeStepInteger; + trackBar.SmallChange = parameterInfo.StepInteger; + } + else if (parameterInfo.IsStepFloatValid) + { + factor = 1 / parameterInfo.StepFloat; + trackBar.LargeChange = (int)(parameterInfo.LargeStepFloat * factor); + trackBar.SmallChange = (int)(parameterInfo.StepFloat * factor); + } - if (trackBar != null && - paramState?.ParameterManager.ActiveParameter != null) - { - paramState.ParameterManager.ActiveParameter.Value = - trackBar.Value / paramState.ValueFactor; - } + if (parameterInfo.IsMinMaxIntegerValid) + { + trackBar.Minimum = (int)(parameterInfo.MinInteger * factor); + trackBar.Maximum = (int)(parameterInfo.MaxInteger * factor); } + else + { + trackBar.Minimum = 0; + trackBar.Maximum = (int)factor; + } + + return factor; + } + + private void TrackBar_ValueChanged(object? sender, System.EventArgs e) + { + var trackBar = (TrackBar?)sender; + var paramState = (ParameterControlState?)trackBar?.Tag; - internal void ProcessIdle() + if (trackBar != null && + paramState?.ParameterManager.ActiveParameter != null) { - // TODO: short idle processing here + paramState.ParameterManager.ActiveParameter.Value = + trackBar.Value / paramState.ValueFactor; } + } + + internal void ProcessIdle() + { + // TODO: short idle processing here + } - /// - /// This class converts the parameter value range to a compatible (integer) TrackBar value range. - /// - private sealed class ParameterControlState + /// + /// This class converts the parameter value range to a compatible (integer) TrackBar value range. + /// + private sealed class ParameterControlState + { + public ParameterControlState(VstParameterManager parameterManager, float valueFactor) { - public ParameterControlState(VstParameterManager parameterManager, float valueFactor) - { - ParameterManager = parameterManager; - ValueFactor = valueFactor; - } + ParameterManager = parameterManager; + ValueFactor = valueFactor; + } - public VstParameterManager ParameterManager { get; } - public float ValueFactor { get; } + public VstParameterManager ParameterManager { get; } + public float ValueFactor { get; } - public int Value + public int Value + { + get { - get - { - return (int)(ParameterManager.CurrentValue * ValueFactor); - } + return (int)(ParameterManager.CurrentValue * ValueFactor); } } } diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.csproj b/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.csproj index 43f31be0..b391d15c 100644 --- a/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.csproj +++ b/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0-windows x64;x86 enable @@ -10,9 +10,9 @@ - + - + diff --git a/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.zip b/Source/Templates/CSharp/VstNetMidiPlugin/VstNetMidiPlugin.zip index 12b6ac90bf609cc349b321449d1e23ca3366997e..8ea33f042d2acd01a9462971a5e59bc16bafa048 100644 GIT binary patch delta 10168 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 delta 10176 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 P-UVJ$VuU@B|9$vBKG=Vj diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 96c3b904..82ef511b 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -45,7 +45,7 @@ There are several plugin [Samples](https://github.com/obiwanjacobi/vst.net/tree/ ### Loading a Plugin After you have compiled a sample -or your own- plugin it is time to load it into a host application. -If the build was successful you should have a deploy folder at `[MyProject]\bin\[x64|x86]\[Debug|Release]\net6.0\deploy`. +If the build was successful you should have a deploy folder at `[MyProject]\bin\[x64|x86]\[Debug|Release]\net6.0\deploy`*. > The **Deploy** folder contains everything needed to load the plugin into a host application. @@ -77,8 +77,10 @@ If you have Visual Studio installed, these files are already present. But if you distribute your project made with VST.NET you need to install this on the client machine where your software will be running. As of `2.0.0-RC1` the nuget packages for plugin and host both contain a build file to create a deployment after each successful build. -The `deploy` folder is at the same location as the project binaries: `[MyProject]\bin\[x64|x86]\[Debug|Release]\net6.0\deploy`. +The `deploy` folder is at the same location as the project binaries: `[MyProject]\bin\[x64|x86]\[Debug|Release]\net6.0\deploy`*. --- +__*__) `net6.0` is used as an example TargetFramework. This can also be newer targets like `net7.0` and `net8.0`. + > Back to [Index](index.md) diff --git a/docs/cli.md b/docs/cli.md index cdf66e06..56c6ba14 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -14,10 +14,11 @@ More commands may be added later as the need arises. ## Publish -`vstnet publish [-o ]` +`vstnet publish [-o ] -p ` - `` is a path to the binary output of your VST.NET project. For a plugin that would be a .dll file. For a host project, that would be a .exe file. - `-o` allows you to specify an output directory that will receive all the dependencies of the specified '``'. If not specified, the output folder will default to '.\deploy'. +- `` must contain `x64` for 64-bits or `x86` for 32-bits. The `publish` command will gather all the dependencies (from the NuGet cache folder on your local drive) and perform the necessary renaming of plugin .dll's in order for them to load correctly by the Interop. It also copies over any `settings.json` files that may be next to your primary project binary. diff --git a/docs/media/VstNetAudioPlugin.zip b/docs/media/VstNetAudioPlugin.zip index d9e1903ee00fa9f0b248f6a815d198b49d39931f..87e919fdd9a4d3a60eda96dae9f5abc5e47aa86d 100644 GIT binary patch delta 8926 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 azWLYsd`V>y{HwwP2$~!dJihdw!v6#7keI{( diff --git a/docs/media/VstNetMidiPlugin.zip b/docs/media/VstNetMidiPlugin.zip index 12b6ac90bf609cc349b321449d1e23ca3366997e..8ea33f042d2acd01a9462971a5e59bc16bafa048 100644 GIT binary patch delta 10168 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 delta 10176 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 P-UVJ$VuU@B|9$vBKG=Vj