notes.js
// chord generator : http://glessinger.de/joomla/media/grundwissen/Wie%20erstelle%20ich%20einen%20Septakkord.pdf let maj7_filter = [4,3,4]; let m7_filter = [3,4,3]; let _7_filter = [3,3,4]; let dim7_filter = [3,3,3]; let major_filter = [4,3]; let lydian_filter = [2,2,2,1,2,1]; let chord_filters = [maj7_filter,m7_filter,_7_filter,dim7_filter,major_filter,lydian_filter]; let bnchrs = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]; let basenote = 0; let current_filter = dim7_filter; function extractNotes( _cfilter, _basenote ){ let _arr = []; let stepi = float(basenote); _arr.push(bnchrs[stepi]); // add basic note //console.log("steppi_one:" + stepi); for(let i=0;i<_cfilter.length;i++){ stepi += float(_cfilter[i]); if(stepi > 11){ _arr.push(bnchrs[stepi-12]); }else{ _arr.push(bnchrs[stepi]); } } // clear note array ----------- notes = []; // fill octaves for(let j=0;j<3;j++){ for(let k=0;k<_arr.length;k++){ notes.push(_arr[k]+(j+3)); } } drawStageBasics(); }
sketch.js
let dragging = false; let notes = []; let synth; let pad = 0; let active_canvas; let static_canvas; let has_touch = false; function setup() { createCanvas(window.innerWidth, window.innerHeight); active_canvas = createGraphics(width,height); static_canvas = createGraphics(width,height); initSynth(); noStroke(); noSmooth(); pad = height*.1; extractNotes( current_filter, basenote ); has_touch = isTouchDevice(); //console.log(has_touch) } function isTouchDevice(){ return typeof window.ontouchstart !== 'undefined'; } function drawStageBasics(){ let ybit = (height*.8) /notes.length; static_canvas.clear(); static_canvas.textSize(14); static_canvas.textAlign(CENTER,CENTER); static_canvas.text(current_chord_id, width/2,height*.05); for(let i=0;i<notes.length;i++){ static_canvas.noStroke(); static_canvas.fill(0,22); static_canvas.textSize(7); static_canvas.textAlign(RIGHT,CENTER); static_canvas.text(notes[i],pad*.8,i*ybit+ybit/2+pad ); static_canvas.fill(111,155); static_canvas.rect(pad,i*ybit+pad,width-pad*2,1); //static_canvas.rect(pad,i*ybit+pad+ybit-2,width-pad*2,1); } let wbit = (width-pad*2)/bnchrs.length; // draw Bar lines ------------- for(let i=0;i<bnchrs.length;i++){ static_canvas.textAlign(CENTER); static_canvas.text( bnchrs[i], wbit*i+pad+wbit/2,height*.95 ); } // draw top selector! static_canvas.textSize(18); static_canvas.textAlign(CENTER); static_canvas.text( ">", width*.75,height*.05 ); static_canvas.text( "<", width*.25,height*.05 ); let bnbit = (width-pad*2)/12; static_canvas.noFill(); static_canvas.stroke(111); static_canvas.ellipse(basenote*bnbit+pad+bnbit/2,height*.95,33,33); } function draw() { background(255); active_canvas.noStroke(); active_canvas.fill(255,18); active_canvas.rect(0,0,width-pad*2,height-pad*2); image(active_canvas,pad,pad); image(static_canvas,0,0); if(dragging){ let nid = int(( (mouseY-pad) / (height*.8))*notes.length); pointed_note = notes[nid]; if(pointed_note != played_note){ if(synth.activeVoices>31){return;} const now = Tone.now(); synth.triggerAttackRelease(pointed_note,"8n",now); played_note = pointed_note; drawScale(nid); } let lpfilter_val = abs(sin( ((mouseX-pad) / (width-pad*2)) * PI+PI) *1000 ) +100; //console.log( lpfilter_val); filter.frequency.value = lpfilter_val; // filter.detune.value = int((mouseX-pad)*1.1); }else{ drawScale(-1); } } let filter; function initSynth(){ synth = new Tone.PolySynth(); synth.polyphony = 32; //synth.harmonicity.value = 2.1; console.log(synth); // synth.options.detune = 155; //synth.set({ detune: 155 }); synth.options.envelope.attack = .03; synth.options.envelope.release = .04; synth.options.envelope.sustain = .5; synth.options.envelope.decay = .1; synth.options.oscillator.modulationType = "sine"; synth.options.oscillator.harmonicity = .5; synth.options.oscillator.type = "sine2"; synth.options.oscillator.partials = [.9,.701 ]; // synth.options.oscillator.type = "fmtriangle"; synth.volume.value = -16; //console.log(synth); //synth.oscillator.type = "triangle"; // synth.oscillator.count = 18; // console.log(synth.oscillator.type); const now = Tone.now(); // synth.triggerAttackRelease("C4", "3n", now); const feedbackDelay = new Tone.FeedbackDelay(0.13, 0.3) ; const freeverb = new Tone.Freeverb(); freeverb.dampening = 1000; freeverb.wet.value = .3; freeverb.roomSize.value = .8; const chorus = new Tone.Chorus(3.5, 52.5, 0.9); filter = new Tone.Filter(1500, "bandpass"); synth.chain( filter, freeverb,chorus, Tone.Destination); } let pointed_note = ""; let played_note = ""; // ------------------------------------ function down(){ if(mouseX>pad && mouseY>pad){ dragging = true; } // change scale ------------ if(mouseY<pad*.7){ if(mouseX>width/2){ current_chord_id++; if( current_chord_id>chord_filters.length-1){ current_chord_id = 0; } }else{ current_chord_id--; if( current_chord_id<0){ current_chord_id = chord_filters.length-1; } } skipChordFilter(current_chord_id); } // change basenote if(mouseY>height*.92){ let npickid = int( ((mouseX-pad)/ (width-pad*2) ) * bnchrs.length ); basenote = npickid; //console.log(basenote); extractNotes( current_filter, basenote ); } } // ------------------------------------ function up(){ dragging = false; pointed_note = ""; played_note = ""; } // ------------------------------------ function mousePressed() { if( !has_touch){ down(); }} function mouseReleased() { if( !has_touch){ up(); }} function touchStarted() { if( has_touch){ down();}} function touchEnded() { if( has_touch){ up();}} // ------------------------------------ function drawScale(_tnid){ let ybit = (height*.8) /notes.length; pad = height*.1; for(let i=0;i<notes.length;i++){ if(i==_tnid){ active_canvas.noStroke(); active_canvas.fill("#4DC3FF"); active_canvas.rect(0,ybit*i,width-pad*2,ybit); } } } function setBaseNote(_e){ basenote = _e.value; extractNotes( current_filter, basenote ); } let current_chord_id = 0; function setChordFilter(_e){ // console.log("change filter: " + chord_filters[ _e.value]); current_chord_id = _e.value; current_filter = chord_filters[ _e.value]; extractNotes( current_filter, basenote ); } function skipChordFilter(_v){ current_filter = chord_filters[_v]; extractNotes( current_filter, basenote ); }
<!DOCTYPE html> <html lang="en"> <head> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.12/Tone.js" integrity="sha512-MyXAzMk3sw/i85erXXKd2+z2fzlmKD15TzKKwZd541ifNwUQ8Z73CfAwuyIPc0p5bL7xEA3u/l+/V0K9IyPbCg==" crossorigin="anonymous"></script> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> <meta charset="utf-8" /> </head> </head> <body> <script src="notes.js"></script> <script src="sketch.js"></script> <!-- <select id = "basenote_list" onchange = "setBaseNote(this)" > <option value="0" >C</option> <option value="1" >C#</option> <option value="2" >D</option> <option value="3" >D#</option> <option value="4" >E</option> </select> --> <!-- <select id = "chordfilter_list" onchange = "setChordFilter(this)" > <option value="0" >Maj7</option> <option value="1" >m7</option> <option value="2" >7</option> <option value="3" >Dim7</option> <option value="4" >major</option> </select> --> </body> </html>