feat(bridge): Return sensible error messages from bridge and test that patches that should fail actually do.

This commit is contained in:
Veikko Sariola 2020-12-05 21:55:49 +02:00
parent cd95c5ae37
commit 50ca02442d
2 changed files with 118 additions and 1 deletions

View File

@ -3,6 +3,7 @@ package bridge
import (
"errors"
"fmt"
"strings"
"github.com/vsariola/sointu/go4k"
)
@ -49,6 +50,27 @@ var opcodeTable = map[string]opTableEntry{
"in": opTableEntry{C.su_in_id, []string{"channel"}},
}
type RenderError struct {
errcode int
}
func (e *RenderError) Error() string {
var reasons []string
if e.errcode&0x40 != 0 {
reasons = append(reasons, "FPU stack over/underflow")
}
if e.errcode&0x04 != 0 {
reasons = append(reasons, "FPU divide by zero")
}
if e.errcode&0x01 != 0 {
reasons = append(reasons, "FPU invalid operation")
}
if e.errcode&0x3800 != 0 {
reasons = append(reasons, "FPU stack push/pops are not balanced")
}
return "RenderError: " + strings.Join(reasons, ", ")
}
// Render renders until the buffer is full or the modulated time is reached, whichever
// happens first.
// Parameters:
@ -74,7 +96,7 @@ func (synth *C.Synth) Render(buffer []float32, maxtime int) (int, int, error) {
time := C.int(maxtime)
errcode := int(C.su_render(synth, (*C.float)(&buffer[0]), &samples, &time))
if errcode > 0 {
return -1, -1, errors.New("RenderTime failed")
return int(samples), int(time), &RenderError{errcode: errcode}
}
return int(samples), int(time), nil
}

View File

@ -67,3 +67,98 @@ func TestBridge(t *testing.T) {
}
}
}
func TestStackUnderflow(t *testing.T) {
patch := go4k.Patch{
Instruments: []go4k.Instrument{
go4k.Instrument{1, []go4k.Unit{
go4k.Unit{"pop", map[string]int{}},
}}},
SampleOffsets: []go4k.SampleOffset{},
DelayTimes: []int{}}
synth, err := bridge.Synth(patch)
if err != nil {
t.Fatalf("bridge compile error: %v", err)
}
buffer := make([]float32, 2)
err = go4k.Render(synth, buffer)
if err == nil {
t.Fatalf("rendering should have failed due to stack underflow")
}
}
func TestStackBalancing(t *testing.T) {
patch := go4k.Patch{
Instruments: []go4k.Instrument{
go4k.Instrument{1, []go4k.Unit{
go4k.Unit{"push", map[string]int{}},
}}},
SampleOffsets: []go4k.SampleOffset{},
DelayTimes: []int{}}
synth, err := bridge.Synth(patch)
if err != nil {
t.Fatalf("bridge compile error: %v", err)
}
buffer := make([]float32, 2)
err = go4k.Render(synth, buffer)
if err == nil {
t.Fatalf("rendering should have failed due to unbalanced stack push/pop")
}
}
func TestStackOverflow(t *testing.T) {
patch := go4k.Patch{
Instruments: []go4k.Instrument{
go4k.Instrument{1, []go4k.Unit{
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
go4k.Unit{"pop", map[string]int{}},
}}},
SampleOffsets: []go4k.SampleOffset{},
DelayTimes: []int{}}
synth, err := bridge.Synth(patch)
if err != nil {
t.Fatalf("bridge compile error: %v", err)
}
buffer := make([]float32, 2)
err = go4k.Render(synth, buffer)
if err == nil {
t.Fatalf("rendering should have failed due to stack overflow, despite balanced push/pops")
}
}
func TestDivideByZero(t *testing.T) {
patch := go4k.Patch{
Instruments: []go4k.Instrument{
go4k.Instrument{1, []go4k.Unit{
go4k.Unit{"loadval", map[string]int{"value": 128}},
go4k.Unit{"invgain", map[string]int{"invgain": 0}},
go4k.Unit{"pop", map[string]int{}},
}}},
SampleOffsets: []go4k.SampleOffset{},
DelayTimes: []int{}}
synth, err := bridge.Synth(patch)
if err != nil {
t.Fatalf("bridge compile error: %v", err)
}
buffer := make([]float32, 2)
err = go4k.Render(synth, buffer)
if err == nil {
t.Fatalf("rendering should have failed due to divide by zero")
}
}