Created attachment 225181 [details] HTML page that demonstates the bug (updated to work in Firefox too). The interpolation for the Web Audio WaveShaperNode does not work properly. I have created the follow JavaScript to demonstrate the 2 problems: var c=new webkitOfflineAudioContext(1, 23, 48000); //Create input values between -1.1 and + 1.1. var b=c.createBuffer(1, 23, 48000); var d=b.getChannelData(0); for (var i=0; i<23; i++){ d[i]=(i*.1)-1.1; } var src=c.createBufferSource(); src.buffer=b; src.start(0); //Simple wave-shaper. It should map -1 to 0, 0 to 1, and +1 to 0 - and interpolate all //points between. var ws=c.createWaveShaper(); var curve=new Float32Array(3); curve[0]=0; curve[1]=1; curve[2]=0; ws.curve=curve; src.connect(ws); ws.connect(c.destination); //Execute. c.oncomplete=function(ev){ var outputData=ev.renderedBuffer.getChannelData(0); var msgItems=[]; for (var i=0; i<23; i++){ msgItems.push("Input value " + d[i].toFixed(4) + " => output value " + outputData[i].toFixed(4)); } alert(msgItems.join("\n")); }; c.startRendering(); The specification says "Any sample value less than -1 will correspond to the first value in the curve array." * An input of -1.1 returns a value -0.1500, it should return 0.0000 The specification says "Each input sample within this range will index into the shaping curve with a signal level of zero corresponding to the center value of the curve array." * An input of 0 returns a value of 0.5000, it should return 1.0000 * An input of 0.4 returns a value of 0.0000, it should return 0.8000 The problem appears to be in WaveShaperDSPKernel.cpp - I think it should be changed to something like: double virtualIndex = 0.5 * (input + 1) * curveLength; double output; if (virtualIndex <= -1) { output = curve[0]; } else if (virtualIndex >= curve[curveLength-1]) { output = curve[curveLength-1]; } else { var index1 = (int)virtualIndex; var value1 = curve[index1]; var value2 = curve[index1+1]; var interpolationFactor = virtualIndex - index1; output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2; } The current test HTML page only tests input values that fall between -1 and +1 - and the error from the mid-point and end-point of the curve are disguised by the large number of elements in the curve array.
Comment on attachment 225181 [details] HTML page that demonstates the bug (updated to work in Firefox too). <html> <body> <pre> The interpolation for the Web Audio WaveShaperNode does not work properly. I have created the follow JavaScript to demonstrate the 2 problems: var audioContextClass=window.OfflineAudioContext||webkitOfflineAudioContext var c=new audioContextClass(1, 23, 48000); //Create input values between -1.1 and + 1.1. var b=c.createBuffer(1, 23, 48000); var d=b.getChannelData(0); for (var i=0; i<23; i++){ d[i]=(i*.1)-1.1; } var src=c.createBufferSource(); src.buffer=b; src.start(0); //Simple wave-shaper. It should map -1 to 0, 0 to 1, and +1 to 0 - and interpolate all //points between. var ws=c.createWaveShaper(); var curve=new Float32Array(3); curve[0]=0; curve[1]=1; curve[2]=0; ws.curve=curve; src.connect(ws); ws.connect(c.destination); //Execute. c.oncomplete=function(ev){ var inputData=b.getChannelData(0); var outputData=ev.renderedBuffer.getChannelData(0); var msgItems=[]; for (var i=0; i<23; i++){ msgItems.push("Input value " + inputData[i].toFixed(4) + " => output value " + outputData[i].toFixed(4)); } alert(msgItems.join("\n")); }; c.startRendering(); The specification says "Any sample value less than -1 will correspond to the first value in the curve array." * In Chrome, an input of -1.1 returns a value -0.1500, it should return 0.0000 The specification says "Each input sample within this range will index into the shaping curve with a signal level of zero corresponding to the center value of the curve array." * In Chrome and FireFox, an input of 0 returns a value of 0.5000, it should return 1.0000 * In Chrome and FireFox, an input of 0.4 returns a value of 0.0000, it should return 0.8000 The problem appears to be in WaveShaperDSPKernel.cpp in the webkit source code - I think it should be something like this: double virtualIndex = 0.5 * (input + 1) * curveLength; double output; if (virtualIndex <= -1) { output = curve[0]; } else if (virtualIndex >= curve[curveLength-1]) { output = curve[curveLength-1]; } else { int index1 = static_cast<int>(virtualIndex); double value1 = curve[index1]; double value2 = curve[index1+1]; double interpolationFactor = virtualIndex - index1; output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2; } The current webkit test HTML page only tests input values that fall between -1 and +1. The error from the mid-point and end-point of the curve are disguised by the large number of elements in the tested curve array. </pre> <script type="text/javascript"> var audioContextClass=(window.OfflineAudioContext||webkitOfflineAudioContext); var c=new audioContextClass(1, 23, 48000); //Create input values between -1.1 and + 1.1. var b=c.createBuffer(1, 23, 48000); var d=b.getChannelData(0); for (var i=0; i<23; i++){ d[i]=(i*.1)-1.1; } var src=c.createBufferSource(); src.buffer=b; src.start(0); //Simple wave-shaper. var ws=c.createWaveShaper(); var curve=new Float32Array(3); curve[0]=0; curve[1]=1; curve[2]=0; ws.curve=curve; src.connect(ws); ws.connect(c.destination); //Execute. c.oncomplete=function(ev){ var inputData=b.getChannelData(0); var outputData=ev.renderedBuffer.getChannelData(0); var msgItems=[]; for (var i=0; i<23; i++){ msgItems.push("Input value " + inputData[i].toFixed(4) + " => output value " + outputData[i].toFixed(4)); } alert(msgItems.join("\n")); }; c.startRendering(); </script> </body> </html>