Skip to content

Instantly share code, notes, and snippets.

@dtinth
Last active December 4, 2015 18:56
Show Gist options
  • Save dtinth/b15fd8b1dbba79d0d5fd to your computer and use it in GitHub Desktop.
Save dtinth/b15fd8b1dbba79d0d5fd to your computer and use it in GitHub Desktop.
# Requirements:
# 1. Install Ruby
# 2. gem install midilib
#
# To run:
#
# ruby split-notes.rb <file.mid> <number-of-parts>
require 'midilib'
name = ARGV[0]
raise "#{name} not exist" unless File.exist? name
parts_count = ARGV[1].to_i
raise "#{parts_count} must be more than 0" unless parts_count > 0
out_name = name.sub(/(?:_src)?(?:\.\w+)?$/, '')
seq = MIDI::Sequence.new()
File.open(name, 'rb') { |io| seq.read(io) }
parts = (1..parts_count).to_a
event_part = { }.compare_by_identity
seq.each do |track|
usage = Hash.new(-1)
using = Hash.new(false)
note_part = { }
track.each do |event|
case event
when MIDI::NoteOn
usable_parts = parts.select { |part| !using[part] }
raise "No usable part!" if usable_parts.empty?
part = usable_parts.min_by { |id| usage[id] }
usage[part] = event.time_from_start
using[part] = true
note_part[event.note] = part
event_part[event] = part
when MIDI::NoteOff
part = note_part[event.note] or raise "Part not found!"
using[part] = false
event_part[event] = part
end
end
end
parts.each do |part|
out = seq.dup
out.tracks = out.tracks.map { |track|
out_track = track.dup
out_track.events = out_track.events.reject { |event| event_part.include?(event) && event_part[event] != part }
out_track.recalc_delta_from_times
out_track
}
out_part_name = "#{out_name}_part#{part}.mid"
puts out_part_name
File.open(out_part_name, 'wb') { |io| out.write io }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment