2015-04-20 22:10:56 +02:00
|
|
|
/** @file
|
|
|
|
* @author Edouard DUPIN
|
|
|
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
2017-01-05 21:28:23 +01:00
|
|
|
* @license MPL v2.0 (see license file)
|
2015-04-20 22:10:56 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2016-10-02 21:24:13 +02:00
|
|
|
#include <audio/algo/speex/Resampler.hpp>
|
|
|
|
#include <audio/algo/speex/debug.hpp>
|
2015-04-20 22:10:56 +02:00
|
|
|
#include <cmath>
|
2015-04-21 21:57:32 +02:00
|
|
|
#ifdef HAVE_SPEEX_DSP
|
2016-10-02 23:40:54 +02:00
|
|
|
#include <speex/speex_resampler.h>
|
2015-04-21 21:57:32 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace audio {
|
|
|
|
namespace algo {
|
|
|
|
namespace speex {
|
|
|
|
class ResamplerPrivate {
|
|
|
|
private:
|
|
|
|
#ifdef HAVE_SPEEX_DSP
|
|
|
|
SpeexResamplerState* m_speexResampler;
|
|
|
|
#endif
|
|
|
|
enum audio::format m_format;
|
|
|
|
public:
|
|
|
|
ResamplerPrivate(int8_t _nbChannel, float _inputSampleRate, float _outputSampleRate, int8_t _quality, enum audio::format _format) :
|
|
|
|
#ifdef HAVE_SPEEX_DSP
|
2018-06-19 22:13:48 +02:00
|
|
|
m_speexResampler(null),
|
2015-04-21 21:57:32 +02:00
|
|
|
#endif
|
|
|
|
m_format(_format) {
|
|
|
|
#ifdef HAVE_SPEEX_DSP
|
2018-06-19 22:13:48 +02:00
|
|
|
if (m_speexResampler != null) {
|
2015-04-21 21:57:32 +02:00
|
|
|
speex_resampler_destroy(m_speexResampler);
|
2018-06-19 22:13:48 +02:00
|
|
|
m_speexResampler = null;
|
2015-04-21 21:57:32 +02:00
|
|
|
}
|
|
|
|
AA_SPEEX_DEBUG("Create resampler for : " << _inputSampleRate << " to " << _outputSampleRate);
|
|
|
|
int err = 0;
|
|
|
|
m_speexResampler = speex_resampler_init(_nbChannel,
|
|
|
|
_inputSampleRate,
|
|
|
|
_outputSampleRate,
|
|
|
|
_quality, &err);
|
|
|
|
#else
|
|
|
|
AA_SPEEX_WARNING("SPEEX DSP lib not accessible ==> can not resample");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
~ResamplerPrivate() {
|
|
|
|
#ifdef HAVE_SPEEX_DSP
|
2018-06-19 22:13:48 +02:00
|
|
|
if (m_speexResampler != null) {
|
2015-04-21 21:57:32 +02:00
|
|
|
speex_resampler_destroy(m_speexResampler);
|
2018-06-19 22:13:48 +02:00
|
|
|
m_speexResampler = null;
|
2015-04-21 21:57:32 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void process(void* _output, size_t& _nbChunkOut, const void* _input, size_t _nbChunk) {
|
|
|
|
#ifdef HAVE_SPEEX_DSP
|
|
|
|
switch (m_format) {
|
|
|
|
case audio::format_int16:
|
|
|
|
{
|
|
|
|
uint32_t nbChunkInput = _nbChunk;
|
|
|
|
uint32_t nbChunkOutput = _nbChunkOut;
|
|
|
|
int ret = speex_resampler_process_interleaved_int(m_speexResampler,
|
|
|
|
reinterpret_cast<const int16_t*>(_input),
|
|
|
|
&nbChunkInput,
|
|
|
|
reinterpret_cast<int16_t*>(_output),
|
|
|
|
&nbChunkOutput);
|
|
|
|
// Check all input and output ...
|
|
|
|
if (nbChunkInput != _nbChunk) {
|
|
|
|
AA_SPEEX_ERROR("inputSize (not all read ...) proceed=" << nbChunkInput << " requested=" << _nbChunk);
|
|
|
|
// TODO : manage this case ...
|
|
|
|
}
|
|
|
|
if (nbChunkOutput == _nbChunkOut) {
|
|
|
|
AA_SPEEX_ERROR("Might have not enought data in output... output size=" << _nbChunkOut);
|
|
|
|
// TODO : manage this case ...
|
|
|
|
}
|
|
|
|
_nbChunkOut = nbChunkOutput;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case audio::format_float:
|
|
|
|
{
|
|
|
|
uint32_t nbChunkInput = _nbChunk;
|
|
|
|
uint32_t nbChunkOutput = _nbChunkOut;
|
|
|
|
int ret = speex_resampler_process_interleaved_float(m_speexResampler,
|
|
|
|
reinterpret_cast<const float*>(_input),
|
|
|
|
&nbChunkInput,
|
|
|
|
reinterpret_cast<float*>(_output),
|
|
|
|
&nbChunkOutput);
|
|
|
|
// Check all input and output ...
|
|
|
|
if (nbChunkInput != _nbChunk) {
|
|
|
|
AA_SPEEX_ERROR("inputSize (not all read ...) proceed=" << nbChunkInput << " requested=" << _nbChunk);
|
|
|
|
// TODO : manage this case ...
|
|
|
|
}
|
|
|
|
if (nbChunkOutput == _nbChunkOut) {
|
|
|
|
AA_SPEEX_ERROR("Might have not enought data in output... output size=" << _nbChunkOut);
|
|
|
|
// TODO : manage this case ...
|
|
|
|
}
|
|
|
|
_nbChunkOut = nbChunkOutput;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
AA_SPEEX_ERROR("Can not Limit with unsupported format : " << m_format);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
AA_SPEEX_ERROR("Not build with speex DSP ... ");
|
|
|
|
_nbChunkOut = _nbChunk/10;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-20 22:10:56 +02:00
|
|
|
|
|
|
|
|
2015-04-21 21:57:32 +02:00
|
|
|
audio::algo::speex::Resampler::Resampler() {
|
2015-04-20 22:10:56 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
audio::algo::speex::Resampler::~Resampler() {
|
2015-04-21 21:57:32 +02:00
|
|
|
|
2015-04-20 22:10:56 +02:00
|
|
|
}
|
|
|
|
|
2015-04-21 21:57:32 +02:00
|
|
|
void audio::algo::speex::Resampler::init(int8_t _nbChannel, float _inputSampleRate, float _outputSampleRate, int8_t _quality, enum audio::format _format) {
|
|
|
|
m_private.reset();
|
2016-07-19 21:43:58 +02:00
|
|
|
m_private = ememory::makeShared<audio::algo::speex::ResamplerPrivate>(_nbChannel, _inputSampleRate, _outputSampleRate, _quality, _format);
|
2015-04-20 22:10:56 +02:00
|
|
|
}
|
|
|
|
|
2017-08-28 00:08:06 +02:00
|
|
|
etk::Vector<enum audio::format> audio::algo::speex::Resampler::getSupportedFormat() {
|
|
|
|
etk::Vector<enum audio::format> out = getNativeSupportedFormat();
|
2015-04-20 22:10:56 +02:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2017-08-28 00:08:06 +02:00
|
|
|
etk::Vector<enum audio::format> audio::algo::speex::Resampler::getNativeSupportedFormat() {
|
|
|
|
etk::Vector<enum audio::format> out;
|
|
|
|
out.pushBack(audio::format_float);
|
|
|
|
out.pushBack(audio::format_int16);
|
2015-04-20 22:10:56 +02:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2015-04-21 21:57:32 +02:00
|
|
|
void audio::algo::speex::Resampler::process(void* _output, size_t& _nbChunkOut, const void* _input, size_t _nbChunk) {
|
2018-06-19 22:13:48 +02:00
|
|
|
if (m_private == null) {
|
2015-04-20 22:10:56 +02:00
|
|
|
AA_SPEEX_ERROR("Algo is not initialized...");
|
|
|
|
}
|
2015-04-21 21:57:32 +02:00
|
|
|
m_private->process(_output, _nbChunkOut, _input, _nbChunk);
|
2015-04-20 22:10:56 +02:00
|
|
|
}
|
|
|
|
|