User:Lbattich/Sound Prototypes

From XPUB & Lens-Based wiki

Circle Scanner

Scans the canvas and produces sounds according to the image data form the canvas element (forefox only)

It has a svg line hovering on top to mark the scan (to keep the canvas image data intact while visualizing the scan)

Circle Scanner

<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    <title>Circle Scanner</title>
  </head>
  <body>
  	
    <button onclick="start()">scan</button>
    <button onclick="circle()">draw a circle</button>
    <button onclick="white()">clear up</button>
    <button onclick="silence()">stop</button>
    <br>
    <br>
    <svg id="line" height="300" style="position: absolute">
  		<line id= "bar" x1="0" y1="0" x2="0" y2="300" style="stroke:rgba(255,0,0,0.7);stroke-width:1" />
	</svg> 
    <canvas id="myCanvas" height="300"></canvas>
    
    <script>
    
    var context = new AudioContext();
    var osc1 = context.createOscillator();
    var osc2 = context.createOscillator();
    var osc3 = context.createOscillator();
    var osc4 = context.createOscillator();
    var osc5 = context.createOscillator();
    var gain1 = context.createGain(); // Create gain node 1
    var gain2 = context.createGain();
    var gain3 = context.createGain();
    var gain4 = context.createGain();
    var gain5 = context.createGain();
    
    var tid;
    var x = 0;
    
     // Connect oscillators to gains, and gain to context destination (speakers)
	osc1.connect(gain1);
	osc2.connect(gain2);
	osc3.connect(gain3);
	osc4.connect(gain4);
	osc5.connect(gain5);
	gain1.connect(context.destination);
	gain2.connect(context.destination);
	gain3.connect(context.destination);
	gain4.connect(context.destination);
	gain5.connect(context.destination);
	
    osc1.frequency.value = 500;
    osc2.frequency.value = 400;
    osc3.frequency.value = 300;
    osc4.frequency.value = 200;
    osc5.frequency.value = 100;
	gain1.gain.value = 0;
	gain2.gain.value = 0;
	gain3.gain.value = 0;
	gain4.gain.value = 0;
	gain5.gain.value = 0;
	osc1.start(0);
	osc2.start(0);
	osc3.start(0);
	osc4.start(0);
	osc5.start(0);
	
	var blackloud = true;
	var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth-30;
    document.getElementById("line").setAttribute("width", canvas.width);
    white();
    circle();
      
    function start(){
    if (tid){
    	clearTimeout(tid);
    	}
    	x = 0;
    	change();
    }
    
	function scan() {
	
		var data = ctx.getImageData(x,0,1,1).data;   // (x, y, width, height)
		var pixel = data[0] + data[1] + data[2];
		var scale = pixel / (255*3);  //scale from 0=black=quiet and 1=white=loud
		gain1.gain.value = blackloud ? 1-scale : scale;
		
		var data = ctx.getImageData(x,75,1,1).data;   // (x, y, width, height)
		var pixel = data[0] + data[1] + data[2];
		var scale = pixel / (255*3);  //0=black and 1=white
		gain2.gain.value = blackloud ? 1-scale : scale;
		
		var data = ctx.getImageData(x,150,1,1).data;   // (x, y, width, height)
		var pixel = data[0] + data[1] + data[2];
		var scale = pixel / (255*3);  //0=black and 1=white
		gain3.gain.value = blackloud ? 1-scale : scale;
		
		var data = ctx.getImageData(x,225,1,1).data;   // (x, y, width, height)
		var pixel = data[0] + data[1] + data[2];
		var scale = pixel / (255*3);  //0=black and 1=white
		gain4.gain.value = blackloud ? 1-scale : scale;
		
		var data = ctx.getImageData(x,299,1,1).data;   // (x, y, width, height)
		var pixel = data[0] + data[1] + data[2];
		var scale = pixel / (255*3);  //0=black and 1=white
		gain5.gain.value = blackloud ? 1-scale : scale;
		
        var bar = document.getElementById("bar");
        bar.setAttribute("x1", x);
        bar.setAttribute("x2", x);
	}
	
	function white() {
		ctx.fillStyle="white"; //first colour
		ctx.fillRect(0,0,canvas.width,canvas.height);
		ctx.fill();
	}
	
	function change() {
		x = x+1;
		scan();
		if (x < (canvas.width-1)) {
			tid = setTimeout(change,7);
		}
		else {
			x=0;
			tid = setTimeout(change,7);
		}
	}
	
  	function silence() {
  		gain1.gain.value = 0;
  		gain2.gain.value = 0;
  		gain3.gain.value = 0;
  		gain4.gain.value = 0;
  		gain5.gain.value = 0;
  		clearTimeout(tid);
  	}
  	function circle()
	{
var xc,yc,radio;
yc=Math.floor((canvas.height+1)*Math.random());
xc=Math.floor((canvas.width+1)*Math.random());
radio=Math.floor((200)*Math.random());
ctx.beginPath();
ctx.arc(xc,yc,radio,0,2*Math.PI);
var grd=ctx.createLinearGradient(xc-radio,yc-radio,xc+radio,yc+radio);
grd.addColorStop(0,colourme());
grd.addColorStop(1,colourme());
ctx.strokeStyle=grd;
ctx.lineWidth=Math.floor((100)*Math.random());
ctx.stroke();
}

