blob: cdd46681591d6d01b2efefe3f6ac88c69e23f1dd [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. 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 COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_
#define COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_
#include <memory>
#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
#include "cobalt/export.h"
namespace cobalt {
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 COBALT_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_; }
SampleType sample_type() const { return sample_type_; }
StorageType storage_type() const { return storage_type_; }
size_t GetSampleSizeInBytes() const;
const uint8* interleaved_data() const;
const uint8* planar_data(size_t channel) const;
uint8* interleaved_data();
uint8* planar_data(size_t channel);
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);
public:
// The .*ForTypes? 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.
template <typename SampleTypeName, StorageType T>
inline uint8* GetSamplePtrForType(size_t channel, size_t frame) const {
DCHECK_LT(channel, channels_);
DCHECK_LT(frame, frames_);
if (T == kInterleaved) {
return channel_data_[0] +
sizeof(SampleTypeName) * (channels_ * frame + channel);
} else if (T == kPlanar) {
return channel_data_[channel] + sizeof(SampleTypeName) * frame;
} else {
NOTREACHED();
}
return NULL;
}
template <typename SampleTypeName, StorageType T>
inline SampleTypeName GetSampleForType(size_t channel, size_t frame) const {
return *reinterpret_cast<const SampleTypeName*>(
GetSamplePtrForType<SampleTypeName, T>(channel, frame));
}
template <StorageType SourceStorageType, StorageType DestStorageType>
void MixFloatSamples(const ShellAudioBus& source);
template <StorageType SourceStorageType, StorageType DestStorageType>
void MixInt16Samples(const ShellAudioBus& source);
private:
void SetFloat32Sample(size_t channel, size_t frame, float sample) {
DCHECK_EQ(sample_type_, kFloat32);
*reinterpret_cast<float*>(GetSamplePtr(channel, frame)) = sample;
}
void SetInt16Sample(size_t channel, size_t frame, int16 sample) {
DCHECK_EQ(sample_type_, kInt16);
*reinterpret_cast<int16*>(GetSamplePtr(channel, frame)) = sample;
}
uint8* GetSamplePtr(size_t channel, size_t frame);
const uint8* GetSamplePtr(size_t channel, size_t frame) const;
// Contiguous block of channel memory if the memory is owned by this object.
std::unique_ptr<uint8[], base::AlignedFreeDeleter> 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
} // namespace cobalt
#endif // COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_