Notes
Note information in MIDI files is typically encoded using NOTEON and NOTEOFF events. A music note however contains more information besides the start and end; we bundle this information into the types Note and Notes. These two structures are central to the way JuliaMusic operates. In addition, all note events of a MIDITrack can be obtained with the function getnotes.
MIDI.Note — TypeNote <: AbstractNoteMutable data structure describing a "music note". A bundle of many notes results in the Notes struct, which is the output of the getnotes function.
Fields:
pitch::UInt8: Pitch, starting from C-1 = 0, adding one per semitone. Use the functionsname_to_pitchandpitch_to_namefor integer and string representations.velocity::UInt8: Dynamic intensity. Cannot be higher than 127 (0x7F).position::UInt: Position in absolute time (since beginning of track), in ticks.duration::UInt: Duration in ticks.channel::UInt8 = 0: Channel of the track that the note is played on. Cannot be higher than 127 (0x7F).
If the channel of the note is 0 (default) it is not printed with show.
MIDI.Notes — TypeNotes{N<:AbstractNote}Data structure describing a collection of "music notes", bundled with a ticks per quarter note measure.
Fields:
notes::Vector{N} where {N <: Notes}tpq::Int16: Ticks per quarter note. Defines the fundamental unit of measurement of a note's position and duration, as well as the length of one quarter note. Takes values from 1 to 960.
Notes is iterated and accessed as if iterating or accessing its field notes.
MIDI.getnotes — Functiongetnotes(midi::MIDIFile [, trackno])Find all NOTEON and NOTEOFF midi events in the trackno track of a midi (default 1 or 2), that correspond to the same note value (pitch) and convert them into the Note datatype. There are special cases where NOTEOFF is actually encoded as NOTEON with 0 velocity, but getnotes takes care of this.
Notice that the first track of a midi typically doesn't have any notes, which is why the function defaults to track 2.
getnotes(track::MIDITrack, tpq = 960)Find the notes from track directly, passing also the ticks per quarter note.
Returns: Notes{Note}, setting the ticks per quarter note as tpq. You can find the originally exported ticks per quarter note from the original MIDIFile through midi.tpq.
If you have some notes and you want to add them to a track, use
MIDI.addnotes! — Functionaddnotes!(track::MIDITrack, notes)Add given notes to given track, internally doing all translations from absolute time to relative time.
Finally, you can use the function getnotnotes(track) to get all TrackEvents that are not NOTEON or NOTEOFF.
Write Example
using MIDI
C = Note(60, 96, 0, 192)
E = Note(64, 96, 48, 144)
G = Note(67, 96, 96, 96)
inc = 192
file = MIDIFile()
track = MIDITrack()
notes = Notes() # tpq automatically = 960
push!(notes, C)
push!(notes, E)
push!(notes, G)
# Notes one octave higher
C = Note(60 + 12, 96, C.position+inc, 192)
E = Note(64 + 12, 96, E.position+inc, 144)
G = Note(67 + 12, 96, G.position+inc, 96)
addnotes!(track, notes)
addtrackname!(track, "simple track")
push!(file.tracks, track)
writeMIDIFile("test.mid", file)Read Example
using MIDI
midi = readMIDIFile(testmidi())MIDIFile (format=1, tpq=960) with tracks:
American Rock Beat 06 Tom
Drums
Bass
ORIGINAL
# Track number 3 is a quantized bass MIDI track
bass = midi.tracks[3]
notes = getnotes(bass, midi.tpq)
println("Notes of track $(trackname(bass)):")
notes177 Notes with tpq=960
Note A♯2 | vel = 95 | pos = 7680, dur = 690
Note A♯2 | vel = 71 | pos = 9280, dur = 308
Note G♯2 | vel = 52 | pos = 9600, dur = 668
Note G♯2 | vel = 58 | pos = 11200, dur = 338
Note G2 | vel = 71 | pos = 11520, dur = 701
Note G♯2 | vel = 83 | pos = 13120, dur = 281
Note G2 | vel = 73 | pos = 13440, dur = 855
⋮
Note F♯1 | vel = 73 | pos = 185280, dur = 878
Note F1 | vel = 85 | pos = 186240, dur = 964
Note A1 | vel = 88 | pos = 187200, dur = 904
Note A♯1 | vel = 81 | pos = 188160, dur = 900
Note B1 | vel = 77 | pos = 189120, dur = 945
Note C2 | vel = 83 | pos = 190080, dur = 847
Note F2 | vel = 90 | pos = 191040, dur = 713Pitch to Int convertion
MIDI.name_to_pitch — Functionname_to_pitch(p::String) -> IntReturn the pitch value of the given note name p, which can be of the form capital_letter*sharp*octave where:
capital_letter: from"A"to"G".sharp: one of"#""♯"or"".octave: any integer (as a string), the octave number (an octave is 12 pitches). If not given it is assumed"5".
We define E.g. name_to_pitch("C4") === 60 (i.e. string "C4", representing the middle-C, corresponds to pitch 60).
See http://newt.phys.unsw.edu.au/jw/notes.html and https://en.wikipedia.org/wiki/C(musicalnote) .
MIDI.pitch_to_name — Functionpitch_to_name(pitch) -> stringReturn the name of the pitch, e.g. F5, A♯3 etc. in modern notation given the pitch value in integer.
Reminder: middle C has pitch 60 and is displayed as C4.
MusicManipulations.note_to_fundamental — Functionnote_to_fundamental(note(s))Return a String or Vector{String} with the fundamental pitch of the notes (i.e. without the octave information).