feat(tracker): implement basic track display

This commit is contained in:
Matias Lahti 2020-11-08 02:24:27 +02:00
parent 90c3536f3e
commit 77949bdc17
7 changed files with 161 additions and 11 deletions

View File

@ -0,0 +1,27 @@
package tracker
import "github.com/vsariola/sointu/go4k"
var defaultSong = go4k.Song{
BPM: 100,
Patterns: [][]byte{
{64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0, 0, 0},
{0, 0, 64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0},
},
Tracks: []go4k.Track{
{NumVoices: 1, Sequence: []byte{0}},
{NumVoices: 1, Sequence: []byte{1}},
},
SongLength: 0,
Patch: go4k.Patch{
go4k.Instrument{NumVoices: 2, Units: []go4k.Unit{
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
{"oscillator", false, map[string]int{"transpose": 64, "detune": 64, "phase": 0, "color": 96, "shape": 64, "gain": 128, "flags": 0x40}},
{"mulp", false, map[string]int{}},
{"envelope", false, map[string]int{"attack": 32, "decay": 32, "sustain": 64, "release": 64, "gain": 128}},
{"oscillator", false, map[string]int{"transpose": 72, "detune": 64, "phase": 64, "color": 64, "shape": 96, "gain": 128, "flags": 0x40}},
{"mulp", false, map[string]int{}},
{"out", true, map[string]int{"gain": 128}},
}},
},
}

View File

@ -2,15 +2,34 @@ package tracker
import (
"gioui.org/layout"
"gioui.org/op/paint"
)
func (t *Tracker) Layout(gtx layout.Context) {
layout.Stack{Alignment: layout.NW}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
paint.Fill(gtx.Ops, black)
return layout.Dimensions{Size: gtx.Constraints.Max}
}),
layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(t.layoutControls),
layout.Flexed(1, Lowered(t.layoutTracker)),
)
}
func (t *Tracker) layoutTracker(gtx layout.Context) layout.Dimensions {
flexTracks := make([]layout.FlexChild, len(t.song.Tracks))
for i, trk := range t.song.Tracks {
flexTracks[i] = layout.Rigid(Lowered(t.layoutTrack(
t.song.Patterns[trk.Sequence[t.DisplayPattern]],
t.ActiveTrack == i,
t.CursorRow,
t.CursorColumn,
)))
}
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
flexTracks...,
)
}
func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.Y = 400
gtx.Constraints.Max.Y = 400
return layout.Stack{Alignment: layout.NW}.Layout(gtx,
layout.Expanded(t.QuitButton.Layout),
layout.Stacked(Raised(Label("Hello", white))),
)

29
go4k/tracker/music.go Normal file
View File

@ -0,0 +1,29 @@
package tracker
import "fmt"
const baseNote = 20
var notes = []string{
"C-",
"C#",
"D-",
"D#",
"E-",
"F-",
"F#",
"G-",
"G#",
"A-",
"A#",
"B-",
}
func valueAsNote(val byte) string {
octave := (val - baseNote) / 12
oNote := (val - baseNote) % 12
if octave < 0 || oNote < 0 || octave > 10 {
return "..."
}
return fmt.Sprintf("%s%d", notes[oNote], octave)
}

View File

