mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-14 11:04:23 -04:00
refactor(compiler): remove EncodedSong and pass patterns & sequences separately
This commit is contained in:
@ -86,7 +86,7 @@ func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(`could not encode patch: %v`, err)
|
return nil, fmt.Errorf(`could not encode patch: %v`, err)
|
||||||
}
|
}
|
||||||
encodedSong, err := EncodeSong(song)
|
patterns, sequences, err := ConstructPatterns(song)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(`could not encode song: %v`, err)
|
return nil, fmt.Errorf(`could not encode song: %v`, err)
|
||||||
}
|
}
|
||||||
@ -104,9 +104,12 @@ func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
|||||||
X86Macros
|
X86Macros
|
||||||
SongMacros
|
SongMacros
|
||||||
*EncodedPatch
|
*EncodedPatch
|
||||||
EncodedSong *EncodedSong
|
Patterns [][]byte
|
||||||
Hold int
|
Sequences [][]byte
|
||||||
}{compilerMacros, featureSetMacros, x86Macros, songMacros, encodedPatch, encodedSong, 1}
|
PatternLength int
|
||||||
|
SequenceLength int
|
||||||
|
Hold int
|
||||||
|
}{compilerMacros, featureSetMacros, x86Macros, songMacros, encodedPatch, patterns, sequences, len(patterns[0]), len(sequences[0]), 1}
|
||||||
populatedTemplate, extension, err = com.compile(templateName, &data)
|
populatedTemplate, extension, err = com.compile(templateName, &data)
|
||||||
} else if com.Arch == "wasm" {
|
} else if com.Arch == "wasm" {
|
||||||
wasmMacros := *NewWasmMacros()
|
wasmMacros := *NewWasmMacros()
|
||||||
@ -116,9 +119,12 @@ func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
|||||||
WasmMacros
|
WasmMacros
|
||||||
SongMacros
|
SongMacros
|
||||||
*EncodedPatch
|
*EncodedPatch
|
||||||
EncodedSong *EncodedSong
|
Patterns [][]byte
|
||||||
Hold int
|
Sequences [][]byte
|
||||||
}{compilerMacros, featureSetMacros, wasmMacros, songMacros, encodedPatch, encodedSong, 1}
|
PatternLength int
|
||||||
|
SequenceLength int
|
||||||
|
Hold int
|
||||||
|
}{compilerMacros, featureSetMacros, wasmMacros, songMacros, encodedPatch, patterns, sequences, len(patterns[0]), len(sequences[0]), 1}
|
||||||
populatedTemplate, extension, err = com.compile(templateName, &data)
|
populatedTemplate, extension, err = com.compile(templateName, &data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
package compiler_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/vsariola/sointu"
|
|
||||||
"github.com/vsariola/sointu/compiler"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPatternReusing(t *testing.T) {
|
|
||||||
song := sointu.Song{
|
|
||||||
Tracks: []sointu.Track{{
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}, {
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
encodedSong, err := compiler.EncodeSong(&song)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("song encoding error: %v", err)
|
|
||||||
}
|
|
||||||
expected := compiler.EncodedSong{
|
|
||||||
Sequences: [][]byte{{0, 1}, {0, 2}},
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(*encodedSong, expected) {
|
|
||||||
t.Fatalf("got different EncodedSong than expected. got: %v expected: %v", *encodedSong, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnnecessaryHolds(t *testing.T) {
|
|
||||||
song := sointu.Song{
|
|
||||||
Tracks: []sointu.Track{{
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 1, 0, 0}, {72, 0, 1, 0, 1, 0, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}, {
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 1, 0}, {84, 0, 0, 0, 1, 1, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
encodedSong, err := compiler.EncodeSong(&song)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("song encoding error: %v", err)
|
|
||||||
}
|
|
||||||
expected := compiler.EncodedSong{
|
|
||||||
Sequences: [][]byte{{0, 1}, {0, 2}},
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(*encodedSong, expected) {
|
|
||||||
t.Fatalf("got different EncodedSong than expected. got: %v expected: %v", *encodedSong, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDontCares(t *testing.T) {
|
|
||||||
song := sointu.Song{
|
|
||||||
Tracks: []sointu.Track{{
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}, {
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 0, 0}},
|
|
||||||
Sequence: []byte{0, 1},
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
encodedSong, err := compiler.EncodeSong(&song)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("song encoding error: %v", err)
|
|
||||||
}
|
|
||||||
expected := compiler.EncodedSong{
|
|
||||||
Sequences: [][]byte{{0, 1}, {2, 1}},
|
|
||||||
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 0, 0, 0}, {64, 1, 1, 1, 1, 1, 1, 1}},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(*encodedSong, expected) {
|
|
||||||
t.Fatalf("got different EncodedSong than expected. got: %v expected: %v", *encodedSong, expected)
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,14 +7,6 @@ import (
|
|||||||
"github.com/vsariola/sointu"
|
"github.com/vsariola/sointu"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodedSong has a single global pattern table and all track sequences are
|
|
||||||
// indices to this table. This is in contrast with sointu. Song, which has one
|
|
||||||
// pattern table per track.
|
|
||||||
type EncodedSong struct {
|
|
||||||
Patterns [][]byte
|
|
||||||
Sequences [][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixPatternLength makes sure that every pattern is the same length. During
|
// fixPatternLength makes sure that every pattern is the same length. During
|
||||||
// composing. Patterns shorter than the given length are padded with 1 / "hold";
|
// composing. Patterns shorter than the given length are padded with 1 / "hold";
|
||||||
// patterns longer than the given length are cropped.
|
// patterns longer than the given length are cropped.
|
||||||
@ -174,19 +166,7 @@ func bytesToInts(array []byte) []int {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EncodedSong) PatternLength() int {
|
func ConstructPatterns(song *sointu.Song) ([][]byte, [][]byte, error) {
|
||||||
return len(e.Patterns[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EncodedSong) SequenceLength() int {
|
|
||||||
return len(e.Sequences[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EncodedSong) TotalRows() int {
|
|
||||||
return e.SequenceLength() * e.PatternLength()
|
|
||||||
}
|
|
||||||
|
|
||||||
func EncodeSong(song *sointu.Song) (*EncodedSong, error) {
|
|
||||||
patLength := song.PatternRows()
|
patLength := song.PatternRows()
|
||||||
sequences := make([][]byte, len(song.Tracks))
|
sequences := make([][]byte, len(song.Tracks))
|
||||||
var patterns [][]int
|
var patterns [][]int
|
||||||
@ -201,7 +181,7 @@ func EncodeSong(song *sointu.Song) (*EncodedSong, error) {
|
|||||||
var err error
|
var err error
|
||||||
sequences[i], err = intsToBytes(sequence)
|
sequences[i], err = intsToBytes(sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("the constructed pattern table would result in > 256 unique patterns; only 256 unique patterns are supported")
|
return nil, nil, errors.New("the constructed pattern table would result in > 256 unique patterns; only 256 unique patterns are supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bytePatterns := make([][]byte, len(patterns))
|
bytePatterns := make([][]byte, len(patterns))
|
||||||
@ -210,8 +190,8 @@ func EncodeSong(song *sointu.Song) (*EncodedSong, error) {
|
|||||||
replaceInts(pat, -1, 0) // replace don't cares with releases
|
replaceInts(pat, -1, 0) // replace don't cares with releases
|
||||||
bytePatterns[i], err = intsToBytes(pat)
|
bytePatterns[i], err = intsToBytes(pat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid note in pattern, notes should be 0 .. 255: %v", err)
|
return nil, nil, fmt.Errorf("invalid note in pattern, notes should be 0 .. 255: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &EncodedSong{Patterns: bytePatterns, Sequences: sequences}, nil
|
return bytePatterns, sequences, nil
|
||||||
}
|
}
|
81
compiler/patterns_test.go
Normal file
81
compiler/patterns_test.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package compiler_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vsariola/sointu"
|
||||||
|
"github.com/vsariola/sointu/compiler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPatternReusing(t *testing.T) {
|
||||||
|
song := sointu.Song{
|
||||||
|
Tracks: []sointu.Track{{
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}, {
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
patterns, sequences, err := compiler.ConstructPatterns(&song)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("erorr constructing patterns: %v", err)
|
||||||
|
}
|
||||||
|
expectedSequences := [][]byte{{0, 1}, {0, 2}}
|
||||||
|
expectedPatterns := [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
|
if !reflect.DeepEqual(patterns, expectedPatterns) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(sequences, expectedSequences) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnnecessaryHolds(t *testing.T) {
|
||||||
|
song := sointu.Song{
|
||||||
|
Tracks: []sointu.Track{{
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 0, 1, 0, 0}, {72, 0, 1, 0, 1, 0, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}, {
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 1, 0}, {84, 0, 0, 0, 1, 1, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
patterns, sequences, err := compiler.ConstructPatterns(&song)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("erorr constructing patterns: %v", err)
|
||||||
|
}
|
||||||
|
expectedSequences := [][]byte{{0, 1}, {0, 2}}
|
||||||
|
expectedPatterns := [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}, {84, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
|
if !reflect.DeepEqual(patterns, expectedPatterns) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(sequences, expectedSequences) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDontCares(t *testing.T) {
|
||||||
|
song := sointu.Song{
|
||||||
|
Tracks: []sointu.Track{{
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}, {
|
||||||
|
Patterns: [][]byte{{64, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 0, 0}},
|
||||||
|
Sequence: []byte{0, 1},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
patterns, sequences, err := compiler.ConstructPatterns(&song)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("erorr constructing patterns: %v", err)
|
||||||
|
}
|
||||||
|
expectedSequences := [][]byte{{0, 1}, {2, 1}}
|
||||||
|
expectedPatterns := [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 0, 0, 0}, {64, 1, 1, 1, 1, 1, 1, 1}}
|
||||||
|
if !reflect.DeepEqual(patterns, expectedPatterns) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(sequences, expectedSequences) {
|
||||||
|
t.Fatalf("got different patterns than expected. got: %v expected: %v", patterns, expectedPatterns)
|
||||||
|
}
|
||||||
|
}
|
@ -61,7 +61,7 @@ su_render_sampleloop: ; loop through every sample in the row
|
|||||||
jl su_render_sampleloop
|
jl su_render_sampleloop
|
||||||
{{.Pop .AX}} ; Stack: pushad ptr
|
{{.Pop .AX}} ; Stack: pushad ptr
|
||||||
inc eax
|
inc eax
|
||||||
cmp eax, {{.EncodedSong.TotalRows}}
|
cmp eax, {{mul .PatternLength .SequenceLength}}
|
||||||
jl su_render_rowloop
|
jl su_render_rowloop
|
||||||
; rewind the stack the entropy of multiple pop {{.AX}} is probably lower than add
|
; rewind the stack the entropy of multiple pop {{.AX}} is probably lower than add
|
||||||
{{- range slice .Stacklocs $prologsize}}
|
{{- range slice .Stacklocs $prologsize}}
|
||||||
@ -91,7 +91,7 @@ su_render_sampleloop: ; loop through every sample in the row
|
|||||||
{{- if ne .VoiceTrackBitmask 0}}
|
{{- if ne .VoiceTrackBitmask 0}}
|
||||||
; The more complicated implementation: one track can trigger multiple voices
|
; The more complicated implementation: one track can trigger multiple voices
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
mov ebx, {{.EncodedSong.PatternLength}} ; we could do xor ebx,ebx; mov bl,PATTERN_SIZE, but that would limit patternsize to 256...
|
mov ebx, {{.PatternLength}} ; we could do xor ebx,ebx; mov bl,PATTERN_SIZE, but that would limit patternsize to 256...
|
||||||
div ebx ; eax = current pattern, edx = current row in pattern
|
div ebx ; eax = current pattern, edx = current row in pattern
|
||||||
{{.Prepare "su_tracks"}}
|
{{.Prepare "su_tracks"}}
|
||||||
lea {{.SI}}, [{{.Use "su_tracks"}}+{{.AX}}] ; esi points to the pattern data for current track
|
lea {{.SI}}, [{{.Use "su_tracks"}}+{{.AX}}] ; esi points to the pattern data for current track
|
||||||
@ -100,7 +100,7 @@ su_render_sampleloop: ; loop through every sample in the row
|
|||||||
mov {{.BP}}, {{.PTRWORD}} su_synth_obj ; ebp points to the current_voiceno array
|
mov {{.BP}}, {{.PTRWORD}} su_synth_obj ; ebp points to the current_voiceno array
|
||||||
su_update_voices_trackloop:
|
su_update_voices_trackloop:
|
||||||
movzx eax, byte [{{.SI}}] ; eax = current pattern
|
movzx eax, byte [{{.SI}}] ; eax = current pattern
|
||||||
imul eax, {{.EncodedSong.PatternLength}} ; eax = offset to current pattern data
|
imul eax, {{.PatternLength}} ; eax = offset to current pattern data
|
||||||
{{- .Prepare "su_patterns" .AX | indent 4}}
|
{{- .Prepare "su_patterns" .AX | indent 4}}
|
||||||
movzx eax,byte [{{.Use "su_patterns" .AX}},{{.DX}}] ; eax = note
|
movzx eax,byte [{{.Use "su_patterns" .AX}},{{.DX}}] ; eax = note
|
||||||
push {{.DX}} ; Stack: ptrnrow
|
push {{.DX}} ; Stack: ptrnrow
|
||||||
@ -138,7 +138,7 @@ su_update_voices_skipreset:
|
|||||||
su_update_voices_nexttrack:
|
su_update_voices_nexttrack:
|
||||||
pop {{.BX}} ; ebx=first voice of next instrument, Stack: ptrnrow
|
pop {{.BX}} ; ebx=first voice of next instrument, Stack: ptrnrow
|
||||||
pop {{.DX}} ; edx=patrnrow
|
pop {{.DX}} ; edx=patrnrow
|
||||||
add {{.SI}}, {{.EncodedSong.SequenceLength}}
|
add {{.SI}}, {{.SequenceLength}}
|
||||||
inc {{.BP}}
|
inc {{.BP}}
|
||||||
{{- $addrname := len .Song.Tracks | printf "su_synth_obj + %v"}}
|
{{- $addrname := len .Song.Tracks | printf "su_synth_obj + %v"}}
|
||||||
{{- .Prepare $addrname | indent 8}}
|
{{- .Prepare $addrname | indent 8}}
|
||||||
@ -149,7 +149,7 @@ su_update_voices_nexttrack:
|
|||||||
; The simple implementation: each track triggers always the same voice
|
; The simple implementation: each track triggers always the same voice
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
mov bl, {{.EncodedSong.PatternLength}} ; rows per pattern
|
mov bl, {{.PatternLength}} ; rows per pattern
|
||||||
div ebx ; eax = current pattern, edx = current row in pattern
|
div ebx ; eax = current pattern, edx = current row in pattern
|
||||||
{{- .Prepare "su_tracks" | indent 4}}
|
{{- .Prepare "su_tracks" | indent 4}}
|
||||||
lea {{.SI}}, [{{.Use "su_tracks"}}+{{.AX}}]; esi points to the pattern data for current track
|
lea {{.SI}}, [{{.Use "su_tracks"}}+{{.AX}}]; esi points to the pattern data for current track
|
||||||
@ -157,7 +157,7 @@ su_update_voices_nexttrack:
|
|||||||
mov bl, {{len .Song.Tracks}} ; MAX_TRACKS is always <= 32 so this is ok
|
mov bl, {{len .Song.Tracks}} ; MAX_TRACKS is always <= 32 so this is ok
|
||||||
su_update_voices_trackloop:
|
su_update_voices_trackloop:
|
||||||
movzx eax, byte [{{.SI}}] ; eax = current pattern
|
movzx eax, byte [{{.SI}}] ; eax = current pattern
|
||||||
imul eax, {{.EncodedSong.PatternLength}} ; multiply by rows per pattern, eax = offset to current pattern data
|
imul eax, {{.PatternLength}} ; multiply by rows per pattern, eax = offset to current pattern data
|
||||||
{{- .Prepare "su_patterns" .AX | indent 8}}
|
{{- .Prepare "su_patterns" .AX | indent 8}}
|
||||||
movzx eax, byte [{{.Use "su_patterns" .AX}} + {{.DX}}] ; ecx = note
|
movzx eax, byte [{{.Use "su_patterns" .AX}} + {{.DX}}] ; ecx = note
|
||||||
cmp al, {{.Hold}} ; anything but hold causes action
|
cmp al, {{.Hold}} ; anything but hold causes action
|
||||||
@ -173,7 +173,7 @@ su_update_voices_retrigger:
|
|||||||
su_update_voices_nexttrack:
|
su_update_voices_nexttrack:
|
||||||
add {{.DI}}, su_voice.size
|
add {{.DI}}, su_voice.size
|
||||||
su_update_voices_skipadd:
|
su_update_voices_skipadd:
|
||||||
add {{.SI}}, {{.EncodedSong.SequenceLength}}
|
add {{.SI}}, {{.SequenceLength}}
|
||||||
dec ebx
|
dec ebx
|
||||||
jnz short su_update_voices_trackloop
|
jnz short su_update_voices_trackloop
|
||||||
ret
|
ret
|
||||||
@ -185,7 +185,7 @@ su_update_voices_skipadd:
|
|||||||
; Patterns
|
; Patterns
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
{{.Data "su_patterns"}}
|
{{.Data "su_patterns"}}
|
||||||
{{- range .EncodedSong.Patterns}}
|
{{- range .Patterns}}
|
||||||
db {{. | toStrings | join ","}}
|
db {{. | toStrings | join ","}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ su_update_voices_skipadd:
|
|||||||
; Tracks
|
; Tracks
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
{{.Data "su_tracks"}}
|
{{.Data "su_tracks"}}
|
||||||
{{- range .EncodedSong.Sequences}}
|
{{- range .Sequences}}
|
||||||
db {{. | toStrings | join ","}}
|
db {{. | toStrings | join ","}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/}}
|
*/}}
|
||||||
{{- .SetLabel "su_patterns"}}
|
{{- .SetLabel "su_patterns"}}
|
||||||
{{- $m := .}}
|
{{- $m := .}}
|
||||||
{{- range .EncodedSong.Patterns}}
|
{{- range .Patterns}}
|
||||||
{{- range .}}
|
{{- range .}}
|
||||||
{{- $.DataB .}}
|
{{- $.DataB .}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
@ -20,7 +20,7 @@
|
|||||||
*/}}
|
*/}}
|
||||||
{{- .SetLabel "su_tracks"}}
|
{{- .SetLabel "su_tracks"}}
|
||||||
{{- $m := .}}
|
{{- $m := .}}
|
||||||
{{- range .EncodedSong.Sequences}}
|
{{- range .Sequences}}
|
||||||
{{- range .}}
|
{{- range .}}
|
||||||
{{- $.DataB .}}
|
{{- $.DataB .}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
@ -111,7 +111,7 @@
|
|||||||
;; TODO: only export start and length with certain compiler options; in demo use, they can be hard coded
|
;; TODO: only export start and length with certain compiler options; in demo use, they can be hard coded
|
||||||
;; in the intro
|
;; in the intro
|
||||||
(global $outputStart (export "s") i32 (i32.const 8388608)) ;; TODO: do not hard code, layout memory somehow intelligently
|
(global $outputStart (export "s") i32 (i32.const 8388608)) ;; TODO: do not hard code, layout memory somehow intelligently
|
||||||
(global $outputLength (export "l") i32 (i32.const {{if .Output16Bit}}{{mul .EncodedSong.TotalRows .Song.SamplesPerRow 4}}{{else}}{{mul .EncodedSong.TotalRows .Song.SamplesPerRow 8}}{{end}}))
|
(global $outputLength (export "l") i32 (i32.const {{if .Output16Bit}}{{mul .PatternLength .SequenceLength .Song.SamplesPerRow 4}}{{else}}{{mul .PatternLength .SequenceLength .Song.SamplesPerRow 8}}{{end}}))
|
||||||
(global $output16bit (export "t") i32 (i32.const {{if .Output16Bit}}1{{else}}0{{end}}))
|
(global $output16bit (export "t") i32 (i32.const {{if .Output16Bit}}1{{else}}0{{end}}))
|
||||||
|
|
||||||
|
|
||||||
@ -183,17 +183,17 @@
|
|||||||
(br_if $sample_loop (i32.lt_s (global.get $sample) (i32.const {{.Song.SamplesPerRow}})))
|
(br_if $sample_loop (i32.lt_s (global.get $sample) (i32.const {{.Song.SamplesPerRow}})))
|
||||||
end
|
end
|
||||||
(global.set $row (i32.add (global.get $row) (i32.const 1)))
|
(global.set $row (i32.add (global.get $row) (i32.const 1)))
|
||||||
(br_if $row_loop (i32.lt_s (global.get $row) (i32.const {{.EncodedSong.PatternLength}})))
|
(br_if $row_loop (i32.lt_s (global.get $row) (i32.const {{.PatternLength}})))
|
||||||
end
|
end
|
||||||
(global.set $pattern (i32.add (global.get $pattern) (i32.const 1)))
|
(global.set $pattern (i32.add (global.get $pattern) (i32.const 1)))
|
||||||
(br_if $pattern_loop (i32.lt_s (global.get $pattern) (i32.const {{.EncodedSong.SequenceLength}})))
|
(br_if $pattern_loop (i32.lt_s (global.get $pattern) (i32.const {{.SequenceLength}})))
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
{{- if ne .VoiceTrackBitmask 0}}
|
{{- if ne .VoiceTrackBitmask 0}}
|
||||||
;; the complex implementation of update_voices: at least one track has more than one voice
|
;; the complex implementation of update_voices: at least one track has more than one voice
|
||||||
(func $su_update_voices (local $si i32) (local $di i32) (local $tracksRemaining i32) (local $note i32) (local $firstVoice i32) (local $nextTrackStartsAt i32) (local $numVoices i32) (local $voiceNo i32)
|
(func $su_update_voices (local $si i32) (local $di i32) (local $tracksRemaining i32) (local $note i32) (local $firstVoice i32) (local $nextTrackStartsAt i32) (local $numVoices i32) (local $voiceNo i32)
|
||||||
(local.set $tracksRemaining (i32.const {{len .EncodedSong.Sequences}}))
|
(local.set $tracksRemaining (i32.const {{len .Sequences}}))
|
||||||
(local.set $si (global.get $pattern))
|
(local.set $si (global.get $pattern))
|
||||||
(local.set $nextTrackStartsAt (i32.const 0))
|
(local.set $nextTrackStartsAt (i32.const 0))
|
||||||
loop $track_loop
|
loop $track_loop
|
||||||
@ -212,7 +212,7 @@
|
|||||||
br_if $voiceLoop
|
br_if $voiceLoop
|
||||||
end
|
end
|
||||||
(i32.load8_u offset={{index .Labels "su_tracks"}} (local.get $si))
|
(i32.load8_u offset={{index .Labels "su_tracks"}} (local.get $si))
|
||||||
(i32.mul (i32.const {{.EncodedSong.PatternLength}}))
|
(i32.mul (i32.const {{.PatternLength}}))
|
||||||
(i32.add (global.get $row))
|
(i32.add (global.get $row))
|
||||||
(i32.load8_u offset={{index .Labels "su_patterns"}})
|
(i32.load8_u offset={{index .Labels "su_patterns"}})
|
||||||
(local.tee $note)
|
(local.tee $note)
|
||||||
@ -246,7 +246,7 @@
|
|||||||
(i32.store8 offset=768 (local.get $tracksRemaining) (local.get $voiceNo))
|
(i32.store8 offset=768 (local.get $tracksRemaining) (local.get $voiceNo))
|
||||||
))
|
))
|
||||||
))
|
))
|
||||||
(local.set $si (i32.add (local.get $si) (i32.const {{.EncodedSong.SequenceLength}})))
|
(local.set $si (i32.add (local.get $si) (i32.const {{.SequenceLength}})))
|
||||||
(br_if $track_loop (local.tee $tracksRemaining (i32.sub (local.get $tracksRemaining) (i32.const 1))))
|
(br_if $track_loop (local.tee $tracksRemaining (i32.sub (local.get $tracksRemaining) (i32.const 1))))
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@ -254,12 +254,12 @@
|
|||||||
{{- else}}
|
{{- else}}
|
||||||
;; the simple implementation of update_voices: each track has exactly one voice
|
;; the simple implementation of update_voices: each track has exactly one voice
|
||||||
(func $su_update_voices (local $si i32) (local $di i32) (local $tracksRemaining i32) (local $note i32)
|
(func $su_update_voices (local $si i32) (local $di i32) (local $tracksRemaining i32) (local $note i32)
|
||||||
(local.set $tracksRemaining (i32.const {{len .EncodedSong.Sequences}}))
|
(local.set $tracksRemaining (i32.const {{len .Sequences}}))
|
||||||
(local.set $si (global.get $pattern))
|
(local.set $si (global.get $pattern))
|
||||||
(local.set $di (i32.const 4160))
|
(local.set $di (i32.const 4160))
|
||||||
loop $track_loop
|
loop $track_loop
|
||||||
(i32.load8_u offset={{index .Labels "su_tracks"}} (local.get $si))
|
(i32.load8_u offset={{index .Labels "su_tracks"}} (local.get $si))
|
||||||
(i32.mul (i32.const {{.EncodedSong.PatternLength}}))
|
(i32.mul (i32.const {{.PatternLength}}))
|
||||||
(i32.add (global.get $row))
|
(i32.add (global.get $row))
|
||||||
(i32.load8_u offset={{index .Labels "su_patterns"}})
|
(i32.load8_u offset={{index .Labels "su_patterns"}})
|
||||||
(local.tee $note)
|
(local.tee $note)
|
||||||
@ -271,7 +271,7 @@
|
|||||||
))
|
))
|
||||||
))
|
))
|
||||||
(local.set $di (i32.add (local.get $di) (i32.const 4096)))
|
(local.set $di (i32.add (local.get $di) (i32.const 4096)))
|
||||||
(local.set $si (i32.add (local.get $si) (i32.const {{.EncodedSong.SequenceLength}})))
|
(local.set $si (i32.add (local.get $si) (i32.const {{.SequenceLength}})))
|
||||||
(br_if $track_loop (local.tee $tracksRemaining (i32.sub (local.get $tracksRemaining) (i32.const 1))))
|
(br_if $track_loop (local.tee $tracksRemaining (i32.sub (local.get $tracksRemaining) (i32.const 1))))
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user