mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
feat(tracker): add panic button to quickly disable the sound & show when synth crashes
This commit is contained in:
parent
33bf5ebd49
commit
35d2ff6308
@ -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
|
||||||
|
@ -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)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user