midilib 2.0.5 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +5 -5
  2. data/ChangeLog +2 -1
  3. data/Credits +39 -2
  4. data/README.rdoc +5 -6
  5. data/Rakefile +36 -49
  6. data/TODO.rdoc +13 -2
  7. data/examples/from_scratch.rb +1 -1
  8. data/examples/measures_mbt.rb +11 -11
  9. data/examples/print_program_changes.rb +2 -2
  10. data/examples/reader2text.rb +47 -47
  11. data/examples/seq2text.rb +1 -1
  12. data/examples/split.rb +4 -3
  13. data/examples/strings.rb +4 -4
  14. data/examples/transpose.rb +19 -20
  15. data/install.rb +21 -13
  16. data/lib/midilib/consts.rb +237 -239
  17. data/lib/midilib/event.rb +128 -100
  18. data/lib/midilib/info.rb +3 -5
  19. data/lib/midilib/io/midifile.rb +155 -182
  20. data/lib/midilib/io/seqreader.rb +80 -85
  21. data/lib/midilib/io/seqwriter.rb +93 -88
  22. data/lib/midilib/measure.rb +78 -80
  23. data/lib/midilib/mergesort.rb +39 -0
  24. data/lib/midilib/sequence.rb +40 -32
  25. data/lib/midilib/track.rb +16 -57
  26. data/lib/midilib/utils.rb +4 -7
  27. data/lib/midilib.rb +5 -5
  28. data/test/event_equality.rb +28 -30
  29. data/test/test_event.rb +9 -11
  30. data/test/test_io.rb +83 -3
  31. data/test/test_mergesort.rb +37 -0
  32. data/test/test_midifile.rb +6 -19
  33. data/test/test_sequence.rb +5 -4
  34. data/test/test_track.rb +9 -38
  35. data/test/test_varlen.rb +1 -3
  36. metadata +8 -95
  37. data/html/IO.html +0 -155
  38. data/html/MIDI/ActiveSense.html +0 -206
  39. data/html/MIDI/ChannelEvent.html +0 -231
  40. data/html/MIDI/ChannelPressure.html +0 -265
  41. data/html/MIDI/Clock.html +0 -206
  42. data/html/MIDI/Continue.html +0 -206
  43. data/html/MIDI/Controller.html +0 -280
  44. data/html/MIDI/Event.html +0 -489
  45. data/html/MIDI/IO/MIDIFile.html +0 -2024
  46. data/html/MIDI/IO/SeqReader.html +0 -904
  47. data/html/MIDI/IO/SeqWriter.html +0 -572
  48. data/html/MIDI/IO.html +0 -95
  49. data/html/MIDI/KeySig.html +0 -353
  50. data/html/MIDI/MIDI/MIDI/Array.html +0 -255
  51. data/html/MIDI/MIDI/MIDI.html +0 -95
  52. data/html/MIDI/MIDI.html +0 -95
  53. data/html/MIDI/Marker.html +0 -158
  54. data/html/MIDI/Measure.html +0 -328
  55. data/html/MIDI/Measures.html +0 -285
  56. data/html/MIDI/MetaEvent.html +0 -461
  57. data/html/MIDI/NoteEvent.html +0 -331
  58. data/html/MIDI/NoteOff.html +0 -228
  59. data/html/MIDI/NoteOn.html +0 -228
  60. data/html/MIDI/PitchBend.html +0 -266
  61. data/html/MIDI/PolyPressure.html +0 -277
  62. data/html/MIDI/ProgramChange.html +0 -265
  63. data/html/MIDI/Realtime.html +0 -242
  64. data/html/MIDI/Sequence.html +0 -896
  65. data/html/MIDI/SongPointer.html +0 -266
  66. data/html/MIDI/SongSelect.html +0 -265
  67. data/html/MIDI/Start.html +0 -206
  68. data/html/MIDI/Stop.html +0 -206
  69. data/html/MIDI/SystemCommon.html +0 -158
  70. data/html/MIDI/SystemExclusive.html +0 -268
  71. data/html/MIDI/SystemReset.html +0 -206
  72. data/html/MIDI/Tempo.html +0 -396
  73. data/html/MIDI/TimeSig.html +0 -388
  74. data/html/MIDI/Track.html +0 -695
  75. data/html/MIDI/TuneRequest.html +0 -242
  76. data/html/MIDI/Utils.html +0 -220
  77. data/html/MIDI.html +0 -547
  78. data/html/README_rdoc.html +0 -731
  79. data/html/TODO_rdoc.html +0 -125
  80. data/html/created.rid +0 -14
  81. data/html/css/fonts.css +0 -167
  82. data/html/css/rdoc.css +0 -590
  83. data/html/fonts/Lato-Light.ttf +0 -0
  84. data/html/fonts/Lato-LightItalic.ttf +0 -0
  85. data/html/fonts/Lato-Regular.ttf +0 -0
  86. data/html/fonts/Lato-RegularItalic.ttf +0 -0
  87. data/html/fonts/SourceCodePro-Bold.ttf +0 -0
  88. data/html/fonts/SourceCodePro-Regular.ttf +0 -0
  89. data/html/images/add.png +0 -0
  90. data/html/images/arrow_up.png +0 -0
  91. data/html/images/brick.png +0 -0
  92. data/html/images/brick_link.png +0 -0
  93. data/html/images/bug.png +0 -0
  94. data/html/images/bullet_black.png +0 -0
  95. data/html/images/bullet_toggle_minus.png +0 -0
  96. data/html/images/bullet_toggle_plus.png +0 -0
  97. data/html/images/date.png +0 -0
  98. data/html/images/delete.png +0 -0
  99. data/html/images/find.png +0 -0
  100. data/html/images/loadingAnimation.gif +0 -0
  101. data/html/images/macFFBgHack.png +0 -0
  102. data/html/images/package.png +0 -0
  103. data/html/images/page_green.png +0 -0
  104. data/html/images/page_white_text.png +0 -0
  105. data/html/images/page_white_width.png +0 -0
  106. data/html/images/plugin.png +0 -0
  107. data/html/images/ruby.png +0 -0
  108. data/html/images/tag_blue.png +0 -0
  109. data/html/images/tag_green.png +0 -0
  110. data/html/images/transparent.png +0 -0
  111. data/html/images/wrench.png +0 -0
  112. data/html/images/wrench_orange.png +0 -0
  113. data/html/images/zoom.png +0 -0
  114. data/html/index.html +0 -768
  115. data/html/js/darkfish.js +0 -161
  116. data/html/js/jquery.js +0 -4
  117. data/html/js/navigation.js +0 -142
  118. data/html/js/navigation.js.gz +0 -0
  119. data/html/js/search.js +0 -109
  120. data/html/js/search_index.js +0 -1
  121. data/html/js/search_index.js.gz +0 -0
  122. data/html/js/searcher.js +0 -228
  123. data/html/js/searcher.js.gz +0 -0
  124. data/html/table_of_contents.html +0 -1265
@@ -1,11 +1,9 @@
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
6
  module IO
8
-
9
7
  # Reads MIDI files. As a subclass of MIDIFile, this class implements the
10
8
  # callback methods for each MIDI event and use them to build Track and
11
9
  # Event objects and give the tracks to a Sequence.
@@ -21,118 +19,119 @@ module MIDI
21
19
  # track when it is output.
22
20
 
23
21
  class SeqReader < MIDIFile
24
-
25
- # The optional proc block is called once at the start of the file and
22
+ # The optional &block is called once at the start of the file and
26
23
  # again at the end of each track. There are three arguments to the
27
24
  # block: the track, the track number (1 through _n_), and the total
28
25
  # 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
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
35
32
  end
36
33
 
37
34
  def header(format, ntrks, division)
38
- @seq.format = format
39
- @seq.ppqn = division
35
+ @seq.format = format
36
+ @seq.ppqn = division
40
37
 
41
- @ntrks = ntrks
42
- @update_block.call(nil, @ntrks, 0) if @update_block
38
+ @ntrks = ntrks
39
+ @update_block.call(nil, @ntrks, 0) if @update_block
43
40
  end
44
41
 
45
- def start_track()
46
- @track = Track.new(@seq)
47
- @seq.tracks << @track
42
+ def start_track
43
+ @track = Track.new(@seq)
44
+ @seq.tracks << @track
48
45
 
49
- @pending = []
46
+ @pending = []
50
47
  end
51
48
 
52
- def end_track()
53
- # Turn off any pending note on messages
54
- @pending.each { |on| make_note_off(on, 64) }
55
- @pending = nil
49
+ def end_track
50
+ # Turn off any pending note on messages
51
+ @pending.each { |on| make_note_off(on, 64) }
52
+ @pending = nil
56
53
 
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.
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.
60
57
 
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()
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
64
61
 
65
- # Store bitmask of all channels used into track
66
- @track.channels_used = @chan_mask
62
+ # Store bitmask of all channels used into track
63
+ @track.channels_used = @chan_mask
67
64
 
68
- # call update block
69
- @update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
65
+ # call update block
66
+ @update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
70
67
  end
71
68
 
72
69
  def note_on(chan, note, vel)
73
- if vel == 0
70
+ if vel == 0
74
71
  note_off(chan, note, 64)
75
72
  return
76
- end
73
+ end
77
74
 
78
- on = NoteOn.new(chan, note, vel, @curr_ticks)
79
- @track.events << on
80
- @pending << on
81
- track_uses_channel(chan)
75
+ on = NoteOn.new(chan, note, vel, @curr_ticks)
76
+ @track.events << on
77
+ @pending << on
78
+ track_uses_channel(chan)
82
79
  end
83
80
 
84
81
  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 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
- $stderr.puts "note off with no earlier note on (ch #{chan}, note" +
95
- " #{note}, vel #{vel})" if $DEBUG
82
+ # Find note on, create note off, connect the two, and remove
83
+ # note on from pending list.
84
+ @pending.each_with_index do |on, i|
85
+ next unless on.note == note && on.channel == chan
86
+
87
+ make_note_off(on, vel)
88
+ @pending.delete_at(i)
89
+ return
90
+ end
91
+ if $DEBUG
92
+ warn "note off with no earlier note on (ch #{chan}, note" +
93
+ " #{note}, vel #{vel})"
94
+ end
96
95
  end
97
96
 
98
97
  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
98
+ off = NoteOff.new(on.channel, on.note, vel, @curr_ticks)
99
+ @track.events << off
100
+ on.off = off
101
+ off.on = on
103
102
  end
104
103
 
105
104
  def pressure(chan, note, press)
106
- @track.events << PolyPressure.new(chan, note, press, @curr_ticks)
107
- track_uses_channel(chan)
105
+ @track.events << PolyPressure.new(chan, note, press, @curr_ticks)
106
+ track_uses_channel(chan)
108
107
  end
109
108
 
110
109
  def controller(chan, control, value)
111
- @track.events << Controller.new(chan, control, value, @curr_ticks)
112
- track_uses_channel(chan)
110
+ @track.events << Controller.new(chan, control, value, @curr_ticks)
111
+ track_uses_channel(chan)
113
112
  end
114
113
 
115
114
  def pitch_bend(chan, lsb, msb)
116
- @track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
117
- track_uses_channel(chan)
115
+ @track.events << PitchBend.new(chan, (msb << 7) + lsb, @curr_ticks)
116
+ track_uses_channel(chan)
118
117
  end
119
118
 
120
119
  def program(chan, program)
121
- @track.events << ProgramChange.new(chan, program, @curr_ticks)
122
- track_uses_channel(chan)
120
+ @track.events << ProgramChange.new(chan, program, @curr_ticks)
121
+ track_uses_channel(chan)
123
122
  end
124
123
 
125
124
  def chan_pressure(chan, press)
126
- @track.events << ChannelPressure.new(chan, press, @curr_ticks)
127
- track_uses_channel(chan)
125
+ @track.events << ChannelPressure.new(chan, press, @curr_ticks)
126
+ track_uses_channel(chan)
128
127
  end
129
128
 
130
129
  def sysex(msg)
131
- @track.events << SystemExclusive.new(msg, @curr_ticks)
130
+ @track.events << SystemExclusive.new(msg, @curr_ticks)
132
131
  end
133
132
 
134
133
  def meta_misc(type, msg)
135
- @track.events << MetaEvent.new(type, msg, @curr_ticks)
134
+ @track.events << MetaEvent.new(type, msg, @curr_ticks)
136
135
  end
137
136
 
138
137
  # --
@@ -144,18 +143,16 @@ module MIDI
144
143
  # ++
145
144
 
146
145
  def text(type, msg)
147
- case type
148
- when META_TEXT, META_LYRIC, META_CUE
146
+ case type
147
+ when META_TEXT, META_LYRIC, META_CUE, META_SEQ_NAME, META_COPYRIGHT
149
148
  @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
149
+ when META_INSTRUMENT
153
150
  @track.instrument = msg
154
- when META_MARKER
151
+ when META_MARKER
155
152
  @track.events << Marker.new(msg, @curr_ticks)
156
- else
157
- $stderr.puts "text = #{msg}, type = #{type}" if $DEBUG
158
- end
153
+ else
154
+ warn "text = #{msg}, type = #{type}" if $DEBUG
155
+ end
159
156
  end
160
157
 
161
158
  # --
@@ -163,13 +160,13 @@ module MIDI
163
160
  # we don't have to worry about always making sure the last event is
164
161
  # always a track end event. We just have to make sure to write one when
165
162
  # the track is output back to a file.
166
- # def eot()
167
- # @track.events << MetaEvent.new(META_TRACK_END, nil, @curr_ticks)
168
- # end
163
+ # def eot()
164
+ # @track.events << MetaEvent.new(META_TRACK_END, nil, @curr_ticks)
165
+ # end
169
166
  # ++
170
167
 
171
168
  def time_signature(numer, denom, clocks, qnotes)
172
- @seq.time_signature(numer, denom, clocks, qnotes)
169
+ @seq.time_signature(numer, denom, clocks, qnotes)
173
170
  @track.events << TimeSig.new(numer, denom, clocks, qnotes, @curr_ticks)
174
171
  end
175
172
 
@@ -179,7 +176,7 @@ module MIDI
179
176
  # ++
180
177
 
181
178
  def tempo(microsecs)
182
- @track.events << Tempo.new(microsecs, @curr_ticks)
179
+ @track.events << Tempo.new(microsecs, @curr_ticks)
183
180
  end
184
181
 
185
182
  def key_signature(sharpflat, is_minor)
@@ -193,10 +190,8 @@ module MIDI
193
190
 
194
191
  # Return true if the current track uses the specified channel.
195
192
  def track_uses_channel(chan)
196
- @chan_mask = @chan_mask | (1 << chan)
193
+ @chan_mask |= (1 << chan)
197
194
  end
198
-
199
195
  end
200
-
201
196
  end
202
197
  end
@@ -1,55 +1,61 @@
1
1
  # Writes MIDI files.
2
2
 
3
- require 'midilib/event'
4
- require 'midilib/utils'
3
+ require_relative '../event'
4
+ require_relative '../utils'
5
5
 
6
6
  module MIDI
7
-
8
7
  module IO
9
-
10
8
  class SeqWriter
11
-
12
- def initialize(seq, proc = nil) # :yields: num_tracks, index
13
- @seq = seq
14
- @update_block = block_given?() ? Proc.new() : proc
9
+ def initialize(seq, midi_format = 1, &block) # :yields: num_tracks, index
10
+ @seq = seq
11
+ @midi_format = midi_format || 1
12
+ @update_block = block
15
13
  end
16
14
 
17
15
  # Writes a MIDI format 1 file.
18
16
  def write_to(io)
19
- @io = io
20
- @bytes_written = 0
21
- write_header()
22
- @update_block.call(nil, @seq.tracks.length, 0) if @update_block
23
- @seq.tracks.each_with_index do |track, i|
17
+ if @midi_format == 0
18
+ # merge tracks before writing
19
+ merged_seq = Sequence.new
20
+ merged_track = Track.new(merged_seq)
21
+ merged_seq.tracks << merged_track
22
+ @seq.each do |track|
23
+ merged_track.merge(track.events)
24
+ end
25
+ @seq = merged_seq # replace
26
+ end
27
+
28
+ @io = io
29
+ @bytes_written = 0
30
+ write_header
31
+ @update_block.call(nil, @seq.tracks.length, 0) if @update_block
32
+ @seq.tracks.each_with_index do |track, i|
24
33
  write_track(track)
25
34
  @update_block.call(track, @seq.tracks.length, i) if @update_block
26
- end
35
+ end
27
36
  end
28
37
 
29
38
  def write_header
30
- @io.print 'MThd'
31
- write32(6)
32
- write16(1) # Ignore sequence format; write as format 1
33
- write16(@seq.tracks.length)
34
- write16(@seq.ppqn)
39
+ @io.print 'MThd'
40
+ write32(6)
41
+ write16(@midi_format) # Ignore sequence format; write as format 1 or 0, default 1
42
+ write16(@seq.tracks.length)
43
+ write16(@seq.ppqn)
35
44
  end
36
45
 
37
46
  def write_track(track)
38
- @io.print 'MTrk'
39
- track_size_file_pos = @io.tell()
40
- write32(0) # Dummy byte count; overwritten later
41
- @bytes_written = 0 # Reset after previous write
42
-
43
- write_instrument(track.instrument)
44
-
45
- prev_event = nil
46
- prev_status = 0
47
- track.events.each do |event|
48
- if !event.kind_of?(Realtime)
49
- write_var_len(event.delta_time)
50
- end
47
+ @io.print 'MTrk'
48
+ track_size_file_pos = @io.tell
49
+ write32(0) # Dummy byte count; overwritten later
50
+ @bytes_written = 0 # Reset after previous write
51
51
 
52
- data = event.data_as_bytes()
52
+ write_instrument(track.instrument)
53
+
54
+ prev_status = 0
55
+ track.events.each do |event|
56
+ write_var_len(event.delta_time) unless event.is_a?(Realtime)
57
+
58
+ data = event.data_as_bytes
53
59
  status = data[0] # status byte plus channel number, if any
54
60
 
55
61
  # running status byte
@@ -57,96 +63,95 @@ module MIDI
57
63
 
58
64
  @bytes_written += write_bytes(data)
59
65
 
60
- prev_event = event
61
66
  prev_status = status
62
- end
63
-
64
- # Write track end event.
65
- event = MetaEvent.new(META_TRACK_END)
66
- write_var_len(0)
67
- @bytes_written += write_bytes(event.data_as_bytes())
68
-
69
- # Go back to beginning of track data and write number of bytes,
70
- # then come back here to end of file.
71
- @io.seek(track_size_file_pos)
72
- write32(@bytes_written)
73
- @io.seek(0, ::IO::SEEK_END)
67
+ end
68
+
69
+ # Write track end event.
70
+ event = MetaEvent.new(META_TRACK_END)
71
+ write_var_len(0)
72
+ @bytes_written += write_bytes(event.data_as_bytes)
73
+
74
+ # Go back to beginning of track data and write number of bytes,
75
+ # then come back here to end of file.
76
+ @io.seek(track_size_file_pos)
77
+ write32(@bytes_written)
78
+ @io.seek(0, ::IO::SEEK_END)
74
79
  end
75
80
 
76
81
  # If we can use a running status byte, delete the status byte from
77
82
  # the given data. Return the status to remember for next time as the
78
83
  # running status byte for this event.
79
84
  def possibly_munge_due_to_running_status_byte(data, prev_status)
80
- status = data[0]
81
- return status if status >= 0xf0 || prev_status >= 0xf0
82
-
83
- chan = (status & 0x0f)
84
- return status if chan != (prev_status & 0x0f)
85
-
86
- status = (status & 0xf0)
87
- prev_status = (prev_status & 0xf0)
88
-
89
- # Both events are on the same channel. If the two status bytes are
90
- # exactly the same, the rest is trivial. If it's note on/note off,
91
- # we can combine those further.
92
- if status == prev_status
93
- data[0,1] = [] # delete status byte from data
94
- return status + chan
95
- elsif status == NOTE_OFF && data[2] == 64
85
+ status = data[0]
86
+ return status if status >= 0xf0 || prev_status >= 0xf0
87
+
88
+ chan = (status & 0x0f)
89
+ return status if chan != (prev_status & 0x0f)
90
+
91
+ status = (status & 0xf0)
92
+ prev_status = (prev_status & 0xf0)
93
+
94
+ # Both events are on the same channel. If the two status bytes are
95
+ # exactly the same, the rest is trivial. If it's note on/note off,
96
+ # we can combine those further.
97
+ if status == prev_status
98
+ data[0, 1] = [] # delete status byte from data
99
+ status + chan
100
+ elsif status == NOTE_OFF && data[2] == 64
96
101
  # If we see a note off and the velocity is 64, we can store
97
102
  # a note on with a velocity of 0. If the velocity isn't 64
98
103
  # then storing a note on would be bad because the would be
99
104
  # changed to 64 when reading the file back in.
100
- data[2] = 0 # set vel to 0; do before possible shrinking
105
+ data[2] = 0 # set vel to 0; do before possible shrinking
101
106
  status = NOTE_ON + chan
102
107
  if prev_status == NOTE_ON
103
- data[0,1] = [] # delete status byte
108
+ data[0, 1] = [] # delete status byte
104
109
  else
105
110
  data[0] = status
106
111
  end
107
- return status
108
- else
112
+ status
113
+ else
109
114
  # Can't compress data
110
- return status + chan
111
- end
115
+ status + chan
116
+ end
112
117
  end
113
118
 
114
119
  def write_instrument(instrument)
115
- event = MetaEvent.new(META_INSTRUMENT, instrument)
116
- write_var_len(0)
117
- data = event.data_as_bytes()
118
- @bytes_written += write_bytes(data)
120
+ return if instrument.nil?
121
+
122
+ event = MetaEvent.new(META_INSTRUMENT, instrument)
123
+ write_var_len(0)
124
+ data = event.data_as_bytes
125
+ @bytes_written += write_bytes(data)
119
126
  end
120
127
 
121
128
  def write_var_len(val)
122
- buffer = Utils.as_var_len(val)
123
- @bytes_written += write_bytes(buffer)
129
+ buffer = Utils.as_var_len(val)
130
+ @bytes_written += write_bytes(buffer)
124
131
  end
125
132
 
126
133
  def write16(val)
127
- val = (-val | 0x8000) if val < 0
134
+ val = (-val | 0x8000) if val < 0
128
135
 
129
- buffer = []
130
- @io.putc((val >> 8) & 0xff)
131
- @io.putc(val & 0xff)
132
- @bytes_written += 2
136
+ @io.putc((val >> 8) & 0xff)
137
+ @io.putc(val & 0xff)
138
+ @bytes_written += 2
133
139
  end
134
140
 
135
141
  def write32(val)
136
- val = (-val | 0x80000000) if val < 0
142
+ val = (-val | 0x80000000) if val < 0
137
143
 
138
- @io.putc((val >> 24) & 0xff)
139
- @io.putc((val >> 16) & 0xff)
140
- @io.putc((val >> 8) & 0xff)
141
- @io.putc(val & 0xff)
142
- @bytes_written += 4
144
+ @io.putc((val >> 24) & 0xff)
145
+ @io.putc((val >> 16) & 0xff)
146
+ @io.putc((val >> 8) & 0xff)
147
+ @io.putc(val & 0xff)
148
+ @bytes_written += 4
143
149
  end
144
150
 
145
151
  def write_bytes(bytes)
146
- bytes.each { |b| @io.putc(b) }
147
- bytes.length
152
+ bytes.each { |b| @io.putc(b) }
153
+ bytes.length
148
154
  end
149
155
  end
150
-
151
156
  end
152
157
  end
@@ -1,80 +1,78 @@
1
- require 'midilib/consts'
2
-
3
- module MIDI
4
-
5
- # The Measure class contains information about a measure from the sequence.
6
- # The measure data is based on the time signature information from the sequence
7
- # and is not stored in the sequence itself
8
- class Measure
9
- # The numerator (top digit) for the measure's time signature
10
- attr_reader :numerator
11
- # The denominator for the measure's time signature
12
- attr_reader :denominator
13
- # Start clock tick for the measure
14
- attr_reader :start
15
- # End clock tick for the measure (inclusive)
16
- attr_reader :end
17
- # The measure number (1-based)
18
- attr_reader :measure_number
19
- # The metronome tick for the measure
20
- attr_reader :metronome_ticks
21
-
22
- # Constructor
23
- def initialize(meas_no, start_time, duration, numer, denom, met_ticks)
24
- @measure_number = meas_no
25
- @start = start_time
26
- @end = start_time + duration - 1
27
- @numerator = numer
28
- @denominator = denom
29
- @metronome_ticks = met_ticks
30
- end
31
-
32
- # Returns a detailed string with information about the measure
33
- def to_s
34
- t = "#{@numerator}/#{2**@denominator}"
35
- m = @metronome_ticks.to_f / 24
36
- "measure #{@measure_number} #{@start}-#{@end} #{t} #{m} qs metronome"
37
- end
38
-
39
- # Returns +true+ if the event is in the measure
40
- def contains_event?(e)
41
- (e.time_from_start >= @start) && (e.time_from_start <= @end)
42
- end
43
- end
44
-
45
- # A specialized container for MIDI::Measure objects, which can be use to map
46
- # event times to measure numbers. Please note that this object has to be remade
47
- # when events are deleted/added in the sequence.
48
- class Measures < Array
49
- # The highest event time in the sequence (at the time when the
50
- # object was created)
51
- attr_reader :max_time
52
-
53
- # The ppqd from the sequence
54
- attr_reader :ppqd
55
-
56
- # Constructor
57
- def initialize(max_time, ppqd)
58
- super(0)
59
- @max_time = max_time
60
- @ppqd = ppqd
61
- end
62
-
63
- # Returns the MIDI::Measure object where the event is located.
64
- # Returns +nil+ if the event isn't found in the container (should
65
- # never happen if the MIDI::Measures object is up to date).
66
- def measure_for_event(e)
67
- detect { |m| m.contains_event?(e) }
68
- end
69
-
70
- # Returns the event's time as a formatted MBT string (Measure:Beat:Ticks)
71
- # as found in MIDI sequencers.
72
- def to_mbt(e)
73
- m = measure_for_event(e)
74
- b = (e.time_from_start.to_f - m.start.to_f) / @ppqd
75
- b *= 24 / m.metronome_ticks
76
- sprintf("%d:%02d:%03d", m.measure_number, b.to_i + 1, (b - b.to_i) * @ppqd)
77
- end
78
- end
79
-
80
- end
1
+ require_relative 'consts'
2
+
3
+ module MIDI
4
+ # The Measure class contains information about a measure from the sequence.
5
+ # The measure data is based on the time signature information from the sequence
6
+ # and is not stored in the sequence itself
7
+ class Measure
8
+ # The numerator (top digit) for the measure's time signature
9
+ attr_reader :numerator
10
+ # The denominator for the measure's time signature
11
+ attr_reader :denominator
12
+ # Start clock tick for the measure
13
+ attr_reader :start
14
+ # End clock tick for the measure (inclusive)
15
+ attr_reader :end
16
+ # The measure number (1-based)
17
+ attr_reader :measure_number
18
+ # The metronome tick for the measure
19
+ attr_reader :metronome_ticks
20
+
21
+ # Constructor
22
+ def initialize(meas_no, start_time, duration, numer, denom, met_ticks)
23
+ @measure_number = meas_no
24
+ @start = start_time
25
+ @end = start_time + duration - 1
26
+ @numerator = numer
27
+ @denominator = denom
28
+ @metronome_ticks = met_ticks
29
+ end
30
+
31
+ # Returns a detailed string with information about the measure
32
+ def to_s
33
+ t = "#{@numerator}/#{2**@denominator}"
34
+ m = @metronome_ticks.to_f / 24
35
+ "measure #{@measure_number} #{@start}-#{@end} #{t} #{m} qs metronome"
36
+ end
37
+
38
+ # Returns +true+ if the event is in the measure
39
+ def contains_event?(e)
40
+ (e.time_from_start >= @start) && (e.time_from_start <= @end)
41
+ end
42
+ end
43
+
44
+ # A specialized container for MIDI::Measure objects, which can be use to map
45
+ # event times to measure numbers. Please note that this object has to be remade
46
+ # when events are deleted/added in the sequence.
47
+ class Measures < Array
48
+ # The highest event time in the sequence (at the time when the
49
+ # object was created)
50
+ attr_reader :max_time
51
+
52
+ # The ppqd from the sequence
53
+ attr_reader :ppqd
54
+
55
+ # Constructor
56
+ def initialize(max_time, ppqd)
57
+ super(0)
58
+ @max_time = max_time
59
+ @ppqd = ppqd
60
+ end
61
+
62
+ # Returns the MIDI::Measure object where the event is located.
63
+ # Returns +nil+ if the event isn't found in the container (should
64
+ # never happen if the MIDI::Measures object is up to date).
65
+ def measure_for_event(e)
66
+ detect { |m| m.contains_event?(e) }
67
+ end
68
+
69
+ # Returns the event's time as a formatted MBT string (Measure:Beat:Ticks)
70
+ # as found in MIDI sequencers.
71
+ def to_mbt(e)
72
+ m = measure_for_event(e)
73
+ b = (e.time_from_start.to_f - m.start.to_f) / @ppqd
74
+ b *= 24 / m.metronome_ticks
75
+ format('%d:%02d:%03d', m.measure_number, b.to_i + 1, (b - b.to_i) * @ppqd)
76
+ end
77
+ end
78
+ end