/
encoder.go
105 lines (88 loc) · 2.24 KB
/
encoder.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
package drum
import (
"encoding/binary"
"os"
)
// EncodePattern encodes the pattern to binary format and saves it to a file.
// Pretty much the opposite of `DecodeFile`.
func EncodePattern(p *Pattern, path string) error {
var err error
var magic []byte = []byte("SPLICE")
var patLen byte
var version []byte = []byte(DrumVersion)
var tempo float32 = p.Tempo
// First we have to create the file.
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
// Helper function to write `n` null bytes to the file.
writeNullBytes := func(n int) error {
b := make([]byte, n)
return binary.Write(f, binary.LittleEndian, b)
}
// Write the magic number to the head of the file.
err = binary.Write(f, binary.LittleEndian, magic)
if err != nil {
return err
}
// Write 7 null bytes.
err = writeNullBytes(7)
if err != nil {
return err
}
// Calculate and write the pattern length. Basically: `versionString + tempo + ((id + nameLen + name) * 16)`.
patLen = byte(len(DrumVersion)) + 4
for _, t := range p.Tracks {
patLen += 4 + 1 + byte(len(t.Name)) + 16
}
err = binary.Write(f, binary.LittleEndian, patLen)
if err != nil {
return err
}
// Write the version string.
err = binary.Write(f, binary.LittleEndian, version)
if err != nil {
return err
}
// The version string is expected to be a char[32], so we have to fill in some
// null bytes till we have reached 32 bytes.
err = writeNullBytes(32 - len(DrumVersion))
if err != nil {
return err
}
// Write the tempo.
err = binary.Write(f, binary.LittleEndian, tempo)
if err != nil {
return err
}
// Loop through each track.
for _, t := range p.Tracks {
var nameLen byte = byte(len(t.Name))
var steps []byte = make([]byte, 16)
// Write the id, name length and name
err = binary.Write(f, binary.LittleEndian, t.Id)
if err != nil {
return err
}
err = binary.Write(f, binary.LittleEndian, nameLen)
if err != nil {
return err
}
err = binary.Write(f, binary.LittleEndian, []byte(t.Name))
if err != nil {
return err
}
// Write the step bytes (`0` for false and `1` for true).
for i, s := range t.Steps {
if s {
steps[i] = 1
} else {
steps[i] = 0
}
}
err = binary.Write(f, binary.LittleEndian, steps)
}
return nil
}