@ -1,7 +1,6 @@
package tracker
import (
"fmt"
"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op"
@ -21,13 +20,11 @@ func Lowered(w layout.Widget) layout.Widget {
func Beveled(w layout.Widget, base, light, shade color.RGBA) layout.Widget {
return func(gtx layout.Context) layout.Dimensions {
fmt.Println("BR", gtx.Constraints)
paint.FillShape(gtx.Ops, light, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, 1)).Op())
paint.FillShape(gtx.Ops, light, clip.Rect(image.Rect(0, 0, 1, gtx.Constraints.Max.Y)).Op())
paint.FillShape(gtx.Ops, base, clip.Rect(image.Rect(1, 1, gtx.Constraints.Max.X-1, gtx.Constraints.Max.Y-1)).Op())
paint.FillShape(gtx.Ops, shade, clip.Rect(image.Rect(0, gtx.Constraints.Max.Y-1, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
paint.FillShape(gtx.Ops, shade, clip.Rect(image.Rect(gtx.Constraints.Max.X-1, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
fmt.Println("drawing sub..", gtx.Constraints)
stack := op.Push(gtx.Ops)
mcs := gtx.Constraints
mcs.Max.X -= 2

View File

@ -15,6 +15,7 @@ var light = color.RGBA{R: 138, G: 219, B: 243, A: 255}
var dark = color.RGBA{R: 24, G: 40, B: 44, A: 255}
var white = color.RGBA{R: 255, G: 255, B: 255, A: 255}
var black = color.RGBA{R: 0, G: 0, B: 0, A: 255}
var yellow = color.RGBA{R: 255, G: 255, B: 130, A: 255}
var panelColor = neutral
var panelShadeColor = dark
@ -22,3 +23,11 @@ var panelLightColor = light
var labelFont = fontCollection[6].Font
var labelFontSize = unit.Px(18)
var activeTrackColor = color.RGBA{0, 0, 50, 255}
var inactiveTrackColor = black
var trackerFont = fontCollection[6].Font
var trackerFontSize = unit.Px(16)
var trackerTextColor = white
var trackerActiveTextColor = yellow

60
go4k/tracker/track.go Normal file
View File

@ -0,0 +1,60 @@
package tracker
import (
"fmt"
"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/widget"
"image"
"strings"
)
const trackRowHeight = 16
const trackWidth = 100
func (t *Tracker) layoutTrack(notes []byte, active bool, cursorRow, cursorCol int) layout.Widget {
return func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.X = trackWidth
gtx.Constraints.Max.X = trackWidth
if active {
paint.FillShape(gtx.Ops, activeTrackColor, clip.Rect{
Max: gtx.Constraints.Max,
}.Op())
} else {
paint.FillShape(gtx.Ops, inactiveTrackColor, clip.Rect{
Max: gtx.Constraints.Max,
}.Op())
}
defer op.Push(gtx.Ops).Pop()
// clip.Rect{Max:gtx.Constraints.Max}.Add(gtx.Ops)
op.Offset(f32.Pt(0, float32(gtx.Constraints.Max.Y/2)-trackRowHeight)).Add(gtx.Ops)
paint.FillShape(gtx.Ops, panelColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, trackRowHeight)}.Op())
if active {
switch cursorCol {
case 0:
paint.FillShape(gtx.Ops, panelShadeColor, clip.Rect{Max: image.Pt(36, trackRowHeight)}.Op())
case 1, 2:
s := op.Push(gtx.Ops)
op.Offset(f32.Pt(trackWidth/2+float32(cursorCol-1)*10, 0)).Add(gtx.Ops)
paint.FillShape(gtx.Ops, panelShadeColor, clip.Rect{Max: image.Pt(10, trackRowHeight)}.Op())
s.Pop()
}
}
op.Offset(f32.Pt(0, (-1*trackRowHeight)*float32(cursorRow))).Add(gtx.Ops)
for i, c := range notes {
if i == cursorRow {
paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops)
} else {
paint.ColorOp{Color: trackerTextColor}.Add(gtx.Ops)
}
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, valueAsNote(c))
op.Offset(f32.Pt(trackWidth/2, 0)).Add(gtx.Ops)
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", c)))
op.Offset(f32.Pt(-trackWidth/2, trackRowHeight)).Add(gtx.Ops)
}
return layout.Dimensions{Size: gtx.Constraints.Max}
}
}

View File

@ -1,13 +1,22 @@
package tracker
import "gioui.org/widget"
import (
"gioui.org/widget"
"github.com/vsariola/sointu/go4k"
)
type Tracker struct {
QuitButton *widget.Clickable
QuitButton *widget.Clickable
song go4k.Song
CursorRow int
CursorColumn int
DisplayPattern int
ActiveTrack int
}
func New() *Tracker {
return &Tracker{
QuitButton: new(widget.Clickable),
song: defaultSong,
}
}