mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 21:14:31 -04:00
feat: add ability to import 4klang patches and instruments
This commit is contained in:
parent
c06ac6ea5e
commit
248ba483c6
@ -33,7 +33,7 @@ type SampleOffset struct {
|
||||
LoopLength uint16
|
||||
}
|
||||
|
||||
func Encode(patch sointu.Patch, featureSet FeatureSet) (*BytePatch, error) {
|
||||
func Encode(patch sointu.Patch, featureSet FeatureSet, bpm int) (*BytePatch, error) {
|
||||
c := BytePatch{PolyphonyBitmask: polyphonyBitmask(patch), NumVoices: uint32(patch.NumVoices())}
|
||||
if c.NumVoices > 32 {
|
||||
return nil, fmt.Errorf("Sointu does not support more than 32 concurrent voices; patch uses %v", c.NumVoices)
|
||||
@ -42,7 +42,7 @@ func Encode(patch sointu.Patch, featureSet FeatureSet) (*BytePatch, error) {
|
||||
globalAddrs := map[int]uint16{}
|
||||
globalFixups := map[int]([]int){}
|
||||
voiceNo := 0
|
||||
delayTable, delayIndices := constructDelayTimeTable(patch)
|
||||
delayTable, delayIndices := constructDelayTimeTable(patch, bpm)
|
||||
c.DelayTimes = make([]uint16, len(delayTable))
|
||||
for i := range delayTable {
|
||||
c.DelayTimes[i] = uint16(delayTable[i])
|
||||
@ -171,7 +171,7 @@ func Encode(patch sointu.Patch, featureSet FeatureSet) (*BytePatch, error) {
|
||||
if count == 0 {
|
||||
continue // skip encoding delays without any delay lines
|
||||
}
|
||||
countTrack := count*2 - 1 + unit.Parameters["notetracking"] // 1 means no note tracking and 1 delay, 2 means notetracking with 1 delay, 3 means no note tracking and 2 delays etc.
|
||||
countTrack := count*2 - 1 + (unit.Parameters["notetracking"] & 1) // 1 means no note tracking and 1 delay, 2 means notetracking with 1 delay, 3 means no note tracking and 2 delays etc.
|
||||
values = append(values, byte(delayIndices[instrIndex][unitIndex]), byte(countTrack))
|
||||
}
|
||||
c.Commands = append(c.Commands, byte(opcode+unit.Parameters["stereo"]))
|
||||
|
@ -16,17 +16,17 @@ import (
|
||||
type BridgeService struct {
|
||||
}
|
||||
|
||||
func (s BridgeService) Compile(patch sointu.Patch) (sointu.Synth, error) {
|
||||
synth, err := Synth(patch)
|
||||
func (s BridgeService) Compile(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
synth, err := Synth(patch, bpm)
|
||||
return synth, err
|
||||
}
|
||||
|
||||
func Synth(patch sointu.Patch) (*C.Synth, error) {
|
||||
func Synth(patch sointu.Patch, bpm int) (*C.Synth, error) {
|
||||
s := new(C.Synth)
|
||||
if n := patch.NumDelayLines(); n > 64 {
|
||||
return nil, fmt.Errorf("native bridge has currently a hard limit of 64 delaylines; patch uses %v", n)
|
||||
}
|
||||
comPatch, err := vm.Encode(patch, vm.AllFeatures{})
|
||||
comPatch, err := vm.Encode(patch, vm.AllFeatures{}, bpm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error compiling patch: %v", err)
|
||||
}
|
||||
@ -109,11 +109,11 @@ func (s *C.Synth) Release(voice int) {
|
||||
}
|
||||
|
||||
// Update
|
||||
func (s *C.Synth) Update(patch sointu.Patch) error {
|
||||
func (s *C.Synth) Update(patch sointu.Patch, bpm int) error {
|
||||
if n := patch.NumDelayLines(); n > 64 {
|
||||
return fmt.Errorf("native bridge has currently a hard limit of 64 delaylines; patch uses %v", n)
|
||||
}
|
||||
comPatch, err := vm.Encode(patch, vm.AllFeatures{})
|
||||
comPatch, err := vm.Encode(patch, vm.AllFeatures{}, bpm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error compiling patch: %v", err)
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func TestRenderSamples(t *testing.T) {
|
||||
sointu.Unit{Type: "out", Parameters: map[string]int{"stereo": 1, "gain": 128}},
|
||||
}}}
|
||||
|
||||
synth, err := bridge.Synth(patch)
|
||||
synth, err := bridge.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
@ -130,7 +130,7 @@ func TestStackUnderflow(t *testing.T) {
|
||||
patch := sointu.Patch{sointu.Instrument{NumVoices: 1, Units: []sointu.Unit{
|
||||
sointu.Unit{Type: "pop", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := bridge.Synth(patch)
|
||||
synth, err := bridge.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
@ -146,7 +146,7 @@ func TestStackBalancing(t *testing.T) {
|
||||
sointu.Instrument{NumVoices: 1, Units: []sointu.Unit{
|
||||
sointu.Unit{Type: "push", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := bridge.Synth(patch)
|
||||
synth, err := bridge.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
@ -179,7 +179,7 @@ func TestStackOverflow(t *testing.T) {
|
||||
sointu.Unit{Type: "pop", Parameters: map[string]int{}},
|
||||
sointu.Unit{Type: "pop", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := bridge.Synth(patch)
|
||||
synth, err := bridge.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
@ -196,7 +196,7 @@ func TestDivideByZero(t *testing.T) {
|
||||
sointu.Unit{Type: "invgain", Parameters: map[string]int{"invgain": 0}},
|
||||
sointu.Unit{Type: "pop", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := bridge.Synth(patch)
|
||||
synth, err := bridge.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
||||
}
|
||||
features := vm.NecessaryFeaturesFor(song.Patch)
|
||||
retmap := map[string]string{}
|
||||
encodedPatch, err := vm.Encode(song.Patch, features)
|
||||
encodedPatch, err := vm.Encode(song.Patch, features, song.BPM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`could not encode patch: %v`, err)
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ func findSuperIntArray(arrays [][]int) ([]int, []int) {
|
||||
// Returns the delay time table and two dimensional array of integers where
|
||||
// element [i][u] is the index for instrument i / unit u in the delay table if
|
||||
// the unit was a delay unit. For non-delay untis, the element is just 0.
|
||||
func constructDelayTimeTable(patch sointu.Patch) ([]int, [][]int) {
|
||||
func constructDelayTimeTable(patch sointu.Patch, bpm int) ([]int, [][]int) {
|
||||
ind := make([][]int, len(patch))
|
||||
var subarrays [][]int
|
||||
// flatten the delay times into one array of arrays
|
||||
@ -119,11 +119,18 @@ func constructDelayTimeTable(patch sointu.Patch) ([]int, [][]int) {
|
||||
// should use delay times
|
||||
if unit.Type == "delay" {
|
||||
ind[i][j] = len(subarrays)
|
||||
end := unit.Parameters["count"]
|
||||
if unit.Parameters["stereo"] > 0 {
|
||||
end *= 2
|
||||
converted := make([]int, len(unit.VarArgs))
|
||||
copy(converted, unit.VarArgs)
|
||||
if unit.Parameters["notetracking"] == 2 {
|
||||
for i, t := range converted {
|
||||
delay := 44100 * 60 * t / 48 / bpm
|
||||
if delay > 65535 {
|
||||
delay = 65535
|
||||
}
|
||||
converted[i] = delay
|
||||
}
|
||||
}
|
||||
subarrays = append(subarrays, unit.VarArgs)
|
||||
subarrays = append(subarrays, converted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ const (
|
||||
envStateRelease
|
||||
)
|
||||
|
||||
func Synth(patch sointu.Patch) (sointu.Synth, error) {
|
||||
bytePatch, err := Encode(patch, AllFeatures{})
|
||||
func Synth(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
bytePatch, err := Encode(patch, AllFeatures{}, bpm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error compiling %v", err)
|
||||
}
|
||||
@ -73,8 +73,8 @@ func Synth(patch sointu.Patch) (sointu.Synth, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s SynthService) Compile(patch sointu.Patch) (sointu.Synth, error) {
|
||||
synth, err := Synth(patch)
|
||||
func (s SynthService) Compile(patch sointu.Patch, bpm int) (sointu.Synth, error) {
|
||||
synth, err := Synth(patch, bpm)
|
||||
return synth, err
|
||||
}
|
||||
|
||||
@ -87,8 +87,8 @@ func (s *Interpreter) Release(voiceIndex int) {
|
||||
s.synth.voices[voiceIndex].release = true
|
||||
}
|
||||
|
||||
func (s *Interpreter) Update(patch sointu.Patch) error {
|
||||
bytePatch, err := Encode(patch, AllFeatures{})
|
||||
func (s *Interpreter) Update(patch sointu.Patch, bpm int) error {
|
||||
bytePatch, err := Encode(patch, AllFeatures{}, bpm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error compiling %v", err)
|
||||
}
|
||||
@ -140,9 +140,11 @@ func (s *Interpreter) Render(buffer []float32, maxtime int) (samples int, time i
|
||||
stereo := channels == 2
|
||||
opNoStereo := (op & 0xFE) >> 1
|
||||
if opNoStereo == 0 {
|
||||
voices = voices[1:]
|
||||
units = voices[0].units[:]
|
||||
voicesRemaining--
|
||||
if voicesRemaining > 0 {
|
||||
voices = voices[1:]
|
||||
units = voices[0].units[:]
|
||||
}
|
||||
if mask := uint32(1) << uint32(voicesRemaining); s.bytePatch.PolyphonyBitmask&mask == mask {
|
||||
commands, values = commandInstr, valuesInstr
|
||||
} else {
|
||||
|
@ -76,7 +76,7 @@ func TestStackUnderflow(t *testing.T) {
|
||||
patch := sointu.Patch{sointu.Instrument{NumVoices: 1, Units: []sointu.Unit{
|
||||
sointu.Unit{Type: "pop", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := vm.Synth(patch)
|
||||
synth, err := vm.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
@ -92,7 +92,7 @@ func TestStackBalancing(t *testing.T) {
|
||||
sointu.Instrument{NumVoices: 1, Units: []sointu.Unit{
|
||||
sointu.Unit{Type: "push", Parameters: map[string]int{}},
|
||||
}}}
|
||||
synth, err := vm.Synth(patch)
|
||||
synth, err := vm.Synth(patch, 120)
|
||||
if err != nil {
|
||||
t.Fatalf("bridge compile error: %v", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user