Class: MTK::IO::MIDIFile
- Inherits:
-
Object
- Object
- MTK::IO::MIDIFile
- Defined in:
- lib/mtk/io/midi_file.rb
Overview
Note:
This class is optional and only available if you require ‘mtk/midi/file’. It depends on the ‘midilib’ gem.
MIDI file I/O: reads MIDI files into Events::Timelines and writes Events::Timelines to MIDI files.
Instance Method Summary collapse
-
#initialize(file) ⇒ MIDIFile
constructor
A new instance of MIDIFile.
-
#to_timelines ⇒ Timeline
Read a MIDI file into an Array of Events::Timelines.
- #write(anything) ⇒ Object
-
#write_timeline(timeline, parent_sequence = nil) ⇒ Object
Write the Timeline as a MIDI file.
- #write_timelines(timelines, parent_sequence = nil) ⇒ Object
Constructor Details
#initialize(file) ⇒ MIDIFile
Returns a new instance of MIDIFile.
10 11 12 13 14 15 16 |
# File 'lib/mtk/io/midi_file.rb', line 10 def initialize file if file.respond_to? :path @file = file.path else @file = file.to_s end end |
Instance Method Details
#to_timelines ⇒ Timeline
Read a MIDI file into an Array of Events::Timelines
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/mtk/io/midi_file.rb', line 22 def to_timelines timelines = [] ::File.open(@file, 'rb') do |f| sequence = ::MIDI::Sequence.new sequence.read(f) pulses_per_beat = sequence.ppqn.to_f track_idx = -1 sequence.each do |track| track_idx += 1 timeline = MTK::Events::Timeline.new note_ons = {} #puts "TRACK #{track_idx}" track.each do |event| #puts "#{event.class}: #{event} @#{event.time_from_start}" time = (event.time_from_start)/pulses_per_beat case event when ::MIDI::NoteOn note_ons[event.note] = [time,event] when ::MIDI::NoteOff on_time,on_event = note_ons.delete(event.note) if on_event duration = time - on_time note = MTK::Events::Note.from_midi(event.note, on_event.velocity, duration, event.channel) timeline.add on_time, note end when ::MIDI::Controller, ::MIDI::PolyPressure, ::MIDI::ChannelPressure, ::MIDI::PitchBend, ::MIDI::ProgramChange timeline.add time, MTK::Events::Parameter.from_midi(*event.data_as_bytes) when ::MIDI::Tempo # Not sure if event.tempo needs to be converted? TODO: test! timeline.add time, MTK::Events::Parameter.new(:tempo, :value => event.tempo) end end timelines << timeline end end timelines end |
#write(anything) ⇒ Object
67 68 69 70 71 72 73 |
# File 'lib/mtk/io/midi_file.rb', line 67 def write(anything) case anything when MTK::Events::Timeline then write_timeline(anything) when Enumerable then write_timelines(anything) else raise "#{self.class}#write doesn't understand #{anything.class}" end end |
#write_timeline(timeline, parent_sequence = nil) ⇒ Object
Write the Timeline as a MIDI file
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/mtk/io/midi_file.rb', line 84 def write_timeline(timeline, parent_sequence=nil) sequence = parent_sequence || ::MIDI::Sequence.new clock_rate = sequence.ppqn track = add_track sequence timeline.each do |time,events| time *= clock_rate events.each do |event| next if event.rest? channel = (event.channel || 1) - 1 # midilib seems to count channels from 0, hence the -1 case event.type when :note pitch, velocity = event.midi_pitch, event.velocity add_event track, time => note_on(channel, pitch, velocity) duration = event.duration_in_pulses(clock_rate) add_event track, time+duration => note_off(channel, pitch, velocity) when :control add_event track, time => cc(channel, event.number, event.midi_value) when :pressure if event.number add_event track, time => poly_pressure(channel, event.number, event.midi_value) else add_event track, time => channel_pressure(channel, event.midi_value) end when :bend add_event track, time => pitch_bend(channel, event.midi_value) when :program add_event track, time => program(channel, event.midi_value) when :tempo add_event track, time => tempo(event.value) end end end track.recalc_delta_from_times write_to_disk sequence unless parent_sequence end |
#write_timelines(timelines, parent_sequence = nil) ⇒ Object
75 76 77 78 79 |
# File 'lib/mtk/io/midi_file.rb', line 75 def write_timelines(timelines, parent_sequence=nil) sequence = parent_sequence || ::MIDI::Sequence.new timelines.each{|timeline| write_timeline(timeline, sequence) } write_to_disk sequence unless parent_sequence end |