Skip to content

Commit

Permalink
add repeat parameter on cycle and dice nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
xaviergodart committed Dec 9, 2024
1 parent f66a879 commit 896f0ae
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 8 deletions.
5 changes: 5 additions & 0 deletions core/common/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ type Movable interface {
MustMove(pulse uint64) bool
}

// Repeatable represents an interface for nodes that can repeat directions.
type Repeatable interface {
Repeat() *ControlValue[int]
}

// Behavioral represents an interface for nodes that have a specific behavior.
type Behavioral interface {
Behavior() EmitterBehavior
Expand Down
8 changes: 8 additions & 0 deletions core/field/grid_serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func (g *Grid) Save(bank *filesystem.Bank) {
"triggers": filesystem.NewParam(*n.(*node.EuclidEmitter).Triggers),
"offset": filesystem.NewParam(*n.(*node.EuclidEmitter).Offset),
}
case "cycle", "dice":
fnode.Params = map[string]filesystem.Param{
"repeat": filesystem.NewParam(*n.(common.Behavioral).Behavior().(common.Repeatable).Repeat()),
}
case "toll":
fnode.Params = map[string]filesystem.Param{
"threshold": filesystem.NewParam(*n.(common.Behavioral).Behavior().(*node.TollEmitter).Threshold),
Expand Down Expand Up @@ -120,8 +124,12 @@ func (g *Grid) Load(index int, grid filesystem.Grid) {
newNode = node.NewSpreadEmitter(g.midi, common.Direction(n.Direction))
case "cycle":
newNode = node.NewCycleEmitter(g.midi, common.Direction(n.Direction))
newNode.(common.Behavioral).Behavior().(*node.CycleEmitter).Repeat().Set(n.Params["repeat"].Value)
newNode.(common.Behavioral).Behavior().(*node.CycleEmitter).Repeat().SetRandomAmount(n.Params["repeat"].Amount)
case "dice":
newNode = node.NewDiceEmitter(g.midi, common.Direction(n.Direction))
newNode.(common.Behavioral).Behavior().(*node.DiceEmitter).Repeat().Set(n.Params["repeat"].Value)
newNode.(common.Behavioral).Behavior().(*node.DiceEmitter).Repeat().SetRandomAmount(n.Params["repeat"].Amount)
case "toll":
newNode = node.NewTollEmitter(g.midi, common.Direction(n.Direction))
newNode.(common.Behavioral).Behavior().(*node.TollEmitter).Threshold.Set(n.Params["threshold"].Value)
Expand Down
23 changes: 20 additions & 3 deletions core/node/cycle.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package node

import (
"math"
"signls/core/common"
"signls/core/music"
"signls/midi"
)

type CycleEmitter struct {
next int
repeat *common.ControlValue[int]
count int
next int
}

func NewCycleEmitter(midi midi.Midi, direction common.Direction) *Emitter {
return &Emitter{
direction: direction,
note: music.NewNote(midi),
behavior: &CycleEmitter{},
behavior: &CycleEmitter{
repeat: common.NewControlValue[int](0, 0, math.MaxInt32),
},
}
}

Expand All @@ -23,10 +28,20 @@ func (e *CycleEmitter) EmitDirections(dir common.Direction, inDir common.Directi
return common.NONE
}
d := e.next % dir.Count()
if e.count < e.repeat.Last() {
e.count++
return dir.Decompose()[d]
}
e.Repeat().Computed()
e.count = 0
e.next = (e.next + 1) % dir.Count()
return dir.Decompose()[d]
}

func (e *CycleEmitter) Repeat() *common.ControlValue[int] {
return e.repeat
}

func (e *CycleEmitter) ShouldPropagate() bool {
return false
}
Expand All @@ -36,8 +51,10 @@ func (e *CycleEmitter) ArmedOnStart() bool {
}

func (e *CycleEmitter) Copy() common.EmitterBehavior {
newRepeat := *e.repeat
return &CycleEmitter{
next: e.next,
next: e.next,
repeat: &newRepeat,
}
}

Expand Down
27 changes: 22 additions & 5 deletions core/node/dice.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package node

import (
"math"
"math/rand"
"time"

Expand All @@ -10,7 +11,10 @@ import (
)

type DiceEmitter struct {
rand *rand.Rand
rand *rand.Rand
repeat *common.ControlValue[int]
last int
count int
}

func NewDiceEmitter(midi midi.Midi, direction common.Direction) *Emitter {
Expand All @@ -19,7 +23,8 @@ func NewDiceEmitter(midi midi.Midi, direction common.Direction) *Emitter {
direction: direction,
note: music.NewNote(midi),
behavior: &DiceEmitter{
rand: rand.New(source),
rand: rand.New(source),
repeat: common.NewControlValue[int](0, 0, math.MaxInt32),
},
}
}
Expand All @@ -28,8 +33,18 @@ func (e *DiceEmitter) EmitDirections(dir common.Direction, inDir common.Directio
if dir.Count() == 0 {
return common.NONE
}
d := e.rand.Intn(dir.Count())
return dir.Decompose()[d]
if e.count < e.repeat.Last() {
e.count++
return dir.Decompose()[e.last]
}
e.repeat.Computed()
e.count = 0
e.last = e.rand.Intn(dir.Count())
return dir.Decompose()[e.last]
}

func (e *DiceEmitter) Repeat() *common.ControlValue[int] {
return e.repeat
}

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

func (e *DiceEmitter) Copy() common.EmitterBehavior {
source := rand.NewSource(time.Now().UnixNano())
newRepeat := *e.repeat
return &DiceEmitter{
rand: rand.New(source),
rand: rand.New(source),
repeat: &newRepeat,
}
}

Expand Down
9 changes: 9 additions & 0 deletions ui/param/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ func NewParamsForNodes(grid *field.Grid, nodes []common.Node) [][]Param {
DefaultEmitterControlChanges(nodes),
DefaultEmitterMetaCommands(nodes),
}
} else if isHomogeneousBehavior[common.Repeatable](nodes) {
return [][]Param{
append(
DefaultEmitterParams(grid, nodes),
Repeat{nodes: nodes},
),
DefaultEmitterControlChanges(nodes),
DefaultEmitterMetaCommands(nodes),
}
}

emitters := filterNodes[music.Audible](nodes)
Expand Down
96 changes: 96 additions & 0 deletions ui/param/repeat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package param

import (
"fmt"
"math"
"strconv"

"signls/core/common"
"signls/core/node"

"signls/ui/util"
)

type Repeat struct {
nodes []common.Node
}

func (r Repeat) Name() string {
return "rpt"
}

func (r Repeat) Help() string {
return ""
}

func (r Repeat) Display() string {
if r.control().RandomAmount() != 0 {
return util.Normalize(
fmt.Sprintf(
"%d%+d\u033c",
r.control().Value(),
r.control().RandomAmount(),
),
)
}
return fmt.Sprintf("%d", r.Value())
}

func (r Repeat) control() *common.ControlValue[int] {
return r.nodes[0].(*node.Emitter).Behavior().(common.Repeatable).Repeat()
}

func (r Repeat) Value() int {
return r.control().Value()
}

func (r Repeat) AltValue() int {
return r.control().RandomAmount()
}

func (r Repeat) Up() {
r.Set(r.Value() + 1)
}

func (r Repeat) Down() {
r.Set(r.Value() - 1)
}

func (r Repeat) Left() {
r.SetAlt(r.AltValue() - 1)
}

func (r Repeat) Right() {
r.SetAlt(r.AltValue() + 1)
}

func (r Repeat) AltUp() {}

func (r Repeat) AltDown() {}

func (r Repeat) AltLeft() {}

func (r Repeat) AltRight() {}

func (r Repeat) Set(value int) {
if value < 0 || value >= math.MaxInt32 {
return
}
for _, n := range r.nodes {
n.(*node.Emitter).Behavior().(common.Repeatable).Repeat().Set(value)
}
}

func (r Repeat) SetAlt(value int) {
for _, n := range r.nodes {
n.(*node.Emitter).Behavior().(common.Repeatable).Repeat().SetRandomAmount(value)
}
}

func (r Repeat) SetEditValue(input string) {
value, err := strconv.Atoi(input)
if err != nil {
return
}
r.Set(value)
}

0 comments on commit 896f0ae

Please sign in to comment.