Update to go 1.21, use callbacks instead of channel output

This commit is contained in:
DataHoarder 2023-10-15 16:24:06 +02:00
parent 6476c8414b
commit 0de09fa45e
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
5 changed files with 72 additions and 90 deletions

View file

@ -5,7 +5,7 @@ name: build
steps:
- name: build
image: golang:1.18-bullseye
image: golang:1.21-bullseye
commands:
- DEBIAN_FRONTEND=noninteractive apt update
- DEBIAN_FRONTEND=noninteractive apt install -y git build-essential cmake make

View file

@ -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
terms of the GNU Affero General Public License, version 3 (henceforth,

2
go.mod
View file

@ -1,5 +1,5 @@
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

View file

@ -7,13 +7,14 @@ package goborator
import "C"
import (
"fmt"
"golang.org/x/exp/slices"
"log"
"runtime"
"slices"
"sync"
"unsafe"
)
type Gaborator struct {
closeOnce sync.Once
pointer C.uintptr_t
audioBlockSize int
coefficientOutputChannel chan []float32
@ -37,97 +38,79 @@ func (g *Gaborator) GetNumberOfBands() int {
return int(C.gaborator_number_of_bands(g.pointer))
}
func (g *Gaborator) gaborTransform(audioData []float32) {
g.analyze(audioData)
func (g *Gaborator) gaborTransform(audioData []float32, outputCallback func(output []float32)) {
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 {
g.coefficientOutputChannel = make(chan []float32, 1024)
for {
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()
go func() {
defer g.ProcessingFinished()
for {
block, more := <-source
if !more {
break
}
err := g.Process(block)
if err != nil {
log.Panic(err)
}
for {
f, more := <-source
if !more {
break
}
audioData = append(audioData, f)
//finish
err := g.Process(nil)
for len(audioData) >= g.audioBlockSize {
g.gaborTransform(audioData[0:g.audioBlockSize], outputCallback)
audioData = audioData[:0]
}
}
//finish
if len(audioData) > 0 {
err := g.Process(audioData, outputCallback)
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) {
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 {
func (g *Gaborator) Process(block []float32, outputCallback func(output []float32)) error {
if 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
}
func (g *Gaborator) ProcessingFinished() {
if g.pointer != 0 {
C.gaborator_release(g.pointer)
g.pointer = 0
}
if g.coefficientOutputChannel != nil {
close(g.coefficientOutputChannel)
g.coefficientOutputChannel = nil
}
g.closeOnce.Do(func() {
if g.pointer != 0 {
C.gaborator_release(g.pointer)
g.pointer = 0
}
})
}
func (g *Gaborator) GetBlockSize() int {
@ -142,27 +125,23 @@ func (g *Gaborator) GetBandwidth() float64 {
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 sliceSize C.size_t
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)
} else {
defer runtime.KeepAlive(block)
returnData = C.gaborator_transform(g.pointer, (*C.float)(&block[0]), C.int64_t(len(block)), &returnSize, &sliceSize)
defer runtime.KeepAlive(input)
returnData = C.gaborator_transform(g.pointer, (*C.float)(&input[0]), C.int64_t(len(input)), &returnSize, &sliceSize)
}
if returnData != nil && returnSize > 0 {
g.outputResult(unsafe.Slice((*float32)(returnData), uint64(returnSize)), 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]
block := unsafe.Slice((*float32)(returnData), uint64(returnSize))
for i := 0; i < len(block); i += int(sliceSize) {
outputCallback(slices.Clone(block[i : i+int(sliceSize)]))
}
}
}

View file

@ -2,8 +2,8 @@ package goborator
import (
"fmt"
"golang.org/x/exp/slices"
"os"
"slices"
"testing"
"time"
"unsafe"
@ -40,8 +40,11 @@ func TestGoborator(t *testing.T) {
start := time.Now()
var data [][]float32
for c := range ob.GaborBlockTransform(channel) {
data = append(data, c)
err = ob.GaborBlockTransform(channel, func(output []float32) {
data = append(data, output)
})
if err != nil {
t.Fatal(err)
}
end := time.Now().Sub(start).Milliseconds()