| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "media/base/audio_bus.h" | 5 #include "media/base/audio_bus.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "media/audio/audio_parameters.h" | 10 #include "media/audio/audio_parameters.h" |
| 11 #include "media/base/limits.h" | 11 #include "media/base/limits.h" |
| 12 #include "media/base/vector_math.h" | 12 #include "media/base/vector_math.h" |
| 13 | 13 |
| 14 namespace media { | 14 namespace media { |
| 15 | 15 |
| 16 static const uint8 kUint8Bias = 128; |
| 17 static const int16 kUint8Min = -kUint8Bias; |
| 18 static const int16 kUint8Max = kUint8Bias - 1; |
| 19 |
| 16 static bool IsAligned(void* ptr) { | 20 static bool IsAligned(void* ptr) { |
| 17 return (reinterpret_cast<uintptr_t>(ptr) & | 21 return (reinterpret_cast<uintptr_t>(ptr) & |
| 18 (AudioBus::kChannelAlignment - 1)) == 0U; | 22 (AudioBus::kChannelAlignment - 1)) == 0U; |
| 19 } | 23 } |
| 20 | 24 |
| 21 // Calculates the required size for an AudioBus with the given params, sets | 25 // Calculates the required size for an AudioBus with the given params, sets |
| 22 // |aligned_frames| to the actual frame length of each channel array. | 26 // |aligned_frames| to the actual frame length of each channel array. |
| 23 static int CalculateMemorySizeInternal(int channels, int frames, | 27 static int CalculateMemorySizeInternal(int channels, int frames, |
| 24 int* out_aligned_frames) { | 28 int* out_aligned_frames) { |
| 25 // Choose a size such that each channel will be aligned by | 29 // Choose a size such that each channel will be aligned by |
| 26 // kChannelAlignment when stored in a contiguous block. | 30 // kChannelAlignment when stored in a contiguous block. |
| 27 int aligned_frames = | 31 int aligned_frames = |
| 28 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & | 32 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & |
| 29 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); | 33 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); |
| 30 | 34 |
| 31 if (out_aligned_frames) | 35 if (out_aligned_frames) |
| 32 *out_aligned_frames = aligned_frames; | 36 *out_aligned_frames = aligned_frames; |
| 33 | 37 |
| 34 return sizeof(float) * channels * aligned_frames; | 38 return sizeof(float) * channels * aligned_frames; |
| 35 } | 39 } |
| 36 | 40 |
| 37 // |Format| is the destination type, |Fixed| is a type larger than |Format| | 41 // |Format| is the destination type, |Fixed| is a type larger than |Format| |
| 38 // such that operations can be made without overflowing. | 42 // such that operations can be made without overflowing. |
| 39 template<class Format, class Fixed> | 43 template<class Format, class Fixed> |
| 40 static void FromInterleavedInternal(const void* src, int start_frame, | 44 static void FromInterleavedInternal(const void* src, int start_frame, |
| 41 int frames, AudioBus* dest) { | 45 int frames, AudioBus* dest, |
| 46 Format bias, float min, float max) { |
| 42 const Format* source = static_cast<const Format*>(src); | 47 const Format* source = static_cast<const Format*>(src); |
| 43 | 48 const int channels = dest->channels(); |
| 44 static const Fixed kBias = std::numeric_limits<Format>::is_signed ? 0 : | |
| 45 std::numeric_limits<Format>::max() / 2 + 1; | |
| 46 static const float kMaxScale = 1.0f / (kBias ? kBias - 1 : | |
| 47 std::numeric_limits<Format>::max()); | |
| 48 static const float kMinScale = 1.0f / (kBias ? kBias : | |
| 49 -static_cast<Fixed>(std::numeric_limits<Format>::min())); | |
| 50 | |
| 51 int channels = dest->channels(); | |
| 52 for (int ch = 0; ch < channels; ++ch) { | 49 for (int ch = 0; ch < channels; ++ch) { |
| 53 float* channel_data = dest->channel(ch); | 50 float* channel_data = dest->channel(ch); |
| 54 for (int i = start_frame, offset = ch; i < start_frame + frames; | 51 for (int i = start_frame, offset = ch; i < start_frame + frames; |
| 55 ++i, offset += channels) { | 52 ++i, offset += channels) { |
| 56 Fixed v = static_cast<Fixed>(source[offset]) - kBias; | 53 const Fixed v = static_cast<Fixed>(source[offset]) - bias; |
| 57 channel_data[i] = v * (v < 0 ? kMinScale : kMaxScale); | 54 channel_data[i] = v * (v < 0 ? -min : max); |
| 58 } | 55 } |
| 59 } | 56 } |
| 60 } | 57 } |
| 61 | 58 |
| 62 // |Format| is the destination type, |Fixed| is a type larger than |Format| | 59 // |Format| is the destination type, |Fixed| is a type larger than |Format| |
| 63 // such that operations can be made without overflowing. | 60 // such that operations can be made without overflowing. |
| 64 template<class Format, class Fixed> | 61 template<class Format, class Fixed> |
| 65 static void ToInterleavedInternal(const AudioBus* source, int start_frame, | 62 static void ToInterleavedInternal(const AudioBus* source, int start_frame, |
| 66 int frames, void* dst) { | 63 int frames, void* dst, |
| 64 Format bias, Fixed min, Fixed max) { |
| 67 Format* dest = static_cast<Format*>(dst); | 65 Format* dest = static_cast<Format*>(dst); |
| 68 | 66 const int channels = source->channels(); |
| 69 static const Format kBias = std::numeric_limits<Format>::is_signed ? 0 : | |
| 70 std::numeric_limits<Format>::max() / 2 + 1; | |
| 71 static const Fixed kMaxValue = kBias ? kBias - 1 : | |
| 72 std::numeric_limits<Format>::max(); | |
| 73 static const Fixed kMinValue = kBias ? -kBias : | |
| 74 std::numeric_limits<Format>::min(); | |
| 75 | |
| 76 int channels = source->channels(); | |
| 77 for (int ch = 0; ch < channels; ++ch) { | 67 for (int ch = 0; ch < channels; ++ch) { |
| 78 const float* channel_data = source->channel(ch); | 68 const float* channel_data = source->channel(ch); |
| 79 for (int i = start_frame, offset = ch; i < start_frame + frames; | 69 for (int i = start_frame, offset = ch; i < start_frame + frames; |
| 80 ++i, offset += channels) { | 70 ++i, offset += channels) { |
| 81 float v = channel_data[i]; | 71 const float v = channel_data[i]; |
| 82 Fixed sample = v * (v < 0 ? -kMinValue : kMaxValue); | |
| 83 | 72 |
| 84 if (sample > kMaxValue) | 73 Fixed sample; |
| 85 sample = kMaxValue; | 74 if (v < 0) |
| 86 else if (sample < kMinValue) | 75 sample = v <= -1 ? -min : static_cast<Fixed>(v * -min); |
| 87 sample = kMinValue; | 76 else |
| 77 sample = v >= 1 ? max : static_cast<Fixed>(v * max); |
| 88 | 78 |
| 89 dest[offset] = static_cast<Format>(sample) + kBias; | 79 dest[offset] = static_cast<Format>(sample) + bias; |
| 90 } | 80 } |
| 91 } | 81 } |
| 92 } | 82 } |
| 93 | 83 |
| 94 static void ValidateConfig(size_t channels, int frames) { | 84 static void ValidateConfig(size_t channels, int frames) { |
| 95 CHECK_GT(frames, 0); | 85 CHECK_GT(frames, 0); |
| 96 CHECK_LE(channels, static_cast<size_t>(limits::kMaxChannels)); | 86 CHECK_LE(channels, static_cast<size_t>(limits::kMaxChannels)); |
| 97 } | 87 } |
| 98 | 88 |
| 99 static void CheckOverflow(int start_frame, int frames, int total_frames) { | 89 static void CheckOverflow(int start_frame, int frames, int total_frames) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 for (int i = 0; i < channels; ++i) | 229 for (int i = 0; i < channels; ++i) |
| 240 channel_data_.push_back(data + i * aligned_frames); | 230 channel_data_.push_back(data + i * aligned_frames); |
| 241 } | 231 } |
| 242 | 232 |
| 243 // TODO(dalecurtis): See if intrinsic optimizations help any here. | 233 // TODO(dalecurtis): See if intrinsic optimizations help any here. |
| 244 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, | 234 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, |
| 245 int frames, int bytes_per_sample) { | 235 int frames, int bytes_per_sample) { |
| 246 CheckOverflow(start_frame, frames, frames_); | 236 CheckOverflow(start_frame, frames, frames_); |
| 247 switch (bytes_per_sample) { | 237 switch (bytes_per_sample) { |
| 248 case 1: | 238 case 1: |
| 249 FromInterleavedInternal<uint8, int16>(source, start_frame, frames, this); | 239 FromInterleavedInternal<uint8, int16>( |
| 240 source, start_frame, frames, this, |
| 241 kUint8Bias, 1.0f / kUint8Min, 1.0f / kUint8Max); |
| 250 break; | 242 break; |
| 251 case 2: | 243 case 2: |
| 252 FromInterleavedInternal<int16, int32>(source, start_frame, frames, this); | 244 FromInterleavedInternal<int16, int32>( |
| 245 source, start_frame, frames, this, |
| 246 0, 1.0f / kint16min, 1.0f / kint16max); |
| 253 break; | 247 break; |
| 254 case 4: | 248 case 4: |
| 255 FromInterleavedInternal<int32, int64>(source, start_frame, frames, this); | 249 FromInterleavedInternal<int32, int64>( |
| 250 source, start_frame, frames, this, |
| 251 0, 1.0f / kint32min, 1.0f / kint32max); |
| 256 break; | 252 break; |
| 257 default: | 253 default: |
| 258 NOTREACHED() << "Unsupported bytes per sample encountered."; | 254 NOTREACHED() << "Unsupported bytes per sample encountered."; |
| 259 ZeroFramesPartial(start_frame, frames); | 255 ZeroFramesPartial(start_frame, frames); |
| 260 return; | 256 return; |
| 261 } | 257 } |
| 262 | 258 |
| 263 // Don't clear remaining frames if this is a partial deinterleave. | 259 // Don't clear remaining frames if this is a partial deinterleave. |
| 264 if (!start_frame) { | 260 if (!start_frame) { |
| 265 // Zero any remaining frames. | 261 // Zero any remaining frames. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 276 void* dest) const { | 272 void* dest) const { |
| 277 ToInterleavedPartial(0, frames, bytes_per_sample, dest); | 273 ToInterleavedPartial(0, frames, bytes_per_sample, dest); |
| 278 } | 274 } |
| 279 | 275 |
| 280 // TODO(dalecurtis): See if intrinsic optimizations help any here. | 276 // TODO(dalecurtis): See if intrinsic optimizations help any here. |
| 281 void AudioBus::ToInterleavedPartial(int start_frame, int frames, | 277 void AudioBus::ToInterleavedPartial(int start_frame, int frames, |
| 282 int bytes_per_sample, void* dest) const { | 278 int bytes_per_sample, void* dest) const { |
| 283 CheckOverflow(start_frame, frames, frames_); | 279 CheckOverflow(start_frame, frames, frames_); |
| 284 switch (bytes_per_sample) { | 280 switch (bytes_per_sample) { |
| 285 case 1: | 281 case 1: |
| 286 ToInterleavedInternal<uint8, int16>(this, start_frame, frames, dest); | 282 ToInterleavedInternal<uint8, int16>( |
| 283 this, start_frame, frames, dest, |
| 284 kUint8Bias, kUint8Min, kUint8Max); |
| 287 break; | 285 break; |
| 288 case 2: | 286 case 2: |
| 289 ToInterleavedInternal<int16, int32>(this, start_frame, frames, dest); | 287 ToInterleavedInternal<int16, int32>( |
| 288 this, start_frame, frames, dest, 0, kint16min, kint16max); |
| 290 break; | 289 break; |
| 291 case 4: | 290 case 4: |
| 292 ToInterleavedInternal<int32, int64>(this, start_frame, frames, dest); | 291 ToInterleavedInternal<int32, int64>( |
| 292 this, start_frame, frames, dest, 0, kint32min, kint32max); |
| 293 break; | 293 break; |
| 294 default: | 294 default: |
| 295 NOTREACHED() << "Unsupported bytes per sample encountered."; | 295 NOTREACHED() << "Unsupported bytes per sample encountered."; |
| 296 memset(dest, 0, frames * bytes_per_sample); | 296 memset(dest, 0, frames * bytes_per_sample); |
| 297 return; | 297 return; |
| 298 } | 298 } |
| 299 } | 299 } |
| 300 | 300 |
| 301 void AudioBus::CopyTo(AudioBus* dest) const { | 301 void AudioBus::CopyTo(AudioBus* dest) const { |
| 302 CHECK_EQ(channels(), dest->channels()); | 302 CHECK_EQ(channels(), dest->channels()); |
| 303 CHECK_EQ(frames(), dest->frames()); | 303 CHECK_EQ(frames(), dest->frames()); |
| 304 | 304 |
| 305 // Since we don't know if the other AudioBus is wrapped or not (and we don't | 305 // Since we don't know if the other AudioBus is wrapped or not (and we don't |
| 306 // want to care), just copy using the public channel() accessors. | 306 // want to care), just copy using the public channel() accessors. |
| 307 for (int i = 0; i < channels(); ++i) | 307 for (int i = 0; i < channels(); ++i) |
| 308 memcpy(dest->channel(i), channel(i), sizeof(*channel(i)) * frames()); | 308 memcpy(dest->channel(i), channel(i), sizeof(*channel(i)) * frames()); |
| 309 } | 309 } |
| 310 | 310 |
| 311 void AudioBus::Scale(float volume) { | 311 void AudioBus::Scale(float volume) { |
| 312 if (volume > 0 && volume != 1) { | 312 if (volume > 0 && volume != 1) { |
| 313 for (int i = 0; i < channels(); ++i) | 313 for (int i = 0; i < channels(); ++i) |
| 314 vector_math::FMUL(channel(i), volume, frames(), channel(i)); | 314 vector_math::FMUL(channel(i), volume, frames(), channel(i)); |
| 315 } else if (volume == 0) { | 315 } else if (volume == 0) { |
| 316 Zero(); | 316 Zero(); |
| 317 } | 317 } |
| 318 } | 318 } |
| 319 | 319 |
| 320 } // namespace media | 320 } // namespace media |
| OLD | NEW |