-
Notifications
You must be signed in to change notification settings - Fork 1
/
control.go
88 lines (76 loc) · 1.59 KB
/
control.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
package audio
import "fmt"
type Control struct {
params Params
points []*ControlPoint
periods []*controlPeriod
x float64
}
type ControlPoint struct {
Time, Value float64
}
func NewControl(points []*ControlPoint) *Control {
return &Control{points: points}
}
func (c *Control) InitAudio(params Params) {
c.params = params
c.SetPoints(c.points)
}
func (c *Control) SetPoints(points []*ControlPoint) {
for i := range points {
if i > 0 && points[i].Time < points[i-1].Time {
fmt.Printf("control points out of order: %#v\n", points)
break
}
}
c.points = points
c.SetTime(0)
}
func (c *Control) Duration() float64 {
if len(c.points) == 0 {
return 0
}
return c.points[len(c.points)-1].Time
}
func (c *Control) SetTime(t float64) {
c.periods = make([]*controlPeriod, len(c.points))
prev := &ControlPoint{}
for i, p := range c.points {
dn := (p.Time - prev.Time) * c.params.SampleRate
dx := (p.Value - prev.Value) / dn
c.periods[i] = &controlPeriod{int(dn), dx, p.Value}
prev = p
}
c.x = 0
n := int(t * c.params.SampleRate)
for _, p := range c.periods {
if p.n > n {
p.n -= n
c.x += float64(n) * p.dx
break
}
n -= p.n
c.x = p.value
c.periods = c.periods[1:]
}
}
func (c *Control) Sing() float64 {
for _, p := range c.periods {
if p.n > 0 {
p.n--
c.x += p.dx
break
}
c.x = p.value // this is necessary for zero-length controlPeriods that mark discontinuities
c.periods = c.periods[1:]
}
return c.x
}
func (c *Control) Done() bool {
return len(c.periods) == 0
}
type controlPeriod struct {
n int
dx float64
value float64
}