midilib 2.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +2 -1
  3. data/Credits +44 -2
  4. data/README.rdoc +13 -9
  5. data/Rakefile +36 -53
  6. data/TODO.rdoc +13 -2
  7. data/examples/from_scratch.rb +4 -6
  8. data/examples/measures_mbt.rb +11 -11
  9. data/examples/print_program_changes.rb +11 -11
  10. data/examples/reader2text.rb +191 -191
  11. data/examples/seq2text.rb +18 -18
  12. data/examples/split.rb +21 -20
  13. data/examples/strings.rb +15 -15
  14. data/examples/transpose.rb +41 -42
  15. data/html/MIDI/ActiveSense.html +89 -213
  16. data/html/MIDI/ChannelEvent.html +95 -224
  17. data/html/MIDI/ChannelPressure.html +103 -241
  18. data/html/MIDI/Clock.html +89 -213
  19. data/html/MIDI/Continue.html +89 -213
  20. data/html/MIDI/Controller.html +105 -246
  21. data/html/MIDI/Event.html +134 -358
  22. data/html/MIDI/IO/MIDIFile.html +544 -1148
  23. data/html/MIDI/IO/SeqReader.html +273 -577
  24. data/html/MIDI/IO/SeqWriter.html +233 -439
  25. data/html/MIDI/IO.html +48 -164
  26. data/html/MIDI/KeySig.html +148 -291
  27. data/html/MIDI/Marker.html +73 -192
  28. data/html/MIDI/Measure.html +104 -267
  29. data/html/MIDI/Measures.html +106 -259
  30. data/html/MIDI/MetaEvent.html +171 -352
  31. data/html/MIDI/NoteEvent.html +114 -276
  32. data/html/MIDI/NoteOff.html +95 -223
  33. data/html/MIDI/NoteOn.html +95 -223
  34. data/html/MIDI/PitchBend.html +104 -242
  35. data/html/MIDI/PolyPressure.html +102 -246
  36. data/html/MIDI/ProgramChange.html +103 -241
  37. data/html/MIDI/Realtime.html +96 -230
  38. data/html/MIDI/Sequence.html +256 -576
  39. data/html/MIDI/SongPointer.html +104 -242
  40. data/html/MIDI/SongSelect.html +103 -241
  41. data/html/MIDI/Start.html +89 -213
  42. data/html/MIDI/Stop.html +89 -213
  43. data/html/MIDI/SystemCommon.html +73 -192
  44. data/html/MIDI/SystemExclusive.html +106 -244
  45. data/html/MIDI/SystemReset.html +89 -213
  46. data/html/MIDI/Tempo.html +127 -309
  47. data/html/MIDI/TimeSig.html +119 -300
  48. data/html/MIDI/Track.html +214 -494
  49. data/html/MIDI/TuneRequest.html +96 -230
  50. data/html/MIDI/Utils.html +91 -233
  51. data/html/MIDI.html +142 -526
  52. data/html/Object.html +197 -0
  53. data/html/README_rdoc.html +280 -486
  54. data/html/TODO_rdoc.html +68 -145
  55. data/html/created.rid +15 -14
  56. data/html/css/fonts.css +167 -0
  57. data/html/css/rdoc.css +639 -0
  58. data/html/fonts/Lato-Light.ttf +0 -0
  59. data/html/fonts/Lato-LightItalic.ttf +0 -0
  60. data/html/fonts/Lato-Regular.ttf +0 -0
  61. data/html/fonts/Lato-RegularItalic.ttf +0 -0
  62. data/html/fonts/SourceCodePro-Bold.ttf +0 -0
  63. data/html/fonts/SourceCodePro-Regular.ttf +0 -0
  64. data/html/images/add.png +0 -0
  65. data/html/images/arrow_up.png +0 -0
  66. data/html/images/delete.png +0 -0
  67. data/html/images/tag_blue.png +0 -0
  68. data/html/index.html +230 -446
  69. data/html/js/darkfish.js +22 -91
  70. data/html/js/navigation.js +4 -41
  71. data/html/js/navigation.js.gz +0 -0
  72. data/html/js/search.js +41 -25
  73. data/html/js/search_index.js +1 -1
  74. data/html/js/search_index.js.gz +0 -0
  75. data/html/js/searcher.js +9 -8
  76. data/html/js/searcher.js.gz +0 -0
  77. data/html/table_of_contents.html +1111 -505
  78. data/install.rb +53 -34
  79. data/lib/midilib/consts.rb +406 -408
  80. data/lib/midilib/event.rb +335 -306
  81. data/lib/midilib/info.rb +5 -7
  82. data/lib/midilib/io/midifile.rb +424 -452
  83. data/lib/midilib/io/seqreader.rb +200 -192
  84. data/lib/midilib/io/seqwriter.rb +151 -147
  85. data/lib/midilib/measure.rb +78 -80
  86. data/lib/midilib/mergesort.rb +39 -0
  87. data/lib/midilib/sequence.rb +93 -87
  88. data/lib/midilib/track.rb +71 -118
  89. data/lib/midilib/utils.rb +17 -20
  90. data/lib/midilib.rb +5 -5
  91. data/test/event_equality.rb +50 -52
  92. data/test/test_event.rb +120 -124
  93. data/test/test_io.rb +118 -38
  94. data/test/test_mergesort.rb +37 -0
  95. data/test/test_midifile.rb +6 -19
  96. data/test/test_sequence.rb +62 -61
  97. data/test/test_track.rb +126 -155
  98. data/test/test_varlen.rb +23 -27
  99. metadata +67 -62
  100. data/html/IO.html +0 -259
  101. data/html/MIDI/MIDI/MIDI/Array.html +0 -353
  102. data/html/MIDI/MIDI/MIDI.html +0 -204
  103. data/html/MIDI/MIDI.html +0 -204
  104. data/html/js/jquery.js +0 -18
  105. data/html/rdoc.css +0 -543
