-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransforms.go
79 lines (70 loc) · 1.96 KB
/
transforms.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
package transforms
import (
"math"
"github.com/go-audio/audio"
)
// FullWaveRectifier to make all signal positive
// See https://en.wikipedia.org/wiki/Rectifier#Full-wave_rectification
func FullWaveRectifier(buf *audio.FloatBuffer) error {
if buf == nil {
return audio.ErrInvalidBuffer
}
for i := 0; i < len(buf.Data); i++ {
buf.Data[i] = math.Abs(buf.Data[i])
}
return nil
}
// MonoRMS converts the buffer to mono and apply an RMS treatment.
// rms = sqrt ( (1/n) * (x12 + x22 + … + xn2) )
// multiplying by 1/n effectively assigns equal weights to all the terms, making it a rectangular window.
// Other window equations can be used instead which would favor terms in the middle of the window.
// This results in even greater accuracy of the RMS value since brand new samples (or old ones at
// the end of the window) have less influence over the signal’s power.)
// TODO: use a sine wave at amplitude of 1: rectication + average = 1.4 (1/square root of 2)
func MonoRMS(b *audio.FloatBuffer, windowSize int) error {
if b == nil {
return audio.ErrInvalidBuffer
}
if len(b.Data) == 0 {
return nil
}
out := []float64{}
winBuf := make([]float64, windowSize)
windowSizeF := float64(windowSize)
processWindow := func(idx int) {
total := 0.0
for i := 0; i < len(winBuf); i++ {
total += winBuf[idx] * winBuf[idx]
}
v := math.Sqrt((1.0 / windowSizeF) * total)
out = append(out, v)
}
nbrChans := 1
if b.Format != nil {
nbrChans = b.Format.NumChannels
}
var windowIDX int
// process each frame, convert it to mono and them RMS it
for i := 0; i < len(b.Data); i++ {
v := b.Data[i]
if nbrChans > 1 {
for j := 1; j < nbrChans; j++ {
i++
v += b.Data[i]
}
v /= float64(nbrChans)
}
winBuf[windowIDX] = v
windowIDX++
if windowIDX == windowSize || i == (len(b.Data)-1) {
windowIDX = 0
processWindow(windowIDX)
}
}
if b.Format != nil {
b.Format.NumChannels = 1
b.Format.SampleRate /= windowSize
}
b.Data = out
return nil
}