1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import Constant, Op, Input, T, sig, evt from require 'alv.base'
-- slower reference implementation
bjorklund = (n, k) ->
full = ['1' for i=1,k]
rest = ['0' for i=k,n-1]
while #rest > 1
next_full = {}
while full[1] and rest[1]
a = table.remove full
b = table.remove rest
table.insert next_full, a .. b
while rest[1]
table.insert full, table.remove rest
full, rest = next_full, full
if rest[1]
table.insert full, rest[1]
table.concat full, ''
-- faster implementation
bjorklund2 = (n, k) ->
a, as = '1', k
b, bs = '0', n - k
while true
if as < 2 or bs < 2
break
elseif as < bs
a, b = a .. b, b
as, bs = as, bs - as
else
a, b = a .. b, a
as, bs = bs, as - bs
(string.rep a, as) .. (string.rep b, bs)
euclid = Constant.meta
meta:
name: 'euclid'
summary: "Generate euclidean rhythms."
examples: { '(euclid trig! n k)', '(euclid i n k)' }
description: "Generates bangs according to the Euclidean algorithm.
When fed a bang! trigger, steps forward to the next step on each trigger.
When fed a num~ or num! stream, outputs a bang if the corresponding step is on."
value: class extends Op
pattern = (evt.bang / sig.num / evt.num) + sig.num + sig.num
setup: (inputs) =>
{ trig, n, k } = pattern\match inputs
@out or= T.bang\mk_evt!
if trig\type! == T.bang
@state or= 1
else
@state = nil
super
trig: Input.hot trig
n: Input.cold n
k: Input.cold k
tick: =>
{ :trig, :n, :k } = @unwrap_all!
n = math.floor n
k = math.floor k
if @inputs.trig\type! == T.bang
@state += 1
if @state >= n
@state -= n
i = 1 + (@state or trig % n)
pat = bjorklund2 n, k
if '1' == pat\sub i, i
@out\set true
trigseq = Constant.meta
meta:
name: 'trigseq'
summary: "Generate rhythms based on a trigger-sequence"
examples: { '(trigseq trig! s1 s2…)', '(trigseq i s1 s2…)' }
description: "Generates bangs according to the sequence `s1`, `s2`, …
Each step should be a bool~ that determines whether a bang should be emitted on
that step or not.
When fed a bang! trigger, steps forward to the next step on each trigger.
When fed a num~ or num! stream, outputs a bang if the corresponding step is on."
value: class extends Op
pattern = (evt.bang / sig.num / evt.num) + sig.bool*0
setup: (inputs) =>
{ trig, steps } = pattern\match inputs
@out or= T.bang\mk_evt!
super
trig: Input.hot trig
steps: [Input.cold s for s in *steps]
if @inputs.trig\type! == T.bang
@state or= 1
else
@state = nil
tick: =>
n = #@inputs.steps
if @inputs.trig\type! == T.bang
@state += 1
if @state >= n
@state -= n
i = 1 + (@state or trig % n)
if @inputs.steps[i]!
@out\set true
Constant.meta
meta:
name: 'rhythm'
summary: "Rhythm-generation and sequencing."
value:
:euclid
:trigseq
|