Skip to content

Instantly share code, notes, and snippets.

@hoch
Last active February 3, 2016 00:12
Show Gist options
  • Save hoch/391d94ffd8f00c432c63 to your computer and use it in GitHub Desktop.
Save hoch/391d94ffd8f00c432c63 to your computer and use it in GitHub Desktop.
Chromium Web Audio Layout Test prototypes for Canopy
// @channels 3
// @sampleRate 128000
// @duration 1.5
function pitchToFrequency(pitch) {
return 440 * Math.pow(2, (Math.floor(pitch)-69)/12);
}
function pitchToPlaybackRate(pitch) {
return Math.pow(2, pitch/12);
}
function createSineWaveBuffer(context, frequency, duration) {
var length = duration * context.sampleRate;
var buffer = context.createBuffer(1, length, context.sampleRate);
var data = buffer.getChannelData(0);
var base = 2 * Math.PI * frequency / context.sampleRate;
for (var i = 0; i < data.length; i++)
data[i] = Math.sin(base * i);
return buffer;
}
var basePitch = 36;
var baseFrequency = pitchToFrequency(basePitch);
var testBuffer = createSineWaveBuffer(context, baseFrequency, 2 / baseFrequency);
console.log(testBuffer.duration);
var unitDuration = 0.025;
function runUnitTest(context, unitStart, unitPitch) {
var source1 = context.createBufferSource();
var source2 = context.createBufferSource();
var inverter = context.createGain();
var merger = context.createChannelMerger(3);
var env = context.createGain();
var expectedBuffer = createSineWaveBuffer(context, pitchToFrequency(unitPitch), unitDuration);
var targetRate = pitchToPlaybackRate(unitPitch - basePitch);
source1.buffer = expectedBuffer;
source1.loop = true;
source2.buffer = testBuffer;
source2.playbackRate.value = targetRate;
source2.loop = true;
source2.loopStart = 0.5 * testBuffer.duration;
source2.loopEnd = testBuffer.duration;
inverter.gain.value = -1.0;
source1.connect(merger, 0, 0);
source2.connect(merger, 0, 1);
source1.connect(merger, 0, 2);
source2.connect(inverter);
inverter.connect(merger, 0, 2);
merger.connect(env);
env.connect(context.destination);
source1.start(unitStart);
source1.stop(unitStart + unitDuration);
source2.start(unitStart);
source2.stop(unitStart + unitDuration);
// env.gain.setValueAtTime(1.0, unitStart);
// env.gain.setValueAtTime(1.0, unitStart + unitDuration - 0.005);
// env.gain.linearRampToValueAtTime(0.0, unitStart + unitDuration);
}
for (var iteration = 0; iteration < 60; iteration++) {
(function (i) {
context.suspend(unitDuration * i).then(function () {
runUnitTest(context, unitDuration * i, basePitch + i);
context.resume();
});
})(iteration);
}
context.oncomplete = function (event) {
var data = event.renderedBuffer.getChannelData(2);
var maxDiff = 0, index = -1;
for (var i = 0; i < data.length; i++) {
var diff = Math.abs(data[i]);
if (diff > maxDiff) {
maxDiff = diff;
index = i;
}
}
console.log('MAXDIFF = ' + maxDiff.toExponential() + ' (' + index + ')');
}
// @sampleRate 44160
// @duration 1.5
function pitchToFrequency(pitch) {
return 440 * Math.pow(2, (Math.floor(pitch)-69)/12);
}
function pitchToRate(pitch) {
return Math.pow(2, pitch/12);
}
function createSineWaveBuffer(context, frequency, duration) {
var length = duration * context.sampleRate;
var buffer = context.createBuffer(1, length, context.sampleRate);
var data = buffer.getChannelData(0);
var phase = 0, base = 2 * Math.PI * frequency / context.sampleRate;
for (var i = 0; i < length; i++)
data[i] = Math.sin(base * i);
return buffer;
}
var testBuffer = createSineWaveBuffer(context, pitchToFrequency(36), 5);
var testDuration = 0.025;
function test(context, testStart, testPitch) {
var source1 = context.createBufferSource();
var source2 = context.createBufferSource();
var inverter = context.createGain();
source1.buffer = createSineWaveBuffer(context, pitchToFrequency(testPitch), testDuration);
source2.buffer = testBuffer;
source2.playbackRate.value = pitchToRate(testPitch - 36);
inverter.gain.value = -1.0;
source1.connect(context.destination);
source2.connect(inverter)
inverter.connect(context.destination);
source1.start(testStart);
source1.stop(testStart + testDuration);
source2.start(testStart);
source2.stop(testStart + testDuration);
}
function onsuspended(iteration) {
return function () {
console.log('pitch = ', 36 + iteration);
test(context, testDuration * iteration, 36 + iteration);
context.resume();
};
}
// batch scheduling
for (var s = 0; s < 60; s++) {
context.suspend(testDuration * s).then(onsuspended(s));
}
context.oncomplete = function (event) {
var data = event.renderedBuffer.getChannelData(0);
var maxDiff = 0;
for (var i = 0; i < data.length; i++) {
var diff = Math.abs(data[i]);
if (diff > maxDiff)
maxDiff = diff;
}
console.log("MAXDIFF = ", maxDiff);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment