Hello, Chris!
In continuation of my previous letter and in response to your request.
Taking as a basis our example (I just simplified the interaction of the buttons on id with their working in function updateParams (newGain, newPan - seriously reducing the code), I appended the example as a test for checking the reliability of function updateParams (newGain, newPan) with standard Web Audio Api nodes - GainNode and StereoPannerNode.
In addition to the original three buttons - Play sample, Update1 volume and balance and Update2 volume and balance:
< Input type = “button” id = “btn1” value = “Play sample with volume = 0.5 and balance = 0.0”>
< Input type = “button” id = “btn2” value = “Update1 volume to 0.7 and balance to +0.9”>
< Input type = “button” id = “btn3” value = “Update2 volume to 0.9 and balance to -0.9”>
I introduced the example of additional buttons, which I arranged vertically for convenience. All new buttons are divided into three arrays, comprising three Tests:
Test # 1 Test the individual work of the GainNode (Volume) node with the same value of the node StereoPannerNode // --------- VOLUME = from 0.1 to to 1.0 — & — PANORAMA (balance) = constant = 0.0- ----> (10 buttons)
Test # 2 checking the separate operation of the StereoPannerNode node with the GainNode value (constant) constant // --------- PANORAMA (balance) = from -1.0 to 0.0 to +1.0 — & — VOLUME = constant = 1.0 -----> (21 buttons)
Test # 3 checking the simultaneous operation of the GainNode (Volume) node and the StereoPannerNode node (panorama = balance) //! Simultaneously ---- VOLUME = from 0.1 to to 1.0 - & - PANORAMA (balance) = from -1.0 to 0.0 to 1.0 —> (21 buttons)
If we represent new buttons in the form of a graph - each of the new buttons is simultaneously a point on the X-axis (time), the Y-axis reflects the value of this point - its Volume and Panorama (balance).
Testing was done through headphones with listening to the same music stereo-sample.mp3, in which the singer’s voice was clearly defined in the center. Testing was performed on several independent PCs (Windows 7, Windows 8.1) through Mozilla, Google Chrome and Opera browsers, the latest on August 4, 2017 versions.
A thorough testing of the example (the code I’m attaching to you below) yielded the following results:
Test # 1 through Mozilla - OK! Through Google Chrome - OK! Through Opera - OK!
Test # 2 through Mozilla - OK! Through Google Chrome - OK! Through Opera - OK!
Test # 3 through Mozilla - NOT OK! Through Google Chrome - OK! Through Opera - OK!
According to Test # 3, starting from the first to the last point (button) on the X (time) scale, when the Panorama values change step by step from the Y-axis (balance from -1.0 to 0.0 to 1.0-from Left to Right) Linear change in the values of Volume from 0.1 to to 1.0 (from min to max). That’s right, smoothly, without a flaw going through the process through the browsers of Google Chrome and Opera, but not through the Mozilla browser!
What should be through the Mozilla browser on test # 3:
Button1 (Volume = 0.1 (min) and Panorama (balance) = -1.0 (Leftmost)),
Button 11 (Middle Volume = 0.5 and Middle Panorama (balance) = 0.0),
Button21 (Volume = 1.0 (max) and Panorama (balance) = 1.0 (Rightmost))
What do we have in reality through the Mozilla browser on test # 3:
Button1 (Volume = 0.1 (min) - NOT OK! (Not regulated!) And Panorama (balance) = -1.0 (Leftmost) - OK! (but about the problem with the panorama (balance), see below in paragraph 4),
Button 11 (Middle Volume = 0.5 - OK! And Middle Panorama (balance) = 0.0 - OK!),
Button21 (Volume = 1.0 (max) - OK! And Panorama (balance) = 1.0 (Rightmost) - OK!)
Testing showed that through Mozilla in test # 3, with the StereoPannerNode node working poorly in test # 3, the GainNode (Volume) node practically does not work, namely:
-
The real Volume of all the buttons (points) except kn21, kn20, kn19, kn18 is greatly overestimated! - relative to the corresponding buttons (points) in test # 1.
-
Volume kn1 (min volume) = kn2 = kn3 = kn4 = kn5 = kn6 = kn7 = kn8 = kn9 = kn10 = constant !!! >> Volume kn11 (Middle Volume) = 0.5 !!! (Balance = 0.0)
Volume kn17 = kn16 = kn15 = kn14 = kn13 = kn12 = constant !!! Volume kn21 = kn20 = kn19 = kn18 = constant !!!
-
In reality, through Mozilla in test # 3 of 21 buttons (dots), only two of them work practically normally - kn21 & kn11 !!!, because:
Test # 3 Volume kn11 (Middle Volume) = 0.5 exactly corresponds to Test # 1 Volume kn5 = 0.5 (balance = 0.0)
Test # 3 Volume kn21 = 1.0 (balance = 0.0) exactly corresponds to Test # 2 Volume kn21 = 1.0 (balance = 0.0)
The remaining buttons (19 of 21) in test # 3 through function updateParams (newGain, newPan) with standard Web Audio Api nodes - GainNode and StereoPannerNode in Mozilla browser practically do not work. (Through Google Chrome and Opera browsers - all test # 3 buttons work without flaw)!
-
when listening attentively through the headphones, it turned out that the Panorama (balance) values in Test # 3 for all buttons (points) except the extreme and center (kn21, kn11, kn1) do not match the Panorama (balance) values for the corresponding buttons ( Points) in Test # 2 !!!
Hence - a confusing, unpleasant physical audio sensation when listening to test # 3 through Mozilla, regardless of the aesthetic beauty of the music itself presented in the sample. Simply put, the latest version of the Mozilla browser works so test # 3 in our simple example that it really spoils the impression of listening to the music itself, destroys its core - the very sound idea inherent in Music by the composer and her performer.
Conclusions:
- since Testing sample.mp3 was conducted from the Internet on several independent from each other PC from under Windows7 and Windows 8.1., And the result is the same - it means it’s not the drivers;
- the code of the example itself is written correctly, without errors - because Browsers GoogleChrome and Opera work it out reliably, without any failures.
- if the nodes GainNode, StereoPannerNode, and function updateParams (newGain, newPan) were written with some kind of defect - it would inevitably be heard through Google Chrome and Opera, as well as through Mozilla. But they work out the work of GainNode, StereoPannerNode and function updateParams (newGain, newPan) according to the code of our example is almost perfect.
Most likely it is in the Mozilla browser itself - in its incorrect working out of the interaction of the standard Web Audio nodes Api - GainNode, StereoPannerNode and function updateParams (newGain, newPan).
Below is what you asked, Chris is our example, adapted for testing (It took some time to again double-check everything and write down). You can check everything by simply copying it and running it through browsers. Note: it is important to test the example on the Internet, on some kind of work site. Better with headphones. And - samle.mp3 should be sure to stereo and the audio center of this stereo-sample should immediately be clearly determined by ear.
The code of our example for Test:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WAA test ( chrismills b-ke )</title>
</head>
</head>
<body>
<input type = "button" id="btn1" value = "Play sample with volume = 0.5 and balance = 0.0">
<input type = "button" id="btn2" value = "Update1 volume to 0.7 and balance to +0.9">
<input type = "button" id="btn3" value = "Update2 volume to 0.9 and balance to -0.9">
<p></p>
//---------VOLUME = from 0.1 to to 1.0---&---PANORAMA(balance) = constant = 0.0----->
<p></p>
<input type = "button" id="btnV01P00" value = "Test#1 kn1 Update volume to 0.1 and balance = 0.0">
<p></p>
<input type = "button" id="btnV02P00" value = "Test#1 kn2 Update volume to 0.2 and balance = 0.0">
<p></p>
<input type = "button" id="btnV03P00" value = "Test#1 kn3 Update volume to 0.3 and balance = 0.0">
<p></p>
<input type = "button" id="btnV04P00" value = "Test#1 kn4 Update volume to 0.4 and balance = 0.0">
<p></p>
<input type = "button" id="btnV05P00" value = "Test#1 kn5 Update volume to 0.5 and balance = 0.0">
<p></p>
<input type = "button" id="btnV06P00" value = "Test#1 kn6 Update volume to 0.6 and balance = 0.0">
<p></p>
<input type = "button" id="btnV07P00" value = "Test#1 kn7 Update volume to 0.7 and balance = 0.0">
<p></p>
<input type = "button" id="btnV08P00" value = "Test#1 kn8 Update volume to 0.8 and balance = 0.0">
<p></p>
<input type = "button" id="btnV09P00" value = "Test#1 kn9 Update volume to 0.9 and balance = 0.0">
<p></p>
<input type = "button" id="btnV10P00" value = "Test#1 kn10 Update volume to 1.0 and balance = 0.0">
<p></p>
//---------PANORAMA(balance) = from -1.0 to 0.0 to +1.0---&---VOLUME = constant = 1.0----->
<p></p>
<input type = "button" id="btnPL10V10" value = "Test#2 kn1 volume = 1.0 and Update balance to -1.0">
<p></p>
<input type = "button" id="btnPL09V10" value = "Test#2 kn2 volume = 1.0 and Update balance to -0.9">
<p></p>
<input type = "button" id="btnPL08V10" value = "Test#2 kn3 volume = 1.0 and Update balance to -0.8">
<p></p>
<input type = "button" id="btnPL07V10" value = "Test#2 kn4 volume = 1.0 and Update balance to -0.7">
<p></p>
<input type = "button" id="btnPL06V10" value = "Test#2 kn5 volume = 1.0 and Update balance to -0.6">
<p></p>
<input type = "button" id="btnPL05V10" value = "Test#2 kn6 volume = 1.0 and Update balance to -0.5">
<p></p>
<input type = "button" id="btnPL04V10" value = "Test#2 kn7 volume = 1.0 and Update balance to -0.4">
<p></p>
<input type = "button" id="btnPL03V10" value = "Test#2 kn8 volume = 1.0 and Update balance to -0.3">
<p></p>
<input type = "button" id="btnPL02V10" value = "Test#2 kn9 volume = 1.0 and Update balance to -0.2">
<p></p>
<input type = "button" id="btnPL01V10" value = "Test#2 kn10 volume = 1.0 and Update balance to -0.1">
<p></p>
<input type = "button" id="btnPL00V10" value = "Test#2 kn11(Middle Panorama) volume = 1.0 and Update balance to 0.0">
<p></p>
<input type = "button" id="btnPR01V10" value = "Test#2 kn12 volume = 1.0 and Update balance to 0.1">
<p></p>
<input type = "button" id="btnPR02V10" value = "Test#2 kn13 volume = 1.0 and Update balance to 0.2">
<p></p>
<input type = "button" id="btnPR03V10" value = "Test#2 kn14 volume = 1.0 and Update balance to 0.3">
<p></p>
<input type = "button" id="btnPR04V10" value = "Test#2 kn15 volume = 1.0 and Update balance to 0.4">
<p></p>
<input type = "button" id="btnPR05V10" value = "Test#2 kn16 volume = 1.0 and Update balance to 0.5">
<p></p>
<input type = "button" id="btnPR06V10" value = "Test#2 kn17 volume = 1.0 and Update balance to 0.6">
<p></p>
<input type = "button" id="btnPR07V10" value = "Test#2 kn18 volume = 1.0 and Update balance to 0.7">
<p></p>
<input type = "button" id="btnPR08V10" value = "Test#2 kn19 volume = 1.0 and Update balance to 0.8">
<p></p>
<input type = "button" id="btnPR09V10" value = "Test#2 kn20 volume = 1.0 and Update balance to 0.9">
<p></p>
<input type = "button" id="btnPR10V10" value = "Test#2 kn21 volume = 1.0 and Update balance to 1.0">
<p></p>
<p></p>
//!Simultaneously----VOLUME = from 0.1 to to 1.0--&--PANORAMA(balance) = from -1.0 to 0.0 to 1.0--->
<p></p>
<input type = "button" id="btnV01PL10" value = "Test#3 kn1 Update volume = 0.1 and balance to -1.0">
<p></p>
<input type = "button" id="btnV01PL09" value = "Test#3 kn2 Update volume = 0.1 and balance to -0.9">
<p></p>
<input type = "button" id="btnV02PL08" value = "Test#3 kn3 Update volume = 0.2 and balance to -0.8">
<p></p>
<input type = "button" id="btnV02PL07" value = "Test#3 kn4 Update volume = 0.2 and balance to -0.7">
<p></p>
<input type = "button" id="btnV03PL06" value = "Test#3 kn5 Update volume = 0.3 and balance to -0.6">
<p></p>
<input type = "button" id="btnV03PL05" value = "Test#3 kn6 Update volume = 0.3 and balance to -0.5">
<p></p>
<input type = "button" id="btnV04PL04" value = "Test#3 kn7 Update volume = 0.4 and balance to -0.4">
<p></p>
<input type = "button" id="btnV04PL03" value = "Test#3 kn8 Update volume = 0.4 and balance to -0.3">
<p></p>
<input type = "button" id="btnV04PL02" value = "Test#3 kn9 Update volume = 0.4 and balance to -0.2">
<p></p>
<input type = "button" id="btnV05PL01" value = "Test#3 kn10 Update volume = 0.5 and balance to -0.1">
<p></p>
<input type = "button" id="btnV05PL00" value = "Test#3 kn11(Middle Volume & Middle Panorama) Update volume = 0.5 and balance to 0.0">
<p></p>
<input type = "button" id="btnV06PR01" value = "Test#3 kn12 Update volume = 0.6 and balance to 0.1">
<p></p>
<input type = "button" id="btnV06PR02" value = "Test#3 kn13 Update volume = 0.6 and balance to 0.2">
<p></p>
<input type = "button" id="btnV07PR03" value = "Test#3 kn14 Update volume = 0.7 and balance to 0.3">
<p></p>
<input type = "button" id="btnV07PR04" value = "Test#3 kn15 Update volume = 0.7 and balance to 0.4">
<p></p>
<input type = "button" id="btnV08PR05" value = "Test#3 kn16 Update volume = 0.8 and balance to 0.5">
<p></p>
<input type = "button" id="btnV08PR06" value = "Test#3 kn17 Update volume = 0.8 and balance to 0.6">
<p></p>
<input type = "button" id="btnV09PR07" value = "Test#3 kn18 Update volume = 0.9 and balance to 0.7">
<p></p>
<input type = "button" id="btnV09PR08" value = "Test#3 kn19 Update volume = 0.9 and balance to 0.8">
<p></p>
<input type = "button" id="btnV10PR09" value = "Test#3 kn20 Update volume = 1.0 and balance to 0.9">
<p></p>
<input type = "button" id="btnV10PR10" value = "Test#3 kn21 Update volume = 1.0 and balance to 1.0">
<p></p>
<script type="text/javascript">
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var sample = "music.mp3";
var panner, gainNode;
function play( snd, vol, balance ) {
var audioContext = new AudioContext();
audioContext.listener.setPosition( 0, 0, 0 );
var request = new XMLHttpRequest();
request.open( "GET", snd, true );
request.responseType = "arraybuffer";
request.onload = function () {
audioData = request.response;
audioContext.decodeAudioData(
audioData,
function ( buffer ) {
// create source with source global variable
source = audioContext.createBufferSource();
source.buffer = buffer;
// create GainNode with gainNode global variable
gainNode = audioContext.createGain();
// create StereoPannerNode with the panner global variable
panner = audioContext.createStereoPanner();
// connect the source and nodes in the chain
source.connect( gainNode );
gainNode.connect( panner );
gainNode.gain.value = vol;
panner.pan.value = balance;
panner.connect( audioContext.destination );
source.start( 0 );
},
function ( e ) {
alert( "Error with decoding audio data" + e.err );
});
};
request.send();
}
function updateParams (newGain, newPan) {
gainNode.gain.value = newGain;
panner.pan.value = newPan;
};
btn1.onclick = function() {
play(sample, 0.5, 0.0);
}
btn2.onclick = function() {
updateParams(0.7, 0.9);
}
btn3.onclick = function() {
updateParams(0.9, -0.9);
}
//---------VOLUME = from 0.1 to to 1.0---&---PANORAMA(balance) = constant = 0.0----->
btnV01P00.onclick = function() {
updateParams(0.1, 0.0);
}
btnV02P00.onclick = function() {
updateParams(0.2, 0.0);
}
btnV03P00.onclick = function() {
updateParams(0.3, 0.0);
}
btnV04P00.onclick = function() {
updateParams(0.4, 0.0);
}
btnV05P00.onclick = function() {
updateParams(0.5, 0.0);
}
btnV06P00.onclick = function() {
updateParams(0.6, 0.0);
}
btnV07P00.onclick = function() {
updateParams(0.7, 0.0);
}
btnV08P00.onclick = function() {
updateParams(0.8, 0.0);
}
btnV09P00.onclick = function() {
updateParams(0.9, 0.0);
}
btnV10P00.onclick = function() {
updateParams(1.0, 0.0);
}
//---------PANORAMA(balance) = from -1.0 to 0.0 to +1.0---&---VOLUME = constant = 1.0----->
btnPL10V10.onclick = function() {
updateParams(1.0, -1.0);
}
btnPL09V10.onclick = function() {
updateParams(1.0, -0.9);
}
btnPL08V10.onclick = function() {
updateParams(1.0, -0.8);
}
btnPL07V10.onclick = function() {
updateParams(1.0, -0.7);
}
btnPL06V10.onclick = function() {
updateParams(1.0, -0.6);
}
btnPL05V10.onclick = function() {
updateParams(1.0, -0.5);
}
btnPL04V10.onclick = function() {
updateParams(1.0, -0.4);
}
btnPL03V10.onclick = function() {
updateParams(1.0, -0.3);
}
btnPL02V10.onclick = function() {
updateParams(1.0, -0.2);
}
btnPL01V10.onclick = function() {
updateParams(1.0, -0.1);
}
btnPL00V10.onclick = function() {
updateParams(1.0, 0.0);
}
btnPR01V10.onclick = function() {
updateParams(1.0, 0.1);
}
btnPR02V10.onclick = function() {
updateParams(1.0, 0.2);
}
btnPR03V10.onclick = function() {
updateParams(1.0, 0.3);
}
btnPR04V10.onclick = function() {
updateParams(1.0, 0.4);
}
btnPR05V10.onclick = function() {
updateParams(1.0, 0.5);
}
btnPR06V10.onclick = function() {
updateParams(1.0, 0.6);
}
btnPR07V10.onclick = function() {
updateParams(1.0, 0.7);
}
btnPR08V10.onclick = function() {
updateParams(1.0, 0.8);
}
btnPR09V10.onclick = function() {
updateParams(1.0, 0.9);
}
btnPR10V10.onclick = function() {
updateParams(1.0, 1.0);
}
//!Simultaneously----VOLUME = from 0.1 to to 1.0--&--PANORAMA(balance) = from -1.0 to 0.0 to 1.0--->
btnV01PL10.onclick = function() {
updateParams(0.1, -1.0);
}
btnV01PL09.onclick = function() {
updateParams(0.1, -0.9);
}
btnV02PL08.onclick = function() {
updateParams(0.2, -0.8);
}
btnV02PL07.onclick = function() {
updateParams(0.2, -0.7);
}
btnV03PL06.onclick = function() {
updateParams(0.3, -0.6);
}
btnV03PL05.onclick = function() {
updateParams(0.3, -0.5);
}
btnV04PL04.onclick = function() {
updateParams(0.4, -0.4);
}
btnV04PL03.onclick = function() {
updateParams(0.4, -0.3);
}
btnV04PL02.onclick = function() {
updateParams(0.4, -0.2);
}
btnV05PL01.onclick = function() {
updateParams(0.5, -0.1);
}
btnV05PL00.onclick = function() {
updateParams(0.5, 0.0);
}
btnV06PR01.onclick = function() {
updateParams(0.6, 0.1);
}
btnV06PR02.onclick = function() {
updateParams(0.6, 0.2);
}
btnV07PR03.onclick = function() {
updateParams(0.7, 0.3);
}
btnV07PR04.onclick = function() {
updateParams(0.7, 0.4);
}
btnV08PR05.onclick = function() {
updateParams(0.8, 0.5);
}
btnV08PR06.onclick = function() {
updateParams(0.8, 0.6);
}
btnV09PR07.onclick = function() {
updateParams(0.9, 0.7);
}
btnV09PR08.onclick = function() {
updateParams(0.9, 0.8);
}
btnV10PR09.onclick = function() {
updateParams(1.0, 0.9);
}
btnV10PR10.onclick = function() {
updateParams(1.0, 1.0);
}
</script>
</body>
</html>
I have a request to you, Chris - after all of the above you check yourself - if possible, please pass this test example to the developers of the Mozilla browser - let them carefully check everything themselves, as we tested - and making sure that The truth is, they will try to find a failure in the browser, and reliably eliminate it so that in one of the future, new versions of Mozilla, this malfunction no longer exists, so that all who use the Mozilla browser are not tormented by using interesting and promising Web Audio Api development MDN, But sincerely rejoiced. As it seems to me, the technical, technological, software-code relationships between Mozilla and MDN should be an example for developers of other browsers, not for turnover.
Chris, if you do not mind, we’ll talk further about the further development of the code of our example with respect to its work, not with one but with several stereo-samples.mp3, as well as about timers and stereo-samples, and try to look into Web Audio Api even deeper.
So far, I’m not strong at Web Audio Api, but I’m persistent in testing. Thanks to your specific tips and detailed explanations of the work of Web Audio Api, I’m learning in practice, and I think that I’m not the only one. Thank you for this!
Yours faithfully,
Boris-KE.