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 <: AbstractNote
Mutable 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_pitch
andpitch_to_name
for 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)):")
notes
177 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 = 713
Pitch to Int
convertion
MIDI.name_to_pitch
— Functionname_to_pitch(p::String) -> Int
Return 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) -> string
Return 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).