midilib 2.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +2 -1
  3. data/Credits +44 -2
  4. data/README.rdoc +13 -9
  5. data/Rakefile +36 -53
  6. data/TODO.rdoc +13 -2
  7. data/examples/from_scratch.rb +4 -6
  8. data/examples/measures_mbt.rb +11 -11
  9. data/examples/print_program_changes.rb +11 -11
  10. data/examples/reader2text.rb +191 -191
  11. data/examples/seq2text.rb +18 -18
  12. data/examples/split.rb +21 -20
  13. data/examples/strings.rb +15 -15
  14. data/examples/transpose.rb +41 -42
  15. data/html/MIDI/ActiveSense.html +89 -213
  16. data/html/MIDI/ChannelEvent.html +95 -224
  17. data/html/MIDI/ChannelPressure.html +103 -241
  18. data/html/MIDI/Clock.html +89 -213
  19. data/html/MIDI/Continue.html +89 -213
  20. data/html/MIDI/Controller.html +105 -246
  21. data/html/MIDI/Event.html +134 -358
  22. data/html/MIDI/IO/MIDIFile.html +544 -1148
  23. data/html/MIDI/IO/SeqReader.html +273 -577
  24. data/html/MIDI/IO/SeqWriter.html +233 -439
  25. data/html/MIDI/IO.html +48 -164
  26. data/html/MIDI/KeySig.html +148 -291
  27. data/html/MIDI/Marker.html +73 -192
  28. data/html/MIDI/Measure.html +104 -267
  29. data/html/MIDI/Measures.html +106 -259
  30. data/html/MIDI/MetaEvent.html +171 -352
  31. data/html/MIDI/NoteEvent.html +114 -276
  32. data/html/MIDI/NoteOff.html +95 -223
  33. data/html/MIDI/NoteOn.html +95 -223
  34. data/html/MIDI/PitchBend.html +104 -242
  35. data/html/MIDI/PolyPressure.html +102 -246
  36. data/html/MIDI/ProgramChange.html +103 -241
  37. data/html/MIDI/Realtime.html +96 -230
  38. data/html/MIDI/Sequence.html +256 -576
  39. data/html/MIDI/SongPointer.html +104 -242
  40. data/html/MIDI/SongSelect.html +103 -241
  41. data/html/MIDI/Start.html +89 -213
  42. data/html/MIDI/Stop.html +89 -213
  43. data/html/MIDI/SystemCommon.html +73 -192
  44. data/html/MIDI/SystemExclusive.html +106 -244
  45. data/html/MIDI/SystemReset.html +89 -213
  46. data/html/MIDI/Tempo.html +127 -309
  47. data/html/MIDI/TimeSig.html +119 -300
  48. data/html/MIDI/Track.html +214 -494
  49. data/html/MIDI/TuneRequest.html +96 -230
  50. data/html/MIDI/Utils.html +91 -233
  51. data/html/MIDI.html +142 -526
  52. data/html/Object.html +197 -0
  53. data/html/README_rdoc.html +280 -486
  54. data/html/TODO_rdoc.html +68 -145
  55. data/html/created.rid +15 -14
  56. data/html/css/fonts.css +167 -0
  57. data/html/css/rdoc.css +639 -0
  58. data/html/fonts/Lato-Light.ttf +0 -0
  59. data/html/fonts/Lato-LightItalic.ttf +0 -0
  60. data/html/fonts/Lato-Regular.ttf +0 -0
  61. data/html/fonts/Lato-RegularItalic.ttf +0 -0
  62. data/html/fonts/SourceCodePro-Bold.ttf +0 -0
  63. data/html/fonts/SourceCodePro-Regular.ttf +0 -0
  64. data/html/images/add.png +0 -0
  65. data/html/images/arrow_up.png +0 -0
  66. data/html/images/delete.png +0 -0
  67. data/html/images/tag_blue.png +0 -0
  68. data/html/index.html +230 -446
  69. data/html/js/darkfish.js +22 -91
  70. data/html/js/navigation.js +4 -41
  71. data/html/js/navigation.js.gz +0 -0
  72. data/html/js/search.js +41 -25
  73. data/html/js/search_index.js +1 -1
  74. data/html/js/search_index.js.gz +0 -0
  75. data/html/js/searcher.js +9 -8
  76. data/html/js/searcher.js.gz +0 -0
  77. data/html/table_of_contents.html +1111 -505
  78. data/install.rb +53 -34
  79. data/lib/midilib/consts.rb +406 -408
  80. data/lib/midilib/event.rb +335 -306
  81. data/lib/midilib/info.rb +5 -7
  82. data/lib/midilib/io/midifile.rb +424 -452
  83. data/lib/midilib/io/seqreader.rb +200 -192
  84. data/lib/midilib/io/seqwriter.rb +151 -147
  85. data/lib/midilib/measure.rb +78 -80
  86. data/lib/midilib/mergesort.rb +39 -0
  87. data/lib/midilib/sequence.rb +93 -87
  88. data/lib/midilib/track.rb +71 -118
  89. data/lib/midilib/utils.rb +17 -20
  90. data/lib/midilib.rb +5 -5
  91. data/test/event_equality.rb +50 -52
  92. data/test/test_event.rb +120 -124
  93. data/test/test_io.rb +118 -38
  94. data/test/test_mergesort.rb +37 -0
  95. data/test/test_midifile.rb +6 -19
  96. data/test/test_sequence.rb +62 -61
  97. data/test/test_track.rb +126 -155
  98. data/test/test_varlen.rb +23 -27
  99. metadata +67 -62
  100. data/html/IO.html +0 -259
  101. data/html/MIDI/MIDI/MIDI/Array.html +0 -353
  102. data/html/MIDI/MIDI/MIDI.html +0 -204
  103. data/html/MIDI/MIDI.html +0 -204
  104. data/html/js/jquery.js +0 -18
  105. data/html/rdoc.css +0 -543
