summaryrefslogtreecommitdiff
path: root/src/loris/lorisNonObj_pi.C
diff options
context:
space:
mode:
authorJohn Glover <glover.john@gmail.com>2011-07-08 18:06:21 +0100
committerJohn Glover <glover.john@gmail.com>2011-07-08 18:06:21 +0100
commitd6073e01c933c77f1e2bc3c3fe1126d617003549 (patch)
tree695d23677c5b84bf3a0f88fbd4959b4f7cbc0e90 /src/loris/lorisNonObj_pi.C
parent641688b252da468eb374674a0dbaae1bbac70b2b (diff)
downloadsimpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.gz
simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.bz2
simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.zip
Start adding Loris files
Diffstat (limited to 'src/loris/lorisNonObj_pi.C')
-rw-r--r--src/loris/lorisNonObj_pi.C1090
1 files changed, 1090 insertions, 0 deletions
diff --git a/src/loris/lorisNonObj_pi.C b/src/loris/lorisNonObj_pi.C
new file mode 100644
index 0000000..605d19c
--- /dev/null
+++ b/src/loris/lorisNonObj_pi.C
@@ -0,0 +1,1090 @@
+/*
+ * 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
+ *
+ *
+ * lorisNonObj_pi.C
+ *
+ * A component of the C-linkable procedural interface for Loris.
+ *
+ * Main components of this interface:
+ * - version identification symbols
+ * - type declarations
+ * - Analyzer configuration
+ * - LinearEnvelope (formerly BreakpointEnvelope) operations
+ * - PartialList operations
+ * - Partial operations
+ * - Breakpoint operations
+ * - sound modeling functions for preparing PartialLists
+ * - utility functions for manipulating PartialLists
+ * - notification and exception handlers (all exceptions must be caught and
+ * handled internally, clients can specify an exception handler and
+ * a notification function. The default one in Loris uses printf()).
+ *
+ * This file defines the non-object-based component of the Loris
+ * procedural interface.
+ *
+ * Kelly Fitz, 10 Nov 2000
+ * loris@cerlsoundgroup.org
+ *
+ * http://www.cerlsoundgroup.org/Loris/
+ *
+ */
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "loris.h"
+#include "lorisException_pi.h"
+
+#include "AiffFile.h"
+#include "Analyzer.h"
+#include "BreakpointEnvelope.h"
+#include "Channelizer.h"
+#include "Collator.h"
+#include "Dilator.h"
+#include "Distiller.h"
+#include "LorisExceptions.h"
+#include "FrequencyReference.h"
+#include "Fundamental.h"
+#include "Harmonifier.h"
+#include "ImportLemur.h"
+#include "Morpher.h"
+#include "Notifier.h"
+#include "Partial.h"
+#include "PartialUtils.h"
+#include "Resampler.h"
+#include "SdifFile.h"
+#include "Sieve.h"
+#include "SpcFile.h"
+#include "SpectralSurface.h"
+#include "Synthesizer.h"
+
+#include <cmath>
+#include <functional>
+#include <list>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <fstream>
+#include <set>
+
+
+using namespace Loris;
+
+/* ---------------------------------------------------------------- */
+/* non-object-based procedures
+/*
+/* Operations in Loris that need not be accessed though object
+ interfaces are represented as simple functions.
+ */
+
+/* ---------------------------------------------------------------- */
+/* channelize
+/*
+/* Label Partials in a PartialList with the integer nearest to
+ the amplitude-weighted average ratio of their frequency envelope
+ to a reference frequency envelope. The frequency spectrum is
+ partitioned into non-overlapping channels whose time-varying
+ center frequencies track the reference frequency envelope.
+ The reference label indicates which channel's center frequency
+ is exactly equal to the reference envelope frequency, and other
+ channels' center frequencies are multiples of the reference
+ envelope frequency divided by the reference label. Each Partial
+ in the PartialList is labeled with the number of the channel
+ that best fits its frequency envelope. The quality of the fit
+ is evaluated at the breakpoints in the Partial envelope and
+ weighted by the amplitude at each breakpoint, so that high-
+ amplitude breakpoints contribute more to the channel decision.
+ Partials are labeled, but otherwise unmodified. In particular,
+ their frequencies are not modified in any way.
+ */
+extern "C"
+void channelize( PartialList * partials,
+ LinearEnvelope * refFreqEnvelope, int refLabel )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+ ThrowIfNull((LinearEnvelope *) refFreqEnvelope);
+
+ if ( refLabel <= 0 )
+ {
+ Throw( InvalidArgument, "Channelization reference label must be positive." );
+ }
+ notifier << "channelizing " << partials->size() << " Partials" << endl;
+
+ Channelizer::channelize( *partials, *refFreqEnvelope, refLabel );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in channelize(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in channelize(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* collate
+/*
+/* Collate unlabeled (zero-labeled) Partials into the smallest-possible
+ number of Partials that does not combine any overlapping Partials.
+ Collated Partials assigned labels higher than any label in the original
+ list, and appear at the end of the sequence, after all previously-labeled
+ Partials.
+ */
+extern "C"
+void collate( PartialList * partials )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ notifier << "collating " << partials->size() << " Partials" << endl;
+
+ // Uses default fade time of 1 ms, and .1 ms gap,
+ // should be parameters.
+ Collator::collate( *partials, 0.001, 0.0001 );
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in collate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in collate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* createFreqReference
+/*
+/* Return a newly-constructed LinearEnvelope using the legacy
+ FrequencyReference class. The envelope will have approximately
+ the specified number of samples. The specified number of samples
+ must be greater than 1. Uses the FundamentalEstimator
+ (FundamentalFromPartials) class to construct an estimator of
+ fundamental frequency, configured to emulate the behavior of
+ the FrequencyReference class in Loris 1.4-1.5.2. If numSamps
+ is zero, construct the reference envelope from fundamental
+ estimates taken every five milliseconds.
+
+
+ For simple sounds, this frequency reference may be a
+ good first approximation to a reference envelope for
+ channelization (see channelize()).
+
+ Clients are responsible for disposing of the newly-constructed
+ LinearEnvelope.
+ */
+extern "C"
+LinearEnvelope *
+createFreqReference( PartialList * partials, double minFreq, double maxFreq,
+ long numSamps )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ // use auto_ptr to manage memory in case
+ // an exception is generated (hard to imagine):
+ std::auto_ptr< LinearEnvelope > env_ptr;
+ if ( numSamps != 0 )
+ {
+ env_ptr.reset( new LinearEnvelope(
+ FrequencyReference( partials->begin(), partials->end(),
+ minFreq, maxFreq, numSamps ).envelope() ) );
+ }
+ else
+ {
+ env_ptr.reset( new LinearEnvelope(
+ FrequencyReference( partials->begin(), partials->end(),
+ minFreq, maxFreq ).envelope() ) );
+ }
+
+ return env_ptr.release();
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in createFreqReference(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in createFreqReference(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/* createF0Estimate
+/*
+/* Return a newly-constructed LinearEnvelope that estimates
+ the time-varying fundamental frequency of the sound
+ represented by the Partials in a PartialList. This uses
+ the FundamentalEstimator (FundamentalFromPartials)
+ class to construct an estimator of fundamental frequency,
+ and returns a LinearEnvelope that samples the estimator at the
+ specified time interval (in seconds). Default values are used
+ to configure the estimator. Only estimates in the specified
+ frequency range will be considered valid, estimates outside this
+ range will be ignored.
+
+ Clients are responsible for disposing of the newly-constructed
+ LinearEnvelope.
+ */
+extern "C"
+LinearEnvelope *
+createF0Estimate( PartialList * partials, double minFreq, double maxFreq,
+ double interval )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ const double Precision = 0.1;
+ const double Confidence = 0.9;
+ FundamentalFromPartials est( Precision );
+
+ std::pair< double, double > span =
+ PartialUtils::timeSpan( partials->begin(), partials->end() );
+
+ LinearEnvelope * env_ptr =
+ new LinearEnvelope( est.buildEnvelope( partials->begin(),
+ partials->end(),
+ span.first, span.second, interval,
+ minFreq, maxFreq,
+ Confidence ) );
+ return env_ptr;
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in createF0Estimate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in createF0Estimate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/* dilate
+/*
+/* Dilate Partials in a PartialList according to the given
+ initial and target time points. Partial envelopes are
+ stretched and compressed so that temporal features at
+ the initial time points are aligned with the final time
+ points. Time points are sorted, so Partial envelopes are
+ are only stretched and compressed, but breakpoints are not
+ reordered. Duplicate time points are allowed. There must be
+ the same number of initial and target time points.
+ */
+extern "C"
+void dilate( PartialList * partials,
+ const double * initial, const double * target, int npts )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+ ThrowIfNull((double *) initial);
+ ThrowIfNull((double *) target);
+
+ notifier << "dilating " << partials->size() << " Partials" << endl;
+ Dilator::dilate( partials->begin(), partials->end(),
+ initial, initial + npts, target );
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in dilate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in dilate(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* distill
+/*
+/* Distill labeled (channelized) Partials in a PartialList into a
+ PartialList containing at most one Partial per label. Unlabeled
+ (zero-labeled) Partials are left unmodified at the end of the
+ distilled Partials.
+ */
+extern "C"
+void distill( PartialList * partials )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ notifier << "distilling " << partials->size() << " Partials" << endl;
+
+ // uses default fade time of 1 ms, should be parameter
+ Distiller::distill( *partials, 0.001 );
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in distill(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in distill(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* exportAiff
+/*
+/* Export mono audio samples stored in an array of size bufferSize to
+ an AIFF file having the specified sample rate at the given file path
+ (or name). The floating point samples in the buffer are clamped to the
+ range (-1.,1.) and converted to integers having bitsPerSamp bits.
+ */
+extern "C"
+void exportAiff( const char * path, const double * buffer,
+ unsigned int bufferSize, double samplerate, int bitsPerSamp )
+{
+ try
+ {
+ ThrowIfNull((double *) buffer);
+
+ // do nothing if there are no samples:
+ if ( bufferSize == 0 )
+ {
+ notifier << "no samples to write to " << path << endl;
+ return;
+ }
+
+ // write out samples:
+ notifier << "writing " << bufferSize << " samples to " << path << endl;
+ AiffFile fout( buffer, bufferSize, samplerate );
+ fout.write( path, bitsPerSamp );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in exportAiff(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in exportAiff(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+
+}
+
+/* ---------------------------------------------------------------- */
+/* exportSdif
+/*
+/* Export Partials in a PartialList to a SDIF file at the specified
+ file path (or name). SDIF data is written in the 1TRC format.
+ For more information about SDIF, see the SDIF web site at:
+ www.ircam.fr/equipes/analyse-synthese/sdif/
+ */
+extern "C"
+void exportSdif( const char * path, PartialList * partials )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ if ( partials->size() == 0 )
+ {
+ Throw( Loris::InvalidObject, "No Partials in PartialList to export to sdif file." );
+ }
+
+ notifier << "exporting sdif partial data to " << path << endl;
+
+ SdifFile fout( partials->begin(), partials->end() );
+ fout.write( path );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in exportSdif(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in exportSdif(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+
+}
+
+/* ---------------------------------------------------------------- */
+/* exportSpc
+/*
+/* Export Partials in a PartialList to a Spc file at the specified file
+ path (or name). The fractional MIDI pitch must be specified. The
+ enhanced parameter defaults to true (for bandwidth-enhanced spc files),
+ but an be specified false for pure-sines spc files. The endApproachTime
+ parameter is in seconds. A nonzero endApproachTime indicates that the plist does
+ not include a release, but rather ends in a static spectrum corresponding
+ to the final breakpoint values of the partials. The endApproachTime
+ specifies how long before the end of the sound the amplitude, frequency,
+ and bandwidth values are to be modified to make a gradual transition to
+ the static spectrum.
+ */
+extern "C"
+void exportSpc( const char * path, PartialList * partials, double midiPitch,
+ int enhanced, double endApproachTime )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ if ( partials->size() == 0 )
+ {
+ Throw( InvalidObject, "No Partials in PartialList to export to Spc file." );
+ }
+
+ notifier << "exporting Spc partial data to " << path << endl;
+
+ SpcFile fout( midiPitch );
+ PartialList::size_type countPartials = 0;
+ for ( PartialList::iterator iter = partials->begin(); iter != partials->end(); ++iter )
+ {
+ if ( iter->label() > 0 && iter->label() < 512 )
+ // should have a symbol defined for 512!!!
+ {
+ fout.addPartial( *iter );
+ ++countPartials;
+ }
+ }
+
+ if ( countPartials != partials->size() )
+ {
+ notifier << "exporting " << countPartials << " of "
+ << partials->size() << " Partials having labels less than 512." << endl;
+ }
+ if ( countPartials == 0 )
+ {
+ Throw( InvalidObject, "No Partials in PartialList have valid Spc labels (1-511)." );
+ }
+
+ if ( 0 == enhanced )
+ {
+ fout.writeSinusoidal( path, endApproachTime );
+ }
+ else
+ {
+ fout.write( path, endApproachTime );
+ }
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in exportSpc(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in exportSdif(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+
+}
+
+/* ---------------------------------------------------------------- */
+/* harmonify
+/*
+/* Apply a reference Partial to fix the frequencies of Breakpoints
+ whose amplitude is below threshold_dB. 0 harmonifies full-amplitude
+ Partials, to apply only to quiet Partials, specify a lower
+ threshold like -90). The reference Partial is the first Partial
+ in the PartialList labeled refLabel (usually 1). The Envelope
+ is a time-varying weighting on the harmonifing process. When 1,
+ harmonic frequencies are used, when 0, breakpoint frequencies are
+ unmodified.
+ */
+extern "C"
+void harmonify( PartialList * partials, long refLabel,
+ const LinearEnvelope * env, double threshold_dB )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+ ThrowIfNull((LinearEnvelope *) env);
+
+ if ( partials->size() == 0 )
+ {
+ Throw( InvalidObject, "No Partials in PartialList to harmonify." );
+ }
+
+ notifier << "harmonifying " << partials->size() << " Partials" << endl;
+
+ Harmonifier::harmonify( partials->begin(), partials->end(), refLabel,
+ *env, threshold_dB );
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in harmonify(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in harmonify(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+
+}
+
+/* ---------------------------------------------------------------- */
+/* importAiff
+/*
+/* Import audio samples stored in an AIFF file at the given file
+ path (or name). The samples are converted to floating point
+ values on the range (-1.,1.) and stored in an array of doubles.
+ The value returned is the number of samples in buffer, and it is at
+ most bufferSize. If samplerate is not a NULL pointer,
+ then, on return, it points to the value of the sample rate (in
+ Hz) of the AIFF samples. The AIFF file must contain only a single
+ channel of audio data. The prior contents of buffer, if any, are
+ overwritten.
+ */
+extern "C"
+unsigned int
+importAiff( const char * path, double * buffer, unsigned int bufferSize,
+ double * samplerate )
+{
+ unsigned int howMany = 0;
+ try
+ {
+ // read samples:
+ notifier << "reading samples from " << path << endl;
+ AiffFile f( path );
+ notifier << "read " << f.samples().size() << " frames at "
+ << f.sampleRate() << " Hz" << endl;
+
+ howMany = std::min( f.samples().size(),
+ std::vector< double >::size_type( bufferSize ) );
+ if ( howMany < f.samples().size() )
+ {
+ notifier << "returning " << howMany << " samples" << endl;
+ }
+
+ std::copy( f.samples().begin(), f.samples().begin() + howMany,
+ buffer );
+ std::fill( buffer + howMany, buffer + bufferSize, 0. );
+
+
+ if ( samplerate )
+ {
+ *samplerate = f.sampleRate();
+ }
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in importAiff(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in importAiff(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ return howMany;
+}
+
+/* ---------------------------------------------------------------- */
+/* importSdif
+/*
+/* Import Partials from an SDIF file at the given file path (or
+ name), and append them to a PartialList. Loris reads SDIF
+ files in the 1TRC format. For more information about SDIF,
+ see the SDIF web site at:
+ www.ircam.fr/equipes/analyse-synthese/sdif/
+ */
+extern "C"
+void importSdif( const char * path, PartialList * partials )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ notifier << "importing Partials from " << path << endl;
+ SdifFile imp( path );
+ partials->splice( partials->end(), imp.partials() );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in importSdif(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in importSdif(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* importSpc
+/*
+/* Import Partials from an Spc file at the given file path (or
+ name), and return them in a PartialList.
+ */
+extern "C"
+void importSpc( const char * path, PartialList * partials )
+{
+ try
+ {
+ Loris::notifier << "importing Partials from " << path << Loris::endl;
+ Loris::SpcFile imp( path );
+ partials->insert( partials->end(), imp.partials().begin(), imp.partials().end() );
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in importSpc(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in importSpc(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* morpher_setAmplitudeShape
+/*
+/* Set the shaping parameter for the amplitude morphing
+ function. This shaping parameter controls the
+ slope of the amplitude morphing function,
+ for values greater than 1, this function
+ gets nearly linear (like the old amplitude
+ morphing function), for values much less
+ than 1 (e.g. 1E-5) the slope is gently
+ curved and sounds pretty "linear", for
+ very small values (e.g. 1E-12) the curve
+ is very steep and sounds un-natural because
+ of the huge jump from zero amplitude to
+ very small amplitude.
+
+ Use LORIS_DEFAULT_AMPMORPHSHAPE to obtain the
+ default amplitude morphing shape for Loris,
+ (equal to 1E-5, which works well for many musical
+ instrument morphs, unless Loris was compiled
+ with the symbol LINEAR_AMP_MORPHS defined, in
+ which case LORIS_DEFAULT_AMPMORPHSHAPE is equal
+ to LORIS_LINEAR_AMPMORPHSHAPE).
+
+ Use LORIS_LINEAR_AMPMORPHSHAPE to approximate
+ the linear amplitude morphs performed by older
+ versions of Loris.
+
+ The amplitude shape must be positive.
+ */
+#if !defined(LINEAR_AMP_MORPHS) || !LINEAR_AMP_MORPHS
+ const double LORIS_DEFAULT_AMPMORPHSHAPE = 1E-5;
+#else
+ const double LORIS_DEFAULT_AMPMORPHSHAPE = 1E5;
+#endif
+
+const double LORIS_LINEAR_AMPMORPHSHAPE = 1E5;
+
+static double PI_ampMorphShape = LORIS_DEFAULT_AMPMORPHSHAPE;
+extern "C"
+void morpher_setAmplitudeShape( double x )
+{
+ if ( x <= 0. )
+ {
+ std::string s("Loris exception in morpher_setAmplitudeShape(): " );
+ s.append( "Invalid Argument: the amplitude morph shaping parameter must be positive" );
+ handleException( s.c_str() );
+ }
+ PI_ampMorphShape = x;
+}
+
+/* ---------------------------------------------------------------- */
+/* morph
+/*
+/* Morph labeled Partials in two PartialLists according to the
+ given frequency, amplitude, and bandwidth (noisiness) morphing
+ envelopes, and append the morphed Partials to the destination
+ PartialList. Loris morphs Partials by interpolating frequency,
+ amplitude, and bandwidth envelopes of corresponding Partials in
+ the source PartialLists. For more information about the Loris
+ morphing algorithm, see the Loris website:
+ www.cerlsoundgroup.org/Loris/
+ */
+extern "C"
+void morph( const PartialList * src0, const PartialList * src1,
+ const LinearEnvelope * ffreq,
+ const LinearEnvelope * famp,
+ const LinearEnvelope * fbw,
+ PartialList * dst )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) src0);
+ ThrowIfNull((PartialList *) src1);
+ ThrowIfNull((PartialList *) dst);
+ ThrowIfNull((LinearEnvelope *) ffreq);
+ ThrowIfNull((LinearEnvelope *) famp);
+ ThrowIfNull((LinearEnvelope *) fbw);
+
+ notifier << "morphing " << src0->size() << " Partials with " <<
+ src1->size() << " Partials" << endl;
+
+ // make a Morpher object and do it:
+ Morpher m( *ffreq, *famp, *fbw );
+ m.morph( src0->begin(), src0->end(), src1->begin(), src1->end() );
+
+ // splice the morphed Partials into dst:
+ dst->splice( dst->end(), m.partials() );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in morph(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in morph(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* morphWithReference
+/*
+/* Morph labeled Partials in two PartialLists according to the
+ given frequency, amplitude, and bandwidth (noisiness) morphing
+ envelopes, and append the morphed Partials to the destination
+ PartialList. Specify the labels of the Partials to be used as
+ reference Partial for the two morph sources. The reference
+ partial is used to compute frequencies for very low-amplitude
+ Partials whose frequency estimates are not considered reliable.
+ The reference Partial is considered to have good frequency
+ estimates throughout. A reference label of 0 indicates that
+ no reference Partial should be used for the corresponding
+ morph source.
+
+ Loris morphs Partials by interpolating frequency,
+ amplitude, and bandwidth envelopes of corresponding Partials in
+ the source PartialLists. For more information about the Loris
+ morphing algorithm, see the Loris website:
+ www.cerlsoundgroup.org/Loris/
+ */
+extern "C"
+void morphWithReference( const PartialList * src0,
+ const PartialList * src1,
+ long src0RefLabel,
+ long src1RefLabel,
+ const LinearEnvelope * ffreq,
+ const LinearEnvelope * famp,
+ const LinearEnvelope * fbw,
+ PartialList * dst )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) src0);
+ ThrowIfNull((PartialList *) src1);
+ ThrowIfNull((PartialList *) dst);
+ ThrowIfNull((LinearEnvelope *) ffreq);
+ ThrowIfNull((LinearEnvelope *) famp);
+ ThrowIfNull((LinearEnvelope *) fbw);
+
+ notifier << "morphing " << src0->size() << " Partials with "
+ << src1->size() << " Partials" << endl;
+
+ // make a Morpher object and do it:
+ Morpher m( *ffreq, *famp, *fbw );
+
+ if ( src0RefLabel != 0 )
+ {
+ notifier << "using Partial labeled " << src0RefLabel;
+ notifier << " as reference Partial for first morph source" << endl;
+ m.setSourceReferencePartial( *src0, src0RefLabel );
+ }
+ else
+ {
+ notifier << "using no reference Partial for first morph source" << endl;
+ }
+
+ if ( src1RefLabel != 0 )
+ {
+ notifier << "using Partial labeled " << src1RefLabel;
+ notifier << " as reference Partial for second morph source" << endl;
+ m.setTargetReferencePartial( *src1, src1RefLabel );
+ }
+ else
+ {
+ notifier << "using no reference Partial for second morph source" << endl;
+ }
+
+ m.morph( src0->begin(), src0->end(), src1->begin(), src1->end() );
+
+ // splice the morphed Partials into dst:
+ dst->splice( dst->end(), m.partials() );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in morphWithReference(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in morphWithReference(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+
+/* ---------------------------------------------------------------- */
+/* resample
+/*
+/* Resample all Partials in a PartialList using the specified
+ sampling interval, so that the Breakpoints in the Partial
+ envelopes will all lie on a common temporal grid.
+ The Breakpoint times in resampled Partials 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.
+
+ */
+extern "C"
+void resample( PartialList * partials, double interval )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ notifier << "resampling " << partials->size() << " Partials" << Loris::endl;
+
+ Resampler::resample( partials->begin(), partials->end(), interval );
+
+ // remove any resulting empty Partials
+ PartialList::iterator it = partials->begin();
+ while ( it != partials->end() )
+ {
+ if ( 0 == it->numBreakpoints() )
+ {
+ it = partials->erase( it );
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s( "Loris exception in resample(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s( "std C++ exception in resample(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* shapeSpectrum
+/* Scale the amplitudes of a set of Partials by applying
+ a spectral suface constructed from another set.
+ Strecth the spectral surface in time and frequency
+ using the specified stretch factors.
+ */
+extern "C"
+void shapeSpectrum( PartialList * partials, PartialList * surface,
+ double stretchFreq, double stretchTime )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+ ThrowIfNull((PartialList *) surface);
+
+ notifier << "shaping " << partials->size() << " Partials using "
+ << "spectral surface created from " << surface->size()
+ << " Partials" << Loris::endl;
+
+ // uses default fade time of 1 ms, should be parameter
+ SpectralSurface surf( surface->begin(), surface->end() );
+ surf.setFrequencyStretch( stretchFreq );
+ surf.setTimeStretch( stretchTime );
+ surf.setEffect( 1.0 ); // should this be a parameter?
+ surf.scaleAmplitudes( partials->begin(), partials->end() );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in shapeSpectrum(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in shapeSpectrum(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+/* ---------------------------------------------------------------- */
+/* sift
+/* Eliminate overlapping Partials having the same label
+ (except zero). If any two partials with same label
+ overlap in time, keep only the longer of the two.
+ Set the label of the shorter duration partial to zero.
+
+ */
+extern "C"
+void sift( PartialList * partials )
+{
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+
+ notifier << "sifting " << partials->size() << " Partials" << Loris::endl;
+
+ // uses default fade time of 1 ms, should be parameter
+ Sieve::sift( partials->begin(), partials->end(), 0.001 );
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in sift(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in sift(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* synthesize
+/*
+/* Synthesize Partials in a PartialList at the given sample
+ rate, and store the (floating point) samples in a buffer of
+ size bufferSize. The buffer is neither resized nor
+ cleared before synthesis, so newly synthesized samples are
+ added to any previously computed samples in the buffer, and
+ samples beyond the end of the buffer are lost. Return the
+ number of samples synthesized, that is, the index of the
+ latest sample in the buffer that was modified.
+ */
+extern "C"
+unsigned int synthesize( const PartialList * partials,
+ double * buffer, unsigned int bufferSize,
+ double srate )
+{
+ unsigned int howMany = 0;
+ try
+ {
+ ThrowIfNull((PartialList *) partials);
+ ThrowIfNull((double *) buffer);
+
+ notifier << "synthesizing " << partials->size()
+ << " Partials at " << srate << " Hz" << endl;
+
+ // synthesize:
+ std::vector< double > vec;
+ Synthesizer synth( srate, vec );
+ synth.synthesize( partials->begin(), partials->end() );
+
+ // determine the number of synthesized samples
+ // that will be stored:
+ howMany = vec.size();
+ if ( howMany > bufferSize )
+ {
+ howMany = bufferSize;
+ }
+
+ // accumulate into the buffer:
+ std::transform( buffer, buffer + howMany, vec.begin(),
+ buffer, std::plus< double >() );
+
+
+ }
+ catch( Exception & ex )
+ {
+ std::string s("Loris exception in synthesize(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ catch( std::exception & ex )
+ {
+ std::string s("std C++ exception in synthesize(): " );
+ s.append( ex.what() );
+ handleException( s.c_str() );
+ }
+ return howMany;
+}
+
+
+
+