feat(tracker): add panic button to quickly disable the sound & show when synth crashes

This commit is contained in:
vsariola 2021-02-10 21:59:29 +02:00
parent 33bf5ebd49
commit 35d2ff6308
3 changed files with 46 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"math" "math"
"sync" "sync"
"sync/atomic"
"github.com/vsariola/sointu" "github.com/vsariola/sointu"
) )
@ -23,6 +24,7 @@ type Sequencer struct {
// that the synth is not changed when audio is being read // that the synth is not changed when audio is being read
mutex sync.Mutex mutex sync.Mutex
synth sointu.Synth synth sointu.Synth
validSynth int32
service sointu.SynthService service sointu.SynthService
// this iterator is a bit unconventional in the sense that it might return // this iterator is a bit unconventional in the sense that it might return
// hasNext false, but might still return hasNext true in future attempts if // hasNext false, but might still return hasNext true in future attempts if
@ -72,10 +74,10 @@ func (s *Sequencer) ReadAudio(buffer []float32) (int, error) {
if !gotRow { if !gotRow {
rowTimeRemaining = math.MaxInt32 rowTimeRemaining = math.MaxInt32
} }
if s.synth != nil { if s.Enabled() {
rendered, timeAdvanced, err := s.synth.Render(buffer[totalRendered*2:], rowTimeRemaining) rendered, timeAdvanced, err := s.synth.Render(buffer[totalRendered*2:], rowTimeRemaining)
if err != nil { if err != nil {
s.synth = nil s.Disable()
} }
totalRendered += rendered totalRendered += rendered
s.rowTime += timeAdvanced s.rowTime += timeAdvanced
@ -98,14 +100,26 @@ func (s *Sequencer) ReadAudio(buffer []float32) (int, error) {
// Updates the patch of the synth // Updates the patch of the synth
func (s *Sequencer) SetPatch(patch sointu.Patch) { func (s *Sequencer) SetPatch(patch sointu.Patch) {
s.mutex.Lock() s.mutex.Lock()
if s.synth != nil { var err error
s.synth.Update(patch) if s.Enabled() {
err = s.synth.Update(patch)
} else { } else {
s.synth, _ = s.service.Compile(patch) s.synth, err = s.service.Compile(patch)
}
if err == nil {
atomic.StoreInt32(&s.validSynth, 1)
} }
s.mutex.Unlock() s.mutex.Unlock()
} }
func (s *Sequencer) Enabled() bool {
return atomic.LoadInt32(&s.validSynth) == 1
}
func (s *Sequencer) Disable() {
atomic.StoreInt32(&s.validSynth, 0)
}
func (s *Sequencer) SetRowLength(rowLength int) { func (s *Sequencer) SetRowLength(rowLength int) {
s.mutex.Lock() s.mutex.Lock()
s.rowLength = rowLength s.rowLength = rowLength

View File

@ -17,7 +17,7 @@ import (
func (t *Tracker) layoutSongPanel(gtx C) D { func (t *Tracker) layoutSongPanel(gtx C) D {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(t.layoutSongButtons), layout.Rigid(t.layoutSongButtons),
layout.Flexed(1, t.layoutSongOptions), layout.Rigid(t.layoutSongOptions),
) )
} }
@ -100,6 +100,23 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
in := layout.UniformInset(unit.Dp(1)) in := layout.UniformInset(unit.Dp(1))
panicBtnStyle := material.Button(t.Theme, t.PanicBtn, "Panic")
if t.sequencer.Enabled() {
panicBtnStyle.Background = transparent
panicBtnStyle.Color = t.Theme.Palette.Fg
} else {
panicBtnStyle.Background = t.Theme.Palette.Fg
panicBtnStyle.Color = t.Theme.Palette.ContrastFg
}
for t.PanicBtn.Clicked() {
if t.sequencer.Enabled() {
t.sequencer.Disable()
} else {
t.sequencer.SetPatch(t.song.Patch)
}
}
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx C) D { layout.Rigid(func(gtx C) D {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
@ -158,5 +175,9 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
}), }),
) )
}), }),
layout.Rigid(func(gtx C) D {
gtx.Constraints.Min = image.Pt(0, 0)
return panicBtnStyle.Layout(gtx)
}),
) )
} }

View File

@ -60,6 +60,7 @@ type Tracker struct {
SongLength *NumberInput SongLength *NumberInput
SaveSongFileBtn *widget.Clickable SaveSongFileBtn *widget.Clickable
FileMenuBtn *widget.Clickable FileMenuBtn *widget.Clickable
PanicBtn *widget.Clickable
FileMenuVisible bool FileMenuVisible bool
ParameterSliders []*widget.Float ParameterSliders []*widget.Float
ParameterList *layout.List ParameterList *layout.List
@ -550,6 +551,7 @@ func New(audioContext sointu.AudioContext, synthService sointu.SynthService) *Tr
AddUnitBtn: new(widget.Clickable), AddUnitBtn: new(widget.Clickable),
DeleteUnitBtn: new(widget.Clickable), DeleteUnitBtn: new(widget.Clickable),
ClearUnitBtn: new(widget.Clickable), ClearUnitBtn: new(widget.Clickable),
PanicBtn: new(widget.Clickable),
UnitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}}, UnitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}},
setPlaying: make(chan bool), setPlaying: make(chan bool),
rowJump: make(chan int), rowJump: make(chan int),