mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
feat(tracker): implement basic track display
This commit is contained in:
parent
90c3536f3e
commit
77949bdc17
27
go4k/tracker/defaultsong.go
Normal file
27
go4k/tracker/defaultsong.go
Normal 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}},
|
||||
}},
|
||||
},
|
||||
}
|
@ -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
29
go4k/tracker/music.go
Normal 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)
|
||||
}
|
@ -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
|
||||
|
@ -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
60
go4k/tracker/track.go
Normal 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}
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user