From e3ce6044e32eacc1093a716a001a71949dab9d9b Mon Sep 17 00:00:00 2001 From: Xavier Lizarraga Date: Tue, 10 Dec 2024 14:45:48 +0100 Subject: [PATCH 1/5] Add first design for the StereoResample algorithm --- src/algorithms/standard/stereoresample.cpp | 219 +++++++++++++++++++++ src/algorithms/standard/stereoresample.h | 112 +++++++++++ 2 files changed, 331 insertions(+) create mode 100644 src/algorithms/standard/stereoresample.cpp create mode 100644 src/algorithms/standard/stereoresample.h diff --git a/src/algorithms/standard/stereoresample.cpp b/src/algorithms/standard/stereoresample.cpp new file mode 100644 index 000000000..5b8204419 --- /dev/null +++ b/src/algorithms/standard/stereoresample.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2006-2021 Music Technology Group - Universitat Pompeu Fabra + * + * This file is part of Essentia + * + * Essentia is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation (FSF), 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 Affero GNU General Public License + * version 3 along with this program. If not, see http://www.gnu.org/licenses/ + */ + +#include "stereoresample.h" + +using namespace std; + +namespace essentia { +namespace standard { + +const char* StereoResample::name = "StereoResample"; +const char* StereoResample::category = "Standard"; +const char* StereoResample::description = DOC("This algorithm resamples the input stereo signal to the desired sampling rate.\n\n" +"The quality of conversion is documented in [3].\n\n" +"This algorithm is only supported if essentia has been compiled with Real=float, otherwise it will throw an exception. It may also throw an exception if there is an internal error in the SRC library during conversion.\n\n" + +"References:\n" +" [1] Secret Rabbit Code, http://www.mega-nerd.com/SRC\n\n" +" [2] Resampling - Wikipedia, the free encyclopedia\n" +" http://en.wikipedia.org/wiki/Resampling\n\n" +" [3] http://www.mega-nerd.com/SRC/api_misc.html#Converters"); + + +void StereoResample::configure() { + _quality = parameter("quality").toInt(); + _factor = parameter("outputSampleRate").toReal() / parameter("inputSampleRate").toReal(); + + // check to make sure Real is typedef'd as float + if (sizeof(Real) != sizeof(float)) { + throw EssentiaException("Resample: Error, Essentia has to be compiled with Real=float for resampling to work."); + } +} + +void StereoResample::compute() { + const std::vector& signal = _signal.get(); + std::vector& resampled = _resampled.get(); + + if (_factor == 1.0) { + resampled = signal; + return; + } + + if (signal.empty()) return; + + SRC_DATA src; + src.input_frames = (long)signal.size(); + src.data_in = const_cast(&(signal[0])); + + // add some samples to make sure we don't crash in a stupid way... + src.output_frames = (long)((double)signal.size()*_factor + 100.0); + resampled.resize(src.output_frames); + src.data_out = &(resampled[0]); + + src.src_ratio = _factor; + + // do the conversion + int error = src_simple(&src, _quality, 2); + + if (error) throw EssentiaException("Resample: Error in resampling: ", src_strerror(error)); + + resampled.resize(src.output_frames_gen); +} + +} // namespace standard +} // namespace essentia + +namespace essentia { +namespace streaming { + +const char* StereoResample::name = standard::StereoResample::name; +const char* StereoResample::description = standard::StereoResample::description; + +// NOTE: streaming process differs slightly from the standard in that there is a transport delay inside the streaming version of the SRC converter: http://www.mega-nerd.com/SRC/faq.html#Q006. For this reason less amount of samples than the expected are found and thus the zeropadding at the end. + +StereoResample::~StereoResample() { + if (_state) src_delete(_state); +} + +void StereoResample::configure() { + int quality = parameter("quality").toInt(); + Real factor = parameter("outputSampleRate").toReal() / parameter("inputSampleRate").toReal(); + + if (_state) src_delete(_state); + int nChannels = 2; + _state = src_new(quality, nChannels, &_errorCode); + + _data.src_ratio = factor; + + reset(); +} + +AlgorithmStatus StereoResample::process() { + EXEC_DEBUG("process()"); + + EXEC_DEBUG("Trying to acquire data"); + AlgorithmStatus status = acquireData(); + + if (status != OK) { + // FIXME: are we sure this still works? + // if status == NO_OUTPUT, we should temporarily stop the resampler, + // return from this function so its dependencies can process the frames, + // and reschedule the framecutter to run when all this is done. + if (status == NO_OUTPUT) { + EXEC_DEBUG("no more output available for resampling; mark it for rescheduling and return"); + //_reschedule = true; + return NO_OUTPUT; // if the buffer is full, we need to have produced something! + } + + // if shouldStop is true, that means there is no more audio, so we need + // to take what's left to fill in the output, instead of waiting for more + // data to come in (which would have done by returning from this function) + if (!shouldStop()) return NO_INPUT; + + int available = input("signal").available(); + EXEC_DEBUG("There are " << available << " available tokens"); + if (available == 0) return NO_INPUT; + + input("signal").setAcquireSize(available); + input("signal").setReleaseSize(available); + output("signal").setAcquireSize((int)(_data.src_ratio * available + 100 + (int)_delay)); + _data.end_of_input = 1; + + return process(); + } + + EXEC_DEBUG("data acquired"); + + const vector& signal = _signal.tokens(); + vector& resampled = _resampled.tokens(); + + EXEC_DEBUG("signal size:" << signal.size()); + EXEC_DEBUG("resampled size:" << resampled.size()); + + _data.data_in = const_cast(&(signal[0])); + _data.input_frames = (long)signal.size(); + + _data.data_out = &(resampled[0]); + _data.output_frames = (long)resampled.size(); + + + if (_data.src_ratio == 1.0) { + assert(_data.output_frames >= _data.input_frames); + fastcopy(_data.data_out, _data.data_in, _data.input_frames); + _data.input_frames_used = _data.input_frames; + _data.output_frames_gen = _data.input_frames; + } + else { + int error = src_process(_state, &_data); + + if (error) { + throw EssentiaException("Resample: ", src_strerror(error)); + } + + if (_data.input_frames_used == 0) { + throw EssentiaException("Resample: Internal consumption problem while resampling"); + } + } + + EXEC_DEBUG("input frames:" << _data.input_frames_used); + EXEC_DEBUG("produced:" << _data.output_frames_gen); + + _delay += (Real)_data.input_frames_used*_data.src_ratio - (Real)_data.output_frames_gen; + + assert((int)resampled.size() >= _data.output_frames_gen); + assert((int)signal.size() >= _data.input_frames_used); + + _signal.setReleaseSize(_data.input_frames_used); + _resampled.setReleaseSize(_data.output_frames_gen); + + releaseData(); + + EXEC_DEBUG("released"); + + return OK; +} + +void StereoResample::reset() { + Algorithm::reset(); + _data.end_of_input = 0; + _delay = 0; + + // make sure to reset I/O sizes, failure to do this causes inconsitent behavior with libsamplerate + // my theory is that because the signal is being chopped up in different intervals than before, + // the sampling is performed differently + _signal.setAcquireSize(_preferredSize); + _signal.setReleaseSize(_preferredSize); + _resampled.setAcquireSize(_preferredSize); + _resampled.setReleaseSize(_preferredSize); + + int maxElementsAtOnce = (int)(_data.src_ratio * _signal.acquireSize()) + 100; + _resampled.setAcquireSize(maxElementsAtOnce); + + BufferInfo buf; + buf.size = maxElementsAtOnce * 32; + buf.maxContiguousElements = maxElementsAtOnce*2; + _resampled.setBufferInfo(buf); + + int error = src_reset(_state); + if (error) throw EssentiaException("StereoResample: ", src_strerror(error)); +} + +} // namespace streaming +} // namespace essentia diff --git a/src/algorithms/standard/stereoresample.h b/src/algorithms/standard/stereoresample.h new file mode 100644 index 000000000..d144789dd --- /dev/null +++ b/src/algorithms/standard/stereoresample.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2006-2021 Music Technology Group - Universitat Pompeu Fabra + * + * This file is part of Essentia + * + * Essentia is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation (FSF), 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 Affero GNU General Public License + * version 3 along with this program. If not, see http://www.gnu.org/licenses/ + */ + +#ifndef ESSENTIA_STEREORESAMPLE_H +#define ESSENTIA_STEREORESAMPLE_H + +#include +#include "algorithm.h" + +namespace essentia { +namespace standard { + +class StereoResample : public Algorithm { + + protected: + Input > _signal; + Output > _StereoResampled; + + public: + StereoResample() { + declareInput(_signal, "signal", "the input signal"); + declareOutput(_StereoResampled, "signal", "the StereoResampled signal"); + } + + void declareParameters() { + declareParameter("inputSampleRate", "the sampling rate of the input signal [Hz]", "(0,inf)", 44100.); + declareParameter("outputSampleRate", "the sampling rate of the output signal [Hz]", "(0,inf)", 44100.); + declareParameter("quality", "the quality of the conversion, 0 for best quality, 4 for fast linear approximation", "[0,4]", 1); + } + + void configure(); + + void compute(); + + static const char* name; + static const char* category; + static const char* description; + + protected: + double _factor; + int _quality; +}; + +} // namespace standard +} // namespace essentia + + +#include "streamingalgorithm.h" + +namespace essentia { +namespace streaming { + +class StereoResample : public Algorithm { + + protected: + Sink _signal; + Source _resampled; + int _preferredSize; + + SRC_STATE* _state; + SRC_DATA _data; + int _errorCode; + float _delay; + + public: + StereoResample() : _state(0) { + _preferredSize = 4096; // arbitrary + declareInput(_signal, _preferredSize, "signal", "the input stereo signal"); + declareOutput(_resampled, _preferredSize, "signal", "the stereo resampled signal"); + + // useless as we do it anyway in the configure() method + //_StereoResampled.setBufferType(BufferUsage::forAudioStream); + } + + ~StereoResample(); + + void declareParameters() { + declareParameter("inputSampleRate", "the sampling rate of the input stereo signal [Hz]", "(0,inf)", 44100.); + declareParameter("outputSampleRate", "the sampling rate of the output stereo signal [Hz]", "(0,inf)", 44100.); + declareParameter("quality", "the quality of the conversion, 0 for best quality, 4 for fast linear approximation", "[0,4]", 1); + } + + void configure(); + AlgorithmStatus process(); + void reset(); + + static const char* name; + static const char* category; + static const char* description; + +}; + +} // namespace streaming +} // namespace essentia + +#endif // ESSENTIA_STEREORESAMPLE_H From afed3344a63cac9287663130f4d9af6cb760ada2 Mon Sep 17 00:00:00 2001 From: Xavi Lizarraga Date: Tue, 10 Dec 2024 14:54:41 +0100 Subject: [PATCH 2/5] Small fix in stereoresample.h --- src/algorithms/standard/stereoresample.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/standard/stereoresample.h b/src/algorithms/standard/stereoresample.h index d144789dd..2a53c0b69 100644 --- a/src/algorithms/standard/stereoresample.h +++ b/src/algorithms/standard/stereoresample.h @@ -35,7 +35,7 @@ class StereoResample : public Algorithm { public: StereoResample() { declareInput(_signal, "signal", "the input signal"); - declareOutput(_StereoResampled, "signal", "the StereoResampled signal"); + declareOutput(_resampled, "signal", "the StereoResampled signal"); } void declareParameters() { From ec780252523f740aef8b86a164094f18a7d4b30f Mon Sep 17 00:00:00 2001 From: Xavi Lizarraga Date: Tue, 10 Dec 2024 14:57:20 +0100 Subject: [PATCH 3/5] Fix output name. --- src/algorithms/standard/stereoresample.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/standard/stereoresample.h b/src/algorithms/standard/stereoresample.h index 2a53c0b69..002f72f29 100644 --- a/src/algorithms/standard/stereoresample.h +++ b/src/algorithms/standard/stereoresample.h @@ -30,7 +30,7 @@ class StereoResample : public Algorithm { protected: Input > _signal; - Output > _StereoResampled; + Output > _resampled; public: StereoResample() { From 812e74db227dd9998280edef8bba949c697f8c67 Mon Sep 17 00:00:00 2001 From: Xavier Lizarraga Date: Tue, 10 Dec 2024 20:08:28 +0100 Subject: [PATCH 4/5] Update with new design using StereoDemuxer, Resample and StereoMuxer --- src/algorithms/standard/stereoresample.cpp | 49 +++++++++++----------- src/algorithms/standard/stereoresample.h | 41 +++++++++++------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/algorithms/standard/stereoresample.cpp b/src/algorithms/standard/stereoresample.cpp index 5b8204419..d7ffc7c52 100644 --- a/src/algorithms/standard/stereoresample.cpp +++ b/src/algorithms/standard/stereoresample.cpp @@ -41,45 +41,45 @@ void StereoResample::configure() { _quality = parameter("quality").toInt(); _factor = parameter("outputSampleRate").toReal() / parameter("inputSampleRate").toReal(); - // check to make sure Real is typedef'd as float - if (sizeof(Real) != sizeof(float)) { - throw EssentiaException("Resample: Error, Essentia has to be compiled with Real=float for resampling to work."); - } + // create and configure algorithms + _stereoDemuxer = AlgorithmFactory::create("StereoDemuxer"); + _stereoMuxer = AlgorithmFactory::create("StereoMuxer"); + _resample = AlgorithmFactory::create("Resample"); + + _resample->configure(INHERIT("inputSampleRate"), + INHERIT("outputSampleRate"), + INHERIT("quality")); } void StereoResample::compute() { const std::vector& signal = _signal.get(); std::vector& resampled = _resampled.get(); - if (_factor == 1.0) { - resampled = signal; - return; - } - - if (signal.empty()) return; + // compute resampling for left and right channel + _stereoDemuxer->input("audio").set(signal); + _stereoDemuxer->output("left").set(_leftStorage); + _stereoDemuxer->output("right").set(_rightStorage); - SRC_DATA src; - src.input_frames = (long)signal.size(); - src.data_in = const_cast(&(signal[0])); + _resample->input("signal").set(_leftStorage); + _resample->output("signal").set(_left); - // add some samples to make sure we don't crash in a stupid way... - src.output_frames = (long)((double)signal.size()*_factor + 100.0); - resampled.resize(src.output_frames); - src.data_out = &(resampled[0]); + _stereoDemuxer->compute(); + _resample->compute(); - src.src_ratio = _factor; + _resample->input("signal").set(_rightStorage); + _resample->output("signal").set(_right); - // do the conversion - int error = src_simple(&src, _quality, 2); + _stereoMuxer->input("left").set(_left); + _stereoMuxer->input("right").set(_right); + _stereoMuxer->output("audio").set(resampled); - if (error) throw EssentiaException("Resample: Error in resampling: ", src_strerror(error)); - - resampled.resize(src.output_frames_gen); + _resample->compute(); + _stereoMuxer->compute(); } } // namespace standard } // namespace essentia - +/* namespace essentia { namespace streaming { @@ -217,3 +217,4 @@ void StereoResample::reset() { } // namespace streaming } // namespace essentia +*/ \ No newline at end of file diff --git a/src/algorithms/standard/stereoresample.h b/src/algorithms/standard/stereoresample.h index d144789dd..631d1e544 100644 --- a/src/algorithms/standard/stereoresample.h +++ b/src/algorithms/standard/stereoresample.h @@ -20,8 +20,8 @@ #ifndef ESSENTIA_STEREORESAMPLE_H #define ESSENTIA_STEREORESAMPLE_H -#include -#include "algorithm.h" +//#include "algorithm.h" +#include "algorithmfactory.h" namespace essentia { namespace standard { @@ -30,12 +30,20 @@ class StereoResample : public Algorithm { protected: Input > _signal; - Output > _StereoResampled; + Output > _resampled; + Algorithm* _stereoDemuxer; + Algorithm* _stereoMuxer; + Algorithm* _resample; + + double _factor; + int _quality; + std::vector _left, _right; + std::vector _leftStorage, _rightStorage; public: StereoResample() { - declareInput(_signal, "signal", "the input signal"); - declareOutput(_StereoResampled, "signal", "the StereoResampled signal"); + declareInput(_signal, "signal", "the input stereo signal"); + declareOutput(_resampled, "signal", "the resampled stereo signal"); } void declareParameters() { @@ -45,16 +53,13 @@ class StereoResample : public Algorithm { } void configure(); - void compute(); + void reset(); static const char* name; static const char* category; static const char* description; - protected: - double _factor; - int _quality; }; } // namespace standard @@ -71,15 +76,15 @@ class StereoResample : public Algorithm { protected: Sink _signal; Source _resampled; - int _preferredSize; - SRC_STATE* _state; - SRC_DATA _data; - int _errorCode; - float _delay; + Algorithm* _stereoDemuxer; + Algorithm* _stereoMuxer; + Algorithm* _resample; + + int _preferredSize; public: - StereoResample() : _state(0) { + StereoResample() { _preferredSize = 4096; // arbitrary declareInput(_signal, _preferredSize, "signal", "the input stereo signal"); declareOutput(_resampled, _preferredSize, "signal", "the stereo resampled signal"); @@ -88,7 +93,11 @@ class StereoResample : public Algorithm { //_StereoResampled.setBufferType(BufferUsage::forAudioStream); } - ~StereoResample(); + ~StereoResample(){ + if (_stereoDemuxer) delete _stereoDemuxer; + if (_stereoMuxer) delete _stereoMuxer; + if (_resample) delete _resample; + }; void declareParameters() { declareParameter("inputSampleRate", "the sampling rate of the input stereo signal [Hz]", "(0,inf)", 44100.); From c375a5eab59b61773487d277b1b68d66c22e075f Mon Sep 17 00:00:00 2001 From: xaviliz Date: Thu, 12 Dec 2024 15:23:32 +0100 Subject: [PATCH 5/5] Add design and prototype for StereoResample in streaming mode --- src/algorithms/standard/stereoresample.cpp | 159 ++++++--------------- src/algorithms/standard/stereoresample.h | 63 +++++--- 2 files changed, 86 insertions(+), 136 deletions(-) diff --git a/src/algorithms/standard/stereoresample.cpp b/src/algorithms/standard/stereoresample.cpp index d7ffc7c52..a0e8bef92 100644 --- a/src/algorithms/standard/stereoresample.cpp +++ b/src/algorithms/standard/stereoresample.cpp @@ -36,10 +36,8 @@ const char* StereoResample::description = DOC("This algorithm resamples the inpu " http://en.wikipedia.org/wiki/Resampling\n\n" " [3] http://www.mega-nerd.com/SRC/api_misc.html#Converters"); - void StereoResample::configure() { - _quality = parameter("quality").toInt(); - _factor = parameter("outputSampleRate").toReal() / parameter("inputSampleRate").toReal(); + //_quality = parameter("quality").toInt(); // create and configure algorithms _stereoDemuxer = AlgorithmFactory::create("StereoDemuxer"); @@ -79,6 +77,8 @@ void StereoResample::compute() { } // namespace standard } // namespace essentia + + /* namespace essentia { namespace streaming { @@ -86,133 +86,56 @@ namespace streaming { const char* StereoResample::name = standard::StereoResample::name; const char* StereoResample::description = standard::StereoResample::description; -// NOTE: streaming process differs slightly from the standard in that there is a transport delay inside the streaming version of the SRC converter: http://www.mega-nerd.com/SRC/faq.html#Q006. For this reason less amount of samples than the expected are found and thus the zeropadding at the end. +StereoResample::StereoResample() : _configured(false) { + _preferredSize = 4096; // arbitrary + declareInput(_signal, _preferredSize, "signal", "the input stereo signal"); + declareOutput(_resampled, _preferredSize, "signal", "the stereo resampled signal"); -StereoResample::~StereoResample() { - if (_state) src_delete(_state); + createInnerNetwork(); } -void StereoResample::configure() { - int quality = parameter("quality").toInt(); - Real factor = parameter("outputSampleRate").toReal() / parameter("inputSampleRate").toReal(); +void StereoResample::createInnerNetwork(){ + AlgorithmFactory& factory = AlgorithmFactory::instance(); + _stereoDemuxer = AlgorithmFactory::create("StereoDemuxer"); + _stereoMuxer = AlgorithmFactory::create("StereoMuxer"); + _resample = AlgorithmFactory::create("Resample"); - if (_state) src_delete(_state); - int nChannels = 2; - _state = src_new(quality, nChannels, &_errorCode); + _resample->configure(INHERIT("inputSampleRate"), + INHERIT("outputSampleRate"), + INHERIT("quality")); - _data.src_ratio = factor; + // wire algorithms + _signal >> _stereoDemuxer->input("audio"); + _stereoDemuxer->output("left") >> _resample->input("signal"); + _resample->output("signal") >> _stereoMuxer->input("left"); + _stereoDemuxer->output("right") >> _resample->input("signal"); + _resample->output("signal") >> _stereoMuxer->input("right"); + _stereoMuxer->output("audio") >> _resampled; - reset(); + // create network + _network = new scheduler::Network(_stereoDemuxer); } -AlgorithmStatus StereoResample::process() { - EXEC_DEBUG("process()"); - - EXEC_DEBUG("Trying to acquire data"); - AlgorithmStatus status = acquireData(); - - if (status != OK) { - // FIXME: are we sure this still works? - // if status == NO_OUTPUT, we should temporarily stop the resampler, - // return from this function so its dependencies can process the frames, - // and reschedule the framecutter to run when all this is done. - if (status == NO_OUTPUT) { - EXEC_DEBUG("no more output available for resampling; mark it for rescheduling and return"); - //_reschedule = true; - return NO_OUTPUT; // if the buffer is full, we need to have produced something! - } - - // if shouldStop is true, that means there is no more audio, so we need - // to take what's left to fill in the output, instead of waiting for more - // data to come in (which would have done by returning from this function) - if (!shouldStop()) return NO_INPUT; - - int available = input("signal").available(); - EXEC_DEBUG("There are " << available << " available tokens"); - if (available == 0) return NO_INPUT; - - input("signal").setAcquireSize(available); - input("signal").setReleaseSize(available); - output("signal").setAcquireSize((int)(_data.src_ratio * available + 100 + (int)_delay)); - _data.end_of_input = 1; - - return process(); - } - - EXEC_DEBUG("data acquired"); - - const vector& signal = _signal.tokens(); - vector& resampled = _resampled.tokens(); - - EXEC_DEBUG("signal size:" << signal.size()); - EXEC_DEBUG("resampled size:" << resampled.size()); - - _data.data_in = const_cast(&(signal[0])); - _data.input_frames = (long)signal.size(); - - _data.data_out = &(resampled[0]); - _data.output_frames = (long)resampled.size(); - - - if (_data.src_ratio == 1.0) { - assert(_data.output_frames >= _data.input_frames); - fastcopy(_data.data_out, _data.data_in, _data.input_frames); - _data.input_frames_used = _data.input_frames; - _data.output_frames_gen = _data.input_frames; - } - else { - int error = src_process(_state, &_data); - - if (error) { - throw EssentiaException("Resample: ", src_strerror(error)); - } - - if (_data.input_frames_used == 0) { - throw EssentiaException("Resample: Internal consumption problem while resampling"); - } - } - - EXEC_DEBUG("input frames:" << _data.input_frames_used); - EXEC_DEBUG("produced:" << _data.output_frames_gen); - - _delay += (Real)_data.input_frames_used*_data.src_ratio - (Real)_data.output_frames_gen; - - assert((int)resampled.size() >= _data.output_frames_gen); - assert((int)signal.size() >= _data.input_frames_used); - - _signal.setReleaseSize(_data.input_frames_used); - _resampled.setReleaseSize(_data.output_frames_gen); - - releaseData(); - - EXEC_DEBUG("released"); +void StereoResample::configure() { + // TODO: initialize algorithms + // TODO: create network + // create and configure algorithms + _stereoDemuxer = AlgorithmFactory::create("StereoDemuxer"); + _stereoMuxer = AlgorithmFactory::create("StereoMuxer"); + _resample = AlgorithmFactory::create("Resample"); - return OK; + _resample->configure(INHERIT("inputSampleRate"), + INHERIT("outputSampleRate"), + INHERIT("quality")); } void StereoResample::reset() { - Algorithm::reset(); - _data.end_of_input = 0; - _delay = 0; - - // make sure to reset I/O sizes, failure to do this causes inconsitent behavior with libsamplerate - // my theory is that because the signal is being chopped up in different intervals than before, - // the sampling is performed differently - _signal.setAcquireSize(_preferredSize); - _signal.setReleaseSize(_preferredSize); - _resampled.setAcquireSize(_preferredSize); - _resampled.setReleaseSize(_preferredSize); - - int maxElementsAtOnce = (int)(_data.src_ratio * _signal.acquireSize()) + 100; - _resampled.setAcquireSize(maxElementsAtOnce); - - BufferInfo buf; - buf.size = maxElementsAtOnce * 32; - buf.maxContiguousElements = maxElementsAtOnce*2; - _resampled.setBufferInfo(buf); - - int error = src_reset(_state); - if (error) throw EssentiaException("StereoResample: ", src_strerror(error)); + clearAlgos(); +} + +void StereoResample::clearAlgos() { + if (!_configured) return; + delete _network; } } // namespace streaming diff --git a/src/algorithms/standard/stereoresample.h b/src/algorithms/standard/stereoresample.h index 631d1e544..e807ad96d 100644 --- a/src/algorithms/standard/stereoresample.h +++ b/src/algorithms/standard/stereoresample.h @@ -65,13 +65,17 @@ class StereoResample : public Algorithm { } // namespace standard } // namespace essentia - -#include "streamingalgorithm.h" +/* +//#include "streamingalgorithm.h" +#include "streamingalgorithmcomposite.h" +#include "pool.h" +#include "algorithm.h" +#include "network.h" namespace essentia { namespace streaming { -class StereoResample : public Algorithm { +class StereoResample : public AlgorithmComposite { protected: Sink _signal; @@ -81,23 +85,16 @@ class StereoResample : public Algorithm { Algorithm* _stereoMuxer; Algorithm* _resample; - int _preferredSize; + scheduler::Network* _network; - public: - StereoResample() { - _preferredSize = 4096; // arbitrary - declareInput(_signal, _preferredSize, "signal", "the input stereo signal"); - declareOutput(_resampled, _preferredSize, "signal", "the stereo resampled signal"); + bool _configured; + int _preferredSize; - // useless as we do it anyway in the configure() method - //_StereoResampled.setBufferType(BufferUsage::forAudioStream); - } + void clearAlgos(); - ~StereoResample(){ - if (_stereoDemuxer) delete _stereoDemuxer; - if (_stereoMuxer) delete _stereoMuxer; - if (_resample) delete _resample; - }; + public: + StereoResample(); + ~StereoResample(); void declareParameters() { declareParameter("inputSampleRate", "the sampling rate of the input stereo signal [Hz]", "(0,inf)", 44100.); @@ -106,8 +103,9 @@ class StereoResample : public Algorithm { } void configure(); - AlgorithmStatus process(); + //AlgorithmStatus process(); void reset(); + void createInnerNetwork(); static const char* name; static const char* category; @@ -115,6 +113,35 @@ class StereoResample : public Algorithm { }; +} // namespace streaming +} // namespace essentia +*/ + + +#include "streamingalgorithmwrapper.h" + +namespace essentia { +namespace streaming { + +class StereoResample : public StreamingAlgorithmWrapper { + + protected: + Sink > _signal; + Source > _resampled; + + public: + + StereoResample() { + declareAlgorithm("StereoResample"); + declareInput(_signal, TOKEN, "signal"); + declareOutput(_resampled, TOKEN, "signal"); + + // useless as we do it anyway in the configure() method + //_StereoResampled.setBufferType(BufferUsage::forAudioStream); + } + +}; + } // namespace streaming } // namespace essentia