Chromium Code Reviews| Index: chromecast/media/cma/backend/alsa/slew_volume.cc |
| diff --git a/chromecast/media/cma/backend/alsa/slew_volume.cc b/chromecast/media/cma/backend/alsa/slew_volume.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..33d9299739758f9d0e1cf62780ccf09a9dc7de43 |
| --- /dev/null |
| +++ b/chromecast/media/cma/backend/alsa/slew_volume.cc |
| @@ -0,0 +1,146 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromecast/media/cma/backend/alsa/slew_volume.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "base/logging.h" |
| +#include "media/base/vector_math.h" |
| + |
| +namespace { |
| + |
| +// The time to slew from 0.0 to 1.0. |
| +const int kMaxSlewTimeMs = 100; |
| +const int kDefaultSampleRate = 44100; |
| +} |
| + |
| +namespace chromecast { |
| +namespace media { |
| + |
| +SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs, kMaxSlewTimeMs) {} |
| + |
| +SlewVolume::SlewVolume(int max_slew_time_up_ms, int max_slew_time_down_ms) |
| + : max_slew_time_up_ms_(max_slew_time_up_ms), |
| + max_slew_time_down_ms_(max_slew_time_down_ms), |
| + max_slew_up_(1000.0 / (max_slew_time_up_ms * kDefaultSampleRate)), |
| + max_slew_down_(1000.0 / (max_slew_time_down_ms * kDefaultSampleRate)) {} |
| + |
| +// Slew rate should be 1 / (slew_time * sample_rate) |
| +void SlewVolume::SetSampleRate(int sample_rate) { |
| + max_slew_up_ = (1000.0 / (max_slew_time_up_ms_ * sample_rate)); |
|
wzhong
2016/09/16 01:03:46
Nit: () is not needed.
jyw
2016/09/16 20:35:41
Done.
|
| + max_slew_down_ = (1000.0 / (max_slew_time_down_ms_ * sample_rate)); |
| +} |
| + |
| +void SlewVolume::SetVolume(double volume_scale) { |
| + volume_scale_ = volume_scale; |
| +} |
| + |
| +void SlewVolume::ProcessFMAC(bool repeat_transition, |
| + const float* src, |
| + int frames, |
| + float* dest) { |
| + DCHECK(src); |
|
wzhong
2016/09/16 01:03:47
DCHECK alignment.
jyw
2016/09/16 20:35:42
Done.
|
| + DCHECK(dest); |
| + |
| + if (!frames) { |
| + return; |
| + } |
| + |
| + if (repeat_transition) { |
| + current_volume_ = last_starting_volume_; |
| + } else { |
| + last_starting_volume_ = current_volume_; |
| + } |
| + |
| + if (current_volume_ == volume_scale_) { |
| + if (current_volume_ == 0.0) { |
|
wzhong
2016/09/16 01:03:47
NO need to clear dest?
jyw
2016/09/16 20:35:42
FMAC does dest[i] += src[i] * current_volume_; so
|
| + return; |
| + } |
| + ::media::vector_math::FMAC(src, current_volume_, frames, dest); |
| + return; |
| + } else if (current_volume_ < volume_scale_) { |
| + do { |
| + (*dest) += (*src) * current_volume_; |
| + ++src; |
| + ++dest; |
| + --frames; |
| + current_volume_ += max_slew_up_; |
| + } while (current_volume_ < volume_scale_ && frames); |
| + current_volume_ = std::min(current_volume_, volume_scale_); |
| + } else { // current_volume_ > volume_scale_ |
| + do { |
| + (*dest) += (*src) * current_volume_; |
| + ++src; |
| + ++dest; |
| + --frames; |
| + current_volume_ -= max_slew_down_; |
| + } while (current_volume_ > volume_scale_ && frames); |
| + current_volume_ = std::max(current_volume_, volume_scale_); |
| + } |
| + |
| + if (frames) { |
| + for (int f = 0; f < frames; ++f) { |
| + dest[f] += src[f] * current_volume_; |
| + } |
| + } |
| +} |
| + |
| +// Scaling samples naively like this takes 0.2% of the CPU's time @ 44100hz |
| +// on pineapple. |
| +// Assumes 2 channel audio. |
| +bool SlewVolume::ProcessInterleaved(int32_t* data, int frames) { |
| + DCHECK(data); |
| + |
| + if (!frames) { |
| + return true; |
| + } |
| + |
| + if (current_volume_ == volume_scale_) { |
| + if (current_volume_ == 1.0) { |
| + return true; |
| + } |
| + for (int i = 0; i < 2 * frames; ++i) { |
| + data[i] *= current_volume_; |
| + } |
| + return true; |
| + } else if (current_volume_ < volume_scale_) { |
| + do { |
| + (*data) *= current_volume_; |
| + ++data; |
| + (*data) *= current_volume_; |
| + ++data; |
| + --frames; |
| + current_volume_ += max_slew_up_; |
| + } while (current_volume_ < volume_scale_ && frames); |
| + current_volume_ = std::min(current_volume_, volume_scale_); |
| + } else { |
| + do { |
| + (*data) *= current_volume_; |
| + ++data; |
| + (*data) *= current_volume_; |
| + ++data; |
| + --frames; |
| + current_volume_ -= max_slew_down_; |
| + } while (current_volume_ > volume_scale_ && frames); |
| + current_volume_ = std::max(current_volume_, volume_scale_); |
| + } |
| + |
| + if (current_volume_ == 1.0) { |
| + return true; |
| + } |
| + |
| + if (current_volume_ == 0.0) { |
| + std::fill_n(data, frames * 2, 0); |
| + return true; |
| + } |
| + |
| + for (int i = 0; i < 2 * frames; ++i) { |
| + data[i] *= current_volume_; |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace media |
| +} // namespace chromecast |