From 0de09fa45e23754089f78eae4fa6272ced5f4557 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Sun, 15 Oct 2023 16:24:06 +0200 Subject: [PATCH] Update to go 1.21, use callbacks instead of channel output --- .drone.yml | 2 +- LICENSE | 2 +- go.mod | 2 +- goborator.go | 147 ++++++++++++++++++++-------------------------- goborator_test.go | 9 ++- 5 files changed, 72 insertions(+), 90 deletions(-) diff --git a/.drone.yml b/.drone.yml index bae7620..1577e49 100644 --- a/.drone.yml +++ b/.drone.yml @@ -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 diff --git a/LICENSE b/LICENSE index 168e6ef..1366ff2 100644 --- a/LICENSE +++ b/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 terms of the GNU Affero General Public License, version 3 (henceforth, diff --git a/go.mod b/go.mod index f26cac0..77f1b7f 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/goborator.go b/goborator.go index 4bd08ff..5d36ee2 100644 --- a/goborator.go +++ b/goborator.go @@ -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)])) + } } } diff --git a/goborator_test.go b/goborator_test.go index f9c843b..5e4fadc 100644 --- a/goborator_test.go +++ b/goborator_test.go @@ -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()