feat: keeping instruments and tracks linked & splitting them

Also includes a refactoring of the List: all methods that accepted
or returned a [from, to] range now return a Range, which is
non-inclusive i.e. [start,end).

Also the assignUnitIds was slightly refactored & a new function
called assignUnitIdsForPatch was added, to assign all unit IDs for
an patch at once.

Closes #157, #163.
This commit is contained in:
5684185+vsariola@users.noreply.github.com
2024-10-20 11:30:52 +03:00
parent 025f8832d9
commit 216cde2365
14 changed files with 675 additions and 284 deletions

View File

@ -27,6 +27,8 @@ type InstrumentEditor struct {
newInstrumentBtn *ActionClickable
enlargeBtn *BoolClickable
deleteInstrumentBtn *ActionClickable
linkInstrTrackBtn *BoolClickable
splitInstrumentBtn *ActionClickable
copyInstrumentBtn *TipClickable
saveInstrumentBtn *TipClickable
loadInstrumentBtn *TipClickable
@ -55,6 +57,9 @@ type InstrumentEditor struct {
deleteInstrumentHint string
muteHint, unmuteHint string
soloHint, unsoloHint string
linkDisabledHint string
linkEnabledHint string
splitInstrumentHint string
}
func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
@ -62,6 +67,8 @@ func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
newInstrumentBtn: NewActionClickable(model.AddInstrument()),
enlargeBtn: NewBoolClickable(model.InstrEnlarged().Bool()),
deleteInstrumentBtn: NewActionClickable(model.DeleteInstrument()),
linkInstrTrackBtn: NewBoolClickable(model.LinkInstrTrack().Bool()),
splitInstrumentBtn: NewActionClickable(model.SplitInstrument()),
copyInstrumentBtn: new(TipClickable),
saveInstrumentBtn: new(TipClickable),
loadInstrumentBtn: new(TipClickable),
@ -95,6 +102,9 @@ func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
ret.unmuteHint = makeHint("Unmute", " (%s)", "MuteToggle")
ret.soloHint = makeHint("Solo", " (%s)", "SoloToggle")
ret.unsoloHint = makeHint("Unsolo", " (%s)", "SoloToggle")
ret.linkDisabledHint = makeHint("Instrument-Track\nlinking disabled", "\n(%s)", "LinkInstrTrackToggle")
ret.linkEnabledHint = makeHint("Instrument-Track\nlinking enabled", "\n(%s)", "LinkInstrTrackToggle")
ret.splitInstrumentHint = makeHint("Split instrument", " (%s)", "SplitInstrument")
return ret
}
@ -116,6 +126,7 @@ func (ie *InstrumentEditor) childFocused(gtx C) bool {
func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
ie.wasFocused = ie.Focused() || ie.childFocused(gtx)
fullscreenBtnStyle := ToggleIcon(gtx, t.Theme, ie.enlargeBtn, icons.NavigationFullscreen, icons.NavigationFullscreenExit, ie.enlargeHint, ie.shrinkHint)
linkBtnStyle := ToggleIcon(gtx, t.Theme, ie.linkInstrTrackBtn, icons.NotificationSyncDisabled, icons.NotificationSync, ie.linkDisabledHint, ie.linkEnabledHint)
octave := func(gtx C) D {
in := layout.UniformInset(unit.Dp(1))
@ -141,6 +152,9 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
)
})
}),
layout.Rigid(func(gtx C) D {
return layout.E.Layout(gtx, linkBtnStyle.Layout)
}),
layout.Rigid(func(gtx C) D {
return layout.E.Layout(gtx, fullscreenBtnStyle.Layout)
}),
@ -173,6 +187,7 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
saveInstrumentBtnStyle := TipIcon(t.Theme, ie.saveInstrumentBtn, icons.ContentSave, "Save instrument")
loadInstrumentBtnStyle := TipIcon(t.Theme, ie.loadInstrumentBtn, icons.FileFolderOpen, "Load instrument")
deleteInstrumentBtnStyle := ActionIcon(gtx, t.Theme, ie.deleteInstrumentBtn, icons.ActionDelete, ie.deleteInstrumentHint)
splitInstrumentBtnStyle := ActionIcon(gtx, t.Theme, ie.splitInstrumentBtn, icons.CommunicationCallSplit, ie.splitInstrumentHint)
soloBtnStyle := ToggleIcon(gtx, t.Theme, ie.soloBtn, icons.SocialGroup, icons.SocialPerson, ie.soloHint, ie.unsoloHint)
muteBtnStyle := ToggleIcon(gtx, t.Theme, ie.muteBtn, icons.AVVolumeUp, icons.AVVolumeOff, ie.muteHint, ie.unmuteHint)
@ -209,6 +224,7 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
dims := numStyle.Layout(gtx)
return dims
}),
layout.Rigid(splitInstrumentBtnStyle.Layout),
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
layout.Rigid(commentExpandBtnStyle.Layout),
layout.Rigid(soloBtnStyle.Layout),

