midilib 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +9 -4
  3. data/Rakefile +2 -6
  4. data/examples/from_scratch.rb +3 -5
  5. data/examples/measures_mbt.rb +4 -4
  6. data/examples/print_program_changes.rb +9 -9
  7. data/examples/reader2text.rb +188 -188
  8. data/examples/seq2text.rb +17 -17
  9. data/examples/split.rb +19 -19
  10. data/examples/strings.rb +14 -14
  11. data/examples/transpose.rb +31 -31
  12. data/html/IO.html +65 -169
  13. data/html/MIDI.html +138 -256
  14. data/html/MIDI/ActiveSense.html +89 -178
  15. data/html/MIDI/ChannelEvent.html +95 -183
  16. data/html/MIDI/ChannelPressure.html +105 -190
  17. data/html/MIDI/Clock.html +89 -178
  18. data/html/MIDI/Continue.html +89 -178
  19. data/html/MIDI/Controller.html +107 -192
  20. data/html/MIDI/Event.html +138 -222
  21. data/html/MIDI/IO.html +45 -157
  22. data/html/MIDI/IO/MIDIFile.html +596 -568
  23. data/html/MIDI/IO/SeqReader.html +272 -314
  24. data/html/MIDI/IO/SeqWriter.html +229 -305
  25. data/html/MIDI/KeySig.html +129 -211
  26. data/html/MIDI/MIDI.html +45 -154
  27. data/html/MIDI/MIDI/MIDI.html +45 -154
  28. data/html/MIDI/MIDI/MIDI/Array.html +87 -185
  29. data/html/MIDI/Marker.html +71 -170
  30. data/html/MIDI/Measure.html +95 -190
  31. data/html/MIDI/Measures.html +103 -193
  32. data/html/MIDI/MetaEvent.html +180 -253
  33. data/html/MIDI/NoteEvent.html +118 -204
  34. data/html/MIDI/NoteOff.html +95 -183
  35. data/html/MIDI/NoteOn.html +95 -183
  36. data/html/MIDI/PitchBend.html +106 -191
  37. data/html/MIDI/PolyPressure.html +106 -189
  38. data/html/MIDI/ProgramChange.html +105 -190
  39. data/html/MIDI/Realtime.html +98 -184
  40. data/html/MIDI/Sequence.html +246 -311
  41. data/html/MIDI/SongPointer.html +106 -191
  42. data/html/MIDI/SongSelect.html +105 -190
  43. data/html/MIDI/Start.html +89 -178
  44. data/html/MIDI/Stop.html +89 -178
  45. data/html/MIDI/SystemCommon.html +71 -170
  46. data/html/MIDI/SystemExclusive.html +108 -193
  47. data/html/MIDI/SystemReset.html +89 -178
  48. data/html/MIDI/Tempo.html +135 -213
  49. data/html/MIDI/TimeSig.html +135 -214
  50. data/html/MIDI/Track.html +217 -291
  51. data/html/MIDI/TuneRequest.html +98 -184
  52. data/html/MIDI/Utils.html +89 -189
  53. data/html/README_rdoc.html +237 -257
  54. data/html/TODO_rdoc.html +64 -139
  55. data/html/created.rid +14 -14
  56. data/html/css/fonts.css +167 -0
  57. data/html/{rdoc.css → css/rdoc.css} +265 -218
  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 +187 -169
  69. data/html/js/darkfish.js +41 -33
  70. data/html/js/jquery.js +4 -18
  71. data/html/js/navigation.js.gz +0 -0
  72. data/html/js/search.js +20 -5
  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.gz +0 -0
  76. data/html/table_of_contents.html +1111 -498
  77. data/install.rb +43 -32
  78. data/lib/midilib/consts.rb +407 -407
  79. data/lib/midilib/event.rb +295 -294
  80. data/lib/midilib/info.rb +5 -5
  81. data/lib/midilib/io/midifile.rb +266 -267
  82. data/lib/midilib/io/seqreader.rb +106 -106
  83. data/lib/midilib/io/seqwriter.rb +59 -60
  84. data/lib/midilib/measure.rb +69 -69
  85. data/lib/midilib/sequence.rb +68 -70
  86. data/lib/midilib/track.rb +96 -102
  87. data/lib/midilib/utils.rb +15 -15
  88. data/test/event_equality.rb +50 -50
  89. data/test/test_event.rb +120 -122
  90. data/test/test_io.rb +35 -48
  91. data/test/test_sequence.rb +60 -60
  92. data/test/test_track.rb +154 -154
  93. data/test/test_varlen.rb +23 -25
  94. metadata +65 -57
