refactor(sointu): Change the signature of Play to accept SynthService instead of Synth

This is more logical as every single use of Play started with compiling the patch of a song with a SynthService.
This commit is contained in:
vsariola 2021-08-30 22:22:04 +03:00
parent a9b90c4db8
commit a8f8911f03
5 changed files with 22 additions and 39 deletions

View File

@ -88,16 +88,7 @@ func main() {
return fmt.Errorf("the song could not be parsed as .json (%v) or .yml (%v)", errJSON, errYaml) return fmt.Errorf("the song could not be parsed as .json (%v) or .yml (%v)", errJSON, errYaml)
} }
} }
synth, err := bridge.Synth(song.Patch) buffer, _, err := sointu.Play(bridge.BridgeService{}, song, !*unreleased) // render the song to calculate its length
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
if err != nil { if err != nil {
return fmt.Errorf("sointu.Play failed: %v", err) return fmt.Errorf("sointu.Play failed: %v", err)
} }

View File

@ -52,15 +52,26 @@ func Render(synth Synth, buffer []float32) error {
return nil return nil
} }
// Play plays the Song using a given Synth, returning the stereo audio buffer // Play plays the Song using a given SynthService, returning the stereo audio
// and the sync buffer as a result (and possible errors). This is a bit // buffer and the sync buffer as a result (and possible errors). Passing
// illogical as the Song contains already the Patch; this could be probably // 'release' as true means that all the notes are released when the synth is
// refactored to just accept a SynthService and a Song. // created. The default behaviour during runtime rendering is to leave them
func Play(synth Synth, song Song) ([]float32, []float32, error) { // 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() err := song.Validate()
if err != nil { if err != nil {
return nil, nil, err 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)) curVoices := make([]int, len(song.Score.Tracks))
for i := range curVoices { for i := range curVoices {
curVoices[i] = song.Score.FirstVoiceForTrack(i) curVoices[i] = song.Score.FirstVoiceForTrack(i)

View File

@ -1,3 +1,4 @@
//go:build !js
// +build !js // +build !js
package gioui package gioui
@ -116,15 +117,7 @@ func (t *Tracker) exportWav(filename string, pcm16 bool) {
if extension == "" { if extension == "" {
filename = filename + ".wav" filename = filename + ".wav"
} }
synth, err := t.synthService.Compile(t.Song().Patch) 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 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
if err != nil { if err != nil {
t.Alert.Update(fmt.Sprintf("Error rendering the song during export: %v", err), Error, time.Second*3) t.Alert.Update(fmt.Sprintf("Error rendering the song during export: %v", err), Error, time.Second*3)
return return

View File

@ -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}}}} 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} song := sointu.Song{BPM: 100, RowsPerBeat: 4, Score: sointu.Score{RowsPerPattern: 16, Length: 1, Tracks: tracks}, Patch: patch}
synth, err := bridge.Synth(patch) buffer, _, err := sointu.Play(bridge.BridgeService{}, song, false)
if err != nil {
t.Fatalf("Compiling patch failed: %v", err)
}
buffer, _, err := sointu.Play(synth, song)
if err != nil { if err != nil {
t.Fatalf("Render failed: %v", err) t.Fatalf("Render failed: %v", err)
} }
@ -99,11 +95,7 @@ func TestAllRegressionTests(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("could not parse the .yml file: %v", err) t.Fatalf("could not parse the .yml file: %v", err)
} }
synth, err := bridge.Synth(song.Patch) buffer, _, err := sointu.Play(bridge.BridgeService{}, song, false)
if err != nil {
t.Fatalf("Compiling patch failed: %v", err)
}
buffer, _, err := sointu.Play(synth, song)
buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always. buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always.
if err != nil { if err != nil {
t.Fatalf("Play failed: %v", err) t.Fatalf("Play failed: %v", err)

View File

@ -41,11 +41,7 @@ func TestAllRegressionTests(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("could not parse the .yml file: %v", err) t.Fatalf("could not parse the .yml file: %v", err)
} }
synth, err := vm.Synth(song.Patch) buffer, syncBuffer, err := sointu.Play(vm.SynthService{}, song, false)
if err != nil {
t.Fatalf("Compiling patch failed: %v", err)
}
buffer, syncBuffer, err := sointu.Play(synth, song)
buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always. buffer = buffer[:song.Score.LengthInRows()*song.SamplesPerRow()*2] // extend to the nominal length always.
if err != nil { if err != nil {
t.Fatalf("Play failed: %v", err) t.Fatalf("Play failed: %v", err)