View File

@ -13,9 +13,12 @@
- {key: "O", shortcut: true, action: "OpenSong"}
- {key: "I", shortcut: true, shift: true, action: "DeleteInstrument"}
- {key: "I", shortcut: true, action: "AddInstrument"}
- {key: "I", shortcut: true, alt: true, action: "SplitInstrument"}
- {key: "T", shortcut: true, shift: true, action: "DeleteTrack"}
- {key: "T", shortcut: true, alt: true, action: "SplitTrack"}
- {key: "T", shortcut: true, action: "AddTrack"}
- {key: "E", shortcut: true, action: "InstrEnlargedToggle"}
- {key: "K", shortcut: true, action: "LinkInstrTrackToggle"}
- {key: "W", shortcut: true, action: "Quit"}
- {key: "Space", action: "PlayingToggleUnfollow"}
- {key: "Space", shift: true, action: "PlayingToggleFollow"}

View File

@ -199,6 +199,10 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
t.ExportFloat().Do()
case "ExportInt16":
t.ExportInt16().Do()
case "SplitTrack":
t.SplitTrack().Do()
case "SplitInstrument":
t.SplitInstrument().Do()
// Booleans
case "PanicToggle":
t.Panic().Bool().Toggle()
@ -212,6 +216,8 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
t.Playing().Bool().Toggle()
case "InstrEnlargedToggle":
t.InstrEnlarged().Bool().Toggle()
case "LinkInstrTrackToggle":
t.LinkInstrTrack().Bool().Toggle()
case "CommentExpandedToggle":
t.CommentExpanded().Bool().Toggle()
case "FollowToggle":

View File

@ -50,9 +50,11 @@ func init() {
}
type NoteEditor struct {
TrackVoices *NumberInput
NewTrackBtn *ActionClickable
DeleteTrackBtn *ActionClickable
TrackVoices *NumberInput
NewTrackBtn *ActionClickable
DeleteTrackBtn *ActionClickable
SplitTrackBtn *ActionClickable
AddSemitoneBtn *ActionClickable
SubtractSemitoneBtn *ActionClickable
AddOctaveBtn *ActionClickable
@ -67,6 +69,7 @@ type NoteEditor struct {
deleteTrackHint string
addTrackHint string
uniqueOffTip, uniqueOnTip string
splitTrackHint string
}
func NewNoteEditor(model *tracker.Model) *NoteEditor {
@ -74,6 +77,7 @@ func NewNoteEditor(model *tracker.Model) *NoteEditor {
TrackVoices: NewNumberInput(model.TrackVoices().Int()),
NewTrackBtn: NewActionClickable(model.AddTrack()),
DeleteTrackBtn: NewActionClickable(model.DeleteTrack()),
SplitTrackBtn: NewActionClickable(model.SplitTrack()),
AddSemitoneBtn: NewActionClickable(model.AddSemitone()),
SubtractSemitoneBtn: NewActionClickable(model.SubtractSemitone()),
AddOctaveBtn: NewActionClickable(model.AddOctave()),
@ -103,6 +107,7 @@ func NewNoteEditor(model *tracker.Model) *NoteEditor {
ret.addTrackHint = makeHint("Add\ntrack", "\n(%s)", "AddTrack")
ret.uniqueOnTip = makeHint("Duplicate non-unique patterns", " (%s)", "UniquePatternsToggle")
ret.uniqueOffTip = makeHint("Allow editing non-unique patterns", " (%s)", "UniquePatternsToggle")
ret.splitTrackHint = makeHint("Split track", " (%s)", "SplitTrack")
return ret
}
@ -148,6 +153,7 @@ func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
subtractOctaveBtnStyle := ActionButton(gtx, t.Theme, te.SubtractOctaveBtn, "-12")
noteOffBtnStyle := ActionButton(gtx, t.Theme, te.NoteOffBtn, "Note Off")
deleteTrackBtnStyle := ActionIcon(gtx, t.Theme, te.DeleteTrackBtn, icons.ActionDelete, te.deleteTrackHint)
splitTrackBtnStyle := ActionIcon(gtx, t.Theme, te.SplitTrackBtn, icons.CommunicationCallSplit, te.splitTrackHint)
newTrackBtnStyle := ActionIcon(gtx, t.Theme, te.NewTrackBtn, icons.ContentAdd, te.addTrackHint)
in := layout.UniformInset(unit.Dp(1))
voiceUpDown := func(gtx C) D {
@ -167,6 +173,7 @@ func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
layout.Rigid(uniqueBtnStyle.Layout),
layout.Rigid(Label(" Voices:", white, t.Theme.Shaper)),
layout.Rigid(voiceUpDown),
layout.Rigid(splitTrackBtnStyle.Layout),
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
layout.Rigid(deleteTrackBtnStyle.Layout),
layout.Rigid(newTrackBtnStyle.Layout))