@@ -4,54 +4,54 @@ require 'midilib/event'
4
4
 
5
5
  module MIDI
6
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
7
+ module IO
8
+
9
+ # Reads MIDI files. As a subclass of MIDIFile, this class implements the
10
+ # callback methods for each MIDI event and use them to build Track and
11
+ # 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
14
+ # call to Track.#add. This means that we must call Track.recalc_times at
15
+ # the end of the track so it can update each event with its time from
16
+ # the track's start (see end_track below).
17
+ #
18
+ # META_TRACK_END events are not added to tracks. This way, we don't have
19
+ # to worry about making sure the last event is always a track end event.
20
+ # We rely on the SeqWriter to append a META_TRACK_END event to each
21
+ # track when it is output.
22
+
23
+ class SeqReader < MIDIFile
24
+
25
+ # The optional proc block is called once at the start of the file and
26
+ # again at the end of each track. There are three arguments to the
27
+ # block: the track, the track number (1 through _n_), and the total
28
+ # number of tracks.
29
+ def initialize(seq, proc = nil) # :yields: track, num_tracks, index
30
30
  super()
31
31
  @seq = seq
32
32
  @track = nil
33
33
  @chan_mask = 0
34
34
  @update_block = block_given?() ? Proc.new() : proc
35
- end
35
+ end
36
36
 
37
- def header(format, ntrks, division)
37
+ def header(format, ntrks, division)
38
38
  @seq.format = format
39
39
  @seq.ppqn = division
40
40
 
41
41
  @ntrks = ntrks
42
42
  @update_block.call(nil, @ntrks, 0) if @update_block
43
- end
43
+ end
44
44
 
45
- def start_track()
45
+ def start_track()
46
46
  @track = Track.new(@seq)
47
47
  @seq.tracks << @track
48
48
 
49
49
  @pending = []
50
- end
50
+ end
51
51
 
52
- def end_track()
52
+ def end_track()
53
53
  # Turn off any pending note on messages
54
- @pending.each { | on | make_note_off(on, 64) }
54
+ @pending.each { |on| make_note_off(on, 64) }
55
55
  @pending = nil
56
56
 
57
57
  # Don't bother adding the META_TRACK_END event to the track.
@@ -67,136 +67,136 @@ class SeqReader < MIDIFile
67
67
 
68
68
  # call update block
69
69
  @update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
70
- end
70
+ end
71
71
 
72
- def note_on(chan, note, vel)
72
+ def note_on(chan, note, vel)
73
73
  if vel == 0
74
- note_off(chan, note, 64)
75
- return
74
+ note_off(chan, note, 64)
75
+ return
76
76
  end
77
77
 
78
78
  on = NoteOn.new(chan, note, vel, @curr_ticks)
79
79
  @track.events << on
80
80
  @pending << on
81
81
  track_uses_channel(chan)
82
- end
82
+ end
83
83
 
84
- def note_off(chan, note, vel)
84
+ def note_off(chan, note, vel)
85
85
  # Find note on, create note off, connect the two, and remove
86
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
- }
87
+ @pending.each_with_index do |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
+ end
94
94
  $stderr.puts "note off with no earlier note on (ch #{chan}, note" +
95
- " #{note}, vel #{vel})" if $DEBUG
96
- end
95
+ " #{note}, vel #{vel})" if $DEBUG
96
+ end
97
97
 
