feat(tracker): add ability to loop part of song during playback

Closes #128.
This commit is contained in:
5684185+vsariola@users.noreply.github.com
2024-02-20 19:10:15 +02:00
parent aa7a2e56fa
commit dc12f58082
10 changed files with 65 additions and 4 deletions

View File

@ -69,6 +69,11 @@ func (t *Tracker) KeyEvent(e key.Event, o *op.Ops) {
t.Model.UnitDisabled().Bool().Toggle()
return
}
case "L":
if e.Modifiers.Contain(key.ModShortcut) {
t.Model.LoopToggle().Bool().Toggle()
return
}
case "N":
if e.Modifiers.Contain(key.ModShortcut) {
t.NewSong().Do()

View File

@ -202,9 +202,13 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
pat := j / rpp
row := j % rpp
w := pxPatMarkWidth + pxRowMarkWidth
paint.ColorOp{Color: rowMarkerPatternTextColor}.Add(gtx.Ops)
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
if row == 0 {
color := rowMarkerPatternTextColor
if l := t.Loop(); pat >= l.Start && pat < l.Start+l.Length {
color = loopMarkerColor
}
paint.ColorOp{Color: color}.Add(gtx.Ops)
widget.Label{}.Layout(gtx, t.Theme.Shaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", pat)), op.CallOp{})
}
defer op.Offset(image.Pt(pxPatMarkWidth, 0)).Push(gtx.Ops).Pop()

View File

@ -81,11 +81,15 @@ func (oe *OrderEditor) Layout(gtx C, t *Tracker) D {
}
rowTitle := func(gtx C, j int) D {
w := gtx.Dp(unit.Dp(30))
if playPos := t.PlayPosition(); t.SongPanel.PlayingBtn.Bool.Value() && j == playPos.OrderRow {
paint.FillShape(gtx.Ops, patternPlayColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, patternCellHeight)}.Op())
}
w := gtx.Dp(unit.Dp(30))
paint.ColorOp{Color: rowMarkerPatternTextColor}.Add(gtx.Ops)
color := rowMarkerPatternTextColor
if l := t.Loop(); j >= l.Start && j < l.Start+l.Length {
color = loopMarkerColor
}
paint.ColorOp{Color: color}.Add(gtx.Ops)
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
widget.Label{}.Layout(gtx, t.Theme.Shaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)), op.CallOp{})
return D{Size: image.Pt(w, patternCellHeight)}

View File

@ -26,6 +26,7 @@ type SongPanel struct {
RecordBtn *BoolClickable
NoteTracking *BoolClickable
PanicBtn *BoolClickable
LoopBtn *BoolClickable
// File menu items
fileMenuItems []MenuItem
@ -50,6 +51,7 @@ func NewSongPanel(model *tracker.Model) *SongPanel {
Step: NewNumberInput(model.Step().Int()),
SongLength: NewNumberInput(model.SongLength().Int()),
PanicBtn: NewBoolClickable(model.Panic().Bool()),
LoopBtn: NewBoolClickable(model.LoopToggle().Bool()),
RecordBtn: NewBoolClickable(model.IsRecording().Bool()),
NoteTracking: NewBoolClickable(model.NoteTracking().Bool()),
PlayingBtn: NewBoolClickable(model.Playing().Bool()),
@ -106,6 +108,7 @@ func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
playBtnStyle := ToggleIcon(tr.Theme, t.PlayingBtn, icons.AVPlayArrow, icons.AVStop, "Play (F6 / Space)", "Stop (F6 / Space)")
recordBtnStyle := ToggleIcon(tr.Theme, t.RecordBtn, icons.AVFiberManualRecord, icons.AVFiberSmartRecord, "Record (F7)", "Stop (F7)")
noteTrackBtnStyle := ToggleIcon(tr.Theme, t.NoteTracking, icons.ActionSpeakerNotesOff, icons.ActionSpeakerNotes, "Follow\nOff\n(F8)", "Follow\nOn\n(F8)")
loopBtnStyle := ToggleIcon(tr.Theme, t.LoopBtn, icons.NavigationArrowForward, icons.AVLoop, "Loop\nOff\n(Ctrl+L)", "Loop\nOn\n(Ctrl+L)")
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx C) D {
@ -174,6 +177,7 @@ func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
layout.Rigid(playBtnStyle.Layout),
layout.Rigid(recordBtnStyle.Layout),
layout.Rigid(noteTrackBtnStyle.Layout),
layout.Rigid(loopBtnStyle.Layout),
)
}),
layout.Rigid(panicBtnStyle.Layout),

View File

@ -44,6 +44,7 @@ var twoBeatHighlight = color.NRGBA{R: 31, G: 51, B: 53, A: 255}
var patternPlayColor = color.NRGBA{R: 55, G: 55, B: 61, A: 255}
var patternTextColor = primaryColor
var patternCellColor = color.NRGBA{R: 255, G: 255, B: 255, A: 3}
var loopMarkerColor = color.NRGBA{R: 252, G: 186, B: 3, A: 255}
var instrumentHoverColor = color.NRGBA{R: 30, G: 31, B: 38, A: 255}
var instrumentNameColor = color.NRGBA{R: 255, G: 255, B: 255, A: 255}

View File

@ -72,7 +72,7 @@ func NewTracker(model *tracker.Model) *Tracker {
OctaveNumberInput: NewNumberInput(model.Octave().Int()),
InstrumentVoices: NewNumberInput(model.InstrumentVoices().Int()),
TopHorizontalSplit: &Split{Ratio: -.6},
TopHorizontalSplit: &Split{Ratio: -.5},
BottomHorizontalSplit: &Split{Ratio: -.6},
VerticalSplit: &Split{Axis: layout.Vertical},