audio-drain/airtalgo/Volume.cpp

407 lines
12 KiB
C++
Raw Normal View History

2015-01-30 21:36:11 +01:00
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include "debug.h"
#include <airtalgo/Volume.h>
#include <iostream>
#undef __class__
#define __class__ "Volume"
airtalgo::Volume::Volume() :
2015-02-02 21:48:57 +01:00
m_volumeAppli(1.0f),
m_functionConvert(nullptr) {
2015-01-30 21:36:11 +01:00
}
void airtalgo::Volume::init() {
airtalgo::Algo::init();
2015-02-01 22:22:42 +01:00
m_type = "Volume";
m_supportedFormat.push_back(format_int16);
m_supportedFormat.push_back(format_int16_on_int32);
2015-01-30 21:36:11 +01:00
}
std::shared_ptr<airtalgo::Volume> airtalgo::Volume::create() {
std::shared_ptr<airtalgo::Volume> tmp(new airtalgo::Volume());
tmp->init();
return tmp;
}
airtalgo::Volume::~Volume() {
}
2015-02-03 21:29:23 +01:00
static int32_t neareastsss(float _val) {
int32_t out = 0;
while (_val > float(1<<out)) {
out++;
}
return std::min(16,out);
}
2015-02-02 21:48:57 +01:00
static void convert__int16__to__int16(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli) {
int16_t* in = static_cast<int16_t*>(_input);
int16_t* out = static_cast<int16_t*>(_output);
for (size_t iii=0; iii<_nbSample; ++iii) {
out[iii] = int16_t((int32_t(in[iii]) * int32_t(_volumeCoef)) >> _volumeDecalage);
}
}
static void convert__int16__to__int32(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli) {
int16_t* in = static_cast<int16_t*>(_input);
int32_t* out = static_cast<int32_t*>(_output);
for (size_t iii=0; iii<_nbSample; ++iii) {
out[iii] = (int32_t(in[iii]) * int32_t(_volumeCoef)) >> _volumeDecalage;
}
//AIRTALGO_INFO("plop " << in[0] << " >> " << out[0]);
}
static void convert__int32__to__int16(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli) {
int32_t* in = static_cast<int32_t*>(_input);
int16_t* out = static_cast<int16_t*>(_output);
for (size_t iii=0; iii<_nbSample; ++iii) {
int32_t value = in[iii] >> 16;
out[iii] = int16_t((int64_t(in[iii]) * int64_t(_volumeCoef)) >> _volumeDecalage);
}
}
static void convert__int32__to__int32(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli) {
int32_t* in = static_cast<int32_t*>(_input);
int32_t* out = static_cast<int32_t*>(_output);
for (size_t iii=0; iii<_nbSample; ++iii) {
out[iii] = int32_t((int64_t(in[iii]) * int64_t(_volumeCoef)) >> _volumeDecalage);
}
//AIRTALGO_INFO("plop " << in[0] << " >> " << out[0]);
}
static void convert__float__to__float(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli) {
float* in = static_cast<float*>(_input);
float* out = static_cast<float*>(_output);
for (size_t iii=0; iii<_nbSample; ++iii) {
out[iii] = in[iii] * _volumeAppli;
}
}
2015-01-30 21:36:11 +01:00
void airtalgo::Volume::configurationChange() {
airtalgo::Algo::configurationChange();
2015-02-02 21:48:57 +01:00
switch (m_input.getFormat()) {
default:
case format_int16:
switch (m_output.getFormat()) {
default:
case format_int16:
m_functionConvert = &convert__int16__to__int16;
AIRTALGO_DEBUG("Use converter : 'convert__int16__to__int16' for " << m_input.getFormat() << " to " << m_output.getFormat());
break;
case format_int16_on_int32:
case format_int32:
m_functionConvert = &convert__int16__to__int32;
AIRTALGO_DEBUG("Use converter : 'convert__int16__to__int32' for " << m_input.getFormat() << " to " << m_output.getFormat());
break;
case format_float:
AIRTALGO_ERROR("Impossible case 1");
break;
}
break;
case format_int16_on_int32:
case format_int32:
switch (m_output.getFormat()) {
default:
case format_int16:
m_functionConvert = &convert__int32__to__int16;
AIRTALGO_DEBUG("Use converter : 'convert__int32__to__int16' for " << m_input.getFormat() << " to " << m_output.getFormat());
break;
case format_int16_on_int32:
case format_int32:
m_functionConvert = &convert__int32__to__int32;
AIRTALGO_DEBUG("Use converter : 'convert__int32__to__int32' for " << m_input.getFormat() << " to " << m_output.getFormat());
break;
case format_float:
AIRTALGO_ERROR("Impossible case 2");
break;
}
break;
case format_float:
switch (m_output.getFormat()) {
default:
case format_int16:
case format_int16_on_int32:
case format_int32:
AIRTALGO_ERROR("Impossible case 4");
break;
case format_float:
m_functionConvert = &convert__float__to__float;
AIRTALGO_DEBUG("Use converter : 'convert__float__to__float' for " << m_input.getFormat() << " to " << m_output.getFormat());
break;
}
break;
2015-01-30 21:36:11 +01:00
}
if (m_input.getMap() != m_output.getMap()) {
AIRTALGO_ERROR("Volume map change is not supported");
}
if (m_input.getFrequency() != m_output.getFrequency()) {
AIRTALGO_ERROR("Volume frequency change is not supported");
}
// nee to process all time (the format not change (just a simple filter))
2015-02-02 21:48:57 +01:00
m_needProcess = true;
2015-02-04 21:08:06 +01:00
volumeChange();
2015-02-02 21:48:57 +01:00
}
2015-02-04 21:08:06 +01:00
void airtalgo::Volume::volumeChange() {
2015-02-02 21:48:57 +01:00
//m_volumeAppli = 20 * log(m_volumedB);
2015-02-03 21:29:23 +01:00
float volumedB = 0.0f;
for (auto &it : m_volumeList) {
if (it == nullptr) {
continue;
}
volumedB += it->getVolume();
2015-02-03 23:29:53 +01:00
AIRTALGO_VERBOSE("append volume : '" << it->getName() << " vol=" << it->getVolume() << "dB");
2015-02-03 21:29:23 +01:00
}
AIRTALGO_DEBUG(" Total volume : " << volumedB << "dB nbVolume=" << m_volumeList.size());
m_volumeAppli = std::pow(10.0f, volumedB/20.0f);
2015-02-02 21:48:57 +01:00
switch (m_input.getFormat()) {
default:
case format_int16:
switch (m_output.getFormat()) {
default:
case format_int16:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 16;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 16-neareast;
}
break;
case format_int16_on_int32:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 16;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 16-neareast;
}
break;
case format_int32:
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 0;
break;
case format_float:
AIRTALGO_ERROR("Impossible case 1");
break;
}
break;
case format_int16_on_int32:
switch (m_output.getFormat()) {
default:
case format_int16:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 16;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 16-neareast;
}
break;
case format_int16_on_int32:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 16;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 16-neareast;
}
break;
case format_int32:
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 0;
break;
case format_float:
AIRTALGO_ERROR("Impossible case 2");
break;
}
break;
case format_int32:
switch (m_output.getFormat()) {
default:
case format_int16:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 32;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 32-neareast;
}
break;
case format_int16_on_int32:
if (m_volumeAppli <= 1.0f) {
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 32;
} else {
int32_t neareast = neareastsss(m_volumeAppli);
m_volumeCoef = m_volumeAppli*float(1<<(16-neareast));
m_volumeDecalage = 32-neareast;
}
break;
case format_int32:
m_volumeCoef = m_volumeAppli*float(1<<16);
m_volumeDecalage = 16;
break;
case format_float:
AIRTALGO_ERROR("Impossible case 3");
break;
}
break;
case format_float:
// nothing to do (use m_volumeAppli)
break;
}
2015-01-30 21:36:11 +01:00
}
2015-02-02 21:48:57 +01:00
2015-02-01 22:22:42 +01:00
std::vector<airtalgo::format> airtalgo::Volume::getFormatSupportedInput() {
2015-02-02 21:48:57 +01:00
std::vector<airtalgo::format> tmp;
if (m_output.getFormat() == format_float) {
tmp.push_back(format_float);
}
if ( m_output.getFormat() == format_int16
|| m_output.getFormat() == format_int16_on_int32
|| m_output.getFormat() == format_int32) {
tmp.push_back(format_int16);
tmp.push_back(format_int16_on_int32);
tmp.push_back(format_int32);
}
return tmp;
2015-02-01 22:22:42 +01:00
};
std::vector<airtalgo::format> airtalgo::Volume::getFormatSupportedOutput() {
2015-02-02 21:48:57 +01:00
std::vector<airtalgo::format> tmp;
if (m_input.getFormat() == format_float) {
tmp.push_back(format_float);
}
if ( m_input.getFormat() == format_int16
|| m_input.getFormat() == format_int16_on_int32
|| m_input.getFormat() == format_int32) {
tmp.push_back(format_int16);
tmp.push_back(format_int16_on_int32);
tmp.push_back(format_int32);
}
return tmp;
2015-02-01 22:22:42 +01:00
};
2015-01-30 21:36:11 +01:00
bool airtalgo::Volume::process(std::chrono::system_clock::time_point& _time,
2015-02-01 22:22:42 +01:00
void* _input,
size_t _inputNbChunk,
void*& _output,
size_t& _outputNbChunk) {
2015-02-02 21:48:57 +01:00
airtalgo::AutoLogInOut tmpLog("Volume");
// chack if we need to process:
if (m_needProcess == false) {
2015-01-30 21:36:11 +01:00
_output = _input;
_outputNbChunk = _inputNbChunk;
return true;
}
2015-02-02 21:48:57 +01:00
if (_input == nullptr) {
_output = &(m_outputData[0]);
_outputNbChunk = 0;
AIRTALGO_ERROR("null pointer input ... ");
return false;
}
_outputNbChunk = _inputNbChunk;
m_outputData.resize(_outputNbChunk*m_input.getMap().size()*m_formatSize);
_output = &(m_outputData[0]);
if (m_functionConvert == nullptr) {
AIRTALGO_ERROR("null function ptr");
return false;
}
//AIRTALGO_WARNING("Apply volume : " << m_volumedB << "dB " << m_volumeAppli << " ==> x*" << m_volumeCoef << ">>" << m_volumeDecalage << " ex:50*C>>D=" << (50*m_volumeCoef>>m_volumeDecalage) );
m_functionConvert(_input, _output, _outputNbChunk*m_input.getMap().size(), m_volumeCoef, m_volumeDecalage, m_volumeAppli);
2015-02-01 22:22:42 +01:00
return true;
2015-01-30 21:36:11 +01:00
}
2015-02-03 21:29:23 +01:00
void airtalgo::Volume::addVolumeStage(const std::shared_ptr<VolumeElement>& _volume) {
if (_volume == nullptr) {
return;
}
for (auto &it : m_volumeList) {
if (it == nullptr) {
continue;
}
if (it == _volume) {
return;
}
if (it->getName() == _volume->getName()) {
return;
}
}
m_volumeList.push_back(_volume);
2015-02-04 21:08:06 +01:00
volumeChange();
2015-02-03 21:29:23 +01:00
}
bool airtalgo::Volume::setParameter(const std::string& _parameter, const std::string& _value) {
if (_parameter == "FLOW") {
// set Volume ...
for (auto &it : m_volumeList) {
if (it == nullptr) {
continue;
}
if (it->getName() == "FLOW") {
float value = 0;
2015-02-03 23:29:53 +01:00
if (sscanf(_value.c_str(), "%fdB", &value) != 1) {
return false;
}
2015-02-03 21:29:23 +01:00
// TODO : Check if out of range ...
it->setVolume(value);
AIRTALGO_DEBUG("Set volume : FLOW = " << value << " dB (from:" << _value << ")");
2015-02-04 21:08:06 +01:00
volumeChange();
2015-02-03 21:29:23 +01:00
return true;
}
}
}
AIRTALGO_ERROR("unknow set Parameter : '" << _parameter << "' with Value: '" << _value << "'");
return false;
}
std::string airtalgo::Volume::getParameter(const std::string& _parameter) const {
if (_parameter == "FLOW") {
// set Volume ...
for (auto &it : m_volumeList) {
if (it == nullptr) {
continue;
}
if (it->getName() == "FLOW") {
return std::to_string(it->getVolume()) + "dB";
}
}
}
AIRTALGO_ERROR("unknow get Parameter : '" << _parameter << "'");
return "[ERROR]";
}
std::string airtalgo::Volume::getParameterProperty(const std::string& _parameter) const {
if (_parameter == "FLOW") {
// set Volume ...
for (auto &it : m_volumeList) {
if (it == nullptr) {
continue;
}
if (it->getName() == "FLOW") {
return "[-300..300]dB";
}
}
}
AIRTALGO_ERROR("unknow Parameter property for: '" << _parameter << "'");
return "[ERROR]";
2015-02-04 21:08:06 +01:00
}