diff options
Diffstat (limited to 'src/loris/Harmonifier.C')
-rw-r--r-- | src/loris/Harmonifier.C | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/loris/Harmonifier.C b/src/loris/Harmonifier.C new file mode 100644 index 0000000..3a41c58 --- /dev/null +++ b/src/loris/Harmonifier.C @@ -0,0 +1,158 @@ +/* + * 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 + * + * + * Harmonifier.h + * + * Definition of class Harmonifier. + * + * Kelly Fitz, 26 Oct 2005 + * loris@cerlsoundgroup.org + * + * http://www.cerlsoundgroup.org/Loris/ + * + */ +#include "Harmonifier.h" + +#include "LinearEnvelope.h" + +#include <cmath> // for pow + +using namespace Loris; + + +// --------------------------------------------------------------------------- +// Constructor +// --------------------------------------------------------------------------- +//! Construct a new Harmonifier that applies the specified +//! reference Partial to fix the frequencies of Breakpoints +//! whose amplitude is below threshold_dB (0 by default, +//! to apply only to quiet Partials, specify a threshold, +//! like -90). +// +Harmonifier::Harmonifier( const Partial & ref, double threshold_dB ) : + _refPartial( ref ), + _freqFixThresholdDb( threshold_dB ), + _weight( createDefaultEnvelope() ) +{ + if ( 0 == _refPartial.numBreakpoints() ) + { + Throw( InvalidArgument, + "Cannot use an empty reference Partial in Harmonizer" ); + } + if ( 0 == _refPartial.label() ) + { + // if the reference is unlabeled, assume that it is the fundamental + _refPartial.setLabel( 1 ); + } + +} + +// --------------------------------------------------------------------------- +// Constructor +// --------------------------------------------------------------------------- +//! Construct a new Harmonifier that applies the specified +//! reference Partial to fix the frequencies of Breakpoints +//! whose amplitude is below threshold_dB (0 by default, +//! to apply only to quiet Partials, specify a threshold, +//! like -90). The Envelope is a time-varying weighting +//! on the harmonifing process. When 1, harmonic frequencies +//! are used, when 0, breakpoint frequencies are unmodified. +// +Harmonifier::Harmonifier( const Partial & ref, const Envelope & env, + double threshold_dB ) : + _refPartial( ref ), + _freqFixThresholdDb( threshold_dB ), + _weight( env.clone() ) +{ + if ( 0 == _refPartial.numBreakpoints() ) + { + Throw( InvalidArgument, + "Cannot use an empty reference Partial in Harmonizer" ); + } + if ( 0 == _refPartial.label() ) + { + // if the reference is unlabeled, assume that it is the fundamental + _refPartial.setLabel( 1 ); + } + +} + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +Harmonifier::~Harmonifier( void ) +{ +} + +// --------------------------------------------------------------------------- +// harmonify +// --------------------------------------------------------------------------- +//! Apply the reference envelope to a Partial. +//! +//! \pre The Partial p must be labeled with its harmonic number. +// +void Harmonifier::harmonify( Partial & p ) const +{ + // compute absolute magnitude thresholds: + static const double FadeRangeDB = 10; + const double BeginFade = std::pow( 10., 0.05 * (_freqFixThresholdDb+FadeRangeDB) ); + const double Threshold = std::pow( 10., 0.05 * _freqFixThresholdDb ); + const double OneOverFadeSpan = 1. / ( BeginFade - Threshold ); + + double fscale = (double)p.label() / _refPartial.label(); + + for ( Partial::iterator it = p.begin(); it != p.end(); ++it ) + { + Breakpoint & bp = it.breakpoint(); + + if ( bp.amplitude() < BeginFade ) + { + // alpha is the harmonic frequency weighting: + // when alpha is 1, the harmonic frequency is used, + // when alpha is 0, the breakpoint frequency is + // unmodified. + double alpha = + std::min( ( BeginFade - bp.amplitude() ) * OneOverFadeSpan, 1. ); + + // alpha is scaled by the weigthing envelope + alpha *= _weight->valueAt( it.time() ); + + double fRef = _refPartial.frequencyAt( it.time() ); + + bp.setFrequency( ( alpha * ( fRef * fscale ) ) + + ( (1 - alpha) * bp.frequency() ) ); + } + + } +} + +// --------------------------------------------------------------------------- +// createDefaultEnvelope (STATIC) +// --------------------------------------------------------------------------- +//! Return the default weighing envelope (always 1). +//! Used in template constructors. +// +Envelope * Harmonifier::createDefaultEnvelope( void ) +{ + return new LinearEnvelope( 1 ); +} + |