DataHoarder
6476c8414b
All checks were successful
continuous-integration/drone/push Build is passing
169 lines
3.7 KiB
Go
169 lines
3.7 KiB
Go
package goborator
|
|
|
|
/*
|
|
#cgo pkg-config: cgaborator
|
|
#include <cgaborator.h>
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"golang.org/x/exp/slices"
|
|
"log"
|
|
"runtime"
|
|
"unsafe"
|
|
)
|
|
|
|
type Gaborator struct {
|
|
pointer C.uintptr_t
|
|
audioBlockSize int
|
|
coefficientOutputChannel chan []float32
|
|
bandsPerOctave int
|
|
bandNumberCache int
|
|
latency int64
|
|
}
|
|
|
|
func NewGaborator(blockSize int, sampleRate float64, bandsPerOctave int, minimumFrequency, maximumFrequency, referenceFrequency float64, stepSize int) *Gaborator {
|
|
ob := &Gaborator{
|
|
pointer: C.gaborator_initialize(C.int(blockSize), C.double(sampleRate), C.int(bandsPerOctave), C.double(minimumFrequency), C.double(referenceFrequency), C.double(maximumFrequency), C.int(stepSize)),
|
|
audioBlockSize: blockSize,
|
|
bandsPerOctave: bandsPerOctave,
|
|
}
|
|
ob.bandNumberCache = ob.GetNumberOfBands()
|
|
ob.latency = int64(C.gaborator_analysis_support(ob.pointer))
|
|
return ob
|
|
}
|
|
|
|
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) GetChannel() chan []float32 {
|
|
|
|
if g.coefficientOutputChannel == nil {
|
|
g.coefficientOutputChannel = make(chan []float32, 1024)
|
|
}
|
|
|
|
return g.coefficientOutputChannel
|
|
}
|
|
|
|
func (g *Gaborator) GaborBlockTransform(source chan []float32) (channel chan []float32) {
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
//finish
|
|
err := g.Process(nil)
|
|
if err != nil {
|
|
log.Panic(err)
|
|
}
|
|
}()
|
|
|
|
return channel
|
|
}
|
|
|
|
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 {
|
|
|
|
if len(block) > g.audioBlockSize {
|
|
return fmt.Errorf("invalid block size %d > %d", len(block), g.audioBlockSize)
|
|
}
|
|
g.gaborTransform(block)
|
|
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
|
|
}
|
|
}
|
|
|
|
func (g *Gaborator) GetBlockSize() int {
|
|
return g.audioBlockSize
|
|
}
|
|
|
|
func (g *Gaborator) GetLatency() int64 {
|
|
return g.latency
|
|
}
|
|
|
|
func (g *Gaborator) GetBandwidth() float64 {
|
|
return 1200. / float64(g.bandsPerOctave)
|
|
}
|
|
|
|
func (g *Gaborator) analyze(block []float32) {
|
|
var returnSize C.size_t
|
|
var sliceSize C.size_t
|
|
var returnData *C.float
|
|
|
|
if len(block) == 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)
|
|
}
|
|
|
|
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]
|
|
}
|
|
}
|