Skip to content

Commit 896f0ae

Browse files
committed
add repeat parameter on cycle and dice nodes
1 parent f66a879 commit 896f0ae

File tree

6 files changed

+160
-8
lines changed

6 files changed

+160
-8
lines changed

core/common/interface.go

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ type Movable interface {
5858
MustMove(pulse uint64) bool
5959
}
6060

61+
// Repeatable represents an interface for nodes that can repeat directions.
62+
type Repeatable interface {
63+
Repeat() *ControlValue[int]
64+
}
65+
6166
// Behavioral represents an interface for nodes that have a specific behavior.
6267
type Behavioral interface {
6368
Behavior() EmitterBehavior

core/field/grid_serialization.go

+8
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ func (g *Grid) Save(bank *filesystem.Bank) {
5454
"triggers": filesystem.NewParam(*n.(*node.EuclidEmitter).Triggers),
5555
"offset": filesystem.NewParam(*n.(*node.EuclidEmitter).Offset),
5656
}
57+
case "cycle", "dice":
58+
fnode.Params = map[string]filesystem.Param{
59+
"repeat": filesystem.NewParam(*n.(common.Behavioral).Behavior().(common.Repeatable).Repeat()),
60+
}
5761
case "toll":
5862
fnode.Params = map[string]filesystem.Param{
5963
"threshold": filesystem.NewParam(*n.(common.Behavioral).Behavior().(*node.TollEmitter).Threshold),
@@ -120,8 +124,12 @@ func (g *Grid) Load(index int, grid filesystem.Grid) {
120124
newNode = node.NewSpreadEmitter(g.midi, common.Direction(n.Direction))
121125
case "cycle":
122126
newNode = node.NewCycleEmitter(g.midi, common.Direction(n.Direction))
127+
newNode.(common.Behavioral).Behavior().(*node.CycleEmitter).Repeat().Set(n.Params["repeat"].Value)
128+
newNode.(common.Behavioral).Behavior().(*node.CycleEmitter).Repeat().SetRandomAmount(n.Params["repeat"].Amount)
123129
case "dice":
124130
newNode = node.NewDiceEmitter(g.midi, common.Direction(n.Direction))
131+
newNode.(common.Behavioral).Behavior().(*node.DiceEmitter).Repeat().Set(n.Params["repeat"].Value)
132+
newNode.(common.Behavioral).Behavior().(*node.DiceEmitter).Repeat().SetRandomAmount(n.Params["repeat"].Amount)
125133
case "toll":
126134
newNode = node.NewTollEmitter(g.midi, common.Direction(n.Direction))
127135
newNode.(common.Behavioral).Behavior().(*node.TollEmitter).Threshold.Set(n.Params["threshold"].Value)

core/node/cycle.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
package node
22

33
import (
4+
"math"
45
"signls/core/common"
56
"signls/core/music"
67
"signls/midi"
78
)
89

910
type CycleEmitter struct {
10-
next int
11+
repeat *common.ControlValue[int]
12+
count int
13+
next int
1114
}
1215

1316
func NewCycleEmitter(midi midi.Midi, direction common.Direction) *Emitter {
1417
return &Emitter{
1518
direction: direction,
1619
note: music.NewNote(midi),
17-
behavior: &CycleEmitter{},
20+
behavior: &CycleEmitter{
21+
repeat: common.NewControlValue[int](0, 0, math.MaxInt32),
22+
},
1823
}
1924
}
2025

@@ -23,10 +28,20 @@ func (e *CycleEmitter) EmitDirections(dir common.Direction, inDir common.Directi
2328
return common.NONE
2429
}
2530
d := e.next % dir.Count()
31+
if e.count < e.repeat.Last() {
32+
e.count++
33+
return dir.Decompose()[d]
34+
}
35+
e.Repeat().Computed()
36+
e.count = 0
2637
e.next = (e.next + 1) % dir.Count()
2738
return dir.Decompose()[d]
2839
}
2940

41+
func (e *CycleEmitter) Repeat() *common.ControlValue[int] {
42+
return e.repeat
43+
}
44+
3045
func (e *CycleEmitter) ShouldPropagate() bool {
3146
return false
3247
}
@@ -36,8 +51,10 @@ func (e *CycleEmitter) ArmedOnStart() bool {
3651
}
3752

3853
func (e *CycleEmitter) Copy() common.EmitterBehavior {
54+
newRepeat := *e.repeat
3955
return &CycleEmitter{
40-
next: e.next,
56+
next: e.next,
57+
repeat: &newRepeat,
4158
}
4259
}
4360

core/node/dice.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package node
22

33
import (
4+
"math"
45
"math/rand"
56
"time"
67

@@ -10,7 +11,10 @@ import (
1011
)
1112

1213
type DiceEmitter struct {
13-
rand *rand.Rand
14+
rand *rand.Rand
15+
repeat *common.ControlValue[int]
16+
last int
17+
count int
1418
}
1519

1620
func NewDiceEmitter(midi midi.Midi, direction common.Direction) *Emitter {
@@ -19,7 +23,8 @@ func NewDiceEmitter(midi midi.Midi, direction common.Direction) *Emitter {
1923
direction: direction,
2024
note: music.NewNote(midi),
2125
behavior: &DiceEmitter{
22-
rand: rand.New(source),
26+
rand: rand.New(source),
27+
repeat: common.NewControlValue[int](0, 0, math.MaxInt32),
2328
},
2429
}
2530
}
@@ -28,8 +33,18 @@ func (e *DiceEmitter) EmitDirections(dir common.Direction, inDir common.Directio
2833
if dir.Count() == 0 {
2934
return common.NONE
3035
}
31-
d := e.rand.Intn(dir.Count())
32-
return dir.Decompose()[d]
36+
if e.count < e.repeat.Last() {
37+
e.count++
38+
return dir.Decompose()[e.last]
39+
}
40+
e.repeat.Computed()
41+
e.count = 0
42+
e.last = e.rand.Intn(dir.Count())
43+
return dir.Decompose()[e.last]
44+
}
45+
46+
func (e *DiceEmitter) Repeat() *common.ControlValue[int] {
47+
return e.repeat
3348
}
3449

3550
func (e *DiceEmitter) ShouldPropagate() bool {
@@ -42,8 +57,10 @@ func (e *DiceEmitter) ArmedOnStart() bool {
4257

4358
func (e *DiceEmitter) Copy() common.EmitterBehavior {
4459
source := rand.NewSource(time.Now().UnixNano())
60+
newRepeat := *e.repeat
4561
return &DiceEmitter{
46-
rand: rand.New(source),
62+
rand: rand.New(source),
63+
repeat: &newRepeat,
4764
}
4865
}
4966

ui/param/param.go

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ func NewParamsForNodes(grid *field.Grid, nodes []common.Node) [][]Param {
6767
DefaultEmitterControlChanges(nodes),
6868
DefaultEmitterMetaCommands(nodes),
6969
}
70+
} else if isHomogeneousBehavior[common.Repeatable](nodes) {
71+
return [][]Param{
72+
append(
73+
DefaultEmitterParams(grid, nodes),
74+
Repeat{nodes: nodes},
75+
),
76+
DefaultEmitterControlChanges(nodes),
77+
DefaultEmitterMetaCommands(nodes),
78+
}
7079
}
7180

7281
emitters := filterNodes[music.Audible](nodes)

ui/param/repeat.go

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
"math"
6+
"strconv"
7+
8+
"signls/core/common"
9+
"signls/core/node"
10+
11+
"signls/ui/util"
12+
)
13+
14+
type Repeat struct {
15+
nodes []common.Node
16+
}
17+
18+
func (r Repeat) Name() string {
19+
return "rpt"
20+
}
21+
22+
func (r Repeat) Help() string {
23+
return ""
24+
}
25+
26+
func (r Repeat) Display() string {
27+
if r.control().RandomAmount() != 0 {
28+
return util.Normalize(
29+
fmt.Sprintf(
30+
"%d%+d\u033c",
31+
r.control().Value(),
32+
r.control().RandomAmount(),
33+
),
34+
)
35+
}
36+
return fmt.Sprintf("%d", r.Value())
37+
}
38+
39+
func (r Repeat) control() *common.ControlValue[int] {
40+
return r.nodes[0].(*node.Emitter).Behavior().(common.Repeatable).Repeat()
41+
}
42+
43+
func (r Repeat) Value() int {
44+
return r.control().Value()
45+
}
46+
47+
func (r Repeat) AltValue() int {
48+
return r.control().RandomAmount()
49+
}
50+
51+
func (r Repeat) Up() {
52+
r.Set(r.Value() + 1)
53+
}
54+
55+
func (r Repeat) Down() {
56+
r.Set(r.Value() - 1)
57+
}
58+
59+
func (r Repeat) Left() {
60+
r.SetAlt(r.AltValue() - 1)
61+
}
62+
63+
func (r Repeat) Right() {
64+
r.SetAlt(r.AltValue() + 1)
65+
}
66+
67+
func (r Repeat) AltUp() {}
68+
69+
func (r Repeat) AltDown() {}
70+
71+
func (r Repeat) AltLeft() {}
72+
73+
func (r Repeat) AltRight() {}
74+
75+
func (r Repeat) Set(value int) {
76+
if value < 0 || value >= math.MaxInt32 {
77+
return
78+
}
79+
for _, n := range r.nodes {
80+
n.(*node.Emitter).Behavior().(common.Repeatable).Repeat().Set(value)
81+
}
82+
}
83+
84+
func (r Repeat) SetAlt(value int) {
85+
for _, n := range r.nodes {
86+
n.(*node.Emitter).Behavior().(common.Repeatable).Repeat().SetRandomAmount(value)
87+
}
88+
}
89+
90+
func (r Repeat) SetEditValue(input string) {
91+
value, err := strconv.Atoi(input)
92+
if err != nil {
93+
return
94+
}
95+
r.Set(value)
96+
}

0 commit comments

Comments
 (0)