using System.IO.Compression; using System.Text; using AquaSynth.Dsl; namespace AquaSynth.Dsl.Tests; public sealed class ZynInstrumentTests { [Fact] public void ParsesProjectAuthoredAdditiveLeadFixture() { var path = FixturePath("ZynAddSubFX", "ProjectAuthored", "additive-lead.xiz"); var bytes = File.ReadAllBytes(path); var instrument = ZynInstrumentReader.Parse(bytes); var reference = instrument.ToReferencePatch( "zyn/project/additive-lead", ZynInstrumentReader.SourceForBytes("fixture://zyn/project/additive-lead.xiz", "project-authored", bytes)); Assert.Equal("AQ Additive Lead", instrument.Name); Assert.Equal("AquaSynth tests", instrument.Author); Assert.Contains(reference.Features, feature => feature.Name == "engine_add" && feature.Value == "1"); Assert.Contains(reference.Features, feature => feature.Name == "engine_sub" && feature.Value == "0"); Assert.Contains(reference.Features, feature => feature.Name == "engine_pad" && feature.Value == "0"); Assert.Contains(reference.Features, feature => feature.Name == "envelope_count" && feature.Value == "2"); Assert.Contains(reference.Features, feature => feature.Name == "lfo_count" && feature.Value == "1"); Assert.Equal("zynaddsubfx", reference.Family); Assert.Equal("zyn-xiz", reference.Source.Kind); Assert.Equal(64, reference.Source.Hash.Length); } [Fact] public void ClassifiesPadAndFormantLayerPressure() { var pad = ZynInstrumentReader.ParseFile(FixturePath("ZynAddSubFX", "ProjectAuthored", "pad-texture.xiz")); var vocal = ZynInstrumentReader.ParseFile(FixturePath("ZynAddSubFX", "ProjectAuthored", "vocal-layer.xiz")); AssertFeature(pad, "engine_pad", "1"); AssertFeature(pad, "filter_count", "1"); AssertFeature(pad, "free_envelope_count", "1"); AssertFeature(vocal, "layered_instrument", "yes"); AssertFeature(vocal, "engine_add", "1"); AssertFeature(vocal, "engine_sub", "1"); AssertFeature(vocal, "formant_filter_count", "1"); AssertFeature(vocal, "effect_count", "1"); } [Fact] public void ParsesGzippedXizXml() { var xml = File.ReadAllText(FixturePath("ZynAddSubFX", "ProjectAuthored", "additive-lead.xiz")); using var output = new MemoryStream(); using (var gzip = new GZipStream(output, CompressionLevel.SmallestSize, leaveOpen: true)) { gzip.Write(Encoding.UTF8.GetBytes(xml)); } var instrument = ZynInstrumentReader.Parse(output.ToArray()); Assert.Equal("AQ Additive Lead", instrument.Name); Assert.Single(instrument.KitItems); } [Fact] public void EngineEnableFlagsOverrideStaleParameterSections() { var instrument = ZynInstrumentReader.Parse(Encoding.UTF8.GetBytes(""" Stale Engine Section """)); AssertFeature(instrument, "engine_pad", "0"); } [Fact] public void ToleratesLeadingWhitespaceBeforeXmlDeclaration() { var instrument = ZynInstrumentReader.Parse(Encoding.UTF8.GetBytes(""" Loose XML """)); Assert.Equal("Loose XML", instrument.Name); AssertFeature(instrument, "engine_add", "1"); } [Fact] public void CountsOnlyActualFormantFilterBlocks() { var instrument = ZynInstrumentReader.Parse(Encoding.UTF8.GetBytes(""" Formant Counting """)); AssertFeature(instrument, "formant_filter_count", "1"); } [Fact] public void SurveyRanksWorstFeaturePressure() { var root = Path.Combine(AppContext.BaseDirectory, "Fixtures", "ZynAddSubFX", "ProjectAuthored"); var survey = ZynInstrumentSurvey.RankDirectory(root, take: 3); Assert.Equal(3, survey.Count); Assert.Equal("vocal-layer.xiz", survey[0].Path); Assert.True(survey[0].ComplexityScore > survey[^1].ComplexityScore); Assert.Contains(survey[0].Features, feature => feature.Name == "formant_filter_count" && feature.Value == "1"); } [Fact] public void RebuildsProjectAuthoredPadAsAquaSynthSpectrumScript() { var path = FixturePath("ZynAddSubFX", "ProjectAuthored", "pad-harmonic.xiz"); var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(path, tableRootFrequencyHz: 77.7813f); var patch = PatchScript.Parse(rebuild.Script); Assert.Equal("AQ Pad Harmonic", rebuild.InstrumentName); Assert.Equal(0, rebuild.KitItemId); Assert.Contains("spectrum", rebuild.Script); Assert.Contains("root=77.7813", rebuild.Script); Assert.Contains("pad_profile=", rebuild.Script); Assert.Contains("pad_position=", rebuild.Script); Assert.DoesNotContain("zyn_profile=", rebuild.Script); Assert.DoesNotContain("zyn_position=", rebuild.Script); var bank = Assert.Single(patch.SpectralBanks); Assert.Equal(77.7813f, bank.RootFrequencyHz, precision: 4); Assert.Equal(PadSpectrumMode.Bandwidth, bank.Profile.Mode); Assert.Contains(bank.Partials, partial => Math.Abs(partial.Ratio - 2) < 0.0001f && partial.Gain > 0); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_oscillator_harmonics"); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_harmonic_profile"); } [Fact] public void UpstreamSin2xOscilFilterKeepsSpikeOnSecondHarmonicWhenAvailable() { var root = RepositoryRoot(); var path = Path.Combine(root, "external", "zynaddsubfx", "instruments", "banks", "Pads", "0002-sin2x pad.xiz"); if (!File.Exists(path)) { return; } var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(path, tableRootFrequencyHz: 109.999f); var patch = PatchScript.Parse(rebuild.Script); var bank = Assert.Single(patch.SpectralBanks); var partials = bank.Partials.ToDictionary(partial => (int)MathF.Round(partial.Ratio), partial => partial.Gain); Assert.True(partials[2] > partials[3] * 10); Assert.True(partials[2] > partials[1]); } [Fact] public void UpstreamOrganChoirMapsHighPassMotionAndShiftTableRootWhenAvailable() { var root = RepositoryRoot(); var path = Path.Combine(root, "external", "zynaddsubfx", "instruments", "banks", "Dual", "0008-Organ Choir Pad2.xiz"); if (!File.Exists(path)) { return; } var rebuild = ZynInstrumentReader.RebuildEnabledPadsAsAquaSynthScript( path, new Dictionary { [0] = new(77.7813f, 311.125f), [1] = new(77.7813f, 622.25f) }); var patch = PatchScript.Parse(rebuild.Script); Assert.Contains("hpf_order=6", rebuild.Script); Assert.Contains("hpf_env=rl", rebuild.Script); Assert.Contains("spectrum layer=organ_choir_pad2_0 root=77.7813", rebuild.Script); Assert.Contains("spectrum layer=organ_choir_pad2_1 root=622.25", rebuild.Script); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_kit_0_filter_hpf_envelope"); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_kit_1_oscillator_base_function" && feature.Value == "7"); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_kit_1_oscillator_base_function_modulation" && feature.Value == "1"); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_kit_1_oscillator_adaptive_harmonics" && feature.Value == "1"); Assert.Equal(77.7813f, patch.SpectralBanks[0].RootFrequencyHz, precision: 4); Assert.Equal(622.25f, patch.SpectralBanks[1].RootFrequencyHz, precision: 4); var octavePartials = patch.SpectralBanks[1].Partials.ToDictionary(partial => (int)MathF.Round(partial.Ratio), partial => partial.Gain); Assert.True(octavePartials[2] > 0.09f); Assert.True(octavePartials[3] < 0.01f); Assert.True(octavePartials[4] < 0.001f); } [Fact] public void UpstreamWideBassExportsFormantMotionWorkoutWhenAvailable() { var root = RepositoryRoot(); var path = Path.Combine(root, "external", "zynaddsubfx", "instruments", "banks", "Companion", "0056-Wide Bass.xiz"); if (!File.Exists(path)) { return; } var rebuild = ZynInstrumentReader.RebuildFirstFormantMotionAsAquaSynthScript(path); var patch = PatchScript.Parse(rebuild.Script); var voice = Assert.Single(patch.Voices); Assert.Equal("Wide Bass", rebuild.InstrumentName); Assert.True(voice.FormantFrames.Count >= 3); Assert.All(voice.FormantFrames, frame => Assert.True(frame.Formants.Count >= 3)); Assert.Contains("vowels=", rebuild.Script); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "formant_sequence"); Assert.Contains(rebuild.MissingFeatures, feature => feature.Name == "zyn_formant_position_driver"); var faust = FaustEmitter.Emit(patch).Source; Assert.Contains("wrap01(age *", faust); } [Fact] public void RebuildMapsZynStateVariablePadLowPassToAquaFilterAuthority() { var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(Encoding.UTF8.GetBytes(""" SV Low PAD """), tableRootFrequencyHz: 77.7813f); var patch = PatchScript.Parse(rebuild.Script); var bank = Assert.Single(patch.SpectralBanks); var voice = bank.Treatment; Assert.True(voice.Filter.LowPass < 1); Assert.Equal(3, voice.Filter.LowPassOrder); Assert.True(voice.Filter.LowPassQ > 0); Assert.Equal(0, voice.Filter.HighPass); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_filter_lpf"); Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "pad_filter_lpf_order" && feature.Value == "3"); } [Fact] public void RebuildMapsZynStateVariablePadBandAndNotchToAquaFilterAuthority() { var band = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(Encoding.UTF8.GetBytes(ZynPadWithFilter(category: 2, type: 2)), tableRootFrequencyHz: 77.7813f); var notch = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(Encoding.UTF8.GetBytes(ZynPadWithFilter(category: 2, type: 3)), tableRootFrequencyHz: 77.7813f); var bandVoice = Assert.Single(PatchScript.Parse(band.Script).SpectralBanks).Treatment; Assert.True(bandVoice.Filter.BandPass > 0); Assert.True(bandVoice.Filter.BandPassQ > 0); Assert.Equal(6, bandVoice.Filter.BandPassOrder); Assert.Equal(0, bandVoice.Filter.Notch); Assert.Contains(band.MatchedFeatures, feature => feature.Name == "pad_filter_bpf"); var notchVoice = Assert.Single(PatchScript.Parse(notch.Script).SpectralBanks).Treatment; Assert.True(notchVoice.Filter.Notch > 0); Assert.True(notchVoice.Filter.NotchQ > 0); Assert.Equal(6, notchVoice.Filter.NotchOrder); Assert.Equal(0, notchVoice.Filter.BandPass); Assert.Contains(notch.MatchedFeatures, feature => feature.Name == "pad_filter_notch"); } [Fact] public async Task SurveysUpstreamGplInstrumentBankWhenAvailable() { var root = RepositoryRoot(); var bankRoot = Path.Combine(root, "external", "zynaddsubfx", "instruments", "banks"); if (!Directory.Exists(bankRoot)) { return; } var files = Directory.GetFiles(bankRoot, "*.xiz", SearchOption.AllDirectories); if (files.Length == 0) { return; } var survey = ZynInstrumentSurvey.RankDirectory(bankRoot, take: 20); Assert.NotEmpty(survey); Assert.Contains(survey, item => item.Features.Any(feature => feature.Name == "engine_pad" && feature.Value != "0")); var artifactDir = Path.Combine(root, "artifacts", "parity", "zyn-upstream-bank-survey"); Directory.CreateDirectory(artifactDir); var report = new List { "ZynAddSubFX upstream GPL instrument bank survey", "source: https://github.com/zynaddsubfx/instruments", "license: GPL test/development corpus via upstream ZynAddSubFX instruments submodule", "usage: feature pressure and parity fixtures only; never NuGet/package content", $"bank_root: {bankRoot}", $"xiz_count: {files.Length}", "" }; foreach (var item in survey) { var features = item.Features.ToDictionary(feature => feature.Name, feature => feature.Value); report.Add($"{item.ComplexityScore}\t{item.Path}\t{item.Name}\tpad={features["engine_pad"]} add={features["engine_add"]} sub={features["engine_sub"]} layers={features["enabled_kit_items"]} env={features["envelope_count"]} free={features["free_envelope_count"]} lfo={features["lfo_count"]} filter={features["filter_count"]} formant={features["formant_filter_count"]} fx={features["effect_count"]}"); } await File.WriteAllLinesAsync(Path.Combine(artifactDir, "report.txt"), report); var coverage = ZynInstrumentSurvey.CoverageDirectory(bankRoot); await File.WriteAllTextAsync(Path.Combine(artifactDir, "coverage.md"), ZynInstrumentSurvey.CoverageMarkdown(coverage)); } [Fact] public void CoverageSurveyClassifiesProjectAuthoredZynPressure() { var root = Path.Combine(AppContext.BaseDirectory, "Fixtures", "ZynAddSubFX", "ProjectAuthored"); var report = ZynInstrumentSurvey.CoverageDirectory(root); Assert.Equal(5, report.FileCount); Assert.Equal(5, report.ParsedFileCount); Assert.Contains(report.Buckets, bucket => bucket.Area == "engine" && bucket.Key == "pad" && bucket.Status == ZynCoverageStatus.Handled); Assert.Contains(report.Buckets, bucket => bucket.Area == "engine" && bucket.Key == "add" && bucket.Status == ZynCoverageStatus.Counted); Assert.Contains(report.Buckets, bucket => bucket.Area == "engine" && bucket.Key == "sub" && bucket.Status == ZynCoverageStatus.Counted); Assert.Contains(report.Buckets, bucket => bucket.Area == "envelope" && bucket.Key.EndsWith(".free", StringComparison.Ordinal) && bucket.Status == ZynCoverageStatus.Counted); var markdown = ZynInstrumentSurvey.CoverageMarkdown(report); Assert.Contains("## Unknown", markdown); Assert.Contains("## Counted", markdown); Assert.Contains("## Handled", markdown); } [Fact] public void CoverageSurveyExposesUnhandledZynPadSubtypes() { var dir = Directory.CreateTempSubdirectory("aquasynth-zyn-coverage-"); try { File.WriteAllText(Path.Combine(dir.FullName, "unknown-pad.xiz"), """ Unknown PAD Modes """); File.WriteAllText(Path.Combine(dir.FullName, "handled-sv-pad.xiz"), """ Handled SV PAD """); var report = ZynInstrumentSurvey.CoverageDirectory(dir.FullName); Assert.Contains(report.Buckets, bucket => bucket.Area == "pad.filter" && bucket.Key == "cat=2 type=0" && bucket.Status == ZynCoverageStatus.Handled); Assert.Contains(report.UnknownBuckets, bucket => bucket.Area == "pad.oscil.filter_type" && bucket.Key == "12"); Assert.Contains(report.UnknownBuckets, bucket => bucket.Area == "pad.oscil.wave_shape" && bucket.Key == "14"); Assert.Contains(report.UnknownBuckets, bucket => bucket.Area == "pad.filter" && bucket.Key == "cat=1 type=0"); Assert.Contains(report.CountedBuckets, bucket => bucket.Area == "pad.filter_lfo" && bucket.Key == "intensity=40"); } finally { dir.Delete(recursive: true); } } private static void AssertFeature(ZynInstrument instrument, string name, string value) => Assert.Contains(instrument.Features(), feature => feature.Name == name && feature.Value == value); private static string FixturePath(params string[] parts) => Path.Combine([AppContext.BaseDirectory, "Fixtures", .. parts]); private static string ZynPadWithFilter(int category, int type) => $$""" Filter PAD """; private static string RepositoryRoot() { var directory = new DirectoryInfo(AppContext.BaseDirectory); while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquaSynth.sln"))) { directory = directory.Parent; } return directory?.FullName ?? throw new InvalidOperationException("could not find repository root"); } }