refactor(sointu): add explicit RowsPerPattern to the song

This commit is contained in:
vsariola 2021-01-21 13:16:41 +02:00
parent 08dcbb9edb
commit 61437db0d6
98 changed files with 117 additions and 28 deletions

View File

@ -40,7 +40,7 @@ func TestOscillatSine(t *testing.T) {
sointu.Unit{Type: "out", Parameters: map[string]int{"stereo": 1, "gain": 128}},
}}}}
tracks := []sointu.Track{{NumVoices: 1, Sequence: []byte{0}, Patterns: [][]byte{{64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0, 0, 0}}}}
song := sointu.Song{BPM: 100, Tracks: tracks, Patch: patch}
song := sointu.Song{BPM: 100, RowsPerPattern: 16, Tracks: tracks, Patch: patch}
synth, err := bridge.Synth(patch)
if err != nil {
t.Fatalf("Compiling patch failed: %v", err)

View File

@ -167,7 +167,7 @@ func bytesToInts(array []byte) []int {
}
func ConstructPatterns(song *sointu.Song) ([][]byte, [][]byte, error) {
patLength := song.PatternRows()
patLength := song.RowsPerPattern
sequences := make([][]byte, len(song.Tracks))
var patterns [][]int
for i, t := range song.Tracks {

View File

@ -10,6 +10,7 @@ import (
func TestPatternReusing(t *testing.T) {
song := sointu.Song{
RowsPerPattern: 8,
Tracks: []sointu.Track{{
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {72, 0, 0, 0, 0, 0, 0, 0}},
Sequence: []byte{0, 1},
@ -34,6 +35,7 @@ func TestPatternReusing(t *testing.T) {
func TestUnnecessaryHolds(t *testing.T) {
song := sointu.Song{
RowsPerPattern: 8,
Tracks: []sointu.Track{{
Patterns: [][]byte{{64, 1, 1, 1, 0, 1, 0, 0}, {72, 0, 1, 0, 1, 0, 0, 0}},
Sequence: []byte{0, 1},
@ -58,6 +60,7 @@ func TestUnnecessaryHolds(t *testing.T) {
func TestDontCares(t *testing.T) {
song := sointu.Song{
RowsPerPattern: 8,
Tracks: []sointu.Track{{
Patterns: [][]byte{{64, 1, 1, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}},
Sequence: []byte{0, 1},

View File

@ -254,9 +254,10 @@ var UnitTypes = map[string]([]UnitParameter){
}
type Song struct {
BPM int
Tracks []Track
Patch Patch
BPM int
RowsPerPattern int
Tracks []Track
Patch Patch
}
func (s *Song) Copy() Song {
@ -267,16 +268,12 @@ func (s *Song) Copy() Song {
return Song{BPM: s.BPM, Tracks: tracks, Patch: s.Patch.Copy()}
}
func (s *Song) PatternRows() int {
return len(s.Tracks[0].Patterns[0])
}
func (s *Song) SequenceLength() int {
return len(s.Tracks[0].Sequence)
}
func (s *Song) TotalRows() int {
return s.PatternRows() * s.SequenceLength()
return s.RowsPerPattern * s.SequenceLength()
}
func (s *Song) SamplesPerRow() int {
@ -350,8 +347,8 @@ func Play(synth Synth, song Song) ([]float32, error) {
buffer := make([]float32, 0, initialCapacity)
rowbuffer := make([]float32, song.SamplesPerRow()*2)
for row := 0; row < song.TotalRows(); row++ {
patternRow := row % song.PatternRows()
pattern := row / song.PatternRows()
patternRow := row % song.RowsPerPattern
pattern := row / song.RowsPerPattern
for t := range song.Tracks {
patternIndex := song.Tracks[t].Sequence[pattern]
note := song.Tracks[t].Patterns[patternIndex][patternRow]

View File

@ -7,7 +7,7 @@
#define SU_SAMPLE_RATE 44100
#define SU_BPM {{.Song.BPM}}
#define SU_PATTERN_SIZE {{.Song.PatternRows}}
#define SU_PATTERN_SIZE {{.Song.RowsPerPattern}}
#define SU_MAX_PATTERNS {{.Song.SequenceLength}}
#define SU_TOTAL_ROWS (SU_MAX_PATTERNS*SU_PATTERN_SIZE)
#define SU_SAMPLES_PER_ROW (SU_SAMPLE_RATE*4*60/(SU_BPM*16))

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 8
tracks:
- numvoices: 1
sequence: [1, 0, 2, 0, 3, 0, 4, 0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 8
tracks:
- numvoices: 1
sequence: [1, 0, 2, 0, 3, 0, 4, 0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 2
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0, 0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -1,4 +1,5 @@
bpm: 100
rowsperpattern: 16
tracks:
- numvoices: 1
sequence: [0]

View File

@ -13,7 +13,8 @@ var defaultInstrument = sointu.Instrument{
}
var defaultSong = sointu.Song{
BPM: 100,
BPM: 100,
RowsPerPattern: 16,
Tracks: []sointu.Track{
{NumVoices: 2, Sequence: []byte{0, 0, 0, 1}, Patterns: [][]byte{{64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0, 0, 0}, {64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 75, 0, 75, 0, 80, 0}}},
{NumVoices: 2, Sequence: []byte{0, 0, 0, 1}, Patterns: [][]byte{{0, 0, 64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 78, 0, 0, 0}, {32, 0, 64, 0, 68, 0, 32, 0, 0, 0, 75, 0, 68, 0, 68, 0}}},

View File

@ -75,7 +75,7 @@ func (t *Tracker) KeyEvent(e key.Event) bool {
case key.NameUpArrow:
delta := -1
if e.Modifiers.Contain(key.ModCtrl) {
delta = -t.song.PatternRows()
delta = -t.song.RowsPerPattern
}
t.Cursor.Row += delta
t.Cursor.Clamp(t.song)
@ -87,7 +87,7 @@ func (t *Tracker) KeyEvent(e key.Event) bool {
case key.NameDownArrow:
delta := 1
if e.Modifiers.Contain(key.ModCtrl) {
delta = t.song.PatternRows()
delta = t.song.RowsPerPattern
}
t.Cursor.Row += delta
t.Cursor.Clamp(t.song)

View File

@ -18,21 +18,21 @@ type SongRect struct {
}
func (r *SongRow) Wrap(song sointu.Song) {
totalRow := r.Pattern*song.PatternRows() + r.Row
r.Row = mod(totalRow, song.PatternRows())
r.Pattern = mod((totalRow-r.Row)/song.PatternRows(), song.SequenceLength())
totalRow := r.Pattern*song.RowsPerPattern + r.Row
r.Row = mod(totalRow, song.RowsPerPattern)
r.Pattern = mod((totalRow-r.Row)/song.RowsPerPattern, song.SequenceLength())
}
func (r *SongRow) Clamp(song sointu.Song) {
totalRow := r.Pattern*song.PatternRows() + r.Row
totalRow := r.Pattern*song.RowsPerPattern + r.Row
if totalRow < 0 {
totalRow = 0
}
if totalRow >= song.TotalRows() {
totalRow = song.TotalRows() - 1
}
r.Row = totalRow % song.PatternRows()
r.Pattern = ((totalRow - r.Row) / song.PatternRows()) % song.SequenceLength()
r.Row = totalRow % song.RowsPerPattern
r.Pattern = ((totalRow - r.Row) / song.RowsPerPattern) % song.SequenceLength()
}
func (p *SongPoint) Wrap(song sointu.Song) {

View File

@ -26,7 +26,7 @@ func (t *Tracker) layoutTrack(trackNo int) layout.Widget {
op.Offset(f32.Pt(0, float32(gtx.Constraints.Max.Y/2)-trackRowHeight)).Add(gtx.Ops)
// TODO: this is a time bomb; as soon as one of the patterns is not the same length as rest. Find a solution
// to fix the pattern lengths to a constant value
cursorSongRow := t.Cursor.Pattern*t.song.PatternRows() + t.Cursor.Row
cursorSongRow := t.Cursor.Pattern*t.song.RowsPerPattern + t.Cursor.Row
op.Offset(f32.Pt(0, (-1*trackRowHeight)*float32(cursorSongRow))).Add(gtx.Ops)
patternRect := SongRect{
Corner1: SongPoint{SongRow: SongRow{Pattern: t.Cursor.Pattern}, Track: t.Cursor.Track},
@ -38,7 +38,7 @@ func (t *Tracker) layoutTrack(trackNo int) layout.Widget {
}
for i, s := range t.song.Tracks[trackNo].Sequence {
if patternRect.Contains(SongPoint{Track: trackNo, SongRow: SongRow{Pattern: i}}) {
paint.FillShape(gtx.Ops, activeTrackColor, clip.Rect{Max: image.Pt(trackWidth, trackRowHeight*t.song.PatternRows())}.Op())
paint.FillShape(gtx.Ops, activeTrackColor, clip.Rect{Max: image.Pt(trackWidth, trackRowHeight*t.song.RowsPerPattern)}.Op())
}
for j, c := range t.song.Tracks[trackNo].Patterns[s] {
songRow := SongRow{Pattern: i, Row: j}

View File

@ -188,7 +188,7 @@ func (t *Tracker) AddTrack() {
t.SaveUndo()
if t.song.TotalTrackVoices() < t.song.Patch.TotalVoices() {
seq := make([]byte, t.song.SequenceLength())
patterns := [][]byte{make([]byte, t.song.PatternRows())}
patterns := [][]byte{make([]byte, t.song.RowsPerPattern)}
t.song.Tracks = append(t.song.Tracks, sointu.Track{
NumVoices: 1,
Patterns: patterns,
@ -233,7 +233,7 @@ func (t *Tracker) SetCurrentPattern(pat byte) {
if int(pat) >= length {
tail := make([][]byte, int(pat)-length+1)
for i := range tail {
tail[i] = make([]byte, t.song.PatternRows())
tail[i] = make([]byte, t.song.RowsPerPattern)
}
t.song.Tracks[t.Cursor.Track].Patterns = append(t.song.Tracks[t.Cursor.Track].Patterns, tail...)
}
@ -261,8 +261,8 @@ func (t *Tracker) SetSongLength(value int) {
}
func (t *Tracker) getSelectionRange() (int, int, int, int) {
r1 := t.Cursor.Pattern*t.song.PatternRows() + t.Cursor.Row
r2 := t.SelectionCorner.Pattern*t.song.PatternRows() + t.SelectionCorner.Row
r1 := t.Cursor.Pattern*t.song.RowsPerPattern + t.Cursor.Row
r2 := t.SelectionCorner.Pattern*t.song.RowsPerPattern + t.SelectionCorner.Row
if r2 < r1 {
r1, r2 = r2, r1
}