chromium/third_party/blink/renderer/modules/webaudio/periodic_wave.cc

/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "third_party/blink/renderer/modules/webaudio/periodic_wave.h"

#include <algorithm>
#include <memory>

#include "build/build_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_periodic_wave_options.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/modules/webaudio/oscillator_node.h"
#include "third_party/blink/renderer/platform/audio/fft_frame.h"
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"

#if defined(ARCH_CPU_X86_FAMILY)
#include <xmmintrin.h>
#elif defined(CPU_ARM_NEON)
#include <arm_neon.h>
#endif

namespace blink {

namespace {

// The number of bands per octave.  Each octave will have this many entries in
// the wave tables.
constexpr unsigned kNumberOfOctaveBands =;

// The max length of a periodic wave. This must be a power of two greater than
// or equal to 2048 and must be supported by the FFT routines.
constexpr unsigned kMaxPeriodicWaveSize =;

constexpr float kCentsPerRange =;

}  // namespace

PeriodicWave* PeriodicWave::Create(BaseAudioContext& context,
                                   const Vector<float>& real,
                                   const Vector<float>& imag,
                                   bool disable_normalization,
                                   ExceptionState& exception_state) {}

PeriodicWave* PeriodicWave::Create(BaseAudioContext* context,
                                   const PeriodicWaveOptions* options,
                                   ExceptionState& exception_state) {}

PeriodicWave* PeriodicWave::CreateSine(float sample_rate) {}

PeriodicWave* PeriodicWave::CreateSquare(float sample_rate) {}

PeriodicWave* PeriodicWave::CreateSawtooth(float sample_rate) {}

PeriodicWave* PeriodicWave::CreateTriangle(float sample_rate) {}

PeriodicWave::PeriodicWave(float sample_rate)
    :{}

void PeriodicWave::Trace(Visitor* visitor) const {}

PeriodicWaveImpl::PeriodicWaveImpl(float sample_rate)
    :{}

PeriodicWaveImpl::~PeriodicWaveImpl() {}

unsigned PeriodicWaveImpl::PeriodicWaveSize() const {}

unsigned PeriodicWaveImpl::MaxNumberOfPartials() const {}

void PeriodicWaveImpl::WaveDataForFundamentalFrequency(
    float fundamental_frequency,
    float*& lower_wave_data,
    float*& higher_wave_data,
    float& table_interpolation_factor) {}

#if defined(ARCH_CPU_X86_FAMILY)
void PeriodicWaveImpl::WaveDataForFundamentalFrequency(
    const float fundamental_frequency[4],
    float* lower_wave_data[4],
    float* higher_wave_data[4],
    float table_interpolation_factor[4]) {}
#elif defined(CPU_ARM_NEON)
void PeriodicWaveImpl::WaveDataForFundamentalFrequency(
    const float fundamental_frequency[4],
    float* lower_wave_data[4],
    float* higher_wave_data[4],
    float table_interpolation_factor[4]) {
  // Negative frequencies are allowed, in which case we alias to the positive
  // frequency.
  float32x4_t frequency = vabsq_f32(vld1q_f32(fundamental_frequency));

  // pos = 0xffffffff if frequency > 0; otherwise 0.
  uint32x4_t pos = vcgtq_f32(frequency, vdupq_n_f32(0));

  // v_ratio = frequency / lowest_fundamental_frequency_.  But NEON
  // doesn't have a division instruction, so multiply by reciprocal.
  // (Aarch64 does, though).
  float32x4_t v_ratio =
      vmulq_f32(frequency, vdupq_n_f32(1 / lowest_fundamental_frequency_));

  // Select v_ratio or 0.5 depending on whether pos is all ones or all
  // zeroes.
  v_ratio = vbslq_f32(pos, v_ratio, vdupq_n_f32(0.5));

  float ratio[4] __attribute__((aligned(16)));
  vst1q_f32(ratio, v_ratio);

  float cents_above_lowest_frequency[4] __attribute__((aligned(16)));

  for (int k = 0; k < 4; ++k) {
    cents_above_lowest_frequency[k] = log2f(ratio[k]) * 1200;
  }

  float32x4_t v_pitch_range = vaddq_f32(
      vdupq_n_f32(1.0), vmulq_f32(vld1q_f32(cents_above_lowest_frequency),
                                  vdupq_n_f32(1 / cents_per_range_)));

  v_pitch_range = vmaxq_f32(v_pitch_range, vdupq_n_f32(0));
  v_pitch_range = vminq_f32(v_pitch_range, vdupq_n_f32(NumberOfRanges() - 1));

  const uint32x4_t v_index1 = vcvtq_u32_f32(v_pitch_range);
  uint32x4_t v_index2 = vaddq_u32(v_index1, vdupq_n_u32(1));
  v_index2 = vminq_u32(v_index2, vdupq_n_u32(NumberOfRanges() - 1));

  uint32_t range_index1[4] __attribute__((aligned(16)));
  uint32_t range_index2[4] __attribute__((aligned(16)));

  vst1q_u32(range_index1, v_index1);
  vst1q_u32(range_index2, v_index2);

  const float32x4_t table_factor =
      vsubq_f32(v_pitch_range, vcvtq_f32_u32(v_index1));
  vst1q_f32(table_interpolation_factor, table_factor);

  for (int k = 0; k < 4; ++k) {
    lower_wave_data[k] = band_limited_tables_[range_index2[k]]->Data();
    higher_wave_data[k] = band_limited_tables_[range_index1[k]]->Data();
  }
}
#else
void PeriodicWaveImpl::WaveDataForFundamentalFrequency(
    const float fundamental_frequency[4],
    float* lower_wave_data[4],
    float* higher_wave_data[4],
    float table_interpolation_factor[4]) {
  for (int k = 0; k < 4; ++k) {
    WaveDataForFundamentalFrequency(fundamental_frequency[k],
                                    lower_wave_data[k], higher_wave_data[k],
                                    table_interpolation_factor[k]);
  }
}
#endif

unsigned PeriodicWaveImpl::NumberOfPartialsForRange(
    unsigned range_index) const {}

// Tell V8 about the memory we're using so it can properly schedule garbage
// collects.
void PeriodicWaveImpl::AdjustV8ExternalMemory(int64_t delta) {}

// Convert into time-domain wave buffers.  One table is created for each range
// for non-aliasing playback at different playback rates.  Thus, higher ranges
// have more high-frequency partials culled out.
void PeriodicWaveImpl::CreateBandLimitedTables(const float* real_data,
                                               const float* imag_data,
                                               unsigned number_of_components,
                                               bool disable_normalization) {}

void PeriodicWaveImpl::GenerateBasicWaveform(int shape) {}

}  // namespace blink