@@ -1,202 +1,210 @@
1
- require 'midilib/io/midifile'
2
- require 'midilib/track'
3
- require 'midilib/event'
1
+ require_relative 'midifile'
2
+ require_relative '../track'
3
+ require_relative '../event'
4
4
 
5
5
  module MIDI
6
-
7
- module IO
8
-
9
- # Reads MIDI files. As a subclass of MIDIFile, this class implements
10
- # the callback methods for each MIDI event and use them to build Track
11
- # and Event objects and give the tracks to a Sequence.
12
- #
13
- # We append new events to the end of a track's event list, bypassing a call
14
- # to Track.#add. This means that we must call Track.recalc_times at the end
15
- # of the track so it can update each event with its time from the track's
16
- # start (see end_track below).
17
- #
18
- # META_TRACK_END events are not added to tracks. This way, we don't have to
19
- # worry about making sure the last event is always a track end event. We
20
- # rely on the SeqWriter to append a META_TRACK_END event to each track when
21
- # it is output.
22
-
23
- class SeqReader < MIDIFile
24
-
25
- # The optional proc block is called once at the start of the file
26
- # and again at the end of each track. There are three arguments
27
- # to the block: the track, the track number (1 through _n_), and
28
- # the total number of tracks.
29
- def initialize(seq, proc = nil) # :yields: track, num_tracks, index
30
- super()
31
- @seq = seq
32
- @track = nil
33
- @chan_mask = 0
34
- @update_block = block_given?() ? Proc.new() : proc
35
- end
36
-
37
- def header(format, ntrks, division)
38
- @seq.format = format
39
- @seq.ppqn = division
40
-
41
- @ntrks = ntrks
42
- @update_block.call(nil, @ntrks, 0) if @update_block
43
- end
44
-
45
- def start_track()
46
- @track = Track.new(@seq)
47
- @seq.tracks << @track
48
-
49
- @pending = []
50
- end
51
-
52
- def end_track()
53
- # Turn off any pending note on messages
54
- @pending.each { | on | make_note_off(on, 64) }
55
- @pending = nil
56
-
57
- # Don't bother adding the META_TRACK_END event to the track.
58
- # This way, we don't have to worry about making sure the
59
- # last event is always a track end event.
60
-
61
- # Let the track calculate event times from start of track. This is
62
- # in lieu of calling Track.add for each event.
63
- @track.recalc_times()
64
-
65
- # Store bitmask of all channels used into track
66
- @track.channels_used = @chan_mask
67
-
68
- # call update block
69
- @update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
70
- end
71
-
72
- def note_on(chan, note, vel)
73
- if vel == 0
74
- note_off(chan, note, 64)
75
- return
76
- end
77
-
78
- on = NoteOn.new(chan, note, vel, @curr_ticks)
79
- @track.events << on
80
- @pending << on
81
- track_uses_channel(chan)
82
- end
83
-
84
- def note_off(chan, note, vel)
85
- # Find note on, create note off, connect the two, and remove
86
- # note on from pending list.
87
- @pending.each_with_index { | on, i |
88
- if on.note == note && on.channel == chan
89
- make_note_off(on, vel)
90
- @pending.delete_at(i)
91
- return
92
- end
93
- }
94
- $stderr.puts "note off with no earlier note on (ch #{chan}, note" +
95
- " #{note}, vel #{vel})" if $DEBUG
96
- end
97
-
98
- def make_note_off(on, vel)
99
- off = NoteOff.new(on.channel, on.note, vel, @curr_ticks)
100
- @track.events << off
101
- on.off = off
102
- off.on = on
103
- end
104
-
105
- def pressure(chan, note, press)
106
- @track.events << PolyPressure.new(chan, note, press, @curr_ticks)
107
- track_uses_channel(chan)
108
- end
109
-
110
- def controller(chan, control, value)
111
- @track.events << Controller.new(chan, control, value, @curr_ticks)
112
- track_uses_channel(chan)
113
- end
114
-
115
- def pitch_bend(chan, lsb, msb)
116
- @track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
117
- track_uses_channel(chan)
118
- end
119
-
120
- def program(chan, program)
121
- @track.events << ProgramChange.new(chan, program, @curr_ticks)
122
- track_uses_channel(chan)
123
- end
124
-
125
- def chan_pressure(chan, press)
126
- @track.events << ChannelPressure.new(chan, press, @curr_ticks)
127
- track_uses_channel(chan)
128
- end
129
-
130
- def sysex(msg)
131
- @track.events << SystemExclusive.new(msg, @curr_ticks)
132
- end
133
-
134
- def meta_misc(type, msg)
135
- @track.events << MetaEvent.new(type, msg, @curr_ticks)
136
- end
137
-
138
- # --
139
- # def sequencer_specific(type, msg)
140
- # end
141
-
142
- # def sequence_number(num)
143
- # end
144
- # ++
145
-
146
- def text(type, msg)
147
- case type
148
- when META_TEXT, META_LYRIC, META_CUE
149
- @track.events << MetaEvent.new(type, msg, @curr_ticks)
150
- when META_SEQ_NAME, META_COPYRIGHT
151
- @track.events << MetaEvent.new(type, msg, 0)
152
- when META_INSTRUMENT
153
- @track.instrument = msg
154
- when META_MARKER
155
- @track.events << Marker.new(msg, @curr_ticks)
156
- else
157
- $stderr.puts "text = #{msg}, type = #{type}" if $DEBUG
158
- end
159
- end
160
-
161
- # --
162
- # Don't bother adding the META_TRACK_END event to the track. This way,
163
- # we don't have to worry about always making sure the last event is
164
- # always a track end event. We just have to make sure to write one when
165
- # the track is output back to a file.
166
- # def eot()
167
- # @track.events << MetaEvent.new(META_TRACK_END, nil, @curr_ticks)
168
- # end
169
- # ++
170
-
171
- def time_signature(numer, denom, clocks, qnotes)
172
- @seq.time_signature(numer, denom, clocks, qnotes)
6
+ module IO
7
+ # Reads MIDI files. As a subclass of MIDIFile, this class implements the
8
+ # callback methods for each MIDI event and use them to build Track and
9
+ # Event objects and give the tracks to a Sequence.
10
+ #
11
+ # We append new events to the end of a track's event list, bypassing a
12
+ # call to Track.#add. This means that we must call Track.recalc_times at
13
+ # the end of the track so it can update each event with its time from
14
+ # the track's start (see end_track below).
15
+ #
16
+ # META_TRACK_END events are not added to tracks. This way, we don't have
17
+ # to worry about making sure the last event is always a track end event.
18
+ # We rely on the SeqWriter to append a META_TRACK_END event to each
19
+ # track when it is output.
20
+
21
+ class SeqReader < MIDIFile
22
+ # The optional &block is called once at the start of the file and
23
+ # again at the end of each track. There are three arguments to the
24
+ # block: the track, the track number (1 through _n_), and the total
25
+ # number of tracks.
26
+ def initialize(seq, &block) # :yields: track, num_tracks, index
27
+ super()
28
+ @seq = seq
29
+ @track = nil
30
+ @chan_mask = 0
31
+ @update_block = block
32
+ end
33
+
34
+ def header(format, ntrks, division)
35
+ @seq.format = format
36
+ @seq.ppqn = division
37
+
38
+ @ntrks = ntrks
39
+ @update_block.call(nil, @ntrks, 0) if @update_block
40
+ end
41
+
42
+ def start_track
43
+ @track = Track.new(@seq)
44
+ @seq.tracks << @track
45
+
46
+ @pending = []
47
+ end
48
+
49
+ def end_track
50
+ # Turn off any pending note on messages
51
+ @pending.each { |on| make_note_off(on, 64) }
52
+ @pending = nil
53
+
54
+ # Don't bother adding the META_TRACK_END event to the track.
55
+ # This way, we don't have to worry about making sure the
56
+ # last event is always a track end event.
57
+
58
+ # Let the track calculate event times from start of track. This is
59
+ # in lieu of calling Track.add for each event.
60
+ @track.recalc_times
61
+
62
+ # Store bitmask of all channels used into track
63
+ @track.channels_used = @chan_mask
64
+
65
+ # call update block
66
+ @update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
67
+ end
68
+
69
+ def note_on(chan, note, vel)
70
+ if vel == 0
71
+ note_off(chan, note, 64)
72
+ return
73
+ end
74
+
75
+ on = NoteOn.new(chan, note, vel, @curr_ticks)
76
+ @track.events << on
77
+ @pending << on
78
+ track_uses_channel(chan)
79
+ end
80
+
81
+ def note_off(chan, note, vel)
82
+ # Find note on, create note off, connect the two, and remove
83
+ # note on from pending list.
84
+
85
+ corresp_note_on = nil
86
+
87
+ @pending.each_with_index do |on, i|
88
+ next unless on.note == note && on.channel == chan
89
+
90
+ @pending.delete_at(i)
91
+ corresp_note_on = on
92
+ break
93
+ end
94
+
95
+ if corresp_note_on
96
+ make_note_off(corresp_note_on, vel)
97
+ else
98
+ # When a corresponding note on is missing,
99
+ # keep note off as input with lefting on/off attr to nil.
100
+ off = NoteOff.new(chan, note, vel, @curr_ticks)
101
+ @track.events << off
102
+
103
+ if $DEBUG
104
+ warn "note off with no earlier note on (ch #{chan}, note" +
105
+ " #{note}, vel #{vel})"
106
+ end
107
+ end
108
+ end
109
+
110
+ def make_note_off(on, vel)
111
+ off = NoteOff.new(on.channel, on.note, vel, @curr_ticks)
112
+ @track.events << off
113
+ on.off = off
114
+ off.on = on
115
+ end
116
+
117
+ def pressure(chan, note, press)
118
+ @track.events << PolyPressure.new(chan, note, press, @curr_ticks)
119
+ track_uses_channel(chan)
120
+ end
121
+
122
+ def controller(chan, control, value)
123
+ @track.events << Controller.new(chan, control, value, @curr_ticks)
124
+ track_uses_channel(chan)
125
+ end
126
+
127
+ def pitch_bend(chan, lsb, msb)
128
+ @track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
129
+ track_uses_channel(chan)
130
+ end
131
+
132
+ def program(chan, program)
133
+ @track.events << ProgramChange.new(chan, program, @curr_ticks)
134
+ track_uses_channel(chan)
135
+ end
136
+
137
+ def chan_pressure(chan, press)
138
+ @track.events << ChannelPressure.new(chan, press, @curr_ticks)
139
+ track_uses_channel(chan)
140
+ end
141
+
142
+ def sysex(msg)
143
+ @track.events << SystemExclusive.new(msg, @curr_ticks)
144
+ end
145
+
146
+ def meta_misc(type, msg)
147
+ @track.events << MetaEvent.new(type, msg, @curr_ticks)
148
+ end
149
+
150
+ # --
151
+ # def sequencer_specific(type, msg)
152
+ # end
153
+
154
+ # def sequence_number(num)
155
+ # end
156
+ # ++
157
+
158
+ def text(type, msg)
159
+ case type
160
+ when META_TEXT, META_LYRIC, META_CUE, META_SEQ_NAME, META_COPYRIGHT
161
+ @track.events << MetaEvent.new(type, msg, @curr_ticks)
162
+ when META_INSTRUMENT
163
+ @track.instrument = msg
164
+ when META_MARKER
165
+ @track.events << Marker.new(msg, @curr_ticks)
166
+ else
167
+ warn "text = #{msg}, type = #{type}" if $DEBUG
168
+ end
169
+ end
170
+
171
+ # --
172
+ # Don't bother adding the META_TRACK_END event to the track. This way,
173
+ # we don't have to worry about always making sure the last event is
174
+ # always a track end event. We just have to make sure to write one when
175
+ # the track is output back to a file.
176
+ # def eot()
177
+ # @track.events << MetaEvent.new(META_TRACK_END, nil, @curr_ticks)
178
+ # end
179
+ # ++
180
+
181
+ def time_signature(numer, denom, clocks, qnotes)
182
+ @seq.time_signature(numer, denom, clocks, qnotes)
173
183
  @track.events << TimeSig.new(numer, denom, clocks, qnotes, @curr_ticks)
