refactor(tracker): refactor IntData to IntValue, following Bool example

This commit is contained in:
5684185+vsariola@users.noreply.github.com
2025-05-26 14:50:09 +03:00
parent fb3a0da3ed
commit 74f37318d6
11 changed files with 186 additions and 189 deletions

View File

@ -215,37 +215,37 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
t.Solo().Toggle() t.Solo().Toggle()
// Integers // Integers
case "InstrumentVoicesAdd": case "InstrumentVoicesAdd":
t.Model.InstrumentVoices().Int().Add(1) t.Model.InstrumentVoices().Add(1)
case "InstrumentVoicesSubtract": case "InstrumentVoicesSubtract":
t.Model.InstrumentVoices().Int().Add(-1) t.Model.InstrumentVoices().Add(-1)
case "TrackVoicesAdd": case "TrackVoicesAdd":
t.TrackVoices().Int().Add(1) t.TrackVoices().Add(1)
case "TrackVoicesSubtract": case "TrackVoicesSubtract":
t.TrackVoices().Int().Add(-1) t.TrackVoices().Add(-1)
case "SongLengthAdd": case "SongLengthAdd":
t.SongLength().Int().Add(1) t.SongLength().Add(1)
case "SongLengthSubtract": case "SongLengthSubtract":
t.SongLength().Int().Add(-1) t.SongLength().Add(-1)
case "BPMAdd": case "BPMAdd":
t.BPM().Int().Add(1) t.BPM().Add(1)
case "BPMSubtract": case "BPMSubtract":
t.BPM().Int().Add(-1) t.BPM().Add(-1)
case "RowsPerPatternAdd": case "RowsPerPatternAdd":
t.RowsPerPattern().Int().Add(1) t.RowsPerPattern().Add(1)
case "RowsPerPatternSubtract": case "RowsPerPatternSubtract":
t.RowsPerPattern().Int().Add(-1) t.RowsPerPattern().Add(-1)
case "RowsPerBeatAdd": case "RowsPerBeatAdd":
t.RowsPerBeat().Int().Add(1) t.RowsPerBeat().Add(1)
case "RowsPerBeatSubtract": case "RowsPerBeatSubtract":
t.RowsPerBeat().Int().Add(-1) t.RowsPerBeat().Add(-1)
case "StepAdd": case "StepAdd":
t.Step().Int().Add(1) t.Step().Add(1)
case "StepSubtract": case "StepSubtract":
t.Step().Int().Add(-1) t.Step().Add(-1)
case "OctaveAdd": case "OctaveAdd":
t.Octave().Int().Add(1) t.Octave().Add(1)
case "OctaveSubtract": case "OctaveSubtract":
t.Octave().Int().Add(-1) t.Octave().Add(-1)
// Other miscellaneous // Other miscellaneous
case "Paste": case "Paste":
gtx.Execute(clipboard.ReadCmd{Tag: t}) gtx.Execute(clipboard.ReadCmd{Tag: t})

View File

@ -76,7 +76,7 @@ type NoteEditor struct {
func NewNoteEditor(model *tracker.Model) *NoteEditor { func NewNoteEditor(model *tracker.Model) *NoteEditor {
ret := &NoteEditor{ ret := &NoteEditor{
TrackVoices: NewNumberInput(model.TrackVoices().Int()), TrackVoices: NewNumberInput(model.TrackVoices()),
NewTrackBtn: NewActionClickable(model.AddTrack()), NewTrackBtn: NewActionClickable(model.AddTrack()),
DeleteTrackBtn: NewActionClickable(model.DeleteTrack()), DeleteTrackBtn: NewActionClickable(model.DeleteTrack()),
SplitTrackBtn: NewActionClickable(model.SplitTrack()), SplitTrackBtn: NewActionClickable(model.SplitTrack()),

View File

@ -84,7 +84,7 @@ func (s *NumericUpDown) Update(gtx layout.Context) {
case pointer.Drag: case pointer.Drag:
var deltaCoord float32 var deltaCoord float32
deltaCoord = e.Position.X - e.Position.Y - s.NumberInput.dragStartXY deltaCoord = e.Position.X - e.Position.Y - s.NumberInput.dragStartXY
s.NumberInput.Int.Set(s.NumberInput.dragStartValue + int(deltaCoord/pxPerStep+0.5)) s.NumberInput.Int.SetValue(s.NumberInput.dragStartValue + int(deltaCoord/pxPerStep+0.5))
} }
} }
} }

View File

@ -47,8 +47,8 @@ func NewOscilloscope(model *tracker.Model) *OscilloscopeState {
return &OscilloscopeState{ return &OscilloscopeState{
onceBtn: NewBoolClickable(model.SignalAnalyzer().Once()), onceBtn: NewBoolClickable(model.SignalAnalyzer().Once()),
wrapBtn: NewBoolClickable(model.SignalAnalyzer().Wrap()), wrapBtn: NewBoolClickable(model.SignalAnalyzer().Wrap()),
lengthInBeatsNumber: NewNumberInput(model.SignalAnalyzer().LengthInBeats().Int()), lengthInBeatsNumber: NewNumberInput(model.SignalAnalyzer().LengthInBeats()),
triggerChannelNumber: NewNumberInput(model.SignalAnalyzer().TriggerChannel().Int()), triggerChannelNumber: NewNumberInput(model.SignalAnalyzer().TriggerChannel()),
} }
} }

