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 |
| index 38ce1a72a186e43f64ebc3b301fb627e2013a2e2..3034681034d386c42c84859df31ab9387e4c9659 100644 |
| --- a/chromecast/media/cma/backend/alsa/slew_volume.cc |
| +++ b/chromecast/media/cma/backend/alsa/slew_volume.cc |
| @@ -14,7 +14,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) { |
| + memset(dest, 0, frames * sizeof(*dest)); |
|
halliwell
2017/05/05 17:24:50
inconsistent with std::memcpy below?
bshaya
2017/05/05 17:54:03
Done.
|
| + } |
| + |
| + 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 +68,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 +93,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,9 +107,24 @@ 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. |
| + /* Ensure |src| and |dest| are 16-byte aligned. */ |
|
halliwell
2017/05/05 17:24:50
why switching comment style in this file?
bshaya
2017/05/05 17:54:03
Done.
|
| DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & |
| (::media::vector_math::kRequiredAlignment - 1)); |
| DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & |
| @@ -82,22 +143,29 @@ 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; |
| current_volume_ += max_slew_per_sample_; |
| } while (current_volume_ < volume_scale_ && frames); |
| current_volume_ = std::min(current_volume_, volume_scale_); |
| - } else { // 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 +173,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 |