Skip to content

List the Notes a Pattern Plays

notes() lists what a pattern, timeline, MIDI track or array of MIDI tracks plays. It reads the same notes midi_export() writes to a file, and plays nothing. Its signature and fields are in the audio reference. To see a pattern as a grid instead, use viz().

Give the source and the number of cycles, and print the result with to_json():

print(to_json(notes([C4 [E4 G4]], 1)));

The output is one line:

[{"channel":1,"duration":0.5,"duration_seconds":1,"name":"C4","note":60,"start":0,"start_seconds":0,"velocity":100},{"channel":1,"duration":0.25,"duration_seconds":0.5,"name":"E4","note":64,"start":0.5,"start_seconds":1,"velocity":100},{"channel":1,"duration":0.25,"duration_seconds":0.5,"name":"G4","note":67,"start":0.75,"start_seconds":1.5,"velocity":100}]

start and duration are in cycles. start_seconds and duration_seconds are at the current tempo, here 120 BPM. Notes are sorted by start, then pitch, and the keys of each note are in sorted order, so the same piece always prints the same text.

The notes of a chord start together, lowest first:

print(to_json(notes([C4:maj _], 1)));
[{"channel":1,"duration":0.5,"duration_seconds":1,"name":"C4","note":60,"start":0,"start_seconds":0,"velocity":100},{"channel":1,"duration":0.5,"duration_seconds":1,"name":"E4","note":64,"start":0,"start_seconds":0,"velocity":100},{"channel":1,"duration":0.5,"duration_seconds":1,"name":"G4","note":67,"start":0,"start_seconds":0,"velocity":100}]

A drum hit names its sample in place of a note. It has no channel, because it plays a sample:

print(to_json(notes([bd _ sd bd^60], 1)));
[{"duration":0.25,"duration_seconds":0.5,"sample":"bd","start":0,"start_seconds":0,"velocity":100},{"duration":0.25,"duration_seconds":0.5,"sample":"sd","start":0.5,"start_seconds":1,"velocity":100},{"duration":0.25,"duration_seconds":0.5,"sample":"bd","start":0.75,"start_seconds":1.5,"velocity":60}]

Pass a track to get its channel, its default velocity and its key, as it plays them. Each note names the track. Add a start cycle as the last argument:

let bass = MidiTrack("bass").set_velocity(90);
bass >> MidiOutput("synth", 2);
bass << [C2 _ G2 _];
print(to_json(notes(bass, 1, 1)));
[{"channel":2,"duration":0.25,"duration_seconds":0.5,"name":"C2","note":36,"start":1,"start_seconds":2,"track":"bass","velocity":90},{"channel":2,"duration":0.25,"duration_seconds":0.5,"name":"G2","note":43,"start":1.5,"start_seconds":3,"track":"bass","velocity":90}]

An array of tracks lists all their notes in one list. A track with a velocity signal is run over the span, as midi_export() runs it, so playback pauses while it is listed. CC and pitch bend are not listed.

notes() returns an Array of Dicts, so a piece can read it directly:

let listed = notes([C4 E4 G4 C5], 4);
print(listed.length()); // 16
print(listed[0]["name"]); // C4