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"
9 #include "base/logging.h"
10 #include "media/audio/audio_parameters.h"
11 #include "media/base/limits.h"
15 static bool IsAligned(void* ptr
) {
16 return (reinterpret_cast<uintptr_t>(ptr
) &
17 (AudioBus::kChannelAlignment
- 1)) == 0U;
20 // Calculates the required size for an AudioBus with the given params, sets
21 // |aligned_frames| to the actual frame length of each channel array.
22 static int CalculateMemorySizeInternal(int channels
, int frames
,
23 int* out_aligned_frames
) {
24 // Choose a size such that each channel will be aligned by
25 // kChannelAlignment when stored in a contiguous block.
27 ((frames
* sizeof(float) + AudioBus::kChannelAlignment
- 1) &
28 ~(AudioBus::kChannelAlignment
- 1)) / sizeof(float);
30 if (out_aligned_frames
)
31 *out_aligned_frames
= aligned_frames
;
33 return sizeof(float) * channels
* aligned_frames
;
36 // |Format| is the destination type, |Fixed| is a type larger than |Format|
37 // such that operations can be made without overflowing.
38 template<class Format
, class Fixed
>
39 static void FromInterleavedInternal(const void* src
, int start_frame
,
40 int frames
, AudioBus
* dest
) {
41 const Format
* source
= static_cast<const Format
*>(src
);
43 static const Fixed kBias
= std::numeric_limits
<Format
>::is_signed
? 0 :
44 std::numeric_limits
<Format
>::max() / 2 + 1;
45 static const float kMaxScale
= 1.0f
/ (kBias
? kBias
- 1 :
46 std::numeric_limits
<Format
>::max());
47 static const float kMinScale
= 1.0f
/ (kBias
? kBias
:
48 -static_cast<Fixed
>(std::numeric_limits
<Format
>::min()));
50 int channels
= dest
->channels();
51 for (int ch
= 0; ch
< channels
; ++ch
) {
52 float* channel_data
= dest
->channel(ch
);
53 for (int i
= start_frame
, offset
= ch
; i
< start_frame
+ frames
;
54 ++i
, offset
+= channels
) {
55 Fixed v
= static_cast<Fixed
>(source
[offset
]) - kBias
;
56 channel_data
[i
] = v
* (v
< 0 ? kMinScale
: kMaxScale
);
61 // |Format| is the destination type, |Fixed| is a type larger than |Format|
62 // such that operations can be made without overflowing.
63 template<class Format
, class Fixed
>
64 static void ToInterleavedInternal(const AudioBus
* source
, int frames
,
66 Format
* dest
= static_cast<Format
*>(dst
);
68 static const Format kBias
= std::numeric_limits
<Format
>::is_signed
? 0 :
69 std::numeric_limits
<Format
>::max() / 2 + 1;
70 static const Fixed kMaxValue
= kBias
? kBias
- 1 :
71 std::numeric_limits
<Format
>::max();
72 static const Fixed kMinValue
= kBias
? -kBias
:
73 std::numeric_limits
<Format
>::min();
75 int channels
= source
->channels();
76 for (int ch
= 0; ch
< channels
; ++ch
) {
77 const float* channel_data
= source
->channel(ch
);
78 for (int i
= 0, offset
= ch
; i
< frames
; ++i
, offset
+= channels
) {
79 float v
= channel_data
[i
];
80 Fixed sample
= v
* (v
< 0 ? -kMinValue
: kMaxValue
);
82 if (sample
> kMaxValue
)
84 else if (sample
< kMinValue
)
87 dest
[offset
] = static_cast<Format
>(sample
) + kBias
;
92 static void ValidateConfig(int channels
, int frames
) {
94 CHECK_GT(channels
, 0);
95 CHECK_LE(channels
, limits::kMaxChannels
);
98 static void CheckOverflow(int start_frame
, int frames
, int total_frames
) {
99 CHECK_GE(start_frame
, 0);
101 CHECK_GT(total_frames
, 0);
102 int sum
= start_frame
+ frames
;
103 CHECK_LE(sum
, total_frames
);
107 AudioBus::AudioBus(int channels
, int frames
)
109 can_set_channel_data_(false) {
110 ValidateConfig(channels
, frames_
);
112 int aligned_frames
= 0;
113 int size
= CalculateMemorySizeInternal(channels
, frames
, &aligned_frames
);
115 data_
.reset(static_cast<float*>(base::AlignedAlloc(
116 size
, AudioBus::kChannelAlignment
)));
118 BuildChannelData(channels
, aligned_frames
, data_
.get());
121 AudioBus::AudioBus(int channels
, int frames
, float* data
)
123 can_set_channel_data_(false) {
124 ValidateConfig(channels
, frames_
);
126 int aligned_frames
= 0;
127 CalculateMemorySizeInternal(channels
, frames
, &aligned_frames
);
129 BuildChannelData(channels
, aligned_frames
, data
);
132 AudioBus::AudioBus(int frames
, const std::vector
<float*>& channel_data
)
133 : channel_data_(channel_data
),
135 can_set_channel_data_(false) {
136 ValidateConfig(channel_data_
.size(), frames_
);
138 // Sanity check wrapped vector for alignment and channel count.
139 for (size_t i
= 0; i
< channel_data_
.size(); ++i
)
140 DCHECK(IsAligned(channel_data_
[i
]));
143 AudioBus::AudioBus(int channels
)
144 : channel_data_(channels
),
146 can_set_channel_data_(true) {
147 for (size_t i
= 0; i
< channel_data_
.size(); ++i
)
148 channel_data_
[i
] = NULL
;
151 AudioBus::~AudioBus() {}
153 scoped_ptr
<AudioBus
> AudioBus::Create(int channels
, int frames
) {
154 return scoped_ptr
<AudioBus
>(new AudioBus(channels
, frames
));
157 scoped_ptr
<AudioBus
> AudioBus::Create(const AudioParameters
& params
) {
158 return scoped_ptr
<AudioBus
>(new AudioBus(
159 params
.channels(), params
.frames_per_buffer()));
162 scoped_ptr
<AudioBus
> AudioBus::CreateWrapper(int channels
) {
163 return scoped_ptr
<AudioBus
>(new AudioBus(channels
));
166 scoped_ptr
<AudioBus
> AudioBus::WrapVector(
167 int frames
, const std::vector
<float*>& channel_data
) {
168 return scoped_ptr
<AudioBus
>(new AudioBus(frames
, channel_data
));
171 scoped_ptr
<AudioBus
> AudioBus::WrapMemory(int channels
, int frames
,
173 // |data| must be aligned by AudioBus::kChannelAlignment.
174 CHECK(IsAligned(data
));
175 return scoped_ptr
<AudioBus
>(new AudioBus(
176 channels
, frames
, static_cast<float*>(data
)));
179 scoped_ptr
<AudioBus
> AudioBus::WrapMemory(const AudioParameters
& params
,
181 // |data| must be aligned by AudioBus::kChannelAlignment.
182 CHECK(IsAligned(data
));
183 return scoped_ptr
<AudioBus
>(new AudioBus(
184 params
.channels(), params
.frames_per_buffer(),
185 static_cast<float*>(data
)));
188 void AudioBus::SetChannelData(int channel
, float* data
) {
189 CHECK(can_set_channel_data_
);
190 CHECK_GE(channel
, 0);
191 CHECK_LT(static_cast<size_t>(channel
), channel_data_
.size());
192 DCHECK(IsAligned(data
));
193 channel_data_
[channel
] = data
;
196 void AudioBus::set_frames(int frames
) {
197 CHECK(can_set_channel_data_
);
201 void AudioBus::ZeroFramesPartial(int start_frame
, int frames
) {
202 CheckOverflow(start_frame
, frames
, frames_
);
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
]));
213 void AudioBus::ZeroFrames(int frames
) {
214 ZeroFramesPartial(0, frames
);
217 void AudioBus::Zero() {
221 int AudioBus::CalculateMemorySize(const AudioParameters
& params
) {
222 return CalculateMemorySizeInternal(
223 params
.channels(), params
.frames_per_buffer(), NULL
);
226 int AudioBus::CalculateMemorySize(int channels
, int frames
) {
227 return CalculateMemorySizeInternal(channels
, frames
, NULL
);
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
);
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
) {
245 FromInterleavedInternal
<uint8
, int16
>(source
, start_frame
, frames
, this);
248 FromInterleavedInternal
<int16
, int32
>(source
, start_frame
, frames
, this);
251 FromInterleavedInternal
<int32
, int64
>(source
, start_frame
, frames
, this);
254 NOTREACHED() << "Unsupported bytes per sample encountered.";
255 ZeroFramesPartial(start_frame
, frames
);
259 // Don't clear remaining frames if this is a partial deinterleave.
261 // Zero any remaining frames.
262 ZeroFramesPartial(frames
, frames_
- frames
);
266 void AudioBus::FromInterleaved(const void* source
, int frames
,
267 int bytes_per_sample
) {
268 FromInterleavedPartial(source
, 0, frames
, bytes_per_sample
);
271 // TODO(dalecurtis): See if intrinsic optimizations help any here.
272 void AudioBus::ToInterleaved(int frames
, int bytes_per_sample
,
274 CheckOverflow(0, frames
, frames_
);
275 switch (bytes_per_sample
) {
277 ToInterleavedInternal
<uint8
, int16
>(this, frames
, dest
);
280 ToInterleavedInternal
<int16
, int32
>(this, frames
, dest
);
283 ToInterleavedInternal
<int32
, int64
>(this, frames
, dest
);
286 NOTREACHED() << "Unsupported bytes per sample encountered.";
287 memset(dest
, 0, frames
* bytes_per_sample
);
292 void AudioBus::CopyTo(AudioBus
* dest
) const {
293 CHECK_EQ(channels(), dest
->channels());
294 CHECK_EQ(frames(), dest
->frames());
296 // Since we don't know if the other AudioBus is wrapped or not (and we don't
297 // want to care), just copy using the public channel() accessors.
298 for (int i
= 0; i
< channels(); ++i
)
299 memcpy(dest
->channel(i
), channel(i
), sizeof(*channel(i
)) * frames());