Bug 215391 - Fix WaveShaperNode's waveshaping curve implementation
Summary: Fix WaveShaperNode's waveshaping curve implementation
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Audio (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL: https://www.w3.org/TR/webaudio/#dom-w...
Keywords: InRadar
Depends on:
Blocks: 212611
  Show dependency treegraph
 
Reported: 2020-08-11 14:02 PDT by Chris Dumez
Modified: 2020-08-12 09:50 PDT (History)
10 users (show)

See Also:


Attachments
Patch (14.77 KB, patch)
2020-08-11 14:41 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (14.87 KB, patch)
2020-08-11 16:02 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (14.85 KB, patch)
2020-08-11 16:21 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2020-08-11 14:02:36 PDT
fix WaveShapperNode's curve implementation to match the specification:
- https://www.w3.org/TR/webaudio/#dom-waveshapernode-curve
Comment 1 Chris Dumez 2020-08-11 14:41:39 PDT
Created attachment 406420 [details]
Patch
Comment 2 Darin Adler 2020-08-11 14:44:16 PDT
Comment on attachment 406420 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406420&action=review

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:111
> +            unsigned k = floor(v);
> +            double f = v - k;

What's the rationale for converting v to an unsigned and back to a double? That’s inefficient and I don’t think it’s needed once we’ve done the floor.
Comment 3 Chris Dumez 2020-08-11 14:55:29 PDT
Comment on attachment 406420 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406420&action=review

>> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:111
>> +            double f = v - k;
> 
> What's the rationale for converting v to an unsigned and back to a double? That’s inefficient and I don’t think it’s needed once we’ve done the floor.

I don't understand this comment. I tried to match the formula in the specification as closely as possible. That said, the formula does not mention what data type should be used for each variable.
k is used as index in curveData array so it needs to be an unsigned integer. However, v and f are not integers as far as I can tell.
Comment 4 Darin Adler 2020-08-11 15:24:08 PDT
Comment on attachment 406420 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406420&action=review

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:102
>          const float input = source[i];

I wonder if we have to convert everything to double to get correct results. Would be more efficient to do the work as float, but may not give identical results.

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:107
> +        else if (v >= (curveLength - 1))

Unnecessary parentheses here.

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:108
> +            destination[i] = curveData[curveLength -1];

Missing space after "-".

>>> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:111
>>> +            double f = v - k;
>> 
>> What's the rationale for converting v to an unsigned and back to a double? That’s inefficient and I don’t think it’s needed once we’ve done the floor.
> 
> I don't understand this comment. I tried to match the formula in the specification as closely as possible. That said, the formula does not mention what data type should be used for each variable.
> k is used as index in curveData array so it needs to be an unsigned integer. However, v and f are not integers as far as I can tell.

I see; I didn’t notice that k was used as an array index. Could do this:

    double dk = floor(v);
    unsigned k = dk;
    double f = v - k;

This would be more efficient than the code above.
Comment 5 Chris Dumez 2020-08-11 16:02:43 PDT
Created attachment 406428 [details]
Patch
Comment 6 Chris Dumez 2020-08-11 16:04:51 PDT
Comment on attachment 406428 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406428&action=review

Ok, I have now using float instead of double for the computation. This still passes the tests and should suffice since values use float precision in the end.

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:110
> +            float fk = floorf(v);

Ok, I did it on 2 lines here as suggested. I don't really understand why it is faster though. If you have time, I'd love to understand why this is faster than:
unsigned k = floorf(v);
Comment 7 Darin Adler 2020-08-11 16:14:55 PDT
Comment on attachment 406428 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406428&action=review

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:112
> +            float f = v - k;

This is where the faster code would be:

    float f = v - fk;

Sorry I wasn’t clear on that before!
Comment 8 Chris Dumez 2020-08-11 16:21:28 PDT
Created attachment 406431 [details]
Patch
Comment 9 Chris Dumez 2020-08-11 16:21:47 PDT
(In reply to Darin Adler from comment #7)
> Comment on attachment 406428 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=406428&action=review
> 
> > Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:112
> > +            float f = v - k;
> 
> This is where the faster code would be:
> 
>     float f = v - fk;
> 
> Sorry I wasn’t clear on that before!

Oh, it makes sense now. Thanks for clarifying.
Comment 10 Darin Adler 2020-08-11 16:43:20 PDT
Comment on attachment 406431 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406431&action=review

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:104
> +        float v = (curveLength - 1) * 0.5 * (input + 1);

This 0.5 is a double, so it makes the expression compute as double and then narrow down to float. Needs to be 0.5f if we want it to be done as float.
Comment 11 EWS 2020-08-11 16:55:38 PDT
Committed r265536: <https://trac.webkit.org/changeset/265536>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 406431 [details].
Comment 12 Radar WebKit Bug Importer 2020-08-11 16:56:21 PDT
<rdar://problem/66870911>
Comment 13 Chris Dumez 2020-08-11 16:59:42 PDT
(In reply to Darin Adler from comment #10)
> Comment on attachment 406431 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=406431&action=review
> 
> > Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:104
> > +        float v = (curveLength - 1) * 0.5 * (input + 1);
> 
> This 0.5 is a double, so it makes the expression compute as double and then
> narrow down to float. Needs to be 0.5f if we want it to be done as float.

Fixed in <https://trac.webkit.org/changeset/265538>, thanks.
Comment 14 Sam Weinig 2020-08-11 18:25:02 PDT
Comment on attachment 406431 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=406431&action=review

> Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:110
> +            float k = floorf(v);

Tiny nit, but I have been trying to convert to using std::floor() in cases like this (it is overloaded based on type, so will end up calling floorf(), but generalizes better).
Comment 15 Chris Dumez 2020-08-12 09:50:40 PDT
(In reply to Sam Weinig from comment #14)
> Comment on attachment 406431 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=406431&action=review
> 
> > Source/WebCore/Modules/webaudio/WaveShaperDSPKernel.cpp:110
> > +            float k = floorf(v);
> 
> Tiny nit, but I have been trying to convert to using std::floor() in cases
> like this (it is overloaded based on type, so will end up calling floorf(),
> but generalizes better).

Thanks for pointing it out. I agree it is nicer and made the nit fix in <https://trac.webkit.org/changeset/265552>.