WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
NEW
129333
WaveShaperNode interpolation does not match specification
https://bugs.webkit.org/show_bug.cgi?id=129333
Summary
WaveShaperNode interpolation does not match specification
Andy Harman
Reported
2014-02-25 13:43:08 PST
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.
Attachments
HTML page that demonstates the bug (updated to work in Firefox too).
(3.08 KB, text/html)
2014-02-25 13:43 PST
,
Andy Harman
no flags
Details
View All
Add attachment
proposed patch, testcase, etc.
Andy Harman
Comment 1
2014-02-28 01:35:38 PST
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>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug