midilib 2.0.5 → 3.0.1

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 (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