@@ -5,77 +5,75 @@
5
5
  # classes. If someone disagrees, it would be trivial to move them there.
6
6
 
7
7
  module MIDI
8
-
9
- class Event
10
- def ==(an_obj)
11
- return an_obj.instance_of?(self.class) &&
12
- @status == an_obj.status &&
13
- @delta_time == an_obj.delta_time &&
14
- @time_from_start == an_obj.time_from_start
15
- end
8
+ class Event
9
+ def ==(other)
10
+ other.instance_of?(self.class) &&
11
+ @status == other.status &&
12
+ @delta_time == other.delta_time &&
13
+ @time_from_start == other.time_from_start
16
14
  end
15
+ end
17
16
 
18
- class ChannelEvent
19
- def ==(an_obj)
20
- return super(an_obj) && @channel == an_obj.channel
21
- end
17
+ class ChannelEvent
18
+ def ==(other)
19
+ super(other) && @channel == other.channel
22
20
  end
21
+ end
23
22
 
24
- class NoteEvent < ChannelEvent
25
- def ==(an_obj)
26
- return super(an_obj) &&
27
- @note == an_obj.note && @velocity == an_obj.velocity
28
- end
23
+ class NoteEvent < ChannelEvent
24
+ def ==(other)
25
+ super(other) &&
26
+ @note == other.note && @velocity == other.velocity
29
27
  end
28
+ end
30
29
 
31
- class Controller < ChannelEvent
32
- def ==(an_obj)
33
- return super(an_obj) &&
34
- @controller == an_obj.controller && @value == an_obj.value
35
- end
30
+ class Controller < ChannelEvent
31
+ def ==(other)
32
+ super(other) &&
33
+ @controller == other.controller && @value == other.value
36
34
  end
35
+ end
37
36
 
38
- class ProgramChange < ChannelEvent
39
- def ==(an_obj)
40
- return super(an_obj) && @program == an_obj.program
41
- end
37
+ class ProgramChange < ChannelEvent
38
+ def ==(other)
39
+ super(other) && @program == other.program
42
40
  end
41
+ end
43
42
 
44
- class ChannelPressure < ChannelEvent
45
- def ==(an_obj)
46
- return super(an_obj) && @pressure == an_obj.pressure
47
- end
43
+ class ChannelPressure < ChannelEvent
44
+ def ==(other)
45
+ super(other) && @pressure == other.pressure
48
46
  end