View File

@ -39,11 +39,11 @@ type SongPanel struct {
func NewSongPanel(model *tracker.Model) *SongPanel { func NewSongPanel(model *tracker.Model) *SongPanel {
ret := &SongPanel{ ret := &SongPanel{
BPM: NewNumberInput(model.BPM().Int()), BPM: NewNumberInput(model.BPM()),
RowsPerPattern: NewNumberInput(model.RowsPerPattern().Int()), RowsPerPattern: NewNumberInput(model.RowsPerPattern()),
RowsPerBeat: NewNumberInput(model.RowsPerBeat().Int()), RowsPerBeat: NewNumberInput(model.RowsPerBeat()),
Step: NewNumberInput(model.Step().Int()), Step: NewNumberInput(model.Step()),
SongLength: NewNumberInput(model.SongLength().Int()), SongLength: NewNumberInput(model.SongLength()),
Scope: NewOscilloscope(model), Scope: NewOscilloscope(model),
MenuBar: NewMenuBar(model), MenuBar: NewMenuBar(model),
PlayBar: NewPlayBar(model), PlayBar: NewPlayBar(model),
@ -61,7 +61,7 @@ func NewSongPanel(model *tracker.Model) *SongPanel {
func (s *SongPanel) Update(gtx C, t *Tracker) { func (s *SongPanel) Update(gtx C, t *Tracker) {
for s.WeightingTypeBtn.Clicked(gtx) { for s.WeightingTypeBtn.Clicked(gtx) {
t.Model.DetectorWeighting().Int().Set((t.DetectorWeighting().Value() + 1) % int(tracker.NumWeightingTypes)) t.Model.DetectorWeighting().SetValue((t.DetectorWeighting().Value() + 1) % int(tracker.NumWeightingTypes))
} }
for s.OversamplingBtn.Clicked(gtx) { for s.OversamplingBtn.Clicked(gtx) {
t.Model.Oversampling().SetValue(!t.Oversampling().Value()) t.Model.Oversampling().SetValue(!t.Oversampling().Value())

View File

@ -71,8 +71,8 @@ var ZoomFactors = []float32{.25, 1. / 3, .5, 2. / 3, .75, .8, 1, 1.1, 1.25, 1.5,
func NewTracker(model *tracker.Model) *Tracker { func NewTracker(model *tracker.Model) *Tracker {
t := &Tracker{ t := &Tracker{
OctaveNumberInput: NewNumberInput(model.Octave().Int()), OctaveNumberInput: NewNumberInput(model.Octave()),
InstrumentVoices: NewNumberInput(model.InstrumentVoices().Int()), InstrumentVoices: NewNumberInput(model.InstrumentVoices()),
TopHorizontalSplit: &Split{Ratio: -.5, MinSize1: 180, MinSize2: 180}, TopHorizontalSplit: &Split{Ratio: -.5, MinSize1: 180, MinSize2: 180},
BottomHorizontalSplit: &Split{Ratio: -.6, MinSize1: 180, MinSize2: 180}, BottomHorizontalSplit: &Split{Ratio: -.6, MinSize1: 180, MinSize2: 180},

View File

@ -208,22 +208,22 @@ func (pe *UnitEditor) command(e key.Event, t *Tracker) {
if sel == nil { if sel == nil {
return return
} }
i := (&tracker.Int{IntData: sel}) i := tracker.MakeInt(sel)
if e.Modifiers.Contain(key.ModShift) { if e.Modifiers.Contain(key.ModShift) {
i.Set(i.Value() - sel.LargeStep()) i.SetValue(i.Value() - sel.LargeStep())
} else { } else {
i.Set(i.Value() - 1) i.SetValue(i.Value() - 1)
} }
case key.NameRightArrow: case key.NameRightArrow:
sel := params.SelectedItem() sel := params.SelectedItem()
if sel == nil { if sel == nil {
return return
} }
i := (&tracker.Int{IntData: sel}) i := tracker.MakeInt(sel)
if e.Modifiers.Contain(key.ModShift) { if e.Modifiers.Contain(key.ModShift) {
i.Set(i.Value() + sel.LargeStep()) i.SetValue(i.Value() + sel.LargeStep())
} else { } else {
i.Set(i.Value() + 1) i.SetValue(i.Value() + 1)
} }
case key.NameEscape: case key.NameEscape:
t.InstrumentEditor.unitDragList.Focus() t.InstrumentEditor.unitDragList.Focus()
@ -286,7 +286,7 @@ func (p ParameterStyle) Layout(gtx C) D {
} }
if ev, ok := e.(pointer.Event); ok && ev.Kind == pointer.Scroll { if ev, ok := e.(pointer.Event); ok && ev.Kind == pointer.Scroll {
delta := math.Min(math.Max(float64(ev.Scroll.Y), -1), 1) delta := math.Min(math.Max(float64(ev.Scroll.Y), -1), 1)
tracker.Int{IntData: p.w.Parameter}.Add(-int(delta)) tracker.MakeInt(p.w.Parameter).Add(-int(delta))
} }
} }
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(200)) gtx.Constraints.Min.X = gtx.Dp(unit.Dp(200))
@ -306,7 +306,7 @@ func (p ParameterStyle) Layout(gtx C) D {
event.Op(gtx.Ops, &p.w.floatWidget) event.Op(gtx.Ops, &p.w.floatWidget)
} }
dims := sliderStyle.Layout(gtx) dims := sliderStyle.Layout(gtx)
tracker.Int{IntData: p.w.Parameter}.Set(int(p.w.floatWidget.Value*float32(ra.Max-ra.Min) + float32(ra.Min) + 0.5)) tracker.MakeInt(p.w.Parameter).SetValue(int(p.w.floatWidget.Value*float32(ra.Max-ra.Min) + float32(ra.Min) + 0.5))
return dims return dims
case tracker.BoolParameter: case tracker.BoolParameter:
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(60)) gtx.Constraints.Min.X = gtx.Dp(unit.Dp(60))
@ -318,9 +318,9 @@ func (p ParameterStyle) Layout(gtx C) D {
defer pointer.PassOp{}.Push(gtx.Ops).Pop() defer pointer.PassOp{}.Push(gtx.Ops).Pop()
dims := layout.Center.Layout(gtx, boolStyle.Layout) dims := layout.Center.Layout(gtx, boolStyle.Layout)
if p.w.boolWidget.Value { if p.w.boolWidget.Value {
tracker.Int{IntData: p.w.Parameter}.Set(ra.Max) tracker.MakeInt(p.w.Parameter).SetValue(ra.Max)
} else { } else {
tracker.Int{IntData: p.w.Parameter}.Set(ra.Min) tracker.MakeInt(p.w.Parameter).SetValue(ra.Min)
} }
return dims return dims
case tracker.IDParameter: case tracker.IDParameter:
@ -334,7 +334,7 @@ func (p ParameterStyle) Layout(gtx C) D {
instrItems[i].IconBytes = icons.NavigationChevronRight instrItems[i].IconBytes = icons.NavigationChevronRight
instrItems[i].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() { instrItems[i].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() {
if id, ok := p.tracker.Instruments().FirstID(i); ok { if id, ok := p.tracker.Instruments().FirstID(i); ok {
tracker.Int{IntData: p.w.Parameter}.Set(id) tracker.MakeInt(p.w.Parameter).SetValue(id)
} }
})) }))
} }
@ -351,7 +351,7 @@ func (p ParameterStyle) Layout(gtx C) D {
unitItems[j].Text = buildUnitLabel(j, unit) unitItems[j].Text = buildUnitLabel(j, unit)
unitItems[j].IconBytes = icons.NavigationChevronRight unitItems[j].IconBytes = icons.NavigationChevronRight
unitItems[j].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() { unitItems[j].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() {
tracker.Int{IntData: p.w.Parameter}.Set(id) tracker.MakeInt(p.w.Parameter).SetValue(id)
})) }))
} }
} }