174
- end
184
+ end
175
185
 
176
- # --
177
- # def smpte(hour, min, sec, frame, fract)
178
- # end
179
- # ++
186
+ # --
187
+ # def smpte(hour, min, sec, frame, fract)
188
+ # end
189
+ # ++
180
190
 
181
- def tempo(microsecs)
182
- @track.events << Tempo.new(microsecs, @curr_ticks)
183
- end
191
+ def tempo(microsecs)
192
+ @track.events << Tempo.new(microsecs, @curr_ticks)
193
+ end
184
194
 
185
- def key_signature(sharpflat, is_minor)
186
- @track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
187
- end
195
+ def key_signature(sharpflat, is_minor)
196
+ @track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
197
+ end
188
198
 
189
- # --
190
- # def arbitrary(msg)
191
- # end
192
- # ++
199
+ # --
200
+ # def arbitrary(msg)
201
+ # end
202
+ # ++
193
203
 
194
- # Return true if the current track uses the specified channel.
195
- def track_uses_channel(chan)
196
- @chan_mask = @chan_mask | (1 << chan)
204
+ # Return true if the current track uses the specified channel.
205
+ def track_uses_channel(chan)
206
+ @chan_mask |= (1 << chan)
207
+ end
197
208
  end
198
-
199
- end
200
-
201
- end
209
+ end
202
210
  end