// Eric Sirianni // Rishi Sahay // Project 3 /* We made patch that allows the user to create tones of specified frequency, amplitude, duration, envelope(trapezoidal), and pan for each of the first four partials of the fundamental. The user first specifies all of these parameters in a GUI window at the start of the program. Then, when ready to hear the resulting sounds, the user clicks on the "Play Sound" button at the top of the GUI. The person can stop the program at any time with the "Stop Sound" button, change the parameters, and play a tone again for different parameters. This can be done repeatedly. We also threw in a couple of extra effects-- optional frequency and amplitude modulation for each of the four partials. The idea is that with the different possible modifications to the first four partials, the user will be able to create tones with large variety in timbre even within the limits of a given fundamental. */ ( var w, // GUI a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, // Sliders for each partial a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, // Numberviews for each partial freq, freq1, // Frequency input first, second, third, fourth, // Frequencies for partials wave1, wave2, wave3, wave4, // Waves for the 4 partials final, // 4 waves mixed together but, but2, // "Play" and "Stop" buttons v1, v2, v3, v4, // Vibrato boxes amp1, amp2, amp3, amp4, // Amplitude modulation boxes pn1, pn2, pn3, pn4; // Pan sliders for partials // GUI Window w = GUIWindow.new("Envelope GUI", Rect.newBy(139, 44, 518, 545)) .backColor_(rgb(84,126,176)); // PLAY AND STOP BUTTONS but = ButtonView.new( w, Rect.newBy(100, 45, 128, 20), "Play Sound", 0, 0, 1, 0, 'linear') .backColor_(rgb(215,215,79)); but2 = ButtonView.new( w, Rect.newBy(300, 45, 128, 20), "Stop Sound", 0, 0, 1, 0, 'linear') .backColor_(rgb(215,215,79)); but.action = {Synth.play(final)}; but2.action = {Synth.stop}; // FREQUENCY INPUT freq1 = NumericalView.new( w, Rect.newBy(108, 12, 42, 19), "NumericalView", 0, -1e+10, 1e+10, 0, 'exponential') .backColor_(rgb(176,176,176)); freq = SliderView.new( w, Rect.newBy(156, 11, 198, 21), "SliderView", 0, 0, 1500, 0, 'linear') .backColor_(rgb(176,176,176)).knobColor_(rgb(176,176,176)); // Synchronize number input with slider freq.action = { freq1.value = freq.value; first.value = freq.value; second.value = 2*freq.value; third.value = 3*freq.value; fourth.value = 4*freq.value }; freq1.action = { freq.value = freq1.value; first.value = freq1.value; second.value = 2*freq1.value; third.value = 3*freq1.value; fourth.value = 4*freq1.value}; StringView.new( w, Rect.newBy(5, 12, 87, 20), "Frequency"); // FIRST PARTIAL // Value of first partial in Hertz StringView.new( w, Rect.newBy(9, 70, 128, 20), "1st Partial"); first = NumericalView.new( w, Rect.newBy(12, 88, 64, 20), "NumericalView", 0, -1e+10, 1e+10, 0, 'linear') .backColor_(rgb(176,176,176)); // Sliders for attack, sustain, decay, and amplitude a = SliderView.new( w, Rect.newBy(206, 88, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,21,54)).knobColor_(rgb(176,176,176)); b = SliderView.new( w, Rect.newBy(206, 111, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(42,120,81)).knobColor_(rgb(176,176,176)); c = SliderView.new( w, Rect.newBy(206, 135, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,148,109)).knobColor_(rgb(176,176,176)); d = SliderView.new( w, Rect.newBy(206, 160, 128, 20), "SliderView", 0, 0, 1, 0, 'linear') .backColor_(rgb(176,176,176)).knobColor_(rgb(176,176,176)); // Corresponding numerical views a1 = NumericalView.new( w, Rect.newBy(164, 88, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,176,176)); b1 = NumericalView.new( w, Rect.newBy(164, 111, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,176,176)); c1 = NumericalView.new( w, Rect.newBy(164, 134, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,176,176)); d1 = NumericalView.new( w, Rect.newBy(164, 159, 38, 19), "NumericalView", 0, 0, 1, 0, 'linear') .backColor_(rgb(176,176,176)); // Synchronize numerical views with sliders a.action = { a1.value = a.value }; b.action = { b1.value = b.value }; c.action = { c1.value = c.value }; d.action = { d1.value = d.value }; // Synchronize sliders with numerical values a1.action = { a.value = a1.value }; b1.action = { b.value = b1.value }; c1.action = { c.value = c1.value }; d1.action = { d.value = d1.value }; // The corresponding labels StringView.new( w, Rect.newBy(92, 87, 61, 20), "Attack"); StringView.new( w, Rect.newBy(92, 111, 61, 20), "Sustain"); StringView.new( w, Rect.newBy(92, 135, 61, 20), "Decay"); StringView.new( w, Rect.newBy(92, 159, 61, 20), "Amplitude"); // Checkboxes v1 = CheckBoxView.new( w, Rect.newBy(358, 88, 128, 20), "Vibrato", 0, 0, 1, 0, 'linear'); amp1 = CheckBoxView.new( w, Rect.newBy(358, 112, 128, 20), "Amp. Modulation", 0, 0, 1, 0, 'linear'); // Pan pn1 = SliderView.new( w, Rect.newBy(358, 160, 128, 20), "SliderView", 0, -1, 1, 0, 'linear') .backColor_(rgb(0,0,0)).knobColor_(rgb(255,255,255)); StringView.new( w, Rect.newBy(406, 138, 63, 18), "Pan"); // SECOND PARTIAL // Value of the second partial in hertz StringView.new( w, Rect.newBy(9, 185, 128, 20), "2nd Partial"); second = NumericalView.new( w, Rect.newBy(12, 203, 64, 20), "NumericalView", 0, -1e+10, 1e+10, 0, 'linear'); // Sliders for attack, sustain, decay, and amplitude e = SliderView.new( w, Rect.newBy(206, 203, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,21,54)).knobColor_(rgb(176,176,176)); f = SliderView.new( w, Rect.newBy(206, 226, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(42,120,81)).knobColor_(rgb(176,176,176)); g = SliderView.new( w, Rect.newBy(206, 250, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,148,109)).knobColor_(rgb(176,176,176)); h = SliderView.new( w, Rect.newBy(206, 275, 128, 20), "SliderView", 0, 0, 1, 0, 'linear') .backColor_(rgb(176,176,176)).knobColor_(rgb(176,176,176)); // Corresponding numerical views e1 = NumericalView.new( w, Rect.newBy(164, 203, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); f1 = NumericalView.new( w, Rect.newBy(164, 226, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); g1 = NumericalView.new( w, Rect.newBy(164, 249, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); h1 = NumericalView.new( w, Rect.newBy(164, 274, 38, 19), "NumericalView", 0, 0, 1, 0, 'linear'); // Synchronize numerical views with sliders e.action = { e1.value = e.value }; f.action = { f1.value = f.value }; g.action = { g1.value = g.value }; h.action = { h1.value = h.value }; // Synchronize sliders with numerical values e1.action = { e.value = e1.value }; f1.action = { f.value = f1.value }; g1.action = { g.value = g1.value }; h1.action = { h.value = h1.value }; // Corresponding labels StringView.new( w, Rect.newBy(92, 202, 61, 20), "Attack"); StringView.new( w, Rect.newBy(92, 226, 61, 20), "Sustain"); StringView.new( w, Rect.newBy(92, 250, 61, 20), "Decay"); StringView.new( w, Rect.newBy(92, 274, 61, 20), "Amplitude"); // Checkboxes v2 = CheckBoxView.new( w, Rect.newBy(358, 203, 128, 20), "Vibrato", 0, 0, 1, 0, 'linear'); amp2 = CheckBoxView.new( w, Rect.newBy(358, 227, 128, 20), "Amp. Modulation", 0, 0, 1, 0, 'linear'); // Pan pn2 = SliderView.new( w, Rect.newBy(358, 275, 128, 20), "SliderView", 0, -1, 1, 0, 'linear') .backColor_(rgb(0,0,0)).knobColor_(rgb(255,255,255)); StringView.new( w, Rect.newBy(406, 253, 63, 18), "Pan"); // THIRD PARTIAL // Value of the third partial in hertz StringView.new( w, Rect.newBy(9, 300, 128, 20), "3rd Partial"); third = NumericalView.new( w, Rect.newBy(12, 318, 64, 20), "NumericalView", 0, -1e+10, 1e+10, 0, 'linear'); // Sliders for attack, sustain, decay, and amplitude i = SliderView.new( w, Rect.newBy(206, 318, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,21,54)).knobColor_(rgb(176,176,176)); j = SliderView.new( w, Rect.newBy(206, 341, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(42,120,81)).knobColor_(rgb(176,176,176)); k = SliderView.new( w, Rect.newBy(206, 365, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,148,109)).knobColor_(rgb(176,176,176)); l = SliderView.new( w, Rect.newBy(206, 390, 128, 20), "SliderView", 0, 0, 1, 0, 'linear') .backColor_(rgb(176,176,176)).knobColor_(rgb(176,176,176)); // Corresponding numerical views i1 = NumericalView.new( w, Rect.newBy(164, 318, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); j1 = NumericalView.new( w, Rect.newBy(164, 341, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); k1 = NumericalView.new( w, Rect.newBy(164, 364, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); l1 = NumericalView.new( w, Rect.newBy(164, 389, 38, 19), "NumericalView", 0, 0, 1, 0, 'linear'); // Synchronize numerical views with sliders i.action = { i1.value = i.value }; j.action = { j1.value = j.value }; k.action = { k1.value = k.value }; l.action = { l1.value = l.value }; // Synchronize sliders with numerical values i1.action = { i.value = i1.value }; j1.action = { j.value = j1.value }; k1.action = { k.value = k1.value }; l1.action = { l.value = l1.value }; // Corresponding labels StringView.new( w, Rect.newBy(92, 317, 61, 20), "Attack"); StringView.new( w, Rect.newBy(92, 341, 61, 20), "Sustain"); StringView.new( w, Rect.newBy(92, 365, 61, 20), "Decay"); StringView.new( w, Rect.newBy(92, 389, 61, 20), "Amplitude"); // Checkboxes v3 = CheckBoxView.new( w, Rect.newBy(358, 318, 128, 20), "Vibrato", 0, 0, 1, 0, 'linear'); amp3 = CheckBoxView.new( w, Rect.newBy(358, 342, 128, 20), "Amp. Modulation", 0, 0, 1, 0, 'linear'); // Pan pn3 = SliderView.new( w, Rect.newBy(358, 505, 128, 20), "SliderView", 0, -1, 1, 0, 'linear') .backColor_(rgb(0,0,0)).knobColor_(rgb(255,255,255)); StringView.new( w, Rect.newBy(406, 369, 63, 18), "Pan"); // FOURTH PARTIAL // Value of the fourth partial in hertz StringView.new( w, Rect.newBy(9, 415, 128, 20), "4th Partial"); fourth = NumericalView.new( w, Rect.newBy(12, 433, 64, 20), "NumericalView", 0, -1e+10, 1e+10, 0, 'linear'); // Sliders for attack, sustain, decay, and amplitude m = SliderView.new( w, Rect.newBy(206, 433, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,21,54)).knobColor_(rgb(176,176,176)); n = SliderView.new( w, Rect.newBy(206, 456, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(42,120,81)).knobColor_(rgb(176,176,176)); o = SliderView.new( w, Rect.newBy(206, 480, 128, 20), "SliderView", 0, 0, 10, 0, 'linear') .backColor_(rgb(176,148,109)).knobColor_(rgb(176,176,176)); p = SliderView.new( w, Rect.newBy(206, 505, 128, 20), "SliderView", 0, 0, 1, 0, 'linear') .backColor_(rgb(176,176,176)).knobColor_(rgb(176,176,176)); // Corresponding numerical views m1 = NumericalView.new( w, Rect.newBy(164, 433, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); n1 = NumericalView.new( w, Rect.newBy(164, 456, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); o1 = NumericalView.new( w, Rect.newBy(164, 479, 38, 19), "NumericalView", 0, 0, 10, 0, 'linear'); p1 = NumericalView.new( w, Rect.newBy(164, 504, 38, 19), "NumericalView", 0, 0, 1, 0, 'linear'); // Synchronize numerical views with sliders m.action = { m1.value = m.value }; n.action = { n1.value = n.value }; o.action = { o1.value = o.value }; p.action = { p1.value = p.value }; // Synchronize sliders with numerical values m1.action = { m.value = m1.value }; n1.action = { n.value = n1.value }; o1.action = { o.value = o1.value }; p1.action = { p.value = p1.value }; // Corresponding labels StringView.new( w, Rect.newBy(92, 432, 61, 20), "Attack"); StringView.new( w, Rect.newBy(92, 456, 61, 20), "Sustain"); StringView.new( w, Rect.newBy(92, 480, 61, 20), "Decay"); StringView.new( w, Rect.newBy(92, 504, 61, 20), "Amplitude"); // Checkboxes v4 = CheckBoxView.new( w, Rect.newBy(358, 433, 128, 20), "Vibrato", 0, 0, 1, 0, 'linear'); amp4 = CheckBoxView.new( w, Rect.newBy(358, 457, 128, 20), "Amp. Modulation", 0, 0, 1, 0, 'linear'); // Pan pn4 = SliderView.new( w, Rect.newBy(358, 390, 128, 20), "SliderView", 0, -1, 1, 0, 'linear') .backColor_(rgb(0,0,0)).knobColor_(rgb(255,255,255)); StringView.new( w, Rect.newBy(406, 484, 63, 18), "Pan"); // CREATE ENVELOPES AND SINE WAVES wave1 = {Pan2.ar(EnvGen.ar(Env.linen(a.value, b.value, c.value, d.value), SinOsc.ar(ControlIn.kr(first) + (SinOsc.ar(5, 0, v1.value * 0.05 * ControlIn.kr(first))), 0, 1 + (amp1.value * (SinOsc.ar(3, 0, 1) - 1)))), pn1.value)}; wave2 = {Pan2.ar(EnvGen.ar(Env.linen(e.value, f.value, g.value, h.value), SinOsc.ar(ControlIn.kr(second) + (SinOsc.ar(5, 0, v2.value * 0.05 * ControlIn.kr(second))), 0, 1 + (amp2.value * (SinOsc.ar(3, 0, 1) - 1)))), pn2.value)}; wave3 = {Pan2.ar(EnvGen.ar(Env.linen(i.value, j.value, k.value, l.value), SinOsc.ar(ControlIn.kr(third) + (SinOsc.ar(5, 0, v3.value * 0.05 * ControlIn.kr(third))), 0, 1 + (amp3.value * (SinOsc.ar(3, 0, 1) - 1)))), pn3.value)}; wave4 = {Pan2.ar(EnvGen.ar(Env.linen(m.value, n.value, o.value, p.value), SinOsc.ar(ControlIn.kr(fourth) + (SinOsc.ar(5, 0, v4.value * 0.05 * ControlIn.kr(fourth))), 0, 1 + (amp4.value * (SinOsc.ar(3, 0, 1) - 1)))), pn4.value)}; // Mix the sounds final = (wave1 + wave2 + wave3 + wave4) * 0.25; )