b=931311 wait for HRTF panner to load impulse database before doing test

--HG--
extra : transplant_source : %2A%1F%D0kKSr%AA%8F%C1%26%E5%E6%EC%D5%CF%8C%A9%D11
This commit is contained in:
Karl Tomlinson 2013-11-09 14:07:50 +13:00
Родитель 5067764d69
Коммит 16c0538632
1 изменённых файлов: 58 добавлений и 30 удалений

Просмотреть файл

@ -27,7 +27,7 @@
//
// Web Audio doesn't provide a means to precisely time connect()s but we can
// test that the output of delay nodes matches the output from a reference
// PannerNodes that we know will not be GCed.
// PannerNode that we know will not be GCed.
//
// Another set of delay nodes is added upstream to ensure that the source node
// has removed its self-reference after dispatching its "ended" event.
@ -41,15 +41,14 @@ const blockSize = 128;
const bufferSize = 4096;
const pannerCount = bufferSize / blockSize;
// sourceDelayBufferCount should be long enough to allow the source node
// onended to finish. Because of the way blocks are processed in sets on
// the graph thread, this also affects when the graph thread receives the
// disconnect.
// onended to finish and remove the source self-reference.
const sourceDelayBufferCount = 3;
var gotEnded = false;
// ccDelayLength should be long enough to allow CC to run
var ccDelayBufferCount = 20;
const ccDelayLength = ccDelayBufferCount * bufferSize;
var ctx;
var testPanners = [];
var referencePanner;
var referenceProcessCount = 0;
@ -58,18 +57,27 @@ var referenceOutput = [new Float32Array(bufferSize),
var testProcessor;
var testProcessCount = 0;
function isChannelSilent(channel) {
for (var i = 0; i < channel.length; ++i) {
if (channel[i] != 0.0) {
dump("input at " + i + "\n");
return false;
}
}
return true;
}
function onReferenceOutput(e) {
switch(referenceProcessCount) {
case sourceDelayBufferCount - 1:
// The panners are about to finish.
if (!gotEnded) {
todo(false, "Oscillator hasn't ended. Increase sourceDelayBufferCount?");
todo(false, "Source hasn't ended. Increase sourceDelayBufferCount?");
}
// Connect each PannerNode output to a downstream DelayNode,
// and connect ScriptProcessors to compare test and reference panners.
var ctx = e.target.context;
var delayDuration = ccDelayLength / ctx.sampleRate;
for (var i = 0; i < pannerCount; ++i) {
var delay = ctx.createDelay(delayDuration);
@ -80,6 +88,9 @@ function onReferenceOutput(e) {
testProcessor = null;
testPanners = null;
// The panning effect is linear so only one reference panner is required.
// This also checks that the individual panners don't chop their output
// too soon.
referencePanner.connect(e.target);
// Assuming the above operations have already scheduled an event to run in
@ -101,16 +112,13 @@ function onReferenceOutput(e) {
e.target.onaudioprocess = null;
e.target.disconnect();
for (var i = 0; i < referenceOutput[0].length; ++i) {
if (referenceOutput[0][i] != 0.0) {
return; // good - a connection must have been received by the graph
}
}
// If the buffer is silent, there is probably not much point just
// increasing the buffer size, because, with the buffer size already
// significantly larger than panner tail time, it demonstrates that the
// lag between threads is much greater than the tail time.
todo(false, "Connections not detected.");
if (isChannelSilent(referenceOutput[0])) {
todo(false, "Connections not detected.");
}
}
referenceProcessCount++;
@ -131,36 +139,30 @@ function onTestOutput(e) {
}
function startTest() {
var ctx = new AudioContext();
// Place the listener to the side of the origin, where the panners are
// positioned, to maximize delay in one ear.
ctx.listener.setPosition(1,0,0);
// 0.002 is MaxDelayTimeSeconds in HRTFpanner.cpp
// and 512 is fftSize() at 48 kHz.
const expectedPannerTailTime = 0.002 * ctx.sampleRate + 512;
// Create some PannerNodes downstream from DelayNodes with delays long
// enough for their source oscillator to finish, dispatch its "ended" event
// enough for their source to finish, dispatch its "ended" event
// and release its playing reference. The DelayNodes should expire their
// tail-time references before the PannerNodes and so only the PannerNode
// lifetimes depends on their tail-time references. Many DelayNodes are
// created and timed to finish at different times so that one PannerNode
// will be finishing the block processed immediately after the connect is
// received.
var oscillator = ctx.createOscillator();
oscillator.start(0);
var source = ctx.createBufferSource();
// Just short of blockSize here to avoid rounding into the next block
oscillator.stop((blockSize - 1) / ctx.sampleRate);
oscillator.onended = function(e) {
var buffer = ctx.createBuffer(1, blockSize - 1, ctx.sampleRate);
for (var i = 0; i < buffer.length; ++i) {
buffer.getChannelData(0)[i] = Math.cos(Math.PI * i / buffer.length);
}
source.buffer = buffer;
source.start(0);
source.onended = function(e) {
gotEnded = true;
};
// The panner effect is linear so only one reference panner is required.
// This also checks that the individual panners don't chop their output too
// soon.
referencePanner = ctx.createPanner();
// Time the first test panner to finish just before downstream DelayNodes
// are about the be connected. Note that DelayNode lifetime depends on
// maxDelayTime so set that equal to the delay.
@ -171,11 +173,11 @@ function startTest() {
for (var i = 0; i < pannerCount; ++i) {
var delay = ctx.createDelay(delayDuration);
delay.delayTime.value = delayDuration;
oscillator.connect(delay);
source.connect(delay);
delay.connect(referencePanner)
var panner = ctx.createPanner();
delay.connect(panner)
delay.connect(panner);
testPanners[i] = panner;
delayDuration += blockSize / ctx.sampleRate;
@ -196,7 +198,33 @@ function startTest() {
testProcessor.connect(ctx.destination);
}
startTest();
function prepareTest() {
ctx = new AudioContext();
// Place the listener to the side of the origin, where the panners are
// positioned, to maximize delay in one ear.
ctx.listener.setPosition(1,0,0);
// A PannerNode will produce no output until it has loaded its HRIR
// database. Wait for this to load before starting the test.
var processor = ctx.createScriptProcessor(bufferSize, 2, 0);
referencePanner = ctx.createPanner();
referencePanner.connect(processor);
var oscillator = ctx.createOscillator();
oscillator.connect(referencePanner);
oscillator.start(0);
processor.onaudioprocess = function(e) {
if (isChannelSilent(e.inputBuffer.getChannelData(0)))
return;
oscillator.stop(0);
oscillator.disconnect();
referencePanner.disconnect();
e.target.onaudioprocess = null;
SimpleTest.executeSoon(startTest);
};
}
prepareTest();
</script>
</pre>
</body>