Skip to content

Commit

Permalink
Merge pull request #1 from floesche/master
Browse files Browse the repository at this point in the history
initial commit
  • Loading branch information
floesche authored Oct 31, 2020
2 parents 32af742 + f144697 commit 6a216ad
Show file tree
Hide file tree
Showing 6 changed files with 1,012 additions and 0 deletions.
9 changes: 9 additions & 0 deletions static/socket.io.slim.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions static/socket.io.slim.js.map

Large diffs are not rendered by default.

332 changes: 332 additions & 0 deletions templates/hello.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,332 @@
<!DOCTYPE html>
<html>
<!-- demo at https://CogNovo.eu/projects/project-17/pitchgrate -->

<head>
<meta charset="UTF-8">
<script src="/static/socket.io.slim.js"></script>
<script>
var socket = io();
socket.on('connect', function(){
socket.emit('my event', {data: 'I\'m connected!'});
});
socket.on('event', function(data){});
socket.on('disconnect', function(){});
</script>
<style>
html,
body {
padding: 0;
margin: 0;
overflow: hidden;
}

.box {
background-color: #000;
width: 5vw;
height: 100vh;
position: absolute;
}

#play {
position: absolute;
background-color: #CCCA;
margin: 20px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}
#play #btn {
text-align:center;
color: green;
font-size: 5em;

}
</style>
</head>

<body>

<div id="container"></div>
<div id="play">
After a click on play you will hear sounds. So please turn down the volume.
<div id="btn">Play</div></div>

<script>
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = null;
var isPlaying = false;
var sourceNode = null;
var counter = 500;

var theBuffer = null;

var buflen = 1024;
var buf = new Float32Array(buflen);

var rafID = null;

(function () {
audioContext = new AudioContext();
document.getElementById('play').addEventListener('click', function () {
audioContext.resume().then(() => {
console.log('Playback resumed successfully');
document.getElementById('play').hidden = true;
//toggleOscillator();
toggleLiveInput();
});
});

cont = document.getElementById("container");
for (num = -1; num < 10; num++) {
bx = document.createElement("div");
bx.id = "b" + num;
bx.className = "box";
bx.style.left = num * 10 + "vw";
cont.appendChild(bx);
}


// var request = new XMLHttpRequest();
// request.open("GET", "./AudioSlideExample.ogg", true);
// request.responseType = "arraybuffer";
// request.onload = function () {
// audioContext.decodeAudioData(request.response, function (buffer) {
// theBuffer = buffer;
// });
// }
// request.send();

// var interval = setInterval(runUpdate, 10);
//toggleLiveInput();
// togglePlayback();
//toggleOscillator();
})();

// var CENTER = 2016;
var CENTER = 1920;
var SENSITIVITY = 10;
function runUpdate(freq) {
console.log(freq);
console.log((CENTER-freq) / SENSITIVITY);
if (freq < CENTER) { counter = counter - (CENTER - freq) / SENSITIVITY; }
else { counter = counter + (freq - CENTER) / SENSITIVITY; }
if (counter < 200 || counter > 1000) {
counter = (counter % 100) + 500;
}
for (num = -1; num < 10; num++) {
bx = document.getElementById("b" + num);
bx.style.left = num * 10 + (counter % 100) / 10 + "vw";
}
// counter = counter + 1;
}

function error() {
alert('Stream generation failed.');
}

function getUserMedia(dictionary, callback) {
try {
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
navigator.getUserMedia(dictionary, callback, error);
} catch (e) {
alert('getUserMedia threw exception :' + e);
}
}

function toggleLiveInput() {
if (isPlaying) {
//stop playing and return
sourceNode.stop(0);
sourceNode = null;
analyser = null;
isPlaying = false;
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
window.cancelAnimationFrame(rafID);
}
getUserMedia(
{
"audio": {
"mandatory": {
"googEchoCancellation": "false",
"googAutoGainControl": "false",
"googNoiseSuppression": "false",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotStream);
}

function toggleOscillator() {
if (isPlaying) {
//stop playing and return
sourceNode.stop(0);
sourceNode = null;
analyser = null;
isPlaying = false;
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
window.cancelAnimationFrame(rafID);
return "play oscillator";
}
sourceNode = audioContext.createOscillator();
var gainNode = audioContext.createGain();
gainNode.connect(audioContext.destination);
sourceNode.connect(gainNode);
gainNode.gain.setValueAtTime(-.95, audioContext.currentTime);
for (i = 0; i < 10; i++) {
sourceNode.frequency.setValueAtTime(1000 + 100 * i, audioContext.currentTime + i + 2);
}
for (i = 11; i < 20; i++) {
sourceNode.frequency.setValueAtTime(1000 - 100 * (i - 11), audioContext.currentTime + i + 2);
}
for (i = 41; i < 60; i++) {
sourceNode.frequency.setValueAtTime(Math.random() * 1950 + 50, audioContext.currentTime + i / 2 + 2);
}

analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
sourceNode.connect(analyser);
analyser.connect(audioContext.destination);
sourceNode.start(0);
isPlaying = true;
isLiveInput = false;
sourceNode.stop(audioContext.currentTime + 35);
updatePitch();

return "stop";
}

function togglePlayback() {
if (isPlaying) {
//stop playing and return
sourceNode.stop(0);
sourceNode = null;
analyser = null;
isPlaying = false;
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
window.cancelAnimationFrame(rafID);
return "start";
}

sourceNode = audioContext.createBufferSource();
sourceNode.buffer = theBuffer;
sourceNode.loop = true;

analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
sourceNode.connect(analyser);
analyser.connect(audioContext.destination);
sourceNode.start(0);
isPlaying = true;
isLiveInput = false;
updatePitch();

return "stop";
}




function gotStream(stream) {
// Create an AudioNode from the stream.
mediaStreamSource = audioContext.createMediaStreamSource(stream);

// Connect it to the destination.
analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
mediaStreamSource.connect(analyser);
updatePitch();
}


var MIN_SAMPLES = 0; // will be initialized when AudioContext is created
var GOOD_ENOUGH_CORRELATION = 0.9; // this is the "bar" for how close a correlation needs to be

function autoCorrelate(buf, sampleRate) {
var SIZE = buf.length;
var MAX_SAMPLES = Math.floor(SIZE / 2);
var best_offset = -1;
var best_correlation = 0;
var rms = 0;
var foundGoodCorrelation = false;
var correlations = new Array(MAX_SAMPLES);

for (var i = 0; i < SIZE; i++) {
var val = buf[i];
rms += val * val;
}
rms = Math.sqrt(rms / SIZE);
if (rms < 0.01) // not enough signal
return -1;

var lastCorrelation = 1;
for (var offset = MIN_SAMPLES; offset < MAX_SAMPLES; offset++) {
var correlation = 0;

for (var i = 0; i < MAX_SAMPLES; i++) {
correlation += Math.abs((buf[i]) - (buf[i + offset]));
}
correlation = 1 - (correlation / MAX_SAMPLES);
correlations[offset] = correlation; // store it, for the tweaking we need to do below.
if ((correlation > GOOD_ENOUGH_CORRELATION) && (correlation > lastCorrelation)) {
foundGoodCorrelation = true;
if (correlation > best_correlation) {
best_correlation = correlation;
best_offset = offset;
}
} else if (foundGoodCorrelation) {
// short-circuit - we found a good correlation, then a bad one, so we'd just be seeing copies from here.
// Now we need to tweak the offset - by interpolating between the values to the left and right of the
// best offset, and shifting it a bit. This is complex, and HACKY in this code (happy to take PRs!) -
// we need to do a curve fit on correlations[] around best_offset in order to better determine precise
// (anti-aliased) offset.

// we know best_offset >=1,
// since foundGoodCorrelation cannot go to true until the second pass (offset=1), and
// we can't drop into this clause until the following pass (else if).
var shift = (correlations[best_offset + 1] - correlations[best_offset - 1]) / correlations[best_offset];
return sampleRate / (best_offset + (8 * shift));
}
lastCorrelation = correlation;
}
if (best_correlation > 0.01) {
// console.log("f = " + sampleRate/best_offset + "Hz (rms: " + rms + " confidence: " + best_correlation + ")")
return sampleRate / best_offset;
}
return -1;
// var best_frequency = sampleRate/best_offset;
}

function updatePitch(time) {
var cycles = new Array;
analyser.getFloatTimeDomainData(buf);
var ac = autoCorrelate(buf, audioContext.sampleRate);
// TODO: Paint confidence meter on canvasElem here.


if (ac == -1) {
// do something if not loud enough
} else {
runUpdate(ac);
}

if (!window.requestAnimationFrame)
window.requestAnimationFrame = window.webkitRequestAnimationFrame;
rafID = window.requestAnimationFrame(updatePitch);
}
// pitch detection from https://github.com/cwilso/PitchDetect/
</script>

</body>

</html>
Loading

0 comments on commit 6a216ad

Please sign in to comment.