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..95a5d5dced39a8dc5c0b97ad2630d06fd0a4b7b2 |
--- /dev/null |
+++ b/chromecast/media/cma/backend/alsa/slew_volume.cc |
@@ -0,0 +1,151 @@ |
+// 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) |
wzhong
2016/09/19 04:48:13
Please add period.
|
+void SlewVolume::SetSampleRate(int sample_rate) { |
+ max_slew_up_ = 1000.0 / (max_slew_time_up_ms_ * sample_rate); |
+ 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); |
+ DCHECK(dest); |
+ // Ensure |src| and |dest| are 16-byte aligned. |
+ DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & |
+ (::media::vector_math::kRequiredAlignment - 1)); |
+ DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & |
+ (::media::vector_math::kRequiredAlignment - 1)); |
+ |
+ 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) { |
+ return; |
+ } |
+ ::media::vector_math::FMAC(src, current_volume_, frames, dest); |
+ return; |
+ } else if (current_volume_ < volume_scale_) { |
wzhong
2016/09/19 04:48:13
Nit: else is not needed.
|
+ 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_) { |
wzhong
2016/09/19 04:48:13
Ditto.
|
+ 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 |