This commit is contained in:
5684185+vsariola@users.noreply.github.com
2025-10-23 14:53:08 +03:00
parent 7f03664870
commit fa7901c7c6
9 changed files with 184 additions and 62 deletions

View File

@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/vsariola/sointu"
"github.com/vsariola/sointu/vm"
@ -16,7 +17,10 @@ import (
type NativeSynther struct {
}
type NativeSynth C.Synth
type NativeSynth struct {
csynth C.Synth
cpuLoad sointu.CPULoad
}
func (s NativeSynther) Name() string { return "Native" }
func (s NativeSynther) SupportsParallelism() bool { return false }
@ -46,7 +50,7 @@ func Synth(patch sointu.Patch, bpm int) (*NativeSynth, error) {
s.Opcodes[0] = 0
s.NumVoices = 1
s.Polyphony = 0
return (*NativeSynth)(s), nil
return &NativeSynth{csynth: *s}, nil
}
for i, v := range comPatch.Opcodes {
s.Opcodes[i] = (C.uchar)(v)
@ -65,11 +69,19 @@ func Synth(patch sointu.Patch, bpm int) (*NativeSynth, error) {
s.NumVoices = C.uint(comPatch.NumVoices)
s.Polyphony = C.uint(comPatch.PolyphonyBitmask)
s.RandSeed = 1
return (*NativeSynth)(s), nil
return &NativeSynth{csynth: *s}, nil
}
func (s *NativeSynth) Close() {}
func (s *NativeSynth) NumCores() int { return 1 }
func (s *NativeSynth) CPULoad(loads []sointu.CPULoad) {
if len(loads) < 1 {
return
}
loads[0] = s.cpuLoad
}
// Render renders until the buffer is full or the modulated time is reached, whichever
// happens first.
// Parameters:
@ -92,12 +104,14 @@ func (s *NativeSynth) Close() {}
// exit condition would fire when the time is already past maxtime.
// Under no conditions, nsamples >= len(buffer)/2 i.e. guaranteed to never overwrite the buffer.
func (bridgesynth *NativeSynth) Render(buffer sointu.AudioBuffer, maxtime int) (int, int, error) {
synth := (*C.Synth)(bridgesynth)
synth := &bridgesynth.csynth
// TODO: syncBuffer is not getting passed to cgo; do we want to even try to support the syncing with the native bridge
if len(buffer)%1 == 1 {
return -1, -1, errors.New("RenderTime writes stereo signals, so buffer should have even length")
}
samples := C.int(len(buffer))
startTime := time.Now()
defer func() { bridgesynth.cpuLoad.Update(time.Since(startTime), int64(samples)) }()
time := C.int(maxtime)
errcode := int(C.su_render(synth, (*C.float)(&buffer[0][0]), &samples, &time))
if errcode > 0 {
@ -108,7 +122,7 @@ func (bridgesynth *NativeSynth) Render(buffer sointu.AudioBuffer, maxtime int) (
// Trigger is part of C.Synths' implementation of sointu.Synth interface
func (bridgesynth *NativeSynth) Trigger(voice int, note byte) {
s := (*C.Synth)(bridgesynth)
s := &bridgesynth.csynth
if voice < 0 || voice >= len(s.SynthWrk.Voices) {
return
}
@ -119,7 +133,7 @@ func (bridgesynth *NativeSynth) Trigger(voice int, note byte) {
// Release is part of C.Synths' implementation of sointu.Synth interface
func (bridgesynth *NativeSynth) Release(voice int) {
s := (*C.Synth)(bridgesynth)
s := &bridgesynth.csynth
if voice < 0 || voice >= len(s.SynthWrk.Voices) {
return
}
@ -128,7 +142,7 @@ func (bridgesynth *NativeSynth) Release(voice int) {
// Update
func (bridgesynth *NativeSynth) Update(patch sointu.Patch, bpm int) error {
s := (*C.Synth)(bridgesynth)
s := &bridgesynth.csynth
if n := patch.NumDelayLines(); n > 128 {
return fmt.Errorf("native bridge has currently a hard limit of 128 delaylines; patch uses %v", n)
}