-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdecoder.go
304 lines (262 loc) · 8.95 KB
/
decoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
167
168
169
170
171
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
package midi
import (
"bufio"
"encoding/binary"
"errors"
"fmt"
"io"
)
type timeFormat int
type nextChunkType int
const (
MetricalTF timeFormat = iota + 1
TimeCodeTF
)
const (
eventChunk nextChunkType = iota + 1
trackChunk
)
/*Decoder Format documented there: http://www.music.mcgill.ca/~ich/classes/mumt306/midiformat.pdf
<Header Chunk> = <chunk type><length><format><ntrks><division>
Division, specifies the meaning of the delta-times.
It has two formats, one for metrical time, and one for time-code-based
time:
+---+-----------------------------------------+
| 0 | ticks per quarter-note |
==============================================|
| 1 | negative SMPTE format | ticks per frame|
+---+-----------------------+-----------------+
|15 |14 8 |7 0 |
If bit 15 of <division> is zero, the bits 14 thru 0 represent the number
of delta time "ticks" which make up a quarter-note. For instance, if
division is 96, then a time interval of an eighth-note between two
events in the file would be 48.
If bit 15 of <division> is a one, delta times in a file correspond
to subdivisions of a second, in a way consistent with SMPTE and MIDI
Time Code. Bits 14 thru 8 contain one of the four values -24, -25, -29,
or -30, corresponding to the four standard SMPTE and MIDI Time Code
formats (-29 corresponds to 30 drop frome), and represents the
number of frames per second. These negative numbers are stored in
two's compliment form. The second byte (stored positive) is the
resolution within a frame: typical values may be 4 (MIDI Time Code
resolution), 8, 10, 80 (bit resolution), or 100. This stream allows
exact specifications of time-code-based tracks, but also allows
milisecond-based tracks by specifying 25|frames/sec and a
resolution of 40 units per frame. If the events in a file are stored
with a bit resolution of thirty-framel time code, the division word
would be E250 hex.
*/
type Decoder struct {
r *bufio.Reader
lastEvent *Event
Debug bool
Ch chan *Track
/*
Format describes the tracks format
0 - single-track
Format 0 file has a header chunk followed by one track chunk. It
is the most interchangable representation of data. It is very useful
for a simple single-track player in a program which needs to make
synthesizers make sounds, but which is primarily concerened with
something else such as mixers or sound effect boxes. It is very
desirable to be able to produce such a format, even if your program
is track-based, in order to work with these simple programs. On the
other hand, perhaps someone will write a format conversion from
format 1 to format 0 which might be so easy to use in some setting
that it would save you the trouble of putting it into your program.
Synchronous multiple tracks means that the tracks will all be vertically synchronous, or in other words,
they all start at the same time, and so can represent different parts in one song.
1 - multiple tracks, synchronous
Asynchronous multiple tracks do not necessarily start at the same time, and can be completely asynchronous.
2 - multiple tracks, asynchronous
*/
Format uint16
// NumTracks represents the number of tracks in the midi file
NumTracks uint16
TicksPerQuarterNote uint16
TimeFormat timeFormat
Tracks []*Track
}
// CurrentTrack returns the current track
func (d *Decoder) CurrentTrack() *Track {
if d == nil || len(d.Tracks) == 0 {
return nil
}
return d.Tracks[len(d.Tracks)-1]
}
// Parse is a deprecated API, Decode() should be used instead.
func (d *Decoder) Parse() error {
return d.Decode()
}
// Decode decodes the MIDI file into a structure available from the decoder.
func (d *Decoder) Decode() error {
var err error
var code [4]byte
var division uint16
if err = binary.Read(d.r, binary.BigEndian, &code); err != nil {
return err
}
if code != headerChunkID {
return fmt.Errorf("%s - %v", ErrFmtNotSupported, code)
}
var headerSize uint32
if err = binary.Read(d.r, binary.BigEndian, &headerSize); err != nil {
return err
}
if headerSize != 6 {
return fmt.Errorf("%s - expected header size to be 6, was %d", ErrFmtNotSupported, headerSize)
}
if err = binary.Read(d.r, binary.BigEndian, &d.Format); err != nil {
return err
}
if err = binary.Read(d.r, binary.BigEndian, &d.NumTracks); err != nil {
return err
}
if err = binary.Read(d.r, binary.BigEndian, &division); err != nil {
return err
}
// If bit 15 of <division> is zero, the bits 14 thru 0 represent the number
// of delta time "ticks" which make up a quarter-note. For instance, if
// division is 96, then a time interval of an eighth-note between two
// events in the file would be 48.
if (division & 0x8000) == 0 {
d.TicksPerQuarterNote = division & 0x7FFF
d.TimeFormat = MetricalTF
} else {
/*
If bit 15 of <division> is a one, delta times in a file correspond
to subdivisions of a second, in a way consistent with SMPTE and MIDI
Time Code. Bits 14 thru 8 contain one of the four values -24, -25, -29,
or -30, corresponding to the four standard SMPTE and MIDI Time Code
formats (-29 corresponds to 30 drop frome), and represents the
number of frames per second. These negative numbers are stored in
two's compliment form. The second byte (stored positive) is the
resolution within a frame: typical values may be 4 (MIDI Time Code
resolution), 8, 10, 80 (bit resolution), or 100. This stream allows
exact specifications of time-code-based tracks, but also allows
milisecond-based tracks by specifying 25|frames/sec and a
resolution of 40 units per frame. If the events in a file are stored
with a bit resolution of thirty-frames time code, the division word
would be E250 hex.
*/
d.TimeFormat = TimeCodeTF
}
_, nextChunk, err := d.parseTrack()
if err != nil {
return err
}
for err != io.EOF {
switch nextChunk {
case eventChunk:
nextChunk, err = d.parseEvent()
case trackChunk:
_, nextChunk, err = d.parseTrack()
}
if err != nil && err != io.EOF {
return err
}
}
// All done
return nil
}
func (d *Decoder) parseTrack() (uint32, nextChunkType, error) {
id, size, err := d.IDnSize()
if err != nil {
return 0, trackChunk, err
}
if id != trackChunkID {
return 0, trackChunk, fmt.Errorf("%s - expected track chunk ID %v, got %v", ErrUnexpectedData, trackChunkID, id)
}
d.Tracks = append(d.Tracks, &Track{Size: size})
return size, eventChunk, nil
}
// IDnSize returns the next ID + block size
func (d *Decoder) IDnSize() ([4]byte, uint32, error) {
var ID [4]byte
var blockSize uint32
if err := binary.Read(d.r, binary.BigEndian, &ID); err != nil {
return ID, blockSize, err
}
if err := binary.Read(d.r, binary.BigEndian, &blockSize); err != nil {
return ID, blockSize, err
}
return ID, blockSize, nil
}
// VarLen returns the variable length value at the exact parser location.
func (d *Decoder) VarLen() (val uint32, readBytes uint32, err error) {
buf := []byte{}
var lastByte bool
var n uint32
for !lastByte {
b, err := d.ReadByte()
if err != nil {
return 0, n, err
}
buf = append(buf, b)
lastByte = (b>>7 == 0x0)
n++
}
val, _ = DecodeVarint(buf)
return val, n, nil
}
// VarLenTxt Returns a variable length text string as well as the amount of
// bytes read
func (d *Decoder) VarLenTxt() (string, uint32, error) {
var l uint32
var err error
var n uint32
if l, n, err = d.VarLen(); err != nil {
return "", n, err
}
buf := make([]byte, l)
m, err := d.r.Read(buf)
if err != nil {
return string(buf), n + uint32(m), err
}
if uint32(m) != l {
err = errors.New("couldn't read full var length text")
}
return string(buf), n + uint32(m), err
}
// ReadByte returns one byte from the decoder
func (d *Decoder) ReadByte() (byte, error) {
var b byte
err := binary.Read(d.r, binary.BigEndian, &b)
return b, err
}
// Read reads n bytes from the parser's reader and stores them into the provided dst,
// which must be a pointer to a fixed-size value.
func (d *Decoder) Read(dst interface{}) error {
return binary.Read(d.r, binary.BigEndian, dst)
}
// Uint7 reads a byte and converts the first 7 bits into an uint8
func (d *Decoder) Uint7() (uint8, error) {
b, err := d.ReadByte()
if err != nil {
return 0, err
}
return (b & 0x7f), nil
}
// Uint24 reads 3 bytes and convert them into a uint32
func (d *Decoder) Uint24() (uint32, error) {
bytes := make([]byte, 3)
if err := d.Read(bytes); err != nil {
return 0, err
}
var output uint32
output |= uint32(bytes[2]) << 0
output |= uint32(bytes[1]) << 8
output |= uint32(bytes[0]) << 16
return output, nil
}
// DecodeUint24 converts 3 bytes to an uint32
func DecodeUint24(bytes []byte) (uint32, error) {
if len(bytes) != 3 {
return 0, fmt.Errorf("bytes length was %d", len(bytes))
}
var output uint32
output |= uint32(bytes[2]) << 0
output |= uint32(bytes[1]) << 8
output |= uint32(bytes[0]) << 16
return output, nil
}