diff --git a/cmd/sointu-play/main.go b/cmd/sointu-play/main.go index 5cb9db9..7118470 100644 --- a/cmd/sointu-play/main.go +++ b/cmd/sointu-play/main.go @@ -88,16 +88,7 @@ func main() { return fmt.Errorf("the song could not be parsed as .json (%v) or .yml (%v)", errJSON, errYaml) } } - synth, err := bridge.Synth(song.Patch) - if err != nil { - return fmt.Errorf("could not create synth based on the patch: %v", err) - } - if !*unreleased { - for i := 0; i < 32; i++ { - synth.Release(i) - } - } - buffer, _, err := sointu.Play(synth, song) // render the song to calculate its length + buffer, _, err := sointu.Play(bridge.BridgeService{}, song, !*unreleased) // render the song to calculate its length if err != nil { return fmt.Errorf("sointu.Play failed: %v", err) } diff --git a/synth.go b/synth.go index 8a88ad4..8578bee 100644 --- a/synth.go +++ b/synth.go @@ -52,15 +52,26 @@ func Render(synth Synth, buffer []float32) error { return nil } -// Play plays the Song using a given Synth, returning the stereo audio buffer -// and the sync buffer as a result (and possible errors). This is a bit -// illogical as the Song contains already the Patch; this could be probably -// refactored to just accept a SynthService and a Song. -func Play(synth Synth, song Song) ([]float32, []float32, error) { +// Play plays the Song using a given SynthService, returning the stereo audio +// buffer and the sync buffer as a result (and possible errors). Passing +// 'release' as true means that all the notes are released when the synth is +// created. The default behaviour during runtime rendering is to leave them +// playing, meaning that envelopes start attacking right away unless an explicit +// note release is put to every track. +func Play(synthService SynthService, song Song, release bool) ([]float32, []float32, error) { err := song.Validate() if err != nil { return nil, nil, err } + synth, err := synthService.Compile(song.Patch) + if err != nil { + return nil, nil, fmt.Errorf("sointu.Play failed: %v", err) + } + if release { + for i := 0; i < 32; i++ { + synth.Release(i) + } + } curVoices := make([]int, len(song.Score.Tracks)) for i := range curVoices { curVoices[i] = song.Score.FirstVoiceForTrack(i) diff --git a/tracker/gioui/files.go b/tracker/gioui/files.go index 2e9e9ff..3670757 100644 --- a/tracker/gioui/files.go +++ b/tracker/gioui/files.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package gioui @@ -116,15 +117,7 @@ func (t *Tracker) exportWav(filename string, pcm16 bool) { if extension == "" { filename = filename + ".wav" } - synth, err := t.synthService.Compile(t.Song().Patch) - if err != nil { - t.Alert.Update(fmt.Sprintf("Error compiling the patch during export: %v", err), Error, time.Second*3) - return - } - for i := 0; i < 32; i++ { - synth.Release(i) - } - data, _, err := sointu.Play(synth, t.Song()) // render the song to calculate its length + data, _, err := sointu.Play(t.synthService, t.Song(), true) // render the song to calculate its length if err != nil { t.Alert.Update(fmt.Sprintf("Error rendering the song during export: %v", err), Error, time.Second*3) return diff --git a/vm/compiler/bridge/bridge_test.go b/vm/compiler/bridge/bridge_test.go index 8fef881..6dedcf4 100644 --- a/vm/compiler/bridge/bridge_test.go +++ b/vm/compiler/bridge/bridge_test.go @@ -40,11 +40,7 @@ func TestOscillatSine(t *testing.T) { }}} tracks := []sointu.Track{{NumVoices: 1, Order: []int{0}, Patterns: []sointu.Pattern{{64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0, 0, 0}}}} song := sointu.Song{BPM: 100, RowsPerBeat: 4, Score: sointu.Score{RowsPerPattern: 16, Length: 1, Tracks: tracks}, Patch: patch} - synth, err := bridge.Synth(patch) - if err != nil { - t.Fatalf("Compiling patch failed: %v", err) - } - buffer, _, err := sointu.Play(synth, song) + buffer, _, err := sointu.Play(bridge.BridgeService{}, song, false) if err != nil { t.Fatalf("Render failed: %v", err) } @@ -99,11 +95,7 @@ func TestAllRegressionTests(t *testing.T) { if err != nil { t.Fatalf("could not parse the .yml file: %v", err) } - synth, err := bridge.Synth(song.Patch) - if err != nil { - t.Fatalf("Compiling patch failed: %v", err) - } - buffer, _, err := sointu.Play(synth, song) + buffer, _, err := sointu.Play(bridge.BridgeService{}, song, false) buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always. if err != nil { t.Fatalf("Play failed: %v", err) diff --git a/vm/interpreter_test.go b/vm/interpreter_test.go index 790cc38..fb97858 100644 --- a/vm/interpreter_test.go +++ b/vm/interpreter_test.go @@ -41,11 +41,7 @@ func TestAllRegressionTests(t *testing.T) { if err != nil { t.Fatalf("could not parse the .yml file: %v", err) } - synth, err := vm.Synth(song.Patch) - if err != nil { - t.Fatalf("Compiling patch failed: %v", err) - } - buffer, syncBuffer, err := sointu.Play(synth, song) + buffer, syncBuffer, err := sointu.Play(vm.SynthService{}, song, false) buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always. if err != nil { t.Fatalf("Play failed: %v", err)