| <!doctype html> |
| <html> |
| <head> |
| <title>Test multichannel support.</title> |
| <style type="text/css"> |
| body { |
| margin: 2em; |
| } |
| .manual-test-ui { |
| font-family: Arial; |
| padding: 1em; |
| border: 1px solid #999; |
| } |
| .manual-test-ui button { |
| padding: 1em; |
| font-size: 1em; |
| } |
| </style> |
| </head> |
| |
| <body> |
| <h1>Test Multichannel Audio Output</h1> |
| |
| <p>Tests that multichannel audio output (> 8 channels) is working correctly. |
| This test cannot be run with an offline audio context because it requires |
| an actual audio hardware with the multichannel capability.</p> |
| |
| <p>Press "Start Test Tone" to run the test. You should hear an one-second |
| sine tone from all the available audio output channels from the channel 1 |
| to the last channel.</p> |
| |
| <p>Note that this test only works on OSX because CoreAudio driver supports |
| the multichannel streams (more than 2) on a single audio device whereas |
| other platforms do not.</p> |
| |
| <p>CRBUG issue: <a href="https://code.google.com/p/chromium/issues/detail?id=424795" target="_blank"> |
| 424795</a></p> |
| |
| <div class="manual-test-ui"> |
| <p>Max Channel Count: <span id="eMaxChannelCount">2</span></p> |
| <p>Currently playing: <span id="eChannelIndex">NONE</span></p> |
| <button id="eButton" onclick="startTestTones()">Start Test Tone</button> |
| </div> |
| |
| <script type="text/javascript"> |
| // Silent interval between the test tones. |
| var testToneInterval = 0.1; |
| |
| // The safe range for the equal loudness of sinusoid is roughly between |
| // 200 ~ 1000Hz, which is A3(57) ~ C6(84). In this test, the starting |
| // pitch is 220Hz and the interval is the whole tone. (2 MIDI pitch) |
| // With 16 speakers, the last test tone will play the MIDI pitch of |
| // F6(89), which is 1396Hz. |
| var startMIDIPitch = 57; |
| |
| var eMaxChannelCount = document.querySelector('#eMaxChannelCount'); |
| var eButton = document.querySelector('#eButton'); |
| var eChannelIndex = document.querySelector('#eChannelIndex'); |
| |
| var context = new AudioContext(); |
| var maxChannelCount = context.destination.maxChannelCount; |
| |
| // Sets the destination properties for multichannel access. |
| context.destination.channelCount = maxChannelCount; |
| context.destination.channelCountMode = 'explicit'; |
| context.destination.channelInterpretation = 'discrete'; |
| |
| // The ChannelMerger for the individual channel access. |
| var merger = context.createChannelMerger(maxChannelCount); |
| merger.channelCountMode = 'explicit'; |
| merger.channelInterpretation = 'discrete'; |
| merger.connect(context.destination); |
| |
| eMaxChannelCount.textContent = maxChannelCount; |
| |
| // Convert the MIDI pitch to frequency. |
| function midi2freq(midiPitch) { |
| return 440 * Math.pow(2, (midiPitch - 69) / 12); |
| } |
| |
| // Play a test tone for the specified amount of duration at the channel. |
| function playTestToneAtChannel(channelIndex, gain, duration) { |
| var osc = context.createOscillator(); |
| var amp = context.createGain(); |
| osc.connect(amp); |
| amp.connect(merger, 0, channelIndex); |
| |
| osc.onended = function () { |
| var nextChannelIndex = channelIndex + 1; |
| if (nextChannelIndex < maxChannelCount) |
| playTestToneAtChannel(nextChannelIndex, gain, duration); |
| else |
| endTestTone(); |
| }; |
| |
| // The pitch for each speaker goes up as the channel index increases. |
| // Note that the interval is 2, whole tone. |
| osc.frequency.value = midi2freq(startMIDIPitch + channelIndex * 2); |
| |
| // The channel index starts from 1. |
| eChannelIndex.textContent = 'Channel #' + (channelIndex + 1); |
| |
| var now = context.currentTime; |
| var toneDuration = duration - testToneInterval; |
| |
| // Add fade in and out to avoid the click noise. |
| amp.gain.setValueAtTime(0.0, now); |
| amp.gain.linearRampToValueAtTime(gain, now + toneDuration * 0.1); |
| amp.gain.setValueAtTime(gain, now + toneDuration * 0.9); |
| amp.gain.linearRampToValueAtTime(0.0, now + toneDuration); |
| |
| osc.start(now); |
| osc.stop(now + duration); |
| } |
| |
| // When the button is clicked the button to produce the test sound, |
| // the button is grayed out so one cannot press again until the tone is |
| // over. (producing sounds multiple times in a short period time will |
| // hurt the speaker). |
| function startTestTones() { |
| eButton.disabled = true; |
| |
| // Math.SQRT1_2(=0.707..) is -3dB. This is necessary because 1.0 |
| // amplitude can cause overload/distortion on some speakers. |
| playTestToneAtChannel(0, Math.SQRT1_2, 1.0); |
| } |
| |
| // The button needs to be active back again when the test tone is over. |
| // The index number in DIV should also be reset. |
| function endTestTone() { |
| eButton.disabled = false; |
| eChannelIndex.textContent = 'NONE'; |
| } |
| </script> |
| </body> |
| </html> |