sclang: array primitives - respect mutability when changing object.
[supercollider.git] / examples / research_and_tools / Diamond.scd
blobb5773be6460f63f80f3814c20f5719003cc425b1
2 /*
4 Diamond by James McCartney
8 Partch "otonalities" (i.e. a set of ratios with the same denominator 
9 and changing numerator, i.e. overtone series) run horizontally.
11 Partch "utonalities" (i.e. a set of ratios with the same numerator and 
12 changing denominator, a.k.a. undertone series) run vertically.
14 The ratio between a pair of buttons in any two columns is the same for 
15 any row in those columns.
16 The ratio between a pair of buttons in any two rows is the same for any 
17 column in those rows.
18 ..there must be a less confusing way of stating that...
19 a set of buttons pressed in one row will be a transposition of the same 
20 columns' buttons pressed in any row.
21 a set of buttons pressed in one column will be a transposition of the 
22 same rows' buttons pressed in any column.
27 s.boot;
30 var w, buttons;
31 var series, series2;
33 SynthDef("tone", { arg freq = 440, amp=0.1, gate =1;
34         var tone, env;
35         env = Linen.kr(gate, 0.01, amp, 0.2, 2);
36         tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.95);
37         Out.ar(0, tone);
38 }).add;
40 series = (8..15);
41 series.remove(13);
43 series2 = series ++ (2 * series) ++ (4 * (series ++ 16));
44 series = 4 * (series ++ 16);
46 w = Window("diamond", Rect(200,200,460,560));
47 w.view.decorator = FlowLayout(w.view.bounds);
49 series2.reverse.do {|denom|
50         series.do {|numer|
51                 var rnumer, rdenom;
52                 var b, gcd, label, ratio, id, freq;
53                 var color;
54                 [numer, denom].post;
55                 rnumer = numer;
56                 rdenom = denom;
57                 gcd = rnumer gcd: rdenom;
58                 rnumer = rnumer div: gcd;
59                 rdenom = rdenom div: gcd;
60                 [rnumer, rdenom].postln;
61                 ratio = rnumer / rdenom;
62                 freq = 50.midicps * ratio;
63                 b = Button(w, 50 @ 20);
64                 label = rnumer.asString ++ " / " ++ rdenom;
65                 color = if (rnumer.isPowerOfTwo && rdenom.isPowerOfTwo) {Color.red(1,0.4)}{
66                         if(numer.isPowerOfTwo || denom.isPowerOfTwo) {Color.yellow(1,0.4)}{Color.clear}};
67                 b.states = [[label, Color.black, color],[label, Color.white, Color.black]];
68                 b.action = {
69                         if (b.value == 1) {
70                                 s.sendMsg(\s_new, \tone, id = s.nextNodeID, 0, 1, \freq, freq);
71                                 [\on, rnumer, rdenom].postln
72                         }{
73                                 s.sendMsg(\n_set, id, \gate, 0);
74                                 [\off, rnumer, rdenom].postln
75                         };      
76                 };
77         };
78         w.view.decorator.nextLine;
80 w.front;
90 ////////////////////////
99 // alternate, horizontal layout:
101 s.boot;
104 var w, buttons;
105 var series, series2;
107 SynthDef("tone", { arg freq = 440, amp=0.1, gate =1;
108         var tone, env;
109         env = Linen.kr(gate, 0.01, amp, 0.2, 2);
110         //tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.95);
111         tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.8);
112         Out.ar(0, tone);
113 }).add;
115 series = (8..15);
116 series.remove(13);
118 series2 = series ++ (2 * series) ++ (4 * (series ++ 16));
119 series = (series ++ 16);
121 w = Window("diamond", Rect(50,200,980,220));
122 w.view.decorator = FlowLayout(w.view.bounds);
124 series.reverse.do {|denom|
125         series2.do {|numer|
126                 var rnumer, rdenom;
127                 var b, gcd, label, ratio, id, freq;
128                 var color;
129                 [numer, denom].post;
130                 rnumer = numer;
131                 rdenom = denom;
132                 gcd = rnumer gcd: rdenom;
133                 rnumer = rnumer div: gcd;
134                 rdenom = rdenom div: gcd;
135                 [rnumer, rdenom].postln;
136                 ratio = rnumer / rdenom;
137                 freq = 50.midicps * ratio;
138                 b = Button(w, 40 @ 20);
139                 label = rnumer.asString ++ "/" ++ rdenom;
140                 color = if (rnumer.isPowerOfTwo && rdenom.isPowerOfTwo) 
141 {Color.red(1,0.4)}{
142                         if(numer.isPowerOfTwo || denom.isPowerOfTwo) 
143 {Color.yellow(1,0.4)}{Color.clear}};
144                 b.states = [[label, Color.black, color],[label, Color.white, 
145 Color.black]];
146                 b.action = {
147                         if (b.value == 1) {
148                                 s.sendMsg(\s_new, \tone, id = s.nextNodeID, 0, 1, \freq, freq);
149                         }{
150                                 s.sendMsg(\n_set, id, \gate, 0);
151                         };      
152                 };
153         };
154         w.view.decorator.nextLine;
156 w.front;
160 //////////////////////////////
164 // This one displays the cyclic cents values for the ratios.
168 s.boot;
171 var w, buttons, buttonFont;
172 var series, series2;
174 SynthDef("tone", { arg freq = 440, amp=0.1, gate =1;
175         var tone, env;
176         env = Linen.kr(gate, 0.01, amp, 0.2, 2);
177         //tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.95);
178         tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.8);
179         Out.ar(0, tone);
180 }).add;
182 series = (8..15);
183 series.remove(13);
185 series2 = series ++ (2 * series) ++ (4 * (series ++ 16));
186 series = (series ++ 16);
188 w = Window("diamond", Rect(50,200,980,370), resizable: false);
189 w.view.decorator = FlowLayout(w.view.bounds);
191 buttonFont = Font("Helvetica", if( GUI.id === \cocoa, 11, 7 )).boldVariant;
193 series.reverse.do {|denom|
194         series2.do {|numer|
195                 var rnumer, rdenom;
196                 var b, gcd, label, ratio, id, freq;
197                 var color;
198                 [numer, denom].post;
199                 rnumer = numer;
200                 rdenom = denom;
201                 gcd = rnumer gcd: rdenom;
202                 rnumer = rnumer div: gcd;
203                 rdenom = rdenom div: gcd;
204                 [rnumer, rdenom].postln;
205                 ratio = rnumer / rdenom;
206                 freq = 50.midicps * ratio;
207                 b = Button(w, 40 @ 40);
208                 label = rnumer.asString ++ " / " ++ rdenom ++ "\n" ++ 
209 ((ratio.ratiomidi * 100).round.asInteger % 1200);
210                 color = if (rnumer.isPowerOfTwo && rdenom.isPowerOfTwo) 
211 {Color.red(1,0.4)}{
212                         if(numer.isPowerOfTwo || denom.isPowerOfTwo) 
213 {Color.yellow(1,0.4)}{Color.clear}};
214                 b.states = [[label, Color.black, color],[label, Color.white, 
215 Color.black]];
216                 b.font = buttonFont;
217                 b.action = {
218                         if (b.value == 1) {
219                                 s.sendMsg(\s_new, \tone, id = s.nextNodeID, 0, 1, \freq, freq);
220                         }{
221                                 s.sendMsg(\n_set, id, \gate, 0);
222                         };      
223                 };
224         };
225         w.view.decorator.nextLine;
227 w.front;
232 /////////////////////////////////