Class: MIDI::IO::SeqReader
Overview
Reads MIDI files. As a subclass of MIDIFile, this class implements the callback methods for each MIDI event and use them to build Track and Event objects and give the tracks to a Sequence.
Ensures that each track ends with an end of track meta event, and that Track#recalc_times is called at the end of the track so it can update each event with its time from the track’s start (see end_track below).
Constant Summary
Constants inherited
from MIDIFile
MIDIFile::MThd_BYTE_ARRAY, MIDIFile::MTrk_BYTE_ARRAY, MIDIFile::NUM_DATA_BYTES
Instance Attribute Summary
Attributes inherited from MIDIFile
#bytes_to_be_read, #curr_ticks, #no_merge, #raw_data, #raw_time_stamp_data, #raw_var_num_data, #skip_init, #ticks_so_far
Instance Method Summary
collapse
-
#chan_pressure(chan, press) ⇒ Object
-
#controller(chan, control, value) ⇒ Object
-
#end_track ⇒ Object
-
#eot ⇒ Object
-
#header(format, ntrks, division) ⇒ Object
-
#initialize(seq, &block) ⇒ SeqReader
constructor
The optional &block is called once at the start of the file and again at the end of each track.
-
#key_signature(sharpflat, is_minor) ⇒ Object
-
#make_note_off(on, vel) ⇒ Object
-
#meta_misc(type, msg) ⇒ Object
-
#note_off(chan, note, vel) ⇒ Object
-
#note_on(chan, note, vel) ⇒ Object
-
#pitch_bend(chan, lsb, msb) ⇒ Object
-
#pressure(chan, note, press) ⇒ Object
-
#program(chan, program) ⇒ Object
-
#start_track ⇒ Object
-
#sysex(msg) ⇒ Object
-
#tempo(microsecs) ⇒ Object
– def smpte(hour, min, sec, frame, fract) end ++.
-
#text(type, msg) ⇒ Object
def sequence_number(num) end ++.
-
#time_signature(numer, denom, clocks, qnotes) ⇒ Object
-
#track_uses_channel(chan) ⇒ Object
Return true if the current track uses the specified channel.
Methods inherited from MIDIFile
#arbitrary, #bad_byte, #chan_message, #error, #get_bytes, #getc, #handle_arbitrary, #handle_sysex, #meta_event, #msg, #msg_add, #msg_init, #msg_read, #read16, #read32, #read_from, #read_header, #read_mt_header_string, #read_track, #read_var_len, #sequence_number, #sequencer_specific, #smpte, #write16, #write32, #write_var_len
Constructor Details
#initialize(seq, &block) ⇒ SeqReader
The optional &block is called once at the start of the file and again at the end of each track. There are three arguments to the block: the track, the track number (1 through n), and the total number of tracks.
19
20
21
22
23
24
25
|
# File 'lib/midilib/io/seqreader.rb', line 19
def initialize(seq, &block) super()
@seq = seq
@track = nil
@chan_mask = 0
@update_block = block
end
|
Instance Method Details
#chan_pressure(chan, press) ⇒ Object
127
128
129
130
|
# File 'lib/midilib/io/seqreader.rb', line 127
def chan_pressure(chan, press)
@track.events << ChannelPressure.new(chan, press, @curr_ticks)
track_uses_channel(chan)
end
|
#controller(chan, control, value) ⇒ Object
112
113
114
115
|
# File 'lib/midilib/io/seqreader.rb', line 112
def controller(chan, control, value)
@track.events << Controller.new(chan, control, value, @curr_ticks)
track_uses_channel(chan)
end
|
#end_track ⇒ Object
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
# File 'lib/midilib/io/seqreader.rb', line 42
def end_track
@pending.each { |on| make_note_off(on, 64) }
@pending = nil
@track.ensure_track_end_meta_event
@track.recalc_times
@track.channels_used = @chan_mask
@update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
end
|
#eot ⇒ Object
136
137
138
|
# File 'lib/midilib/io/seqreader.rb', line 136
def eot
@track.events << MetaEvent.new(META_TRACK_END, nil, @curr_ticks)
end
|
27
28
29
30
31
32
33
|
# File 'lib/midilib/io/seqreader.rb', line 27
def (format, ntrks, division)
@seq.format = format
@seq.ppqn = division
@ntrks = ntrks
@update_block.call(nil, @ntrks, 0) if @update_block
end
|
#key_signature(sharpflat, is_minor) ⇒ Object
179
180
181
|
# File 'lib/midilib/io/seqreader.rb', line 179
def key_signature(sharpflat, is_minor)
@track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
end
|
#make_note_off(on, vel) ⇒ Object
100
101
102
103
104
105
|
# File 'lib/midilib/io/seqreader.rb', line 100
def make_note_off(on, vel)
off = NoteOff.new(on.channel, on.note, vel, @curr_ticks)
@track.events << off
on.off = off
off.on = on
end
|
140
141
142
|
# File 'lib/midilib/io/seqreader.rb', line 140
def meta_misc(type, msg)
@track.events << MetaEvent.new(type, msg, @curr_ticks)
end
|
#note_off(chan, note, vel) ⇒ Object
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/midilib/io/seqreader.rb', line 71
def note_off(chan, note, vel)
corresp_note_on = nil
@pending.each_with_index do |on, i|
next unless on.note == note && on.channel == chan
@pending.delete_at(i)
corresp_note_on = on
break
end
if corresp_note_on
make_note_off(corresp_note_on, vel)
else
off = NoteOff.new(chan, note, vel, @curr_ticks)
@track.events << off
if $DEBUG
warn "note off with no earlier note on (ch #{chan}, note" +
" #{note}, vel #{vel})"
end
end
end
|
#note_on(chan, note, vel) ⇒ Object
59
60
61
62
63
64
65
66
67
68
69
|
# File 'lib/midilib/io/seqreader.rb', line 59
def note_on(chan, note, vel)
if vel == 0
note_off(chan, note, 64)
return
end
on = NoteOn.new(chan, note, vel, @curr_ticks)
@track.events << on
@pending << on
track_uses_channel(chan)
end
|
#pitch_bend(chan, lsb, msb) ⇒ Object
117
118
119
120
|
# File 'lib/midilib/io/seqreader.rb', line 117
def pitch_bend(chan, lsb, msb)
@track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
track_uses_channel(chan)
end
|
#pressure(chan, note, press) ⇒ Object
107
108
109
110
|
# File 'lib/midilib/io/seqreader.rb', line 107
def pressure(chan, note, press)
@track.events << PolyPressure.new(chan, note, press, @curr_ticks)
track_uses_channel(chan)
end
|
#program(chan, program) ⇒ Object
122
123
124
125
|
# File 'lib/midilib/io/seqreader.rb', line 122
def program(chan, program)
@track.events << ProgramChange.new(chan, program, @curr_ticks)
track_uses_channel(chan)
end
|
#start_track ⇒ Object
35
36
37
38
39
40
|
# File 'lib/midilib/io/seqreader.rb', line 35
def start_track
@track = Track.new(@seq)
@seq.tracks << @track
@pending = []
end
|
#sysex(msg) ⇒ Object
132
133
134
|
# File 'lib/midilib/io/seqreader.rb', line 132
def sysex(msg)
@track.events << SystemExclusive.new(msg, @curr_ticks)
end
|
#tempo(microsecs) ⇒ Object
–
def smpte(hour, min, sec, frame, fract)
end
++
175
176
177
|
# File 'lib/midilib/io/seqreader.rb', line 175
def tempo(microsecs)
@track.events << Tempo.new(microsecs, @curr_ticks)
end
|
#text(type, msg) ⇒ Object
def sequence_number(num)
end
++
152
153
154
155
156
157
158
159
160
161
162
163
|
# File 'lib/midilib/io/seqreader.rb', line 152
def text(type, msg)
case type
when META_TEXT, META_LYRIC, META_CUE, META_SEQ_NAME, META_COPYRIGHT
@track.events << MetaEvent.new(type, msg, @curr_ticks)
when META_INSTRUMENT
@track.instrument = msg
when META_MARKER
@track.events << Marker.new(msg, @curr_ticks)
else
warn "text = #{msg}, type = #{type}" if $DEBUG
end
end
|
#time_signature(numer, denom, clocks, qnotes) ⇒ Object
165
166
167
168
|
# File 'lib/midilib/io/seqreader.rb', line 165
def time_signature(numer, denom, clocks, qnotes)
@seq.time_signature(numer, denom, clocks, qnotes)
@track.events << TimeSig.new(numer, denom, clocks, qnotes, @curr_ticks)
end
|
#track_uses_channel(chan) ⇒ Object
Return true if the current track uses the specified channel.
189
190
191
|
# File 'lib/midilib/io/seqreader.rb', line 189
def track_uses_channel(chan)
@chan_mask |= (1 << chan)
end
|