зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5067764d69
Коммит
16c0538632
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче