User:Lbattich/Sound Prototypes: Difference between revisions
No edit summary |
|||
Line 178: | Line 178: | ||
Works only on Firefox so far... | Works only on Firefox so far... | ||
* [http://lucasbattich.com/tests/12-tone5.html Last version HERE!] | |||
A different mode of displaying/visualizing the musical notes and pattern. | |||
* [http://lucasbattich.com/tests/12-tone2.html A VERY basic concept for a 12-tone composition generator... Based on Schoenberg's system and using a randomized approach.] | * [http://lucasbattich.com/tests/12-tone2.html A VERY basic concept for a 12-tone composition generator... Based on Schoenberg's system and using a randomized approach.] | ||
This version | This version just uses one octave, and it visualizes the notes in the traditional muscial notation (by using the [http://www.vexflow.com/docs/tutorial.html VexFlow]library - [http://www.vexflow.com/support/vexflow-min.js vexflow-min.js]) | ||
<source lang="html4strict"> | <source lang="html4strict"> |
Revision as of 01:05, 18 December 2014
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)
<!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>