-
Notifications
You must be signed in to change notification settings - Fork 0
/
calculate.go
77 lines (59 loc) · 2.26 KB
/
calculate.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
// Package calculate provides convenient functions to help perform various
// repetitive calculations. It is meant to be used by the top level package
// inside compositional algos (ie. Algo1.)
package calculate
import (
"github.com/chewxy/math32"
"github.com/go-audio/audio"
)
// LinearScale (value - r.Min) / (r.Max - r.Min) * (t.Max - t.Min) + t.Min.
func LinearScale(value float64, r MinMax, t MinMax) float64 {
return ((value - r.Min) / (r.Max - r.Min)) * ((t.Max - t.Min) + t.Min)
}
// SineOptions hold the frequency, amplitude, and attack, decay, release information.
type SineOptions struct {
// Freq is the frequency of the sine wave.
Freq float32
// Amp is the amplitude of the sine wave.
Amp float32
// A, D, R represents the attack, decay, release times in milliseconds.
A, D, R float64
}
// SineGeneration generates a sine wave according to the parameters provided.
// It returns an audio.PCMBuffer loaded with the generated sine wave as 32bit floating point slice []F32.
// The math package used to calculate the sine wave is github.com/chewxy/math32.
// If f is nil it returns an empty audio.PCMbuffer{}.
func SineGeneration(f *audio.Format, opts SineOptions) audio.PCMBuffer {
if f == nil {
return audio.PCMBuffer{}
}
var phase float32
var step = opts.Freq / float32(f.SampleRate)
var signal = audio.PCMBuffer{
Format: f,
DataType: audio.DataTypeF32,
SourceBitDepth: 32,
}
attackInSamples := int(opts.A / (1000 / float64(f.SampleRate)))
for i := 0; i < attackInSamples; i++ {
sample := math32.Sin(2 * math32.Pi * phase)
s := sample * (float32(i) * (opts.Amp / float32(attackInSamples)))
signal.F32 = append(signal.F32, s)
_, phase = math32.Modf(phase + step)
}
decayInSamples := int(opts.D / (1000 / float64(f.SampleRate)))
for i := 0; i < decayInSamples; i++ {
sample := math32.Sin(2 * math32.Pi * phase)
s := sample * opts.Amp
signal.F32 = append(signal.F32, s)
_, phase = math32.Modf(phase + step)
}
releaseInSamples := int(opts.R / (1000 / float64(f.SampleRate)))
for i := releaseInSamples; i > 0; i-- {
sample := math32.Sin(2 * math32.Pi * phase)
s := sample * (float32(i) * (opts.Amp / float32(releaseInSamples)))
signal.F32 = append(signal.F32, s)
_, phase = math32.Modf(phase + step)
}
return signal
}