midilib 2.0.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +2 -1
- data/Credits +44 -2
- data/README.rdoc +13 -9
- data/Rakefile +36 -53
- data/TODO.rdoc +13 -2
- data/examples/from_scratch.rb +4 -6
- data/examples/measures_mbt.rb +11 -11
- data/examples/print_program_changes.rb +11 -11
- data/examples/reader2text.rb +191 -191
- data/examples/seq2text.rb +18 -18
- data/examples/split.rb +21 -20
- data/examples/strings.rb +15 -15
- data/examples/transpose.rb +41 -42
- data/html/MIDI/ActiveSense.html +89 -213
- data/html/MIDI/ChannelEvent.html +95 -224
- data/html/MIDI/ChannelPressure.html +103 -241
- data/html/MIDI/Clock.html +89 -213
- data/html/MIDI/Continue.html +89 -213
- data/html/MIDI/Controller.html +105 -246
- data/html/MIDI/Event.html +134 -358
- data/html/MIDI/IO/MIDIFile.html +544 -1148
- data/html/MIDI/IO/SeqReader.html +273 -577
- data/html/MIDI/IO/SeqWriter.html +233 -439
- data/html/MIDI/IO.html +48 -164
- data/html/MIDI/KeySig.html +148 -291
- data/html/MIDI/Marker.html +73 -192
- data/html/MIDI/Measure.html +104 -267
- data/html/MIDI/Measures.html +106 -259
- data/html/MIDI/MetaEvent.html +171 -352
- data/html/MIDI/NoteEvent.html +114 -276
- data/html/MIDI/NoteOff.html +95 -223
- data/html/MIDI/NoteOn.html +95 -223
- data/html/MIDI/PitchBend.html +104 -242
- data/html/MIDI/PolyPressure.html +102 -246
- data/html/MIDI/ProgramChange.html +103 -241
- data/html/MIDI/Realtime.html +96 -230
- data/html/MIDI/Sequence.html +256 -576
- data/html/MIDI/SongPointer.html +104 -242
- data/html/MIDI/SongSelect.html +103 -241
- data/html/MIDI/Start.html +89 -213
- data/html/MIDI/Stop.html +89 -213
- data/html/MIDI/SystemCommon.html +73 -192
- data/html/MIDI/SystemExclusive.html +106 -244
- data/html/MIDI/SystemReset.html +89 -213
- data/html/MIDI/Tempo.html +127 -309
- data/html/MIDI/TimeSig.html +119 -300
- data/html/MIDI/Track.html +214 -494
- data/html/MIDI/TuneRequest.html +96 -230
- data/html/MIDI/Utils.html +91 -233
- data/html/MIDI.html +142 -526
- data/html/Object.html +197 -0
- data/html/README_rdoc.html +280 -486
- data/html/TODO_rdoc.html +68 -145
- data/html/created.rid +15 -14
- data/html/css/fonts.css +167 -0
- data/html/css/rdoc.css +639 -0
- data/html/fonts/Lato-Light.ttf +0 -0
- data/html/fonts/Lato-LightItalic.ttf +0 -0
- data/html/fonts/Lato-Regular.ttf +0 -0
- data/html/fonts/Lato-RegularItalic.ttf +0 -0
- data/html/fonts/SourceCodePro-Bold.ttf +0 -0
- data/html/fonts/SourceCodePro-Regular.ttf +0 -0
- data/html/images/add.png +0 -0
- data/html/images/arrow_up.png +0 -0
- data/html/images/delete.png +0 -0
- data/html/images/tag_blue.png +0 -0
- data/html/index.html +230 -446
- data/html/js/darkfish.js +22 -91
- data/html/js/navigation.js +4 -41
- data/html/js/navigation.js.gz +0 -0
- data/html/js/search.js +41 -25
- data/html/js/search_index.js +1 -1
- data/html/js/search_index.js.gz +0 -0
- data/html/js/searcher.js +9 -8
- data/html/js/searcher.js.gz +0 -0
- data/html/table_of_contents.html +1111 -505
- data/install.rb +53 -34
- data/lib/midilib/consts.rb +406 -408
- data/lib/midilib/event.rb +335 -306
- data/lib/midilib/info.rb +5 -7
- data/lib/midilib/io/midifile.rb +424 -452
- data/lib/midilib/io/seqreader.rb +200 -192
- data/lib/midilib/io/seqwriter.rb +151 -147
- data/lib/midilib/measure.rb +78 -80
- data/lib/midilib/mergesort.rb +39 -0
- data/lib/midilib/sequence.rb +93 -87
- data/lib/midilib/track.rb +71 -118
- data/lib/midilib/utils.rb +17 -20
- data/lib/midilib.rb +5 -5
- data/test/event_equality.rb +50 -52
- data/test/test_event.rb +120 -124
- data/test/test_io.rb +118 -38
- data/test/test_mergesort.rb +37 -0
- data/test/test_midifile.rb +6 -19
- data/test/test_sequence.rb +62 -61
- data/test/test_track.rb +126 -155
- data/test/test_varlen.rb +23 -27
- metadata +67 -62
- data/html/IO.html +0 -259
- data/html/MIDI/MIDI/MIDI/Array.html +0 -353
- data/html/MIDI/MIDI/MIDI.html +0 -204
- data/html/MIDI/MIDI.html +0 -204
- data/html/js/jquery.js +0 -18
- data/html/rdoc.css +0 -543
data/examples/reader2text.rb
CHANGED
@@ -20,202 +20,202 @@ require 'midilib/io/midifile'
|
|
20
20
|
DEFAULT_MIDI_TEST_FILE = 'NoFences.mid'
|
21
21
|
|
22
22
|
class TextTranslator < MIDI::IO::MIDIFile
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
end
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
23
|
+
def initialize(seq, &block)
|
24
|
+
super()
|
25
|
+
@seq = seq
|
26
|
+
@track = nil
|
27
|
+
@update_block = block
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generate a unique number for a channel/note combination. This is used
|
31
|
+
# to remember pending note on events.
|
32
|
+
def note_hash(chan, note)
|
33
|
+
(chan << 8) + note
|
34
|
+
end
|
35
|
+
|
36
|
+
# Print a delta time.
|
37
|
+
def pdelta
|
38
|
+
print "#{@curr_ticks}: "
|
39
|
+
end
|
40
|
+
|
41
|
+
# The remaining methods are overrides of methods in MIDI::IO::MIDIFile.
|
42
|
+
|
43
|
+
def header(format, ntrks, division)
|
44
|
+
puts "header: format = #{format}, ntrks = #{ntrks}," +
|
45
|
+
" division = #{division}"
|
46
|
+
|
47
|
+
@ntrks = ntrks
|
48
|
+
@update_block.call(nil, @ntrks, 0) if @update_block
|
49
|
+
end
|
50
|
+
|
51
|
+
def start_track
|
52
|
+
pdelta
|
53
|
+
puts 'track start'
|
54
|
+
|
55
|
+
@pending = []
|
56
|
+
@chan_mask = 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def end_track
|
60
|
+
pdelta
|
61
|
+
puts "track end; chans used bitmask = #{@chan_mask}"
|
62
|
+
# Write message for any pending note on messages
|
63
|
+
@pending.each_with_index do |num, chan|
|
64
|
+
if note_obj
|
65
|
+
puts "pending note off missing for chan #{num >> 8}," +
|
66
|
+
" note #{num & 0xff}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@pending = nil
|
70
|
+
|
71
|
+
# call update block
|
72
|
+
@update_block.call(@track, @ntrks, @seq.tracks.length) if @update_block
|
73
|
+
end
|
74
|
+
|
75
|
+
def note_on(chan, note, vel)
|
76
|
+
pdelta
|
77
|
+
if vel == 0
|
78
|
+
print '(note on, vel 0) '
|
79
|
+
note_off(chan, note, 64)
|
80
|
+
return
|
81
|
+
end
|
82
|
+
|
83
|
+
puts "note on chan #{chan}, note #{note}, vel #{vel}"
|
84
|
+
@pending << note_hash(chan, note)
|
85
|
+
track_uses_channel(chan)
|
86
|
+
end
|
87
|
+
|
88
|
+
def note_off(chan, note, vel)
|
89
|
+
pdelta
|
90
|
+
# Find note on, create note off, connect the two, and remove
|
91
|
+
# note on from pending list.
|
92
|
+
pnum = note_hash(chan, note)
|
93
|
+
@pending.each_with_index do |num, i|
|
94
|
+
next unless pnum == num
|
95
|
+
|
96
|
+
puts "note off chan #{chan}, note #{note}, vel #{vel}"
|
97
|
+
@pending.delete_at(i)
|
98
|
+
return
|
99
|
+
end
|
100
|
+
puts "note off with no earlier note on (ch #{chan}, note" +
|
101
|
+
" #{note}, vel #{vel})"
|
102
|
+
end
|
103
|
+
|
104
|
+
def pressure(chan, note, press)
|
105
|
+
pdelta
|
106
|
+
puts "pressure chan #{chan}, note #{note}, press #{press}"
|
107
|
+
track_uses_channel(chan)
|
108
|
+
end
|
109
|
+
|
110
|
+
def controller(chan, control, value)
|
111
|
+
pdelta
|
112
|
+
puts "controller chan #{chan}, control #{control}, value #{value}"
|
113
|
+
track_uses_channel(chan)
|
114
|
+
end
|
115
|
+
|
116
|
+
def pitch_bend(chan, msb, lsb)
|
117
|
+
pdelta
|
118
|
+
puts "pitch bend chan #{chan}, msb #{msb}, lsb #{lsb}"
|
119
|
+
track_uses_channel(chan)
|
120
|
+
end
|
121
|
+
|
122
|
+
def program(chan, program)
|
123
|
+
pdelta
|
124
|
+
puts "program chan #{chan}, program #{program}"
|
125
|
+
track_uses_channel(chan)
|
126
|
+
end
|
127
|
+
|
128
|
+
def chan_pressure(chan, press)
|
129
|
+
pdelta
|
130
|
+
puts "chan press chan #{chan}, press #{press}"
|
131
|
+
track_uses_channel(chan)
|
132
|
+
end
|
133
|
+
|
134
|
+
def sysex(msg)
|
135
|
+
pdelta
|
136
|
+
puts "sysex size #{msg.length}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def meta_misc(type, msg)
|
140
|
+
pdelta
|
141
|
+
puts "meta misc type #{type}, length #{msg.length}"
|
142
|
+
end
|
143
|
+
|
144
|
+
def sequencer_specific(type, msg)
|
145
|
+
pdelta
|
146
|
+
puts "sequencer specific type #{type}, msg #{msg.length}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def sequence_number(num)
|
150
|
+
pdelta
|
151
|
+
puts "sequence number #{num}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def text(type, msg)
|
155
|
+
pdelta
|
156
|
+
msg = MIDI::MetaEvent.bytes_as_str(msg)
|
157
|
+
case type
|
158
|
+
when MIDI::META_SEQ_NAME
|
159
|
+
puts "seq or track name #{msg}"
|
160
|
+
when MIDI::META_INSTRUMENT
|
161
|
+
puts "instrument name #{msg}"
|
162
|
+
when MIDI::META_MARKER
|
163
|
+
puts "marker #{msg}"
|
164
|
+
else
|
165
|
+
puts "text = #{msg}, type = #{type}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def eot
|
170
|
+
pdelta
|
171
|
+
puts 'end of track event'
|
172
|
+
end
|
173
|
+
|
174
|
+
def time_signature(numer, denom, clocks, qnotes)
|
175
|
+
pdelta
|
176
|
+
puts "time sig numer #{numer}, denom #{denom}, clocks #{clocks}," +
|
177
|
+
" qnotes #{qnotes}"
|
178
|
+
end
|
179
|
+
|
180
|
+
def smpte(hour, min, sec, frame, fract)
|
181
|
+
pdelta
|
182
|
+
puts "smpte #{hour}:#{min}.#{sec}, frame #{frame}, fract #{fract}"
|
183
|
+
end
|
184
|
+
|
185
|
+
def tempo(microsecs)
|
186
|
+
pdelta
|
187
|
+
bpm = 1.0 / microsecs # quarter notes per microsecond
|
188
|
+
bpm *= 1_000_000.0 # quarter notes per second
|
189
|
+
bpm *= 60.0 # quarter notes per minute
|
190
|
+
puts "tempo microsecs pqn = #{microsecs} (#{bpm} bpm)"
|
191
|
+
end
|
192
|
+
|
193
|
+
def key_signature(sharpflat, is_minor)
|
194
|
+
pdelta
|
195
|
+
puts "key sig sharpflat #{sharpflat}, is_minor #{is_minor}"
|
196
|
+
end
|
197
|
+
|
198
|
+
def arbitrary(msg)
|
199
|
+
pdelta
|
200
|
+
puts "arbitrary length = #{msg.length}"
|
201
|
+
end
|
202
|
+
|
203
|
+
def track_uses_channel(chan)
|
204
|
+
@chan_mask |= (1 << chan)
|
205
|
+
end
|
206
206
|
end
|
207
207
|
|
208
208
|
# ================================================================
|
209
209
|
|
210
|
-
seq = MIDI::Sequence.new
|
210
|
+
seq = MIDI::Sequence.new
|
211
211
|
|
212
212
|
# Specify what class to use when reading the MIDI file.
|
213
213
|
seq.reader_class = TextTranslator
|
214
214
|
|
215
|
-
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb')
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
215
|
+
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb') do |file|
|
216
|
+
# The block we pass in to Sequence.read is called at the end of every
|
217
|
+
# track read. It is optional, but is useful for progress reports.
|
218
|
+
seq.read(file) do |track, num_tracks, i|
|
219
|
+
puts "read track #{track ? track.name : ''} (#{i} of #{num_tracks})"
|
220
|
+
end
|
221
|
+
end
|
data/examples/seq2text.rb
CHANGED
@@ -19,23 +19,23 @@ require 'midilib/sequence'
|
|
19
19
|
DEFAULT_MIDI_TEST_FILE = 'NoFences.mid'
|
20
20
|
|
21
21
|
# Read from MIDI file
|
22
|
-
seq = MIDI::Sequence.new
|
22
|
+
seq = MIDI::Sequence.new
|
23
23
|
|
24
|
-
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb')
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb') do |file|
|
25
|
+
# The block we pass in to Sequence.read is called at the end of every
|
26
|
+
# track read. It is optional, but is useful for progress reports.
|
27
|
+
seq.read(file) do |track, num_tracks, i|
|
28
|
+
puts "read track #{track ? track.name : ''} (#{i} of #{num_tracks})"
|
29
|
+
end
|
30
|
+
end
|
31
31
|
|
32
|
-
seq.each
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
32
|
+
seq.each do |track|
|
33
|
+
puts "*** track name \"#{track.name}\""
|
34
|
+
puts "instrument name \"#{track.instrument}\""
|
35
|
+
puts "#{track.events.length} events"
|
36
|
+
track.each do |e|
|
37
|
+
e.print_decimal_numbers = true # default = false (print hex)
|
38
|
+
e.print_note_names = true # default = false (print note numbers)
|
39
|
+
puts e
|
40
|
+
end
|
41
|
+
end
|
data/examples/split.rb
CHANGED
@@ -22,31 +22,32 @@ DEFAULT_MIDI_TEST_FILE = 'NoFences.mid'
|
|
22
22
|
filename = ARGV[0]
|
23
23
|
include_tempo_track = true
|
24
24
|
if filename == '-x'
|
25
|
-
|
26
|
-
|
25
|
+
include_tempo_track = false
|
26
|
+
filename = ARGV[1]
|
27
27
|
end
|
28
28
|
|
29
29
|
# Read from MIDI file
|
30
|
-
seq = MIDI::Sequence.new
|
30
|
+
seq = MIDI::Sequence.new
|
31
31
|
|
32
|
-
File.open(filename || DEFAULT_MIDI_TEST_FILE, 'rb')
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
File.open(filename || DEFAULT_MIDI_TEST_FILE, 'rb') do |file|
|
33
|
+
# The block we pass in to Sequence.read is called at the end of every
|
34
|
+
# track read. It is optional, but is useful for progress reports.
|
35
|
+
seq.read(file) do |track, num_tracks, i|
|
36
|
+
puts "read track #{track ? track.name : ''} (#{i} of #{num_tracks})"
|
37
|
+
end
|
38
|
+
end
|
39
39
|
|
40
40
|
t0 = seq.tracks[0]
|
41
41
|
unless include_tempo_track
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
s = MIDI::Sequence.new
|
43
|
+
s.tracks << t0
|
44
|
+
File.open('tempo_track.mid', 'wb') { |file| s.write(file) }
|
45
|
+
end
|
46
|
+
seq.each_with_index do |track, i|
|
47
|
+
next unless i > 0
|
48
|
+
|
49
|
+
s = MIDI::Sequence.new
|
50
|
+
s.tracks << t0 if include_tempo_track
|
51
|
+
s.tracks << track
|
52
|
+
File.open("#{track.name}.mid", 'wb') { |file| s.write(file) }
|
45
53
|
end
|
46
|
-
seq.each_with_index { | track, i |
|
47
|
-
next unless i > 0
|
48
|
-
s = MIDI::Sequence.new
|
49
|
-
s.tracks << t0 if include_tempo_track
|
50
|
-
s.tracks << track
|
51
|
-
File.open("#{track.name}.mid", 'wb') { | file | s.write(file) }
|
52
|
-
}
|
data/examples/strings.rb
CHANGED
@@ -15,20 +15,20 @@ require 'midilib/consts'
|
|
15
15
|
|
16
16
|
DEFAULT_MIDI_TEST_FILE = 'NoFences.mid'
|
17
17
|
|
18
|
-
seq = MIDI::Sequence.new
|
19
|
-
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb')
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
seq = MIDI::Sequence.new
|
19
|
+
File.open(ARGV[0] || DEFAULT_MIDI_TEST_FILE, 'rb') do |file|
|
20
|
+
# The block we pass in to Sequence.read is called at the end of every
|
21
|
+
# track read. It is optional, but is useful for progress reports.
|
22
|
+
seq.read(file) do |track, num_tracks, i|
|
23
|
+
puts "read track #{track ? track.name : ''} (#{i} of #{num_tracks})"
|
24
|
+
end
|
25
|
+
end
|
26
26
|
|
27
27
|
include MIDI
|
28
|
-
seq.each
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
seq.each do |track|
|
29
|
+
track.each do |event|
|
30
|
+
puts event.data if event.is_a?(MIDI::MetaEvent) &&
|
31
|
+
[META_TEXT, META_COPYRIGHT, META_SEQ_NAME, META_INSTRUMENT,
|
32
|
+
META_LYRIC, META_CUE, META_MARKER].include?(event.meta_type)
|
33
|
+
end
|
34
|
+
end
|
data/examples/transpose.rb
CHANGED
@@ -17,59 +17,58 @@ require 'midilib/sequence'
|
|
17
17
|
require 'midilib/io/seqreader'
|
18
18
|
require 'midilib/io/seqwriter'
|
19
19
|
|
20
|
-
|
21
20
|
def usage
|
22
|
-
|
23
|
-
usage: #{$0} [--channel|-c channel] [--transpose|-t half_steps]
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
EOF
|
29
|
-
|
21
|
+
$stderr.print <<~EOF
|
22
|
+
usage: #{$0} [--channel|-c channel] [--transpose|-t half_steps]
|
23
|
+
input_midi_file output_midi_file
|
24
|
+
#{' '}
|
25
|
+
--channel|-c channel 1-16; default is 1
|
26
|
+
--transpose|-t half_steps default = 12 (one octave up)
|
27
|
+
EOF
|
28
|
+
exit(1)
|
30
29
|
end
|
31
30
|
|
32
31
|
transpose = 12
|
33
32
|
channel = 0
|
34
33
|
|
35
34
|
g = GetoptLong.new(['--transpose', '-t', GetoptLong::REQUIRED_ARGUMENT],
|
36
|
-
|
37
|
-
g.each
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
35
|
+
['--channel', '-c', GetoptLong::REQUIRED_ARGUMENT])
|
36
|
+
g.each do |name, arg|
|
37
|
+
case name
|
38
|
+
when '--transpose'
|
39
|
+
transpose = arg.to_i
|
40
|
+
when '--channel'
|
41
|
+
channel = arg.to_i - 1
|
42
|
+
else
|
43
|
+
usage
|
44
|
+
end
|
45
|
+
end
|
47
46
|
|
48
|
-
usage
|
47
|
+
usage unless ARGV.length >= 2
|
49
48
|
|
50
|
-
seq = MIDI::Sequence.new
|
51
|
-
File.open(ARGV[0], 'rb')
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
seq = MIDI::Sequence.new
|
50
|
+
File.open(ARGV[0], 'rb') do |file|
|
51
|
+
# The block we pass in to Sequence.read is called at the end of every
|
52
|
+
# track read. It is optional, but is useful for progress reports.
|
53
|
+
seq.read(file) do |num_tracks, i|
|
54
|
+
puts "read track #{i} of #{num_tracks}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
seq.each do |track|
|
59
|
+
track.each do |event|
|
60
|
+
next unless event.is_a?(MIDI::NoteEvent) && event.channel == channel
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
end
|
69
|
-
}
|
70
|
-
}
|
62
|
+
val = event.note + transpose
|
63
|
+
if val < 0 || val > 127
|
64
|
+
warn 'transposition out of range; ignored'
|
65
|
+
else
|
66
|
+
event.note = val
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
71
70
|
|
72
71
|
# Output to named file or stdout.
|
73
72
|
file = ARGV[1] ? File.open(ARGV[1], 'wb') : $stdout
|
74
73
|
seq.write(file)
|
75
|
-
file.close
|
74
|
+
file.close if ARGV[1]
|