#ifndef INCLUDE_RESAMPLER_H #define INCLUDE_RESAMPLER_H /* * This is the Loris C++ Class Library, implementing analysis, * manipulation, and synthesis of digitized sounds using the Reassigned * Bandwidth-Enhanced Additive Sound Model. * * Loris is Copyright (c) 1999-2010 by Kelly Fitz and Lippold Haken * * 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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * Resampler.h * * Definition of class Resampler, for converting reassigned Partial envelopes * into more conventional additive synthesis envelopes, having data points * at regular time intervals. The benefits of reassigned analysis are NOT * lost in this process, since the elimination of unreliable data and the * reduction of temporal smearing are reflected in the resampled data. * * Lippold, 7 Aug 2003 * loris@cerlsoundgroup.org * * http://www.cerlsoundgroup.org/Loris/ * */ #include "PartialList.h" #include "LinearEnvelope.h" // begin namespace namespace Loris { class Partial; // --------------------------------------------------------------------------- // class Resampler // //! Class Resampler represents an algorithm for resampling Partial envelopes //! at regular time intervals. Resampling makes the envelope data more suitable //! for exchange (as SDIF data, for example) with other applications that //! cannot process raw (continuously-distributed) reassigned data. Resampling //! will often greatly reduce the size of the data (by greatly reducing the //! number of Breakpoints in the Partials) without adversely affecting the //! quality of the reconstruction. // class Resampler { // --- public interface --- public: // --- lifecycle --- //! Initialize a Resampler having the specified uniform sampling //! interval. Enable phase-correct resampling, in which frequencies //! of resampled Partials are modified (using fixFrequency) such //! that the resampled phases are achieved in synthesis. Phase- //! correct resampling can be disabled using setPhaseCorrect. //! //! Resampled Partials will be composed of Breakpoints at every //! integer multiple of the resampling interval. //! //! \sa setPhaseCorrect //! \sa fixFrequency //! //! \param sampleInterval is the resampling interval in seconds, //! Breakpoint data is computed at integer multiples of //! sampleInterval seconds. //! //! \throw InvalidArgument if sampleInterval is not positive. explicit Resampler( double sampleInterval ); // --- use compiler-generated copy/assign/destroy --- // --- parameters --- //! Specify phase-corrected resampling, or not. If phase //! correct, Partial frequencies are altered slightly //! to match, as nearly as possible, the Breakpoint //! phases after resampling. Phases are updated so that //! the Partial frequencies and phases are consistent after //! resampling. //! //! \param correctPhase is a boolean flag specifying that //! (if true) frequency/phase correction should be //! applied after resampling. void setPhaseCorrect( bool correctPhase ); // --- resampling --- //! Resample the specified Partial using the stored quanitization interval. //! The Breakpoint times will comprise a contiguous sequence of all integer //! multiples of the sampling interval, starting and ending with the nearest //! multiples to the ends of the Partial. If phase correct resampling is //! specified (the default)≤ frequencies and phases are corrected to be in //! agreement and to match as nearly as possible the resampled phases. //! //! Resampling is performed in-place. //! //! \param p is the Partial to resample void resample( Partial & p ) const; //! Function call operator: same as resample( p ). void operator() ( Partial & p ) const { resample( p ); } //! Resample the specified Partial using the stored quanitization interval. //! The Breakpoint times will comprise a contiguous sequence of all integer //! multiples of the sampling interval, starting and ending with the nearest //! multiples to the ends of the Partial. If phase correct resampling is //! specified (the default)≤ frequencies and phases are corrected to be in //! agreement and to match as nearly as possible the resampled phases. //! //! The timing envelope represents a warping of the time axis that is //! applied during resampling. The Breakpoint times in resampled Partials //! will a comprise contiguous sequence of all integer multiples of the //! sampling interval between the first and last breakpoints in the timing //! envelope, and each Breakpoint will represent the parameters of the //! original Partial at the time that is the value of the timing envelope //! at that instant. //! //! Resampling is performed in-place. //! //! \param p is the Partial to resample //! //! \param timingEnv is the timing envelope, a map of Breakpoint //! times in resampled Partials onto parameter sampling //! instants in the original Partials. //! //! \throw InvalidArgument if timingEnv has any negative breakpoint //! times or values. void resample( Partial & p, const LinearEnvelope & timingEnv ) const; //! Quantize the Breakpoint times using the specified Partial using the //! stored quanitization interval. Each Breakpoint in the Partial is //! replaced by a Breakpoint constructed by resampling the Partial at //! the nearest integer multiple of the of the resampling interval. //! //! Quantization is performed in-place. //! //! \param p is the Partial to resample void quantize( Partial & p ) const; //! Resample all Partials in the specified (half-open) range using this //! Resampler's stored quanitization interval. The Breakpoint times in //! resampled Partials will comprise a contiguous sequence of all integer //! multiples of the sampling interval, starting and ending with the nearest //! multiples to the ends of the Partial. If phase correct resampling is //! specified (the default)≤ frequencies and phases are corrected to be in //! agreement and to match as nearly as possible the resampled phases. //! //! Resampling is performed in-place. //! //! \param begin is the beginning of the range of Partials to resample //! \param end is (one-past) the end of the range of Partials to resample //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. #if ! defined(NO_TEMPLATE_MEMBERS) template void resample( Iter begin, Iter end ) const; #else inline void resample( PartialList::iterator begin, PartialList::iterator end ) const; #endif //! Function call operator: same as resample( begin, end ). #if ! defined(NO_TEMPLATE_MEMBERS) template void operator()( Iter begin, Iter end ) const #else void operator()( PartialList::iterator begin, PartialList::iterator end ) const #endif { resample( begin, end ); } //! Resample all Partials in the specified (half-open) range using this //! Resampler's stored quanitization interval. The Breakpoint times in //! resampled Partials will comprise a contiguous sequence of all integer //! multiples of the sampling interval, starting and ending with the nearest //! multiples to the ends of the Partial. If phase correct resampling is //! specified (the default)≤ frequencies and phases are corrected to be in //! agreement and to match as nearly as possible the resampled phases. //! //! The timing envelope represents a warping of the time axis that is //! applied during resampling. The Breakpoint times in resampled Partials //! will a comprise contiguous sequence of all integer multiples of the //! sampling interval between the first and last breakpoints in the timing //! envelope, and each Breakpoint will represent the parameters of the //! original Partial at the time that is the value of the timing envelope //! at that instant. //! //! Resampling is performed in-place. //! //! \param begin is the beginning of the range of Partials to resample //! \param end is (one-past) the end of the range of Partials to resample //! \param timingEnv is the timing envelope, a map of Breakpoint //! times in resampled Partials onto parameter sampling //! instants in the original Partials. //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. #if ! defined(NO_TEMPLATE_MEMBERS) template void resample( Iter begin, Iter end, const LinearEnvelope & timingEnv ) const; #else inline void resample( PartialList::iterator begin, PartialList::iterator end, const LinearEnvelope & timingEnv) const; #endif //! Quantize all Partials in the specified (half-open) range. //! Each Breakpoint in the Partials is replaced by a Breakpoint //! constructed by resampling the Partial at the nearest //! integer multiple of the of the resampling interval. //! //! \param begin is the beginning of the range of Partials to quantize //! \param end is (one-past) the end of the range of Partials to quantize //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. #if ! defined(NO_TEMPLATE_MEMBERS) template void quantize( Iter begin, Iter end ) const; #else inline void quantize( PartialList::iterator begin, PartialList::iterator end ) const; #endif // -- static members -- //! Static member that constructs an instance and applies //! it to a sequence of Partials. //! Construct a Resampler using the specified resampling //! interval, and use it to channelize a sequence of Partials. //! //! \param begin is the beginning of a sequence of Partials to //! resample. //! \param end is the end of a sequence of Partials to //! resample. //! \param sampleInterval is the resampling interval in seconds, //! Breakpoint data is computed at integer multiples of //! sampleInterval seconds. //! \param denseResampling is a boolean flag indicating that dense //! resamping (Breakpoint at every integer multiple of the //! resampling interval) should be performed. If false (the //! default), sparse resampling (Breakpoints only at multiples //! of the resampling interval near Breakpoint times in the //! original Partial) is performed. //! \throw InvalidArgument if sampleInterval is not positive. //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. #if ! defined(NO_TEMPLATE_MEMBERS) template< typename Iter > static void resample( Iter begin, Iter end, double sampleInterval, bool denseResampling = false ); #else static inline void resample( PartialList::iterator begin, PartialList::iterator end, double sampleInterval, bool denseResampling = false ); #endif // --- instance variables --- private: //! the resampling interval in seconds double interval_; //! boolean flag selecting phase-corrected resampling //! (default is true) bool phaseCorrect_; }; // end of class Resampler // --------------------------------------------------------------------------- // resample (sequence of Partials) // --------------------------------------------------------------------------- //! Resample all Partials in the specified (half-open) range using this //! Resampler's stored sampling interval, so that the Breakpoints in //! the Partial envelopes will all lie on a common temporal grid. //! The Breakpoint times in the resampled Partial will comprise a //! contiguous sequence of integer multiples of the sampling interval, //! beginning with the multiple nearest to the Partial's start time and //! ending with the multiple nearest to the Partial's end time. Resampling //! is performed in-place. //! //! \param begin is the beginning of the range of Partials to resample //! \param end is (one-past) the end of the range of Partials to resample //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. // #if ! defined(NO_TEMPLATE_MEMBERS) template void Resampler::resample( Iter begin, Iter end ) const #else inline void Resampler::resample( PartialList::iterator begin, PartialList::iterator end ) const #endif { while ( begin != end ) { resample( *begin++ ); } } // --------------------------------------------------------------------------- // resample (sequence of Partials, with timing envelope) // --------------------------------------------------------------------------- //! Resample all Partials in the specified (half-open) range using this //! Resampler's stored sampling interval, so that the Breakpoints in //! the Partial envelopes will all lie on a common temporal grid. //! The Breakpoint times in the resampled Partial will comprise a //! contiguous sequence of integer multiples of the sampling interval, //! beginning with the multiple nearest to the Partial's start time and //! ending with the multiple nearest to the Partial's end time. Resampling //! is performed in-place. //! //! \param begin is the beginning of the range of Partials to resample //! \param end is (one-past) the end of the range of Partials to resample //! \param timingEnv is the timing envelope, a map of Breakpoint //! times in resampled Partials onto parameter sampling //! instants in the original Partials. //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. // #if ! defined(NO_TEMPLATE_MEMBERS) template void Resampler::resample( Iter begin, Iter end, const LinearEnvelope & timingEnv ) const #else inline void Resampler::resample( PartialList::iterator begin, PartialList::iterator end, const LinearEnvelope & timingEnv ) const #endif { while ( begin != end ) { resample( *begin++, timingEnv ); } } // --------------------------------------------------------------------------- // quantize (sequence of Partials) // --------------------------------------------------------------------------- //! Quantize all Partials in the specified (half-open) range. //! Each Breakpoint in the Partials is replaced by a Breakpoint //! constructed by resampling the Partial at the nearest //! integer multiple of the of the resampling interval. //! //! \param begin is the beginning of the range of Partials to quantize //! \param end is (one-past) the end of the range of Partials to quantize //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. // #if ! defined(NO_TEMPLATE_MEMBERS) template void Resampler::quantize( Iter begin, Iter end ) const #else inline void Resampler::quantize( PartialList::iterator begin, PartialList::iterator end ) const #endif { while ( begin != end ) { quantize( *begin++ ); } } // --------------------------------------------------------------------------- // resample (static) // --------------------------------------------------------------------------- //! Static member that constructs an instance and applies //! phase-correct resampling to a sequence of Partials. //! Construct a Resampler using the specified resampling //! interval, and use it to channelize a sequence of Partials. //! //! \param begin is the beginning of a sequence of Partials to //! resample. //! \param end is the end of a sequence of Partials to //! resample. //! \param sampleInterval is the resampling interval in seconds, //! Breakpoint data is computed at integer multiples of //! sampleInterval seconds. //! \param denseResampling is a boolean flag indicating that dense //! resamping (Breakpoint at every integer multiple of the //! resampling interval) should be performed. If false (the //! default), sparse resampling (Breakpoints only at multiples //! of the resampling interval near Breakpoint times in the //! original Partial) is performed. //! \throw InvalidArgument if sampleInterval is not positive. //! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end //! must be PartialList::iterators, otherwise they can be any type //! of iterators over a sequence of Partials. // #if ! defined(NO_TEMPLATE_MEMBERS) template< typename Iter > void Resampler::resample( Iter begin, Iter end, double sampleInterval, bool denseResampling ) #else inline void Resampler::resample( PartialList::iterator begin, PartialList::iterator end, double sampleInterval, bool denseResampling ) #endif { Resampler instance( sampleInterval ); if ( denseResampling ) { instance.resample( begin, end ); } else { instance.quantize( begin, end ); } } } // end of namespace Loris #endif /* ndef INCLUDE_RESAMPLER_H */