«Language based n x n step sequencer» byDavid Morgan

on 04 Dec'16 17:37 in sequencer
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
Language based n x n step sequencer.

Without a UI it's easy to create and transform arbitrary matrixes.
You can also map x/x coordinates to whatever you wish.
*/

(
// Factory method for creating loopr object
~createLoopr = {arg dur;

var obj = (

grid: [],

dur: 1,

setDur: {arg self, dur;
self.dur = dur;
self.seq = self.dur.asStream;
},

getDur: {arg self;
self.dur;
},

seq: 1.asStream,

func: {},

player: {arg self;

var me = self;

var pattern = Pspawner({arg sp;
inf.do({arg i;
var time = me.seq.next;
var evt = me.process(i.asInt, time);
sp.par(evt);
sp.wait(time);
});
});

EventPatternProxy.new(pattern);
},

process: {arg self, count, time;

var me = self;

Plazy({

var rows = me.grid;
var evts = rows.collect({arg item, row;

var val;
var event;
var x = (count % item.size).asInt;
val = item.wrapAt(count).value;

event = (isRest:true);
if (val > 0) {
var myEvent = me.func(x, row, val, time, count);
if (myEvent.isKindOf(Event) or: myEvent.isKindOf(Pattern)) {
event = myEvent;
};
};

Pn(event, 1);
});

Ppar(evts);
});
}
);

obj.setDur(dur);
obj;
};
)

// Create a synth to play
(
SynthDef(\blip, {arg freq, time = 1, out = 0;
var rel = TRand.kr(0.1,4,1);
var sig = SinOsc.ar(freq*[0.9,0.99,1,1.01,1.1], mul:[0.05,0.2,1,0.2,0.05]).mean;
var env = EnvGen.ar(Env.perc(1e-4,rel,0.75), 1, timeScale:time, doneAction:2);
sig = Splay.ar(sig) * env * \amp.kr(0.1) * AmpCompA.kr(freq);
Out.ar(out, sig);
)

// Grid values greater than zero will invoke the func handler in order to do something.
// You can map the x, y coordinates however you wish.
// Plus the value at each point can be used for additional parameterization.
(~grid = [
[7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0],
[0 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0],
[0 , 0 , 5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0],
[0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 5 , 5 , 5 , 5 , 0 , 0 , 0 , 0],
[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 6 , 0 , 0 , 0],
[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 0 , 7 , 0 , 0],
// can handle asymetrical arrays
[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 5],
[6 , {[5,6].choose}, 4 , 0]
]);

// Create a new instance specifying the initial dur value
~loopr1 = ~createLoopr.value(0.25);
// Set the grid.
~loopr1.grid = ~grid;

// Set up the handler.
// This is the function that will be called
// for each non zero point in the grid.
// Return an Event or Pattern to be played.
(
var fx = NodeProxy.new(s, \audio, 2);
fx[1] = \filter -> {arg in; GVerb.ar(in, 100); };
fx.play;

~loopr1.func = {arg self, x, y, val, time;

// the value of each point maps to an octave
// time is the event duration, i.e. the dur value
(instrument: \blip,
\amp: 0.5,
\degree: y,
\octave: val,
\scale: Scale.ritusen,
\time: time,
\group: fx.group,
\out: fx.bus
);
}
);

//Play the sequencer
~loopr1.player.play(quant:1.0);

// Apply transformations to the grid
~loopr1.grid = ~grid.reverse;
~loopr1.grid = ~grid.flop;
~loopr1.grid = ~grid.stutter;
~loopr1.grid = ~grid.mirror;
~loopr1.grid = ~grid;

// You can change the rhythm duration to a pattern
(
~loopr1.setDur(
Pseg(
Pwhite().linexp(0, 1, 1/32, 1),
Pbrown(0,1,0.05).linexp(0, 1, 1/8, 8),
\sin
)
)
)

// Reset
~loopr1.setDur(0.25);
raw 3681 chars (focus & ctrl+a+c to copy)
reception