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 |
index 38ce1a72a186e43f64ebc3b301fb627e2013a2e2..6f2c5fe415fba83ab3273da82f7b8f8ac3951e66 100644 |
--- a/chromecast/media/cma/backend/alsa/slew_volume.cc |
+++ b/chromecast/media/cma/backend/alsa/slew_volume.cc |
@@ -5,6 +5,7 @@ |
#include "chromecast/media/cma/backend/alsa/slew_volume.h" |
#include <algorithm> |
+#include <cstring> |
#include "base/logging.h" |
#include "media/base/vector_math.h" |
@@ -14,7 +15,51 @@ namespace { |
// The time to slew from current volume to target volume. |
const int kMaxSlewTimeMs = 100; |
const int kDefaultSampleRate = 44100; |
-} |
+ |
+} // namespace |
+ |
+struct FMACTraits { |
+ static void ProcessBulkData(const float* src, |
+ float volume, |
+ int frames, |
+ float* dest) { |
+ ::media::vector_math::FMAC(src, volume, frames, dest); |
+ } |
+ |
+ static void ProcessSingleDatum(const float* src, float volume, float* dest) { |
+ (*dest) += (*src) * volume; |
+ } |
+ |
+ static void ProcessZeroVolume(const float* src, int frames, float* dest) {} |
+ |
+ static void ProcessUnityVolume(const float* src, int frames, float* dest) { |
+ ProcessBulkData(src, 1.0, frames, dest); |
+ } |
+}; |
+ |
+struct FMULTraits { |
+ static void ProcessBulkData(const float* src, |
+ float volume, |
+ int frames, |
+ float* dest) { |
+ ::media::vector_math::FMUL(src, volume, frames, dest); |
+ } |
+ |
+ static void ProcessSingleDatum(const float* src, float volume, float* dest) { |
+ (*dest) = (*src) * volume; |
+ } |
+ |
+ static void ProcessZeroVolume(const float* src, int frames, float* dest) { |
+ std::memset(dest, 0, frames * sizeof(*dest)); |
+ } |
+ |
+ static void ProcessUnityVolume(const float* src, int frames, float* dest) { |
+ if (src == dest) { |
+ return; |
+ } |
+ std::memcpy(dest, src, frames * sizeof(*dest)); |
+ } |
+}; |
namespace chromecast { |
namespace media { |
@@ -24,11 +69,11 @@ SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {} |
SlewVolume::SlewVolume(int max_slew_time_ms) |
: sample_rate_(kDefaultSampleRate), |
max_slew_time_ms_(max_slew_time_ms), |
- max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) { |
- LOG(INFO) << "Creating a slew volume: " << max_slew_time_ms; |
-} |
+ max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) {} |
void SlewVolume::SetSampleRate(int sample_rate) { |
+ DCHECK_GT(sample_rate, 0); |
+ |
sample_rate_ = sample_rate; |
SetVolume(volume_scale_); |
} |
@@ -49,6 +94,8 @@ void SlewVolume::SetVolume(double volume_scale) { |
} |
void SlewVolume::SetMaxSlewTimeMs(int max_slew_time_ms) { |
+ DCHECK_GE(max_slew_time_ms, 0); |
+ |
max_slew_time_ms_ = max_slew_time_ms; |
} |
@@ -61,6 +108,21 @@ void SlewVolume::ProcessFMAC(bool repeat_transition, |
const float* src, |
int frames, |
float* dest) { |
+ ProcessData<FMACTraits>(repeat_transition, src, frames, dest); |
+} |
+ |
+void SlewVolume::ProcessFMUL(bool repeat_transition, |
+ const float* src, |
+ int frames, |
+ float* dest) { |
+ ProcessData<FMULTraits>(repeat_transition, src, frames, dest); |
+} |
+ |
+template <typename Traits> |
+void SlewVolume::ProcessData(bool repeat_transition, |
+ const float* src, |
+ int frames, |
+ float* dest) { |
DCHECK(src); |
DCHECK(dest); |
// Ensure |src| and |dest| are 16-byte aligned. |
@@ -82,13 +144,20 @@ void SlewVolume::ProcessFMAC(bool repeat_transition, |
if (current_volume_ == volume_scale_) { |
if (current_volume_ == 0.0) { |
+ Traits::ProcessZeroVolume(src, frames, dest); |
+ return; |
+ } |
+ if (current_volume_ == 1.0) { |
+ Traits::ProcessUnityVolume(src, frames, dest); |
return; |
} |
- ::media::vector_math::FMAC(src, current_volume_, frames, dest); |
+ Traits::ProcessBulkData(src, current_volume_, frames, dest); |
return; |
- } else if (current_volume_ < volume_scale_) { |
+ } |
+ |
+ if (current_volume_ < volume_scale_) { |
do { |
- (*dest) += (*src) * current_volume_; |
+ Traits::ProcessSingleDatum(src, current_volume_, dest); |
++src; |
++dest; |
--frames; |
@@ -97,7 +166,7 @@ void SlewVolume::ProcessFMAC(bool repeat_transition, |
current_volume_ = std::min(current_volume_, volume_scale_); |
} else { // current_volume_ > volume_scale_ |
do { |
- (*dest) += (*src) * current_volume_; |
+ Traits::ProcessSingleDatum(src, current_volume_, dest); |
++src; |
++dest; |
--frames; |
@@ -105,68 +174,17 @@ void SlewVolume::ProcessFMAC(bool repeat_transition, |
} 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_; |
- } |
+ while (frames && (reinterpret_cast<uintptr_t>(src) & |
+ (::media::vector_math::kRequiredAlignment - 1))) { |
+ Traits::ProcessSingleDatum(src, current_volume_, dest); |
+ ++src; |
+ ++dest; |
+ --frames; |
} |
-} |
- |
-// 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; |
- } |
- |
- interrupted_ = false; |
- 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_per_sample_; |
- } 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_per_sample_; |
- } 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; |
} |
- return true; |
+ Traits::ProcessBulkData(src, current_volume_, frames, dest); |
} |
} // namespace media |