-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfades.go
124 lines (113 loc) · 3.71 KB
/
fades.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
package gotes
import (
"math"
"time"
)
// Looper will swap through the provided set of wave functions, playing each one
// for "dur" amount of time. There is no transition; so unless the wave
// functions themselves blend well this can easily lead to popping.
func Looper(
dur time.Duration,
fns ...WaveFn,
) WaveFn {
if len(fns) == 0 {
return ZeroWave()
}
durT := float64(dur) / float64(time.Second)
return func(t float64) float64 {
nextI := (int(t/durT) + len(fns)) % len(fns)
t = math.Mod(t, durT) // note (bs): inefficient
return fns[nextI](t)
}
}
// LinearFadeLooper will swap through the provided set of wave functions,
// playing each one for "dur" amount of time and transitioning in time "fade".
// It uses an linear transition function between waves.
func LinearFadeLooper(
dur, fade time.Duration,
fns ...WaveFn,
) WaveFn {
return genericFadeLooper(dur, fade, LinearMix, fns...)
}
// ExpFadeLooper will swap through the provided set of wave functions,
// playing each one for "dur" amount of time and transitioning in time "fade".
// It uses an exponential transition function between waves.
func ExpFadeLooper(
dur, fade time.Duration,
fns ...WaveFn,
) WaveFn {
return genericFadeLooper(dur, fade, ExpMix, fns...)
}
// SinFadeLooper will swap through the provided set of wave functions,
// playing each one for "dur" amount of time and transitioning in time "fade".
// It uses an sin transition function between waves.
func SinFadeLooper(
dur, fade time.Duration,
fns ...WaveFn,
) WaveFn {
return genericFadeLooper(dur, fade, SinMix, fns...)
}
// SigmoidFadeLooper will swap through the provided set of wave functions,
// playing each one for "dur" amount of time and transitioning in time "fade".
// It uses an sigmoid transition function between waves.
func SigmoidFadeLooper(
dur, fade time.Duration,
fns ...WaveFn,
) WaveFn {
return genericFadeLooper(dur, fade, SigmoidMix, fns...)
}
func genericFadeLooper(
dur, fade time.Duration,
mix func(t float64, v1, v2 float64) float64,
fns ...WaveFn,
) WaveFn {
if len(fns) == 0 {
fns = []WaveFn{
ZeroWave(),
}
}
durT := float64(dur) / float64(time.Second)
fadeT := float64(fade) / float64(time.Second)
return func(t float64) float64 {
nextI := (int(t/durT) + len(fns)) % len(fns)
lastI := (nextI - 1 + len(fns)) % len(fns)
lastFn, nextFn := fns[lastI], fns[nextI]
if nextI == 0 && t < durT {
lastFn = ZeroWave()
}
// fixme (bs): math.mod is very inefficient
return mix(math.Mod(t, durT)/fadeT, lastFn(t), nextFn(t))
}
}
// LinearMix blends v1 and v2 based on the time value. It's v1 for t<0, v2 for t>1,
// and a linear transition between the two from 0->1.
func LinearMix(t float64, v1, v2 float64) float64 {
per := math.Min(1, math.Max(0, t))
fadeOut := 1 - per
fadeIn := per
return v1*fadeOut + v2*fadeIn
}
// ExpMix blends v1 and v2 based on the time value. It's v1 for t<0, v2 for t>1,
// and an exponential transition in 0->1.
func ExpMix(t float64, v1, v2 float64) float64 {
c := 0.1 // note (bs) - technically, this could be made configurable.
fadeOut := (1 / (1 - c)) * (math.Pow(c, t) - c)
fadeIn := 1 - fadeOut
return fadeOut*v1 + fadeIn*v2
}
// Sin blends v1 and v2 based on the time value. It's v1 for t<0, v2 for t>1,
// and a sin transition in 0->1.
func SinMix(t float64, v1, v2 float64) float64 {
t = math.Min(1, math.Max(0, t))
fadeOut := (math.Cos(t*math.Pi) + 1) / 2
fadeIn := 1 - fadeOut
return v1*fadeOut + v2*fadeIn
}
// SigmoidMix blends v1 and v2 based on the time value. It's v1 for t<0, v2 for t>1,
// and a sigmoid transition in 0->1.
func SigmoidMix(t float64, v1, v2 float64) float64 {
t = math.Min(1, math.Max(0, t))
fadeIn := 1 / (1 + math.Pow(math.E, 6-12*t))
fadeOut := 1 - fadeIn
return v1*fadeOut + v2*fadeIn
}