⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 267386 in webkit


Ignore:
Timestamp:
Sep 21, 2020, 5:17:33 PM (6 years ago)
Author:
Chris Dumez
Message:

AudioBufferSourceNode should update grain parameters when buffer is set after rendering has started
https://bugs.webkit.org/show_bug.cgi?id=216808

Reviewed by Eric Carlson.

Source/WebCore:

AudioBufferSourceNode should update grain parameters when buffer is set after rendering has
started. The grain parameters need to be adjusted so that they make sense given the buffer
length. Previously, we would only update grain parameters in AudioBufferSourceNode::startPlaying(),
when a buffer is set. We would fail to update those grain parameters when the buffer is set,
in setBuffer(), if startPlaying() has already been called.

No new tests, rebaselined existing test.

  • Modules/webaudio/AudioBufferSourceNode.cpp:

(WebCore::AudioBufferSourceNode::setBuffer):
(WebCore::AudioBufferSourceNode::startLater):
(WebCore::AudioBufferSourceNode::startPlaying):
(WebCore::AudioBufferSourceNode::updateGrainParameters):

  • Modules/webaudio/AudioBufferSourceNode.h:

LayoutTests:

Rebaseline test that is now passing.

  • webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration-expected.txt:
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r267384 r267386  
     12020-09-21  Chris Dumez  <cdumez@apple.com>
     2
     3        AudioBufferSourceNode should update grain parameters when buffer is set after rendering has started
     4        https://bugs.webkit.org/show_bug.cgi?id=216808
     5
     6        Reviewed by Eric Carlson.
     7
     8        Rebaseline test that is now passing.
     9
     10        * webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration-expected.txt:
     11
    1122020-09-21  Chris Dumez  <cdumez@apple.com>
    213
  • trunk/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration-expected.txt

    r267245 r267386  
    88PASS < [loop-count] All assertions passed. (total 1 assertions)
    99PASS > [delayed-start] 
    10 FAIL X The content of the left and right channel expected to be equal to the array [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...] but differs in 8128 places:
    11         Index   Actual                  Expected
    12         [8193]  7.8125000000000000e-3   0.0000000000000000e+0
    13         [8194]  1.5625000000000000e-2   0.0000000000000000e+0
    14         [8195]  2.3437500000000000e-2   0.0000000000000000e+0
    15         [8196]  3.1250000000000000e-2   0.0000000000000000e+0
    16         ...and 8124 more errors. assert_true: expected true got false
    17 FAIL < [delayed-start] 1 out of 1 assertions were failed. assert_true: expected true got false
    18 FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 2 tasks were failed. assert_true: expected true got false
     10PASS   The content of the left and right channel is identical to the array [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...].
     11PASS < [delayed-start] All assertions passed. (total 1 assertions)
     12PASS # AUDIT TASK RUNNER FINISHED: 2 tasks ran successfully.
    1913
  • trunk/Source/WebCore/ChangeLog

    r267383 r267386  
     12020-09-21  Chris Dumez  <cdumez@apple.com>
     2
     3        AudioBufferSourceNode should update grain parameters when buffer is set after rendering has started
     4        https://bugs.webkit.org/show_bug.cgi?id=216808
     5
     6        Reviewed by Eric Carlson.
     7
     8        AudioBufferSourceNode should update grain parameters when buffer is set after rendering has
     9        started. The grain parameters need to be adjusted so that they make sense given the buffer
     10        length. Previously, we would only update grain parameters in AudioBufferSourceNode::startPlaying(),
     11        when a buffer is set. We would fail to update those grain parameters when the buffer is set,
     12        in setBuffer(), if startPlaying() has already been called.
     13
     14        No new tests, rebaselined existing test.
     15
     16        * Modules/webaudio/AudioBufferSourceNode.cpp:
     17        (WebCore::AudioBufferSourceNode::setBuffer):
     18        (WebCore::AudioBufferSourceNode::startLater):
     19        (WebCore::AudioBufferSourceNode::startPlaying):
     20        (WebCore::AudioBufferSourceNode::updateGrainParameters):
     21        * Modules/webaudio/AudioBufferSourceNode.h:
     22
    1232020-09-21  Chris Dumez  <cdumez@apple.com>
    224
  • trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp

    r267170 r267386  
    451451    m_virtualReadIndex = 0;
    452452    m_buffer = WTFMove(buffer);
     453
     454    // In case the buffer gets set after playback has started, we need to clamp the grain parameters now.
     455    if (m_isGrain)
     456        adjustGrainParameters();
     457
    453458    return { };
    454459}
     
    459464}
    460465
    461 ExceptionOr<void> AudioBufferSourceNode::startLater(double when, double grainOffset, Optional<double> optionalGrainDuration)
    462 {
    463     double grainDuration = 0;
    464     if (optionalGrainDuration)
    465         grainDuration = optionalGrainDuration.value();
    466     else if (buffer())
    467         grainDuration = buffer()->duration() - grainOffset;
    468 
     466ExceptionOr<void> AudioBufferSourceNode::startLater(double when, double grainOffset, Optional<double> grainDuration)
     467{
    469468    return startPlaying(when, grainOffset, grainDuration);
    470469}
    471470
    472 ExceptionOr<void> AudioBufferSourceNode::startPlaying(double when, double grainOffset, double grainDuration)
     471ExceptionOr<void> AudioBufferSourceNode::startPlaying(double when, double grainOffset, Optional<double> grainDuration)
    473472{
    474473    ASSERT(isMainThread());
    475     ALWAYS_LOG(LOGIDENTIFIER, "when = ", when, ", offset = ", grainOffset, ", duration = ", grainDuration);
     474    ALWAYS_LOG(LOGIDENTIFIER, "when = ", when, ", offset = ", grainOffset, ", duration = ", grainDuration.valueOr(0));
    476475
    477476    context().nodeWillBeginPlayback();
     
    486485        return Exception { RangeError, "offset value should be positive"_s };
    487486
    488     if (!std::isfinite(grainDuration) || (grainDuration < 0))
     487    if (grainDuration && (!std::isfinite(*grainDuration) || (*grainDuration < 0)))
    489488        return Exception { RangeError, "duration value should be positive"_s };
     489
     490    // This synchronizes with process().
     491    auto locker = holdLock(m_processMutex);
    490492
    491493    m_isGrain = true;
    492494    m_grainOffset = grainOffset;
    493     m_grainDuration = grainDuration;
     495    m_grainDuration = grainDuration.valueOr(0);
     496    m_wasGrainDurationGiven = !!grainDuration;
    494497    m_startTime = when;
    495498
    496     if (buffer()) {
    497         // Do sanity checking of grain parameters versus buffer size.
    498         double bufferDuration = buffer()->duration();
    499 
    500         m_grainOffset = std::min(bufferDuration, grainOffset);
    501 
    502         double maxDuration = bufferDuration - m_grainOffset;
    503         m_grainDuration = std::min(maxDuration, grainDuration);
    504 
    505         // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
    506         // at a sub-sample position since it will degrade the quality.
    507         // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
    508         // Since playbackRate == 1 is very common, it's worth considering quality.
    509         if (playbackRate().value() < 0)
    510             m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, buffer()->sampleRate()) - 1;
    511         else
    512             m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
    513     }
     499    adjustGrainParameters();
     500
    514501    m_playbackState = SCHEDULED_STATE;
    515502
    516503    return { };
     504}
     505
     506void AudioBufferSourceNode::adjustGrainParameters()
     507{
     508    ASSERT(m_processMutex.isHeld());
     509
     510    auto buffer = this->buffer();
     511    if (!buffer)
     512        return;
     513
     514    // Do sanity checking of grain parameters versus buffer size.
     515    double bufferDuration = buffer->duration();
     516
     517    m_grainOffset = std::min(bufferDuration, m_grainOffset);
     518
     519    double maxDuration = bufferDuration - m_grainOffset;
     520
     521    if (m_wasGrainDurationGiven)
     522        m_grainDuration = std::min(m_grainDuration, maxDuration);
     523    else
     524        m_grainDuration = maxDuration;
     525
     526    // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
     527    // at a sub-sample position since it will degrade the quality.
     528    // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
     529    // Since playbackRate == 1 is very common, it's worth considering quality.
     530    if (playbackRate().value() < 0)
     531        m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, buffer->sampleRate()) - 1;
     532    else
     533        m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer->sampleRate());
    517534}
    518535
  • trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h

    r266794 r267386  
    100100    virtual bool shouldThrowOnAttemptToOverwriteBuffer() const { return true; }
    101101
    102     ExceptionOr<void> startPlaying(double when, double grainOffset, double grainDuration);
     102    ExceptionOr<void> startPlaying(double when, double grainOffset, Optional<double> grainDuration);
     103    void adjustGrainParameters();
    103104
    104105    // Returns true on success.
     
    135136    double m_grainOffset { 0 }; // in seconds
    136137    double m_grainDuration; // in seconds
     138    double m_wasGrainDurationGiven { false };
    137139
    138140    // totalPitchRate() returns the instantaneous pitch rate (non-time preserving).
Note: See TracChangeset for help on using the changeset viewer.