98
- def make_note_off(on, vel)
98
+ def make_note_off(on, vel)
99
99
  off = NoteOff.new(on.channel, on.note, vel, @curr_ticks)
100
100
  @track.events << off
101
101
  on.off = off
102
102
  off.on = on
103
- end
103
+ end
104
104
 
105
- def pressure(chan, note, press)
105
+ def pressure(chan, note, press)
106
106
  @track.events << PolyPressure.new(chan, note, press, @curr_ticks)
107
107
  track_uses_channel(chan)
108
- end
108
+ end
109
109
 
110
- def controller(chan, control, value)
110
+ def controller(chan, control, value)
111
111
  @track.events << Controller.new(chan, control, value, @curr_ticks)
112
112
  track_uses_channel(chan)
113
- end
113
+ end
114
114
 
115
- def pitch_bend(chan, lsb, msb)
115
+ def pitch_bend(chan, lsb, msb)
116
116
  @track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
117
117
  track_uses_channel(chan)
118
- end
118
+ end
119
119
 
120
- def program(chan, program)
120
+ def program(chan, program)
121
121
  @track.events << ProgramChange.new(chan, program, @curr_ticks)
122
122
  track_uses_channel(chan)
123
- end
123
+ end
124
124
 
125
- def chan_pressure(chan, press)
125
+ def chan_pressure(chan, press)
126
126
  @track.events << ChannelPressure.new(chan, press, @curr_ticks)
127
127
  track_uses_channel(chan)
128
- end
128
+ end
129
129
 
130
- def sysex(msg)
130
+ def sysex(msg)
131
131
  @track.events << SystemExclusive.new(msg, @curr_ticks)
132
- end
132
+ end
133
133
 
134
- def meta_misc(type, msg)
134
+ def meta_misc(type, msg)
135
135
  @track.events << MetaEvent.new(type, msg, @curr_ticks)
136
- end
136
+ end
137
137
 
138
- # --
139
- # def sequencer_specific(type, msg)
140
- # end
138
+ # --
139
+ # def sequencer_specific(type, msg)
140
+ # end
141
141
 
142
- # def sequence_number(num)
143
- # end
144
- # ++
142
+ # def sequence_number(num)
143
+ # end
144
+ # ++
145
145
 
146
- def text(type, msg)
146
+ def text(type, msg)
147
147
  case type
148
148
  when META_TEXT, META_LYRIC, META_CUE
149
- @track.events << MetaEvent.new(type, msg, @curr_ticks)
149
+ @track.events << MetaEvent.new(type, msg, @curr_ticks)
150
150
  when META_SEQ_NAME, META_COPYRIGHT
151
- @track.events << MetaEvent.new(type, msg, 0)
152
- when META_INSTRUMENT
153
- @track.instrument = msg
151
+ @track.events << MetaEvent.new(type, msg, 0)
152
+ when META_INSTRUMENT
153
+ @track.instrument = msg
154
154
  when META_MARKER
155
- @track.events << Marker.new(msg, @curr_ticks)
155
+ @track.events << Marker.new(msg, @curr_ticks)
156
156
  else
157
- $stderr.puts "text = #{msg}, type = #{type}" if $DEBUG
157
+ $stderr.puts "text = #{msg}, type = #{type}" if $DEBUG
158
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)
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
172
  @seq.time_signature(numer, denom, clocks, qnotes)
173
173
  @track.events << TimeSig.new(numer, denom, clocks, qnotes, @curr_ticks)
174
- end
174
+ end
175
175
 
176
- # --
177
- # def smpte(hour, min, sec, frame, fract)
178
- # end
179
- # ++
176
+ # --
177
+ # def smpte(hour, min, sec, frame, fract)
178
+ # end
179
+ # ++
180
180
 
181
- def tempo(microsecs)
181
+ def tempo(microsecs)
182
182
  @track.events << Tempo.new(microsecs, @curr_ticks)
183
- end
183
+ end
184
184
 
185
- def key_signature(sharpflat, is_minor)
186
- @track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
187
- end
185
+ def key_signature(sharpflat, is_minor)
186
+ @track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
187
+ end
188
188
 
189
- # --
190
- # def arbitrary(msg)
191
- # end
192
- # ++
189
+ # --
190
+ # def arbitrary(msg)
191
+ # end
192
+ # ++
193
193
 
194
- # Return true if the current track uses the specified channel.
195
- def track_uses_channel(chan)
194
+ # Return true if the current track uses the specified channel.
195
+ def track_uses_channel(chan)
196
196
  @chan_mask = @chan_mask | (1 << chan)
197
- end
197
+ end
198
198
 
199
- end
199
+ end
200
200
 
201
- end
201
+ end
202
202
  end
@@ -5,36 +5,36 @@ require 'midilib/utils'
5
5
 
6
6
  module MIDI
7
7
 
8
- module IO
8
+ module IO
9
9
 
10
- class SeqWriter
10
+ class SeqWriter
11
11
 
12
- def initialize(seq, proc = nil) # :yields: num_tracks, index
12
+ def initialize(seq, proc = nil) # :yields: num_tracks, index
13
13
  @seq = seq
14
14
  @update_block = block_given?() ? Proc.new() : proc
15
- end
15
+ end
16
16
 
17
- # Writes a MIDI format 1 file.
18
- def write_to(io)
17
+ # Writes a MIDI format 1 file.
18
+ def write_to(io)
19
19
  @io = io
20
20
  @bytes_written = 0
21
21
  write_header()
22
22
  @update_block.call(nil, @seq.tracks.length, 0) if @update_block
23
- @seq.tracks.each_with_index { | track, i |
24
- write_track(track)
25
- @update_block.call(track, @seq.tracks.length, i) if @update_block
26
- }
27
- end
23
+ @seq.tracks.each_with_index do |track, i|
24
+ write_track(track)
25
+ @update_block.call(track, @seq.tracks.length, i) if @update_block
26
+ end
27
+ end
28
28
 
29
- def write_header
29
+ def write_header
30
30
  @io.print 'MThd'
31
31
  write32(6)
32
32
  write16(1) # Ignore sequence format; write as format 1
33
33
  write16(@seq.tracks.length)
34
34
  write16(@seq.ppqn)
35
- end
35
+ end
36
36
 
37
- def write_track(track)
37
+ def write_track(track)
38
38
  @io.print 'MTrk'
39
39
  track_size_file_pos = @io.tell()
40
40
  write32(0) # Dummy byte count; overwritten later
@@ -44,23 +44,22 @@ class SeqWriter
44
44
 
45
45
  prev_event = nil
46
46
  prev_status = 0
47
- track.events.each { | event |
48
- if !event.kind_of?(Realtime)
49
- write_var_len(event.delta_time)
50
- end
47
+ track.events.each do |event|
48
+ if !event.kind_of?(Realtime)
49
+ write_var_len(event.delta_time)
50
+ end
51
51
 
52
- data = event.data_as_bytes()
53
- status = data[0] # status byte plus channel number, if any
52
+ data = event.data_as_bytes()
53
+ status = data[0] # status byte plus channel number, if any
54
54
 
55
- # running status byte
56
- status = possibly_munge_due_to_running_status_byte(data,
57
- prev_status)
55
+ # running status byte
56
+ status = possibly_munge_due_to_running_status_byte(data, prev_status)
58
57
 
59
- @bytes_written += write_bytes(data)
58
+ @bytes_written += write_bytes(data)
60
59
 
61
- prev_event = event
62
- prev_status = status
63
- }
60
+ prev_event = event
61
+ prev_status = status
62
+ end
64
63
 
65
64
  # Write track end event.
66
65
  event = MetaEvent.new(META_TRACK_END)
@@ -72,12 +71,12 @@ class SeqWriter
72
71
  @io.seek(track_size_file_pos)
