blob: aefb8f03191c2808ec2157c6b75d5d9db7be0ac0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#ifndef SRC_MEDIA_AUDIO_AUDIO_CORE_MIXER_FILTER_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_MIXER_FILTER_H_
#include <lib/syslog/cpp/macros.h>
#include <cmath>
#include <memory>
#include <vector>
#include "src/media/audio/audio_core/mixer/coefficient_table.h"
#include "src/media/audio/audio_core/mixer/coefficient_table_cache.h"
#include "src/media/audio/audio_core/mixer/constants.h"
#include "src/media/audio/lib/format/constants.h"
namespace media::audio::mixer {
// This class represents a symmetric, convolution-based filter, to be applied to an audio stream.
//
// Param side_length is the number of subframes included on each side, including center subframe 0.
// Child classes differ only in their filter coefficients.
class Filter {
public:
Filter(int32_t source_rate, int32_t dest_rate, int64_t side_length,
int32_t num_frac_bits = Fixed::Format::FractionalBits)
: source_rate_(source_rate),
dest_rate_(dest_rate),
side_length_(side_length),
num_frac_bits_(num_frac_bits),
frac_size_(1 << num_frac_bits),
rate_conversion_ratio_(static_cast<double>(dest_rate_) / source_rate_) {
FX_DCHECK(source_rate_ > 0);
FX_DCHECK(dest_rate_ > 0);
FX_DCHECK(side_length > 0);
FX_DCHECK(num_frac_bits_ > 0);
}
virtual float ComputeSample(int64_t frac_offset, float* center) = 0;
int32_t source_rate() const { return source_rate_; }
int32_t dest_rate() const { return dest_rate_; }
int64_t side_length() const { return side_length_; }
int32_t num_frac_bits() const { return num_frac_bits_; }
int64_t frac_size() const { return frac_size_; }
double rate_conversion_ratio() const { return rate_conversion_ratio_; }
// used for debugging purposes only
virtual void Display() = 0;
// Eagerly precompute needed data. If not called, lazily compute on the first ComputeSample() call
// TODO(fxbug.dev/45074): This is for tests only and can be removed once filter creation is eager.
virtual void EagerlyPrepare() = 0;
protected:
float ComputeSampleFromTable(const CoefficientTable& filter_coefficients, int64_t frac_offset,
float* center);
void DisplayTable(const CoefficientTable& filter_coefficients);
private:
int32_t source_rate_;
int32_t dest_rate_;
int64_t side_length_;
int32_t num_frac_bits_;
int64_t frac_size_;
double rate_conversion_ratio_;
};
// See PointFilterCoefficientTable.
class PointFilter : public Filter {
public:
PointFilter(int32_t source_rate, int32_t dest_rate,
int32_t num_frac_bits = Fixed::Format::FractionalBits)
: Filter(source_rate, dest_rate,
/* side_length= */ (1 << (num_frac_bits - 1)) + 1, num_frac_bits),
filter_coefficients_(cache_, Inputs{
.side_length = this->side_length(),
.num_frac_bits = this->num_frac_bits(),
}) {}
float ComputeSample(int64_t frac_offset, float* center) override {
return ComputeSampleFromTable(*filter_coefficients_, frac_offset, center);
}
void Display() override { DisplayTable(*filter_coefficients_); }
const float& operator[](int64_t index) { return (*filter_coefficients_)[index]; }
void EagerlyPrepare() override { filter_coefficients_.get(); }
private:
using Inputs = PointFilterCoefficientTable::Inputs;
using CacheT = CoefficientTableCache<Inputs>;
static CacheT* const cache_;
LazySharedCoefficientTable<Inputs> filter_coefficients_;
};
// See LinearFilterCoefficientTable.
class LinearFilter : public Filter {
public:
LinearFilter(int32_t source_rate, int32_t dest_rate,
int32_t num_frac_bits = Fixed::Format::FractionalBits)
: Filter(source_rate, dest_rate,
/* side_length= */ 1 << num_frac_bits, num_frac_bits),
filter_coefficients_(cache_, Inputs{
.side_length = this->side_length(),
.num_frac_bits = this->num_frac_bits(),
}) {}
float ComputeSample(int64_t frac_offset, float* center) override {
return ComputeSampleFromTable(*filter_coefficients_, frac_offset, center);
}
void Display() override { DisplayTable(*filter_coefficients_); }
const float& operator[](int64_t index) { return (*filter_coefficients_)[index]; }
void EagerlyPrepare() override { filter_coefficients_.get(); }
private:
using Inputs = LinearFilterCoefficientTable::Inputs;
using CacheT = CoefficientTableCache<Inputs>;
static CacheT* const cache_;
LazySharedCoefficientTable<Inputs> filter_coefficients_;
};
// See SincFilterCoefficientTable.
class SincFilter : public Filter {
public:
static constexpr auto kSideTaps = SincFilterCoefficientTable::kSideTaps;
static constexpr auto kFracSideLength = SincFilterCoefficientTable::kFracSideLength;
static constexpr auto kMaxFracSideLength = SincFilterCoefficientTable::kMaxFracSideLength;
SincFilter(int32_t source_rate, int32_t dest_rate,
int64_t side_length = SincFilterCoefficientTable::kFracSideLength,
int32_t num_frac_bits = Fixed::Format::FractionalBits)
: Filter(source_rate, dest_rate, side_length, num_frac_bits),
filter_coefficients_(cache_, Inputs{
.side_length = this->side_length(),
.num_frac_bits = this->num_frac_bits(),
.rate_conversion_ratio = this->rate_conversion_ratio(),
}) {}
static inline Fixed Length(int32_t source_frame_rate, int32_t dest_frame_rate) {
return SincFilterCoefficientTable::Length(source_frame_rate, dest_frame_rate);
}
float ComputeSample(int64_t frac_offset, float* center) override {
return ComputeSampleFromTable(*filter_coefficients_, frac_offset, center);
}
void Display() override { DisplayTable(*filter_coefficients_); }
const float& operator[](int64_t index) { return (*filter_coefficients_)[index]; }
void EagerlyPrepare() override { filter_coefficients_.get(); }
private:
using Inputs = SincFilterCoefficientTable::Inputs;
using CacheT = CoefficientTableCache<Inputs>;
friend CacheT* CreateSincFilterCoefficientTableCache();
static CacheT* const cache_;
static std::vector<CacheT::SharedPtr>* persistent_cache_;
LazySharedCoefficientTable<Inputs> filter_coefficients_;
};
} // namespace media::audio::mixer
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_MIXER_FILTER_H_