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:
|
||||
- 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
|
||||
|
|
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
|
||||
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
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
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 (
|
||||
"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)]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue