-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathsound.go
112 lines (94 loc) · 2.13 KB
/
sound.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
// This code uses OpenAL Soft via gomobile/exp/audio/al.
// See included license file.
package main
import (
"encoding/binary"
"fmt"
"io"
"golang.org/x/mobile/asset"
"golang.org/x/mobile/exp/audio/al"
)
type Sound struct {
sources []al.Source
buffers []al.Buffer
sounds map[string]int
initiated bool
}
func (s *Sound) Init() {
if err := al.OpenDevice(); err != nil {
fmt.Printf("ERROR: failed to open sound device: %v", err)
return
}
s.initiated = true
s.sounds = make(map[string]int)
}
func (s *Sound) Load(name, file string, format uint32, hz int32) {
// So we still can play w/o audio
if !s.initiated {
return
}
f, err := asset.Open(file)
defer f.Close()
if err != nil {
panic(err)
}
data, err := io.ReadAll(f)
if err != nil {
panic(err)
}
// Skip wav headers (to avoid "playing" the header)
// We could parse this correctly, by following:
// http://www.topherlee.com/software/pcm-tut-wavformat.html
// But this will do for now...
// Position 41-44 is specifying data length
length := binary.LittleEndian.Uint32(data[40:44])
data = data[44:length]
s.sources = append(s.sources, al.GenSources(1)...)
s.buffers = append(s.buffers, al.GenBuffers(1)...)
id := len(s.buffers) - 1
s.sounds[name] = id
s.buffers[id].BufferData(format, data, hz)
s.sources[id].QueueBuffers(s.buffers[id])
}
func (s *Sound) Play(name string) {
if !s.initiated {
return
}
id, ok := s.sounds[name]
if !ok {
fmt.Printf("Sound %v not found\n", name)
return
}
if len(s.sources) < id {
fmt.Printf("Error: Sound is not loaded? Len: %d Id: %d\n", len(s.sources), id)
return
}
al.PlaySources(s.sources[id])
}
func (s *Sound) Stop(name string) {
if !s.initiated {
return
}
id, ok := s.sounds[name]
if !ok {
fmt.Printf("Sound %v not found\n", name)
return
}
if len(s.sources) < id {
fmt.Printf("Error: Sound is not loaded? Len: %d Id: %d\n", len(s.sources), id)
return
}
al.StopSources(s.sources[id])
}
func (s *Sound) Close() {
if !s.initiated {
return
}
for i := range s.sources {
al.DeleteSources(s.sources[i])
}
for i := range s.buffers {
al.DeleteBuffers(s.buffers[i])
}
al.CloseDevice()
}