View File

@ -5,19 +5,22 @@ import (
) )
type ( type (
// Int represents an integer value in the tracker model e.g. BPM, song
// length, etc. It is a wrapper around an IntValue interface that provides
// methods to manipulate the value, but Int guard that all changes are
// within the range of the underlying IntValue implementation and that
// SetValue is not called when the value is unchanged.
Int struct { Int struct {
IntData value IntValue
} }
IntData interface { IntValue interface {
Value() int Value() int
Range() intRange SetValue(int) bool // returns true if the value was changed
Range() IntRange
setValue(int)
change(kind string) func()
} }
intRange struct { IntRange struct {
Min, Max int Min, Max int
} }
@ -29,123 +32,124 @@ type (
RowsPerBeat Model RowsPerBeat Model
Step Model Step Model
Octave Model Octave Model
DetectorWeighting Model DetectorWeighting Model
) )
func MakeInt(value IntValue) Int {
return Int{value}
}
func (v Int) Add(delta int) (ok bool) { func (v Int) Add(delta int) (ok bool) {
return v.SetValue(v.Value() + delta)
}
func (v Int) SetValue(value int) (ok bool) {
r := v.Range() r := v.Range()
value := r.Clamp(v.Value() + delta) value = r.Clamp(value)
if value == v.Value() || value < r.Min || value > r.Max { if value == v.Value() || value < r.Min || value > r.Max {
return false return false
} }
defer v.change("Add")() return v.value.SetValue(value)
v.setValue(value)
return true
} }
func (v Int) Set(value int) (ok bool) { func (v Int) Range() IntRange {
r := v.Range() if v.value == nil {
value = v.Range().Clamp(value) return IntRange{0, 0}
if value == v.Value() || value < r.Min || value > r.Max {
return false
} }
defer v.change("Set")() return v.value.Range()
v.setValue(value)
return true
} }
func (r intRange) Clamp(value int) int { func (v Int) Value() int {
if v.value == nil {
return 0
}
return v.value.Value()
}
func (r IntRange) Clamp(value int) int {
return max(min(value, r.Max), r.Min) return max(min(value, r.Max), r.Min)
} }
// Model methods // Model methods
func (m *Model) InstrumentVoices() *InstrumentVoices { return (*InstrumentVoices)(m) } func (m *Model) BPM() Int { return MakeInt((*BPM)(m)) }
func (m *Model) TrackVoices() *TrackVoices { return (*TrackVoices)(m) } func (m *Model) InstrumentVoices() Int { return MakeInt((*InstrumentVoices)(m)) }
func (m *Model) SongLength() *SongLength { return (*SongLength)(m) } func (m *Model) TrackVoices() Int { return MakeInt((*TrackVoices)(m)) }
func (m *Model) BPM() *BPM { return (*BPM)(m) } func (m *Model) SongLength() Int { return MakeInt((*SongLength)(m)) }
func (m *Model) RowsPerPattern() *RowsPerPattern { return (*RowsPerPattern)(m) } func (m *Model) RowsPerPattern() Int { return MakeInt((*RowsPerPattern)(m)) }
func (m *Model) RowsPerBeat() *RowsPerBeat { return (*RowsPerBeat)(m) } func (m *Model) RowsPerBeat() Int { return MakeInt((*RowsPerBeat)(m)) }
func (m *Model) Step() *Step { return (*Step)(m) } func (m *Model) Step() Int { return MakeInt((*Step)(m)) }
func (m *Model) Octave() *Octave { return (*Octave)(m) } func (m *Model) Octave() Int { return MakeInt((*Octave)(m)) }
func (m *Model) DetectorWeighting() *DetectorWeighting { return (*DetectorWeighting)(m) } func (m *Model) DetectorWeighting() Int { return MakeInt((*DetectorWeighting)(m)) }
// BeatsPerMinuteInt // BeatsPerMinuteInt
func (v *BPM) Int() Int { return Int{v} }
func (v *BPM) Value() int { return v.d.Song.BPM } func (v *BPM) Value() int { return v.d.Song.BPM }
func (v *BPM) setValue(value int) { v.d.Song.BPM = value } func (v *BPM) SetValue(value int) bool {
func (v *BPM) Range() intRange { return intRange{1, 999} } defer (*Model)(v).change("BPMInt", SongChange, MinorChange)()
func (v *BPM) change(kind string) func() { v.d.Song.BPM = value
return (*Model)(v).change("BPMInt."+kind, SongChange, MinorChange) return true
} }
func (v *BPM) Range() IntRange { return IntRange{1, 999} }
// RowsPerPatternInt // RowsPerPatternInt
func (v *RowsPerPattern) Int() Int { return Int{v} }
func (v *RowsPerPattern) Value() int { return v.d.Song.Score.RowsPerPattern } func (v *RowsPerPattern) Value() int { return v.d.Song.Score.RowsPerPattern }
func (v *RowsPerPattern) setValue(value int) { v.d.Song.Score.RowsPerPattern = value } func (v *RowsPerPattern) SetValue(value int) bool {
func (v *RowsPerPattern) Range() intRange { return intRange{1, 256} } defer (*Model)(v).change("RowsPerPatternInt", SongChange, MinorChange)()
func (v *RowsPerPattern) change(kind string) func() { v.d.Song.Score.RowsPerPattern = value
return (*Model)(v).change("RowsPerPatternInt."+kind, SongChange, MinorChange) return true
} }
func (v *RowsPerPattern) Range() IntRange { return IntRange{1, 256} }
// SongLengthInt // SongLengthInt
func (v *SongLength) Int() Int { return Int{v} }
func (v *SongLength) Value() int { return v.d.Song.Score.Length } func (v *SongLength) Value() int { return v.d.Song.Score.Length }
func (v *SongLength) setValue(value int) { v.d.Song.Score.Length = value } func (v *SongLength) SetValue(value int) bool {
func (v *SongLength) Range() intRange { return intRange{1, math.MaxInt32} } defer (*Model)(v).change("SongLengthInt", SongChange, MinorChange)()
func (v *SongLength) change(kind string) func() { v.d.Song.Score.Length = value
return (*Model)(v).change("SongLengthInt."+kind, SongChange, MinorChange) return true
} }
func (v *SongLength) Range() IntRange { return IntRange{1, math.MaxInt32} }
// StepInt // StepInt
func (v *Step) Int() Int { return Int{v} }
func (v *Step) Value() int { return v.d.Step } func (v *Step) Value() int { return v.d.Step }
func (v *Step) setValue(value int) { v.d.Step = value } func (v *Step) SetValue(value int) bool {
func (v *Step) Range() intRange { return intRange{0, 8} } defer (*Model)(v).change("StepInt", NoChange, MinorChange)()
func (v *Step) change(kind string) func() { v.d.Step = value
return (*Model)(v).change("StepInt"+kind, NoChange, MinorChange) return true
} }
func (v *Step) Range() IntRange { return IntRange{0, 8} }
// OctaveInt // OctaveInt
func (v *Octave) Int() Int { return Int{v} }
func (v *Octave) Value() int { return v.d.Octave } func (v *Octave) Value() int { return v.d.Octave }
func (v *Octave) setValue(value int) { v.d.Octave = value } func (v *Octave) SetValue(value int) bool { v.d.Octave = value; return true }
func (v *Octave) Range() intRange { return intRange{0, 9} } func (v *Octave) Range() IntRange { return IntRange{0, 9} }
func (v *Octave) change(kind string) func() { return func() {} }
// RowsPerBeatInt // RowsPerBeatInt
func (v *RowsPerBeat) Int() Int { return Int{v} }
func (v *RowsPerBeat) Value() int { return v.d.Song.RowsPerBeat } func (v *RowsPerBeat) Value() int { return v.d.Song.RowsPerBeat }
func (v *RowsPerBeat) setValue(value int) { v.d.Song.RowsPerBeat = value } func (v *RowsPerBeat) SetValue(value int) bool {
func (v *RowsPerBeat) Range() intRange { return intRange{1, 32} } defer (*Model)(v).change("RowsPerBeatInt", SongChange, MinorChange)()
func (v *RowsPerBeat) change(kind string) func() { v.d.Song.RowsPerBeat = value
return (*Model)(v).change("RowsPerBeatInt."+kind, SongChange, MinorChange) return true
} }
func (v *RowsPerBeat) Range() IntRange { return IntRange{1, 32} }
// ModelLoudnessType // ModelLoudnessType
func (v *DetectorWeighting) Int() Int { return Int{v} }
func (v *DetectorWeighting) Value() int { return int(v.weightingType) } func (v *DetectorWeighting) Value() int { return int(v.weightingType) }
func (v *DetectorWeighting) setValue(value int) { func (v *DetectorWeighting) SetValue(value int) bool {
v.weightingType = WeightingType(value) v.weightingType = WeightingType(value)
TrySend(v.broker.ToDetector, MsgToDetector{HasWeightingType: true, WeightingType: WeightingType(value)}) TrySend(v.broker.ToDetector, MsgToDetector{HasWeightingType: true, WeightingType: WeightingType(value)})
return true
} }
func (v *DetectorWeighting) Range() intRange { return intRange{0, int(NumLoudnessTypes) - 1} } func (v *DetectorWeighting) Range() IntRange { return IntRange{0, int(NumLoudnessTypes) - 1} }
func (v *DetectorWeighting) change(kind string) func() { return func() {} }
// InstrumentVoicesInt // InstrumentVoicesInt
func (v *InstrumentVoices) Int() Int {
return Int{v}
}
func (v *InstrumentVoices) Value() int { func (v *InstrumentVoices) Value() int {
if v.d.InstrIndex < 0 || v.d.InstrIndex >= len(v.d.Song.Patch) { if v.d.InstrIndex < 0 || v.d.InstrIndex >= len(v.d.Song.Patch) {
return 1 return 1
@ -153,10 +157,11 @@ func (v *InstrumentVoices) Value() int {
return max(v.d.Song.Patch[v.d.InstrIndex].NumVoices, 1) return max(v.d.Song.Patch[v.d.InstrIndex].NumVoices, 1)
} }
func (m *InstrumentVoices) setValue(value int) { func (m *InstrumentVoices) SetValue(value int) bool {
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) { if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
return return false
} }
defer (*Model)(m).change("InstrumentVoices", SongChange, MinorChange)()
voiceIndex := m.d.Song.Patch.FirstVoiceForInstrument(m.d.InstrIndex) voiceIndex := m.d.Song.Patch.FirstVoiceForInstrument(m.d.InstrIndex)
voiceRange := Range{voiceIndex, voiceIndex + m.d.Song.Patch[m.d.InstrIndex].NumVoices} voiceRange := Range{voiceIndex, voiceIndex + m.d.Song.Patch[m.d.InstrIndex].NumVoices}
ranges := MakeSetLength(voiceRange, value) ranges := MakeSetLength(voiceRange, value)
@ -164,22 +169,15 @@ func (m *InstrumentVoices) setValue(value int) {
if !ok { if !ok {
m.changeCancel = true m.changeCancel = true
} }
return ok
} }
func (v *InstrumentVoices) Range() intRange { func (v *InstrumentVoices) Range() IntRange {
return intRange{1, (*Model)(v).remainingVoices(true, v.linkInstrTrack) + v.Value()} return IntRange{1, (*Model)(v).remainingVoices(true, v.linkInstrTrack) + v.Value()}
}
func (v *InstrumentVoices) change(kind string) func() {
return (*Model)(v).change("InstrumentVoices."+kind, SongChange, MinorChange)
} }
// TrackVoicesInt // TrackVoicesInt
func (v *TrackVoices) Int() Int {
return Int{v}
}
func (v *TrackVoices) Value() int { func (v *TrackVoices) Value() int {
t := v.d.Cursor.Track t := v.d.Cursor.Track
if t < 0 || t >= len(v.d.Song.Score.Tracks) { if t < 0 || t >= len(v.d.Song.Score.Tracks) {
@ -188,7 +186,8 @@ func (v *TrackVoices) Value() int {
return max(v.d.Song.Score.Tracks[t].NumVoices, 1) return max(v.d.Song.Score.Tracks[t].NumVoices, 1)
} }
func (m *TrackVoices) setValue(value int) { func (m *TrackVoices) SetValue(value int) bool {
defer (*Model)(m).change("TrackVoices", SongChange, MinorChange)()
voiceIndex := m.d.Song.Score.FirstVoiceForTrack(m.d.Cursor.Track) voiceIndex := m.d.Song.Score.FirstVoiceForTrack(m.d.Cursor.Track)
voiceRange := Range{voiceIndex, voiceIndex + m.d.Song.Score.Tracks[m.d.Cursor.Track].NumVoices} voiceRange := Range{voiceIndex, voiceIndex + m.d.Song.Score.Tracks[m.d.Cursor.Track].NumVoices}
ranges := MakeSetLength(voiceRange, value) ranges := MakeSetLength(voiceRange, value)
@ -196,16 +195,13 @@ func (m *TrackVoices) setValue(value int) {
if !ok { if !ok {
m.changeCancel = true m.changeCancel = true
} }
return ok
} }
func (v *TrackVoices) Range() intRange { func (v *TrackVoices) Range() IntRange {
t := v.d.Cursor.Track t := v.d.Cursor.Track
if t < 0 || t >= len(v.d.Song.Score.Tracks) { if t < 0 || t >= len(v.d.Song.Score.Tracks) {
return intRange{1, 1} return IntRange{1, 1}
} }
return intRange{1, (*Model)(v).remainingVoices(v.linkInstrTrack, true) + v.d.Song.Score.Tracks[t].NumVoices} return IntRange{1, (*Model)(v).remainingVoices(v.linkInstrTrack, true) + v.d.Song.Score.Tracks[t].NumVoices}
}
func (v *TrackVoices) change(kind string) func() {
return (*Model)(v).change("TrackVoices."+kind, SongChange, MinorChange)
} }

View File

@ -46,14 +46,14 @@ func (mwc *myWriteCloser) Close() error {
func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)) bool, seed int) { func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)) bool, seed int) {
// Ints // Ints
s.IterateInt("InstrumentVoices", s.model.InstrumentVoices().Int(), yield, seed) s.IterateInt("InstrumentVoices", s.model.InstrumentVoices(), yield, seed)
s.IterateInt("TrackVoices", s.model.TrackVoices().Int(), yield, seed) s.IterateInt("TrackVoices", s.model.TrackVoices(), yield, seed)
s.IterateInt("SongLength", s.model.SongLength().Int(), yield, seed) s.IterateInt("SongLength", s.model.SongLength(), yield, seed)
s.IterateInt("BPM", s.model.BPM().Int(), yield, seed) s.IterateInt("BPM", s.model.BPM(), yield, seed)
s.IterateInt("RowsPerPattern", s.model.RowsPerPattern().Int(), yield, seed) s.IterateInt("RowsPerPattern", s.model.RowsPerPattern(), yield, seed)
s.IterateInt("RowsPerBeat", s.model.RowsPerBeat().Int(), yield, seed) s.IterateInt("RowsPerBeat", s.model.RowsPerBeat(), yield, seed)
s.IterateInt("Step", s.model.Step().Int(), yield, seed) s.IterateInt("Step", s.model.Step(), yield, seed)
s.IterateInt("Octave", s.model.Octave().Int(), yield, seed) s.IterateInt("Octave", s.model.Octave(), yield, seed)
// Lists // Lists
s.IterateList("Instruments", s.model.Instruments().List(), yield, seed) s.IterateList("Instruments", s.model.Instruments().List(), yield, seed)
s.IterateList("Units", s.model.Units().List(), yield, seed) s.IterateList("Units", s.model.Units().List(), yield, seed)
@ -135,7 +135,7 @@ func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)
func (s *modelFuzzState) IterateInt(name string, i tracker.Int, yield func(string, func(p string, t *testing.T)) bool, seed int) { func (s *modelFuzzState) IterateInt(name string, i tracker.Int, yield func(string, func(p string, t *testing.T)) bool, seed int) {
r := i.Range() r := i.Range()
yield(name+".Set", func(p string, t *testing.T) { yield(name+".Set", func(p string, t *testing.T) {
i.Set(seed%(r.Max-r.Min+10) - 5 + r.Min) i.SetValue(seed%(r.Max-r.Min+10) - 5 + r.Min)
}) })
yield(name+".Value", func(p string, t *testing.T) { yield(name+".Value", func(p string, t *testing.T) {
if v := i.Value(); v < r.Min || v > r.Max { if v := i.Value(); v < r.Min || v > r.Max {

View File

@ -12,7 +12,7 @@ import (
type ( type (
Parameter interface { Parameter interface {
IntData IntValue
Type() ParameterType Type() ParameterType
Name() string Name() string
Hint() ParameterHint Hint() ParameterHint
@ -61,12 +61,6 @@ const (
func (m *Model) Params() *Params { return (*Params)(m) } func (m *Model) Params() *Params { return (*Params)(m) }
// parameter methods
func (p parameter) change(kind string) func() {
return p.m.change("Parameter."+kind, PatchChange, MinorChange)
}
// ParamList // ParamList
func (pl *Params) List() List { return List{pl} } func (pl *Params) List() List { return List{pl} }
@ -152,16 +146,20 @@ func (pl *Params) Iterate(yield ParamYieldFunc) {
// NamedParameter // NamedParameter
func (p NamedParameter) Name() string { return p.up.Name } func (p NamedParameter) Name() string { return p.up.Name }
func (p NamedParameter) Range() intRange { return intRange{Min: p.up.MinValue, Max: p.up.MaxValue} } func (p NamedParameter) Range() IntRange { return IntRange{Min: p.up.MinValue, Max: p.up.MaxValue} }
func (p NamedParameter) Value() int { return p.unit.Parameters[p.up.Name] } func (p NamedParameter) Value() int { return p.unit.Parameters[p.up.Name] }
func (p NamedParameter) setValue(value int) { p.unit.Parameters[p.up.Name] = value } func (p NamedParameter) SetValue(value int) bool {
defer p.m.change("Parameter"+p.Name(), PatchChange, MinorChange)()
p.unit.Parameters[p.up.Name] = value
return true
}
func (p NamedParameter) Reset() { func (p NamedParameter) Reset() {
v, ok := defaultUnits[p.unit.Type].Parameters[p.up.Name] v, ok := defaultUnits[p.unit.Type].Parameters[p.up.Name]
if !ok || p.unit.Parameters[p.up.Name] == v { if !ok || p.unit.Parameters[p.up.Name] == v {
return return
} }
defer p.parameter.change("Reset")() defer p.m.change("Reset"+p.Name(), PatchChange, MinorChange)()
p.unit.Parameters[p.up.Name] = v p.unit.Parameters[p.up.Name] = v
} }
@ -220,7 +218,7 @@ func (p NamedParameter) Unit() sointu.Unit {
func (p GmDlsEntryParameter) Name() string { return "sample" } func (p GmDlsEntryParameter) Name() string { return "sample" }
func (p GmDlsEntryParameter) Type() ParameterType { return IntegerParameter } func (p GmDlsEntryParameter) Type() ParameterType { return IntegerParameter }
func (p GmDlsEntryParameter) Range() intRange { return intRange{Min: 0, Max: len(GmDlsEntries)} } func (p GmDlsEntryParameter) Range() IntRange { return IntRange{Min: 0, Max: len(GmDlsEntries)} }
func (p GmDlsEntryParameter) LargeStep() int { return 16 } func (p GmDlsEntryParameter) LargeStep() int { return 16 }
func (p GmDlsEntryParameter) Reset() { return } func (p GmDlsEntryParameter) Reset() { return }
@ -232,15 +230,17 @@ func (p GmDlsEntryParameter) Value() int {
return 0 return 0
} }
func (p GmDlsEntryParameter) setValue(v int) { func (p GmDlsEntryParameter) SetValue(v int) bool {
if v < 1 || v > len(GmDlsEntries) { if v < 1 || v > len(GmDlsEntries) {
return return false
} }
defer p.m.change("GmDlsEntryParameter", PatchChange, MinorChange)()
e := GmDlsEntries[v-1] e := GmDlsEntries[v-1]
p.unit.Parameters["samplestart"] = e.Start p.unit.Parameters["samplestart"] = e.Start
p.unit.Parameters["loopstart"] = e.LoopStart p.unit.Parameters["loopstart"] = e.LoopStart
p.unit.Parameters["looplength"] = e.LoopLength p.unit.Parameters["looplength"] = e.LoopLength
p.unit.Parameters["transpose"] = 64 + e.SuggestedTranspose p.unit.Parameters["transpose"] = 64 + e.SuggestedTranspose
return true
} }
func (p GmDlsEntryParameter) Hint() ParameterHint { func (p GmDlsEntryParameter) Hint() ParameterHint {
@ -265,15 +265,17 @@ func (p DelayTimeParameter) Value() int {
return p.unit.VarArgs[p.index] return p.unit.VarArgs[p.index]
} }
func (p DelayTimeParameter) setValue(v int) { func (p DelayTimeParameter) SetValue(v int) bool {
defer p.m.change("DelayTimeParameter", PatchChange, MinorChange)()
p.unit.VarArgs[p.index] = v p.unit.VarArgs[p.index] = v
return true
} }
func (p DelayTimeParameter) Range() intRange { func (p DelayTimeParameter) Range() IntRange {
if p.unit.Parameters["notetracking"] == 2 { if p.unit.Parameters["notetracking"] == 2 {
return intRange{Min: 1, Max: 576} return IntRange{Min: 1, Max: 576}
} }
return intRange{Min: 1, Max: 65535} return IntRange{Min: 1, Max: 65535}
} }
func (p DelayTimeParameter) Hint() ParameterHint { func (p DelayTimeParameter) Hint() ParameterHint {
@ -325,7 +327,7 @@ func (p DelayTimeParameter) Hint() ParameterHint {
func (p DelayLinesParameter) Name() string { return "delaylines" } func (p DelayLinesParameter) Name() string { return "delaylines" }
func (p DelayLinesParameter) Type() ParameterType { return IntegerParameter } func (p DelayLinesParameter) Type() ParameterType { return IntegerParameter }
func (p DelayLinesParameter) Range() intRange { return intRange{Min: 1, Max: 32} } func (p DelayLinesParameter) Range() IntRange { return IntRange{Min: 1, Max: 32} }
func (p DelayLinesParameter) LargeStep() int { return 4 } func (p DelayLinesParameter) LargeStep() int { return 4 }
func (p DelayLinesParameter) Reset() { return } func (p DelayLinesParameter) Reset() { return }
@ -341,7 +343,8 @@ func (p DelayLinesParameter) Value() int {
return val return val
} }
func (p DelayLinesParameter) setValue(v int) { func (p DelayLinesParameter) SetValue(v int) bool {
defer p.m.change("DelayLinesParameter", PatchChange, MinorChange)()
targetLines := v targetLines := v
if p.unit.Parameters["stereo"] == 1 { if p.unit.Parameters["stereo"] == 1 {
targetLines *= 2 targetLines *= 2
@ -350,13 +353,14 @@ func (p DelayLinesParameter) setValue(v int) {
p.unit.VarArgs = append(p.unit.VarArgs, 1) p.unit.VarArgs = append(p.unit.VarArgs, 1)
} }
p.unit.VarArgs = p.unit.VarArgs[:targetLines] p.unit.VarArgs = p.unit.VarArgs[:targetLines]
return true
} }
// ReverbParameter // ReverbParameter
func (p ReverbParameter) Name() string { return "reverb" } func (p ReverbParameter) Name() string { return "reverb" }
func (p ReverbParameter) Type() ParameterType { return IntegerParameter } func (p ReverbParameter) Type() ParameterType { return IntegerParameter }
func (p ReverbParameter) Range() intRange { return intRange{Min: 0, Max: len(reverbs)} } func (p ReverbParameter) Range() IntRange { return IntRange{Min: 0, Max: len(reverbs)} }
func (p ReverbParameter) LargeStep() int { return 1 } func (p ReverbParameter) LargeStep() int { return 1 }
func (p ReverbParameter) Reset() { return } func (p ReverbParameter) Reset() { return }
@ -367,15 +371,17 @@ func (p ReverbParameter) Value() int {
return i + 1 return i + 1
} }
func (p ReverbParameter) setValue(v int) { func (p ReverbParameter) SetValue(v int) bool {
if v < 1 || v > len(reverbs) { if v < 1 || v > len(reverbs) {
return return false
} }
defer p.m.change("ReverbParameter", PatchChange, MinorChange)()
entry := reverbs[v-1] entry := reverbs[v-1]
p.unit.Parameters["stereo"] = entry.stereo p.unit.Parameters["stereo"] = entry.stereo
p.unit.Parameters["notetracking"] = 0 p.unit.Parameters["notetracking"] = 0
p.unit.VarArgs = make([]int, len(entry.varArgs)) p.unit.VarArgs = make([]int, len(entry.varArgs))
copy(p.unit.VarArgs, entry.varArgs) copy(p.unit.VarArgs, entry.varArgs)
return true
} }
func (p ReverbParameter) Hint() ParameterHint { func (p ReverbParameter) Hint() ParameterHint {

View File

@ -69,8 +69,8 @@ func (s *ScopeModel) Waveform() RingBuffer[[2]float32] { return s.waveForm }
func (s *ScopeModel) Once() Bool { return MakeEnabledBool((*SignalOnce)(s)) } func (s *ScopeModel) Once() Bool { return MakeEnabledBool((*SignalOnce)(s)) }
func (s *ScopeModel) Wrap() Bool { return MakeEnabledBool((*SignalWrap)(s)) } func (s *ScopeModel) Wrap() Bool { return MakeEnabledBool((*SignalWrap)(s)) }
func (s *ScopeModel) LengthInBeats() *SignalLengthInBeats { return (*SignalLengthInBeats)(s) } func (s *ScopeModel) LengthInBeats() Int { return MakeInt((*SignalLengthInBeats)(s)) }
func (s *ScopeModel) TriggerChannel() *TriggerChannel { return (*TriggerChannel)(s) } func (s *ScopeModel) TriggerChannel() Int { return MakeInt((*TriggerChannel)(s)) }
func (m *SignalOnce) Value() bool { return m.once } func (m *SignalOnce) Value() bool { return m.once }
func (m *SignalOnce) SetValue(val bool) { m.once = val } func (m *SignalOnce) SetValue(val bool) { m.once = val }
@ -78,22 +78,17 @@ func (m *SignalOnce) SetValue(val bool) { m.once = val }
func (m *SignalWrap) Value() bool { return m.wrap } func (m *SignalWrap) Value() bool { return m.wrap }
func (m *SignalWrap) SetValue(val bool) { m.wrap = val } func (m *SignalWrap) SetValue(val bool) { m.wrap = val }
func (m *SignalLengthInBeats) Int() Int { return Int{m} }
func (m *SignalLengthInBeats) Value() int { return m.lengthInBeats } func (m *SignalLengthInBeats) Value() int { return m.lengthInBeats }
func (m *SignalLengthInBeats) setValue(val int) { func (m *SignalLengthInBeats) SetValue(val int) bool {
m.lengthInBeats = val m.lengthInBeats = val
(*ScopeModel)(m).updateBufferLength() (*ScopeModel)(m).updateBufferLength()
return true
} }
func (m *SignalLengthInBeats) Enabled() bool { return true } func (m *SignalLengthInBeats) Range() IntRange { return IntRange{1, 999} }
func (m *SignalLengthInBeats) Range() intRange { return intRange{1, 999} }
func (m *SignalLengthInBeats) change(string) func() { return func() {} }
func (m *TriggerChannel) Int() Int { return Int{m} }
func (m *TriggerChannel) Value() int { return m.triggerChannel } func (m *TriggerChannel) Value() int { return m.triggerChannel }
func (m *TriggerChannel) setValue(val int) { m.triggerChannel = val } func (m *TriggerChannel) SetValue(val int) bool { m.triggerChannel = val; return true }
func (m *TriggerChannel) Enabled() bool { return true } func (m *TriggerChannel) Range() IntRange { return IntRange{0, vm.MAX_VOICES} }
func (m *TriggerChannel) Range() intRange { return intRange{0, vm.MAX_VOICES} }
func (m *TriggerChannel) change(string) func() { return func() {} }
func (s *ScopeModel) ProcessAudioBuffer(bufPtr *sointu.AudioBuffer) { func (s *ScopeModel) ProcessAudioBuffer(bufPtr *sointu.AudioBuffer) {
if s.wrap { if s.wrap {