# import packages using DigitalMusicology using DataFrames using Plots # A4 is set to 440Hz frequency_to_pitch(f) = 69 + 12 * log2(f / 440) pitch_to_frequency(p) = 2^((p - 69) / 12) * 440 # the frequency of C4 pitch_to_frequency(60) # the lowest midi note has a frequency of about 8Hz, # the highest about 13kHz # humans typically hear between 20Hz and 20kHz pitch_to_frequency(0), pitch_to_frequency(127) notes = midifilenotes("Run_To_The_Hills.mid") head(notes) notes[:key_sharps] |> unique ?midifilenotes # this is a small pipeline notes[:track] |> unique |> sort # it is equivalent to sort(unique(notes[:track])) track_names = ["meta", "vocals", "vocal harmony", "guitar 1", "guitar 2", "bass", "drums"] # drums in first bar # there are 192 ticks per quarter note notes[1:20, [:onset_wholes, :onset_ticks]] # select the the instruments other than the drums not_percussive_notes = notes[notes[:track] .!= 7, :] head(not_percussive_notes) # convert midi notes to pitch numbers pitches = [note.pitch for note in not_percussive_notes[:pitch]] pitches[1:10] # plot pitch histogram histogram(pitches, bins=collect(0:127)) # plot pitch class histogram pitch_classes = [mod(p, 12) for p in pitches] xticks = (collect(0:11) .+ 0.5, collect(0:11)) histogram(pitch_classes, bins=12, xticks=xticks) # shift the histogram so that the most prominent note is in front shifted_xticks = (collect(0:11) .+ 0.5, [mod(pc+7, 12) for pc in 0:11]) histogram( [mod(pc-7, 12) for pc in pitch_classes], bins=12, xticks=shifted_xticks ) transform(p) = mod((p+4)*7, 12) histogram( transform.(pitch_classes), bins = 12, xticks = (transform.(collect(0:11)) .+ 0.5, (collect(0:11))), xlim = (0,12) ) for track in 2:6 display( histogram( [mod(note.pitch, 12) for note in notes[notes[:track] .== track, :pitch]], bins = collect(0:12), xticks = xticks, title = track_names[track], xlim = (0,12) ) ) end onsets = notes[notes[:track] .== 4, :onset_wholes] offsets = notes[notes[:track] .== 4, :offset_wholes] durations = offsets - onsets [(d.num + 1) // d.den for d in durations] for track in 2:6 onsets = notes[notes[:track] .== track, :onset_wholes] offsets = notes[notes[:track] .== track, :offset_wholes] durations = offsets - onsets display(histogram([(d.num + 1) // d.den for d in durations], title=track_names[track])) end for track in 2:6 onsets = notes[notes[:track] .== track, :onset_wholes] display( histogram( [o - floor(o) for o in onsets], bins = [x*1/16 for x in 0:16], title = track_names[track] ) ) end