User:Lbattich/Sound Prototypes

From XPUB & Lens-Based wiki

Colour Tones

Colour Tones A colour is chosen at random from the RGB colour wheel. The RGB colour is the converted to the HLS system (Hue, Light, Saturation). The hue is extracted from this colour and a frequency value is corresponded to it. The gain of the the sound (volume) is relative to the light value.


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>