73
72
  write32(@bytes_written)
74
73
  @io.seek(0, ::IO::SEEK_END)
75
- end
74
+ end
76
75
 
77
- # If we can use a running status byte, delete the status byte from
78
- # the given data. Return the status to remember for next time as the
79
- # running status byte for this event.
80
- def possibly_munge_due_to_running_status_byte(data, prev_status)
76
+ # If we can use a running status byte, delete the status byte from
77
+ # the given data. Return the status to remember for next time as the
78
+ # running status byte for this event.
79
+ def possibly_munge_due_to_running_status_byte(data, prev_status)
81
80
  status = data[0]
82
81
  return status if status >= 0xf0 || prev_status >= 0xf0
83
82
 
@@ -91,49 +90,49 @@ class SeqWriter
91
90
  # exactly the same, the rest is trivial. If it's note on/note off,
92
91
  # we can combine those further.
93
92
  if status == prev_status
94
- data[0,1] = [] # delete status byte from data
95
- return status + chan
93
+ data[0,1] = [] # delete status byte from data
94
+ return status + chan
96
95
  elsif status == NOTE_OFF && data[2] == 64
97
- # If we see a note off and the velocity is 64, we can store
98
- # a note on with a velocity of 0. If the velocity isn't 64
99
- # then storing a note on would be bad because the would be
100
- # changed to 64 when reading the file back in.
101
- data[2] = 0 # set vel to 0; do before possible shrinking
102
- status = NOTE_ON + chan
103
- if prev_status == NOTE_ON
104
- data[0,1] = [] # delete status byte
105
- else
106
- data[0] = status
107
- end
108
- return status
96
+ # If we see a note off and the velocity is 64, we can store
97
+ # a note on with a velocity of 0. If the velocity isn't 64
98
+ # then storing a note on would be bad because the would be
99
+ # changed to 64 when reading the file back in.
100
+ data[2] = 0 # set vel to 0; do before possible shrinking
101
+ status = NOTE_ON + chan
102
+ if prev_status == NOTE_ON
103
+ data[0,1] = [] # delete status byte
104
+ else
105
+ data[0] = status
106
+ end
107
+ return status
109
108
  else
110
- # Can't compress data
111
- return status + chan
109
+ # Can't compress data
110
+ return status + chan
112
111
  end
113
- end
112
+ end
114
113
 
115
- def write_instrument(instrument)
114
+ def write_instrument(instrument)
116
115
  event = MetaEvent.new(META_INSTRUMENT, instrument)
117
116
  write_var_len(0)
118
117
  data = event.data_as_bytes()
119
118
  @bytes_written += write_bytes(data)
120
- end
119
+ end
121
120
 
122
- def write_var_len(val)
121
+ def write_var_len(val)
123
122
  buffer = Utils.as_var_len(val)
124
123
  @bytes_written += write_bytes(buffer)
125
- end
124
+ end
126
125
 
127
- def write16(val)
126
+ def write16(val)
128
127
  val = (-val | 0x8000) if val < 0
129
128
 
130
129
  buffer = []
131
130
  @io.putc((val >> 8) & 0xff)
132
131
  @io.putc(val & 0xff)
133
132
  @bytes_written += 2
134
- end
133
+ end
135
134
 
136
- def write32(val)
135
+ def write32(val)
137
136
  val = (-val | 0x80000000) if val < 0
138
137
 
139
138
  @io.putc((val >> 24) & 0xff)
@@ -141,13 +140,13 @@ class SeqWriter
141
140
  @io.putc((val >> 8) & 0xff)
142
141
  @io.putc(val & 0xff)
143
142
  @bytes_written += 4
144
- end
143
+ end
145
144
 
146
- def write_bytes(bytes)
145
+ def write_bytes(bytes)
147
146
  bytes.each { |b| @io.putc(b) }
148
147
  bytes.length
148
+ end
149
149
  end
150
- end
151
150
 
152
- end
151
+ end
153
152
  end