> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://p5js.sketchpad.cc/sp/pad/view/ro.yC1XmiZ3EJ5/rev.4646
 * 
 * authors: 
 *   
 *   A J
 *   A J
 *   
 *   

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



/* 
  Pressing Control-R will render this p5.js sketch.
  p5.js, p5.dom.js, and p5.sound.js libraries are already loaded.
  To load more libraries/resources, use the "HTML" menu.
  To upload resources (including scripts), use the "Files" menu. 
*/

var i = 0; 
var chord = 3; //how many sounds are played
var envs = []; //array of envelopes for playing
var cnv; //html5 canvas for buttons
var button;
var buttons = new Array(10);
for (var i = 0; i < 10; i++) {
  buttons[i] = new Array(10);
}
//var noteEnvelopes = {};

var attackTime = 0.01;
var decayTime = 0.9;
var releaseTime = 0.5;

var lastThree = [null, null, null];


 
function createOscs(upperToneCount, startFreq) {
    var tones = [];
    var f = startFreq;  
    var maxF = 1000;
    var envelopes = [];
    for(i = 0; i<upperToneCount; i+=1)
    {        
        //joka ylä-äänes tehdään 5 ääneksestä: 2 matalempaa 1 luonnollinen harmonia ja 2 korkeampaa (normaalijakautunut)
        
        //mult = 0.05;
        //var sampleFreq = f-mult*40;
        var k = 0;
        //for(j = sampleFreq; j < sampleFreq+mult*100; j+=mult*20)
        //{
            j = f;
            osc = new p5.Oscillator();
            //osc.setType('tri');
            //console.log(i, amp);
            var amp = ylaAanesHiljeneminen(j, f) * startFreq/(2.0*f);
            amp = round(amp*10)/10;        
            //console.log(j, amp);
            //osc.amp(amp, 100);
            env = new p5.Env(attackTime, amp, decayTime, .0);
            osc.amp(env);
            //osc.phase(ylaAanesPhase(i, upperToneCount));
            osc.start();
            osc.freq(j);
            tones[i] = osc; //we dont wanna lose the oscillators or they cant be turned off.. lol!
            envs[i] = env; //we dont wanna lose envelopes
            env.play();
            k++;
        //}
        f = f*(i+2)/(i+1);
    }
    //noteEnvelopes["" + round(startFreq)] = [];
    for(i = 0; i<3; i++)
    {
        //noteEnvelopes["" + round(startFreq)][i] = envs[i];
        tones[i].stop(attackTime+decayTime);
        delete tones[i];
        delete envs[i];
        //clear();
    } 
    return envs;
}

function clear() {
    delete noteEnvelopes;    
}

function ylaAanesHiljeneminen(f, base) {
    //return 1/2.0;
    return pow( 2, pow( f-base, 2)/(-0.1) )/10.0;
    //return (pow(abs(220.0-f%base)/220.0,1000));
}

function ylaAanesPhase(i, maxI) {
    return random(0,100)/100.0;    
}

  // this is run once.   
function setup() {  
      
    // set the size of the canvas inside the window.
    createCanvas(400, 400);
      
    // set the background color
    background(255);
    
    // smooth edges
    smooth();
    
    // limit the number of frames per second
    frameRate(30);
    
    // set the width of the line. 
    strokeWeight(12);
    
    i = 10;
    //createOscs(i, 220);
    //createOscs(i, 440);
    fft = new p5.FFT();
    
    bW = 24;
    bH = 16;
    noteCount = 8;
    notes = ["A", "B", "C#", "D", "E", "F#", "G#"];
    n_i = 0;
    prev_x = 8;
    prev_y = 8; //these are used for calculating intervalls
    for(x = 28+50*0; x<width; x+=50)
    {
      x_i=(x-28)/50;
      n_j = n_i;
      for(y = 33+42*0; y<height; y+=42)
        {
          y_i = (y-33)/42;
          terssit = x_i-4;
          kvintit = y_i-4;
          intervalli = pow(10/8, terssit)*pow(2/3, kvintit);
          //intervalli = (prev_y+4)
          freq = 220.0*intervalli;
          freq = round(freq*10)/10;  
          button = createButton(notes[n_j]);
          button.position(x-bW/2,y-bH/2);
          button.mousePressed(getPlay(freq));
          buttons[x_i][y_i] = button;
          n_j = (n_j+4)%8;
        }
      prev_x += 2;
      n_i = (n_i+2)%8;
    }
    button = createButton("Chord");
    button.position(100, 100);
    button.mousePressed(playChord);
} 


  // this is run repeatedly.  
function draw() {  
    background(0);

  var spectrum = fft.analyze(); 
  noStroke();
  fill(0,255,0); // spectrum is green  
  for (var i = 0; i< spectrum.length; i++){
    var x = map(i, 0, spectrum.length, 0, width);
    var h = -height + map(spectrum[i], 0, 255, height, 0);
    rect(x, height, width / spectrum.length, h )
  }

  var waveform = fft.waveform();
  noFill();
  beginShape();
  stroke(255,0,0); // waveform is red  
  strokeWeight(1);
  for (var i = 0; i< waveform.length; i++){
    var x = map(i, 0, waveform.length, 0, width);
    var y = map( waveform[i], -1, 1, 0, height);
    vertex(x,y);
  }
  endShape();
  console.log("Waveform values:", waveform[10], waveform[100] )
  
  //cnv = new createCanvas(400,400);
}
    
function keyPressed() 
{
        setup()
}

function getPlay(baseFreq)
{
    //envelopes = createOscs(baseFreq);
    var F = function() { createOscs(3, baseFreq); console.log("Playing", baseFreq); addNote(F) };
    return F;   
}

function addNote(playFunction) 
{
    lastThree[0] = lastThree[1]; 
    lastThree[1] = lastThree[2]; 
    lastThree[2] = playFunction;
}

function playChord()
{
    timeout = 100;
    if (lastThree[0] != null)
        setTimeout(lastThree[0], 0);   
    if (lastThree[1] != null)
        setTimeout(lastThree[1], 1*timeout);
    if (lastThree[2] != null)
        setTimeout(lastThree[2], 2*timeout);
}

function playEnv()
{
    for(k = 0; k < 50; k+=1)
    {
        envs[k].play();
    }
}