-
Notifications
You must be signed in to change notification settings - Fork 1
/
04 HDR, more gui.scd
344 lines (276 loc) · 9.07 KB
/
04 HDR, more gui.scd
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
//DX463
//Fall 2015
//class 04
/*
- Recording – HDR (note: multichannel recording is BROKEN in 3.6.6; use 3.6.5 or 3.7)
- slider/knob for tempo ?
- more
- more Gui: knobs etc
- controlSpec
- ezgui
//first: note this syntax with arrays
#a, b = [1, 3];
a;
b;
#a, b = [[1, 3], [100, 300]];
a;
b;
//and flopping
[[1, 3], [100, 300]].flop
#a, b = [[1, 3], [100, 300]].flop;
a;
b;
executable
*/
//--------------------------------------------------
// note this syntax with arrays
//--------------------------------------------------
#a, b = [1, 3];
a;
b;
#a, b = [[1, 3, 5, 7], [100, 300, 560, 900]];
a;
b;
//and flopping
c = [[1, 3, 5, 7], [100, 300, 560, 900]].flop
c[2]
a = [0.2, 0.3, 2, 3.1];
b = [440, 560, 340, 500];
c = [0.6, 0.8, 0.5, 0.9];
d = [a, b, c].flop
d.do({arg parameters, inc;
parameters.postln;
});
[ [ 1, 100 ], [ 3, 300 ], [ 5, 560 ], [ 7, 900 ] ]
#a, b = [[1, 3], [100, 300]].flop;
a;
b;
s.makeGui
//--------------------------------------------------
// HDR - a hard disk recorder
//--------------------------------------------------
//written by Josh
//part of JoshUGen package (found in SC3plugins)
//no help file, but it's fairly simple
(
~hdr = HDR.new(
Server.default, //server
[0, 1, s.options.numOutputBusChannels + 0, s.options.numOutputBusChannels + 1], //an array of all the channels to record
sessionPath: "".resolveRelative, //current folder
filename: "rec",
headerFormat: "wav",
sampleFormat: "float", //also int16, int24
)
)
~hdr.record
s.queryAllNodes
~hdr.stop
"".resolveRelative.openOS
//--------------------------------------------------
// Spec and ControlSpec
//--------------------------------------------------
// for mapping values
"ControlSpec".openHelpFile; //proper controlspec file
"Spec".openHelpFile; //see what shortcuts are available for creating ControlSpecs
//from the help file
g = ControlSpec(20, 20000, \exp, 0, 220, "Hz");
g.map(0.5); // convert from [0..1] to [0.01..2000]
g.unmap(1000); // convert from [0.01..2000] to [0..1]
// fore and back translation should be close to identical:
g.unmap(g.map(0.5));
//--------------------------------------------------
// EZGUI - EZSlider
//--------------------------------------------------
//now let's see EZSLider
(
var window, allBuffers, relativeSearchPath, fileNames, synth, allButtons, mappingDictionary, vLayout;
relativeSearchPath = "../02/audio/*.wav"; //configuration
s.waitForBoot({
allBuffers = relativeSearchPath.resolveRelative.pathMatch.collect({|thisPath|
thisPath.postln; //so we can see what's happening
CtkBuffer.playbuf(thisPath).load(sync: true);
});
//prepare synth
synth = CtkSynthDef(\stereoPlayer, {|buffer = 0, amp = 1|
Out.ar(0, PlayBuf.ar(2, buffer) * amp);
});
//create a layout which will space our buttons
vLayout = VLayout.new;
//we also need a window
window = Window.new("simple player");
allButtons = allBuffers.collect({|thisBuffer, inc|
var note, filename, thisButton, thisSlider;
filename = thisBuffer.path.basename;
filename.postln; //just the filename, without full path, use for display
//create a button and add it to a layout
vLayout.add(
thisButton = Button(window)
.states_([[filename], [filename ++ " playing"]])
.action_({|buttonObject|
buttonObject.value.postln;
if(buttonObject.value.asBoolean, {
//note obtaining amp from the slider
note = synth.note.buffer_(thisBuffer).amp_(thisSlider.value.dbamp).play;
}, {
note.free;
});
});
);
vLayout.add(
//also let's add volume control - slider
thisSlider = EZSlider(window, label: "amp", controlSpec: ControlSpec(0.ampdb, 2.ampdb, \db, units: " dB"), initVal: 0, layout: \horz, unitWidth: 30)
.action_({|slider|
if(note.notNil, {
note.amp_(slider.value.dbamp); //note dbamp here, since we're using decibel scale above (ControlSpec)
});
});
thisSlider.view; //we're passing EZSlider's "view" to the layout, it won't work otherwise; this is fine, but doesn't always work as expected, see next example
); //add to layout parenthesis
thisButton; //we need this to add button to our allButtons variable!
});
//add layout to the window
window.layout_(vLayout);
//bring the window to front
window.front;
//free buffers on close
window.onClose_({
"stop all notes - through buttons".postln; //new - stopping all notes
allButtons.do(_.valueAction_(0));
"freeing buffers".postln;
allBuffers.do(_.free);
});
window.view.keyUpAction_({|thisView, char, modifiers, unicode, keycode, key|
var thisIndex, thisButton;
[char, modifiers, unicode, keycode, key].postln;
// char.class.postln;
thisIndex = key - 49;
"thisIndex: ".post; thisIndex.postln;
// thisIndex = thisIndex.clip(0, allButtons.size - 1);
// thisIndex = thisIndex % allButtons.size;
if((thisIndex >= 0) && (thisIndex < allButtons.size), {
thisButton = allButtons[thisIndex];
// "thisButton.value.asBoolean: "a.post; thisButton.value.asBoolean.postln;
if(thisButton.value.asBoolean, {
thisButton.valueAction = 0;
}, {
thisButton.valueAction = 1;
});
});
});
});
)
//---------------
// more ezGUIs - now with explicit layout-ing
//--------------
//add pan/balance
(
var window, allBuffers, relativeSearchPath, fileNames, synth, allButtons, mappingDictionary, vLayout;
relativeSearchPath = "../02/audio/*.wav"; //configuration
s.waitForBoot({
allBuffers = relativeSearchPath.resolveRelative.pathMatch.collect({|thisPath|
thisPath.postln; //so we can see what's happening
CtkBuffer.playbuf(thisPath).load(sync: true);
});
//prepare synth
synth = CtkSynthDef(\stereoPlayerWithPan, {|buffer = 0, amp = 1, pan = 0|
var sig;
sig = PlayBuf.ar(2, buffer);
Out.ar(0, Balance2.ar(sig[0], sig[1], pan, amp));
});
//create a layout which will space our buttons
vLayout = VLayout.new;
//we also need a window
window = Window.new("simple player", 600@400/*syntactical shorcut to create a Point*/);
allButtons = allBuffers.collect({|thisBuffer, inc|
var note, filename, thisButton, thisSlider, thisKnob;
filename = thisBuffer.path.basename;
filename.postln; //just the filename, without full path, use for display
//before adding more to the layout, let's create the button and ezgui objects first
thisButton = Button(window)
.states_([[filename], [filename ++ " playing"]])
.action_({|buttonObject|
buttonObject.value.postln;
if(buttonObject.value.asBoolean, {
note = synth.note.buffer_(thisBuffer).play;
}, {
note.free;
});
});
thisSlider = EZSlider(window, label: "amp", controlSpec: ControlSpec(0.ampdb, 2.ampdb, \db, units: " dB"), initVal: 0, layout: \horz, unitWidth: 30)
.action_({|slider|
if(note.notNil, {
note.amp_(slider.value.dbamp); //note dbamp here, since we're using decibel scale above (ControlSpec)
});
});
thisKnob = EZKnob(window, controlSpec: \pan, label: "pan", layout: \vert)
.action_({|knob|
if(note.notNil, {
note.pan_(knob.value);
});
});
//now this will get somewhat messy... since EZGuis don't play nice with the layouts, we'll put the views of indivitual elements of each ezgui in a layout
//it SHOULD be like this....
/* vLayout.add( //add to the general layout
HLayout(
VLayout(
thisButton, //button here
thisSlider.view
), //use HLayout to set 4 elements of the ezslider
thisKnob.view
),
); //add to layout parenthesis*/
//but needs to be like this for the time being
vLayout.add( //add to the general layout
HLayout(
VLayout(
thisButton, //button here
HLayout(
thisSlider.labelView,
thisSlider.sliderView,
thisSlider.numberView.maxWidth_(40), //number box seems the only thing that doesn't scale reasonably by default, so we limit its width here
thisSlider.unitView //since we've set the unitWidth > 0 above, in slider declaration
) //use HLayout to set 4 elements of the ezslider
),
VLayout(
thisKnob.labelView,
thisKnob.knobView,
thisKnob.numberView.maxWidth_(40) //as above
//no unitview here since we are not "enabling" it in the declaration
) //as above
);
); //add to layout parenthesis
thisButton; //we need this to add button to our allButtons variable!
});
//add layout to the window
window.layout_(vLayout);
//bring the window to front
window.front;
//free buffers on close
window.onClose_({
"stop all notes - through buttons".postln;
allButtons.do(_.valueAction_(0));
"freeing buffers".postln;
allBuffers.do(_.free);
});
//see "Char".openHelpFile;
//also "Dictionary".openHelpFile;
window.view.keyUpAction_({|thisView, char, modifiers, unicode, keycode, key|
var thisIndex, thisButton;
[char, modifiers, unicode, keycode, key].postln;
// char.class.postln;
thisIndex = key - 49;
"thisIndex: ".post; thisIndex.postln;
// thisIndex = thisIndex.clip(0, allButtons.size - 1);
// thisIndex = thisIndex % allButtons.size;
if((thisIndex >= 0) && (thisIndex < allButtons.size), {
thisButton = allButtons[thisIndex];
// "thisButton.value.asBoolean: "a.post; thisButton.value.asBoolean.postln;
if(thisButton.value.asBoolean, {
thisButton.valueAction = 0;
}, {
thisButton.valueAction = 1;
});
});
});
});
)