/
sound.go
156 lines (130 loc) · 2.84 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
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
package main
// Based on: https://github.com/hajimehoshi/oto/blob/main/example/main.go
import (
"io"
"math"
"runtime"
"sync"
"time"
"github.com/hajimehoshi/oto/v2"
)
var (
otoContext *oto.Context
players []oto.Player
sampleRate = 44100
channelNum = 2
bitDepthInBytes = 2
ready chan struct{}
)
type SineWave struct {
freq float64
length int64
pos int64
remaining []byte
}
func initSound() {
otoContext, ready, err = oto.NewContext(sampleRate, channelNum, bitDepthInBytes)
}
func algoSound(totalDots int) {
var numerator int
if randomSeed > 5000 {
numerator = randomSeed
} else {
numerator = 5000
}
var counting int
if totalDots < 5000 {
counting = 5000
} else {
counting = totalDots
}
multiple := (numerator / 2000) + 1
freq := float64(counting/multiple) * math.Sin(float64(totalDots))
if totalDots%3 == 0 {
playSound(freq)
}
}
func playSound(freq float64) error {
if err != nil {
return err
}
<-ready
var m sync.Mutex
go func() {
p := play(otoContext, freq, time.Duration(1000)*time.Millisecond)
m.Lock()
players = append(players, p)
m.Unlock()
}()
// Pin the players not to GC the players.
runtime.KeepAlive(players)
return nil
}
func play(context *oto.Context, freq float64, duration time.Duration) oto.Player {
p := context.NewPlayer(NewSineWave(freq, duration))
p.Play()
return p
}
func NewSineWave(freq float64, duration time.Duration) *SineWave {
l := int64(channelNum) * int64(bitDepthInBytes) * int64(sampleRate) * int64(duration) / int64(time.Second)
l = l / 4 * 4
return &SineWave{
freq: freq,
length: l,
}
}
func (s *SineWave) Read(buf []byte) (int, error) {
if len(s.remaining) > 0 {
n := copy(buf, s.remaining)
copy(s.remaining, s.remaining[n:])
s.remaining = s.remaining[:len(s.remaining)-n]
return n, nil
}
if s.pos == s.length {
return 0, io.EOF
}
eof := false
if s.pos+int64(len(buf)) > s.length {
buf = buf[:s.length-s.pos]
eof = true
}
var origBuf []byte
if len(buf)%4 > 0 {
origBuf = buf
buf = make([]byte, len(origBuf)+4-len(origBuf)%4)
}
length := float64(sampleRate) / float64(s.freq)
num := (bitDepthInBytes) * (channelNum)
p := s.pos / int64(num)
switch bitDepthInBytes {
case 1:
for i := 0; i < len(buf)/num; i++ {
const max = 127
b := int(math.Sin(2*math.Pi*float64(p)/length) * 0.3 * max)
for ch := 0; ch < channelNum; ch++ {
buf[num*i+ch] = byte(b + 128)
}
p++
}
case 2:
for i := 0; i < len(buf)/num; i++ {
const max = 32767
b := int16(math.Sin(2*math.Pi*float64(p)/length) * 0.3 * max)
for ch := 0; ch < channelNum; ch++ {
buf[num*i+2*ch] = byte(b)
buf[num*i+1+2*ch] = byte(b >> 8)
}
p++
}
}
s.pos += int64(len(buf))
n := len(buf)
if origBuf != nil {
n = copy(origBuf, buf)
s.remaining = buf[n:]
}
if eof {
return n, io.EOF
}
return n, nil
}