Last active
February 24, 2021 12:22
-
-
Save melanchall/d4142f5f0fb36ab86e46110d69966fed to your computer and use it in GitHub Desktop.
Creating a MIDI file with the DryWetMIDI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void CreateMidiFile() | |
{ | |
// Create an empty MIDI file | |
var midiFile = new MidiFile(); | |
// Set tempo map of the file using tempo of 110 BPM. See | |
// https://github.com/melanchall/drywetmidi/wiki/Tempo-map to learn more about managing | |
// tempo map in DryWetMIDI | |
var tempoMap = TempoMap.Create(Tempo.FromBeatsPerMinute(110)); | |
midiFile.ReplaceTempoMap(tempoMap); | |
// Add first track chunk to the file | |
var trackChunk1 = BuildFirstTrackChunk(tempoMap); | |
midiFile.Chunks.Add(trackChunk1); | |
// Add second track chunk to the file | |
var trackChunk2 = BuildSecondTrackChunk(tempoMap); | |
midiFile.Chunks.Add(trackChunk2); | |
// Write MIDI data to file. See https://github.com/melanchall/drywetmidi/wiki/Writing-a-MIDI-file | |
// to learn more | |
midiFile.Write("Path to the Greatest MIDI File ever.mid"); | |
} | |
private static TrackChunk BuildFirstTrackChunk(TempoMap tempoMap) | |
{ | |
// We are going to create the first track chunk using PatternBuilder | |
// class which provides fluent interface to program music. See | |
// https://github.com/melanchall/drywetmidi/wiki/Pattern to learn more about features | |
// provided by pattern building API | |
var trackChunk = new PatternBuilder() | |
// All following notes will have eighth length (if length is not | |
// specified explicitly as an argument of corresponding methods) | |
.SetNoteLength(MusicalTimeSpan.Eighth) | |
// Insert A2 and A3 and repeat them one time so four notes totally | |
// will be inserted (A2 A3 A2 A3) | |
.Note(OctaveDefinition.Get(2).A) | |
.Note(OctaveDefinition.Get(3).A) | |
.Repeat(2, 1) | |
// All following notes will have length of 2 seconds (if length is not | |
// specified explicitly as an argument of corresponding methods) | |
.SetNoteLength(new MetricTimeSpan(0, 0, 2)) | |
// All following intervals will be calculated relative to C4 | |
.SetRootNote(NoteDefinition.Get(NoteName.C, 4)) // or OctaveDefinition.Get(4).C | |
// Insert notes by intervals relative to the root note set before | |
.Note(IntervalDefinition.Nine) // C4 + 9 | |
.Note(IntervalDefinition.Seven) // C4 + 7 | |
.Note(-IntervalDefinition.One) // C4 - 1 | |
.Note(IntervalDefinition.Three) // C4 + 3 | |
// Insert a pause with length of 2 bars | |
.StepForward(new BarBeatTimeSpan(2, 0)) | |
// Insert a chord defined by intervals relative to the root note specified | |
// as an argument of Chord method (B2) | |
.Chord(new[] | |
{ | |
IntervalDefinition.Two, // B2 + 2 | |
IntervalDefinition.Three, // B2 + 3 | |
-IntervalDefinition.Twelve, // B2 - 12 | |
}, | |
OctaveDefinition.Get(2).B) | |
// Insert a pause of single dotted triplet half length | |
.StepForward(MusicalTimeSpan.Half.Triplet().SingleDotted()) | |
// Insert a chord defined by the specified notes | |
.Chord(new[] | |
{ | |
NoteDefinition.Get(NoteName.B, 3), // B3 | |
NoteDefinition.Get(NoteName.C, 4), // C4 | |
}) | |
// Build pattern into an instance of the Pattern class | |
.Build() | |
// Export the pattern to track chunk | |
.ToTrackChunk(tempoMap); | |
// Add Program Change event to specify an instrument used to play the track chunk. | |
// See https://github.com/melanchall/drywetmidi/wiki/Events-absolute-time to learn more | |
// about managing events by absolute time | |
using (var timedEventsManager = trackChunk.ManageTimedEvents()) | |
{ | |
timedEventsManager.Events.AddEvent( | |
new ProgramChangeEvent((SevenBitNumber)26), // 'Acoustic Guitar (steel)' in GM | |
time: 0); | |
} | |
return trackChunk; | |
} | |
private static TrackChunk BuildSecondTrackChunk(TempoMap tempoMap) | |
{ | |
// We can create a track chunk and put events in it via its constructor | |
var trackChunk = new TrackChunk( | |
new ProgramChangeEvent((SevenBitNumber)1)); // 'Acoustic Grand Piano' in GM | |
// Insert notes via NotesManager class. See https://github.com/melanchall/drywetmidi/wiki/Notes | |
// to learn more about managing notes | |
using (var notesManager = trackChunk.ManageNotes()) | |
{ | |
var notes = notesManager.Notes; | |
// Convert time span of 1 minute and 30 seconds to MIDI ticks. See | |
// https://github.com/melanchall/drywetmidi/wiki/Time-and-length to learn more | |
// about time and length representations and conversion between them | |
var oneAndHalfMinute = TimeConverter.ConvertFrom(new MetricTimeSpan(0, 1, 30), tempoMap); | |
// Insert two notes: | |
// - A2 with length of 4/15 at 1 minute and 30 seconds from a file start | |
// - B4 with length of 4 beats (1 beat = 1 quarter length at this case) at the start of a file | |
notes.Add(new Note(noteName: NoteName.A, | |
octave: 2, | |
length: LengthConverter.ConvertFrom(new MusicalTimeSpan(4, 15), | |
time: oneAndHalfMinute, | |
tempoMap: tempoMap), | |
time: oneAndHalfMinute), | |
new Note(noteName: NoteName.B, | |
octave: 4, | |
length: LengthConverter.ConvertFrom(new BarBeatTimeSpan(0, 4), | |
time: 0, | |
tempoMap: tempoMap), | |
time: 0)); | |
} | |
// Insert chords via ChordsManager class. See https://github.com/melanchall/drywetmidi/wiki/Chords | |
// to learn more about managing chords | |
using (var chordsManager = trackChunk.ManageChords()) | |
{ | |
var chords = chordsManager.Chords; | |
// Define notes for a chord: | |
// - C2 with length of 30 seconds and 600 milliseconds | |
// - C#3 with length of 300 milliseconds | |
var notes = new[] | |
{ | |
new Note(noteName: NoteName.C, | |
octave: 2, | |
length: LengthConverter.ConvertFrom(new MetricTimeSpan(0, 0, 30, 600), | |
time: 0, | |
tempoMap: tempoMap)), | |
new Note(noteName: NoteName.CSharp, | |
octave: 3, | |
length: LengthConverter.ConvertFrom(new MetricTimeSpan(0, 0, 0, 300), | |
time: 0, | |
tempoMap: tempoMap)) | |
}; | |
// Insert the chord at different times: | |
// - at the start of a file | |
// - at 10 bars and 2 beats from a file start | |
// - at 10 hours from a file start | |
chords.Add(new Chord(notes, | |
time: 0), | |
new Chord(notes, | |
time: TimeConverter.ConvertFrom(new BarBeatTimeSpan(10, 2), | |
tempoMap)), | |
new Chord(notes, | |
time: TimeConverter.ConvertFrom(new MetricTimeSpan(10, 0, 0), | |
tempoMap))); | |
} | |
return trackChunk; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment