midilib 0.8.4

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 (252) hide show
  1. data/ChangeLog +87 -0
  2. data/Credits +8 -0
  3. data/README +361 -0
  4. data/Rakefile +68 -0
  5. data/TODO +25 -0
  6. data/examples/NoFences.mid +0 -0
  7. data/examples/from_scratch.mid +0 -0
  8. data/examples/from_scratch.rb +56 -0
  9. data/examples/reader2text.rb +220 -0
  10. data/examples/seq2text.rb +41 -0
  11. data/examples/strings.rb +34 -0
  12. data/examples/transpose.rb +75 -0
  13. data/html/classes/MIDI.html +738 -0
  14. data/html/classes/MIDI/ActiveSense.html +156 -0
  15. data/html/classes/MIDI/ActiveSense.src/M000136.html +18 -0
  16. data/html/classes/MIDI/ActiveSense.src/M000137.html +18 -0
  17. data/html/classes/MIDI/ChannelEvent.html +179 -0
  18. data/html/classes/MIDI/ChannelEvent.src/M000124.html +20 -0
  19. data/html/classes/MIDI/ChannelEvent.src/M000125.html +18 -0
  20. data/html/classes/MIDI/ChannelPressure.html +184 -0
  21. data/html/classes/MIDI/ChannelPressure.src/M000088.html +19 -0
  22. data/html/classes/MIDI/ChannelPressure.src/M000089.html +21 -0
  23. data/html/classes/MIDI/ChannelPressure.src/M000090.html +18 -0
  24. data/html/classes/MIDI/Clock.html +156 -0
  25. data/html/classes/MIDI/Clock.src/M000134.html +18 -0
  26. data/html/classes/MIDI/Clock.src/M000135.html +18 -0
  27. data/html/classes/MIDI/Continue.html +156 -0
  28. data/html/classes/MIDI/Continue.src/M000132.html +18 -0
  29. data/html/classes/MIDI/Continue.src/M000133.html +18 -0
  30. data/html/classes/MIDI/Controller.html +189 -0
  31. data/html/classes/MIDI/Controller.src/M000129.html +21 -0
  32. data/html/classes/MIDI/Controller.src/M000130.html +22 -0
  33. data/html/classes/MIDI/Controller.src/M000131.html +18 -0
  34. data/html/classes/MIDI/Event.html +424 -0
  35. data/html/classes/MIDI/Event.src/M000145.html +27 -0
  36. data/html/classes/MIDI/Event.src/M000146.html +18 -0
  37. data/html/classes/MIDI/Event.src/M000147.html +18 -0
  38. data/html/classes/MIDI/Event.src/M000148.html +18 -0
  39. data/html/classes/MIDI/Event.src/M000149.html +18 -0
  40. data/html/classes/MIDI/Event.src/M000150.html +18 -0
  41. data/html/classes/MIDI/Event.src/M000151.html +18 -0
  42. data/html/classes/MIDI/Event.src/M000152.html +18 -0
  43. data/html/classes/MIDI/Event.src/M000153.html +18 -0
  44. data/html/classes/MIDI/Event.src/M000154.html +22 -0
  45. data/html/classes/MIDI/Event.src/M000155.html +18 -0
  46. data/html/classes/MIDI/Event.src/M000156.html +18 -0
  47. data/html/classes/MIDI/Event.src/M000157.html +18 -0
  48. data/html/classes/MIDI/IO.html +121 -0
  49. data/html/classes/MIDI/IO/MIDIFile.html +925 -0
  50. data/html/classes/MIDI/IO/MIDIFile.src/M000028.html +22 -0
  51. data/html/classes/MIDI/IO/MIDIFile.src/M000029.html +24 -0
  52. data/html/classes/MIDI/IO/MIDIFile.src/M000030.html +19 -0
  53. data/html/classes/MIDI/IO/MIDIFile.src/M000031.html +19 -0
  54. data/html/classes/MIDI/IO/MIDIFile.src/M000032.html +17 -0
  55. data/html/classes/MIDI/IO/MIDIFile.src/M000033.html +17 -0
  56. data/html/classes/MIDI/IO/MIDIFile.src/M000034.html +17 -0
  57. data/html/classes/MIDI/IO/MIDIFile.src/M000035.html +17 -0
  58. data/html/classes/MIDI/IO/MIDIFile.src/M000036.html +17 -0
  59. data/html/classes/MIDI/IO/MIDIFile.src/M000037.html +17 -0
  60. data/html/classes/MIDI/IO/MIDIFile.src/M000038.html +17 -0
  61. data/html/classes/MIDI/IO/MIDIFile.src/M000039.html +17 -0
  62. data/html/classes/MIDI/IO/MIDIFile.src/M000040.html +17 -0
  63. data/html/classes/MIDI/IO/MIDIFile.src/M000041.html +17 -0
  64. data/html/classes/MIDI/IO/MIDIFile.src/M000042.html +17 -0
  65. data/html/classes/MIDI/IO/MIDIFile.src/M000043.html +17 -0
  66. data/html/classes/MIDI/IO/MIDIFile.src/M000044.html +17 -0
  67. data/html/classes/MIDI/IO/MIDIFile.src/M000045.html +17 -0
  68. data/html/classes/MIDI/IO/MIDIFile.src/M000046.html +17 -0
  69. data/html/classes/MIDI/IO/MIDIFile.src/M000047.html +17 -0
  70. data/html/classes/MIDI/IO/MIDIFile.src/M000048.html +17 -0
  71. data/html/classes/MIDI/IO/MIDIFile.src/M000049.html +17 -0
  72. data/html/classes/MIDI/IO/MIDIFile.src/M000050.html +17 -0
  73. data/html/classes/MIDI/IO/MIDIFile.src/M000051.html +17 -0
  74. data/html/classes/MIDI/IO/MIDIFile.src/M000052.html +17 -0
  75. data/html/classes/MIDI/IO/MIDIFile.src/M000053.html +43 -0
  76. data/html/classes/MIDI/IO/MIDIFile.src/M000054.html +34 -0
  77. data/html/classes/MIDI/IO/MIDIFile.src/M000055.html +96 -0
  78. data/html/classes/MIDI/IO/MIDIFile.src/M000056.html +18 -0
  79. data/html/classes/MIDI/IO/MIDIFile.src/M000057.html +48 -0
  80. data/html/classes/MIDI/IO/MIDIFile.src/M000058.html +42 -0
  81. data/html/classes/MIDI/IO/MIDIFile.src/M000059.html +19 -0
  82. data/html/classes/MIDI/IO/MIDIFile.src/M000060.html +19 -0
  83. data/html/classes/MIDI/IO/MIDIFile.src/M000061.html +20 -0
  84. data/html/classes/MIDI/IO/MIDIFile.src/M000062.html +21 -0
  85. data/html/classes/MIDI/IO/MIDIFile.src/M000063.html +31 -0
  86. data/html/classes/MIDI/IO/MIDIFile.src/M000064.html +20 -0
  87. data/html/classes/MIDI/IO/MIDIFile.src/M000065.html +22 -0
  88. data/html/classes/MIDI/IO/MIDIFile.src/M000066.html +30 -0
  89. data/html/classes/MIDI/IO/MIDIFile.src/M000067.html +18 -0
  90. data/html/classes/MIDI/IO/MIDIFile.src/M000068.html +20 -0
  91. data/html/classes/MIDI/IO/MIDIFile.src/M000069.html +18 -0
  92. data/html/classes/MIDI/IO/MIDIFile.src/M000070.html +18 -0
  93. data/html/classes/MIDI/IO/SeqReader.html +460 -0
  94. data/html/classes/MIDI/IO/SeqReader.src/M000001.html +22 -0
  95. data/html/classes/MIDI/IO/SeqReader.src/M000002.html +22 -0
  96. data/html/classes/MIDI/IO/SeqReader.src/M000003.html +21 -0
  97. data/html/classes/MIDI/IO/SeqReader.src/M000004.html +34 -0
  98. data/html/classes/MIDI/IO/SeqReader.src/M000005.html +26 -0
  99. data/html/classes/MIDI/IO/SeqReader.src/M000006.html +28 -0
  100. data/html/classes/MIDI/IO/SeqReader.src/M000007.html +21 -0
  101. data/html/classes/MIDI/IO/SeqReader.src/M000008.html +19 -0
  102. data/html/classes/MIDI/IO/SeqReader.src/M000009.html +19 -0
  103. data/html/classes/MIDI/IO/SeqReader.src/M000010.html +19 -0
  104. data/html/classes/MIDI/IO/SeqReader.src/M000011.html +19 -0
  105. data/html/classes/MIDI/IO/SeqReader.src/M000012.html +19 -0
  106. data/html/classes/MIDI/IO/SeqReader.src/M000013.html +18 -0
  107. data/html/classes/MIDI/IO/SeqReader.src/M000014.html +18 -0
  108. data/html/classes/MIDI/IO/SeqReader.src/M000015.html +27 -0
  109. data/html/classes/MIDI/IO/SeqReader.src/M000016.html +18 -0
  110. data/html/classes/MIDI/IO/SeqReader.src/M000017.html +18 -0
  111. data/html/classes/MIDI/IO/SeqReader.src/M000018.html +18 -0
  112. data/html/classes/MIDI/IO/SeqWriter.html +267 -0
  113. data/html/classes/MIDI/IO/SeqWriter.src/M000019.html +19 -0
  114. data/html/classes/MIDI/IO/SeqWriter.src/M000020.html +25 -0
  115. data/html/classes/MIDI/IO/SeqWriter.src/M000021.html +22 -0
  116. data/html/classes/MIDI/IO/SeqWriter.src/M000022.html +54 -0
  117. data/html/classes/MIDI/IO/SeqWriter.src/M000023.html +49 -0
  118. data/html/classes/MIDI/IO/SeqWriter.src/M000024.html +21 -0
  119. data/html/classes/MIDI/IO/SeqWriter.src/M000025.html +19 -0
  120. data/html/classes/MIDI/IO/SeqWriter.src/M000026.html +24 -0
  121. data/html/classes/MIDI/IO/SeqWriter.src/M000027.html +26 -0
  122. data/html/classes/MIDI/Marker.html +139 -0
  123. data/html/classes/MIDI/Marker.src/M000107.html +18 -0
  124. data/html/classes/MIDI/MetaEvent.html +189 -0
  125. data/html/classes/MIDI/MetaEvent.src/M000167.html +21 -0
  126. data/html/classes/MIDI/MetaEvent.src/M000168.html +23 -0
  127. data/html/classes/MIDI/MetaEvent.src/M000169.html +53 -0
  128. data/html/classes/MIDI/NoteEvent.html +233 -0
  129. data/html/classes/MIDI/NoteEvent.src/M000091.html +21 -0
  130. data/html/classes/MIDI/NoteEvent.src/M000092.html +20 -0
  131. data/html/classes/MIDI/NoteEvent.src/M000093.html +18 -0
  132. data/html/classes/MIDI/NoteEvent.src/M000094.html +22 -0
  133. data/html/classes/MIDI/NoteOffEvent.html +169 -0
  134. data/html/classes/MIDI/NoteOffEvent.src/M000086.html +19 -0
  135. data/html/classes/MIDI/NoteOffEvent.src/M000087.html +19 -0
  136. data/html/classes/MIDI/NoteOnEvent.html +169 -0
  137. data/html/classes/MIDI/NoteOnEvent.src/M000102.html +19 -0
  138. data/html/classes/MIDI/NoteOnEvent.src/M000103.html +19 -0
  139. data/html/classes/MIDI/PitchBend.html +184 -0
  140. data/html/classes/MIDI/PitchBend.src/M000104.html +19 -0
  141. data/html/classes/MIDI/PitchBend.src/M000105.html +22 -0
  142. data/html/classes/MIDI/PitchBend.src/M000106.html +18 -0
  143. data/html/classes/MIDI/PolyPressure.html +186 -0
  144. data/html/classes/MIDI/PolyPressure.src/M000170.html +18 -0
  145. data/html/classes/MIDI/PolyPressure.src/M000171.html +18 -0
  146. data/html/classes/MIDI/PolyPressure.src/M000172.html +18 -0
  147. data/html/classes/MIDI/PolyPressure.src/M000173.html +19 -0
  148. data/html/classes/MIDI/ProgramChange.html +184 -0
  149. data/html/classes/MIDI/ProgramChange.src/M000099.html +19 -0
  150. data/html/classes/MIDI/ProgramChange.src/M000100.html +21 -0
  151. data/html/classes/MIDI/ProgramChange.src/M000101.html +18 -0
  152. data/html/classes/MIDI/Realtime.html +171 -0
  153. data/html/classes/MIDI/Realtime.src/M000083.html +19 -0
  154. data/html/classes/MIDI/Realtime.src/M000084.html +20 -0
  155. data/html/classes/MIDI/Realtime.src/M000085.html +18 -0
  156. data/html/classes/MIDI/Sequence.html +469 -0
  157. data/html/classes/MIDI/Sequence.src/M000108.html +28 -0
  158. data/html/classes/MIDI/Sequence.src/M000109.html +21 -0
  159. data/html/classes/MIDI/Sequence.src/M000110.html +22 -0
  160. data/html/classes/MIDI/Sequence.src/M000113.html +18 -0
  161. data/html/classes/MIDI/Sequence.src/M000114.html +27 -0
  162. data/html/classes/MIDI/Sequence.src/M000115.html +18 -0
  163. data/html/classes/MIDI/Sequence.src/M000116.html +19 -0
  164. data/html/classes/MIDI/Sequence.src/M000117.html +19 -0
  165. data/html/classes/MIDI/Sequence.src/M000118.html +20 -0
  166. data/html/classes/MIDI/Sequence.src/M000119.html +19 -0
  167. data/html/classes/MIDI/Sequence.src/M000120.html +18 -0
  168. data/html/classes/MIDI/SongPointer.html +184 -0
  169. data/html/classes/MIDI/SongPointer.src/M000138.html +19 -0
  170. data/html/classes/MIDI/SongPointer.src/M000139.html +22 -0
  171. data/html/classes/MIDI/SongPointer.src/M000140.html +18 -0
  172. data/html/classes/MIDI/SongSelect.html +184 -0
  173. data/html/classes/MIDI/SongSelect.src/M000126.html +19 -0
  174. data/html/classes/MIDI/SongSelect.src/M000127.html +21 -0
  175. data/html/classes/MIDI/SongSelect.src/M000128.html +18 -0
  176. data/html/classes/MIDI/Start.html +156 -0
  177. data/html/classes/MIDI/Start.src/M000097.html +18 -0
  178. data/html/classes/MIDI/Start.src/M000098.html +18 -0
  179. data/html/classes/MIDI/Stop.html +156 -0
  180. data/html/classes/MIDI/Stop.src/M000095.html +18 -0
  181. data/html/classes/MIDI/Stop.src/M000096.html +18 -0
  182. data/html/classes/MIDI/SystemCommon.html +139 -0
  183. data/html/classes/MIDI/SystemCommon.src/M000144.html +19 -0
  184. data/html/classes/MIDI/SystemExclusive.html +184 -0
  185. data/html/classes/MIDI/SystemExclusive.src/M000141.html +19 -0
  186. data/html/classes/MIDI/SystemExclusive.src/M000142.html +23 -0
  187. data/html/classes/MIDI/SystemExclusive.src/M000143.html +18 -0
  188. data/html/classes/MIDI/SystemReset.html +156 -0
  189. data/html/classes/MIDI/SystemReset.src/M000081.html +18 -0
  190. data/html/classes/MIDI/SystemReset.src/M000082.html +18 -0
  191. data/html/classes/MIDI/Tempo.html +250 -0
  192. data/html/classes/MIDI/Tempo.src/M000158.html +18 -0
  193. data/html/classes/MIDI/Tempo.src/M000159.html +18 -0
  194. data/html/classes/MIDI/Tempo.src/M000160.html +18 -0
  195. data/html/classes/MIDI/Tempo.src/M000161.html +18 -0
  196. data/html/classes/MIDI/Tempo.src/M000162.html +18 -0
  197. data/html/classes/MIDI/Tempo.src/M000163.html +25 -0
  198. data/html/classes/MIDI/Tempo.src/M000164.html +18 -0
  199. data/html/classes/MIDI/Track.html +380 -0
  200. data/html/classes/MIDI/Track.src/M000071.html +23 -0
  201. data/html/classes/MIDI/Track.src/M000072.html +21 -0
  202. data/html/classes/MIDI/Track.src/M000073.html +26 -0
  203. data/html/classes/MIDI/Track.src/M000074.html +18 -0
  204. data/html/classes/MIDI/Track.src/M000075.html +22 -0
  205. data/html/classes/MIDI/Track.src/M000076.html +20 -0
  206. data/html/classes/MIDI/Track.src/M000077.html +22 -0
  207. data/html/classes/MIDI/Track.src/M000078.html +22 -0
  208. data/html/classes/MIDI/Track.src/M000079.html +18 -0
  209. data/html/classes/MIDI/Track.src/M000080.html +19 -0
  210. data/html/classes/MIDI/TuneRequest.html +171 -0
  211. data/html/classes/MIDI/TuneRequest.src/M000121.html +18 -0
  212. data/html/classes/MIDI/TuneRequest.src/M000122.html +20 -0
  213. data/html/classes/MIDI/TuneRequest.src/M000123.html +18 -0
  214. data/html/classes/MIDI/Utils.html +190 -0
  215. data/html/classes/MIDI/Utils.src/M000165.html +20 -0
  216. data/html/classes/MIDI/Utils.src/M000166.html +25 -0
  217. data/html/created.rid +1 -0
  218. data/html/files/README.html +599 -0
  219. data/html/files/TODO.html +142 -0
  220. data/html/files/lib/midilib/consts_rb.html +107 -0
  221. data/html/files/lib/midilib/event_rb.html +109 -0
  222. data/html/files/lib/midilib/info_rb.html +101 -0
  223. data/html/files/lib/midilib/io/midifile_rb.html +108 -0
  224. data/html/files/lib/midilib/io/seqreader_rb.html +110 -0
  225. data/html/files/lib/midilib/io/seqwriter_rb.html +115 -0
  226. data/html/files/lib/midilib/sequence_rb.html +109 -0
  227. data/html/files/lib/midilib/track_rb.html +108 -0
  228. data/html/files/lib/midilib/utils_rb.html +101 -0
  229. data/html/files/lib/midilib_rb.html +124 -0
  230. data/html/fr_class_index.html +59 -0
  231. data/html/fr_file_index.html +38 -0
  232. data/html/fr_method_index.html +199 -0
  233. data/html/index.html +24 -0
  234. data/html/rdoc-style.css +208 -0
  235. data/install.rb +57 -0
  236. data/lib/midilib.rb +16 -0
  237. data/lib/midilib/consts.rb +422 -0
  238. data/lib/midilib/event.rb +559 -0
  239. data/lib/midilib/info.rb +9 -0
  240. data/lib/midilib/io/midifile.rb +446 -0
  241. data/lib/midilib/io/seqreader.rb +198 -0
  242. data/lib/midilib/io/seqwriter.rb +151 -0
  243. data/lib/midilib/sequence.rb +144 -0
  244. data/lib/midilib/track.rb +115 -0
  245. data/lib/midilib/utils.rb +36 -0
  246. data/test/event_equality.rb +81 -0
  247. data/test/test_event.rb +116 -0
  248. data/test/test_io.rb +55 -0
  249. data/test/test_sequence.rb +68 -0
  250. data/test/test_track.rb +111 -0
  251. data/test/test_varlen.rb +40 -0
  252. metadata +330 -0
@@ -0,0 +1,9 @@
1
+ module MIDI
2
+
3
+ VERSION_MAJOR = 0
4
+ VERSION_MINOR = 8
5
+ VERSION_TWEAK = 4
6
+ Version = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_TWEAK}"
7
+ Copyright = 'Copyright (c) 2003-2005 by Jim Menard <jimm@io.com>'
8
+
9
+ end
@@ -0,0 +1,446 @@
1
+ require 'midilib/consts'
2
+
3
+ module MIDI
4
+
5
+ module IO
6
+
7
+ # A MIDIFile parses a MIDI file and calls methods when it sees MIDI events.
8
+ # Most of the methods are stubs. To do anything interesting with the events,
9
+ # override these methods (those between the "The rest of these are NOPs by
10
+ # default" and "End of NOPs" comments).
11
+ #
12
+ # See SeqReader for a subclass that uses these methods to create Event
13
+ # objects.
14
+ class MIDIFile
15
+
16
+ # This array is indexed by the high half of a status byte. Its
17
+ # value is either the number of bytes needed (1 or 2) for a channel
18
+ # message, or 0 if it's not a channel message.
19
+ NUM_DATA_BYTES = [
20
+ 0, 0, 0, 0, 0, 0, 0, 0, # 0x00 - 0x70
21
+ 2, 2, 2, 2, 1, 1, 2, 0 # 0x80 - 0xf0
22
+ ]
23
+
24
+ attr_accessor :curr_ticks # Current time, from delta-time in MIDI file
25
+ attr_accessor :ticks_so_far # Number of delta-time ticks so far
26
+ attr_accessor :bytes_to_be_read # Counts number of bytes expected
27
+
28
+ attr_accessor :no_merge # true means continued sysex are not collapsed
29
+ attr_accessor :skip_init # true if initial garbage should be skipped
30
+
31
+ # Raw data info
32
+ attr_accessor :raw_time_stamp_data
33
+ attr_accessor :raw_var_num_data
34
+ attr_accessor :raw_data
35
+
36
+ def initialize
37
+ @no_merge = false
38
+ @skip_init = true
39
+ @io = nil
40
+ @bytes_to_be_read = 0
41
+ @msg_buf = nil
42
+ end
43
+
44
+ # The only public method. Each MIDI event in the file causes a
45
+ # method to be called.
46
+ def read_from(io)
47
+ error('must specify non-nil input stream') if io.nil?
48
+ @io = io
49
+
50
+ ntrks = read_header()
51
+ error('No tracks!') if ntrks <= 0
52
+
53
+ ntrks.times { read_track() }
54
+ end
55
+
56
+ # This default getc implementation tries to read a single character
57
+ # from io.
58
+ def getc
59
+ @bytes_to_be_read -= 1
60
+ return @io.getc()
61
+ end
62
+
63
+ # The default error handler.
64
+ def error(str)
65
+ loc = @io.tell() - 1
66
+ raise "#{self.class.name} error at byte #{loc} (0x#{'%02x' % loc}): #{str}"
67
+ end
68
+
69
+ # The rest of these are NOPs by default.
70
+
71
+ # MIDI header.
72
+ def header(format, ntrks, division)
73
+ end
74
+
75
+ def start_track(bytes_to_be_read)
76
+ end
77
+
78
+ def end_track()
79
+ end
80
+
81
+ def note_on(chan, note, vel)
82
+ end
83
+
84
+ def note_off(chan, note, vel)
85
+ end
86
+
87
+ def pressure(chan, note, press)
88
+ end
89
+
90
+ def controller(chan, control, value)
91
+ end
92
+
93
+ def pitch_bend(chan, msb, lsb)
94
+ end
95
+
96
+ def program(chan, program)
97
+ end
98
+
99
+ def chan_pressure(chan, press)
100
+ end
101
+
102
+ def sysex(msg)
103
+ end
104
+
105
+ def meta_misc(type, msg)
106
+ end
107
+
108
+ def sequencer_specific(type, msg)
109
+ end
110
+
111
+ def sequence_number(num)
112
+ end
113
+
114
+ def text(type, msg)
115
+ end
116
+
117
+ def eot()
118
+ end
119
+
120
+ def time_signature(numer, denom, clocks, qnotes)
121
+ end
122
+
123
+ def smpte(hour, min, sec, frame, fract)
124
+ end
125
+
126
+ def tempo(microsecs)
127
+ end
128
+
129
+ def key_signature(sharpflat, is_minor)
130
+ end
131
+
132
+ def arbitrary(msg)
133
+ end
134
+
135
+ # End of NOPs.
136
+
137
+
138
+ # Read through 'MThd' or 'MTrk' header string. If skip is true, attempt
139
+ # to skip initial trash. If there is an error, #error is called.
140
+ def read_mt_header_string(s, skip)
141
+ b = ''
142
+ bytes_to_read = 4
143
+ while true
144
+ b << @io.read(bytes_to_read)
145
+ if b.length < 4
146
+ error("unexpected EOF while trying to read header" +
147
+ " string #{s}")
148
+ end
149
+ @bytes_to_be_read -= bytes_to_read
150
+
151
+ # See if we found the string we're looking for
152
+ return if b == s
153
+
154
+ if skip # Try again with the next char
155
+ i = b.index(s[0], 1)
156
+ if i.nil?
157
+ b = ''
158
+ bytes_to_read = 4
159
+ else
160
+ b = b[i..-1]
161
+ bytes_to_read = 4 - i
162
+ end
163
+ else
164
+ error("header string #{s} not found")
165
+ end
166
+ end
167
+ end
168
+
169
+ # Read a header chunk.
170
+ def read_header
171
+ @bytes_to_be_read = 0
172
+ read_mt_header_string('MThd', @skip_init)
173
+
174
+ @bytes_to_be_read = read32()
175
+ format = read16()
176
+ ntrks = read16()
177
+ division = read16()
178
+
179
+ header(format, ntrks, division)
180
+
181
+ # Flush any extra stuff, in case the length of the header is not 6
182
+ if @bytes_to_be_read > 0
183
+ @io.read(@bytes_to_be_read)
184
+ @bytes_to_be_read = 0
185
+ end
186
+
187
+ return ntrks
188
+ end
189
+
190
+ # Read a track chunk.
191
+ def read_track
192
+ c = c1 = type = needed = 0
193
+ sysex_continue = false # True if last msg was unfinished
194
+ running = false # True when running status used
195
+ status = 0 # (Possibly running) status byte
196
+
197
+ @bytes_to_be_read = 0
198
+ read_mt_header_string('MTrk', false)
199
+
200
+ @bytes_to_be_read = read32()
201
+ @curr_ticks = @ticks_so_far = 0
202
+
203
+ start_track()
204
+
205
+ while @bytes_to_be_read > 0
206
+ @curr_ticks = read_var_len() # Delta time
207
+ @ticks_so_far += @curr_ticks
208
+
209
+ # Copy raw var num data into raw time stamp data
210
+ @raw_time_stamp_data = @raw_var_num_data.dup()
211
+
212
+ c = getc() # Read first byte
213
+
214
+ if sysex_continue && c != EOX
215
+ error("didn't find expected continuation of a sysex")
216
+ end
217
+
218
+ if (c & 0x80).zero? # Running status?
219
+ error('unexpected running status') if status.zero?
220
+ running = true
221
+ else
222
+ status = c
223
+ running = false
224
+ end
225
+
226
+ needed = NUM_DATA_BYTES[(status >> 4) & 0x0f]
227
+
228
+ if needed.nonzero? # i.e., is it a channel message?
229
+ c1 = running ? c : (getc() & 0x7f)
230
+
231
+ # The "& 0x7f" here may seem unnecessary, but I've seen
232
+ # "bad" MIDI files that had, for example, volume bytes
233
+ # with the upper bit set. This code should not harm
234
+ # proper data.
235
+ chan_message(running, status, c1,
236
+ (needed > 1) ? (getc() & 0x7f) : 0)
237
+ next
238
+ end
239
+
240
+ case c
241
+ when META_EVENT # Meta event
242
+ type = getc()
243
+ msg_init()
244
+ msg_read(read_var_len())
245
+ meta_event(type)
246
+ when SYSEX # Start of system exclusive
247
+ msg_init()
248
+ msg_add(SYSEX)
249
+ c = msg_read(read_var_len())
250
+
251
+ if c == EOX || !@no_merge
252
+ handle_sysex(msg())
253
+ else
254
+ sysex_continue = true
255
+ end
256
+ when EOX # Sysex continuation or arbitrary stuff
257
+ msg_init() if !sysex_continue
258
+ c = msg_read(read_var_len())
259
+
260
+ if !sysex_continue
261
+ handle_arbitrary(msg())
262
+ elsif c == EOX
263
+ handle_sysex(msg())
264
+ sysex_continue = false
265
+ end
266
+ else
267
+ bad_byte(c)
268
+ end
269
+ end
270
+ end_track()
271
+ end
272
+
273
+ # Handle an unexpected byte.
274
+ def bad_byte(c)
275
+ error(sprintf("unexpected byte: 0x%02x", c))
276
+ end
277
+
278
+ # Handle a meta event.
279
+ def meta_event(type)
280
+ m = msg() # Copy of internal message buffer
281
+
282
+ # Create raw data array
283
+ @raw_data = ''
284
+ @raw_data << META_EVENT
285
+ @raw_data << type
286
+ @raw_data << @raw_var_num_data
287
+ @raw_data << m
288
+
289
+ case type
290
+ when META_SEQ_NUM
291
+ sequence_number((m[0] << 8) + m[1])
292
+ when META_TEXT, META_COPYRIGHT, META_SEQ_NAME, META_INSTRUMENT,
293
+ META_LYRIC, META_MARKER, META_CUE, 0x08, 0x09, 0x0a,
294
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
295
+ text(type, m)
296
+ when META_TRACK_END
297
+ eot()
298
+ when META_SET_TEMPO
299
+ tempo((m[0] << 16) + (m[1] << 8) + m[2])
300
+ when META_SMPTE
301
+ smpte(m[0], m[1], m[2], m[3], m[4])
302
+ when META_TIME_SIG
303
+ time_signature(m[0], m[1], m[2], m[3])
304
+ when META_KEY_SIG
305
+ key_signature(m[0], m[1] == 0 ? false : true)
306
+ when META_SEQ_SPECIF
307
+ sequencer_specific(type, m)
308
+ else
309
+ meta_misc(type, m)
310
+ end
311
+ end
312
+
313
+ # Handle a channel message (note on, note off, etc.)
314
+ def chan_message(running, status, c1, c2)
315
+ @raw_data = []
316
+ @raw_data << status unless running
317
+ @raw_data << c1
318
+ @raw_data << c2
319
+
320
+ chan = status & 0x0f
321
+
322
+ case (status & 0xf0)
323
+ when NOTE_OFF
324
+ note_off(chan, c1, c2)
325
+ when NOTE_ON
326
+ note_on(chan, c1, c2)
327
+ when POLY_PRESSURE
328
+ pressure(chan, c1, c2)
329
+ when CONTROLLER
330
+ controller(chan, c1, c2)
331
+ when PITCH_BEND
332
+ pitch_bend(chan, c1, c2)
333
+ when PROGRAM_CHANGE
334
+ program(chan, c1)
335
+ when CHANNEL_PRESSURE
336
+ chan_pressure(chan, c1)
337
+ else
338
+ error("illegal chan message 0x#{'%02x' % (status & 0xf0)}\n")
339
+ end
340
+ end
341
+
342
+ # Copy message into raw data array, then call sysex().
343
+ def handle_sysex(msg)
344
+ @raw_data = msg.dup()
345
+ sysex(msg)
346
+ end
347
+
348
+ # Copy message into raw data array, then call arbitrary().
349
+ def handle_arbitrary(msg)
350
+ @raw_data = msg.dup()
351
+ arbitrary(msg)
352
+ end
353
+
354
+ # Read and return a sixteen bit value.
355
+ def read16
356
+ val = (getc() << 8) + getc()
357
+ val = -(val & 0x7fff) if (val & 0x8000).nonzero?
358
+ return val
359
+ end
360
+
361
+ # Read and return a 32-bit value.
362
+ def read32
363
+ val = (getc() << 24) + (getc() << 16) + (getc() << 8) +
364
+ getc()
365
+ val = -(val & 0x7fffffff) if (val & 0x80000000).nonzero?
366
+ return val
367
+ end
368
+
369
+ # Read a varlen value.
370
+ def read_var_len
371
+ @raw_var_num_data = ''
372
+ c = getc()
373
+ @raw_var_num_data << c
374
+ val = c
375
+ if (val & 0x80).nonzero?
376
+ val &= 0x7f
377
+ while true
378
+ c = getc()
379
+ @raw_var_num_data << c
380
+ val = (val << 7) + (c & 0x7f)
381
+ break if (c & 0x80).zero?
382
+ end
383
+ end
384
+ return val
385
+ end
386
+
387
+ # Write a sixteen-bit value.
388
+ def write16(val)
389
+ val = (-val) | 0x8000 if val < 0
390
+ putc((val >> 8) & 0xff)
391
+ putc(val & 0xff)
392
+ end
393
+
394
+ # Write a 32-bit value.
395
+ def write32(val)
396
+ val = (-val) | 0x80000000 if val < 0
397
+ putc((val >> 24) & 0xff)
398
+ putc((val >> 16) & 0xff)
399
+ putc((val >> 8) & 0xff)
400
+ putc(val & 0xff)
401
+ end
402
+
403
+ # Write a variable length value.
404
+ def write_var_len(val)
405
+ if val.zero?
406
+ putc(0)
407
+ return
408
+ end
409
+
410
+ buf = Array.new()
411
+
412
+ buf << (val & 0x7f)
413
+ while (value >>= 7) > 0
414
+ buf << (val & 0x7f) | 0x80
415
+ end
416
+
417
+ buf.reverse.each { | b | putc(b) }
418
+ end
419
+
420
+ # Add a byte to the current message buffer.
421
+ def msg_add(c)
422
+ @msg_buf << c
423
+ end
424
+
425
+ # Read and add a number of bytes to the message buffer. Return
426
+ # the last byte (so we can see if it's an EOX or not).
427
+ def msg_read(n_bytes)
428
+ @msg_buf << @io.read(n_bytes)
429
+ @bytes_to_be_read -= n_bytes
430
+ return @msg_buf[-1]
431
+ end
432
+
433
+ # Initialize the internal message buffer.
434
+ def msg_init
435
+ @msg_buf = ''
436
+ end
437
+
438
+ # Return a copy of the internal message buffer.
439
+ def msg
440
+ return @msg_buf.dup()
441
+ end
442
+
443
+ end
444
+
445
+ end
446
+ end