function colourme()
{
var a = Math.floor(256*Math.random());
var b = Math.floor(256*Math.random());
var c = Math.floor(256*Math.random());
var colour = "rgb("+a+","+b+","+c+")";
return colour;
}
    </script>
  </body>
</html>

Audio Test - Play a random composition using the Oscillator wave generator on the Web Audio API

Works only on Firefox so far...

A different mode of displaying/visualizing the musical notes and pattern.


This version just uses one octave, and it visualizes the notes in the traditional muscial notation (by using the VexFlowlibrary - vexflow-min.js)

<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    <script src="vexflow-min.js"></script>
    <script src="jquery-1.11.1.min.js"></script>
    <title>Audio test - 12-tone</title>
  </head>
  <body>
  	<p style="font-size:1.5em;">Audio Test. 12-Tone Composition Generator</p>
  	<br>
  	<button onclick="makeRow()">make row</button>
    <button onclick="play()">play</button>
    <button onclick="silence()">stop</button>
    <br>
    <p style="font-size:1.2em;">Prime Row:</p><canvas id="primenotation" width="700" height="100"></canvas> 
    <br>
    <p style="font-size:1.2em; color:red;">Now Playing: <span id="current"></span></p>
    <canvas id="notation" width="700" height="100"></canvas> 
    <div style="color:red; font-size:1.5em;" width="700">
    <span id="dotspan" style="position: relative; left:55px"></span>
    </div>
    <br>
    <p>Duration of note now playing <input type="text" size="10" id="tm" value=""> <label for="tm"></label></p>
  	<p>Frequency:  <input type="text" size="7" id="fr" value=""> <label for="fr">Hz</label></p>
  	<p>Choose gain between 0.3 and 1.2:          <input type="text" size="7" id="gn" value=""> <label for="gn">Gain</label></p>
  	<p>Choose waveform:                          <input type="text" size="7" id="vw" value=""> <label for="vw">wave</label></p>
  	
  	<br>
  	<p><input type="text" size="25" id="tempo" value="120"> <label for="tempo">Tempo - Choose from 50 (largo) to 220 (prestissimo)</label></p>
  	<p><input type="text" size="25" id="row" value=""> <label for="row">Prime row</label></p>
  	<p><input type="text" size="25" id="rowr" value=""> <label for="rowr">Retrograde</label></p>
  	<p><input type="text" size="25" id="rowi" value=""> <label for="rowi">Inversion</label></p>
  	<p><input type="text" size="25" id="rowri" value=""> <label for="rowri">Retrograde Inversion</label></p>
  	<p><input type="text" size="25" id="currentR" value=""> <label for="currentR">Row currently being played</label></p>
  	<p><input type="text" size="25" id="times" value=""> <label for="times">Duration of each note in the row</label></p>
  	<p><input type="text" size="25" id="note" value=""> <label for="note">Note currently being played (0=C, 1=C#, etc...)</label></p>
  	<p><textarea rows="10" cols="70" id="log" value="">Log</Textarea></p>
  	
  
  
    <script>
    
    var context = new AudioContext();
    var tone = context.createOscillator();
    var gainNode1 = context.createGain(); // Create gain node 1
    var on=0;
    var tones = [0,1,2,3,4,5,6,7,8,9,10,11];
    var freqvalues = [261.63,277.18,293.66,311.13,329.63,349.23,369.99,392,415.30,440,466.16,493.88];
	var p = new Array();
    var inv = new Array();
    var r = new Array();
    var ri = new Array()
    var currentRow = new Array();
    var currentTime = new Array();
    var currentTimeName = new Array();
    var note = 0;
    var tempo = 500;
    var durations = [4,2,1,0.5,0.25,0.125,0.0625]; //semibreve to 64th-note
    var durationNames = ["Whole-note","Half-note","Quarter-note","Eighth-note","16th-note","32th-note","64th-note"];
    var dot = document.getElementById("dotspan");
    var primecanvas = document.getElementById("primenotation");
    var canvas = document.getElementById("notation");
    var currentText = document.getElementById("current");
    var str = "";
    
    jQuery.get('source.txt', function(data) {
    alert(data);
    //$('#log').html(data);
    //document.getElementById("log").value = data;
    	});
    
    tone.type = 0; // sine wave
    tone.frequency.value = 0;
	tone.connect(gainNode1); // Connect sound source tone to gain node 1
	gainNode1.connect(context.destination);
	gainNode1.gain.value = 0;
	tone.start(0);
	setup(canvas);
	setup(primecanvas);
	
	function setup(where){
	var renderer = new Vex.Flow.Renderer(where,
    Vex.Flow.Renderer.Backends.CANVAS);
  	var ctx = renderer.getContext();
  	var stave = new Vex.Flow.Stave(10, 0, 500);
  	stave.addClef("treble").setContext(ctx).draw();
  	}
	
	function drawNotes(who,where) {
	var canvasCTX = where.getContext("2d");
	canvasCTX.fillStyle="white";
	canvasCTX.fillRect(0,0,where.width,where.height);
	canvasCTX.fill();
	canvasCTX.fillStyle="black";
	var renderer = new Vex.Flow.Renderer(where,
    Vex.Flow.Renderer.Backends.CANVAS);

  	var ctx = renderer.getContext();
  	var stave = new Vex.Flow.Stave(10, 0, 500);
  	stave.addClef("treble").setContext(ctx).draw();
	
		// Create the notes
  	var notes = [
    new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["c#/4"], duration: "q" }).addAccidental(0, new Vex.Flow.Accidental("#")),
    new Vex.Flow.StaveNote({ keys: ["d/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["d#/4"], duration: "q" }).addAccidental(0, new Vex.Flow.Accidental("#")),
    new Vex.Flow.StaveNote({ keys: ["e/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["f/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["f#/4"], duration: "q" }).addAccidental(0, new Vex.Flow.Accidental("#")),
    new Vex.Flow.StaveNote({ keys: ["g/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["g#/4"], duration: "q" }).addAccidental(0, new Vex.Flow.Accidental("#")),
    new Vex.Flow.StaveNote({ keys: ["a/4"], duration: "q" }),
    new Vex.Flow.StaveNote({ keys: ["a#/4"], duration: "q" }).addAccidental(0, new Vex.Flow.Accidental("#")),
    new Vex.Flow.StaveNote({ keys: ["b/4"], duration: "q" })
  	];
  	var notes2 = [];
  	
  	// display notes
  	var all_notes = notes2.concat(notes[who[0]]).concat(notes[who[1]]).concat(notes[who[2]]).concat(notes[who[3]]).concat(notes[who[4]]).concat(notes[who[5]]).concat(notes[who[6]]).concat(notes[who[7]]).concat(notes[who[8]]).concat(notes[who[9]]).concat(notes[who[10]]).concat(notes[who[11]]);
	Vex.Flow.Formatter.FormatAndDraw(ctx, stave, all_notes);
  }
	
	function makeRow() {
		p = shuffle(tones);
		r = Array.prototype.slice.call(p);
		r.reverse();
		
		inv[0] = p[0];
		for (i = 1; i < 12; i++){
			inv[i] = inv[i-1] - (p[i] - p[i-1]);
			
			if (inv[i] == -1) {inv[i] = 11;}
			else if (inv[i] == -1) {inv[i] = 11;}
			else if (inv[i] == -2) {inv[i] = 10;}
			else if (inv[i] == -3) {inv[i] = 9;}
			else if (inv[i] == -4) {inv[i] = 8;}
			else if (inv[i] == -5) {inv[i] = 7;}
			else if (inv[i] == -6) {inv[i] = 6;}
			else if (inv[i] == -7) {inv[i] = 5;}
			else if (inv[i] == -8) {inv[i] = 4;}
			else if (inv[i] == -9) {inv[i] = 3;}
			else if (inv[i] == -10) {inv[i] = 2;}
			else if (inv[i] == -11) {inv[i] = 1;}
			else if (inv[i] == 12) {inv[i] = 0;}
			else if (inv[i] == 13) {inv[i] = 1;}
			else if (inv[i] == 14) {inv[i] = 2;}
			else if (inv[i] == 15) {inv[i] = 3;}
			else if (inv[i] == 16) {inv[i] = 4;}
			else if (inv[i] == 17) {inv[i] = 5;}
			else if (inv[i] == 18) {inv[i] = 6;}
			else if (inv[i] == 19) {inv[i] = 7;}
			else if (inv[i] == 20) {inv[i] = 8;}
			else if (inv[i] == 21) {inv[i] = 9;}
			else if (inv[i] == 22) {inv[i] = 10;}
			else if (inv[i] == 23) {inv[i] = 11;}
			}
		
		ri = Array.prototype.slice.call(inv);
		ri.reverse();
		note = 0;
		
		// choose tempo between 50 and 230 (BPM) - save value in ms
		tempo = 60000 / (50 + Math.floor(181*Math.random()));
		
		drawNotes(p,primecanvas);
		str="prime:,"+p+",";
		chooseRow();
		
		document.getElementById("row").value = p; // display
		document.getElementById("rowr").value = r; // display
		document.getElementById("rowi").value = inv; // display
		document.getElementById("rowri").value = ri; // display
		document.getElementById("tempo").value = 60000/tempo;
			
	}
	
	//frequencies:
	//http://www.phy.mtu.edu/~suits/notefreqs.html
	
	
	function chooseRow() {
		var numb=Math.floor(Math.random()*4);
        if (numb==0){currentRow = Array.prototype.slice.call(p);currentText.innerHTML="Prime Row";} // prime
        else if (numb==1){currentRow = Array.prototype.slice.call(r);currentText.innerHTML="Retrograde";} // retro
        else if (numb==2){currentRow = Array.prototype.slice.call(inv);currentText.innerHTML="Inversion";} // inv
        else if (numb==3){currentRow = Array.prototype.slice.call(ri);currentText.innerHTML="Retrograde Inversion";} // retro in
        
		for (i = 0; i < 12; i++){
			var rdmTime = Math.floor(7*Math.random());
			currentTime[i] = durations[rdmTime];
			currentTimeName[i] = durationNames[rdmTime];
        }
        document.getElementById("currentR").value = currentRow; // display
        document.getElementById("times").value = currentTime; // display
        drawNotes(currentRow,canvas);
        record();
        
	}
	
	
	function shuffle(row){
    	for (var i = row.length-1; i >=0; i--) {  
        	var index = Math.floor(Math.random()*(i+1)); 
        	var tempvalue = row[index]; 
        	row[index] = row[i]; 
        	row[i] = tempvalue;
    	}
    	return row;
	}
	
		function play(){
		
			if (on==0){
				on=1;
				makeRow();
				changeNote();
			}
		}

	function changeNote() {
		if (on==1){
		// random gain between 0.5 and 1.5
			var gain = 0.5+Math.random();
			gainNode1.gain.value = gain;
			document.getElementById("gn").value = gain;
		
		// play current note
			var n = currentRow[note];
			tone.frequency.value = freqvalues[n];
			document.getElementById("fr").value = freqvalues[n];
			document.getElementById("note").value = n;
			dot.style.left = 55+(42*note)+"px";
			
			
		//random wave shape
			var wave = Math.floor(4*Math.random());
			tone.type = wave; 
			if (wave==0){document.getElementById("vw").value="Sine";}
        	else if (wave==1){document.getElementById("vw").value="Square";}
        	else if (wave==2){document.getElementById("vw").value="Sawtooth";}
        	else if (wave==3){document.getElementById("vw").value="Triangle";}
        
		// duration of note
			var time = currentTime[note] * tempo;
			document.getElementById("tm").value = currentTimeName[note];
			
			note++;
			if (note==12){
				note=0;
				dot.style.left = "55px";
				chooseRow();
			}
			setTimeout(function(){changeNote()},time);
        }
	}
	function record() {
		for (var i=0;i<12;i++){
     			str = str+currentRow[i]+"/"+currentTime[i]+",";
     			}
     	document.getElementById("log").value = str;
     		}
     		
  	function silence() {
  		tone.frequency.value = 0;
  		gainNode1.gain.value = 0;
  		note=0;
  		on=0;
  	}
  
    </script>
  </body>
</html>

Code for the Audio Test:

<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    <title>Audio test - Play a random composition</title>
  </head>
  <body>
  	<p>Choose frequency between 80Hz and 880Hz: <input type="text" size="7" id="fr" value=""> <label for="fr">Hz</label></p>
  	<p>Choose gain between 0.2 and 1.2: <input type="text" size="7" id="gn" value=""> <label for="gn">Gain</label></p>
  	<p>Choose duration between 1/50sec and 1sec: <input type="text" size="7" id="tm" value=""> <label for="tm">Seconds</label></p>
  	<p>Choose waveform: <input type="text" size="7" id="vw" value=""> <label for="tm">wave</label></p>
  	<br>
    <button onclick="play()">play</button>
    <button onclick="silence()">stop</button>
    <script>
    
    var context = new AudioContext();
    var tone = context.createOscillator();
    var gainNode1 = context.createGain(); // Create gain node 1
    var on=0;
    
    tone.type = 0; // sine wave
    tone.frequency.value = 0;
	tone.connect(gainNode1); // Connect sound source tone to gain node 1
	gainNode1.connect(context.destination);
	gainNode1.gain.value = 0;
	tone.start(0);
	
	function play(){
		if (on==0){
			on=1;
			change();
		}
	}

	function change() {
		if (on==1){
		// random gain between 0.2 and 1.2
			var gain = 0.2+Math.random();
			gainNode1.gain.value = gain;
			document.getElementById("gn").value = gain;
		
		// random frequency between 80 and 880
			var freq = 80 + Math.floor(801*Math.random());
			tone.frequency.value = freq;
			document.getElementById("fr").value = freq;
		
		//random wave shape
			var wave = Math.floor(4*Math.random());
			tone.type = wave; 
			if (wave==0){document.getElementById("vw").value="Sine";}
        		else if (wave==1){document.getElementById("vw").value="Square";}
        		else if (wave==2){document.getElementById("vw").value="Sawtooth";}
        		else if (wave==3){document.getElementById("vw").value="Triangle";}
        
		// random duration of note -  1/50sec to 1sec
			var time = 20 + Math.floor(901*Math.random());
			document.getElementById("tm").value = time/1000;
			setTimeout(function(){change()},time);
        	}
	}
	
  	function silence() {
  		tone.frequency.value = 0;
  		gainNode1.gain.value = 0;
  		on=0;
  	}
    </script>
  </body>
</html>