47
+ end
49
48
 
50
- class PitchBend < ChannelEvent
51
- def ==(an_obj)
52
- return super(an_obj) && @value == an_obj.value
53
- end
49
+ class PitchBend < ChannelEvent
50
+ def ==(other)
51
+ super(other) && @value == other.value
54
52
  end
53
+ end
55
54
 
56
- class SystemExclusive < SystemCommon
57
- def ==(an_obj)
58
- return super(an_obj) && @data == an_obj.data
59
- end
55
+ class SystemExclusive < SystemCommon
56
+ def ==(other)
57
+ super(other) && @data == other.data
60
58
  end
59
+ end
61
60
 
62
- class SongPointer < SystemCommon
63
- def ==(an_obj)
64
- return super(an_obj) && @pointer == an_obj.pointer
65
- end
61
+ class SongPointer < SystemCommon
62
+ def ==(other)
63
+ super(other) && @pointer == other.pointer
66
64
  end
65
+ end
67
66
 
68
- class SongSelect < SystemCommon
69
- def ==(an_obj)
70
- return super(an_obj) && @song == an_obj.song
71
- end
67
+ class SongSelect < SystemCommon
68
+ def ==(other)
69
+ super(other) && @song == other.song
72
70
  end
71
+ end
73
72
 
74
- class MetaEvent < Event
75
- def ==(an_obj)
76
- return super(an_obj) && @meta_type == an_obj.meta_type &&
77
- @data == an_obj.data
78
- end
73
+ class MetaEvent < Event
74
+ def ==(other)
75
+ super(other) && @meta_type == other.meta_type &&
76
+ @data == other.data
79
77
  end
80
-
78
+ end
81
79
  end
data/test/test_event.rb CHANGED
@@ -7,131 +7,127 @@ require 'test/unit'
7
7
  require 'midilib'
8
8
 
9
9
  class EventTester < Test::Unit::TestCase
10
-
11
- def test_note_on
12
- e = MIDI::NoteOn.new
13
- assert_equal(MIDI::NOTE_ON, e.status)
14
- assert_equal(0, e.channel)
15
- assert_equal(64, e.note)
16
- assert_equal(64, e.velocity)
17
- assert_equal(0, e.delta_time)
18
- assert_equal(0, e.time_from_start)
19
- end
20
-
21
- def test_quantize
22
- e = MIDI::NoteOn.new
23
- e.quantize_to(4)
24
- assert_equal(0, e.time_from_start)
25
-
26
- # Each value in this array is the expected quantized value of
27
- # its index in the array.
28
-
29
- # Test with quantize_to(4)
30
- [0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16].each_with_index {
31
- | after, before |
32
- e.time_from_start = before
33
- e.quantize_to(4)
34
- assert_equal(after, e.time_from_start)
35
- }
36
-
37
- # Test with quantize_to(6)
38
- [0, 0, 0, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12,
39
- 18, 18, 18, 18, 18, 18, 24].each_with_index {
40
- | after, before |
41
- e.time_from_start = before
42
- e.quantize_to(6)
43
- assert_equal(after, e.time_from_start)
44
- }
45
- end
46
-
47
- def test_to_s
48
- e = MIDI::NoteOn.new
49
- assert_equal("0: ch 00 on 40 40", e.to_s)
50
- e.print_decimal_numbers = true
51
- assert_equal("0: ch 0 on 64 64", e.to_s)
52
- e.print_note_names = true
53
- assert_equal("0: ch 0 on E4 64", e.to_s)
54
- e.print_decimal_numbers = false
55
- assert_equal("0: ch 00 on E4 40", e.to_s)
56
- end
57
-
58
- def test_pitch_bend
59
- e = MIDI::PitchBend.new(0, 128)
60
- b = e.data_as_bytes
61
- assert_equal(0, b[1]) # lsb, 7 bits
62
- assert_equal(1, b[2]) # msb, 7 bits
63
-
64
- e.value = (3 << 7) + 42
65
- b = e.data_as_bytes
66
- assert_equal(42, b[1]) # lsb, 7 bits
67
- assert_equal(3, b[2]) # msb, 7 bits
68
- end
69
-
70
- def test_quantize
71
- e = MIDI::NoteOn.new(0, 64, 64, 0)
72
- e.quantize_to(80)
73
- assert_equal(0, e.time_from_start)
74
-
75
- e.time_from_start = 1
76
- e.quantize_to(80)
77
- assert_equal(0, e.time_from_start)
78
-
79
- e.time_from_start = 70
80
- e.quantize_to(80)
81
- assert_equal(80, e.time_from_start)
82
-
83
- e.time_from_start = 100
84
- e.quantize_to(80)
85
- assert_equal(80, e.time_from_start)
86
-
87
- e.time_from_start = 398
88
- e.quantize_to(80)
89
- assert_equal(400, e.time_from_start)
90
-
91
- e.time_from_start = 405
92
- e.quantize_to(80)
93
- assert_equal(400, e.time_from_start)
94
-
95
- e.time_from_start = 439
96
- e.quantize_to(80)
97
- assert_equal(400, e.time_from_start)
98
-
99
- e.time_from_start = 440
100
- e.quantize_to(80)
101
- assert_equal(480, e.time_from_start)
102
-
103
- e.time_from_start = 441
104
- e.quantize_to(80)
105
- assert_equal(480, e.time_from_start)
10
+ def test_note_on
11
+ e = MIDI::NoteOn.new
12
+ assert_equal(MIDI::NOTE_ON, e.status)
13
+ assert_equal(0, e.channel)
14
+ assert_equal(64, e.note)
15
+ assert_equal(64, e.velocity)
16
+ assert_equal(0, e.delta_time)
17
+ assert_equal(0, e.time_from_start)
18
+ end
19
+
20
+ def test_to_s
21
+ e = MIDI::NoteOn.new
22
+ assert_equal('0: ch 00 on 40 40', e.to_s)
23
+ e.print_decimal_numbers = true
24
+ assert_equal('0: ch 0 on 64 64', e.to_s)
25
+ e.print_note_names = true
26
+ assert_equal('0: ch 0 on E4 64', e.to_s)
27
+ e.print_decimal_numbers = false
28
+ assert_equal('0: ch 00 on E4 40', e.to_s)
29
+ end
30
+
31
+ def test_pitch_bend
32
+ e = MIDI::PitchBend.new(0, 128)
33
+ b = e.data_as_bytes
34
+ assert_equal(0, b[1]) # lsb, 7 bits
35
+ assert_equal(1, b[2]) # msb, 7 bits
36
+
37
+ e.value = (3 << 7) + 42
38
+ b = e.data_as_bytes
39
+ assert_equal(42, b[1]) # lsb, 7 bits
40
+ assert_equal(3, b[2]) # msb, 7 bits
41
+ end
42
+
43
+ def test_quantize_1
44
+ e = MIDI::NoteOn.new
45
+ e.quantize_to(4)
46
+ assert_equal(0, e.time_from_start)
47
+
48
+ # Each value in this array is the expected quantized value of
49
+ # its index in the array.
50
+
51
+ # Test with quantize_to(4)
52
+ [0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16].each_with_index do |after, before|
53
+ e.time_from_start = before
54
+ e.quantize_to(4)
55
+ assert_equal(after, e.time_from_start)
106
56
  end
107
57
 
108
- def test_meta_strings
109
- e = MIDI::MetaEvent.new(MIDI::META_TEXT, [97, 98, 99])
110
- assert_equal([97, 98, 99], e.data)
111
- assert_equal('abc', e.data_as_str)
112
-
113
- assert_equal([MIDI::META_EVENT, MIDI::META_TEXT, 3, 97, 98, 99], e.data_as_bytes)
58
+ # Test with quantize_to(6)
59
+ [0, 0, 0, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12,
60
+ 18, 18, 18, 18, 18, 18, 24].each_with_index do |after, before|
61
+ e.time_from_start = before
62
+ e.quantize_to(6)
63
+ assert_equal(after, e.time_from_start)
114
64
  end
115
-
116
- def test_meta_event_string_in_ctor
117
- e = MIDI::MetaEvent.new(MIDI::META_TEXT, 'abc')
118
- assert_equal([97, 98, 99], e.data)
119
- assert_equal('abc', e.data_as_str)
120
- assert_equal([MIDI::META_EVENT, MIDI::META_TEXT, 3, 97, 98, 99], e.data_as_bytes)
121
- end
122
-
123
- def test_meta_event_data_assignment
124
- foobar_as_array = [102, 111, 111, 98, 97, 114]
125
-
126
- e = MIDI::MetaEvent.new(MIDI::META_TEXT, [97, 98, 99])
127
- e.data = 'foobar'
128
- assert_equal('foobar', e.data_as_str)
129
- assert_equal(foobar_as_array, e.data)
130
-
131
- e.data = nil
132
- e.data = foobar_as_array
133
- assert_equal('foobar', e.data_as_str)
134
- assert_equal(foobar_as_array, e.data)
135
- end
136
-
65
+ end
66
+
67
+ def test_quantize_2
68
+ e = MIDI::NoteOn.new(0, 64, 64, 0)
69
+ e.quantize_to(80)
70
+ assert_equal(0, e.time_from_start)
71
+
72
+ e.time_from_start = 1
73
+ e.quantize_to(80)
74
+ assert_equal(0, e.time_from_start)
75
+
76
+ e.time_from_start = 70
77
+ e.quantize_to(80)
78
+ assert_equal(80, e.time_from_start)
79
+
80
+ e.time_from_start = 100
81
+ e.quantize_to(80)
82
+ assert_equal(80, e.time_from_start)
83
+
84
+ e.time_from_start = 398
85
+ e.quantize_to(80)
86
+ assert_equal(400, e.time_from_start)
87
+
88
+ e.time_from_start = 405
89
+ e.quantize_to(80)
90
+ assert_equal(400, e.time_from_start)
91
+
92
+ e.time_from_start = 439
93
+ e.quantize_to(80)
94
+ assert_equal(400, e.time_from_start)
95
+
96
+ e.time_from_start = 440
97
+ e.quantize_to(80)
98
+ assert_equal(480, e.time_from_start)
99
+
100
+ e.time_from_start = 441
101
+ e.quantize_to(80)
102
+ assert_equal(480, e.time_from_start)
103
+ end
104
+
105
+ def test_meta_strings
106
+ e = MIDI::MetaEvent.new(MIDI::META_TEXT, [97, 98, 99])
107
+ assert_equal([97, 98, 99], e.data)
108
+ assert_equal('abc', e.data_as_str)
109
+
110
+ assert_equal([MIDI::META_EVENT, MIDI::META_TEXT, 3, 97, 98, 99], e.data_as_bytes)
111
+ end
112
+
113
+ def test_meta_event_string_in_ctor
114
+ e = MIDI::MetaEvent.new(MIDI::META_TEXT, 'abc')
115
+ assert_equal([97, 98, 99], e.data)
116
+ assert_equal('abc', e.data_as_str)
117
+ assert_equal([MIDI::META_EVENT, MIDI::META_TEXT, 3, 97, 98, 99], e.data_as_bytes)
118
+ end
119
+
120
+ def test_meta_event_data_assignment
121
+ foobar_as_array = [102, 111, 111, 98, 97, 114]
122
+
123
+ e = MIDI::MetaEvent.new(MIDI::META_TEXT, [97, 98, 99])
124
+ e.data = 'foobar'
125
+ assert_equal('foobar', e.data_as_str)
126
+ assert_equal(foobar_as_array, e.data)
127
+
128
+ e.data = nil
129
+ e.data = foobar_as_array
130
+ assert_equal('foobar', e.data_as_str)
131
+ assert_equal(foobar_as_array, e.data)
132
+ end
137
133
  end
data/test/test_io.rb CHANGED
@@ -7,57 +7,137 @@ $LOAD_PATH[0, 0] = File.dirname(__FILE__)
7
7
 
8
8
  require 'test/unit'
9
9
  require 'midilib'
10
+ require 'midilib/consts'
10
11
  require 'event_equality'
11
12
 
12
13
  class IOTester < Test::Unit::TestCase
14
+ SEQ_TEST_FILE = File.join(File.dirname(__FILE__), 'test.mid')
15
+ OUTPUT_FILE = 'testout.mid'
16
+ TEMPFILE = '/tmp/midilib_test.mid'
13
17
 
14
- SEQ_TEST_FILE = File.join(File.dirname(__FILE__), 'test.mid')
15
- OUTPUT_FILE = 'testout.mid'
16
-
17
- def compare_tracks(t0, t1)
18
- assert_equal(t0.name, t1.name, 'track names differ')
19
- assert_equal(t0.events.length, t1.events.length,
20
- 'number of track events differ')
21
- t0.each_with_index { | ev0, i |
22
- assert_equal(ev0, t1.events[i], 'events differ')
23
- }
24
- assert_equal(t0.instrument, t1.instrument)
25
- end
18
+ def compare_tracks(t0, t1)
19
+ assert_equal(t0.name, t1.name, 'track names differ')
20
+ assert_equal(t0.events.length, t1.events.length,
21
+ 'number of track events differ')
22
+ t0.each_with_index { |ev0, i| assert_equal(ev0, t1.events[i], 'events differ') }
23
+ assert_equal(t0.instrument, t1.instrument)
24
+ end
25
+
26
+ def compare_sequences(s0, s1)
27
+ assert_equal(s0.name, s1.name, 'sequence names differ')
28
+ assert_equal(s0.tracks.length, s1.tracks.length,
29
+ 'number of tracks differ')
30
+ s0.each_with_index { |track0, i| compare_tracks(track0, s1.tracks[i]) }
31
+ end
32
+
33
+ def compare_sequences_format_0(multitrack_seq, format0_seq)
34
+ assert_equal(multitrack_seq.name, format0_seq.name, 'sequence names differ')
35
+ assert_equal(1, format0_seq.tracks.length, 'number of tracks differ')
36
+ format_1_count = multitrack_seq.tracks.map { |t| t.events.count }.reduce(:+)
37
+ format_0_count = format0_seq.tracks.map { |t| t.events.count }.reduce(:+)
38
+ assert_equal(format_1_count, format_0_count, 'same number of total events')
39
+ end
40
+
41
+ def test_read_and_write
42
+ seq0 = MIDI::Sequence.new
43
+ File.open(SEQ_TEST_FILE, 'rb') { |f| seq0.read(f) }
44
+ File.open(OUTPUT_FILE, 'wb') { |f| seq0.write(f) }
45
+ seq1 = MIDI::Sequence.new
46
+ File.open(OUTPUT_FILE, 'rb') { |f| seq1.read(f) }
47
+ compare_sequences(seq0, seq1)
48
+ ensure
49
+ File.delete(OUTPUT_FILE) if File.exist?(OUTPUT_FILE)
50
+ end
51
+
52
+ def test_read_and_write_format_0
53
+ seq0 = MIDI::Sequence.new
54
+ File.open(SEQ_TEST_FILE, 'rb') { |f| seq0.read(f) }
55
+ File.open(OUTPUT_FILE, 'wb') { |f| seq0.write(f, 0) }
56
+ seq1 = MIDI::Sequence.new
57
+ File.open(OUTPUT_FILE, 'rb') { |f| seq1.read(f) }
58
+ compare_sequences_format_0(seq0, seq1)
59
+ ensure
60
+ File.delete(OUTPUT_FILE) if File.exist?(OUTPUT_FILE)
61
+ end
26
62
 
27
- def compare_sequences(s0, s1)
28
- assert_equal(s0.name, s1.name, 'sequence names differ')
29
- assert_equal(s0.tracks.length, s1.tracks.length,
30
- 'number of tracks differ')
31
- s0.each_with_index { | track0, i |
32
- compare_tracks(track0, s1.tracks[i])
33
- }
63
+ def test_read_callback
64
+ seq = MIDI::Sequence.new
65
+ names = []
66
+ num_tracks = -1
67
+ File.open(SEQ_TEST_FILE, 'rb') do |f|
68
+ seq.read(f) do |track, ntracks, i|
69
+ names << (track ? track.name : nil)
70
+ num_tracks = ntracks
71
+ end
34
72
  end
73
+ assert_equal(names, [nil, 'Sequence Name', 'My New Track'])
74
+ assert_equal(num_tracks, 2)
75
+ ensure
76
+ File.delete(OUTPUT_FILE) if File.exist?(OUTPUT_FILE)
77
+ end
35
78
 
36
- def test_read_and_write
37
- seq0 = MIDI::Sequence.new()
79
+ def test_write_callback
80
+ seq = MIDI::Sequence.new
81
+ File.open(SEQ_TEST_FILE, 'rb') { |f| seq.read(f) }
38
82
 
39
- puts if $DEBUG
40
- puts ' reading file' if $DEBUG
41
- File.open(SEQ_TEST_FILE, 'rb') { | f | seq0.read(f) }
83
+ names = []
84
+ num_tracks = -1
85
+ File.open(OUTPUT_FILE, 'wb') do |f|
86
+ seq.write(f) do |track, ntracks, i|
87
+ names << (track ? track.name : nil)
88
+ num_tracks = ntracks
89
+ end
90
+ end
91
+ assert_equal(names, [nil, 'Sequence Name', 'My New Track'])
92
+ assert_equal(num_tracks, 2)
93
+ ensure
94
+ File.delete(OUTPUT_FILE) if File.exist?(OUTPUT_FILE)
95
+ end
42
96
 
43
- puts ' writing file' if $DEBUG
44
- File.open(OUTPUT_FILE, 'wb') { | f | seq0.write(f) }
97
+ def test_read_strings
98
+ seq = MIDI::Sequence.new
99
+ File.open(SEQ_TEST_FILE, 'rb') { |f| seq.read(f) }
100
+ assert_equal('Sequence Name', seq.tracks[0].name)
101
+ assert_equal(MIDI::GM_PATCH_NAMES[0], seq.tracks[1].instrument)
102
+ end
45
103
 
46
- puts ' reading file' if $DEBUG
47
- seq1 = MIDI::Sequence.new()
48
- File.open(OUTPUT_FILE, 'rb') { | f | seq1.read(f) }
104
+ def test_preserve_deltas_in_some_situations
105
+ out_seq = MIDI::Sequence.new
106
+ out_track = MIDI::Track.new(out_seq)
107
+ out_seq.tracks << out_track
108
+ out_track.events << MIDI::Tempo.new(MIDI::Tempo.bpm_to_mpq(120))
49
109
 
50
- puts ' comparing sequences' if $DEBUG
51
- compare_sequences(seq0, seq1)
52
- ensure
53
- File.delete(OUTPUT_FILE) if File.exist?(OUTPUT_FILE)
110
+ # 1) The meta events with non-zero delta time
111
+ # Normally copyright and sequence name events are at time 0, but non-zero
112
+ # start times are allowed.
113
+ begin
114
+ out_track.events << MIDI::MetaEvent.new(MIDI::META_COPYRIGHT, '(C) 1950 Donald Duck', 100)
115
+ out_track.events << MIDI::MetaEvent.new(MIDI::META_SEQ_NAME, 'Quack, Track 1', 200)
116
+ out_track.events << MIDI::NoteOn.new(0, 64, 127, 0)
117
+ out_track.events << MIDI::NoteOff.new(0, 64, 127, 100)
54
118
  end
55
119
 
56
- def test_read_strings
57
- seq = MIDI::Sequence.new
58
- File.open(SEQ_TEST_FILE, 'rb') { |f| seq.read(f) }
59
- assert_equal('Sequence Name', seq.tracks[0].name)
60
- assert_equal(MIDI::GM_PATCH_NAMES[0], seq.tracks[1].instrument)
120
+ # 2) The unusual note off event with non-zero delta time
121
+ begin
122
+ out_track.events << MIDI::NoteOff.new(0, 65, 127, 120)
123
+ out_track.events << MIDI::NoteOn.new(0, 65, 127, 0)
124
+ # Add note off (which will be complemented at #end_track if missing) for later comparison.
125
+ out_track.events << MIDI::NoteOff.new(0, 65, 127, 230)
61
126
  end
62
127
 
128
+ File.open('/tmp/midilib_test.mid', 'wb') { |file| out_seq.write(file) }
129
+
130
+ # Although start times are not written out to the MIDI file, we
131
+ # calculate them because we are about to compare the out events with the
132
+ # newly-read events which will have their start times set.
133
+ out_track.recalc_times
134
+
135
+ in_seq = MIDI::Sequence.new
136
+ File.open(TEMPFILE, 'rb') { |file| in_seq.read(file) }
137
+ in_track = in_seq.tracks[0]
138
+ assert_equal(out_track.events.length, in_track.events.length)
139
+ out_track.events.each_with_index do |event, i|
140
+ assert_equal(event, in_track.events[i])
141
+ end
142
+ end
63
143
  end
@@ -0,0 +1,37 @@
1
+ # Start looking for MIDI classes in the directory above this one.
2
+ # This forces us to use the local copy of MIDI, even if there is
3
+ # a previously installed version out there somewhere.
4
+ $LOAD_PATH[0, 0] = File.join(File.dirname(__FILE__), '..', 'lib')
5
+
6
+ require 'test/unit'
7
+ require 'midilib/mergesort'
8
+
9
+ class MergesortTester < Test::Unit::TestCase
10
+ def test_mergesort
11
+ track = MIDI::Track.new(nil)
12
+ track.events = []
13
+
14
+ # Two events with later start times but earlier in the event list
15
+ e2 = MIDI::NoteOff.new(0, 64, 64, 100)
16
+ e2.time_from_start = 100
17
+ track.events << e2
18
+
19
+ e3 = MIDI::NoteOn.new(0, 64, 64, 100)
20
+ e3.time_from_start = 100
21
+ track.events << e3
22
+
23
+ # Earliest start time, latest in the list of events
24
+ e1 = MIDI::NoteOn.new(0, 64, 64, 100)
25
+ e1.time_from_start = 0
26
+ track.events << e1
27
+
28
+ # Recalc sorts. Make sure note off/note on pair at t 100 are in the
29
+ # correct order.
30
+ track.recalc_delta_from_times
31
+
32
+ # These tests would fail before we moved to mergesort.
33
+ assert_equal(e1, track.events[0])
34
+ assert_equal(e2, track.events[1])
35
+ assert_equal(e3, track.events[2])
36
+ end
37
+ end
@@ -8,30 +8,18 @@ require 'stringio'
8
8
  require 'midilib'
9
9
 
10
10
  class MIDI::IO::MIDIFile
11
- def io=(io)
12
- @io = io
13
- end
14
- end
15
- if RUBY_VERSION < '1.9'
16
- class StringIO
17
- def readbyte
18
- c = getc()
19
- raise 'unexpected EOF' unless c
20
- c
21
- end
22
- end
11
+ attr_writer :io
23
12
  end
24
13
 
25
14
  class MIDIFileTester < Test::Unit::TestCase
26
-
27
15
  def setup
28
16
  @m = MIDI::IO::MIDIFile.new
29
17
  end
30
18
 
31
19
  def test_msg_io
32
20
  io = StringIO.new
33
- io.write("abcdef")
34
- io.rewind()
21
+ io.write('abcdef')
22
+ io.rewind
35
23
  @m.io = io
36
24
  @m.msg_init
37
25
  @m.msg_read(6)
@@ -41,9 +29,9 @@ class MIDIFileTester < Test::Unit::TestCase
41
29
  def test_read32
42
30
  io = StringIO.new
43
31
  io.write("\0\0\0\6")
44
- io.rewind()
32
+ io.rewind
45
33
  @m.io = io
46
- assert_equal 6, @m.read32()
34
+ assert_equal 6, @m.read32
47
35
  end
48
36
 
49
37
  def test_write32
@@ -52,8 +40,7 @@ class MIDIFileTester < Test::Unit::TestCase
52
40
  $stdout = io
53
41
  @m.write32(6)
54
42
  $stdout = old_stdout
55
- io.rewind()
43
+ io.rewind
56
44
  assert_equal "\0\0\0\6", io.string
57
45
  end
58
-
59
46
  end