diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc index c5d329479a4..135588f56eb 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/modules/webaudio/audio_param.h" +#include "build/build_config.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h" #include "third_party/blink/renderer/modules/webaudio/audio_node.h" @@ -235,6 +236,49 @@ void AudioParamHandler::CalculateSampleAccurateValues( CalculateFinalValues(values, number_of_values, IsAudioRate()); } +// Replace NaN values in |values| with |default_value|. +static void HandleNaNValues(float* values, + unsigned number_of_values, + float default_value) { + unsigned k = 0; +#if defined(ARCH_CPU_X86_FAMILY) + if (number_of_values >= 4) { + __m128 defaults = _mm_set1_ps(default_value); + for (k = 0; k < number_of_values; k += 4) { + __m128 v = _mm_loadu_ps(values + k); + // cmpuord returns all 1's if v is NaN for each elmeent of v. + __m128 isnan = _mm_cmpunord_ps(v, v); + // Replace NaN parts with default. + __m128 result = _mm_and_ps(isnan, defaults); + // Merge in the parts that aren't NaN + result = _mm_or_ps(_mm_andnot_ps(isnan, v), result); + _mm_storeu_ps(values + k, result); + } + } +#elif defined(CPU_ARM_NEON) + if (number_of_values >= 4) { + uint32x4_t defaults = static_cast<uint32x4_t>(vdupq_n_f32(default_value)); + for (k = 0; k < number_of_values; k += 4) { + float32x4_t v = vld1q_f32(values + k); + // Returns true (all ones) if v is not NaN + uint32x4_t is_not_nan = vceqq_f32(v, v); + // Get the parts that are not NaN + uint32x4_t result = vandq_u32(is_not_nan, v); + // Replace the parts that are NaN with the default and merge with previous + // result. (Note: vbic_u32(x, y) = x and not y) + result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan)); + vst1q_f32(values + k, static_cast<float32x4_t>(result)); + } + } +#endif + + for (; k < number_of_values; ++k) { + if (std::isnan(values[k])) { + values[k] = default_value; + } + } +} + void AudioParamHandler::CalculateFinalValues(float* values, unsigned number_of_values, bool sample_accurate) { @@ -297,10 +341,21 @@ void AudioParamHandler::CalculateFinalValues(float* values, } } - // Clamp the values now to the nominal range float min_value = MinValue(); float max_value = MaxValue(); + if (NumberOfRenderingConnections() > 0) { + // AudioParams by themselves don't produce NaN because of the finite min + // and max values. But an input to an AudioParam could have NaNs. + // + // NaN values in AudioParams must be replaced by the AudioParam's + // defaultValue. Then these values must be clamped to lie in the nominal + // range between the AudioParam's minValue and maxValue. + // + // See https://webaudio.github.io/web-audio-api/#computation-of-value. + HandleNaNValues(values, number_of_values, DefaultValue()); + } + vector_math::Vclip(values, 1, &min_value, &max_value, values, 1, number_of_values); } |