1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/base/audio_bus.h" 6 7 #include "base/logging.h" 8 #include "base/safe_numerics.h" 9 #include "media/audio/audio_parameters.h" 10 #include "media/base/limits.h" 11 #include "media/base/vector_math.h" 12 13 namespace media { 14 15 static const uint8 kUint8Bias = 128; 16 17 static bool IsAligned(void* ptr) { 18 return (reinterpret_cast<uintptr_t>(ptr) & 19 (AudioBus::kChannelAlignment - 1)) == 0U; 20 } 21 22 // Calculates the required size for an AudioBus with the given params, sets 23 // |aligned_frames| to the actual frame length of each channel array. 24 static int CalculateMemorySizeInternal(int channels, int frames, 25 int* out_aligned_frames) { 26 // Choose a size such that each channel will be aligned by 27 // kChannelAlignment when stored in a contiguous block. 28 int aligned_frames = 29 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & 30 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); 31 32 if (out_aligned_frames) 33 *out_aligned_frames = aligned_frames; 34 35 return sizeof(float) * channels * aligned_frames; 36 } 37 38 // |Format| is the destination type. If a bias is present, |Fixed| must be a 39 // type larger than |Format| such that operations can be made without 40 // overflowing. Without a bias |Fixed| must be the same as |Format|. 41 template<class Format, class Fixed, Format Bias> 42 static void FromInterleavedInternal(const void* src, int start_frame, 43 int frames, AudioBus* dest, 44 float min, float max) { 45 COMPILE_ASSERT((Bias == 0 && sizeof(Fixed) == sizeof(Format)) || 46 sizeof(Fixed) > sizeof(Format), invalid_deinterleave_types); 47 const Format* source = static_cast<const Format*>(src); 48 const int channels = dest->channels(); 49 for (int ch = 0; ch < channels; ++ch) { 50 float* channel_data = dest->channel(ch); 51 for (int i = start_frame, offset = ch; i < start_frame + frames; 52 ++i, offset += channels) { 53 const Fixed v = static_cast<Fixed>(source[offset]) - Bias; 54 channel_data[i] = v * (v < 0 ? -min : max); 55 } 56 } 57 } 58 59 // |Format| is the destination type. If a bias is present, |Fixed| must be a 60 // type larger than |Format| such that operations can be made without 61 // overflowing. Without a bias |Fixed| must be the same as |Format|. 62 template<class Format, class Fixed, Format Bias> 63 static void ToInterleavedInternal(const AudioBus* source, int start_frame, 64 int frames, void* dst, Fixed min, Fixed max) { 65 COMPILE_ASSERT((Bias == 0 && sizeof(Fixed) == sizeof(Format)) || 66 sizeof(Fixed) > sizeof(Format), invalid_interleave_types); 67 Format* dest = static_cast<Format*>(dst); 68 const int channels = source->channels(); 69 for (int ch = 0; ch < channels; ++ch) { 70 const float* channel_data = source->channel(ch); 71 for (int i = start_frame, offset = ch; i < start_frame + frames; 72 ++i, offset += channels) { 73 const float v = channel_data[i]; 74 75 Fixed sample; 76 if (v < 0) 77 sample = v <= -1 ? min : static_cast<Fixed>(-v * min); 78 else 79 sample = v >= 1 ? max : static_cast<Fixed>(v * max); 80 81 dest[offset] = static_cast<Format>(sample) + Bias; 82 } 83 } 84 } 85 86 static void ValidateConfig(int channels, int frames) { 87 CHECK_GT(frames, 0); 88 CHECK_GT(channels, 0); 89 CHECK_LE(channels, static_cast<int>(limits::kMaxChannels)); 90 } 91 92 static void CheckOverflow(int start_frame, int frames, int total_frames) { 93 CHECK_GE(start_frame, 0); 94 CHECK_GE(frames, 0); 95 CHECK_GT(total_frames, 0); 96 int sum = start_frame + frames; 97 CHECK_LE(sum, total_frames); 98 CHECK_GE(sum, 0); 99 } 100 101 AudioBus::AudioBus(int channels, int frames) 102 : frames_(frames), 103 can_set_channel_data_(false) { 104 ValidateConfig(channels, frames_); 105 106 int aligned_frames = 0; 107 int size = CalculateMemorySizeInternal(channels, frames, &aligned_frames); 108 109 data_.reset(static_cast<float*>(base::AlignedAlloc( 110 size, AudioBus::kChannelAlignment))); 111 112 BuildChannelData(channels, aligned_frames, data_.get()); 113 } 114 115 AudioBus::AudioBus(int channels, int frames, float* data) 116 : frames_(frames), 117 can_set_channel_data_(false) { 118 // Since |data| may have come from an external source, ensure it's valid. 119 CHECK(data); 120 ValidateConfig(channels, frames_); 121 122 int aligned_frames = 0; 123 CalculateMemorySizeInternal(channels, frames, &aligned_frames); 124 125 BuildChannelData(channels, aligned_frames, data); 126 } 127 128 AudioBus::AudioBus(int frames, const std::vector<float*>& channel_data) 129 : channel_data_(channel_data), 130 frames_(frames), 131 can_set_channel_data_(false) { 132 ValidateConfig( 133 base::checked_numeric_cast<int>(channel_data_.size()), frames_); 134 135 // Sanity check wrapped vector for alignment and channel count. 136 for (size_t i = 0; i < channel_data_.size(); ++i) 137 DCHECK(IsAligned(channel_data_[i])); 138 } 139 140 AudioBus::AudioBus(int channels) 141 : channel_data_(channels), 142 frames_(0), 143 can_set_channel_data_(true) { 144 CHECK_GT(channels, 0); 145 for (size_t i = 0; i < channel_data_.size(); ++i) 146 channel_data_[i] = NULL; 147 } 148 149 AudioBus::~AudioBus() {} 150 151 scoped_ptr<AudioBus> AudioBus::Create(int channels, int frames) { 152 return scoped_ptr<AudioBus>(new AudioBus(channels, frames)); 153 } 154 155 scoped_ptr<AudioBus> AudioBus::Create(const AudioParameters& params) { 156 return scoped_ptr<AudioBus>(new AudioBus( 157 params.channels(), params.frames_per_buffer())); 158 } 159 160 scoped_ptr<AudioBus> AudioBus::CreateWrapper(int channels) { 161 return scoped_ptr<AudioBus>(new AudioBus(channels)); 162 } 163 164 scoped_ptr<AudioBus> AudioBus::WrapVector( 165 int frames, const std::vector<float*>& channel_data) { 166 return scoped_ptr<AudioBus>(new AudioBus(frames, channel_data)); 167 } 168 169 scoped_ptr<AudioBus> AudioBus::WrapMemory(int channels, int frames, 170 void* data) { 171 // |data| must be aligned by AudioBus::kChannelAlignment. 172 CHECK(IsAligned(data)); 173 return scoped_ptr<AudioBus>(new AudioBus( 174 channels, frames, static_cast<float*>(data))); 175 } 176 177 scoped_ptr<AudioBus> AudioBus::WrapMemory(const AudioParameters& params, 178 void* data) { 179 // |data| must be aligned by AudioBus::kChannelAlignment. 180 CHECK(IsAligned(data)); 181 return scoped_ptr<AudioBus>(new AudioBus( 182 params.channels(), params.frames_per_buffer(), 183 static_cast<float*>(data))); 184 } 185 186 void AudioBus::SetChannelData(int channel, float* data) { 187 CHECK(can_set_channel_data_); 188 CHECK(data); 189 CHECK_GE(channel, 0); 190 CHECK_LT(static_cast<size_t>(channel), channel_data_.size()); 191 DCHECK(IsAligned(data)); 192 channel_data_[channel] = data; 193 } 194 195 void AudioBus::set_frames(int frames) { 196 CHECK(can_set_channel_data_); 197 ValidateConfig(static_cast<int>(channel_data_.size()), frames); 198 frames_ = frames; 199 } 200 201 void AudioBus::ZeroFramesPartial(int start_frame, int frames) { 202 CheckOverflow(start_frame, frames, frames_); 203 204 if (frames <= 0) 205 return; 206 207 for (size_t i = 0; i < channel_data_.size(); ++i) { 208 memset(channel_data_[i] + start_frame, 0, 209 frames * sizeof(*channel_data_[i])); 210 } 211 } 212 213 void AudioBus::ZeroFrames(int frames) { 214 ZeroFramesPartial(0, frames); 215 } 216 217 void AudioBus::Zero() { 218 ZeroFrames(frames_); 219 } 220 221 int AudioBus::CalculateMemorySize(const AudioParameters& params) { 222 return CalculateMemorySizeInternal( 223 params.channels(), params.frames_per_buffer(), NULL); 224 } 225 226 int AudioBus::CalculateMemorySize(int channels, int frames) { 227 return CalculateMemorySizeInternal(channels, frames, NULL); 228 } 229 230 void AudioBus::BuildChannelData(int channels, int aligned_frames, float* data) { 231 DCHECK(IsAligned(data)); 232 DCHECK_EQ(channel_data_.size(), 0U); 233 // Separate audio data out into channels for easy lookup later. Figure out 234 channel_data_.reserve(channels); 235 for (int i = 0; i < channels; ++i) 236 channel_data_.push_back(data + i * aligned_frames); 237 } 238 239 // TODO(dalecurtis): See if intrinsic optimizations help any here. 240 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, 241 int frames, int bytes_per_sample) { 242 CheckOverflow(start_frame, frames, frames_); 243 switch (bytes_per_sample) { 244 case 1: 245 FromInterleavedInternal<uint8, int16, kUint8Bias>( 246 source, start_frame, frames, this, 247 1.0f / kint8min, 1.0f / kint8max); 248 break; 249 case 2: 250 FromInterleavedInternal<int16, int16, 0>( 251 source, start_frame, frames, this, 252 1.0f / kint16min, 1.0f / kint16max); 253 break; 254 case 4: 255 FromInterleavedInternal<int32, int32, 0>( 256 source, start_frame, frames, this, 257 1.0f / kint32min, 1.0f / kint32max); 258 break; 259 default: 260 NOTREACHED() << "Unsupported bytes per sample encountered."; 261 ZeroFramesPartial(start_frame, frames); 262 return; 263 } 264 265 // Don't clear remaining frames if this is a partial deinterleave. 266 if (!start_frame) { 267 // Zero any remaining frames. 268 ZeroFramesPartial(frames, frames_ - frames); 269 } 270 } 271 272 void AudioBus::FromInterleaved(const void* source, int frames, 273 int bytes_per_sample) { 274 FromInterleavedPartial(source, 0, frames, bytes_per_sample); 275 } 276 277 void AudioBus::ToInterleaved(int frames, int bytes_per_sample, 278 void* dest) const { 279 ToInterleavedPartial(0, frames, bytes_per_sample, dest); 280 } 281 282 // TODO(dalecurtis): See if intrinsic optimizations help any here. 283 void AudioBus::ToInterleavedPartial(int start_frame, int frames, 284 int bytes_per_sample, void* dest) const { 285 CheckOverflow(start_frame, frames, frames_); 286 switch (bytes_per_sample) { 287 case 1: 288 ToInterleavedInternal<uint8, int16, kUint8Bias>( 289 this, start_frame, frames, dest, kint8min, kint8max); 290 break; 291 case 2: 292 ToInterleavedInternal<int16, int16, 0>( 293 this, start_frame, frames, dest, kint16min, kint16max); 294 break; 295 case 4: 296 ToInterleavedInternal<int32, int32, 0>( 297 this, start_frame, frames, dest, kint32min, kint32max); 298 break; 299 default: 300 NOTREACHED() << "Unsupported bytes per sample encountered."; 301 memset(dest, 0, frames * bytes_per_sample); 302 return; 303 } 304 } 305 306 void AudioBus::CopyTo(AudioBus* dest) const { 307 CopyPartialFramesTo(0, frames(), 0, dest); 308 } 309 310 void AudioBus::CopyPartialFramesTo(int source_start_frame, 311 int frame_count, 312 int dest_start_frame, 313 AudioBus* dest) const { 314 CHECK_EQ(channels(), dest->channels()); 315 CHECK_LE(source_start_frame + frame_count, frames()); 316 CHECK_LE(dest_start_frame + frame_count, dest->frames()); 317 318 // Since we don't know if the other AudioBus is wrapped or not (and we don't 319 // want to care), just copy using the public channel() accessors. 320 for (int i = 0; i < channels(); ++i) { 321 memcpy(dest->channel(i) + dest_start_frame, 322 channel(i) + source_start_frame, 323 sizeof(*channel(i)) * frame_count); 324 } 325 } 326 327 void AudioBus::Scale(float volume) { 328 if (volume > 0 && volume != 1) { 329 for (int i = 0; i < channels(); ++i) 330 vector_math::FMUL(channel(i), volume, frames(), channel(i)); 331 } else if (volume == 0) { 332 Zero(); 333 } 334 } 335 336 } // namespace media 337