Commit 4df2ec50 authored by Michael Montvelishsky's avatar Michael Montvelishsky Committed by Commit Bot

Add cosine volume slew.

Raised cosine add less audible artifacts when used as volume slew
curve, compared to linear one.

Recurrent calculation of slew cosine is based on:
https://basesandframes.files.wordpress.com/2016/05/rgreenfastermath_gdc02.pdf

Bug: internal b/167251783
Change-Id: Ia9262700ecc0b9f4ee5e3895cc9864480eabab73
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2391894Reviewed-by: default avatarKenneth MacKay <kmackay@chromium.org>
Commit-Queue: Kenneth MacKay <kmackay@chromium.org>
Auto-Submit: Michael Montvelishsky <mont@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804478}
parent a33189c2
...@@ -68,9 +68,13 @@ namespace media { ...@@ -68,9 +68,13 @@ namespace media {
SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {} SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {}
SlewVolume::SlewVolume(int max_slew_time_ms) SlewVolume::SlewVolume(int max_slew_time_ms)
: SlewVolume(max_slew_time_ms, false) {}
SlewVolume::SlewVolume(int max_slew_time_ms, bool use_cosine_slew)
: sample_rate_(kDefaultSampleRate), : sample_rate_(kDefaultSampleRate),
max_slew_time_ms_(max_slew_time_ms), max_slew_time_ms_(max_slew_time_ms),
max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) {} max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)),
use_cosine_slew_(use_cosine_slew) {}
void SlewVolume::SetSampleRate(int sample_rate) { void SlewVolume::SetSampleRate(int sample_rate) {
CHECK_GT(sample_rate, 0); CHECK_GT(sample_rate, 0);
...@@ -92,6 +96,16 @@ void SlewVolume::SetVolume(double volume_scale) { ...@@ -92,6 +96,16 @@ void SlewVolume::SetVolume(double volume_scale) {
std::max(0.1, std::fabs(volume_scale_ - current_volume_)); std::max(0.1, std::fabs(volume_scale_ - current_volume_));
max_slew_per_sample_ = max_slew_per_sample_ =
volume_diff * 1000.0 / (max_slew_time_ms_ * sample_rate_); volume_diff * 1000.0 / (max_slew_time_ms_ * sample_rate_);
if (use_cosine_slew_) {
// Set initial state for cosine slew. Cosine fading always lasts
// max_slew_time_ms_.
slew_counter_ = max_slew_time_ms_ * 0.001 * sample_rate_;
slew_angle_ = sin(M_PI / slew_counter_);
slew_offset_ = (current_volume_ + volume_scale_) * 0.5;
slew_cos_ = (current_volume_ - volume_scale_) * 0.5;
slew_sin_ = 0.0;
}
} }
float SlewVolume::LastBufferMaxMultiplier() { float SlewVolume::LastBufferMaxMultiplier() {
...@@ -163,7 +177,24 @@ void SlewVolume::ProcessData(bool repeat_transition, ...@@ -163,7 +177,24 @@ void SlewVolume::ProcessData(bool repeat_transition,
return; return;
} }
if (current_volume_ < volume_scale_) { if (use_cosine_slew_) {
int slew_frames = std::min(slew_counter_, frames);
frames -= slew_frames;
slew_counter_ -= slew_frames;
for (; slew_frames > 0; --slew_frames) {
slew_cos_ -= slew_sin_ * slew_angle_;
slew_sin_ += slew_cos_ * slew_angle_;
current_volume_ = std::min(1.0, std::max(0.0, slew_offset_ + slew_cos_));
for (int i = 0; i < channels; ++i) {
Traits::ProcessSingleDatum(src, current_volume_, dest);
++src;
++dest;
}
}
if (!slew_counter_) {
current_volume_ = volume_scale_;
}
} else if (current_volume_ < volume_scale_) {
do { do {
for (int i = 0; i < channels; ++i) { for (int i = 0; i < channels; ++i) {
Traits::ProcessSingleDatum(src, current_volume_, dest); Traits::ProcessSingleDatum(src, current_volume_, dest);
......
...@@ -18,6 +18,9 @@ class SlewVolume { ...@@ -18,6 +18,9 @@ class SlewVolume {
public: public:
SlewVolume(); SlewVolume();
explicit SlewVolume(int max_slew_time_ms); explicit SlewVolume(int max_slew_time_ms);
// Use raised negative cosine function when |use_cosine_slew| is true and
// linear otherwise.
SlewVolume(int max_slew_time_ms, bool use_cosine_slew);
~SlewVolume() = default; ~SlewVolume() = default;
void SetSampleRate(int sample_rate); void SetSampleRate(int sample_rate);
...@@ -76,7 +79,12 @@ class SlewVolume { ...@@ -76,7 +79,12 @@ class SlewVolume {
double max_slew_time_ms_; double max_slew_time_ms_;
double max_slew_per_sample_; double max_slew_per_sample_;
bool interrupted_ = true; bool interrupted_ = true;
bool use_cosine_slew_ = false;
int slew_counter_;
double slew_angle_;
double slew_offset_;
double slew_cos_;
double slew_sin_;
DISALLOW_COPY_AND_ASSIGN(SlewVolume); DISALLOW_COPY_AND_ASSIGN(SlewVolume);
}; };
......
...@@ -48,7 +48,7 @@ MixerInput::MixerInput(Source* source, FilterGroup* filter_group) ...@@ -48,7 +48,7 @@ MixerInput::MixerInput(Source* source, FilterGroup* filter_group)
primary_(source->primary()), primary_(source->primary()),
device_id_(source->device_id()), device_id_(source->device_id()),
content_type_(source->content_type()), content_type_(source->content_type()),
slew_volume_(kDefaultSlewTimeMs), slew_volume_(kDefaultSlewTimeMs, true),
volume_applied_(false), volume_applied_(false),
previous_ended_in_silence_(false), previous_ended_in_silence_(false),
first_buffer_(true), first_buffer_(true),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment