blob: 6c43f8ce9280f7224c4a84b925b04859eead0455 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MEDIA_BASE_SHELL_AUDIO_BUS_H_
#define MEDIA_BASE_SHELL_AUDIO_BUS_H_
#include <vector>
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
namespace media {
// This swiss army knife class encapsulates audio data in multiple channels, in
// different storage types and with different sample sizes. It also provides
// operation to convert, mix between different types of audio data. It should
// be used whenever such audio data is stored or passed around.
// In this class, "sample" is one audio wave form data at a certain time from a
// certain channel, while "frame" refers to all samples at the same time from
// all channels. For example, for a 48000KHz stereo audio with samples in
// float, its sample size in bytes is 4 but its frame size in bytes is 8. One
// second of such audio contains 48000 frames (96000 samples).
// Note: This class doesn't do endianness conversions. It assumes that all data
// is in the correct endianness.
class MEDIA_EXPORT ShellAudioBus {
public:
// Guaranteed alignment of each channel's data; use 64-byte alignment so it
// satisfies all our current platforms. Note that this is only used for
// buffers that are allocated and owned by the ShellAudioBus. We don't
// enforce alignment for the buffers passed in and extra caution should be
// taken if they are used as hardware buffer.
static const size_t kChannelAlignmentInBytes = 64;
enum SampleType { kInt16, kFloat32 };
enum StorageType { kInterleaved, kPlanar };
ShellAudioBus(size_t channels, size_t frames, SampleType sample_type,
StorageType storage_type);
ShellAudioBus(size_t frames, const std::vector<float*>& samples);
ShellAudioBus(size_t channels, size_t frames, float* samples);
ShellAudioBus(size_t frames, const std::vector<int16*>& samples);
ShellAudioBus(size_t channels, size_t frames, int16* samples);
size_t channels() const { return channels_; }
size_t frames() const { return frames_; }
size_t GetSampleSizeInBytes() const;
const uint8* interleaved_data() const;
const uint8* planar_data(size_t channel) const;
int16 GetInt16Sample(size_t channel, size_t frame) const {
DCHECK_EQ(sample_type_, kInt16);
return *reinterpret_cast<const int16*>(GetSamplePtr(channel, frame));
}
float GetFloat32Sample(size_t channel, size_t frame) const {
DCHECK_EQ(sample_type_, kFloat32);
return *reinterpret_cast<const float*>(GetSamplePtr(channel, frame));
}
void ZeroFrames(size_t start_frame, size_t end_frame);
void ZeroAllFrames() { ZeroFrames(0, frames()); }
// Copy frames from |source| provided that it has the same number of channels
// as the destination object (this). This function does any necessary
// conversion between different sample types and storage types. When source
// has less frames than the destination object, it will only copy these frames
// and will not fill the rest frames in our buffer with 0.
void Assign(const ShellAudioBus& source);
// The same as the above function except that this function also does mixing.
// |matrix| is a |dest.channels()| row * |source.channels()| column matrix in
// row major.
// dest.sample[dest_channel][frame] =
// source.sample[0][frame] * matrix[dest_channel * source.channels() + 0]
// + source.sample[1][frame] * matrix[dest_channel * source.channels() + 1]
// ...
// + source.sample[source.channels() - 1][frame] *
// matrix[channels() * source.channels() + source.channels() - 1];
// Note: Both objects must have storage type of kFloat32.
void Assign(const ShellAudioBus& source, const std::vector<float>& matrix);
// The following functions are the same as the Assign() functions except that
// they add the calculated samples to the target samples instead of replacing
// the target samples with the calculated samples.
// Note: Both objects must have storage type of kFloat32.
void Mix(const ShellAudioBus& source);
void Mix(const ShellAudioBus& source, const std::vector<float>& matrix);
private:
void SetFloat32Sample(size_t channel, size_t frame, float sample) {
DCHECK_EQ(sample_type_, kFloat32);
*reinterpret_cast<float*>(GetSamplePtr(channel, frame)) = sample;
}
uint8* GetSamplePtr(size_t channel, size_t frame);
const uint8* GetSamplePtr(size_t channel, size_t frame) const;
// The *ForType functions below are optimized versions that assume what
// storage type the bus is using. They are meant to be called after checking
// what storage type the bus is once, and then performing a batch of
// operations, where it is known that the type will not change.
// Note: The bus must have storage type of kFloat32.
template <StorageType T>
inline uint8* GetSamplePtrForType(size_t channel, size_t frame) const;
template <StorageType T>
inline float GetFloat32SampleForType(size_t channel, size_t frame) const;
template <StorageType SourceStorageType, StorageType DestStorageType>
void MixForType(const ShellAudioBus& source);
// Contiguous block of channel memory if the memory is owned by this object.
scoped_ptr_malloc<uint8, base::ScopedPtrAlignedFree> data_;
std::vector<uint8*> channel_data_;
size_t channels_;
size_t frames_;
SampleType sample_type_;
StorageType storage_type_;
DISALLOW_COPY_AND_ASSIGN(ShellAudioBus);
};
} // namespace media
#endif // MEDIA_BASE_SHELL_AUDIO_BUS_H_