Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1277)

Side by Side Diff: chromecast/media/cma/backend/alsa/slew_volume.cc

Issue 2860673003: [Chromecast] Correct libcast_governor behavior. (Closed)
Patch Set: Use template function instead of macro. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromecast/media/cma/backend/alsa/slew_volume.h" 5 #include "chromecast/media/cma/backend/alsa/slew_volume.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "media/base/vector_math.h" 10 #include "media/base/vector_math.h"
11 11
12 namespace { 12 namespace {
13 13
14 // The time to slew from current volume to target volume. 14 // The time to slew from current volume to target volume.
15 const int kMaxSlewTimeMs = 100; 15 const int kMaxSlewTimeMs = 100;
16 const int kDefaultSampleRate = 44100; 16 const int kDefaultSampleRate = 44100;
17 } 17
18 } // namespace
19
20 // Used to create ProcessFMAC and ProcessFMUL.
21 // |BULK_OPERATOR| processes all remaining data.
22 // |SINGLE_OPERATOR| processes a single datum.
23 // |ZERO_OPERATOR| is run when |current_volume_| is 0
24 // |UNITY_OPERATOR| is run when |current_volume_| is 1
kmackay 2017/05/05 00:37:17 Update this comment block
25
26 struct FMACTraits {
27 static void ProcessBulkData(const float* src,
28 float volume,
29 int frames,
30 float* dest) {
31 ::media::vector_math::FMAC(src, volume, frames, dest);
32 }
33
34 static void ProcessSingleDatum(const float* src, float volume, float* dest) {
35 (*dest) += (*src) * volume;
36 }
37
38 static void ProcessZeroVolume(const float* src, int frames, float* dest) {}
39
40 static void ProcessUnityVolume(const float* src, int frames, float* dest) {
41 ProcessBulkData(src, 1.0, frames, dest);
42 }
43 };
44
45 struct FMULTraits {
46 static void ProcessBulkData(const float* src,
47 float volume,
48 int frames,
49 float* dest) {
50 ::media::vector_math::FMUL(src, volume, frames, dest);
51 }
52
53 static void ProcessSingleDatum(const float* src, float volume, float* dest) {
54 (*dest) = (*src) * volume;
55 }
56
57 static void ProcessZeroVolume(const float* src, int frames, float* dest) {
58 memset(dest, 0, frames * sizeof(*dest));
59 }
60
61 static void ProcessUnityVolume(const float* src, int frames, float* dest) {
62 if (src == dest) {
63 return;
64 }
65 std::memcpy(dest, src, frames * sizeof(*dest));
66 }
67 };
18 68
19 namespace chromecast { 69 namespace chromecast {
20 namespace media { 70 namespace media {
21 71
22 SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {} 72 SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {}
23 73
24 SlewVolume::SlewVolume(int max_slew_time_ms) 74 SlewVolume::SlewVolume(int max_slew_time_ms)
25 : sample_rate_(kDefaultSampleRate), 75 : sample_rate_(kDefaultSampleRate),
26 max_slew_time_ms_(max_slew_time_ms), 76 max_slew_time_ms_(max_slew_time_ms),
27 max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) { 77 max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) {}
28 LOG(INFO) << "Creating a slew volume: " << max_slew_time_ms;
29 }
30 78
31 void SlewVolume::SetSampleRate(int sample_rate) { 79 void SlewVolume::SetSampleRate(int sample_rate) {
80 DCHECK_GT(sample_rate, 0);
81
32 sample_rate_ = sample_rate; 82 sample_rate_ = sample_rate;
33 SetVolume(volume_scale_); 83 SetVolume(volume_scale_);
34 } 84 }
35 85
36 // Slew rate should be volume_to_slew / slew_time / sample_rate 86 // Slew rate should be volume_to_slew / slew_time / sample_rate
37 void SlewVolume::SetVolume(double volume_scale) { 87 void SlewVolume::SetVolume(double volume_scale) {
38 volume_scale_ = volume_scale; 88 volume_scale_ = volume_scale;
39 if (interrupted_) { 89 if (interrupted_) {
40 current_volume_ = volume_scale_; 90 current_volume_ = volume_scale_;
41 } 91 }
42 if (volume_scale_ > current_volume_) { 92 if (volume_scale_ > current_volume_) {
43 max_slew_per_sample_ = (volume_scale_ - current_volume_) * 1000.0 / 93 max_slew_per_sample_ = (volume_scale_ - current_volume_) * 1000.0 /
44 (max_slew_time_ms_ * sample_rate_); 94 (max_slew_time_ms_ * sample_rate_);
45 } else { 95 } else {
46 max_slew_per_sample_ = (current_volume_ - volume_scale_) * 1000.0 / 96 max_slew_per_sample_ = (current_volume_ - volume_scale_) * 1000.0 /
47 (max_slew_time_ms_ * sample_rate_); 97 (max_slew_time_ms_ * sample_rate_);
48 } 98 }
49 } 99 }
50 100
51 void SlewVolume::SetMaxSlewTimeMs(int max_slew_time_ms) { 101 void SlewVolume::SetMaxSlewTimeMs(int max_slew_time_ms) {
102 DCHECK_GE(max_slew_time_ms, 0);
103
52 max_slew_time_ms_ = max_slew_time_ms; 104 max_slew_time_ms_ = max_slew_time_ms;
53 } 105 }
54 106
55 void SlewVolume::Interrupted() { 107 void SlewVolume::Interrupted() {
56 interrupted_ = true; 108 interrupted_ = true;
57 current_volume_ = volume_scale_; 109 current_volume_ = volume_scale_;
58 } 110 }
59 111
60 void SlewVolume::ProcessFMAC(bool repeat_transition, 112 void SlewVolume::ProcessFMAC(bool repeat_transition,
61 const float* src, 113 const float* src,
62 int frames, 114 int frames,
63 float* dest) { 115 float* dest) {
116 ProcessData<FMACTraits>(repeat_transition, src, frames, dest);
117 }
118
119 void SlewVolume::ProcessFMUL(bool repeat_transition,
120 const float* src,
121 int frames,
122 float* dest) {
123 ProcessData<FMULTraits>(repeat_transition, src, frames, dest);
124 }
125
126 template <typename Traits>
127 void SlewVolume::ProcessData(bool repeat_transition,
128 const float* src,
129 int frames,
130 float* dest) {
64 DCHECK(src); 131 DCHECK(src);
65 DCHECK(dest); 132 DCHECK(dest);
66 // Ensure |src| and |dest| are 16-byte aligned. 133 /* Ensure |src| and |dest| are 16-byte aligned. */
67 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & 134 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) &
68 (::media::vector_math::kRequiredAlignment - 1)); 135 (::media::vector_math::kRequiredAlignment - 1));
69 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & 136 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) &
70 (::media::vector_math::kRequiredAlignment - 1)); 137 (::media::vector_math::kRequiredAlignment - 1));
71 138
72 if (!frames) { 139 if (!frames) {
73 return; 140 return;
74 } 141 }
75 142
76 interrupted_ = false; 143 interrupted_ = false;
77 if (repeat_transition) { 144 if (repeat_transition) {
78 current_volume_ = last_starting_volume_; 145 current_volume_ = last_starting_volume_;
79 } else { 146 } else {
80 last_starting_volume_ = current_volume_; 147 last_starting_volume_ = current_volume_;
81 } 148 }
82 149
83 if (current_volume_ == volume_scale_) { 150 if (current_volume_ == volume_scale_) {
84 if (current_volume_ == 0.0) { 151 if (current_volume_ == 0.0) {
152 Traits::ProcessZeroVolume(src, frames, dest);
85 return; 153 return;
86 } 154 }
87 ::media::vector_math::FMAC(src, current_volume_, frames, dest); 155 if (current_volume_ == 1.0) {
156 Traits::ProcessUnityVolume(src, frames, dest);
157 return;
158 }
159 Traits::ProcessBulkData(src, current_volume_, frames, dest);
88 return; 160 return;
89 } else if (current_volume_ < volume_scale_) { 161 }
162
163 if (current_volume_ < volume_scale_) {
90 do { 164 do {
91 (*dest) += (*src) * current_volume_; 165 Traits::ProcessSingleDatum(src, current_volume_, dest);
92 ++src; 166 ++src;
93 ++dest; 167 ++dest;
94 --frames; 168 --frames;
95 current_volume_ += max_slew_per_sample_; 169 current_volume_ += max_slew_per_sample_;
96 } while (current_volume_ < volume_scale_ && frames); 170 } while (current_volume_ < volume_scale_ && frames);
97 current_volume_ = std::min(current_volume_, volume_scale_); 171 current_volume_ = std::min(current_volume_, volume_scale_);
98 } else { // current_volume_ > volume_scale_ 172 } else { /* current_volume_ > volume_scale_ */
99 do { 173 do {
100 (*dest) += (*src) * current_volume_; 174 Traits::ProcessSingleDatum(src, current_volume_, dest);
101 ++src; 175 ++src;
102 ++dest; 176 ++dest;
103 --frames; 177 --frames;
104 current_volume_ -= max_slew_per_sample_; 178 current_volume_ -= max_slew_per_sample_;
105 } while (current_volume_ > volume_scale_ && frames); 179 } while (current_volume_ > volume_scale_ && frames);
106 current_volume_ = std::max(current_volume_, volume_scale_); 180 current_volume_ = std::max(current_volume_, volume_scale_);
107 } 181 }
108 182 while (frames && (reinterpret_cast<uintptr_t>(src) &
109 if (frames) { 183 (::media::vector_math::kRequiredAlignment - 1))) {
110 for (int f = 0; f < frames; ++f) { 184 Traits::ProcessSingleDatum(src, current_volume_, dest);
111 dest[f] += src[f] * current_volume_; 185 ++src;
112 } 186 ++dest;
187 --frames;
113 } 188 }
114 }
115
116 // Scaling samples naively like this takes 0.2% of the CPU's time @ 44100hz
117 // on pineapple.
118 // Assumes 2 channel audio.
119 bool SlewVolume::ProcessInterleaved(int32_t* data, int frames) {
120 DCHECK(data);
121
122 if (!frames) { 189 if (!frames) {
123 return true; 190 return;
124 } 191 }
125 192 Traits::ProcessBulkData(src, current_volume_, frames, dest);
126 interrupted_ = false;
127 if (current_volume_ == volume_scale_) {
128 if (current_volume_ == 1.0) {
129 return true;
130 }
131 for (int i = 0; i < 2 * frames; ++i) {
132 data[i] *= current_volume_;
133 }
134 return true;
135 } else if (current_volume_ < volume_scale_) {
136 do {
137 (*data) *= current_volume_;
138 ++data;
139 (*data) *= current_volume_;
140 ++data;
141 --frames;
142 current_volume_ += max_slew_per_sample_;
143 } while (current_volume_ < volume_scale_ && frames);
144 current_volume_ = std::min(current_volume_, volume_scale_);
145 } else {
146 do {
147 (*data) *= current_volume_;
148 ++data;
149 (*data) *= current_volume_;
150 ++data;
151 --frames;
152 current_volume_ -= max_slew_per_sample_;
153 } while (current_volume_ > volume_scale_ && frames);
154 current_volume_ = std::max(current_volume_, volume_scale_);
155 }
156
157 if (current_volume_ == 1.0) {
158 return true;
159 }
160
161 if (current_volume_ == 0.0) {
162 std::fill_n(data, frames * 2, 0);
163 return true;
164 }
165
166 for (int i = 0; i < 2 * frames; ++i) {
167 data[i] *= current_volume_;
168 }
169 return true;
170 } 193 }
171 194
172 } // namespace media 195 } // namespace media
173 } // namespace chromecast 196 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/cma/backend/alsa/slew_volume.h ('k') | chromecast/media/cma/backend/alsa/slew_volume_unittests.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698