AudioBuffer: Optimize const accesses to arrays that autoconvert int16<->float
Specifically, when someone asks for a const pointer to the int16 version of the array, there's no need to invalidate the float version of that array, and vice versa. (But obviously, invalidation still has to happen when someone asks for a non-const pointer.) R=aluebs@webrtc.org, andrew@webrtc.org, minyue@webrtc.org Review URL: https://webrtc-codereview.appspot.com/18809004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6725 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c145668dc8
commit
e364ac902f
@ -70,8 +70,9 @@ void StereoToMono(const int16_t* left, const int16_t* right, int16_t* out,
|
|||||||
// One int16_t and one float ChannelBuffer that are kept in sync. The sync is
|
// One int16_t and one float ChannelBuffer that are kept in sync. The sync is
|
||||||
// broken when someone requests write access to either ChannelBuffer, and
|
// broken when someone requests write access to either ChannelBuffer, and
|
||||||
// reestablished when someone requests the outdated ChannelBuffer. It is
|
// reestablished when someone requests the outdated ChannelBuffer. It is
|
||||||
// therefore safe to use the return value of ibuf() and fbuf() until the next
|
// therefore safe to use the return value of ibuf_const() and fbuf_const()
|
||||||
// call to the other method.
|
// until the next call to ibuf() or fbuf(), and the return value of ibuf() and
|
||||||
|
// fbuf() until the next call to any of the other functions.
|
||||||
class IFChannelBuffer {
|
class IFChannelBuffer {
|
||||||
public:
|
public:
|
||||||
IFChannelBuffer(int samples_per_channel, int num_channels)
|
IFChannelBuffer(int samples_per_channel, int num_channels)
|
||||||
@ -80,19 +81,24 @@ class IFChannelBuffer {
|
|||||||
fvalid_(true),
|
fvalid_(true),
|
||||||
fbuf_(samples_per_channel, num_channels) {}
|
fbuf_(samples_per_channel, num_channels) {}
|
||||||
|
|
||||||
ChannelBuffer<int16_t>* ibuf() {
|
ChannelBuffer<int16_t>* ibuf() { return ibuf(false); }
|
||||||
|
ChannelBuffer<float>* fbuf() { return fbuf(false); }
|
||||||
|
const ChannelBuffer<int16_t>* ibuf_const() { return ibuf(true); }
|
||||||
|
const ChannelBuffer<float>* fbuf_const() { return fbuf(true); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChannelBuffer<int16_t>* ibuf(bool readonly) {
|
||||||
RefreshI();
|
RefreshI();
|
||||||
fvalid_ = false;
|
fvalid_ = readonly;
|
||||||
return &ibuf_;
|
return &ibuf_;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelBuffer<float>* fbuf() {
|
ChannelBuffer<float>* fbuf(bool readonly) {
|
||||||
RefreshF();
|
RefreshF();
|
||||||
ivalid_ = false;
|
ivalid_ = readonly;
|
||||||
return &fbuf_;
|
return &fbuf_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void RefreshF() {
|
void RefreshF() {
|
||||||
if (!fvalid_) {
|
if (!fvalid_) {
|
||||||
assert(ivalid_);
|
assert(ivalid_);
|
||||||
@ -266,69 +272,71 @@ void AudioBuffer::InitForNewData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int16_t* AudioBuffer::data(int channel) const {
|
const int16_t* AudioBuffer::data(int channel) const {
|
||||||
return channels_->ibuf()->channel(channel);
|
return channels_->ibuf_const()->channel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* AudioBuffer::data(int channel) {
|
int16_t* AudioBuffer::data(int channel) {
|
||||||
mixed_low_pass_valid_ = false;
|
mixed_low_pass_valid_ = false;
|
||||||
const AudioBuffer* t = this;
|
return channels_->ibuf()->channel(channel);
|
||||||
return const_cast<int16_t*>(t->data(channel));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float* AudioBuffer::data_f(int channel) const {
|
const float* AudioBuffer::data_f(int channel) const {
|
||||||
return channels_->fbuf()->channel(channel);
|
return channels_->fbuf_const()->channel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float* AudioBuffer::data_f(int channel) {
|
float* AudioBuffer::data_f(int channel) {
|
||||||
mixed_low_pass_valid_ = false;
|
mixed_low_pass_valid_ = false;
|
||||||
const AudioBuffer* t = this;
|
return channels_->fbuf()->channel(channel);
|
||||||
return const_cast<float*>(t->data_f(channel));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int16_t* AudioBuffer::low_pass_split_data(int channel) const {
|
const int16_t* AudioBuffer::low_pass_split_data(int channel) const {
|
||||||
return split_channels_low_.get()
|
return split_channels_low_.get()
|
||||||
? split_channels_low_->ibuf()->channel(channel)
|
? split_channels_low_->ibuf_const()->channel(channel)
|
||||||
: data(channel);
|
: data(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* AudioBuffer::low_pass_split_data(int channel) {
|
int16_t* AudioBuffer::low_pass_split_data(int channel) {
|
||||||
mixed_low_pass_valid_ = false;
|
mixed_low_pass_valid_ = false;
|
||||||
const AudioBuffer* t = this;
|
return split_channels_low_.get()
|
||||||
return const_cast<int16_t*>(t->low_pass_split_data(channel));
|
? split_channels_low_->ibuf()->channel(channel)
|
||||||
|
: data(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float* AudioBuffer::low_pass_split_data_f(int channel) const {
|
const float* AudioBuffer::low_pass_split_data_f(int channel) const {
|
||||||
return split_channels_low_.get()
|
return split_channels_low_.get()
|
||||||
? split_channels_low_->fbuf()->channel(channel)
|
? split_channels_low_->fbuf_const()->channel(channel)
|
||||||
: data_f(channel);
|
: data_f(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float* AudioBuffer::low_pass_split_data_f(int channel) {
|
float* AudioBuffer::low_pass_split_data_f(int channel) {
|
||||||
mixed_low_pass_valid_ = false;
|
mixed_low_pass_valid_ = false;
|
||||||
const AudioBuffer* t = this;
|
return split_channels_low_.get()
|
||||||
return const_cast<float*>(t->low_pass_split_data_f(channel));
|
? split_channels_low_->fbuf()->channel(channel)
|
||||||
|
: data_f(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int16_t* AudioBuffer::high_pass_split_data(int channel) const {
|
const int16_t* AudioBuffer::high_pass_split_data(int channel) const {
|
||||||
|
return split_channels_high_.get()
|
||||||
|
? split_channels_high_->ibuf_const()->channel(channel)
|
||||||
|
: NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t* AudioBuffer::high_pass_split_data(int channel) {
|
||||||
return split_channels_high_.get()
|
return split_channels_high_.get()
|
||||||
? split_channels_high_->ibuf()->channel(channel)
|
? split_channels_high_->ibuf()->channel(channel)
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* AudioBuffer::high_pass_split_data(int channel) {
|
|
||||||
const AudioBuffer* t = this;
|
|
||||||
return const_cast<int16_t*>(t->high_pass_split_data(channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* AudioBuffer::high_pass_split_data_f(int channel) const {
|
const float* AudioBuffer::high_pass_split_data_f(int channel) const {
|
||||||
return split_channels_high_.get()
|
return split_channels_high_.get()
|
||||||
? split_channels_high_->fbuf()->channel(channel)
|
? split_channels_high_->fbuf_const()->channel(channel)
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
float* AudioBuffer::high_pass_split_data_f(int channel) {
|
float* AudioBuffer::high_pass_split_data_f(int channel) {
|
||||||
const AudioBuffer* t = this;
|
return split_channels_high_.get()
|
||||||
return const_cast<float*>(t->high_pass_split_data_f(channel));
|
? split_channels_high_->fbuf()->channel(channel)
|
||||||
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int16_t* AudioBuffer::mixed_low_pass_data() {
|
const int16_t* AudioBuffer::mixed_low_pass_data() {
|
||||||
|
@ -55,7 +55,9 @@ class AudioBuffer {
|
|||||||
int samples_per_split_channel() const;
|
int samples_per_split_channel() const;
|
||||||
int samples_per_keyboard_channel() const;
|
int samples_per_keyboard_channel() const;
|
||||||
|
|
||||||
// It can be assumed that channels are stored contiguously.
|
// Sample array accessors. Channels are guaranteed to be stored contiguously
|
||||||
|
// in memory. Prefer to use the const variants of each accessor when
|
||||||
|
// possible, since they incur less float<->int16 conversion overhead.
|
||||||
int16_t* data(int channel);
|
int16_t* data(int channel);
|
||||||
const int16_t* data(int channel) const;
|
const int16_t* data(int channel) const;
|
||||||
int16_t* low_pass_split_data(int channel);
|
int16_t* low_pass_split_data(int channel);
|
||||||
|
@ -54,10 +54,14 @@ class ChannelBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
T* data() { return data_.get(); }
|
T* data() { return data_.get(); }
|
||||||
T* channel(int i) {
|
const T* channel(int i) const {
|
||||||
assert(i >= 0 && i < num_channels_);
|
assert(i >= 0 && i < num_channels_);
|
||||||
return channels_[i];
|
return channels_[i];
|
||||||
}
|
}
|
||||||
|
T* channel(int i) {
|
||||||
|
const ChannelBuffer<T>* t = this;
|
||||||
|
return const_cast<T*>(t->channel(i));
|
||||||
|
}
|
||||||
T** channels() { return channels_.get(); }
|
T** channels() { return channels_.get(); }
|
||||||
|
|
||||||
int samples_per_channel() { return samples_per_channel_; }
|
int samples_per_channel() { return samples_per_channel_; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user