Skip to content

Instantly share code, notes, and snippets.

@CoralineAda
Last active April 11, 2025 17:27
Show Gist options
  • Save CoralineAda/3f559279caa892a46fa2ee26fc62b339 to your computer and use it in GitHub Desktop.
Save CoralineAda/3f559279caa892a46fa2ee26fc62b339 to your computer and use it in GitHub Desktop.
# Put your .mid file in a "midi" directory next to this file.
# Then, in your terminal in the directory that this file is in:
# gem install midilib
# ruby ./midisort.rb
# The _sorted MIDI file is now in the "midi" directory.
require 'midilib'
sequence = MIDI::Sequence.new()
# Read the contents of a MIDI file into the sequence.
filename = Dir.glob('./midi/*.mid').first
File.open("#{filename}", 'rb') do |file|
sequence.read(file)
end
notes = []
sequence.each do |track|
events = track.events
events.each_with_index do |event, i|
next unless event.is_a?(MIDI::NoteEvent)
if event.respond_to?(:off)
notes << {
note: event.note,
note_name: MIDI::Utils.note_to_s(event.note),
duration: event.off.time_from_start - event.time_from_start
}
end
end
end
# Explore variations by uncommenting a different sorting algorithm. Only one uncommented at a time!
# Randomize
sorted_notes = notes.sort{ |a,b| rand(1) <=> rand(1) }
# Sort by octave-agnostic note names
#sorted_notes = notes.sort{ |a,b| "#{a[:note_name]}" <=> "#{b[:note_name]}" }
# Sort by octave-aware note names
#sorted_notes = notes.sort{ |a,b| "#{a[:note_name]}-#{a[:note]}" <=> "#{b[:note_name]}-#{b[:note]}" }
# Sort by octave-aware note names and durations
#sorted_notes = notes.sort{ |a,b| "#{a[:note_name]}-#{a[:note]}-#{a[:duration]}" <=> "#{b[:note_name]}-#{b[:note]}-#{b[:duration]}" }
sequence.each do |track|
track.each do |event|
next unless event.is_a?(MIDI::NoteEvent)
if event.respond_to?(:off)
note = sorted_notes.pop
event.note = note[:note]
event.off.note = note[:note]
event.off.time_from_start = event.off.time_from_start - event.time_from_start
end
track.recalc_times
end
end
output_filename = filename.gsub(".mid", "_sorted.mid")
File.open(output_filename, 'wb') do |file|
sequence.write(file)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment