midilib 1.0.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +23 -0
- data/Credits +6 -0
- data/README +33 -1
- data/Rakefile +1 -1
- data/examples/from_scratch.rb +0 -0
- data/examples/measures_mbt.rb +30 -0
- data/examples/print_program_changes.rb +28 -0
- data/examples/reader2text.rb +0 -0
- data/examples/seq2text.rb +0 -0
- data/examples/split.rb +0 -0
- data/examples/strings.rb +0 -0
- data/examples/transpose.rb +0 -0
- data/html/classes/MIDI/ActiveSense.html +156 -0
- data/html/classes/MIDI/ActiveSense.src/M000157.html +18 -0
- data/html/classes/MIDI/ActiveSense.src/M000158.html +18 -0
- data/html/classes/MIDI/ChannelEvent.html +179 -0
- data/html/classes/MIDI/ChannelEvent.src/M000129.html +20 -0
- data/html/classes/MIDI/ChannelEvent.src/M000130.html +18 -0
- data/html/classes/MIDI/ChannelPressure.html +184 -0
- data/html/classes/MIDI/ChannelPressure.src/M000089.html +19 -0
- data/html/classes/MIDI/ChannelPressure.src/M000090.html +21 -0
- data/html/classes/MIDI/ChannelPressure.src/M000091.html +18 -0
- data/html/classes/MIDI/Clock.html +156 -0
- data/html/classes/MIDI/Clock.src/M000145.html +18 -0
- data/html/classes/MIDI/Clock.src/M000146.html +18 -0
- data/html/classes/MIDI/Continue.html +156 -0
- data/html/classes/MIDI/Continue.src/M000143.html +18 -0
- data/html/classes/MIDI/Continue.src/M000144.html +18 -0
- data/html/classes/MIDI/Controller.html +189 -0
- data/html/classes/MIDI/Controller.src/M000134.html +21 -0
- data/html/classes/MIDI/Controller.src/M000135.html +22 -0
- data/html/classes/MIDI/Controller.src/M000136.html +18 -0
- data/html/classes/MIDI/Event.html +507 -0
- data/html/classes/MIDI/Event.src/M000166.html +30 -0
- data/html/classes/MIDI/Event.src/M000167.html +18 -0
- data/html/classes/MIDI/Event.src/M000168.html +18 -0
- data/html/classes/MIDI/Event.src/M000169.html +18 -0
- data/html/classes/MIDI/Event.src/M000170.html +18 -0
- data/html/classes/MIDI/Event.src/M000171.html +18 -0
- data/html/classes/MIDI/Event.src/M000172.html +18 -0
- data/html/classes/MIDI/Event.src/M000173.html +18 -0
- data/html/classes/MIDI/Event.src/M000174.html +18 -0
- data/html/classes/MIDI/Event.src/M000175.html +18 -0
- data/html/classes/MIDI/Event.src/M000176.html +18 -0
- data/html/classes/MIDI/Event.src/M000177.html +18 -0
- data/html/classes/MIDI/Event.src/M000178.html +22 -0
- data/html/classes/MIDI/Event.src/M000179.html +18 -0
- data/html/classes/MIDI/Event.src/M000180.html +18 -0
- data/html/classes/MIDI/Event.src/M000181.html +19 -0
- data/html/classes/MIDI/Event.src/M000182.html +18 -0
- data/html/classes/MIDI/IO/MIDIFile.html +931 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000029.html +22 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000030.html +24 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000031.html +20 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000032.html +19 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000033.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000034.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000035.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000036.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000037.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000038.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000039.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000040.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000041.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000042.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000043.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000044.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000045.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000046.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000047.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000048.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000049.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000050.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000051.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000052.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000053.html +17 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000054.html +43 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000055.html +34 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000056.html +96 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000057.html +18 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000058.html +48 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000059.html +42 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000060.html +19 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000061.html +19 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000062.html +20 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000063.html +21 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000064.html +31 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000065.html +20 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000066.html +22 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000067.html +30 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000068.html +18 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000069.html +20 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000070.html +18 -0
- data/html/classes/MIDI/IO/MIDIFile.src/M000071.html +18 -0
- data/html/classes/MIDI/IO/SeqReader.html +476 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000001.html +22 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000002.html +22 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000003.html +21 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000004.html +34 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000005.html +26 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000006.html +28 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000007.html +21 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000008.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000009.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000010.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000011.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000012.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000013.html +18 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000014.html +18 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000015.html +29 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000016.html +19 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000017.html +18 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000018.html +18 -0
- data/html/classes/MIDI/IO/SeqReader.src/M000019.html +18 -0
- data/html/classes/MIDI/IO/SeqWriter.html +267 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000020.html +19 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000021.html +25 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000022.html +22 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000023.html +54 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000024.html +49 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000025.html +21 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000026.html +19 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000027.html +24 -0
- data/html/classes/MIDI/IO/SeqWriter.src/M000028.html +26 -0
- data/html/classes/MIDI/IO.html +121 -0
- data/html/classes/MIDI/KeySig.html +241 -0
- data/html/classes/MIDI/KeySig.src/M000137.html +19 -0
- data/html/classes/MIDI/KeySig.src/M000138.html +23 -0
- data/html/classes/MIDI/KeySig.src/M000139.html +18 -0
- data/html/classes/MIDI/KeySig.src/M000140.html +18 -0
- data/html/classes/MIDI/KeySig.src/M000141.html +18 -0
- data/html/classes/MIDI/KeySig.src/M000142.html +23 -0
- data/html/classes/MIDI/Marker.html +139 -0
- data/html/classes/MIDI/Marker.src/M000111.html +18 -0
- data/html/classes/MIDI/Measure.html +242 -0
- data/html/classes/MIDI/Measure.src/M000147.html +23 -0
- data/html/classes/MIDI/Measure.src/M000148.html +20 -0
- data/html/classes/MIDI/Measure.src/M000149.html +18 -0
- data/html/classes/MIDI/Measures.html +217 -0
- data/html/classes/MIDI/Measures.src/M000105.html +20 -0
- data/html/classes/MIDI/Measures.src/M000106.html +18 -0
- data/html/classes/MIDI/Measures.src/M000107.html +21 -0
- data/html/classes/MIDI/MetaEvent.html +189 -0
- data/html/classes/MIDI/MetaEvent.src/M000192.html +21 -0
- data/html/classes/MIDI/MetaEvent.src/M000193.html +23 -0
- data/html/classes/MIDI/MetaEvent.src/M000194.html +53 -0
- data/html/classes/MIDI/NoteEvent.html +233 -0
- data/html/classes/MIDI/NoteEvent.src/M000092.html +21 -0
- data/html/classes/MIDI/NoteEvent.src/M000093.html +20 -0
- data/html/classes/MIDI/NoteEvent.src/M000094.html +18 -0
- data/html/classes/MIDI/NoteEvent.src/M000095.html +22 -0
- data/html/classes/MIDI/NoteOffEvent.html +169 -0
- data/html/classes/MIDI/NoteOffEvent.src/M000087.html +19 -0
- data/html/classes/MIDI/NoteOffEvent.src/M000088.html +19 -0
- data/html/classes/MIDI/NoteOnEvent.html +169 -0
- data/html/classes/MIDI/NoteOnEvent.src/M000103.html +19 -0
- data/html/classes/MIDI/NoteOnEvent.src/M000104.html +19 -0
- data/html/classes/MIDI/PitchBend.html +184 -0
- data/html/classes/MIDI/PitchBend.src/M000108.html +19 -0
- data/html/classes/MIDI/PitchBend.src/M000109.html +22 -0
- data/html/classes/MIDI/PitchBend.src/M000110.html +18 -0
- data/html/classes/MIDI/PolyPressure.html +186 -0
- data/html/classes/MIDI/PolyPressure.src/M000195.html +18 -0
- data/html/classes/MIDI/PolyPressure.src/M000196.html +18 -0
- data/html/classes/MIDI/PolyPressure.src/M000197.html +18 -0
- data/html/classes/MIDI/PolyPressure.src/M000198.html +19 -0
- data/html/classes/MIDI/ProgramChange.html +184 -0
- data/html/classes/MIDI/ProgramChange.src/M000100.html +20 -0
- data/html/classes/MIDI/ProgramChange.src/M000101.html +21 -0
- data/html/classes/MIDI/ProgramChange.src/M000102.html +18 -0
- data/html/classes/MIDI/Realtime.html +171 -0
- data/html/classes/MIDI/Realtime.src/M000084.html +19 -0
- data/html/classes/MIDI/Realtime.src/M000085.html +20 -0
- data/html/classes/MIDI/Realtime.src/M000086.html +18 -0
- data/html/classes/MIDI/Sequence.html +500 -0
- data/html/classes/MIDI/Sequence.src/M000112.html +28 -0
- data/html/classes/MIDI/Sequence.src/M000113.html +21 -0
- data/html/classes/MIDI/Sequence.src/M000114.html +22 -0
- data/html/classes/MIDI/Sequence.src/M000117.html +18 -0
- data/html/classes/MIDI/Sequence.src/M000118.html +27 -0
- data/html/classes/MIDI/Sequence.src/M000119.html +18 -0
- data/html/classes/MIDI/Sequence.src/M000120.html +19 -0
- data/html/classes/MIDI/Sequence.src/M000121.html +19 -0
- data/html/classes/MIDI/Sequence.src/M000122.html +19 -0
- data/html/classes/MIDI/Sequence.src/M000123.html +19 -0
- data/html/classes/MIDI/Sequence.src/M000124.html +18 -0
- data/html/classes/MIDI/Sequence.src/M000125.html +54 -0
- data/html/classes/MIDI/SongPointer.html +184 -0
- data/html/classes/MIDI/SongPointer.src/M000159.html +19 -0
- data/html/classes/MIDI/SongPointer.src/M000160.html +22 -0
- data/html/classes/MIDI/SongPointer.src/M000161.html +18 -0
- data/html/classes/MIDI/SongSelect.html +184 -0
- data/html/classes/MIDI/SongSelect.src/M000131.html +19 -0
- data/html/classes/MIDI/SongSelect.src/M000132.html +21 -0
- data/html/classes/MIDI/SongSelect.src/M000133.html +18 -0
- data/html/classes/MIDI/Start.html +156 -0
- data/html/classes/MIDI/Start.src/M000098.html +18 -0
- data/html/classes/MIDI/Start.src/M000099.html +18 -0
- data/html/classes/MIDI/Stop.html +156 -0
- data/html/classes/MIDI/Stop.src/M000096.html +18 -0
- data/html/classes/MIDI/Stop.src/M000097.html +18 -0
- data/html/classes/MIDI/SystemCommon.html +139 -0
- data/html/classes/MIDI/SystemCommon.src/M000165.html +19 -0
- data/html/classes/MIDI/SystemExclusive.html +184 -0
- data/html/classes/MIDI/SystemExclusive.src/M000162.html +19 -0
- data/html/classes/MIDI/SystemExclusive.src/M000163.html +23 -0
- data/html/classes/MIDI/SystemExclusive.src/M000164.html +18 -0
- data/html/classes/MIDI/SystemReset.html +156 -0
- data/html/classes/MIDI/SystemReset.src/M000082.html +18 -0
- data/html/classes/MIDI/SystemReset.src/M000083.html +18 -0
- data/html/classes/MIDI/Tempo.html +250 -0
- data/html/classes/MIDI/Tempo.src/M000183.html +18 -0
- data/html/classes/MIDI/Tempo.src/M000184.html +20 -0
- data/html/classes/MIDI/Tempo.src/M000185.html +18 -0
- data/html/classes/MIDI/Tempo.src/M000186.html +18 -0
- data/html/classes/MIDI/Tempo.src/M000187.html +18 -0
- data/html/classes/MIDI/Tempo.src/M000188.html +25 -0
- data/html/classes/MIDI/Tempo.src/M000189.html +18 -0
- data/html/classes/MIDI/TimeSig.html +263 -0
- data/html/classes/MIDI/TimeSig.src/M000150.html +19 -0
- data/html/classes/MIDI/TimeSig.src/M000151.html +25 -0
- data/html/classes/MIDI/TimeSig.src/M000152.html +18 -0
- data/html/classes/MIDI/TimeSig.src/M000153.html +18 -0
- data/html/classes/MIDI/TimeSig.src/M000154.html +18 -0
- data/html/classes/MIDI/TimeSig.src/M000155.html +18 -0
- data/html/classes/MIDI/TimeSig.src/M000156.html +18 -0
- data/html/classes/MIDI/Track.html +389 -0
- data/html/classes/MIDI/Track.src/M000072.html +23 -0
- data/html/classes/MIDI/Track.src/M000073.html +21 -0
- data/html/classes/MIDI/Track.src/M000074.html +26 -0
- data/html/classes/MIDI/Track.src/M000075.html +18 -0
- data/html/classes/MIDI/Track.src/M000076.html +22 -0
- data/html/classes/MIDI/Track.src/M000077.html +25 -0
- data/html/classes/MIDI/Track.src/M000078.html +22 -0
- data/html/classes/MIDI/Track.src/M000079.html +26 -0
- data/html/classes/MIDI/Track.src/M000080.html +18 -0
- data/html/classes/MIDI/Track.src/M000081.html +19 -0
- data/html/classes/MIDI/TuneRequest.html +171 -0
- data/html/classes/MIDI/TuneRequest.src/M000126.html +18 -0
- data/html/classes/MIDI/TuneRequest.src/M000127.html +20 -0
- data/html/classes/MIDI/TuneRequest.src/M000128.html +18 -0
- data/html/classes/MIDI/Utils.html +190 -0
- data/html/classes/MIDI/Utils.src/M000190.html +20 -0
- data/html/classes/MIDI/Utils.src/M000191.html +25 -0
- data/html/classes/MIDI.html +758 -0
- data/html/created.rid +1 -0
- data/html/files/README.html +681 -0
- data/html/files/TODO.html +142 -0
- data/html/files/lib/midilib/consts_rb.html +107 -0
- data/html/files/lib/midilib/event_rb.html +109 -0
- data/html/files/lib/midilib/info_rb.html +101 -0
- data/html/files/lib/midilib/io/midifile_rb.html +108 -0
- data/html/files/lib/midilib/io/seqreader_rb.html +110 -0
- data/html/files/lib/midilib/io/seqwriter_rb.html +115 -0
- data/html/files/lib/midilib/measure_rb.html +108 -0
- data/html/files/lib/midilib/sequence_rb.html +110 -0
- data/html/files/lib/midilib/track_rb.html +108 -0
- data/html/files/lib/midilib/utils_rb.html +101 -0
- data/html/files/lib/midilib_rb.html +124 -0
- data/html/fr_class_index.html +63 -0
- data/html/fr_file_index.html +39 -0
- data/html/fr_method_index.html +224 -0
- data/html/index.html +24 -0
- data/html/rdoc-style.css +208 -0
- data/lib/midilib/consts.rb +2 -1
- data/lib/midilib/event.rb +132 -4
- data/lib/midilib/info.rb +2 -2
- data/lib/midilib/io/midifile.rb +3 -2
- data/lib/midilib/io/seqreader.rb +10 -6
- data/lib/midilib/measure.rb +80 -0
- data/lib/midilib/sequence.rb +50 -3
- data/test/test.mid +0 -0
- metadata +343 -38
data/lib/midilib/event.rb
CHANGED
@@ -23,6 +23,10 @@ class Event
|
|
23
23
|
# decimal # (true). Delta times are always printed as decimal.
|
24
24
|
attr_accessor :print_decimal_numbers
|
25
25
|
|
26
|
+
# Determines if to_s outputs MIDI channel numbers from 1-16 instead
|
27
|
+
# of the default 0-15.
|
28
|
+
attr_accessor :print_channel_numbers_from_one
|
29
|
+
|
26
30
|
def initialize(status = 0, delta_time = 0)
|
27
31
|
@status = status
|
28
32
|
@delta_time = delta_time
|
@@ -33,6 +37,9 @@ class Event
|
|
33
37
|
@is_meta = false
|
34
38
|
@is_system = false
|
35
39
|
@is_realtime = false
|
40
|
+
@is_timesig = false
|
41
|
+
@is_keysig = false
|
42
|
+
@is_program_change = false
|
36
43
|
@time_from_start = 0 # maintained by tracks
|
37
44
|
end
|
38
45
|
protected :initialize
|
@@ -74,13 +81,27 @@ class Event
|
|
74
81
|
def system?
|
75
82
|
return @is_system
|
76
83
|
end
|
84
|
+
|
85
|
+
# Returns +true+ if this is a time signature event.
|
86
|
+
def timesig?
|
87
|
+
return @is_timesig
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns +true+ if this is a key signature event.
|
91
|
+
def keysig?
|
92
|
+
return @is_keysig
|
93
|
+
end
|
77
94
|
|
78
95
|
# Returns +true+ if this is a realtime status byte.
|
79
|
-
|
80
96
|
def realtime?
|
81
97
|
return @is_realtime
|
82
98
|
end
|
83
99
|
|
100
|
+
# Returns +true+ if this is a program change.
|
101
|
+
def program_change?
|
102
|
+
return @is_program_change
|
103
|
+
end
|
104
|
+
|
84
105
|
# Quantize this event's time_from_start by moving it to the nearest
|
85
106
|
# multiple of +boundary+. See MIDI::Track#quantize. *Note*: does not
|
86
107
|
# modify the event's delta_time, though MIDI::Track#quantize calls
|
@@ -106,6 +127,13 @@ class Event
|
|
106
127
|
return @print_decimal_numbers ? val.to_s : ('%02x' % val)
|
107
128
|
end
|
108
129
|
|
130
|
+
# Returns +val+ as a decimal or hex string, depending upon the value of
|
131
|
+
# @print_decimal_numbers.
|
132
|
+
def channel_to_s(val)
|
133
|
+
val += 1 if @print_channel_numbers_from_one
|
134
|
+
return number_to_s(val)
|
135
|
+
end
|
136
|
+
|
109
137
|
def to_s
|
110
138
|
"#{@delta_time}: "
|
111
139
|
end
|
@@ -125,7 +153,7 @@ class ChannelEvent < Event
|
|
125
153
|
protected :initialize
|
126
154
|
|
127
155
|
def to_s
|
128
|
-
return super << "ch #{
|
156
|
+
return super << "ch #{channel_to_s(@channel)} "
|
129
157
|
end
|
130
158
|
|
131
159
|
end
|
@@ -203,7 +231,7 @@ class PolyPressure < NoteEvent
|
|
203
231
|
end
|
204
232
|
def to_s
|
205
233
|
return super <<
|
206
|
-
"poly press #{
|
234
|
+
"poly press #{channel_to_s(@channel)} #{note_to_s} #{number_to_s(@velocity)}"
|
207
235
|
end
|
208
236
|
end
|
209
237
|
|
@@ -236,6 +264,7 @@ class ProgramChange < ChannelEvent
|
|
236
264
|
def initialize(channel = 0, program = 0, delta_time = 0)
|
237
265
|
super(PROGRAM_CHANGE, channel, delta_time)
|
238
266
|
@program = program
|
267
|
+
@is_program_change = true
|
239
268
|
end
|
240
269
|
|
241
270
|
def data_as_bytes
|
@@ -526,7 +555,9 @@ class Tempo < MetaEvent
|
|
526
555
|
|
527
556
|
# Translates microseconds per quarter note (beat) to beats per minute.
|
528
557
|
def Tempo.mpq_to_bpm(mpq)
|
529
|
-
|
558
|
+
# Nov 17 2007: Fixed integer rounding error issue:
|
559
|
+
# 110 bpm (as 545455 msecs) becomes 109.999 (which became 109 bpm)
|
560
|
+
return Integer(MICROSECS_PER_MINUTE.to_f / mpq + 0.49)
|
530
561
|
end
|
531
562
|
|
532
563
|
def initialize(msecs_per_qnote, delta_time = 0)
|
@@ -556,4 +587,101 @@ class Tempo < MetaEvent
|
|
556
587
|
"tempo #{@data} msecs per qnote (#{Tempo.mpq_to_bpm(@data)} bpm)"
|
557
588
|
end
|
558
589
|
end
|
590
|
+
|
591
|
+
# Container for time signature events
|
592
|
+
class TimeSig < MetaEvent
|
593
|
+
|
594
|
+
# Constructor
|
595
|
+
def initialize(numer, denom, clocks, qnotes, delta_time = 0)
|
596
|
+
super(META_TIME_SIG, [numer, denom, clocks, qnotes], delta_time)
|
597
|
+
@is_timesig = true
|
598
|
+
end
|
599
|
+
|
600
|
+
# Returns the complete event as stored in the sequence
|
601
|
+
def data_as_bytes
|
602
|
+
data = ''
|
603
|
+
data << @status
|
604
|
+
data << @meta_type
|
605
|
+
data << 4
|
606
|
+
data << @data[0]
|
607
|
+
data << @data[1]
|
608
|
+
data << @data[2]
|
609
|
+
data << @data[3]
|
610
|
+
end
|
611
|
+
|
612
|
+
# Calculates the duration (in ticks) for a full measure
|
613
|
+
def measure_duration(ppqn)
|
614
|
+
(4 * ppqn * @data[0]) / (2**@data[1])
|
615
|
+
end
|
616
|
+
|
617
|
+
# Returns the numerator (the top digit) for the time signature
|
618
|
+
def numerator
|
619
|
+
@data[0]
|
620
|
+
end
|
621
|
+
|
622
|
+
# Returns the denominator of the time signature. Use it as a power of 2
|
623
|
+
# to get the displayed (lower-part) digit of the time signature.
|
624
|
+
def denominator
|
625
|
+
@data[1]
|
626
|
+
end
|
627
|
+
|
628
|
+
# Returns the metronome tick duration for the time signature. On
|
629
|
+
# each quarter note, there's 24 ticks.
|
630
|
+
def metronome_ticks
|
631
|
+
@data[2]
|
632
|
+
end
|
633
|
+
|
634
|
+
# Returns the time signature for the event as a string.
|
635
|
+
# Example: "time sig 3/4"
|
636
|
+
def to_s
|
637
|
+
"time sig #{@data[0]}/#{2**@data[1]}"
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
# Container for key signature events
|
642
|
+
class KeySig < MetaEvent
|
643
|
+
|
644
|
+
# Constructor
|
645
|
+
def initialize(sharpflat, is_minor, delta_time = 0)
|
646
|
+
super(META_KEY_SIG, [sharpflat, is_minor], delta_time)
|
647
|
+
@is_keysig = true
|
648
|
+
end
|
649
|
+
|
650
|
+
# Returns the complete event as stored in the sequence
|
651
|
+
def data_as_bytes
|
652
|
+
data = ''
|
653
|
+
data << @status
|
654
|
+
data << @meta_type
|
655
|
+
data << 2
|
656
|
+
data << @data[0]
|
657
|
+
data << @data[1] ? 1 : 0
|
658
|
+
end
|
659
|
+
|
660
|
+
# Returns true if it's a minor key, false if major key
|
661
|
+
def minor_key?
|
662
|
+
@data[1]
|
663
|
+
end
|
664
|
+
|
665
|
+
# Returns true if it's a major key, false if minor key
|
666
|
+
def major_key?
|
667
|
+
!@data[1]
|
668
|
+
end
|
669
|
+
|
670
|
+
# Returns the number of sharps/flats in the key sig. Negative for flats.
|
671
|
+
def sharpflat
|
672
|
+
@data[0] > 7 ? @data[0] - 256 : @data[0]
|
673
|
+
end
|
674
|
+
|
675
|
+
# Returns the key signature as a text string.
|
676
|
+
# Example: "key sig A flat major"
|
677
|
+
def to_s
|
678
|
+
majorkeys = ['C flat', 'G flat', 'D flat', 'A flat', 'E flat', 'B flat', 'F',
|
679
|
+
'C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#']
|
680
|
+
minorkeys = ['a flat', 'e flat', 'b flat', 'f', 'c', 'g', 'd',
|
681
|
+
'a', 'e', 'b', 'f#', 'c#', 'g#', 'd#', 'a#']
|
682
|
+
minor_key? ? "key sig #{minorkeys[sharpflat + 7]} minor" :
|
683
|
+
"key sig #{majorkeys[sharpflat + 7]} major"
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
559
687
|
end
|
data/lib/midilib/info.rb
CHANGED
data/lib/midilib/io/midifile.rb
CHANGED
@@ -54,10 +54,11 @@ class MIDIFile
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# This default getc implementation tries to read a single character
|
57
|
-
# from io.
|
57
|
+
# from io and returns it as an integer.
|
58
58
|
def getc
|
59
59
|
@bytes_to_be_read -= 1
|
60
|
-
|
60
|
+
c = @io.getc()
|
61
|
+
c.respond_to?(:bytes) ? c.bytes.first : c
|
61
62
|
end
|
62
63
|
|
63
64
|
# The default error handler.
|
data/lib/midilib/io/seqreader.rb
CHANGED
@@ -145,9 +145,11 @@ class SeqReader < MIDIFile
|
|
145
145
|
|
146
146
|
def text(type, msg)
|
147
147
|
case type
|
148
|
-
|
149
|
-
|
150
|
-
when
|
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
|
151
153
|
@track.instrument = msg
|
152
154
|
when META_MARKER
|
153
155
|
@track.events << Marker.new(msg, @curr_ticks)
|
@@ -168,6 +170,7 @@ class SeqReader < MIDIFile
|
|
168
170
|
|
169
171
|
def time_signature(numer, denom, clocks, qnotes)
|
170
172
|
@seq.time_signature(numer, denom, clocks, qnotes)
|
173
|
+
@track.events << TimeSig.new(numer, denom, clocks, qnotes, @curr_ticks)
|
171
174
|
end
|
172
175
|
|
173
176
|
# --
|
@@ -179,10 +182,11 @@ class SeqReader < MIDIFile
|
|
179
182
|
@track.events << Tempo.new(microsecs, @curr_ticks)
|
180
183
|
end
|
181
184
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
+
def key_signature(sharpflat, is_minor)
|
186
|
+
@track.events << KeySig.new(sharpflat, is_minor, @curr_ticks)
|
187
|
+
end
|
185
188
|
|
189
|
+
# --
|
186
190
|
# def arbitrary(msg)
|
187
191
|
# end
|
188
192
|
# ++
|
@@ -0,0 +1,80 @@
|
|
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
|
data/lib/midilib/sequence.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'midilib/io/seqreader'
|
2
2
|
require 'midilib/io/seqwriter'
|
3
|
+
require 'midilib/measure.rb'
|
3
4
|
|
4
5
|
module MIDI
|
5
6
|
|
@@ -27,7 +28,12 @@ class Sequence
|
|
27
28
|
'64th' => 0.0625
|
28
29
|
}
|
29
30
|
|
30
|
-
|
31
|
+
# Array with all tracks for the sequence
|
32
|
+
attr_accessor :tracks
|
33
|
+
# Pulses (i.e. clocks) Per Quarter Note resolution for the sequence
|
34
|
+
attr_accessor :ppqn
|
35
|
+
# The MIDI file format (0, 1, or 2)
|
36
|
+
attr_accessor :format
|
31
37
|
attr_accessor :numer, :denom, :clocks, :qnotes
|
32
38
|
# The class to use for reading MIDI from a stream. The default is
|
33
39
|
# MIDI::IO::SeqReader. You can change this at any time.
|
@@ -43,7 +49,7 @@ class Sequence
|
|
43
49
|
# Time signature
|
44
50
|
@numer = 4 # Numer + denom = 4/4 time default
|
45
51
|
@denom = 2
|
46
|
-
@clocks =
|
52
|
+
@clocks = 24 # Bug fix Nov 11, 2007 - this is not the same as ppqn!
|
47
53
|
@qnotes = 8
|
48
54
|
|
49
55
|
@reader_class = IO::SeqReader
|
@@ -124,7 +130,6 @@ class Sequence
|
|
124
130
|
|
125
131
|
# Reads a MIDI stream.
|
126
132
|
def read(io, proc = nil) # :yields: track, num_tracks, index
|
127
|
-
@tracks = Array.new()
|
128
133
|
reader = @reader_class.new(self, block_given?() ? Proc.new() : proc)
|
129
134
|
reader.read_from(io)
|
130
135
|
end
|
@@ -140,5 +145,47 @@ class Sequence
|
|
140
145
|
@tracks.each { | track | yield track }
|
141
146
|
end
|
142
147
|
|
148
|
+
# Returns a Measures object, which is an array container for all measures
|
149
|
+
# in the sequence
|
150
|
+
def get_measures
|
151
|
+
# Collect time sig events and scan for last event time
|
152
|
+
time_sigs = []
|
153
|
+
max_pos = 0
|
154
|
+
@tracks.each { |t|
|
155
|
+
t.each { |e|
|
156
|
+
time_sigs << e if e.timesig?
|
157
|
+
max_pos = e.time_from_start if e.time_from_start > max_pos
|
158
|
+
}
|
159
|
+
}
|
160
|
+
time_sigs.sort { |x,y| x.time_from_start <=> y.time_from_start }
|
161
|
+
|
162
|
+
# Add a "fake" time sig event at the very last position of the sequence,
|
163
|
+
# just to make sure the whole sequence is calculated.
|
164
|
+
t = MIDI::TimeSig.new(4, 2, 24, 8, 0)
|
165
|
+
t.time_from_start = max_pos
|
166
|
+
time_sigs << t
|
167
|
+
|
168
|
+
# Default to 4/4
|
169
|
+
measure_length = @ppqn * 4
|
170
|
+
oldnumer, olddenom, oldbeats = 4, 2, 24
|
171
|
+
|
172
|
+
measures = MIDI::Measures.new(max_pos, @ppqn)
|
173
|
+
curr_pos = 0
|
174
|
+
curr_meas_no = 1
|
175
|
+
time_sigs.each { |te|
|
176
|
+
meas_count = (te.time_from_start - curr_pos) / measure_length
|
177
|
+
meas_count += 1 if (te.time_from_start - curr_pos) % measure_length > 0
|
178
|
+
1.upto(meas_count) { |i|
|
179
|
+
measures << MIDI::Measure.new(curr_meas_no,
|
180
|
+
curr_pos, measure_length, oldnumer, olddenom, oldbeats)
|
181
|
+
curr_meas_no += 1
|
182
|
+
curr_pos += measure_length
|
183
|
+
}
|
184
|
+
oldnumer, olddenom, oldbeats = te.numerator, te.denominator, te.metronome_ticks
|
185
|
+
measure_length = te.measure_duration(@ppqn)
|
186
|
+
}
|
187
|
+
measures
|
188
|
+
end
|
189
|
+
|
143
190
|
end
|
144
191
|
end
|
data/test/test.mid
ADDED
Binary file
|