// Chord Builder // by Steve Hsu and Jeremy Robin // our patch is called chord builder and it allows students to see ready made chords and build their own // this is a little exercise that gives someone the experience of building chords out of any of the // 12 semitones in the western scale. There are a bunch of basic built in chords, major, minor, seventh, // augmented, diminished, fourth, and fifth // just to give the user (if they have no musical experience) a little bit of an idea where to start. // Also, the visual representation of the chord on the left gives the user a good idea of exactly how the chord is // formed. we also experimented a bit with panning, scaling to make sure that there is no clipping, and vibrato. ( // Declare our variables var tonic, st, w, major, minor, fifth, seventh, diminished, augmented, fourth, scale, sum, balance, vrate, vdepth; var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; // set the ratio of one semitone to the next semitone st = 1.059465; // The GUI window w = GUIWindow.new("Chord Builder", Rect.newBy(167, 74, 450, 350)) .backColor_(rgb(156,220,220)); // The semitone checkboxes StringView.new( w, Rect.newBy(50, 15, 128, 20), "Semitones"); s0 = CheckBoxView.new( w, Rect.newBy(30, 50, 128, 20), "Tonic", 1, 0, 1, 0, 'linear'); s1 = CheckBoxView.new( w, Rect.newBy(30, 70, 128, 20), "1st Semitone", 0, 0, 1, 0, 'linear'); s2 = CheckBoxView.new( w, Rect.newBy(30, 90, 128, 20), "2nd Semitone", 0, 0, 1, 0, 'linear'); s3 = CheckBoxView.new( w, Rect.newBy(30, 110, 128, 20), "3rd Semitone", 0, 0, 1, 0, 'linear'); s4 = CheckBoxView.new( w, Rect.newBy(30, 130, 128, 20), "4th Semitone", 1, 0, 1, 0, 'linear'); s5 = CheckBoxView.new( w, Rect.newBy(30, 150, 128, 20), "5th Semitone", 0, 0, 1, 0, 'linear'); s6 = CheckBoxView.new( w, Rect.newBy(30, 170, 128, 20), "6th Semitone", 0, 0, 1, 0, 'linear'); s7 = CheckBoxView.new( w, Rect.newBy(30, 190, 128, 20), "7th Semitone", 1, 0, 1, 0, 'linear'); s8 = CheckBoxView.new( w, Rect.newBy(30, 210, 128, 20), "8th Semitone", 0, 0, 1, 0, 'linear'); s9 = CheckBoxView.new( w, Rect.newBy(30, 230, 128, 20), "9th Semitone", 0, 0, 1, 0, 'linear'); s10 = CheckBoxView.new( w, Rect.newBy(30, 250, 128, 20), "10th Semitone", 0, 0, 1, 0, 'linear'); s11 = CheckBoxView.new( w, Rect.newBy(30, 270, 128, 20), "11th Semitone", 0, 0, 1, 0, 'linear'); // The prebuilt chords StringView.new( w, Rect.newBy(190, 15, 128, 20), "Prebuilt Chords"); major = RadioButtonView.new( w, Rect.newBy(200, 50, 60, 20), "Major", 1, 0, 1, 0, 'linear'); minor = RadioButtonView.new( w, Rect.newBy(200, 70, 128, 20), "Minor", 0, 0, 1, 0, 'linear'); seventh = RadioButtonView.new( w, Rect.newBy(200, 90, 128, 20), "Seventh", 0, 0, 1, 0, 'linear'); diminished = RadioButtonView.new( w, Rect.newBy(200, 110, 128, 20), "Diminished", 0, 0, 1, 0, 'linear'); augmented = RadioButtonView.new( w, Rect.newBy(200, 130, 128, 20), "Augmented", 0, 0, 1, 0, 'linear'); fourth = RadioButtonView.new( w, Rect.newBy(200, 150, 128, 20), "Fourth", 0, 0, 1, 0, 'linear'); fifth = RadioButtonView.new( w, Rect.newBy(300, 50, 128, 20), "Fifth", 0, 0, 1, 0, 'linear'); // The slider controls StringView.new( w, Rect.newBy(350, 170, 128, 20), "Tonic"); tonic = SliderView.new( w, Rect.newBy(200, 170, 128, 20), "Tonic", 255.067, 200, 400, 0, 'exponential') .backColor_(rgb(77,138,176)).labelColor_(rgb(79,176,166)).knobColor_(rgb(176,120,122)); StringView.new( w, Rect.newBy(350, 200, 128, 20), "Balance"); balance = SliderView.new( w, Rect.newBy(200, 200, 128, 20), "Balance", 0, -1, 1, 0, 'linear') .backColor_(rgb(77,138,176)).labelColor_(rgb(79,176,166)).knobColor_(rgb(176,120,122)); StringView.new( w, Rect.newBy(350, 230, 128, 20), "Vibrato Rate"); vrate = SliderView.new( w, Rect.newBy(200, 230, 128, 20), "VibratoRate", 0, 0, 1, 0, 'linear') .backColor_(rgb(77,138,176)).labelColor_(rgb(79,176,166)).knobColor_(rgb(176,120,122)); StringView.new( w, Rect.newBy(350, 260, 128, 20), "Vibrato Depth"); vdepth = SliderView.new( w, Rect.newBy(200, 260, 128, 20), "VibratoDepth", 0, 0, 1, 0, 'linear') .backColor_(rgb(77,138,176)).labelColor_(rgb(79,176,166)).knobColor_(rgb(176,120,122)); // Ensure when a prebuilt chord is selected, the other prebuilt chords are deselected and // the proper semitones are turned on major.action = { if(major.value == 1, { // deselect the other prebuilt chords minor.value = 0; seventh.value = 0; diminished.value = 0; augmented.value = 0; fourth.value = 0; // turn on the major semitones s1.value = 0;s2.value = 0;s3.value = 0;s5.value = 0;s6.value = 0;s8.value = 0;s9.value =0; s10.value = 0;s11.value = 0; s0.value = 1; s4.value = 1; s7.value = 1; } ); }; minor.action = { if(minor.value == 1, { // deselect the other prebuilt chords major.value = 0; seventh.value = 0; diminished.value = 0; augmented.value = 0; fourth.value = 0; // turn on the minor semitones s1.value = 0;s2.value = 0;s4.value = 0;s5.value =0; s6.value = 0;s8.value = 0;s9.value = 0;s10.value = 0;s11.value = 0; s0.value = 1;s3.value = 1;s7.value = 1; } ); }; seventh.action = { if(seventh.value == 1, { // deselect the other prebuilt chords major.value = 0; minor.value = 0;diminished.value = 0; augmented.value = 0; fourth.value = 0; // turn on the seventh semitones s1.value = 0;s2.value = 0;s3.value = 0;s5.value = 0;s6.value = 0;s8.value = 0;s9.value = 0;s11.value = 0; s0.value = 1;s4.value = 1;s7.value = 1;s10.value = 1; } ); }; diminished.action = { if(diminished.value == 1, { // deselect the other prebuilt chords major.value = 0; minor.value = 0; augmented.value = 0;seventh.value = 0; fourth.value = 0; // turn on the diminished semitones s1.value = 0;s2.value = 0;s4.value = 0;s7.value = 0;s5.value = 0;s6.value = 0;s8.value = 0;s9.value = 0;s11.value = 0;s10.value = 0; s0.value = 1;s3.value = 1;s6.value = 1; } ); }; augmented.action = { if(augmented.value == 1, { // deselect the other prebuilt chords major.value = 0; minor.value = 0; diminished.value = 0;seventh.value = 0; fourth.value = 0; // turn on the augmented semitones s1.value = 0;s2.value = 0;s3.value = 0;s7.value = 0;s10.value = 0; s5.value = 0;s6.value = 0;s8.value = 0;s9.value = 0;s11.value = 0; s0.value = 1;s4.value = 1;s8.value = 1; } ); }; fourth.action = { if(fourth.value == 1, { // deselect the other prebuilt chords major.value = 0; minor.value = 0; diminished.value = 0;seventh.value = 0;augmented.value = 0; // turn on the fourth semitones s1.value = 0;s2.value = 0;s3.value = 0; s4.value = 0;s6.value = 0; s7.value = 0;s10.value = 0; s8.value = 0;s11.value = 0; s0.value = 1;s5.value = 1;s9.value = 1; } ); }; fifth.action = { if(fifth.value == 1, { // deselect the other prebuilt chords major.value = 0; minor.value = 0; diminished.value = 0;seventh.value = 0;augmented.value = 0;fourth.value = 0; // turn on the fifth semitones s1.value = 0;s5.value = 0;s3.value = 0; s4.value = 0;s6.value = 0; s0.value = 0;s10.value = 0; s8.value = 0;s9.value = 0; s7.value = 1;s11.value = 1;s2.value = 1; } ); }; // If the user clicks on one of the semitones, deslect the prebuilt chords s0.action = { major.value = 0; minor.value = 0; augmented.value = 0; diminished.value = 0; fourth.value = 0; seventh.value = 0; fifth.value = 0; }; s1.action = s0.action; s2.action = s0.action; s3.action = s0.action; s4.action = s0.action; s5.action = s0.action; s6.action = s0.action; s7.action = s0.action; s8.action = s0.action; s9.action = s0.action; s10.action = s0.action; s11.action = s0.action; { // Now determine whether or not to sound a semitone by its checkbox value (0 or 1) a = SinOsc.ar(Plug.kr(tonic) * (st ** 0), 0, Plug.kr(s0)); b = SinOsc.ar(Plug.kr(tonic) * (st ** 1), 0, Plug.kr(s1)); c = SinOsc.ar(Plug.kr(tonic) * (st ** 2), 0, Plug.kr(s2)); d = SinOsc.ar(Plug.kr(tonic) * (st ** 3), 0, Plug.kr(s3)); e = SinOsc.ar(Plug.kr(tonic) * (st ** 4), 0, Plug.kr(s4)); f = SinOsc.ar(Plug.kr(tonic) * (st ** 5), 0, Plug.kr(s5)); g = SinOsc.ar(Plug.kr(tonic) * (st ** 6), 0, Plug.kr(s6)); h = SinOsc.ar(Plug.kr(tonic) * (st ** 7), 0, Plug.kr(s7)); i = SinOsc.ar(Plug.kr(tonic) * (st ** 8), 0, Plug.kr(s8)); j = SinOsc.ar(Plug.kr(tonic) * (st ** 9), 0, Plug.kr(s9)); k = SinOsc.ar(Plug.kr(tonic) * (st ** 10), 0, Plug.kr(s10)); l = SinOsc.ar(Plug.kr(tonic) * (st ** 11), 0, Plug.kr(s11)); // Determine the scaling factor to avoid clipping regardless of // how many semitones are turned on. The 1 factor at the end is // to avoid the divide by zero problem and // a popping problem if it is too low. scale = 1 / (Plug.kr(s0) + Plug.kr(s1) + Plug.kr(s2) + Plug.kr(s3) + Plug.kr(s4) + Plug.kr(s5) + Plug.kr(s6) + Plug.kr(s7) + Plug.kr(s8) + Plug.kr(s9) + Plug.kr(s10) + Plug.kr(s11) + 1); // Add the semitones together and scale them sum = 0.5 * scale * (a + b + c + d + e + f + g + h + i + j + k + l); // Take care of the panning sum = Pan2.ar(sum, Plug.kr(balance), 1); // Play the sound with 'vibrato' (1 + SinOsc.ar((10 * Plug.kr(vrate)), 0, (2 * Plug.kr(vdepth)))) * sum }.play; w.close; // close the window when the sound is stopped )