mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 13:04:25 -04:00
feat: Delays and samples are now working through the bridge.
One should call bridge.Init() once during the initialization of the program to load the static sample table. On linux, bridge.Init() does nothing.
This commit is contained in:
@ -17,6 +17,8 @@ func ParseAsm(reader io.Reader) (*Song, error) {
|
||||
tracks := make([]Track, 0)
|
||||
var patch Patch
|
||||
var instr Instrument
|
||||
var delayTimes []int
|
||||
var sampleOffsets [][]int
|
||||
paramReg, err := regexp.Compile(`([a-zA-Z]\w*)\s*\(\s*([0-9]+)\s*\)`) // matches FOO(42), groups "FOO" and "42"
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -158,6 +160,20 @@ func ParseAsm(reader io.Reader) (*Song, error) {
|
||||
instr = Instrument{NumVoices: ints[0], Units: []Unit{}}
|
||||
case "END_INSTRUMENT":
|
||||
patch = append(patch, instr)
|
||||
case "DELTIME":
|
||||
ints, err := parseNumbers(rest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range ints {
|
||||
delayTimes = append(delayTimes, v)
|
||||
}
|
||||
case "SAMPLE_OFFSET":
|
||||
ints, err := parseNumbers(rest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sampleOffsets = append(sampleOffsets, ints)
|
||||
}
|
||||
if unittype, ok := unitNameMap[word]; ok {
|
||||
instrMatch := wordReg.FindStringSubmatch(rest)
|
||||
@ -214,6 +230,12 @@ func ParseAsm(reader io.Reader) (*Song, error) {
|
||||
} else {
|
||||
parameters["pop"] = 0
|
||||
}
|
||||
} else if unittype == "delay" {
|
||||
if flags["NOTETRACKING"] {
|
||||
parameters["notetracking"] = 1
|
||||
} else {
|
||||
parameters["notetracking"] = 0
|
||||
}
|
||||
}
|
||||
unit := Unit{Type: unittype, Stereo: stereo, Parameters: parameters}
|
||||
instr.Units = append(instr.Units, unit)
|
||||
@ -221,6 +243,26 @@ func ParseAsm(reader io.Reader) (*Song, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range patch {
|
||||
for u := range patch[i].Units {
|
||||
if patch[i].Units[u].Type == "delay" {
|
||||
s := patch[i].Units[u].Parameters["delay"]
|
||||
e := patch[i].Units[u].Parameters["count"]
|
||||
if patch[i].Units[u].Stereo {
|
||||
e *= 2 // stereo delays use 'count' number of delaytimes, but for both channels
|
||||
}
|
||||
patch[i].Units[u].DelayTimes = append(patch[i].Units[u].DelayTimes, delayTimes[s:e]...)
|
||||
delete(patch[i].Units[u].Parameters, "delay")
|
||||
delete(patch[i].Units[u].Parameters, "count")
|
||||
} else if patch[i].Units[u].Type == "oscillator" && patch[i].Units[u].Parameters["type"] == Sample {
|
||||
sampleno := patch[i].Units[u].Parameters["color"]
|
||||
patch[i].Units[u].Parameters["start"] = sampleOffsets[sampleno][0]
|
||||
patch[i].Units[u].Parameters["loopstart"] = sampleOffsets[sampleno][1]
|
||||
patch[i].Units[u].Parameters["looplength"] = sampleOffsets[sampleno][2]
|
||||
delete(patch[i].Units[u].Parameters, "color")
|
||||
}
|
||||
}
|
||||
}
|
||||
s := Song{BPM: bpm, Patterns: patterns, Tracks: tracks, Patch: patch, SongLength: -1}
|
||||
return &s, nil
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func TestAllAsmFiles(t *testing.T) {
|
||||
bridge.Init()
|
||||
_, myname, _, _ := runtime.Caller(0)
|
||||
files, err := filepath.Glob(path.Join(path.Dir(myname), "..", "tests", "*.asm"))
|
||||
if err != nil {
|
||||
@ -27,9 +28,6 @@ func TestAllAsmFiles(t *testing.T) {
|
||||
basename := filepath.Base(filename)
|
||||
testname := strings.TrimSuffix(basename, path.Ext(basename))
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
if strings.Contains(testname, "delay") || strings.Contains(testname, "sample") {
|
||||
return // delays and samples are not implemented yet in the bridge, so skip them for now
|
||||
}
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read the .asm file: %v", filename)
|
||||
|
@ -34,7 +34,7 @@ var opcodeTable = map[string]opTableEntry{
|
||||
"filter": opTableEntry{C.su_filter_id, []string{"frequency", "resonance"}},
|
||||
"clip": opTableEntry{C.su_clip_id, []string{}},
|
||||
"pan": opTableEntry{C.su_pan_id, []string{"panning"}},
|
||||
"delay": opTableEntry{C.su_delay_id, []string{"pregain", "dry", "feedback", "damp", "damp", "delay", "count"}},
|
||||
"delay": opTableEntry{C.su_delay_id, []string{"pregain", "dry", "feedback", "damp", "delaycount"}},
|
||||
"compressor": opTableEntry{C.su_compres_id, []string{"attack", "release", "invgain", "threshold", "ratio"}},
|
||||
"speed": opTableEntry{C.su_speed_id, []string{}},
|
||||
"out": opTableEntry{C.su_out_id, []string{"gain"}},
|
||||
@ -80,6 +80,9 @@ func (synth *C.Synth) Render(buffer []float32, maxtime int) (int, int, error) {
|
||||
}
|
||||
|
||||
func Synth(patch go4k.Patch) (*C.Synth, error) {
|
||||
s := new(C.Synth)
|
||||
sampleno := 0
|
||||
delaytimeno := 0
|
||||
totalVoices := 0
|
||||
commands := make([]byte, 0)
|
||||
values := make([]byte, 0)
|
||||
@ -99,13 +102,31 @@ func Synth(patch go4k.Patch) (*C.Synth, error) {
|
||||
}
|
||||
commands = append(commands, byte(opCode))
|
||||
for _, paramname := range val.parameterList {
|
||||
if pval, ok := unit.Parameters[paramname]; ok {
|
||||
if unit.Type == "delay" && paramname == "count" {
|
||||
pval = pval*2 - 1
|
||||
if val, ok := unit.Parameters["notetracking"]; ok && val == 1 {
|
||||
pval++
|
||||
}
|
||||
if unit.Type == "delay" && paramname == "delaycount" {
|
||||
if unit.Stereo && len(unit.DelayTimes)%2 != 0 {
|
||||
return nil, errors.New("Stereo delays should have even number of delaytimes")
|
||||
}
|
||||
values = append(values, byte(delaytimeno))
|
||||
for _, v := range unit.DelayTimes {
|
||||
s.DelayTimes[delaytimeno] = C.ushort(v)
|
||||
delaytimeno++
|
||||
}
|
||||
count := len(unit.DelayTimes)
|
||||
if unit.Stereo {
|
||||
count /= 2
|
||||
}
|
||||
count = count*2 - 1
|
||||
if unit.Parameters["notetracking"] == 1 {
|
||||
count++
|
||||
}
|
||||
values = append(values, byte(count))
|
||||
} else if unit.Type == "oscillator" && unit.Parameters["type"] == go4k.Sample && paramname == "color" {
|
||||
values = append(values, byte(sampleno))
|
||||
s.SampleOffsets[sampleno].Start = (C.uint)(unit.Parameters["start"])
|
||||
s.SampleOffsets[sampleno].LoopStart = (C.ushort)(unit.Parameters["loopstart"])
|
||||
s.SampleOffsets[sampleno].LoopLength = (C.ushort)(unit.Parameters["looplength"])
|
||||
sampleno++
|
||||
} else if pval, ok := unit.Parameters[paramname]; ok {
|
||||
values = append(values, byte(pval))
|
||||
} else {
|
||||
return nil, fmt.Errorf("Unit parameter undefined: %v (at instrument %v, unit %v)", paramname, insid, unitid)
|
||||
@ -178,7 +199,6 @@ func Synth(patch go4k.Patch) (*C.Synth, error) {
|
||||
if len(values) > 16384 { // TODO: 16384 could probably be pulled automatically from cgo
|
||||
return nil, errors.New("The patch would result in more than 16384 values")
|
||||
}
|
||||
s := new(C.Synth)
|
||||
for i := range commands {
|
||||
s.Commands[i] = (C.uchar)(commands[i])
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ const su_max_samples = SAMPLES_PER_ROW * TOTAL_ROWS
|
||||
func TestBridge(t *testing.T) {
|
||||
patch := []go4k.Instrument{
|
||||
go4k.Instrument{1, []go4k.Unit{
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 64, "decay": 64, "sustain": 64, "release": 80, "gain": 128}},
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 95, "decay": 64, "sustain": 64, "release": 80, "gain": 128}},
|
||||
go4k.Unit{"out", true, map[string]int{"gain": 128}},
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 64, "decay": 64, "sustain": 64, "release": 80, "gain": 128}, []int{}},
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 95, "decay": 64, "sustain": 64, "release": 80, "gain": 128}, []int{}},
|
||||
go4k.Unit{"out", true, map[string]int{"gain": 128}, []int{}},
|
||||
}}}
|
||||
synth, err := bridge.Synth(patch)
|
||||
if err != nil {
|
||||
|
6
go4k/bridge/init_nonwin.go
Normal file
6
go4k/bridge/init_nonwin.go
Normal file
@ -0,0 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package bridge
|
||||
|
||||
func Init() {
|
||||
}
|
12
go4k/bridge/init_win.go
Normal file
12
go4k/bridge/init_win.go
Normal file
@ -0,0 +1,12 @@
|
||||
// +build windows
|
||||
|
||||
package bridge
|
||||
|
||||
// #cgo CFLAGS: -I"${SRCDIR}/../../include/sointu"
|
||||
// #cgo LDFLAGS: "${SRCDIR}/../../build/libsointu.a"
|
||||
// #include <sointu.h>
|
||||
import "C"
|
||||
|
||||
func Init() {
|
||||
C.su_load_gmdls() // GM.DLS is an windows specific sound bank so samples work currently only on windows
|
||||
}
|
@ -10,6 +10,7 @@ type Unit struct {
|
||||
Type string
|
||||
Stereo bool
|
||||
Parameters map[string]int
|
||||
DelayTimes []int
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -2,12 +2,13 @@ package go4k_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/vsariola/sointu/go4k"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/vsariola/sointu/go4k"
|
||||
)
|
||||
|
||||
const expectedMarshaled = "{\"BPM\":100,\"Patterns\":[\"QABEACAAAABLAE4AAAAAAA==\"],\"Tracks\":[{\"NumVoices\":1,\"Sequence\":\"AA==\"}],\"SongLength\":0,\"Patch\":[{\"NumVoices\":1,\"Units\":[{\"Type\":\"envelope\",\"Stereo\":false,\"Parameters\":{\"attack\":32,\"decay\":32,\"gain\":128,\"release\":64,\"sustain\":64}},{\"Type\":\"oscillator\",\"Stereo\":false,\"Parameters\":{\"color\":96,\"detune\":64,\"flags\":64,\"gain\":128,\"phase\":0,\"shape\":64,\"transpose\":64}},{\"Type\":\"mulp\",\"Stereo\":false,\"Parameters\":{}},{\"Type\":\"envelope\",\"Stereo\":false,\"Parameters\":{\"attack\":32,\"decay\":32,\"gain\":128,\"release\":64,\"sustain\":64}},{\"Type\":\"oscillator\",\"Stereo\":false,\"Parameters\":{\"color\":64,\"detune\":64,\"flags\":64,\"gain\":128,\"phase\":64,\"shape\":96,\"transpose\":72}},{\"Type\":\"mulp\",\"Stereo\":false,\"Parameters\":{}},{\"Type\":\"out\",\"Stereo\":true,\"Parameters\":{\"gain\":128}}]}]}"
|
||||
const expectedMarshaled = "{\"BPM\":100,\"Patterns\":[\"QABEACAAAABLAE4AAAAAAA==\"],\"Tracks\":[{\"NumVoices\":1,\"Sequence\":\"AA==\"}],\"SongLength\":0,\"Patch\":[{\"NumVoices\":1,\"Units\":[{\"Type\":\"envelope\",\"Stereo\":false,\"Parameters\":{\"attack\":32,\"decay\":32,\"gain\":128,\"release\":64,\"sustain\":64},\"DelayTimes\":[]},{\"Type\":\"oscillator\",\"Stereo\":false,\"Parameters\":{\"color\":96,\"detune\":64,\"flags\":64,\"gain\":128,\"phase\":0,\"shape\":64,\"transpose\":64},\"DelayTimes\":[]},{\"Type\":\"mulp\",\"Stereo\":false,\"Parameters\":{},\"DelayTimes\":[]},{\"Type\":\"envelope\",\"Stereo\":false,\"Parameters\":{\"attack\":32,\"decay\":32,\"gain\":128,\"release\":64,\"sustain\":64},\"DelayTimes\":[]},{\"Type\":\"oscillator\",\"Stereo\":false,\"Parameters\":{\"color\":64,\"detune\":64,\"flags\":64,\"gain\":128,\"phase\":64,\"shape\":96,\"transpose\":72},\"DelayTimes\":[]},{\"Type\":\"mulp\",\"Stereo\":false,\"Parameters\":{},\"DelayTimes\":[]},{\"Type\":\"out\",\"Stereo\":true,\"Parameters\":{\"gain\":128},\"DelayTimes\":[]}]}]}"
|
||||
|
||||
var testSong = go4k.Song{
|
||||
BPM: 100,
|
||||
@ -18,13 +19,13 @@ var testSong = go4k.Song{
|
||||
SongLength: 0,
|
||||
Patch: go4k.Patch{
|
||||
go4k.Instrument{NumVoices: 1, Units: []go4k.Unit{
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "flags": 0x40}},
|
||||
{"mulp", false, map[string]int{}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "flags": 0x40}},
|
||||
{"mulp", false, map[string]int{}},
|
||||
{"out", true, map[string]int{"gain": 128}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "flags": 0x40}, []int{}},
|
||||
{"mulp", false, map[string]int{}, []int{}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "flags": 0x40}, []int{}},
|
||||
{"mulp", false, map[string]int{}, []int{}},
|
||||
{"out", true, map[string]int{"gain": 128}, []int{}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ const su_max_samples = SAMPLES_PER_ROW * TOTAL_ROWS
|
||||
// const bufsize = su_max_samples * 2
|
||||
|
||||
func TestPlayer(t *testing.T) {
|
||||
patch := go4k.Patch{go4k.Instrument{1, []go4k.Unit{
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
go4k.Unit{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "type": go4k.Sine, "lfo": 0, "unison": 0}},
|
||||
go4k.Unit{"mulp", false, map[string]int{}},
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
go4k.Unit{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "type": go4k.Sine, "lfo": 0, "unison": 0}},
|
||||
go4k.Unit{"mulp", false, map[string]int{}},
|
||||
go4k.Unit{"out", true, map[string]int{"gain": 128}},
|
||||
patch := []go4k.Instrument{go4k.Instrument{1, []go4k.Unit{
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
go4k.Unit{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "type": go4k.Sine, "lfo": 0, "unison": 0}, []int{}},
|
||||
go4k.Unit{"mulp", false, map[string]int{}, []int{}},
|
||||
go4k.Unit{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
go4k.Unit{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "type": go4k.Sine, "lfo": 0, "unison": 0}, []int{}},
|
||||
go4k.Unit{"mulp", false, map[string]int{}, []int{}},
|
||||
go4k.Unit{"out", true, map[string]int{"gain": 128}, []int{}},
|
||||
}}}
|
||||
patterns := [][]byte{{64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0, 0, 0}}
|
||||
tracks := []go4k.Track{go4k.Track{1, []byte{0}}}
|
||||
|
@ -15,13 +15,13 @@ var defaultSong = go4k.Song{
|
||||
SongLength: 0,
|
||||
Patch: go4k.Patch{
|
||||
go4k.Instrument{NumVoices: 2, Units: []go4k.Unit{
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "type": go4k.Sine}},
|
||||
{"mulp", false, map[string]int{}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
|
||||
{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "type": go4k.Sine}},
|
||||
{"mulp", false, map[string]int{}},
|
||||
{"out", true, map[string]int{"gain": 128}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "type": go4k.Sine}, []int{}},
|
||||
{"mulp", false, map[string]int{}, []int{}},
|
||||
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}, []int{}},
|
||||
{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "type": go4k.Sine}, []int{}},
|
||||
{"mulp", false, map[string]int{}, []int{}},
|
||||
{"out", true, map[string]int{"gain": 128}, []int{}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _SOINTU_H
|
||||
#define _SOINTU_H
|
||||
|
||||
#pragma pack(push,4) // this should be fine for both Go and assembly
|
||||
#pragma pack(push,1) // this should be fine for both Go and assembly
|
||||
typedef struct Unit {
|
||||
float State[8];
|
||||
float Ports[8];
|
||||
@ -30,9 +30,17 @@ typedef struct SynthWorkspace {
|
||||
struct Voice Voices[32];
|
||||
} SynthWorkspace;
|
||||
|
||||
typedef struct SampleOffset {
|
||||
unsigned int Start;
|
||||
unsigned short LoopStart;
|
||||
unsigned short LoopLength;
|
||||
} SampleOffset;
|
||||
|
||||
typedef struct Synth {
|
||||
struct SynthWorkspace SynthWrk;
|
||||
struct DelayWorkspace DelayWrks[64]; // let's keep this as 64 for now, so the delays take 16 meg. If that's too little or too much, we can change this in future.
|
||||
unsigned short DelayTimes[768];
|
||||
struct SampleOffset SampleOffsets[256];
|
||||
unsigned int RandSeed;
|
||||
unsigned int GlobalTick;
|
||||
unsigned char Commands[32 * 64];
|
||||
@ -52,9 +60,7 @@ typedef struct Synth {
|
||||
#define CALLCONV // the asm will use honor honor correct x64 ABI on all 64-bit platforms
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_GMDLS
|
||||
extern void CALLCONV su_load_gmdls(void);
|
||||
#endif
|
||||
void CALLCONV su_load_gmdls(void);
|
||||
|
||||
// int su_render(Synth* synth, float* buffer, int* samples, int* time):
|
||||
// Renders samples until 'samples' number of samples are reached or 'time' number of
|
||||
|
35
render.asm
35
render.asm
@ -70,6 +70,7 @@ USE_IN
|
||||
%define INCLUDE_SINE
|
||||
%define INCLUDE_PULSE
|
||||
%define INCLUDE_GATE
|
||||
%define INCLUDE_SAMPLES
|
||||
%define INCLUDE_UNISONS
|
||||
%define INCLUDE_POLYPHONY
|
||||
%define INCLUDE_MULTIVOICE_TRACKS
|
||||
@ -80,14 +81,26 @@ USE_IN
|
||||
%define INCLUDE_NEGBANDPASS
|
||||
%define INCLUDE_NEGHIGHPASS
|
||||
%define INCLUDE_GLOBAL_SEND
|
||||
%define INCLUDE_DELAY_NOTETRACKING
|
||||
%define INCLUDE_DELAY_FLOAT_TIME
|
||||
%define INCLUDE_GMDLS
|
||||
|
||||
%include "sointu/footer.inc"
|
||||
|
||||
section .text
|
||||
|
||||
struc su_sampleoff
|
||||
.start resd 1
|
||||
.loopstart resw 1
|
||||
.looplength resw 1
|
||||
.size:
|
||||
endstruc
|
||||
|
||||
struc su_synth
|
||||
.synthwrk resb su_synthworkspace.size
|
||||
.delaywrks resb su_delayline_wrk.size * 64
|
||||
.delaytimes resw 768
|
||||
.sampleoffs resb su_sampleoff.size * 256
|
||||
.randseed resd 1
|
||||
.globaltime resd 1
|
||||
.commands resb 32 * 64
|
||||
@ -125,6 +138,10 @@ EXPORT MANGLE_FUNC(su_render,16)
|
||||
push _SI ; push bufsize
|
||||
push _DX ; push bufptr
|
||||
push _CX ; this takes place of the voicetrack
|
||||
lea _AX, [_CX + su_synth.sampleoffs]
|
||||
push _AX
|
||||
lea _AX, [_CX + su_synth.delaytimes]
|
||||
push _AX
|
||||
mov eax, [_CX + su_synth.randseed]
|
||||
push _AX ; randseed
|
||||
mov eax, [_CX + su_synth.globaltime]
|
||||
@ -135,12 +152,12 @@ EXPORT MANGLE_FUNC(su_render,16)
|
||||
su_render_samples_loop:
|
||||
cmp eax, [_SP] ; if rowtick >= maxtime
|
||||
jge su_render_samples_time_finish ; goto finish
|
||||
mov ecx, [_SP + PTRSIZE*5] ; ecx = buffer length in samples
|
||||
cmp [_SP + PTRSIZE*6], ecx ; if samples >= maxsamples
|
||||
mov ecx, [_SP + PTRSIZE*7] ; ecx = buffer length in samples
|
||||
cmp [_SP + PTRSIZE*8], ecx ; if samples >= maxsamples
|
||||
jge su_render_samples_time_finish ; goto finish
|
||||
inc eax ; time++
|
||||
inc dword [_SP + PTRSIZE*6] ; samples++
|
||||
mov _CX, [_SP + PTRSIZE*3]
|
||||
inc dword [_SP + PTRSIZE*8] ; samples++
|
||||
mov _CX, [_SP + PTRSIZE*5]
|
||||
push _AX ; push rowtick
|
||||
mov eax, [_CX + su_synth.polyphony]
|
||||
push _AX ;polyphony
|
||||
@ -154,12 +171,12 @@ su_render_samples_loop:
|
||||
call MANGLE_FUNC(su_run_vm,0)
|
||||
pop _AX
|
||||
pop _AX
|
||||
mov _DI, [_SP + PTRSIZE*5] ; edi containts buffer ptr
|
||||
mov _CX, [_SP + PTRSIZE*4]
|
||||
mov _DI, [_SP + PTRSIZE*7] ; edi containts buffer ptr
|
||||
mov _CX, [_SP + PTRSIZE*6]
|
||||
lea _SI, [_CX + su_synth.synthwrk + su_synthworkspace.left]
|
||||
movsd ; copy left channel to output buffer
|
||||
movsd ; copy right channel to output buffer
|
||||
mov [_SP + PTRSIZE*5], _DI ; save back the updated ptr
|
||||
mov [_SP + PTRSIZE*7], _DI ; save back the updated ptr
|
||||
lea _DI, [_SI-8]
|
||||
xor eax, eax
|
||||
stosd ; clear left channel so the VM is ready to write them again
|
||||
@ -170,7 +187,9 @@ su_render_samples_loop:
|
||||
su_render_samples_time_finish:
|
||||
pop _CX
|
||||
pop _BX
|
||||
pop _DX
|
||||
pop _DX
|
||||
pop _CX ; discard delaytimes ptr
|
||||
pop _CX ; discard samplesoffs ptr
|
||||
pop _CX
|
||||
mov [_CX + su_synth.randseed], edx
|
||||
mov [_CX + su_synth.globaltime], ebx
|
||||
|
Reference in New Issue
Block a user