summaryrefslogtreecommitdiff
path: root/src/loris/Harmonifier.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/loris/Harmonifier.C')
-rw-r--r--src/loris/Harmonifier.C158
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 );
+}
+