Commit c90d7416 authored by Adrien Béraud's avatar Adrien Béraud

RingBuffer backed by one AudioBuffer

parent b1a9caed
......@@ -160,18 +160,21 @@ void AudioBuffer::fromInterleaved(const SFLAudioSample* in, size_t sample_num, u
}
}
size_t AudioBuffer::mix(const AudioBuffer& other)
size_t AudioBuffer::mix(const AudioBuffer& other, bool up /* = true */)
{
const bool upmix = up && (other.channels_ < channels_);
const size_t samp_num = std::min(sampleNum_, other.sampleNum_);
const unsigned chan_num = std::min(channels_, other.channels_);
const unsigned chan_num = upmix ? channels_ : std::min(channels_, other.channels_);
for(unsigned i=0; i<chan_num; i++) {
unsigned src_chan = upmix ? std::min(i, other.channels_-1) : i;
for(unsigned j=0; j<samp_num; j++)
samples_[i][j] += other.samples_[i][j];
samples_[i][j] += other.samples_[src_chan][j];
}
return samp_num;
}
size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_in /* = 0 */, size_t pos_out /* = 0 */)
size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_in /* = 0 */, size_t pos_out /* = 0 */, bool up /* = true */)
{
if(sample_num == -1)
sample_num = in.samples();
......@@ -179,7 +182,8 @@ size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_
int to_copy = std::min((int)in.samples()-(int)pos_in, sample_num);
if(to_copy <= 0) return 0;
const size_t chan_num = std::min(in.channels_, channels_);
const bool upmix = up && (in.channels_ < channels_);
const size_t chan_num = upmix ? channels_ : std::min(in.channels_, channels_);
if(pos_out+to_copy > sampleNum_)
resize(pos_out+to_copy);
......@@ -189,7 +193,8 @@ size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_
unsigned i;
for(i=0; i<chan_num; i++) {
std::copy(in.samples_[i].begin()+pos_in, in.samples_[i].begin()+pos_in+to_copy, samples_[i].begin()+pos_out);
unsigned src_chan = upmix ? std::min(i, in.channels_-1) : i;
std::copy(in.samples_[src_chan].begin()+pos_in, in.samples_[src_chan].begin()+pos_in+to_copy, samples_[i].begin()+pos_out);
}
return to_copy;
......
......@@ -35,7 +35,6 @@
#include <cstddef> // for size_t
#include "sfl_types.h"
//#include "noncopyable.h"
class AudioBuffer {
public:
......@@ -98,8 +97,8 @@ class AudioBuffer {
* Return the total number of single samples in the buffer (same as samples()*channels()).
*/
inline size_t capacity() const {
return samples()*channels();
}
return samples()*channels();
}
/**
* Resize the buffer to make it able to hold sample_num multichannel samples.
......@@ -165,12 +164,20 @@ class AudioBuffer {
void applyGain(double gain);
/**
* Mix elements of the other buffer with this buffer (in-place simple addition).
* Mix elements of the other buffer within this buffer (in-place simple addition).
* If other.channels() is higher than this.channels(), only the first this.channels() channels are imported.
* If other.channels() is lower than this.channels(), behavior depends on upmix.
* Sample rate is not considered by this function.
*
* TODO: some kind of check for overflow/saturation.
*
* @param other: the other buffer to mix in this one.
* @param upmix: if true, upmixing occurs when other.channels() < this.channels().
* If false, only the first other.channels() channels are edited in this buffer.
*
* @returns Number of samples modified.
*/
size_t mix(const AudioBuffer& other);
size_t mix(const AudioBuffer& other, bool upmix=true);
/**
* Copy sample_num samples from in (from sample pos_in) to this buffer (at sample pos_out).
......@@ -179,7 +186,7 @@ class AudioBuffer {
* The number of channels is changed to match the in channel number.
* Buffer sample number is also increased if required to hold the new requested samples.
*/
size_t copy(AudioBuffer& in, int sample_num=-1, size_t pos_in=0, size_t pos_out=0);
size_t copy(AudioBuffer& in, int sample_num=-1, size_t pos_in=0, size_t pos_out=0, bool upmix=true);
/**
* Copy sample_num samples from in to this buffer (at sample pos_out).
......@@ -190,8 +197,6 @@ class AudioBuffer {
size_t copy(SFLAudioSample* in, size_t sample_num, size_t pos_out=0);
private:
//NON_COPYABLE(AudioBuffer);
int sampleRate_;
unsigned channels_; // should allways be the same as samples_.size()
size_t sampleNum_;
......
......@@ -49,7 +49,6 @@ AudioLoop::AudioLoop(unsigned int sampleRate) : buffer_(), pos_(0), isRecording_
AudioLoop::~AudioLoop()
{
//delete [] buffer_;
delete buffer_;
}
......@@ -64,7 +63,6 @@ AudioLoop::seek(double relative_position)
static unsigned int updatePlaybackScale = 0;
void
//AudioLoop::getNext(SFLAudioSample* output, size_t total_samples, short volume)
AudioLoop::getNext(AudioBuffer& output, unsigned int volume)
{
if(!buffer_) {
......@@ -88,23 +86,8 @@ AudioLoop::getNext(AudioBuffer& output, unsigned int volume)
while (total_samples > 0) {
size_t samples = std::min(total_samples, buf_samples - pos);
/* if (samples > (buf_samples - pos))
samples = buf_samples - pos;*/
// short->char conversion
//memcpy(output, buffer_ + pos, samples * sizeof(SFLAudioSample));
//buffer_.copy(output, pos, samples);
output.copy(*buffer_, samples, pos, output_pos);
// Scaling needed
/*if (volume != 100) {
const double gain = volume * 0.01;
for (size_t i = 0; i < samples; ++i, ++output)
*output *= gain;
} else
output_pos += samples;*/
//output += samples; // this is the destination...
output_pos += samples;
pos = (pos + samples) % buf_samples;
......
......@@ -56,7 +56,6 @@ class AudioLoop {
* @param nb of int16 to send
* @param volume The volume
*/
//void getNext(SFLAudioSample* output, size_t samples, short volume=100);
void getNext(AudioBuffer& output, unsigned int volume=100);
void seek(double relative_position);
......@@ -73,7 +72,7 @@ class AudioLoop {
* @return unsigned int The size
*/
size_t getSize() {
return buffer_->samples();//size_;
return buffer_->samples();
}
/**
......@@ -87,17 +86,10 @@ class AudioLoop {
protected:
/** The data buffer */
AudioBuffer * buffer_;
//SFLAudioSample* buffer_;
/** Number of samples inside the buffer */
//size_t size_;
/** current position, set to 0, when initialize */
size_t pos_;
/** Sample rate */
//unsigned int sampleRate_;
/** Is a playback recording */
bool isRecording_;
......
......@@ -135,8 +135,6 @@ PulseLayer::~PulseLayer()
if (mainloop_)
pa_threaded_mainloop_free(mainloop_);
//delete [] mic_buffer_;
}
void PulseLayer::context_state_callback(pa_context* c, void *user_data)
......@@ -365,6 +363,8 @@ void PulseLayer::writeToSpeaker()
} else if (ret == 0)
return;
DEBUG("writeToSpeaker with n_channels=%d", n_channels);
size_t writableBytes = ret;
size_t writableSamples = writableBytes/sample_size;
......
......@@ -55,15 +55,15 @@ typedef struct PaDeviceInfos {
pa_channel_map channel_map;
PaDeviceInfos(unsigned idx, const char* ep_name, pa_sample_spec samp_spec, pa_channel_map chan_map)
: index(idx), name(ep_name), sample_spec(samp_spec), channel_map(chan_map)
{}
: index(idx), name(ep_name), sample_spec(samp_spec), channel_map(chan_map) {}
virtual ~PaDeviceInfos() {}
/**
* Unary function to search for a device by name in a list using std functions.
*/
struct nameComparator : public std::unary_function<const PaDeviceInfos, bool>
{
explicit nameComparator(const std::string &baseline) : baseline(baseline) {}
explicit nameComparator(const std::string &ref) : baseline(ref) {}
bool operator() (const PaDeviceInfos &arg) {
return arg.name == baseline;
}
......
......@@ -3,6 +3,7 @@
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* Author: Adrien Beraud <adrien.beraud@gmail.com>
*
* Portions (c) Dominic Mazzoni (Audacity)
*
......@@ -40,15 +41,14 @@
#include "ringbuffer.h"
namespace {
// corresponds to 106 ms (about 5 rtp packets)
// corresponds to 160 ms (about 5 rtp packets)
const size_t MIN_BUFFER_SIZE = 1280;
}
// Create a ring buffer with 'size' bytes
RingBuffer::RingBuffer(size_t size, const std::string &call_id) :
endPos_(0)
, bufferSize_(std::max(size, MIN_BUFFER_SIZE))
, buffer_(1, std::vector<SFLAudioSample>(bufferSize_))
, buffer_(std::max(size, MIN_BUFFER_SIZE), 1)
, readpointers_()
, buffer_id_(call_id)
{
......@@ -73,19 +73,21 @@ RingBuffer::flushAll()
size_t
RingBuffer::putLength() const
{
const size_t buffer_size = buffer_.samples();
const size_t startPos = (not readpointers_.empty()) ? getSmallestReadPointer() : 0;
return (endPos_ + bufferSize_ - startPos) % bufferSize_;
return (endPos_ + buffer_size - startPos) % buffer_size;
}
size_t RingBuffer::getLength(const std::string &call_id) const
{
return (endPos_ + bufferSize_ - getReadPointer(call_id)) % bufferSize_;
const size_t buffer_size = buffer_.samples();
return (endPos_ + buffer_size - getReadPointer(call_id)) % buffer_size;
}
void
RingBuffer::debug()
{
DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadPointer(), endPos_, bufferSize_);
DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadPointer(), endPos_, buffer_.samples());
}
size_t RingBuffer::getReadPointer(const std::string &call_id) const
......@@ -103,7 +105,7 @@ RingBuffer::getSmallestReadPointer() const
if (hasNoReadPointers())
return 0;
size_t smallest = bufferSize_;
size_t smallest = buffer_.samples();
ReadPointer::const_iterator iter;
......@@ -161,22 +163,20 @@ bool RingBuffer::hasNoReadPointers() const
//
// This one puts some data inside the ring buffer.
//void RingBuffer::put(void* buffer, size_t toCopy)
void RingBuffer::put(AudioBuffer& buf)
{
const size_t len = putLength();
const unsigned chans = buf.channels();
const size_t sample_num = buf.samples();
const size_t buffer_size = buffer_.samples();
size_t toCopy = sample_num;
// Add more channels if the input buffer holds more channels than the ring.
if(buffer_.size() < chans)
buffer_.resize(chans, std::vector<SFLAudioSample>(bufferSize_, 0));
if(buffer_.channels() < buf.channels())
buffer_.setChannelNum(buf.channels());
if (toCopy > bufferSize_ - len)
toCopy = bufferSize_ - len;
if (toCopy > buffer_size - len)
toCopy = buffer_size - len;
//unsigned char *src = static_cast<SFLAudioSample *>(buffer);
size_t in_pos = 0;
size_t pos = endPos_;
......@@ -184,14 +184,12 @@ void RingBuffer::put(AudioBuffer& buf)
size_t block = toCopy;
size_t i;
if (block > bufferSize_ - pos) // Wrap block around ring ?
block = bufferSize_ - pos; // Fill in to the end of the buffer
if (block > buffer_size - pos) // Wrap block around ring ?
block = buffer_size - pos; // Fill in to the end of the buffer
for(i=0; i<chans; i++) {
copy(buf.getChannel(i)->begin()+in_pos, buf.getChannel(i)->begin()+in_pos+block, buffer_[i].begin()+pos);
}
buffer_.copy(buf, block, in_pos, pos);
in_pos += block;
pos = (pos + block) % bufferSize_;
pos = (pos + block) % buffer_size;
toCopy -= block;
}
endPos_ = pos;
......@@ -209,7 +207,6 @@ RingBuffer::availableForGet(const std::string &call_id) const
}
// Get will move 'toCopy' bytes from the internal FIFO to 'buffer'
//size_t RingBuffer::get(void *buffer, size_t toCopy, const std::string &call_id)
size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id)
{
if (hasNoReadPointers())
......@@ -220,12 +217,9 @@ size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id)
const size_t len = getLength(call_id);
const size_t sample_num = buf.samples();
const size_t chans = std::min((unsigned)buffer_.size(), buf.channels());
const size_t buffer_size = buffer_.samples();
size_t toCopy = std::min(sample_num, len);
/* if (toCopy > len)
toCopy = len;*/
const size_t copied = toCopy;
size_t dest = 0;
......@@ -235,17 +229,13 @@ size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id)
size_t block = toCopy;
unsigned i;
if (block > bufferSize_ - startPos)
block = bufferSize_ - startPos;
if (block > buffer_size - startPos)
block = buffer_size - startPos;
for(i=0; i<chans; i++) {
copy(buffer_[i].begin()+startPos, buffer_[i].begin()+startPos+block, buf.getChannel(i)->begin()+dest);
// memcpy(buf->getChannel(i), &(*buffer_[i].begin()) + startPos, block);
}
buf.copy(buffer_, block, startPos, dest);
//memcpy(dest, &(*buffer_.begin()) + startPos, block);
dest += block;
startPos = (startPos + block) % bufferSize_;
startPos = (startPos + block) % buffer_size;
toCopy -= block;
}
......@@ -261,7 +251,8 @@ RingBuffer::discard(size_t toDiscard, const std::string &call_id)
if (toDiscard > len)
toDiscard = len;
size_t startPos = (getReadPointer(call_id) + toDiscard) % bufferSize_;
size_t buffer_size = buffer_.samples();
size_t startPos = (getReadPointer(call_id) + toDiscard) % buffer_size;
storeReadPointer(startPos, call_id);
......
......@@ -3,6 +3,7 @@
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Adrien Beraud <adrien.beraud@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -98,7 +99,6 @@ class RingBuffer {
* @param toCopy Number of bytes to copy
*/
void put(AudioBuffer& buf);
//void put(void* buffer, size_t toCopy);
/**
* To get how much samples are available in the buffer to read in
......@@ -113,7 +113,6 @@ class RingBuffer {
* @return size_t Number of bytes copied
*/
size_t get(AudioBuffer& buf, const std::string &call_id);
//size_t get(void* buffer, size_t toCopy, const std::string &call_id);
/**
* Discard data from the buffer
......@@ -141,10 +140,8 @@ class RingBuffer {
/** Pointer on the last data */
size_t endPos_;
/** Buffer size */
size_t bufferSize_;
/** Data */
std::vector<std::vector<SFLAudioSample> > buffer_;
AudioBuffer buffer_;
ReadPointer readpointers_;
std::string buffer_id_;
......
......@@ -58,7 +58,7 @@ class DTMF {
/**
* Copy the sound inside the sampling* buffer
* @param buffer : a vector of SFLDataFormat
* @param buffer : a vector of SFLAudioSample
*/
bool generateDTMF(std::vector<SFLAudioSample> &buffer);
......
......@@ -422,7 +422,7 @@ void MainBufferTest::testTwoPointer()
input_buffer->put(test_input);
CPPUNIT_ASSERT(output_buffer->get(test_output, MainBuffer::DEFAULT_ID) == 1);
CPPUNIT_ASSERT((*test_input.getChannel())[0] == (*test_output.getChannel())[0]);
CPPUNIT_ASSERT(test_sample == (*test_output.getChannel())[0]);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment