diff --git a/src/BaroquenMelody.Library/Configurations/AggregateOrnamentationConfiguration.cs b/src/BaroquenMelody.Library/Configurations/AggregateOrnamentationConfiguration.cs index a2c00353..d32f9d78 100644 --- a/src/BaroquenMelody.Library/Configurations/AggregateOrnamentationConfiguration.cs +++ b/src/BaroquenMelody.Library/Configurations/AggregateOrnamentationConfiguration.cs @@ -38,7 +38,9 @@ public sealed record AggregateOrnamentationConfiguration(ISet new BaroquenNote(Instrument.One, Note.Get(compositionConfiguration.Scale.Tonic, 4), compositionConfiguration.DefaultNoteTimeSpan), OrnamentationType.UpperOctavePedalPassingTone => new BaroquenNote(Instrument.One, Note.Get(compositionConfiguration.Scale.Mediant, 4), compositionConfiguration.DefaultNoteTimeSpan), OrnamentationType.UpperOctavePedalArpeggio => new BaroquenNote(Instrument.One, Note.Get(compositionConfiguration.Scale.Dominant, 4), compositionConfiguration.DefaultNoteTimeSpan), + OrnamentationType.TriplePickup => new BaroquenNote(Instrument.One, Note.Get(compositionConfiguration.Scale.Mediant, 4), compositionConfiguration.DefaultNoteTimeSpan), + OrnamentationType.SequencedThirds => new BaroquenNote(Instrument.One, Note.Get(compositionConfiguration.Scale.Subdominant, 3), compositionConfiguration.DefaultNoteTimeSpan), _ => throw new ArgumentOutOfRangeException(nameof(ornamentationType), ornamentationType, "Ornamentation type not supported.") }; } diff --git a/src/BaroquenMelody.Library/Ornamentation/Engine/Processors/Factories/OrnamentationProcessorConfigurationFactory.cs b/src/BaroquenMelody.Library/Ornamentation/Engine/Processors/Factories/OrnamentationProcessorConfigurationFactory.cs index e0cf1a91..c74fee0b 100644 --- a/src/BaroquenMelody.Library/Ornamentation/Engine/Processors/Factories/OrnamentationProcessorConfigurationFactory.cs +++ b/src/BaroquenMelody.Library/Ornamentation/Engine/Processors/Factories/OrnamentationProcessorConfigurationFactory.cs @@ -612,6 +612,48 @@ public IEnumerable Create(OrnamentationConf ) ); break; + case OrnamentationType.TriplePickup: + processorConfigurations.Add( + new OrnamentationProcessorConfiguration( + OrnamentationType.TriplePickup, + InputPolicies: + [ + wantsToOrnament, + _hasNoOrnamentation, + _hasNextBeat, + _isNotRepeatedNote, + new IsNextNoteIntervalWithinInstrumentRange(compositionConfiguration, 3).And(new IsIntervalWithinInstrumentRange(compositionConfiguration, -3)) + ], + OutputPolicies: [logOrnamentation], + Translations: [3, 2, 1], + ShouldInvertBasedOnDirection, + TranslationInversionIndices: new HashSet { 0, 1, 2 }.ToFrozenSet(), + ShouldTranslateOnCurrentNote: false + ) + ); + break; + case OrnamentationType.SequencedThirds: + processorConfigurations.Add( + new OrnamentationProcessorConfiguration( + OrnamentationType.SequencedThirds, + InputPolicies: + [ + wantsToOrnament, + _hasNoOrnamentation, + _hasNextBeat, + _isNotRepeatedNote, + new IsApplicableInterval(compositionConfiguration, 4), + _isAscending.And(new IsNextNoteIntervalWithinInstrumentRange(compositionConfiguration, 1)) + .Or(_isDescending.And(new IsNextNoteIntervalWithinInstrumentRange(compositionConfiguration, -1))) + ], + OutputPolicies: [logOrnamentation], + Translations: [2, 1, 3, 2, 4, 3, 5], + ShouldInvertBasedOnDirection, + TranslationInversionIndices: new HashSet { 0, 1, 2, 3, 4, 5, 6 }.ToFrozenSet(), + ShouldTranslateOnCurrentNote: true + ) + ); + break; case OrnamentationType.None: case OrnamentationType.Sustain: case OrnamentationType.MidSustain: diff --git a/src/BaroquenMelody.Library/Ornamentation/Enums/Extensions/OrnamentationTypeExtensions.cs b/src/BaroquenMelody.Library/Ornamentation/Enums/Extensions/OrnamentationTypeExtensions.cs index 3f7387be..28801196 100644 --- a/src/BaroquenMelody.Library/Ornamentation/Enums/Extensions/OrnamentationTypeExtensions.cs +++ b/src/BaroquenMelody.Library/Ornamentation/Enums/Extensions/OrnamentationTypeExtensions.cs @@ -28,6 +28,7 @@ internal static class OrnamentationTypeExtensions { OrnamentationType.DelayedPickup, 1 }, { OrnamentationType.DelayedDoublePickup, 2 }, { OrnamentationType.DoublePickup, 2 }, + { OrnamentationType.TriplePickup, 3 }, { OrnamentationType.DecorateThird, 3 }, { OrnamentationType.OctavePedal, 3 }, { OrnamentationType.OctavePedalPassingTone, 3 }, @@ -35,6 +36,7 @@ internal static class OrnamentationTypeExtensions { OrnamentationType.UpperOctavePedal, 3 }, { OrnamentationType.UpperOctavePedalPassingTone, 3 }, { OrnamentationType.UpperOctavePedalArpeggio, 3 }, + { OrnamentationType.SequencedThirds, 7 }, { OrnamentationType.None, 0 }, { OrnamentationType.Sustain, 0 }, { OrnamentationType.MidSustain, 0 }, diff --git a/src/BaroquenMelody.Library/Ornamentation/Enums/OrnamentationType.cs b/src/BaroquenMelody.Library/Ornamentation/Enums/OrnamentationType.cs index 8db00751..dffb0a0b 100644 --- a/src/BaroquenMelody.Library/Ornamentation/Enums/OrnamentationType.cs +++ b/src/BaroquenMelody.Library/Ornamentation/Enums/OrnamentationType.cs @@ -166,4 +166,14 @@ public enum OrnamentationType : byte /// An upper octave pedal with an arpeggio. /// UpperOctavePedalArpeggio, + + /// + /// Three notes leading into the next note. + /// + TriplePickup, + + /// + /// A sequence of thirds. + /// + SequencedThirds, } diff --git a/src/BaroquenMelody.Library/Ornamentation/Utilities/MusicalTimeSpanCalculator.cs b/src/BaroquenMelody.Library/Ornamentation/Utilities/MusicalTimeSpanCalculator.cs index 1185e07a..943ac351 100644 --- a/src/BaroquenMelody.Library/Ornamentation/Utilities/MusicalTimeSpanCalculator.cs +++ b/src/BaroquenMelody.Library/Ornamentation/Utilities/MusicalTimeSpanCalculator.cs @@ -35,6 +35,10 @@ internal sealed class MusicalTimeSpanCalculator : IMusicalTimeSpanCalculator OrnamentationType.DelayedDoublePickup when meter == Meter.ThreeFour => MusicalTimeSpan.Half + MusicalTimeSpan.Eighth, OrnamentationType.DelayedDoublePickup when meter == Meter.FiveEight => MusicalTimeSpan.Half, + OrnamentationType.TriplePickup when meter == Meter.FourFour => MusicalTimeSpan.Eighth, + OrnamentationType.TriplePickup when meter == Meter.ThreeFour => MusicalTimeSpan.Quarter.Dotted(1), + OrnamentationType.TriplePickup when meter == Meter.FiveEight => MusicalTimeSpan.Quarter, + OrnamentationType.Run when meter == Meter.FourFour => MusicalTimeSpan.Eighth, OrnamentationType.Run when meter == Meter.ThreeFour => MusicalTimeSpan.Quarter.Dotted(1), OrnamentationType.Run when meter == Meter.FiveEight => MusicalTimeSpan.Quarter, @@ -135,6 +139,10 @@ internal sealed class MusicalTimeSpanCalculator : IMusicalTimeSpanCalculator OrnamentationType.UpperOctavePedalArpeggio when meter == Meter.ThreeFour => MusicalTimeSpan.Quarter.Dotted(1), OrnamentationType.UpperOctavePedalArpeggio when meter == Meter.FiveEight => MusicalTimeSpan.Quarter, + OrnamentationType.SequencedThirds when meter == Meter.FourFour => MusicalTimeSpan.Sixteenth, + OrnamentationType.SequencedThirds when meter == Meter.ThreeFour => MusicalTimeSpan.Quarter + MusicalTimeSpan.Sixteenth, + OrnamentationType.SequencedThirds when meter == Meter.FiveEight => MusicalTimeSpan.Eighth.Dotted(1), + OrnamentationType.MidSustain => Zero, OrnamentationType.Rest => Zero, @@ -165,6 +173,10 @@ internal sealed class MusicalTimeSpanCalculator : IMusicalTimeSpanCalculator OrnamentationType.DelayedDoublePickup when meter == Meter.ThreeFour => MusicalTimeSpan.Sixteenth, OrnamentationType.DelayedDoublePickup when meter == Meter.FiveEight => MusicalTimeSpan.Sixteenth, + OrnamentationType.TriplePickup when meter == Meter.FourFour => MusicalTimeSpan.Eighth, + OrnamentationType.TriplePickup when meter == Meter.ThreeFour => MusicalTimeSpan.Eighth, + OrnamentationType.TriplePickup when meter == Meter.FiveEight => MusicalTimeSpan.Eighth, + OrnamentationType.Run when meter == Meter.FourFour => MusicalTimeSpan.Eighth, OrnamentationType.Run when meter == Meter.ThreeFour => MusicalTimeSpan.Eighth, OrnamentationType.Run when meter == Meter.FiveEight => MusicalTimeSpan.Eighth, @@ -275,6 +287,10 @@ internal sealed class MusicalTimeSpanCalculator : IMusicalTimeSpanCalculator OrnamentationType.UpperOctavePedalArpeggio when meter == Meter.ThreeFour => MusicalTimeSpan.Eighth, OrnamentationType.UpperOctavePedalArpeggio when meter == Meter.FiveEight => MusicalTimeSpan.Eighth, + OrnamentationType.SequencedThirds when meter == Meter.FourFour => MusicalTimeSpan.Sixteenth, + OrnamentationType.SequencedThirds when meter == Meter.ThreeFour => MusicalTimeSpan.Sixteenth, + OrnamentationType.SequencedThirds when meter == Meter.FiveEight => MusicalTimeSpan.Sixteenth, + OrnamentationType.MidSustain => Zero, OrnamentationType.Rest => Zero, diff --git a/tests/BaroquenMelody.Library.Tests/Configuration/Services/OrnamentationConfigurationServiceTests.cs b/tests/BaroquenMelody.Library.Tests/Configuration/Services/OrnamentationConfigurationServiceTests.cs index 5f667f85..252fbaa7 100644 --- a/tests/BaroquenMelody.Library.Tests/Configuration/Services/OrnamentationConfigurationServiceTests.cs +++ b/tests/BaroquenMelody.Library.Tests/Configuration/Services/OrnamentationConfigurationServiceTests.cs @@ -63,7 +63,9 @@ public void ConfigurableOrnamentations_returns_expected_values() OrnamentationType.OctavePedalArpeggio, OrnamentationType.UpperOctavePedal, OrnamentationType.UpperOctavePedalPassingTone, - OrnamentationType.UpperOctavePedalArpeggio + OrnamentationType.UpperOctavePedalArpeggio, + OrnamentationType.TriplePickup, + OrnamentationType.SequencedThirds }; // act @@ -119,7 +121,9 @@ public void Randomize_dispatches_expected_actions() { OrnamentationType.OctavePedalArpeggio, new OrnamentationConfiguration(OrnamentationType.OctavePedalArpeggio, ConfigurationStatus.Enabled, 100) }, { OrnamentationType.UpperOctavePedal, new OrnamentationConfiguration(OrnamentationType.UpperOctavePedal, ConfigurationStatus.Enabled, 100) }, { OrnamentationType.UpperOctavePedalPassingTone, new OrnamentationConfiguration(OrnamentationType.UpperOctavePedalPassingTone, ConfigurationStatus.Enabled, 100) }, - { OrnamentationType.UpperOctavePedalArpeggio, new OrnamentationConfiguration(OrnamentationType.UpperOctavePedalArpeggio, ConfigurationStatus.Enabled, 100) } + { OrnamentationType.UpperOctavePedalArpeggio, new OrnamentationConfiguration(OrnamentationType.UpperOctavePedalArpeggio, ConfigurationStatus.Enabled, 100) }, + { OrnamentationType.TriplePickup, new OrnamentationConfiguration(OrnamentationType.TriplePickup, ConfigurationStatus.Enabled, 100) }, + { OrnamentationType.SequencedThirds, new OrnamentationConfiguration(OrnamentationType.SequencedThirds, ConfigurationStatus.Enabled, 100) } }; _mockState.Value.Returns(new CompositionOrnamentationConfigurationState(configurations));