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.
5 #include "media/base/audio_bus.h"
7 #include "base/logging.h"
8 #include "media/audio/audio_parameters.h"
9 #include "media/base/limits.h"
10 #include "media/base/vector_math.h"
14 static const uint8 kUint8Bias
= 128;
16 static bool IsAligned(void* ptr
) {
17 return (reinterpret_cast<uintptr_t>(ptr
) &
18 (AudioBus::kChannelAlignment
- 1)) == 0U;
21 // Calculates the required size for an AudioBus with the given params, sets
22 // |aligned_frames| to the actual frame length of each channel array.
23 static int CalculateMemorySizeInternal(int channels
, int frames
,
24 int* out_aligned_frames
) {
25 // Choose a size such that each channel will be aligned by
26 // kChannelAlignment when stored in a contiguous block.
28 ((frames
* sizeof(float) + AudioBus::kChannelAlignment
- 1) &
29 ~(AudioBus::kChannelAlignment
- 1)) / sizeof(float);
31 if (out_aligned_frames
)
32 *out_aligned_frames
= aligned_frames
;
34 return sizeof(float) * channels
* aligned_frames
;
37 // |Format| is the destination type. If a bias is present, |Fixed| must be a
38 // type larger than |Format| such that operations can be made without
39 // overflowing. Without a bias |Fixed| must be the same as |Format|.
40 template<class Format
, class Fixed
, Format Bias
>
41 static void FromInterleavedInternal(const void* src
, int start_frame
,
42 int frames
, AudioBus
* dest
,
43 float min
, float max
) {
44 COMPILE_ASSERT((Bias
== 0 && sizeof(Fixed
) == sizeof(Format
)) ||
45 sizeof(Fixed
) > sizeof(Format
), invalid_deinterleave_types
);
46 const Format
* source
= static_cast<const Format
*>(src
);
47 const int channels
= dest
->channels();
48 for (int ch
= 0; ch
< channels
; ++ch
) {
49 float* channel_data
= dest
->channel(ch
);
50 for (int i
= start_frame
, offset
= ch
; i
< start_frame
+ frames
;
51 ++i
, offset
+= channels
) {
52 const Fixed v
= static_cast<Fixed
>(source
[offset
]) - Bias
;
53 channel_data
[i
] = v
* (v
< 0 ? -min
: max
);
58 // |Format| is the destination type. If a bias is present, |Fixed| must be a
59 // type larger than |Format| such that operations can be made without
60 // overflowing. Without a bias |Fixed| must be the same as |Format|.
61 template<class Format
, class Fixed
, Format Bias
>
62 static void ToInterleavedInternal(const AudioBus
* source
, int start_frame
,
63 int frames
, void* dst
, Fixed min
, Fixed max
) {
64 COMPILE_ASSERT((Bias
== 0 && sizeof(Fixed
) == sizeof(Format
)) ||
65 sizeof(Fixed
) > sizeof(Format
), invalid_interleave_types
);
66 Format
* dest
= static_cast<Format
*>(dst
);
67 const int channels
= source
->channels();
68 for (int ch
= 0; ch
< channels
; ++ch
) {
69 const float* channel_data
= source
->channel(ch
);
70 for (int i
= start_frame
, offset
= ch
; i
< start_frame
+ frames
;
71 ++i
, offset
+= channels
) {
72 const float v
= channel_data
[i
];
76 sample
= v
<= -1 ? min
: static_cast<Fixed
>(-v
* min
);
78 sample
= v
>= 1 ? max
: static_cast<Fixed
>(v
* max
);
80 dest
[offset
] = static_cast<Format
>(sample
) + Bias
;
85 static void ValidateConfig(size_t channels
, int frames
) {
87 CHECK_LE(channels
, static_cast<size_t>(limits::kMaxChannels
));
90 static void CheckOverflow(int start_frame
, int frames
, int total_frames
) {
91 CHECK_GE(start_frame
, 0);
93 CHECK_GT(total_frames
, 0);
94 int sum
= start_frame
+ frames
;
95 CHECK_LE(sum
, total_frames
);
99 AudioBus::AudioBus(int channels
, int frames
)
101 can_set_channel_data_(false) {
102 ValidateConfig(channels
, frames_
);
104 int aligned_frames
= 0;
105 int size
= CalculateMemorySizeInternal(channels
, frames
, &aligned_frames
);
107 data_
.reset(static_cast<float*>(base::AlignedAlloc(
108 size
, AudioBus::kChannelAlignment
)));
110 BuildChannelData(channels
, aligned_frames
, data_
.get());
113 AudioBus::AudioBus(int channels
, int frames
, float* data
)
115 can_set_channel_data_(false) {
116 // Since |data| may have come from an external source, ensure it's valid.
118 ValidateConfig(channels
, frames_
);
120 int aligned_frames
= 0;
121 CalculateMemorySizeInternal(channels
, frames
, &aligned_frames
);
123 BuildChannelData(channels
, aligned_frames
, data
);
126 AudioBus::AudioBus(int frames
, const std::vector
<float*>& channel_data
)
127 : channel_data_(channel_data
),
129 can_set_channel_data_(false) {
130 ValidateConfig(channel_data_
.size(), frames_
);
132 // Sanity check wrapped vector for alignment and channel count.
133 for (size_t i
= 0; i
< channel_data_
.size(); ++i
)
134 DCHECK(IsAligned(channel_data_
[i
]));
137 AudioBus::AudioBus(int channels
)
138 : channel_data_(channels
),
140 can_set_channel_data_(true) {
141 for (size_t i
= 0; i
< channel_data_
.size(); ++i
)
142 channel_data_
[i
] = NULL
;
145 AudioBus::~AudioBus() {}
147 scoped_ptr
<AudioBus
> AudioBus::Create(int channels
, int frames
) {
148 return scoped_ptr
<AudioBus
>(new AudioBus(channels
, frames
));
151 scoped_ptr
<AudioBus
> AudioBus::Create(const AudioParameters
& params
) {
152 return scoped_ptr
<AudioBus
>(new AudioBus(
153 params
.channels(), params
.frames_per_buffer()));
156 scoped_ptr
<AudioBus
> AudioBus::CreateWrapper(int channels
) {
157 return scoped_ptr
<AudioBus
>(new AudioBus(channels
));
160 scoped_ptr
<AudioBus
> AudioBus::WrapVector(
161 int frames
, const std::vector
<float*>& channel_data
) {
162 return scoped_ptr
<AudioBus
>(new AudioBus(frames
, channel_data
));
165 scoped_ptr
<AudioBus
> AudioBus::WrapMemory(int channels
, int frames
,
167 // |data| must be aligned by AudioBus::kChannelAlignment.
168 CHECK(IsAligned(data
));
169 return scoped_ptr
<AudioBus
>(new AudioBus(
170 channels
, frames
, static_cast<float*>(data
)));
173 scoped_ptr
<AudioBus
> AudioBus::WrapMemory(const AudioParameters
& params
,
175 // |data| must be aligned by AudioBus::kChannelAlignment.
176 CHECK(IsAligned(data
));
177 return scoped_ptr
<AudioBus
>(new AudioBus(
178 params
.channels(), params
.frames_per_buffer(),
179 static_cast<float*>(data
)));
182 void AudioBus::SetChannelData(int channel
, float* data
) {
183 CHECK(can_set_channel_data_
);
185 CHECK_GE(channel
, 0);
186 CHECK_LT(static_cast<size_t>(channel
), channel_data_
.size());
187 DCHECK(IsAligned(data
));
188 channel_data_
[channel
] = data
;
191 void AudioBus::set_frames(int frames
) {
192 CHECK(can_set_channel_data_
);
196 void AudioBus::ZeroFramesPartial(int start_frame
, int frames
) {
197 CheckOverflow(start_frame
, frames
, frames_
);
202 for (size_t i
= 0; i
< channel_data_
.size(); ++i
) {
203 memset(channel_data_
[i
] + start_frame
, 0,
204 frames
* sizeof(*channel_data_
[i
]));
208 void AudioBus::ZeroFrames(int frames
) {
209 ZeroFramesPartial(0, frames
);
212 void AudioBus::Zero() {
216 int AudioBus::CalculateMemorySize(const AudioParameters
& params
) {
217 return CalculateMemorySizeInternal(
218 params
.channels(), params
.frames_per_buffer(), NULL
);
221 int AudioBus::CalculateMemorySize(int channels
, int frames
) {
222 return CalculateMemorySizeInternal(channels
, frames
, NULL
);
225 void AudioBus::BuildChannelData(int channels
, int aligned_frames
, float* data
) {
226 DCHECK(IsAligned(data
));
227 DCHECK_EQ(channel_data_
.size(), 0U);
228 // Separate audio data out into channels for easy lookup later. Figure out
229 channel_data_
.reserve(channels
);
230 for (int i
= 0; i
< channels
; ++i
)
231 channel_data_
.push_back(data
+ i
* aligned_frames
);
234 // TODO(dalecurtis): See if intrinsic optimizations help any here.
235 void AudioBus::FromInterleavedPartial(const void* source
, int start_frame
,
236 int frames
, int bytes_per_sample
) {
237 CheckOverflow(start_frame
, frames
, frames_
);
238 switch (bytes_per_sample
) {
240 FromInterleavedInternal
<uint8
, int16
, kUint8Bias
>(
241 source
, start_frame
, frames
, this,
242 1.0f
/ kint8min
, 1.0f
/ kint8max
);
245 FromInterleavedInternal
<int16
, int16
, 0>(
246 source
, start_frame
, frames
, this,
247 1.0f
/ kint16min
, 1.0f
/ kint16max
);
250 FromInterleavedInternal
<int32
, int32
, 0>(
251 source
, start_frame
, frames
, this,
252 1.0f
/ kint32min
, 1.0f
/ kint32max
);
255 NOTREACHED() << "Unsupported bytes per sample encountered.";
256 ZeroFramesPartial(start_frame
, frames
);
260 // Don't clear remaining frames if this is a partial deinterleave.
262 // Zero any remaining frames.
263 ZeroFramesPartial(frames
, frames_
- frames
);
267 void AudioBus::FromInterleaved(const void* source
, int frames
,
268 int bytes_per_sample
) {
269 FromInterleavedPartial(source
, 0, frames
, bytes_per_sample
);
272 void AudioBus::ToInterleaved(int frames
, int bytes_per_sample
,
274 ToInterleavedPartial(0, frames
, bytes_per_sample
, dest
);
277 // TODO(dalecurtis): See if intrinsic optimizations help any here.
278 void AudioBus::ToInterleavedPartial(int start_frame
, int frames
,
279 int bytes_per_sample
, void* dest
) const {
280 CheckOverflow(start_frame
, frames
, frames_
);
281 switch (bytes_per_sample
) {
283 ToInterleavedInternal
<uint8
, int16
, kUint8Bias
>(
284 this, start_frame
, frames
, dest
, kint8min
, kint8max
);
287 ToInterleavedInternal
<int16
, int16
, 0>(
288 this, start_frame
, frames
, dest
, kint16min
, kint16max
);
291 ToInterleavedInternal
<int32
, int32
, 0>(
292 this, start_frame
, frames
, dest
, kint32min
, kint32max
);
295 NOTREACHED() << "Unsupported bytes per sample encountered.";
296 memset(dest
, 0, frames
* bytes_per_sample
);
301 void AudioBus::CopyTo(AudioBus
* dest
) const {
302 CHECK_EQ(channels(), dest
->channels());
303 CHECK_EQ(frames(), dest
->frames());
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.
307 for (int i
= 0; i
< channels(); ++i
)
308 memcpy(dest
->channel(i
), channel(i
), sizeof(*channel(i
)) * frames());
311 void AudioBus::Scale(float volume
) {
312 if (volume
> 0 && volume
!= 1) {
313 for (int i
= 0; i
< channels(); ++i
)
314 vector_math::FMUL(channel(i
), volume
, frames(), channel(i
));
315 } else if (volume
== 0) {