-
Notifications
You must be signed in to change notification settings - Fork 0
/
audio.go
82 lines (72 loc) · 1.86 KB
/
audio.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
// The author disclaims copyright to this source code. In place of
// a legal notice, here is a blessing:
//
// May you do good and not evil.
// May you find forgiveness for yourself and forgive others.
// May you share freely, never taking more than you give.
package drum
import (
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
)
type audioData struct {
Channels uint16
Samples uint32
SamplesPerSecond uint32
BytesPerSecond uint32
BytesPerBlock uint16
BitsPerSample uint16
Data []int32
}
func decodeAudio(p string) (*audioData, error) {
switch strings.ToLower(path.Ext(p)) {
case ".wav":
return decodeWAV(p)
default:
return nil, fmt.Errorf("unsupported audio format")
}
}
func decodeWAV(path string) (*audioData, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
if string(b[0:4]) != "RIFF" || string(b[8:16]) != "WAVEfmt " {
return nil, fmt.Errorf("bad file format")
}
a := audioData{
Channels: binary.LittleEndian.Uint16(b[22:24]),
SamplesPerSecond: binary.LittleEndian.Uint32(b[24:28]),
BytesPerSecond: binary.LittleEndian.Uint32(b[28:32]),
BytesPerBlock: binary.LittleEndian.Uint16(b[32:34]),
BitsPerSample: binary.LittleEndian.Uint16(b[34:36]),
}
if string(b[36:40]) != "data" {
return nil, fmt.Errorf("bad file format")
}
sampleDataSize := binary.LittleEndian.Uint32(b[40:44])
b = b[44 : 44+sampleDataSize]
a.Data = make([]int32, len(b)/4)
switch a.BytesPerBlock {
case 3:
ts := make([]byte, 4)
for i := 0; i < len(a.Data); i++ {
copy(ts[1:4], b[i*3:(i+1)*3])
a.Data[i] = int32(binary.LittleEndian.Uint32(ts))
}
default:
for i := 0; i < len(a.Data); i++ {
a.Data[i] = int32(binary.LittleEndian.Uint32(b[i*4 : (i+1)*4]))
}
}
return &a, nil
}