diff --git a/airtalgo/Algo.cpp b/airtalgo/Algo.cpp index b23b6cb..27f3e88 100644 --- a/airtalgo/Algo.cpp +++ b/airtalgo/Algo.cpp @@ -8,19 +8,6 @@ #include "debug.h" -std::ostream& airtalgo::operator <<(std::ostream& _os, const IOFormatInterface& _obj) { - _os << "{"; - if (_obj.getConfigured() == false) { - _os << "Not configured"; - } else { - _os << "format=" << _obj.getFormat(); - _os << ", frequency=" << _obj.getFrequency(); - _os << ", map=" << _obj.getMap(); - } - _os << "}"; - return _os; -} - #undef __class__ #define __class__ "Algo" diff --git a/airtalgo/Algo.h b/airtalgo/Algo.h index 6cbbe9e..21bb28f 100644 --- a/airtalgo/Algo.h +++ b/airtalgo/Algo.h @@ -16,155 +16,11 @@ #include #include #include +#include "AutoLogInOut.h" +#include "IOFormatInterface.h" #include "debug.h" namespace airtalgo{ - class autoLogInOut { - private: - std::string m_value; - public: - autoLogInOut(const std::string& _value) : - m_value(_value) { - AIRTALGO_VERBOSE(" '" << m_value << "' [START]"); - } - ~autoLogInOut() { - AIRTALGO_VERBOSE(" '" << m_value << "' [STOP]"); - } - }; - class IOFormatInterface { - public: - IOFormatInterface() : - m_configured(false), - m_format(airtalgo::format_unknow), - m_map(), - m_frequency(0) { - m_map.push_back(airtalgo::channel_frontLeft); - m_map.push_back(airtalgo::channel_frontRight); - } - IOFormatInterface(std::vector _map, airtalgo::format _format=airtalgo::format_int16, float _frequency=48000.0f) : - m_configured(true), - m_format(_format), - m_map(_map), - m_frequency(_frequency) { - - AIRTALGO_WARNING(" plop : " << m_map << " " << m_format << " " << m_frequency); - } - void set(std::vector _map, airtalgo::format _format=airtalgo::format_int16, float _frequency=48000.0f) { - bool hasChange = false; - if (m_map != _map) { - m_map = _map; - hasChange = true; - } - if (m_format != _format) { - m_format = _format; - hasChange = true; - } - if (m_frequency == _frequency) { - m_frequency = _frequency; - hasChange = true; - } - if (hasChange == true) { - m_configured = true; - configurationChange(); - } - AIRTALGO_WARNING(" plop : " << m_map << " " << m_format << " " << m_frequency); - } - protected: - bool m_configured; - public: - void setConfigured(bool _value) { - m_configured = _value; - } - bool getConfigured() const { - return m_configured; - } - protected: - airtalgo::format m_format; //!< input Algo Format - public: - /** - * @brief Get the algo format. - * @return the current Format. - */ - airtalgo::format getFormat() const { - return m_format; - } - /** - * @brief Set the algo format. - * @param[in] _value New Format. - */ - void setFormat(airtalgo::format _value) { - if (m_format == _value) { - return; - } - m_format = _value; - m_configured = true; - configurationChange(); - } - protected: - std::vector m_map; //!< input channel Map - public: - /** - * @brief Get the algo channel Map. - * @return the current channel Map. - */ - const std::vector& getMap() const{ - return m_map; - } - /** - * @brief Set the algo channel Map. - * @param[in] _value New channel Map. - */ - void setMap(const std::vector& _value) { - AIRTALGO_DEBUG(" base : " << m_map << " " << _value); - if (m_map == _value) { - return; - } - m_map = _value; - m_configured = true; - AIRTALGO_DEBUG(" base2 : " << m_map); - configurationChange(); - } - protected: - float m_frequency; //!< input Algo Format - public: - /** - * @brief Get the algo frequency. - * @return the current frequency. - */ - float getFrequency() const{ - return m_frequency; - } - /** - * @brief Set the algo frequency. - * @param[in] _value New frequency. - */ - void setFrequency(float _value) { - if (m_frequency == _value) { - return; - } - m_configured = true; - m_frequency = _value; - configurationChange(); - } - protected: - std::function m_ioChangeFunctor; //!< function pointer on the upper class - void configurationChange() { - if (m_ioChangeFunctor != nullptr) { - m_ioChangeFunctor(); - } - } - public: - /** - * @brief Set the callback function to be notify when the arameter change. - * @param[in] _functor Function to call. - */ - void setCallback(const std::function& _functor) { - m_ioChangeFunctor = _functor; - } - - }; - std::ostream& operator <<(std::ostream& _os, const IOFormatInterface& _obj); - class Algo : public std::enable_shared_from_this { private: std::string m_name; @@ -211,7 +67,6 @@ namespace airtalgo{ IOFormatInterface m_input; //!< Input audio property public: void setInputFormat(const IOFormatInterface& _format) { - AIRTALGO_WARNING(" plopp : " << _format.getMap() << " " << _format.getFormat() << " " << _format.getFrequency()); m_input.set(_format.getMap(), _format.getFormat(), _format.getFrequency()); } const IOFormatInterface& getInputFormat() const { @@ -224,7 +79,6 @@ namespace airtalgo{ IOFormatInterface m_output; //!< Output audio property public: void setOutputFormat(const IOFormatInterface& _format) { - AIRTALGO_WARNING(" plopp : " << _format.getMap() << " " << _format.getFormat() << " " << _format.getFrequency()); m_output.set(_format.getMap(), _format.getFormat(), _format.getFrequency()); } const IOFormatInterface& getOutputFormat() const { diff --git a/airtalgo/AutoLogInOut.cpp b/airtalgo/AutoLogInOut.cpp new file mode 100644 index 0000000..d1cbfee --- /dev/null +++ b/airtalgo/AutoLogInOut.cpp @@ -0,0 +1,17 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include "AutoLogInOut.h" +#include "debug.h" + +airtalgo::AutoLogInOut::AutoLogInOut(const std::string& _value) : + m_value(_value) { + AIRTALGO_VERBOSE(" '" << m_value << "' [START]"); +} + +airtalgo::AutoLogInOut::~AutoLogInOut() { + AIRTALGO_VERBOSE(" '" << m_value << "' [STOP]"); +} diff --git a/airtalgo/AutoLogInOut.h b/airtalgo/AutoLogInOut.h new file mode 100644 index 0000000..40b11e9 --- /dev/null +++ b/airtalgo/AutoLogInOut.h @@ -0,0 +1,27 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + + +#ifndef __AIRT_ALGO_AUTO_LOG_IN_OUT_H__ +#define __AIRT_ALGO_AUTO_LOG_IN_OUT_H__ + +#include +#include "debug.h" + +namespace airtalgo{ + class AutoLogInOut { + private: + std::string m_value; + public: + AutoLogInOut(const std::string& _value); + ~AutoLogInOut(); + }; +} + +#include "debugRemove.h" + +#endif + diff --git a/airtalgo/ChannelReorder.cpp b/airtalgo/ChannelReorder.cpp index efd0b09..ffe2b12 100644 --- a/airtalgo/ChannelReorder.cpp +++ b/airtalgo/ChannelReorder.cpp @@ -30,7 +30,7 @@ std::shared_ptr airtalgo::ChannelReorder::create() { } void airtalgo::ChannelReorder::configurationChange() { - airtalgo::autoLogInOut("ChannelReorder (config)"); + airtalgo::AutoLogInOut("ChannelReorder (config)"); airtalgo::Algo::configurationChange(); if (m_input.getFormat() != m_output.getFormat()) { AIRTALGO_ERROR("can not support Format Change ..."); @@ -54,7 +54,7 @@ bool airtalgo::ChannelReorder::process(std::chrono::system_clock::time_point& _t size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk) { - airtalgo::autoLogInOut tmpLog("ChannelReorder"); + airtalgo::AutoLogInOut tmpLog("ChannelReorder"); _outputNbChunk = _inputNbChunk; // check if we need to process: if (m_needProcess == false) { diff --git a/airtalgo/EndPointCallback.cpp b/airtalgo/EndPointCallback.cpp index 5a87399..5aeea63 100644 --- a/airtalgo/EndPointCallback.cpp +++ b/airtalgo/EndPointCallback.cpp @@ -51,7 +51,7 @@ bool airtalgo::EndPointCallback::process(std::chrono::system_clock::time_point& size_t _inputNbChunk, // requested number of sample ... void*& _output, size_t& _outputNbChunk){ - airtalgo::autoLogInOut tmpLog("EndPointCallback"); + airtalgo::AutoLogInOut tmpLog("EndPointCallback"); if (m_outputFunction != nullptr) { // update buffer size ... m_outputData.resize(_inputNbChunk*m_output.getMap().size()*m_formatSize); diff --git a/airtalgo/EndPointRead.cpp b/airtalgo/EndPointRead.cpp index fe08d7e..da7d7fd 100644 --- a/airtalgo/EndPointRead.cpp +++ b/airtalgo/EndPointRead.cpp @@ -37,7 +37,7 @@ bool airtalgo::EndPointRead::process(std::chrono::system_clock::time_point& _tim size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk){ - airtalgo::autoLogInOut tmpLog("EndPointRead"); + airtalgo::AutoLogInOut tmpLog("EndPointRead"); return false; } diff --git a/airtalgo/EndPointWrite.cpp b/airtalgo/EndPointWrite.cpp index 54e5fe6..257fbb4 100644 --- a/airtalgo/EndPointWrite.cpp +++ b/airtalgo/EndPointWrite.cpp @@ -37,7 +37,7 @@ bool airtalgo::EndPointWrite::process(std::chrono::system_clock::time_point& _ti size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk){ - airtalgo::autoLogInOut tmpLog("EndPointWrite"); + airtalgo::AutoLogInOut tmpLog("EndPointWrite"); //AIRTALGO_INFO(" nb Sample in buffer : " << m_tmpData.size()); if (m_function != nullptr) { if (m_tmpData.size() <= 20000) { @@ -72,9 +72,10 @@ bool airtalgo::EndPointWrite::process(std::chrono::system_clock::time_point& _ti void airtalgo::EndPointWrite::write(const void* _value, size_t _nbChunk) { std::unique_lock lock(m_mutex); - AIRTALGO_INFO("[ASYNC] Get data : " << _nbChunk << " chunks" + AIRTALGO_INFO("[ASYNC] Write data : " << _nbChunk << " chunks" << " ==> " << _nbChunk*m_output.getMap().size() << " samples" - << " formatSize=" << int32_t(m_formatSize)); + << " formatSize=" << int32_t(m_formatSize) + << " bufferSize=" << m_tmpData.size()); const int8_t* value = static_cast(_value); for (size_t iii=0; iii<_nbChunk*m_formatSize*m_output.getMap().size(); ++iii) { m_tmpData.push_back(*value++); diff --git a/airtalgo/FormatUpdate.cpp b/airtalgo/FormatUpdate.cpp index 2b3c6bb..5743c11 100644 --- a/airtalgo/FormatUpdate.cpp +++ b/airtalgo/FormatUpdate.cpp @@ -248,14 +248,14 @@ bool airtalgo::FormatUpdate::process(std::chrono::system_clock::time_point& _tim size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk) { - airtalgo::autoLogInOut tmpLog("FormatUpdate"); + airtalgo::AutoLogInOut tmpLog("FormatUpdate"); // chack if we need to process: if (m_needProcess == false) { _output = _input; _outputNbChunk = _inputNbChunk; return true; } - if (_input == NULL) { + if (_input == nullptr) { _output = &(m_outputData[0]); _outputNbChunk = 0; AIRTALGO_ERROR("null pointer input ... "); @@ -264,7 +264,7 @@ bool airtalgo::FormatUpdate::process(std::chrono::system_clock::time_point& _tim _outputNbChunk = _inputNbChunk; m_outputData.resize(_outputNbChunk*m_input.getMap().size()*m_formatSize); _output = &(m_outputData[0]); - if (m_functionConvert == NULL) { + if (m_functionConvert == nullptr) { AIRTALGO_ERROR("null function ptr"); return false; } diff --git a/airtalgo/IOFormatInterface.cpp b/airtalgo/IOFormatInterface.cpp new file mode 100644 index 0000000..6f6a351 --- /dev/null +++ b/airtalgo/IOFormatInterface.cpp @@ -0,0 +1,119 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include "IOFormatInterface.h" +#include "debug.h" + +#undef __class__ +#define __class__ "IOFormatInterface" + + +std::ostream& airtalgo::operator <<(std::ostream& _os, const IOFormatInterface& _obj) { + _os << "{"; + if (_obj.getConfigured() == false) { + _os << "Not configured"; + } else { + _os << "format=" << _obj.getFormat(); + _os << ", frequency=" << _obj.getFrequency(); + _os << ", map=" << _obj.getMap(); + } + _os << "}"; + return _os; +} + +airtalgo::IOFormatInterface::IOFormatInterface() : + m_configured(false), + m_format(airtalgo::format_unknow), + m_map(), + m_frequency(0) { + m_map.push_back(airtalgo::channel_frontLeft); + m_map.push_back(airtalgo::channel_frontRight); +} + +airtalgo::IOFormatInterface::IOFormatInterface(std::vector _map, airtalgo::format _format, float _frequency) : + m_configured(true), + m_format(_format), + m_map(_map), + m_frequency(_frequency) { + +} + +void airtalgo::IOFormatInterface::set(std::vector _map, airtalgo::format _format, float _frequency) { + bool hasChange = false; + if (m_map != _map) { + m_map = _map; + hasChange = true; + } + if (m_format != _format) { + m_format = _format; + hasChange = true; + } + if (m_frequency != _frequency) { + m_frequency = _frequency; + hasChange = true; + } + if (hasChange == true) { + m_configured = true; + configurationChange(); + } +} + +void airtalgo::IOFormatInterface::setConfigured(bool _value) { + m_configured = _value; +} + +bool airtalgo::IOFormatInterface::getConfigured() const { + return m_configured; +} + +airtalgo::format airtalgo::IOFormatInterface::getFormat() const { + return m_format; +} + +void airtalgo::IOFormatInterface::setFormat(airtalgo::format _value) { + if (m_format == _value) { + return; + } + m_format = _value; + m_configured = true; + configurationChange(); +} + +const std::vector& airtalgo::IOFormatInterface::getMap() const{ + return m_map; +} + +void airtalgo::IOFormatInterface::setMap(const std::vector& _value) { + if (m_map == _value) { + return; + } + m_map = _value; + m_configured = true; + configurationChange(); +} + +float airtalgo::IOFormatInterface::getFrequency() const{ + return m_frequency; +} + +void airtalgo::IOFormatInterface::setFrequency(float _value) { + if (m_frequency == _value) { + return; + } + m_configured = true; + m_frequency = _value; + configurationChange(); +} + +void airtalgo::IOFormatInterface::configurationChange() { + if (m_ioChangeFunctor != nullptr) { + m_ioChangeFunctor(); + } +} + +void airtalgo::IOFormatInterface::setCallback(const std::function& _functor) { + m_ioChangeFunctor = _functor; +} diff --git a/airtalgo/IOFormatInterface.h b/airtalgo/IOFormatInterface.h new file mode 100644 index 0000000..bfbcc94 --- /dev/null +++ b/airtalgo/IOFormatInterface.h @@ -0,0 +1,85 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + + +#ifndef __AIRT_ALGO_IO_FORMAT_INTERFACE_H__ +#define __AIRT_ALGO_IO_FORMAT_INTERFACE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "AutoLogInOut.h" +#include "debug.h" + +namespace airtalgo{ + class IOFormatInterface { + public: + IOFormatInterface(); + IOFormatInterface(std::vector _map, airtalgo::format _format=airtalgo::format_int16, float _frequency=48000.0f); + void set(std::vector _map, airtalgo::format _format=airtalgo::format_int16, float _frequency=48000.0f); + protected: + bool m_configured; + public: + void setConfigured(bool _value); + bool getConfigured() const; + protected: + airtalgo::format m_format; //!< input Algo Format + public: + /** + * @brief Get the algo format. + * @return the current Format. + */ + airtalgo::format getFormat() const; + /** + * @brief Set the algo format. + * @param[in] _value New Format. + */ + void setFormat(airtalgo::format _value); + protected: + std::vector m_map; //!< input channel Map + public: + /** + * @brief Get the algo channel Map. + * @return the current channel Map. + */ + const std::vector& getMap() const; + /** + * @brief Set the algo channel Map. + * @param[in] _value New channel Map. + */ + void setMap(const std::vector& _value); + protected: + float m_frequency; //!< input Algo Format + public: + /** + * @brief Get the algo frequency. + * @return the current frequency. + */ + float getFrequency() const; + /** + * @brief Set the algo frequency. + * @param[in] _value New frequency. + */ + void setFrequency(float _value); + protected: + std::function m_ioChangeFunctor; //!< function pointer on the upper class + void configurationChange(); + public: + /** + * @brief Set the callback function to be notify when the arameter change. + * @param[in] _functor Function to call. + */ + void setCallback(const std::function& _functor); + }; + std::ostream& operator <<(std::ostream& _os, const IOFormatInterface& _obj); +} + +#endif diff --git a/airtalgo/Process.cpp b/airtalgo/Process.cpp index df1ee8d..df99929 100644 --- a/airtalgo/Process.cpp +++ b/airtalgo/Process.cpp @@ -12,12 +12,16 @@ #include #include #include +#include +#include +#include #include #undef __class__ #define __class__ "Process" -airtalgo::Process::Process() { +airtalgo::Process::Process() : + m_isConfigured(false) { } airtalgo::Process::~Process() { @@ -108,10 +112,12 @@ bool airtalgo::Process::process(std::chrono::system_clock::time_point& _time, } void airtalgo::Process::pushBack(const std::shared_ptr& _algo) { + removeAlgoDynamic(); m_listAlgo.push_back(_algo); } void airtalgo::Process::pushFront(const std::shared_ptr& _algo) { + removeAlgoDynamic(); m_listAlgo.insert(m_listAlgo.begin(), _algo); } @@ -151,6 +157,10 @@ template std::vector getUnion(const std::vector& _out, const s } void airtalgo::Process::updateInterAlgo() { + if (m_isConfigured == true) { + // cahin is already configured + return ; + } AIRTALGO_INFO(" display properties : nbAlgo : " << m_listAlgo.size()); for (auto &it : m_listAlgo) { AIRTALGO_INFO(" [" << it->getType() << "] '" << it->getName() << "'"); @@ -175,33 +185,155 @@ void airtalgo::Process::updateInterAlgo() { for (size_t iii=1; iiigetOutputFormat().getConfigured() == false && m_listAlgo[iii]->getInputFormat().getConfigured() == false) { - std::vector freq; - std::vector> map; - std::vector format; // step 1 : check frequency: - freq = getUnion(m_listAlgo[iii-1]->getFrequencySupportedOutput(), - m_listAlgo[iii]->getFrequencySupportedInput()); + std::vector freqOut = m_listAlgo[iii-1]->getFrequencySupportedOutput(); + std::vector freqIn = m_listAlgo[iii]->getFrequencySupportedInput(); + std::vector freq = getUnion(freqOut, freqIn); // step 2 : Check map: - map = getUnion>(m_listAlgo[iii-1]->getMapSupportedOutput(), - m_listAlgo[iii]->getMapSupportedInput()); + std::vector> mapOut = m_listAlgo[iii-1]->getMapSupportedOutput(); + std::vector> mapIn = m_listAlgo[iii]->getMapSupportedInput(); + std::vector> map = getUnion>(mapOut, mapIn); // step 3 : Check Format: - format = getUnion(m_listAlgo[iii-1]->getFormatSupportedOutput(), - m_listAlgo[iii]->getFormatSupportedInput()); + std::vector formatOut = m_listAlgo[iii-1]->getFormatSupportedOutput(); + std::vector formatIn = m_listAlgo[iii]->getFormatSupportedInput(); + std::vector format = getUnion(formatOut, formatIn); - if ( freq.size() == 1 - && map.size() == 1 - && format.size() == 1) { + if ( freq.size() >= 1 + && map.size() >= 1 + && format.size() >= 1) { AIRTALGO_INFO(" find 1 compatibility :{format=" << format << ",frequency=" << freq << ",map=" << map << "}"); airtalgo::IOFormatInterface tmp(map[0], format[0], freq[0]); m_listAlgo[iii-1]->setOutputFormat(tmp); m_listAlgo[iii]->setInputFormat(tmp); continue; } - + // create mapping to transform: + airtalgo::IOFormatInterface out; + airtalgo::IOFormatInterface in; + if (freq.size() > 0) { + out.setFrequency(freq[0]); + in.setFrequency(freq[0]); + } else { + if (freqOut.size() == 0) { + if (freqIn.size() == 0) { + out.setFrequency(m_listAlgo[iii-1]->getInputFormat().getFrequency()); + in.setFrequency(m_listAlgo[iii-1]->getInputFormat().getFrequency()); + } else { + out.setFrequency(freqIn[0]); + in.setFrequency(freqIn[0]); + } + } else { + if (freqIn.size() == 0) { + out.setFrequency(freqOut[0]); + in.setFrequency(freqOut[0]); + } else { + out.setFrequency(freqOut[0]); + in.setFrequency(freqIn[0]); + } + } + } + if (map.size() > 0) { + out.setMap(map[0]); + in.setMap(map[0]); + } else { + if (mapOut.size() == 0) { + if (mapIn.size() == 0) { + out.setMap(m_listAlgo[iii-1]->getInputFormat().getMap()); + in.setMap(m_listAlgo[iii-1]->getInputFormat().getMap()); + } else { + out.setMap(mapIn[0]); + in.setMap(mapIn[0]); + } + } else { + if (mapIn.size() == 0) { + out.setMap(mapOut[0]); + in.setMap(mapOut[0]); + } else { + out.setMap(mapOut[0]); + in.setMap(mapIn[0]); + } + } + } + if (format.size() > 0) { + out.setFormat(format[0]); + in.setFormat(format[0]); + } else { + if (formatOut.size() == 0) { + if (formatIn.size() == 0) { + out.setFormat(m_listAlgo[iii-1]->getInputFormat().getFormat()); + in.setFormat(m_listAlgo[iii-1]->getInputFormat().getFormat()); + } else { + out.setFormat(formatIn[0]); + in.setFormat(formatIn[0]); + } + } else { + if (formatIn.size() == 0) { + out.setFormat(formatOut[0]); + in.setFormat(formatOut[0]); + } else { + out.setFormat(formatOut[0]); + in.setFormat(formatIn[0]); + } + } + } AIRTALGO_INFO(" union:"); AIRTALGO_INFO(" format : " << format); AIRTALGO_INFO(" frequency : " << freq); AIRTALGO_INFO(" map : " << map); + AIRTALGO_INFO(" update: out=" << out); + AIRTALGO_INFO(" in=" << in); + m_listAlgo[iii-1]->setOutputFormat(out); + m_listAlgo[iii]->setInputFormat(in); + // TODO : Add updater with an optimisation of CPU + if (out.getFrequency() != in.getFrequency()) { + + // TODO : Do it better: special check for resampler : only support int16_t + if ( out.getFormat() != format_int16 + /* && out.getFormat() != format_float */) { + // need add a format Updater + std::shared_ptr algo = airtalgo::FormatUpdate::create(); + algo->setTemporary(); + algo->setInputFormat(out); + out.setFormat(format_int16); + algo->setOutputFormat(out); + m_listAlgo.insert(m_listAlgo.begin()+iii, algo); + AIRTALGO_INFO("convert " << out.getFormat() << " -> " << in.getFormat()); + iii++; + } + // need add a resampler + std::shared_ptr algo = airtalgo::Resampler::create(); + algo->setTemporary(); + algo->setInputFormat(out); + out.setFrequency(in.getFrequency()); + algo->setOutputFormat(out); + m_listAlgo.insert(m_listAlgo.begin()+iii, algo); + AIRTALGO_INFO("convert " << out.getFrequency() << " -> " << in.getFrequency()); + out.setFrequency(in.getFrequency()); + iii++; + } + if (out.getMap() != in.getMap()) { + // need add a channel Reorder + std::shared_ptr algo = airtalgo::ChannelReorder::create(); + algo->setTemporary(); + algo->setInputFormat(out); + out.setMap(in.getMap()); + algo->setOutputFormat(out); + m_listAlgo.insert(m_listAlgo.begin()+iii, algo); + AIRTALGO_INFO("convert " << out.getMap() << " -> " << in.getMap()); + iii++; + } + if (out.getFormat() != in.getFormat()) { + // need add a format Updater + std::shared_ptr algo = airtalgo::FormatUpdate::create(); + algo->setTemporary(); + algo->setInputFormat(out); + out.setFormat(in.getFormat()); + algo->setOutputFormat(out); + m_listAlgo.insert(m_listAlgo.begin()+iii, algo); + AIRTALGO_INFO("convert " << out.getFormat() << " -> " << in.getFormat()); + iii++; + } + } else if ( m_listAlgo[iii-1]->getOutputFormat().getConfigured() == false || m_listAlgo[iii]->getInputFormat().getConfigured() == false) { AIRTALGO_ERROR(" configuration error mode in " << iii-1 << " && " << iii ); @@ -221,10 +353,14 @@ void airtalgo::Process::updateInterAlgo() { AIRTALGO_ERROR(" Output : Not configured"); } } - + m_isConfigured = true; //exit(-1); } void airtalgo::Process::removeAlgoDynamic() { - + if (m_isConfigured == true) { + // chain is already unconfigured. + return; + } + m_isConfigured = false; } diff --git a/airtalgo/Process.h b/airtalgo/Process.h index 8eaf455..fea0c0d 100644 --- a/airtalgo/Process.h +++ b/airtalgo/Process.h @@ -70,6 +70,7 @@ namespace airtalgo{ void pushBack(const std::shared_ptr& _algo); void pushFront(const std::shared_ptr& _algo); void clear() { + m_isConfigured = false; m_listAlgo.clear(); } template void removeIfFirst() { @@ -100,6 +101,9 @@ namespace airtalgo{ } return false; } + private: + bool m_isConfigured; + public: void updateInterAlgo(); void removeAlgoDynamic(); }; diff --git a/airtalgo/Resampler.cpp b/airtalgo/Resampler.cpp index 5cf5119..bba0ade 100644 --- a/airtalgo/Resampler.cpp +++ b/airtalgo/Resampler.cpp @@ -23,6 +23,7 @@ airtalgo::Resampler::Resampler() : void airtalgo::Resampler::init() { airtalgo::Algo::init(); m_type = "Resampler"; + m_supportedFormat.push_back(format_int16); } std::shared_ptr airtalgo::Resampler::create() { @@ -82,7 +83,7 @@ bool airtalgo::Resampler::process(std::chrono::system_clock::time_point& _time, size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk) { - airtalgo::autoLogInOut tmpLog("Resampler"); + airtalgo::AutoLogInOut tmpLog("Resampler"); _outputNbChunk = 2048; // chack if we need to process: if (m_needProcess == false) { diff --git a/airtalgo/Volume.cpp b/airtalgo/Volume.cpp index 47c86fc..6f45530 100644 --- a/airtalgo/Volume.cpp +++ b/airtalgo/Volume.cpp @@ -13,7 +13,8 @@ airtalgo::Volume::Volume() : m_volumedB(0.0f), - m_volumeAppli(1.0f) { + m_volumeAppli(1.0f), + m_functionConvert(nullptr) { } @@ -34,10 +35,104 @@ airtalgo::Volume::~Volume() { } + + +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(_input); + int16_t* out = static_cast(_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(_input); + int32_t* out = static_cast(_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(_input); + int16_t* out = static_cast(_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(_input); + int32_t* out = static_cast(_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(_input); + float* out = static_cast(_output); + for (size_t iii=0; iii<_nbSample; ++iii) { + out[iii] = in[iii] * _volumeAppli; + } +} + void airtalgo::Volume::configurationChange() { airtalgo::Algo::configurationChange(); - if (m_input.getFormat() != m_output.getFormat()) { - AIRTALGO_ERROR("Volume format change is not supported"); + 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; } if (m_input.getMap() != m_output.getMap()) { AIRTALGO_ERROR("Volume map change is not supported"); @@ -46,29 +141,183 @@ void airtalgo::Volume::configurationChange() { AIRTALGO_ERROR("Volume frequency change is not supported"); } // nee to process all time (the format not change (just a simple filter)) - m_needProcess = false; + m_needProcess = true; } +void airtalgo::Volume::updateVolumeValues() { + //m_volumeAppli = 20 * log(m_volumedB); + m_volumeAppli = std::pow(10.0f, m_volumedB/20.0f); + 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; + } +} + + std::vector airtalgo::Volume::getFormatSupportedInput() { - return m_supportedFormat; + std::vector 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; }; std::vector airtalgo::Volume::getFormatSupportedOutput() { - return m_supportedFormat; + std::vector 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; }; - +static int32_t neareastsss(float _val) { + int32_t out = 0; + while (_val > float(1< 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); return true; } diff --git a/airtalgo/Volume.h b/airtalgo/Volume.h index 69599d9..53d4aa9 100644 --- a/airtalgo/Volume.h +++ b/airtalgo/Volume.h @@ -14,10 +14,21 @@ #include namespace airtalgo { + // TODO: Optimisation + // TODO: Zero crossing + // TODO: Continuous update volume + // TODO: Manage multiple volume + // TODO: Manage set volume class Volume : public Algo { private: float m_volumedB; + // for float input : float m_volumeAppli; + // for integer input : + int32_t m_volumeDecalage; // Volume to apply is simple as : X * m_coef >> m_coef + int32_t m_volumeCoef; + // convertion function: + void (*m_functionConvert)(void* _input, void* _output, size_t _nbSample, int32_t _volumeCoef, int32_t _volumeDecalage, float _volumeAppli); protected: /** * @brief Constructor @@ -41,6 +52,8 @@ namespace airtalgo { public: virtual std::vector getFormatSupportedInput(); virtual std::vector getFormatSupportedOutput(); + protected: + virtual void updateVolumeValues(); }; }; diff --git a/lutin_airtalgo.py b/lutin_airtalgo.py index 9ba2e62..2a5e7aa 100644 --- a/lutin_airtalgo.py +++ b/lutin_airtalgo.py @@ -24,10 +24,12 @@ def create(target): 'airtalgo/FormatUpdate.cpp', 'airtalgo/Process.cpp', 'airtalgo/Resampler.cpp', - 'airtalgo/Volume.cpp' + 'airtalgo/Volume.cpp', + 'airtalgo/IOFormatInterface.cpp', + 'airtalgo/AutoLogInOut.cpp' ]) - # TODO: myModule.add_optionnal_module_depend('speexdsp', "HAVE_SPEEX_DSP_RESAMPLE") + # TODO: myModule.add_optional_module_depend('speexdsp', "HAVE_SPEEX_DSP_RESAMPLE") myModule.compile_flags_CC("-DHAVE_SPEEX_DSP_RESAMPLE") myModule.add_module_depend(['etk', 'speexdsp']) myModule.add_export_path(tools.get_current_path(__file__))