var context = null; var sp = null; var renderNumberOfChannels = 8; var singleTestFrameLength = 8; var testBuffers;
// A list of connections to an AudioNode input, each of which is to be used in one or more specific test cases.
// Each element in the list is a string, with the number of connections corresponding to the length of the string,
// and each character in the string is from '1' to '8' representing a 1 to 8 channel connection (from an AudioNode output).
// For example, the string "128" means 3 connections, having 1, 2, and 8 channels respectively. var connectionsList = [];
for (var i = 1; i <= 8; ++i) {
connectionsList.push(i.toString());
for (var j = 1; j <= 8; ++j) {
connectionsList.push(i.toString() + j.toString());
}
}
var numberOfTests = mixingRulesList.length * connectionsList.length;
// Create an n-channel buffer, with all sample data zero except for a shifted impulse.
// The impulse position depends on the channel index.
// For example, for a 4-channel buffer:
// channel0: 1 0 0 0 0 0 0 0
// channel1: 0 1 0 0 0 0 0 0
// channel2: 0 0 1 0 0 0 0 0
// channel3: 0 0 0 1 0 0 0 0
function createTestBuffer(numberOfChannels) { var buffer = context.createBuffer(numberOfChannels, singleTestFrameLength, context.sampleRate);
for (var i = 0; i < numberOfChannels; ++i) { var data = buffer.getChannelData(i);
data[i] = 1;
}
return buffer;
}
// Discrete channel interpretation mixing:
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix
// up-mix by filling channels until they run out then ignore remaining dest channels.
// down-mix by filling as many channels as possible, then dropping remaining source channels.
function discreteSum(sourceBuffer, destBuffer) {
if (sourceBuffer.length != destBuffer.length) {
is(sourceBuffer.length, destBuffer.length, "source and destination buffers should have the same length");
}
var numberOfChannels = Math.min(sourceBuffer.numberOfChannels, destBuffer.numberOfChannels); var length = sourceBuffer.length;
for (var c = 0; c < numberOfChannels; ++c) { varsource = sourceBuffer.getChannelData(c); var dest = destBuffer.getChannelData(c);
for (var i = 0; i < length; ++i) {
dest[i] += source[i];
}
}
}
// Speaker channel interpretation mixing:
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix
// eslint-disable-next-line complexity
function speakersSum(sourceBuffer, destBuffer)
{ var numberOfSourceChannels = sourceBuffer.numberOfChannels; var numberOfDestinationChannels = destBuffer.numberOfChannels; var length = destBuffer.length;
if ((numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) ||
(numberOfDestinationChannels == 4 && numberOfSourceChannels == 1)) {
// Handle mono -> stereo/Quad case (summing mono channel into both left and right). varsource = sourceBuffer.getChannelData(0); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1);
for (var i = 0; i < length; ++i) {
destL[i] += source[i];
destR[i] += source[i];
}
} else if ((numberOfDestinationChannels == 4 && numberOfSourceChannels == 2) ||
(numberOfDestinationChannels == 6 && numberOfSourceChannels == 2)) {
// Handle stereo -> Quad/5.1 case (summing left and right channels into the output's left and right). var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1);
for (var i = 0; i < length; ++i) {
destL[i] += sourceL[i];
destR[i] += sourceR[i];
}
} else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
// Handle stereo -> mono case. output += 0.5 * (input.L + input.R). var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var dest = destBuffer.getChannelData(0);
for (var i = 0; i < length; ++i) {
dest[i] += 0.5 * (sourceL[i] + sourceR[i]);
}
} else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 4) {
// Handle Quad -> mono case. output += 0.25 * (input.L + input.R + input.SL + input.SR). var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceSL = sourceBuffer.getChannelData(2); var sourceSR = sourceBuffer.getChannelData(3); var dest = destBuffer.getChannelData(0);
for (var i = 0; i < length; ++i) {
dest[i] += 0.25 * (sourceL[i] + sourceR[i] + sourceSL[i] + sourceSR[i]);
}
} else if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 4) {
// Handle Quad -> stereo case. outputLeft += 0.5 * (input.L + input.SL),
// outputRight += 0.5 * (input.R + input.SR). var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceSL = sourceBuffer.getChannelData(2); var sourceSR = sourceBuffer.getChannelData(3); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1);
for (var i = 0; i < length; ++i) {
destL[i] += 0.5 * (sourceL[i] + sourceSL[i]);
destR[i] += 0.5 * (sourceR[i] + sourceSR[i]);
}
} else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 4) {
// Handle Quad -> 5.1 case. outputLeft += (inputL, inputR, 0, 0, inputSL, inputSR) var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceSL = sourceBuffer.getChannelData(2); var sourceSR = sourceBuffer.getChannelData(3); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1); var destSL = destBuffer.getChannelData(4); var destSR = destBuffer.getChannelData(5);
for (var i = 0; i < length; ++i) {
destL[i] += sourceL[i];
destR[i] += sourceR[i];
destSL[i] += sourceSL[i];
destSR[i] += sourceSR[i];
}
} else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) {
// Handle mono -> 5.1 case, sum mono channel into center. varsource = sourceBuffer.getChannelData(0); var dest = destBuffer.getChannelData(2);
for (var i = 0; i < length; ++i) {
dest[i] += source[i];
}
} else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) {
// Handle 5.1 -> mono. var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceC = sourceBuffer.getChannelData(2);
// skip LFE for now, according to current spec. var sourceSL = sourceBuffer.getChannelData(4); var sourceSR = sourceBuffer.getChannelData(5); var dest = destBuffer.getChannelData(0);
for (var i = 0; i < length; ++i) {
dest[i] += 0.7071 * (sourceL[i] + sourceR[i]) + sourceC[i] + 0.5 * (sourceSL[i] + sourceSR[i]);
}
} else if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 6) {
// Handle 5.1 -> stereo. var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceC = sourceBuffer.getChannelData(2);
// skip LFE for now, according to current spec. var sourceSL = sourceBuffer.getChannelData(4); var sourceSR = sourceBuffer.getChannelData(5); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1);
for (var i = 0; i < length; ++i) {
destL[i] += sourceL[i] + 0.7071 * (sourceC[i] + sourceSL[i]);
destR[i] += sourceR[i] + 0.7071 * (sourceC[i] + sourceSR[i]);
}
} else if (numberOfDestinationChannels == 4 && numberOfSourceChannels == 6) {
// Handle 5.1 -> Quad. var sourceL = sourceBuffer.getChannelData(0); var sourceR = sourceBuffer.getChannelData(1); var sourceC = sourceBuffer.getChannelData(2);
// skip LFE for now, according to current spec. var sourceSL = sourceBuffer.getChannelData(4); var sourceSR = sourceBuffer.getChannelData(5); var destL = destBuffer.getChannelData(0); var destR = destBuffer.getChannelData(1); var destSL = destBuffer.getChannelData(2); var destSR = destBuffer.getChannelData(3);
for (var i = 0; i < connections.length; ++i) { var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCodeAt(0);
varsource = context.createBufferSource();
// Get a buffer with the right number of channels, converting from 1-based to 0-based index. var buffer = testBuffers[connectionNumberOfChannels - 1]; source.buffer = buffer; source.connect(mixNode);
// Start at the right offset. var sampleFrameOffset = testNumber * singleTestFrameLength; vartime = sampleFrameOffset / context.sampleRate; source.start(time);
}
}
function computeNumberOfChannels(connections, channelCount, channelCountMode) {
if (channelCountMode == "explicit")
return channelCount;
var computedNumberOfChannels = 1; // Must have at least one channel.
// Compute "computedNumberOfChannels" based on all the connections.
for (var i = 0; i < connections.length; ++i) { var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCodeAt(0);
computedNumberOfChannels = Math.max(computedNumberOfChannels, connectionNumberOfChannels);
}
if (channelCountMode == "clamped-max")
computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCount);
return computedNumberOfChannels;
}
function checkTestResult(renderedBuffer, testNumber, connections, channelCount, channelCountMode, channelInterpretation) { var computedNumberOfChannels = computeNumberOfChannels(connections, channelCount, channelCountMode);
// Create a zero-initialized silent AudioBuffer with computedNumberOfChannels. var destBuffer = context.createBuffer(computedNumberOfChannels, singleTestFrameLength, context.sampleRate);
// Mix all of the connections into the destination buffer.
for (var i = 0; i < connections.length; ++i) { var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCodeAt(0); var sourceBuffer = testBuffers[connectionNumberOfChannels - 1]; // convert from 1-based to 0-based index
// Validate that destBuffer matches the rendered output.
// We need to check the rendered output at a specific sample-frame-offset corresponding
// to the specific test case we're checking for based on testNumber.
var sampleFrameOffset = testNumber * singleTestFrameLength;
for (var c = 0; c < renderNumberOfChannels; ++c) { var renderedData = renderedBuffer.getChannelData(c);
for (varframe = 0; frame < singleTestFrameLength; ++frame) { var renderedValue = renderedData[frame + sampleFrameOffset];
var expectedValue = 0;
if (c < destBuffer.numberOfChannels) { var expectedData = destBuffer.getChannelData(c);
expectedValue = expectedData[frame];
}
if (Math.abs(renderedValue - expectedValue) > 1e-4) { var s = "connections: " + connections + ", " + channelCountMode;
// channelCount is ignored in "max" mode.
if (channelCountMode == "clamped-max" || channelCountMode == "explicit") {
s += "(" + channelCount + ")";
}
// Check all the tests. var testNumber = 0;
for (var m = 0; m < mixingRulesList.length; ++m) { var mixingRules = mixingRulesList[m];
for (var i = 0; i < connectionsList.length; ++i, ++testNumber) {
checkTestResult(buffer, testNumber, connectionsList[i], mixingRules.channelCount, mixingRules.channelCountMode, mixingRules.channelInterpretation);
}
}
sp.onaudioprocess = null;
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
function runTest() {
// Create 8-channel offline audio context.
// Each test will render 8 sample-frames starting at sample-frame position testNumber * 8. var totalFrameLength = numberOfTests * singleTestFrameLength;
context = new AudioContext(); var nextPowerOfTwo = 256;
while (nextPowerOfTwo < totalFrameLength) {
nextPowerOfTwo *= 2;
}
sp = context.createScriptProcessor(nextPowerOfTwo, renderNumberOfChannels);
// Set destination to discrete mixing.
sp.channelCount = renderNumberOfChannels;
sp.channelCountMode = "explicit";
sp.channelInterpretation = "discrete";
// Create test buffers from 1 to 8 channels.
testBuffers = new Array();
for (var i = 0; i < renderNumberOfChannels; ++i) {
testBuffers[i] = createTestBuffer(i + 1);
}
// Schedule all the tests. var testNumber = 0;
for (var m = 0; m < mixingRulesList.length; ++m) { var mixingRules = mixingRulesList[m];
for (var i = 0; i < connectionsList.length; ++i, ++testNumber) {
scheduleTest(testNumber, connectionsList[i], mixingRules.channelCount, mixingRules.channelCountMode, mixingRules.channelInterpretation);
}
}
// Render then check results.
sp.onaudioprocess = checkResult;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.