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:
kwiberg@webrtc.org 2014-07-18 07:50:29 +00:00
parent c145668dc8
commit e364ac902f
3 changed files with 43 additions and 29 deletions

View File

@ -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
// broken when someone requests write access to either ChannelBuffer, and
// reestablished when someone requests the outdated ChannelBuffer. It is
// therefore safe to use the return value of ibuf() and fbuf() until the next
// call to the other method.
// therefore safe to use the return value of ibuf_const() and fbuf_const()
// 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 {
public:
IFChannelBuffer(int samples_per_channel, int num_channels)
@ -80,19 +81,24 @@ class IFChannelBuffer {
fvalid_(true),
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();
fvalid_ = false;
fvalid_ = readonly;
return &ibuf_;
}
ChannelBuffer<float>* fbuf() {
ChannelBuffer<float>* fbuf(bool readonly) {
RefreshF();
ivalid_ = false;
ivalid_ = readonly;
return &fbuf_;
}
private:
void RefreshF() {
if (!fvalid_) {
assert(ivalid_);
@ -266,69 +272,71 @@ void AudioBuffer::InitForNewData() {
}
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) {
mixed_low_pass_valid_ = false;
const AudioBuffer* t = this;
return const_cast<int16_t*>(t->data(channel));
return channels_->ibuf()->channel(channel);
}
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) {
mixed_low_pass_valid_ = false;
const AudioBuffer* t = this;
return const_cast<float*>(t->data_f(channel));
return channels_->fbuf()->channel(channel);
}
const int16_t* AudioBuffer::low_pass_split_data(int channel) const {
return split_channels_low_.get()
? split_channels_low_->ibuf()->channel(channel)
? split_channels_low_->ibuf_const()->channel(channel)
: data(channel);
}
int16_t* AudioBuffer::low_pass_split_data(int channel) {
mixed_low_pass_valid_ = false;
const AudioBuffer* t = this;
return const_cast<int16_t*>(t->low_pass_split_data(channel));
return split_channels_low_.get()
? split_channels_low_->ibuf()->channel(channel)
: data(channel);
}
const float* AudioBuffer::low_pass_split_data_f(int channel) const {
return split_channels_low_.get()
? split_channels_low_->fbuf()->channel(channel)
? split_channels_low_->fbuf_const()->channel(channel)
: data_f(channel);
}
float* AudioBuffer::low_pass_split_data_f(int channel) {
mixed_low_pass_valid_ = false;
const AudioBuffer* t = this;
return const_cast<float*>(t->low_pass_split_data_f(channel));
return split_channels_low_.get()
? split_channels_low_->fbuf()->channel(channel)
: data_f(channel);
}
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()
? split_channels_high_->ibuf()->channel(channel)
: 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 {
return split_channels_high_.get()
? split_channels_high_->fbuf()->channel(channel)
? split_channels_high_->fbuf_const()->channel(channel)
: NULL;
}
float* AudioBuffer::high_pass_split_data_f(int channel) {
const AudioBuffer* t = this;
return const_cast<float*>(t->high_pass_split_data_f(channel));
return split_channels_high_.get()
? split_channels_high_->fbuf()->channel(channel)
: NULL;
}
const int16_t* AudioBuffer::mixed_low_pass_data() {

View File

@ -55,7 +55,9 @@ class AudioBuffer {
int samples_per_split_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);
const int16_t* data(int channel) const;
int16_t* low_pass_split_data(int channel);

View File

@ -54,10 +54,14 @@ class ChannelBuffer {
}
T* data() { return data_.get(); }
T* channel(int i) {
const T* channel(int i) const {
assert(i >= 0 && i < num_channels_);
return channels_[i];
}
T* channel(int i) {
const ChannelBuffer<T>* t = this;
return const_cast<T*>(t->channel(i));
}
T** channels() { return channels_.get(); }
int samples_per_channel() { return samples_per_channel_; }