Commit 6d8610a6 authored by Adrien Béraud's avatar Adrien Béraud

first set of change to support multichannel

parent 3ca4680c
......@@ -696,8 +696,8 @@ void AlsaLayer::capture()
const int framesPerBufferAlsa = 2048;
toGetSamples = std::min(framesPerBufferAlsa, toGetSamples);
std::vector<SFLDataFormat> in(toGetSamples);
SFLDataFormat * const in_ptr = &(*in.begin());
std::vector<SFLAudioSample> in(toGetSamples);
SFLAudioSample * const in_ptr = &(*in.begin());
const int toGetBytes = in.size() * sizeof(in[0]);
if (read(in_ptr, toGetBytes) != toGetBytes) {
......@@ -709,8 +709,8 @@ void AlsaLayer::capture()
if (resample) {
int outSamples = toGetSamples * (static_cast<double>(sampleRate_) / mainBufferSampleRate);
std::vector<SFLDataFormat> rsmpl_out(outSamples);
SFLDataFormat * const rsmpl_out_ptr = &(*rsmpl_out.begin());
std::vector<SFLAudioSample> rsmpl_out(outSamples);
SFLAudioSample * const rsmpl_out_ptr = &(*rsmpl_out.begin());
converter_.resample(in_ptr, rsmpl_out_ptr,
rsmpl_out.size(), mainBufferSampleRate, sampleRate_,
toGetSamples);
......@@ -728,7 +728,7 @@ void AlsaLayer::playback(int maxSamples)
{
size_t bytesToGet = Manager::instance().getMainBuffer().availableForGet(MainBuffer::DEFAULT_ID);
const size_t bytesToPut = maxSamples * sizeof(SFLDataFormat);
const size_t bytesToPut = maxSamples * sizeof(SFLAudioSample);
// no audio available, play tone or silence
if (bytesToGet <= 0) {
// FIXME: not thread safe! we only lock the mutex when we get the
......@@ -736,8 +736,8 @@ void AlsaLayer::playback(int maxSamples)
AudioLoop *tone = Manager::instance().getTelephoneTone();
AudioLoop *file_tone = Manager::instance().getTelephoneFile();
std::vector<SFLDataFormat> out(maxSamples, 0);
SFLDataFormat * const out_ptr = &(*out.begin());
std::vector<SFLAudioSample> out(maxSamples, 0);
SFLAudioSample * const out_ptr = &(*out.begin());
if (tone)
tone->getNext(out_ptr, out.size(), getPlaybackGain());
else if (file_tone && !ringtoneHandle_)
......@@ -759,17 +759,17 @@ void AlsaLayer::playback(int maxSamples)
bytesToGet = std::min(maxNbBytesToGet, bytesToGet);
const size_t samplesToGet = bytesToGet / sizeof(SFLDataFormat);
std::vector<SFLDataFormat> out(samplesToGet, 0);
SFLDataFormat * const out_ptr = &(*out.begin());
const size_t samplesToGet = bytesToGet / sizeof(SFLAudioSample);
std::vector<SFLAudioSample> out(samplesToGet, 0);
SFLAudioSample * const out_ptr = &(*out.begin());
Manager::instance().getMainBuffer().getData(out_ptr, bytesToGet, MainBuffer::DEFAULT_ID);
AudioLayer::applyGain(out_ptr, samplesToGet, getPlaybackGain());
if (resample) {
const size_t outSamples = samplesToGet * resampleFactor;
const size_t outBytes = outSamples * sizeof(SFLDataFormat);
std::vector<SFLDataFormat> rsmpl_out(outSamples);
SFLDataFormat * const rsmpl_out_ptr = &(*rsmpl_out.begin());
const size_t outBytes = outSamples * sizeof(SFLAudioSample);
std::vector<SFLAudioSample> rsmpl_out(outSamples);
SFLAudioSample * const rsmpl_out_ptr = &(*rsmpl_out.begin());
converter_.resample(out_ptr, rsmpl_out_ptr, rsmpl_out.size(),
mainBufferSampleRate, sampleRate_, samplesToGet);
write(rsmpl_out_ptr, outBytes, playbackHandle_);
......@@ -791,16 +791,16 @@ void AlsaLayer::audioCallback()
int playbackAvailSmpl = 0;
if (not safeUpdate(playbackHandle_, playbackAvailSmpl))
return;
const size_t playbackAvailBytes = playbackAvailSmpl * sizeof(SFLDataFormat);
const size_t playbackAvailBytes = playbackAvailSmpl * sizeof(SFLAudioSample);
size_t bytesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID);
if (bytesToGet > 0) {
// Urgent data (dtmf, incoming call signal) come first.
bytesToGet = std::min(bytesToGet, playbackAvailBytes);
const size_t samplesToGet = bytesToGet / sizeof(SFLDataFormat);
std::vector<SFLDataFormat> out(samplesToGet);
SFLDataFormat * const out_ptr = &(*out.begin());
const size_t samplesToGet = bytesToGet / sizeof(SFLAudioSample);
std::vector<SFLAudioSample> out(samplesToGet);
SFLAudioSample * const out_ptr = &(*out.begin());
urgentRingBuffer_.get(out_ptr, bytesToGet, MainBuffer::DEFAULT_ID);
AudioLayer::applyGain(out_ptr, samplesToGet, getPlaybackGain());
......@@ -817,10 +817,10 @@ void AlsaLayer::audioCallback()
int ringtoneAvailSmpl = 0;
if (not safeUpdate(ringtoneHandle_, ringtoneAvailSmpl))
return;
int ringtoneAvailBytes = ringtoneAvailSmpl * sizeof(SFLDataFormat);
int ringtoneAvailBytes = ringtoneAvailSmpl * sizeof(SFLAudioSample);
std::vector<SFLDataFormat> out(ringtoneAvailSmpl, 0);
SFLDataFormat * const out_ptr = &(*out.begin());
std::vector<SFLAudioSample> out(ringtoneAvailSmpl, 0);
SFLAudioSample * const out_ptr = &(*out.begin());
if (file_tone) {
DEBUG("playback gain %d", getPlaybackGain());
......
/*
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Author: Adrien Beraud <adrien.beraud@wisdomvibes.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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
AudioBuffer::AudioBuffer(size_t sample_num /* = 0 */, size_t channel_num /* = 1 */, int sample_rate /* = 8000 */)
: sampleRate_(8000),
sampleNum_(sample_num),
channels_(channel_num),
samples_(channel_num, vector<SFLAudioSample>(sample_num, 0))
{
}
AudioBuffer(const AudioBuffer& other, bool copy_content /* = false */)
: sampleRate_(other.sampleRate_),
sampleNum_(other.sampleNum_),
channels_(other.channels_),
samples_(channel_num, vector<SFLAudioSample>())
{
unsigned i;
if(copy_content) {
for(i=0; i<channels_; i++)
samples_[i] = other.samples_[i];
} else {
for(i=0; i<channels_; i++)
samples_[i].resize(sampleNum_, 0);
}
}
int AudioBuffer::getSampleRate()
{
return sampleRate_;
}
void setSampleRate(int sr)
{
sampleRate_ = sr;
}
size_t AudioBuffer::getChannelNum()
{
return channels_;
}
void AudioBuffer::setChannelNum(size_t n, bool copy_content /* = false */)
{
if(channels_ != n) {
channels_ = n;
samples_.resize(n, std::vector<SFLAudioSample>(sampleNum_, (copy_content && samples_.size()>0)?samples_[0]:0));
}
}
size_t AudioBuffer::samples()
{
return sampleNum_;
}
void AudioBuffer::resize(size_t sample_num)
{
unsigned i;
if(sampleNum_ != sample_num) {
sampleNum_ = sample_num;
for(i=0; i<channels_; i++)
samples_[i].resize(sample_num);
}
}
void AudioBuffer::clear()
{
unsigned i, j;
for(i=0; i<channels_; i++)
samples_[i].assign(sampleNum_, 0);
}
void AudioBuffer::empty()
{
unsigned i;
for(i=0; i<channels_; i++)
samples_[i].clear();
sampleNum_ = 0;
}
std::vector<SFLAudioSample> *
AudioBuffer::getChannel(size_t chan /* = 0 */)
{
return samples_[chan];
}
void AudioBuffer::applyGain(AudioBuffer *src, int gain)
{
if(gain != 100)
applyGain(gain*0.01);
}
void AudioBuffer::applyGain(AudioBuffer *src, double gain)
{
if(gain == 1.0) return;
unsigned i, j;
for(i=0; i<channels_; i++)
for(j=0; j<sampleNum_; j++)
samples_[i][j] *= gain;
}
size_t AudioBuffer::interleave(SFLAudioSample* out)
{
unsigned i, j;
for(i=0; i<sampleNum_; i++)
for(j=0; j<channels_; j++)
*out++ = samples_[j][i];
return sampleNum_*channels_;
}
size_t AudioBuffer::interleaveFloat(float* out)
{
unsigned i, j;
for(i=0; i<sampleNum_; i++)
for(j=0; j<channels_; j++)
*out++ = (float) samples_[j][i] * .000030517578125f;
return sampleNum_*channels_;
}
void AudioBuffer::fromInterleaved(SFLAudioSample* in, size_t sample_num, size_t channel_num)
{
unsigned i;
// Resize buffer
setChannelNum(channel_num);
resize(sample_num);
for(i=0; i<sampleNum_; i++) {
unsigned j;
for(j=0; j<channels_; j++)
samples_[j][i] = *in++;
}
}
size_t AudioBuffer::mix(const AudioBuffer& other)
{
const size_t samp_num = std::min(sampleNum_, other.sampleNum_);
const size_t chan_num = std::min(channels_, other.channels_);
unsigned i;
for(i=0; i<chan_num; i++) {
unsigned j;
for(j=0; j<samp_num; j++)
samples_[i][j] += other.samples_[i][j];
}
return samp_num;
}
size_t AudioBuffer::sub(AudioBuffer& out, size_t pos)
{
out.copy(this, samples(), pos);
}
size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_in /* = 0 */, size_t pos_out /* = 0 */)
{
if(sample_num == -1)
sample_num = in.samples();
int to_copy = std::min(in.samples()-(int)pos_in, (int)sample_num);
if(to_copy <= 0) return 0;
const size_t chan_num = in.channels_;
if(pos_out+to_copy > sampleNum_)
resize(pos_out+to_copy);
sampleRate_ = in.sampleRate_;
setChannelNum(chan_num);
unsigned i;
for(i=0; i<chan_num; i++) {
copy(in.samples_[i].begin()+pos_in, in.samples_[i].begin()+pos_in+to_copy, samples_[i].begin()+pos_out);
}
return to_copy;
}
size_t AudioBuffer::copy(SFLAudioSample* in, size_t sample_num, size_t pos_out /* = 0 */)
{
if(pos_out+sample_num > sampleNum_)
resize(pos_out+to_copy);
const size_t chan_num = channels_;
unsigned i;
for(i=0; i<chan_num; i++) {
copy(in, in+to_copy, samples_[i].begin()+pos_out);
}
}
/*
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Author: Adrien Beraud <adrien.beraud@wisdomvibes.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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef _AUDIO_BUFFER_H
#define _AUDIO_BUFFER_H
#include <vector>
#include <cstddef> // for size_t
#include "sfl_types.h"
#include "noncopyable.h"
class AudioBuffer {
public:
AudioBuffer(size_t sample_num=0, size_t channel_num=1, int sample_rate=8000);
/**
* Copy constructor that by default only copies the buffer parameters (channel number, sample rate and buffer size).
* If copy_content is set to true, the buffer content is also copied.
*/
AudioBuffer(const AudioBuffer& other, bool copy_content=false);
/**
* Returns the sample rate (in samples/sec) associated to this buffer.
*/
int getSampleRate();
/**
* Set the sample rate (in samples/sec) associated to this buffer.
*/
void setSampleRate(int sr);
/**
* Returns the number of samples in this buffer.
*/
size_t getChannelNum();
/**
* Set the number of channels of this buffer.
*
* @param n: the new number of channels. If n < getChannelNum(), channels are deleted from the buffer, otherwise the behavior depends on copy_first.
*
* @param copy_first: if set to true and n > getChannelNum(), new channels are initialised with samples from the first channel. If set to false, new channels are initialised to 0.
*/
void setChannelNum(size_t n, bool copy_first=false);
/**
* Returns the number of (multichannel) samples.
*/
size_t samples();
/**
*
*/
void resize(size_t sample_num);
/**
* Set the buffer to 0. Buffer size is kept.
*/
void clear();
/**
* Resize the buffer to 0.
*/
void empty();
/**
* Return the data (audio samples) for a given channel number.
* Channel data can be modified but size of individual channel vectors should not be changed manually.
*/
std::vector<SFLAudioSample> *getChannel(size_t chan=0);
/**
* Write interleaved multichannel data to the out buffer.
* The out buffer must be at least of size getChannelNum()*samples()*sizeof(SFLAudioSample).
*
* @returns Number of samples writen.
*/
size_t interleave(SFLAudioSample* out);
/**
* Write interleaved multichannel data to the out buffer, while samples are converted to float.
* The buffer must be at least of size getChannelNum()*samples()*sizeof(float).
*
* @returns Number of samples writen.
*/
size_t interleaveFloat(float* out);
/**
* Import interleaved multichannel data. Internal buffer is resized as needed. Function will read sample_num*channel_num elements of the in buffer.
*/
void fromInterleaved(SFLAudioSample* in, size_t sample_num, size_t channel_num=1);
/**
* In-place gain transformation with integer parameter.
*
* @param gain: 0 -> 100 scale
*/
void applyGain(int gain);
/**
* In-place gain transformation.
*
* @param gain: 0.0 -> 1.0 scale
*/
void applyGain(double gain);
/**
* Mix elements of the other buffer with this buffer (in-place simple addition).
* TODO: some kind of check for overflow/saturation.
*
* @returns Number of samples modified.
*/
size_t mix(const AudioBuffer& other);
/**
* Copy sample_num samples from in (from sample pos_in) to this (at sample pos_out).
* If sample_num is -1 (the default), the entire in buffer is copied.
*
* 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);
/**
* Copy sample_num samples from in to this (at sample pos_out).
* Input data is treated as mono and samples are duplicated in the case of a multichannel buffer.
*
* Buffer sample number is increased if required to hold the new requested samples.
*/
size_t copy(SFLAudioSample* in, size_t sample_num, size_t pos_out=0);
private:
NON_COPYABLE(AudioBuffer);
int sampleRate_;
size_t channels_; // should allways be samples_.size()
size_t sampleNum_;
// main buffers holding data for each channels
std::vector<std::vector<SFLAudioSample> > samples_;
};
#endif // _AUDIO_BUFFER_H
......@@ -76,12 +76,17 @@ void AudioLayer::putUrgent(void* buffer, int toCopy)
urgentRingBuffer_.put(buffer, toCopy);
}
void AudioLayer::applyGain(SFLDataFormat *src , int samples, int gain)
/*
//void AudioLayer::applyGain(SFLDataFormat *src , int samples, int gain)
void AudioLayer::applyGain(AudioBuffer *src, int gain)
{
size_t len = src->sample_num * src->channels;
SFLAudioSample *buf = src->samples;
if (gain != 100)
for (int i = 0 ; i < samples; i++)
src[i] = src[i] * gain* 0.01;
}
for (int i = 0 ; i < len; i++)
buf[i] = buf[i] * gain* 0.01;
}*/
// Notify (with a beep) an incoming call when there is already a call in progress
void AudioLayer::notifyIncomingCall()
......@@ -103,7 +108,7 @@ void AudioLayer::notifyIncomingCall()
Tone tone("440/160", getSampleRate());
unsigned int nbSample = tone.getSize();
SFLDataFormat buf[nbSample];
SFLAudioSample buf[nbSample];
tone.getNext(buf, nbSample);
/* Put the data in the urgent ring buffer */
......
......@@ -138,7 +138,8 @@ class AudioLayer {
/**
* Apply gain to audio frame
*/
static void applyGain(SFLDataFormat *src , int samples, int gain);
//static void applyGain(SFLDataFormat *src , int samples, int gain);
// static void applyGain(SFLAudioBuffer *src, int gain)
/**
* Convert audio amplitude value from linear value to dB
......
......@@ -41,12 +41,12 @@
#include <cassert>
#include "logger.h"
AudioLoop::AudioLoop(unsigned int sampleRate) : buffer_(0), size_(0), pos_(0), sampleRate_(sampleRate), isRecording_(false)
AudioLoop::AudioLoop(unsigned int sampleRate) : buffer_(0), pos_(0), sampleRate_(sampleRate), isRecording_(false)
{}
AudioLoop::~AudioLoop()
{
delete [] buffer_;
//delete [] buffer_;
}
void
......@@ -60,41 +60,55 @@ AudioLoop::seek(double relative_position)
static unsigned int updatePlaybackScale = 0;
void
AudioLoop::getNext(SFLDataFormat* output, size_t total_samples, short volume)
//AudioLoop::getNext(SFLAudioSample* output, size_t total_samples, short volume)
AudioLoop::getNext(AudioBuffer* output, short volume)
{
if(!buffer_) {
ERROR("AudioLoop::buffer_ is not set (NULL pointer)");
return;
}
const size_t buf_samples = buffer_.samples();
size_t pos = pos_;
size_t total_samples = output->samples();
size_t output_pos = 0;
if (size_ == 0) {
if (buf_samples == 0) {
ERROR("Audio loop size is 0");
return;
} else if (pos >= size_) {
} else if (pos >= buf_samples) {
ERROR("Invalid loop position %d", pos);
return;
}
while (total_samples > 0) {
size_t samples = total_samples;
size_t samples = std::min(total_samples, buf_samples - pos);
if (samples > (size_ - pos))
samples = size_ - pos;
/* if (samples > (buf_samples - pos))
samples = buf_samples - pos;*/
// short->char conversion
memcpy(output, buffer_ + pos, samples * sizeof(SFLDataFormat));
//memcpy(output, buffer_ + pos, samples * sizeof(SFLAudioSample));
//buffer_.copy(output, pos, samples);
output.copy(buffer_, samples, pos, output_pos);
// Scaling needed
if (volume != 100) {
/*if (volume != 100) {
const double gain = volume * 0.01;
for (size_t i = 0; i < samples; ++i, ++output)
*output *= gain;
} else
output += samples; // this is the destination...
output_pos += samples;*/
//output += samples; // this is the destination...
output_pos += samples;
pos = (pos + samples) % size_;
total_samples -= samples;
}
output.applyGain(volume); // apply volume
pos_ = pos;
// We want to send values in milisecond
......
......@@ -36,6 +36,7 @@
#include "sfl_types.h"
#include <cstring>
#include "noncopyable.h"
#include "audiobuffer.h"
/**
* @file audioloop.h
......@@ -55,7 +56,8 @@ class AudioLoop {
* @param nb of int16 to send
* @param volume The volume
*/
void getNext(SFLDataFormat* output, size_t samples, short volume=100);
//void getNext(SFLAudioSample* output, size_t samples, short volume=100);
void getNext(AudioBuffer* output, short volume=100);
void seek(double relative_position);
......@@ -70,8 +72,8 @@ class AudioLoop {
* Accessor to the size of the buffer
* @return unsigned int The size
*/
size_t getSize() const {
return size_;
size_t getSize() {
return buffer_->samples();//size_;
}
/**
......@@ -84,16 +86,17 @@ class AudioLoop {
protected:
/** The data buffer */
SFLDataFormat* buffer_;
AudioBuffer * buffer_;
//SFLAudioSample* buffer_;
/** Number of samples inside the buffer */
size_t size_;
//size_t size_;
/** current position, set to 0, when initialize */
size_t pos_;
/** Sample rate */
unsigned int sampleRate_;
//unsigned int sampleRate_;
/** Is a playback recording */
bool isRecording_;
......
......@@ -413,7 +413,8 @@ void AudioRecord::closeWavFile()
WARN("Can't close file");
}
void AudioRecord::recData(SFLDataFormat* buffer, size_t nSamples)
//void AudioRecord::recData(SFLDataFormat* buffer, size_t nSamples)
void AudioRecord::recData(AudioBuffer* buffer)
{
if (recordingEnabled_) {
if (fileHandle_ == 0) {
......@@ -421,11 +422,13 @@ void AudioRecord::recData(SFLDataFormat* buffer, size_t nSamples)
return;
}
if (fwrite(buffer, sizeof(SFLDataFormat), nSamples, fileHandle_) != nSamples)
size_t nSamples = buffer->sample_num;
if (fwrite(&(buffer->getChannel(0)), sizeof(SFLAudioSample), nSamples, fileHandle_) != nSamples)
WARN("Could not record data! ");
else {
fflush(fileHandle_);
byteCounter_ += nSamples * sizeof(SFLDataFormat);
byteCounter_ += nSamples * sizeof(SFLAudioSample);
}
}
}
......@@ -102,7 +102,8 @@ class AudioRecord {
* @param buffer The data chunk to be recorded
* @param nSamples Number of samples (number of bytes) to be recorded
*/
void recData(SFLDataFormat* buffer, size_t nSamples);
//void recData(SFLDataFormat* buffer, size_t nSamples);
void recData(SFLAudioSample* buffer);
protected:
......@@ -180,17 +181,17 @@ class AudioRecord {
/**
* Buffer used for mixing two channels
*/
SFLDataFormat mixBuffer_[NB_SAMPLES_MAX];
SFLAudioSample mixBuffer_[NB_SAMPLES_MAX];
/**
* Buffer used to copy mic info
*/
SFLDataFormat micBuffer_[NB_SAMPLES_MAX];
SFLAudioSample micBuffer_[NB_SAMPLES_MAX];
/**
* Buffer used to copy spkr info
*/
SFLDataFormat spkBuffer_[NB_SAMPLES_MAX];
SFLAudioSample spkBuffer_[NB_SAMPLES_MAX];
/**
* Filename for this recording
......