Skip to content

Commit

Permalink
Added ControlChange method to PatternBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Aug 17, 2024
1 parent 6cbb5d6 commit 31c21f5
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Composing;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Interaction;
using Melanchall.DryWetMidi.MusicTheory;
using NUnit.Framework;

namespace Melanchall.DryWetMidi.Tests.Composing
{
[TestFixture]
public sealed partial class PatternBuilderTests
{
#region Test methods

[Test]
public void ControlChange_1()
{
var controlNumber = (SevenBitNumber)10;
var controlValue = (SevenBitNumber)70;
var eventTime = MusicalTimeSpan.Quarter;

var pattern = new PatternBuilder()

.Note(NoteName.A, eventTime)
.ControlChange(controlNumber, controlValue)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ControlChangeEvent(controlNumber, controlValue) { Channel = PatternTestUtilities.Channel }, eventTime)
});
}

[Test]
public void ControlChange_2()
{
var controlNumber1 = (SevenBitNumber)10;
var controlValue1 = (SevenBitNumber)70;
var noteLength1 = MusicalTimeSpan.Quarter;

var controlNumber2 = (SevenBitNumber)15;
var controlValue2 = (SevenBitNumber)55;
var noteLength2 = MusicalTimeSpan.Sixteenth;

var pattern = new PatternBuilder()

.Note(NoteName.A, noteLength1)
.ControlChange(controlNumber1, controlValue1)
.Note(NoteName.CSharp, noteLength2)
.ControlChange(controlNumber2, controlValue2)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ControlChangeEvent(controlNumber1, controlValue1) { Channel = PatternTestUtilities.Channel }, noteLength1),
new TimedEventInfo(new ControlChangeEvent(controlNumber2, controlValue2) { Channel = PatternTestUtilities.Channel }, noteLength1 + noteLength2),
});
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,85 +16,6 @@ public sealed partial class PatternBuilderTests
{
#region Test methods

#region ProgramChange

[Test]
public void ProgramChange_Number()
{
var programNumber = (SevenBitNumber)10;
var eventTime = MusicalTimeSpan.Quarter;

var pattern = new PatternBuilder()

.Note(NoteName.A, eventTime)
.ProgramChange(programNumber)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ProgramChangeEvent(programNumber) { Channel = PatternTestUtilities.Channel }, eventTime)
});
}

[Test]
public void ProgramChange_GeneralMidiProgram()
{
var program1 = GeneralMidiProgram.Applause;
var program2 = GeneralMidiProgram.AltoSax;
var eventTime = MusicalTimeSpan.Quarter;

var noteNumber = (SevenBitNumber)100;
var note = DryWetMidi.MusicTheory.Note.Get(noteNumber);

var pattern = new PatternBuilder()

.ProgramChange(program1)
.Note(note, eventTime)
.ProgramChange(program2)

.Build();

PatternTestUtilities.TestTimedEventsWithExactOrder(pattern, new[]
{
new TimedEventInfo(new ProgramChangeEvent(program1.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, new MidiTimeSpan()),
new TimedEventInfo(new NoteOnEvent(noteNumber, DryWetMidi.Interaction.Note.DefaultVelocity) { Channel = PatternTestUtilities.Channel }, new MidiTimeSpan()),
new TimedEventInfo(new ProgramChangeEvent(program2.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, eventTime),
new TimedEventInfo(new NoteOffEvent(noteNumber, SevenBitNumber.MinValue) { Channel = PatternTestUtilities.Channel }, eventTime)
});
}

[Test]
public void ProgramChange_GeneralMidi2Program()
{
var eventsTime = MusicalTimeSpan.Quarter;

var bankMsbControlNumber = ControlName.BankSelect.AsSevenBitNumber();
var bankMsb = (SevenBitNumber)0x79;

var bankLsbControlNumber = ControlName.LsbForBankSelect.AsSevenBitNumber();
var bankLsb = (SevenBitNumber)0x03;

var generalMidiProgram = GeneralMidiProgram.BirdTweet;
var generalMidi2Program = GeneralMidi2Program.BirdTweet2;

var pattern = new PatternBuilder()

.Note(NoteName.A, eventsTime)
.ProgramChange(generalMidi2Program)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ControlChangeEvent(bankMsbControlNumber, bankMsb) { Channel = PatternTestUtilities.Channel }, eventsTime),
new TimedEventInfo(new ControlChangeEvent(bankLsbControlNumber, bankLsb) { Channel = PatternTestUtilities.Channel }, eventsTime),
new TimedEventInfo(new ProgramChangeEvent(generalMidiProgram.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, eventsTime),
});
}

#endregion

#region ReplayPattern

[Test]
Expand Down Expand Up @@ -213,6 +134,7 @@ public void ClonePatternAction_TypeIsCorrect()
{
PatternAction patternAction = null;

// TODO: randomize values
if (type == typeof(AddChordAction))
patternAction = new AddChordAction(new ChordDescriptor(Enumerable.Empty<DryWetMidi.MusicTheory.Note>(), SevenBitNumber.MinValue, MusicalTimeSpan.Eighth));
else if (type == typeof(AddNoteAction))
Expand All @@ -221,6 +143,8 @@ public void ClonePatternAction_TypeIsCorrect()
patternAction = new AddPatternAction(new PatternBuilder().Build());
else if (type == typeof(AddTextEventAction<>))
patternAction = new AddTextEventAction<TextEvent>(string.Empty);
else if (type == typeof(AddControlChangeEventAction))
patternAction = new AddControlChangeEventAction((SevenBitNumber)70, (SevenBitNumber)30);
else if (type == typeof(MoveToAnchorAction))
patternAction = new MoveToAnchorAction(AnchorPosition.First);
else if (type == typeof(SetGeneralMidi2ProgramAction))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Composing;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Interaction;
using Melanchall.DryWetMidi.MusicTheory;
using Melanchall.DryWetMidi.Standards;
using NUnit.Framework;

namespace Melanchall.DryWetMidi.Tests.Composing
{
[TestFixture]
public sealed partial class PatternBuilderTests
{
#region Test methods

[Test]
public void ProgramChange_Number()
{
var programNumber = (SevenBitNumber)10;
var eventTime = MusicalTimeSpan.Quarter;

var pattern = new PatternBuilder()

.Note(NoteName.A, eventTime)
.ProgramChange(programNumber)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ProgramChangeEvent(programNumber) { Channel = PatternTestUtilities.Channel }, eventTime)
});
}

[Test]
public void ProgramChange_GeneralMidiProgram()
{
var program1 = GeneralMidiProgram.Applause;
var program2 = GeneralMidiProgram.AltoSax;
var eventTime = MusicalTimeSpan.Quarter;

var noteNumber = (SevenBitNumber)100;
var note = DryWetMidi.MusicTheory.Note.Get(noteNumber);

var pattern = new PatternBuilder()

.ProgramChange(program1)
.Note(note, eventTime)
.ProgramChange(program2)

.Build();

PatternTestUtilities.TestTimedEventsWithExactOrder(pattern, new[]
{
new TimedEventInfo(new ProgramChangeEvent(program1.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, new MidiTimeSpan()),
new TimedEventInfo(new NoteOnEvent(noteNumber, DryWetMidi.Interaction.Note.DefaultVelocity) { Channel = PatternTestUtilities.Channel }, new MidiTimeSpan()),
new TimedEventInfo(new ProgramChangeEvent(program2.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, eventTime),
new TimedEventInfo(new NoteOffEvent(noteNumber, SevenBitNumber.MinValue) { Channel = PatternTestUtilities.Channel }, eventTime)
});
}

[Test]
public void ProgramChange_GeneralMidi2Program()
{
var eventsTime = MusicalTimeSpan.Quarter;

var bankMsbControlNumber = ControlName.BankSelect.AsSevenBitNumber();
var bankMsb = (SevenBitNumber)0x79;

var bankLsbControlNumber = ControlName.LsbForBankSelect.AsSevenBitNumber();
var bankLsb = (SevenBitNumber)0x03;

var generalMidiProgram = GeneralMidiProgram.BirdTweet;
var generalMidi2Program = GeneralMidi2Program.BirdTweet2;

var pattern = new PatternBuilder()

.Note(NoteName.A, eventsTime)
.ProgramChange(generalMidi2Program)

.Build();

PatternTestUtilities.TestTimedEvents(pattern, new[]
{
new TimedEventInfo(new ControlChangeEvent(bankMsbControlNumber, bankMsb) { Channel = PatternTestUtilities.Channel }, eventsTime),
new TimedEventInfo(new ControlChangeEvent(bankLsbControlNumber, bankLsb) { Channel = PatternTestUtilities.Channel }, eventsTime),
new TimedEventInfo(new ProgramChangeEvent(generalMidiProgram.AsSevenBitNumber()) { Channel = PatternTestUtilities.Channel }, eventsTime),
});
}

#endregion
}
}
47 changes: 47 additions & 0 deletions DryWetMidi/Composing/Actions/AddControlChangeEventAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Interaction;

namespace Melanchall.DryWetMidi.Composing
{
internal sealed class AddControlChangeEventAction : PatternAction
{
#region Constructor

public AddControlChangeEventAction(SevenBitNumber controlNumber, SevenBitNumber controlValue)
{
ControlNumber = controlNumber;
ControlValue = controlValue;
}

#endregion

#region Properties

public SevenBitNumber ControlNumber { get; }

public SevenBitNumber ControlValue { get; }

#endregion

#region Overrides

public override PatternActionResult Invoke(long time, PatternContext context)
{
if (State != PatternActionState.Enabled)
return PatternActionResult.DoNothing;

var controlChangeEvent = new ControlChangeEvent(ControlNumber, ControlValue) { Channel = context.Channel };
var timedEvent = new TimedEvent(controlChangeEvent, time);

return new PatternActionResult(time, new[] { timedEvent });
}

public override PatternAction Clone()
{
return new AddControlChangeEventAction(ControlNumber, ControlValue);
}

#endregion
}
}
16 changes: 16 additions & 0 deletions DryWetMidi/Composing/PatternBuilder.ControlChange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Melanchall.DryWetMidi.Common;

namespace Melanchall.DryWetMidi.Composing
{
public sealed partial class PatternBuilder
{
#region Methods

public PatternBuilder ControlChange(SevenBitNumber controlNumber, SevenBitNumber controlValue)
{
return AddAction(new AddControlChangeEventAction(controlNumber, controlValue));
}

#endregion
}
}

0 comments on commit 31c21f5

Please sign in to comment.