//***************************************************************************************// // Dennis Walsh and Tom Catlin // // Assignment 3 // // Ear Master // //***************************************************************************************// // (Ideally designed for earphones) // // Ear Master is a little patch that tests the users ability to create a tone // // thats matches a random tone designed by the patch, but the catch is that one tone is // // played in one ear, while you try to match it using the other. So for the musically // // inclined who are able to match the tone, it really can be thought of as a test to // // see if both the users ears hear sound the same. For the rest of us, it provides a // // good lesson in creating tones from component tones. The random tone is made up of // // three sine waves of varying amplitudes and frequencies, and the user is given the // // the ability to create the same tone using three sine waves while varying their // // amplitude and frequency. Their is also a difficulty constant set in the first line // // of the patch. It basically controls the duration that the tones play for each time // // they play, and the shorter the duration the more difficult it is to match the sound. // // When the user gives up or thinks they have the tone on the money, they can see the // // frequencies and amplitudes of the component sine waves of the tone they were trying // // to match by clicking a button which says such. // // // //***************************************************************************************// ( // SET DIFFICULTY HERE (MUST BE BETWEEN 1-20) var kDifficulty = 10; // DECLARE ALL VARS // Main GUI window vars var window, left, top, right, bottom; // Constants var kMaxFreq, kMinFreq, kMaxAmp, kMinAmp; // Constant colors var kColorBG, kColorLabel1, kColorLabel2, kColorSlider; // Freq and Amp Control vars var sinFreq1, sinFreq2, sinFreq3, sinAmp1, sinAmp2, sinAmp3, numFreq1, numFreq2, numFreq3, numAmp1, numAmp2, numAmp3, initFreq1, initFreq2, initFreq3, initAmp1, initAmp2, initAmp3, randFreq1, randAmp1, randFreq2, randAmp2, randFreq3, randAmp3, randNumFreq1, randNumAmp1, randNumFreq2, randNumAmp2, randNumFreq3, randNumAmp3; // State control vars var revealButton, difficultySlide, difficulty, notBegin, beginButton; // Sine wave vars var sinOut, sin1, sin2, sin3, randSinOut, randSin1, randSin2, randSin3, spawnOut, randSpawnOut, envSin, audioOut; // DEFINE VARS // Main GUI window vars left = 100; top = 100; right = 730; bottom = 400; // Constants kMaxFreq = 2000; kMinFreq = 40; kMaxAmp = 0.33; kMinAmp = 0.00; // Color Constants kColorBG = rgb(0,0,0); kColorLabel1 = rgb(0,250,0); kColorLabel2 = rgb(250,0,250); kColorSlider = rgb(0,100,250); // Randomnize the initial values initFreq1 = kMinFreq + (kMaxFreq - kMinFreq).rand; initFreq2 = kMinFreq + (kMaxFreq - kMinFreq).rand; initFreq3 = kMinFreq + (kMaxFreq - kMinFreq).rand; initAmp1 = kMinAmp + (kMaxAmp - kMinAmp).rand; initAmp2 = kMinAmp + (kMaxAmp - kMinAmp).rand; initAmp3 = kMinAmp + (kMaxAmp - kMinAmp).rand; // Make the random frequency and amplitude for our random sound randFreq1 = kMinFreq + (kMaxFreq - kMinFreq).rand; randFreq2 = kMinFreq + (kMaxFreq - kMinFreq).rand; randFreq3 = kMinFreq + (kMaxFreq - kMinFreq).rand; randAmp1 = kMinAmp + (kMaxAmp - kMinAmp).rand; randAmp2 = kMinAmp + (kMaxAmp - kMinAmp).rand; randAmp3 = kMinAmp + (kMaxAmp - kMinAmp).rand; // The window window = GUIWindow.new("Ear Master", Rect.new(left, top, right, bottom)).backColor_(kColorBG); // Our labels StringView.new(window, Rect.newBy(45, 5, 100, 15), "FIRST SINE WAVE").labelColor_(kColorLabel1); StringView.new(window, Rect.newBy(50, 20, 100, 15), "Frequency").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(50, 55, 100, 15), "Amplitude").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(45, 100, 100, 15), "SECOND SINE WAVE").labelColor_(kColorLabel1); StringView.new(window, Rect.newBy(50, 115, 100, 15), "Frequency").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(50, 150, 100, 15), "Amplitude").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(45, 195, 100, 15), "THIRD SINE WAVE").labelColor_(kColorLabel1); StringView.new(window, Rect.newBy(50, 210, 100, 15), "Frequency").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(50, 245, 100, 15), "Amplitude").labelColor_(kColorLabel2); // And some more for the right side... StringView.new(window, Rect.newBy(375, 5, 250, 15), "THE DIFFICULTY IS CURRENTLY SET AT:").labelColor_(kColorLabel1); StringView.new(window, Rect.newBy(390, 20, 100, 15), "Harder").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(535, 20, 100, 15), "Easier").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(390, 70, 250, 15), "(Note: Difficulty can be set").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(390, 87, 250, 15), "in the first line of the file)").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(375, 135, 250, 15), "THE COMPONENTS OF THE RANDOM SOUND:").labelColor_(kColorLabel1); StringView.new(window, Rect.newBy(375, 190, 200, 15), "Frequencies:").labelColor_(kColorLabel2); StringView.new(window, Rect.newBy(482, 190, 200, 15), "Their Amplitudes:").labelColor_(kColorLabel2); // Our sliders sinFreq1 = SliderView.new(window, Rect.newBy(50, 40, 150, 10), "Freq1Slider", initFreq1, kMinFreq, kMaxFreq, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); sinAmp1 = SliderView.new(window, Rect.newBy(50, 75, 150, 10), "Amp1Slider", initAmp1, kMinAmp, kMaxAmp, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); sinFreq2 = SliderView.new(window, Rect.newBy(50, 135, 150, 10), "Freq2Slider", initFreq2, kMinFreq, kMaxFreq, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); sinAmp2 = SliderView.new(window, Rect.newBy(50, 170, 150, 10), "Amp2Slider", initAmp2, kMinAmp, kMaxAmp, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); sinFreq3 = SliderView.new(window, Rect.newBy(50, 230, 150, 10), "Freq3Slider", initFreq3, kMinFreq, kMaxFreq, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); sinAmp3 = SliderView.new(window, Rect.newBy(50, 265, 150, 10), "Amp3Slider", initAmp3, kMinAmp, kMaxAmp, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); difficultySlide = SliderView.new(window, Rect.newBy(410, 40, 150, 10), "DifficultySlide", kDifficulty, 1, 20, 0, 'linear').knobColor_(kColorSlider).backColor_(kColorLabel1); // Our numerical viewers numFreq1 = NumericalView.new(window, Rect.newBy(210, 37, 35, 15), "Freq1Num", initFreq1, kMinFreq, kMaxFreq, 1, 'linear'); numAmp1 = NumericalView.new(window, Rect.newBy(210, 72, 35, 15), "Amp1Num", initAmp1, kMinAmp, kMaxAmp, 0.01, 'linear'); numFreq2 = NumericalView.new(window, Rect.newBy(210, 132, 35, 15), "Freq2Num", initFreq2, kMinFreq, kMaxFreq, 1, 'linear'); numAmp2 = NumericalView.new(window, Rect.newBy(210, 167, 35, 15), "Amp2Num", initAmp2, kMinAmp, kMaxAmp, 0.01, 'linear'); numFreq3 = NumericalView.new(window, Rect.newBy(210, 227, 35, 15), "Freq3Num", initFreq3, kMinFreq, kMaxFreq, 1, 'linear'); numAmp3 = NumericalView.new(window, Rect.newBy(210, 262, 35, 15), "Amp3Num", initAmp3, kMinAmp, kMaxAmp, 0.01, 'linear'); // And all the ones for the random sound as well... randNumFreq1 = NumericalView.new(window, Rect.newBy(395, 210, 35, 15), "randFreq1Num", 0, kMinFreq, kMaxFreq, 1, 'linear'); randNumAmp1 = NumericalView.new(window, Rect.newBy(530, 210, 35, 15), "randAmp1Num", 0, kMinAmp, kMaxAmp, 0.01, 'linear'); randNumFreq2 = NumericalView.new(window, Rect.newBy(395, 235, 35, 15), "randFreq1Num", 0, kMinFreq, kMaxFreq, 1, 'linear'); randNumAmp2 = NumericalView.new(window, Rect.newBy(530, 235, 35, 15), "randAmp1Num", 0, kMinAmp, kMaxAmp, 0.01, 'linear'); randNumFreq3 = NumericalView.new(window, Rect.newBy(395, 260, 35, 15), "randFreq1Num", 0, kMinFreq, kMaxFreq, 1, 'linear'); randNumAmp3 = NumericalView.new(window, Rect.newBy(530, 260, 35, 15), "randAmp1Num", 0, kMinAmp, kMaxAmp, 0.01, 'linear'); // Bind the sliders and numerical viewers numFreq1.action = {sinFreq1.value = numFreq1.value}; sinFreq1.action = {numFreq1.value = sinFreq1.value}; numAmp1.action = {sinAmp1.value = numAmp1.value}; sinAmp1.action = {numAmp1.value = sinAmp1.value}; numFreq2.action = {sinFreq2.value = numFreq2.value}; sinFreq2.action = {numFreq2.value = sinFreq2.value}; numAmp2.action = {sinAmp2.value = numAmp2.value}; sinAmp2.action = {numAmp2.value = sinAmp2.value}; numFreq3.action = {sinFreq3.value = numFreq3.value}; sinFreq3.action = {numFreq3.value = sinFreq3.value}; numAmp3.action = {sinAmp3.value = numAmp3.value}; sinAmp3.action = {numAmp3.value = sinAmp3.value}; // A couple buttons and their actions revealButton = ButtonView.new(window, Rect.newBy(384, 160, 200, 20), "To reveal them, click here", 0, 0, 1, 0, 'linear').backColor_(kColorSlider); revealButton.action = { randNumFreq1.value = randFreq1; randNumAmp1.value = randAmp1; randNumFreq2.value = randFreq2; randNumAmp2.value = randAmp2; randNumFreq3.value = randFreq3; randNumAmp3.value = randAmp3; }; Synth.scope( { envSin = Env.sine(kDifficulty,1); // Get the values from the sliders and make the sines sin1 = SinOsc.ar(sinFreq1.kr, 0, sinAmp1.kr); sin2 = SinOsc.ar(sinFreq2.kr, 0, sinAmp2.kr); sin3 = SinOsc.ar(sinFreq3.kr, 0, sinAmp3.kr); // Get the random values and make the random sines randSin1 = SinOsc.ar(randFreq1, 0, randAmp1); randSin2 = SinOsc.ar(randFreq2, 0, randAmp2); randSin3 = SinOsc.ar(randFreq3, 0, randAmp3); // The user's sine sinOut = sin1 + sin2 + sin3; // The random sine randSinOut = randSin1 + randSin2 + randSin3; spawnOut = Spawn.ar({EnvGen.ar(envSin,sinOut)}, 1, kDifficulty); randSpawnOut = Spawn.ar({EnvGen.ar(envSin,randSinOut)}, 1, kDifficulty); [spawnOut, randSpawnOut] }); window.close; )