Update to go 1.21, use callbacks instead of channel output
This commit is contained in:
parent
6476c8414b
commit
0de09fa45e
|
@ -5,7 +5,7 @@ name: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: golang:1.18-bullseye
|
image: golang:1.21-bullseye
|
||||||
commands:
|
commands:
|
||||||
- DEBIAN_FRONTEND=noninteractive apt update
|
- DEBIAN_FRONTEND=noninteractive apt update
|
||||||
- DEBIAN_FRONTEND=noninteractive apt install -y git build-essential cmake make
|
- DEBIAN_FRONTEND=noninteractive apt install -y git build-essential cmake make
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
goborator is Copyright (C) 2022 WeebDataHoarder.
|
goborator is Copyright (C) 2023 WeebDataHoarder.
|
||||||
|
|
||||||
License to distribute and modify the code is hereby granted under the
|
License to distribute and modify the code is hereby granted under the
|
||||||
terms of the GNU Affero General Public License, version 3 (henceforth,
|
terms of the GNU Affero General Public License, version 3 (henceforth,
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,5 +1,5 @@
|
||||||
module git.gammaspectra.live/S.O.N.G/goborator
|
module git.gammaspectra.live/S.O.N.G/goborator
|
||||||
|
|
||||||
go 1.18
|
go 1.21
|
||||||
|
|
||||||
require golang.org/x/exp v0.0.0-20221212164502-fae10dda9338
|
require golang.org/x/exp v0.0.0-20221212164502-fae10dda9338
|
||||||
|
|
147
goborator.go
147
goborator.go
|
@ -7,13 +7,14 @@ package goborator
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"log"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gaborator struct {
|
type Gaborator struct {
|
||||||
|
closeOnce sync.Once
|
||||||
pointer C.uintptr_t
|
pointer C.uintptr_t
|
||||||
audioBlockSize int
|
audioBlockSize int
|
||||||
coefficientOutputChannel chan []float32
|
coefficientOutputChannel chan []float32
|
||||||
|
@ -37,97 +38,79 @@ func (g *Gaborator) GetNumberOfBands() int {
|
||||||
return int(C.gaborator_number_of_bands(g.pointer))
|
return int(C.gaborator_number_of_bands(g.pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) gaborTransform(audioData []float32) {
|
func (g *Gaborator) gaborTransform(audioData []float32, outputCallback func(output []float32)) {
|
||||||
g.analyze(audioData)
|
g.analyze(audioData, outputCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) GetChannel() chan []float32 {
|
func (g *Gaborator) GaborBlockTransform(source chan []float32, outputCallback func(output []float32)) error {
|
||||||
|
defer g.ProcessingFinished()
|
||||||
|
|
||||||
if g.coefficientOutputChannel == nil {
|
for {
|
||||||
g.coefficientOutputChannel = make(chan []float32, 1024)
|
block, more := <-source
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := g.Process(block, outputCallback)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.coefficientOutputChannel
|
//finish
|
||||||
|
err := g.Process(nil, outputCallback)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) GaborBlockTransform(source chan []float32) (channel chan []float32) {
|
func (g *Gaborator) GaborTransform(source chan float32, outputCallback func(output []float32)) error {
|
||||||
|
defer g.ProcessingFinished()
|
||||||
|
audioData := make([]float32, 0, g.audioBlockSize)
|
||||||
|
|
||||||
channel = g.GetChannel()
|
for {
|
||||||
go func() {
|
f, more := <-source
|
||||||
defer g.ProcessingFinished()
|
if !more {
|
||||||
|
break
|
||||||
for {
|
|
||||||
block, more := <-source
|
|
||||||
if !more {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
err := g.Process(block)
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
audioData = append(audioData, f)
|
||||||
|
|
||||||
//finish
|
for len(audioData) >= g.audioBlockSize {
|
||||||
err := g.Process(nil)
|
g.gaborTransform(audioData[0:g.audioBlockSize], outputCallback)
|
||||||
|
audioData = audioData[:0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//finish
|
||||||
|
if len(audioData) > 0 {
|
||||||
|
err := g.Process(audioData, outputCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
return err
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
err := g.Process(nil, outputCallback)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return channel
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) GaborTransform(source chan float32) (channel chan []float32) {
|
func (g *Gaborator) Process(block []float32, outputCallback func(output []float32)) error {
|
||||||
channel = g.GetChannel()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer g.ProcessingFinished()
|
|
||||||
audioData := make([]float32, 0, g.audioBlockSize)
|
|
||||||
|
|
||||||
for {
|
|
||||||
f, more := <-source
|
|
||||||
if !more {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
audioData = append(audioData, f)
|
|
||||||
|
|
||||||
for len(audioData) >= g.audioBlockSize {
|
|
||||||
g.gaborTransform(audioData[0:g.audioBlockSize])
|
|
||||||
audioData = audioData[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//finish
|
|
||||||
if len(audioData) > 0 {
|
|
||||||
err := g.Process(audioData)
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := g.Process(nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return channel
|
|
||||||
}
|
|
||||||
func (g *Gaborator) Process(block []float32) error {
|
|
||||||
|
|
||||||
if len(block) > g.audioBlockSize {
|
if len(block) > g.audioBlockSize {
|
||||||
return fmt.Errorf("invalid block size %d > %d", len(block), g.audioBlockSize)
|
return fmt.Errorf("invalid block size %d > %d", len(block), g.audioBlockSize)
|
||||||
}
|
}
|
||||||
g.gaborTransform(block)
|
g.gaborTransform(block, outputCallback)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) ProcessingFinished() {
|
func (g *Gaborator) ProcessingFinished() {
|
||||||
if g.pointer != 0 {
|
g.closeOnce.Do(func() {
|
||||||
C.gaborator_release(g.pointer)
|
if g.pointer != 0 {
|
||||||
g.pointer = 0
|
C.gaborator_release(g.pointer)
|
||||||
}
|
g.pointer = 0
|
||||||
if g.coefficientOutputChannel != nil {
|
}
|
||||||
close(g.coefficientOutputChannel)
|
})
|
||||||
g.coefficientOutputChannel = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) GetBlockSize() int {
|
func (g *Gaborator) GetBlockSize() int {
|
||||||
|
@ -142,27 +125,23 @@ func (g *Gaborator) GetBandwidth() float64 {
|
||||||
return 1200. / float64(g.bandsPerOctave)
|
return 1200. / float64(g.bandsPerOctave)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gaborator) analyze(block []float32) {
|
func (g *Gaborator) analyze(input []float32, outputCallback func(output []float32)) {
|
||||||
var returnSize C.size_t
|
var returnSize C.size_t
|
||||||
var sliceSize C.size_t
|
var sliceSize C.size_t
|
||||||
var returnData *C.float
|
var returnData *C.float
|
||||||
|
|
||||||
if len(block) == 0 {
|
if len(input) == 0 {
|
||||||
returnData = C.gaborator_transform(g.pointer, (*C.float)(nil), C.int64_t(0), &returnSize, &sliceSize)
|
returnData = C.gaborator_transform(g.pointer, (*C.float)(nil), C.int64_t(0), &returnSize, &sliceSize)
|
||||||
} else {
|
} else {
|
||||||
defer runtime.KeepAlive(block)
|
defer runtime.KeepAlive(input)
|
||||||
returnData = C.gaborator_transform(g.pointer, (*C.float)(&block[0]), C.int64_t(len(block)), &returnSize, &sliceSize)
|
returnData = C.gaborator_transform(g.pointer, (*C.float)(&input[0]), C.int64_t(len(input)), &returnSize, &sliceSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if returnData != nil && returnSize > 0 {
|
if returnData != nil && returnSize > 0 {
|
||||||
g.outputResult(unsafe.Slice((*float32)(returnData), uint64(returnSize)), int(sliceSize))
|
block := unsafe.Slice((*float32)(returnData), uint64(returnSize))
|
||||||
}
|
|
||||||
}
|
for i := 0; i < len(block); i += int(sliceSize) {
|
||||||
|
outputCallback(slices.Clone(block[i : i+int(sliceSize)]))
|
||||||
func (g *Gaborator) outputResult(block []float32, sliceSize int) {
|
}
|
||||||
buf := slices.Clone(block)
|
|
||||||
|
|
||||||
for i := 0; i < len(block); i += sliceSize {
|
|
||||||
g.coefficientOutputChannel <- buf[i : i+sliceSize]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ package goborator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -40,8 +40,11 @@ func TestGoborator(t *testing.T) {
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
var data [][]float32
|
var data [][]float32
|
||||||
for c := range ob.GaborBlockTransform(channel) {
|
err = ob.GaborBlockTransform(channel, func(output []float32) {
|
||||||
data = append(data, c)
|
data = append(data, output)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
end := time.Now().Sub(start).Milliseconds()
|
end := time.Now().Sub(start).Milliseconds()
|
||||||
|
|
Loading…
Reference in a new issue