/* * 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 * * * lorisAnalyzer_pi.C * * A component of the C-linkable procedural interface for Loris. * * Main components of the Loris procedural interface: * - object interfaces - Analyzer, Synthesizer, Partial, PartialIterator, * PartialList, PartialListIterator, Breakpoint, BreakpointEnvelope, * and SampleVector need to be (opaque) objects in the interface, * either because they hold state (e.g. Analyzer) or because they are * fundamental data types (e.g. Partial), so they need a procedural * interface to their member functions. All these things need to be * opaque pointers for the benefit of C. * - non-object-based procedures - other classes in Loris are not so stateful, * and have sufficiently narrow functionality that they need only * procedures, and no object representation. * - utility functions - some procedures that are generally useful but are * not yet part of the Loris core are also defined. * - 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 contains the procedural interface for the Loris Analyzer class. * * 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 "Analyzer.h" #include "Notifier.h" using namespace Loris; /* ---------------------------------------------------------------- */ /* Analyzer object interface /* /* An Analyzer represents a configuration of parameters for performing Reassigned Bandwidth-Enhanced Additive Analysis of sampled waveforms. This analysis process yields a collection of Partials, each having a trio of synchronous, non-uniformly- sampled breakpoint envelopes representing the time-varying frequency, amplitude, and noisiness of a single bandwidth- enhanced sinusoid. For more information about Reassigned Bandwidth-Enhanced Analysis and the Reassigned Bandwidth-Enhanced Additive Sound Model, refer to the Loris website: www.cerlsoundgroup.org/Loris/. In the procedural interface, there is only one Analyzer. It must be configured by calling analyzer_configure before any of the other analyzer operations can be performed. */ static Analyzer * ptr_instance = 0; /* ---------------------------------------------------------------- */ /* analyzer_configure /* /* Configure the sole Analyzer instance with the specified frequency resolution (minimum instantaneous frequency difference between Partials). All other Analyzer parameters are computed from the specified frequency resolution. Construct the Analyzer instance if necessary. In the procedural interface, there is only one Analyzer. It must be configured by calling analyzer_configure before any of the other analyzer operations can be performed. */ extern "C" void analyzer_configure( double resolution, double windowWidth ) { try { if ( 0 == ptr_instance ) { debugger << "creating Analyzer" << endl; ptr_instance = new Analyzer( resolution, windowWidth ); } else { debugger << "configuring Analyzer" << endl; ptr_instance->configure( resolution, windowWidth ); } } catch( Exception & ex ) { std::string s("Loris exception in createAnalyzer(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in createAnalyzer(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyze /* /* Analyze an array of bufferSize (mono) samples at the given sample rate (in Hz) and append the extracted Partials to the given PartialList. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyze( const double * buffer, unsigned int bufferSize, double srate, PartialList * partials ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ThrowIfNull((double *) buffer); ThrowIfNull((PartialList *) partials); // perform analysis: notifier << "analyzing " << bufferSize << " samples at " << srate << " Hz with frequency resolution " << ptr_instance->freqResolution() << endl; if ( bufferSize > 0 ) { ptr_instance->analyze( buffer, buffer + bufferSize, srate ); // splice the Partials into the destination list: partials->splice( partials->end(), ptr_instance->partials() ); } } catch( Exception & ex ) { std::string s("Loris exception in analyze(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyze(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getFreqResolution /* /* Return the frequency resolution (minimum instantaneous frequency difference between Partials) for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getFreqResolution( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->freqResolution(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getFreqResolution(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getFreqResolution(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setFreqResolution /* /* Set the frequency resolution (minimum instantaneous frequency difference between Partials) for this Analyzer. (Does not cause other parameters to be recomputed.) analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setFreqResolution( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setFreqResolution( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setFreqResolution(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setFreqResolution(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getAmpFloor /* /* Return the amplitude floor (lowest detected spectral amplitude), in (negative) dB, for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getAmpFloor( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->ampFloor(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getAmpFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getAmpFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setAmpFloor /* /* Set the amplitude floor (lowest detected spectral amplitude), in (negative) dB, for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setAmpFloor( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setAmpFloor( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setAmpFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setAmpFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getWindowWidth /* /* Return the frequency-domain main lobe width (measured between zero-crossings) of the analysis window used by this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getWindowWidth( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->windowWidth(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getWindowWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getWindowWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setWindowWidth /* /* Set the frequency-domain main lobe width (measured between zero-crossings) of the analysis window used by this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setWindowWidth( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setWindowWidth( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setWindowWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setWindowWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getSidelobeLevel /* /* Return the sidelobe attenutation level for the Kaiser analysis window in negative dB. More negative numbers (e.g. -90) give very good sidelobe rejection but cause the window to be longer in time. Less negative numbers raise the level of the sidelobes, increasing the liklihood of frequency-domain interference, but allow the window to be shorter in time. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getSidelobeLevel( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->sidelobeLevel(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getSidelobeLevel(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getSidelobeLevel(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setSidelobeLevel /* /* Set the sidelobe attenutation level for the Kaiser analysis window in negative dB. More negative numbers (e.g. -90) give very good sidelobe rejection but cause the window to be longer in time. Less negative numbers raise the level of the sidelobes, increasing the liklihood of frequency-domain interference, but allow the window to be shorter in time. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setSidelobeLevel( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setSidelobeLevel( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setSidelobeLevel(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setSidelobeLevel(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getFreqFloor /* /* Return the frequency floor (minimum instantaneous Partial frequency), in Hz, for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getFreqFloor( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->freqFloor(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getFreqFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getFreqFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setFreqFloor /* /* Set the amplitude floor (minimum instantaneous Partial frequency), in Hz, for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setFreqFloor( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setFreqFloor( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setFreqFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setFreqFloor(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getFreqDrift /* /* Return the maximum allowable frequency difference between consecutive Breakpoints in a Partial envelope for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getFreqDrift( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->freqDrift(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getFreqDrift(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getFreqDrift(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setFreqDrift /* /* Set the maximum allowable frequency difference between consecutive Breakpoints in a Partial envelope for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setFreqDrift( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setFreqDrift( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setFreqDrift(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setFreqDrift(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getHopTime /* /* Return the hop time (which corresponds approximately to the average density of Partial envelope Breakpoint data) for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getHopTime( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->hopTime(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getHopTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getHopTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setHopTime /* /* Set the hop time (which corresponds approximately to the average density of Partial envelope Breakpoint data) for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setHopTime( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setHopTime( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setHopTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setHopTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getCropTime /* /* Return the crop time (maximum temporal displacement of a time- frequency data point from the time-domain center of the analysis window, beyond which data points are considered "unreliable") for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getCropTime( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->cropTime(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getCropTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getCropTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setCropTime /* /* Set the crop time (maximum temporal displacement of a time- frequency data point from the time-domain center of the analysis window, beyond which data points are considered "unreliable") for this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setCropTime( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setCropTime( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setCropTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setCropTime(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getBwRegionWidth /* /* Return the width (in Hz) of the Bandwidth Association regions used by this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" double analyzer_getBwRegionWidth( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->bwRegionWidth(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getBwRegionWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getBwRegionWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; } /* ---------------------------------------------------------------- */ /* analyzer_setBwRegionWidth /* /* Set the width (in Hz) of the Bandwidth Association regions used by this Analyzer. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_setBwRegionWidth( double x ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->setBwRegionWidth( x ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_setBwRegionWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_setBwRegionWidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_storeResidueBandwidth /* /* Construct Partial bandwidth envelopes during analysis by associating residual energy in the spectrum (after peak extraction) with the selected spectral peaks that are used to construct Partials. regionWidth is the width (in Hz) of the bandwidth association regions used by this process, must be positive. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_storeResidueBandwidth( double regionWidth ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->storeResidueBandwidth( regionWidth ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_storeResidueBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_storeResidueBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_storeConvergenceBandwidth /* /* Construct Partial bandwidth envelopes during analysis by storing the mixed derivative of short-time phase, scaled and shifted so that a value of 0 corresponds to a pure sinusoid, and a value of 1 corresponds to a bandwidth-enhanced sinusoid with maximal energy spread (minimum sinusoidal convergence). tolerance is the amount of range over which the mixed derivative indicator should be allowed to drift away from a pure sinusoid before saturating. This range is mapped to bandwidth values on the range [0,1]. Must be positive and not greater than 1. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_storeConvergenceBandwidth( double tolerance ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->storeConvergenceBandwidth( tolerance ); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_storeConvergenceBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_storeConvergenceBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_storeNoBandwidth /* /* Disable bandwidth envelope construction. Bandwidth will be zero for all Breakpoints in all Partials. analyzer_configure must be called before any other analyzer function. */ extern "C" void analyzer_storeNoBandwidth( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return; } try { ptr_instance->storeNoBandwidth(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_storeNoBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_storeNoBandwidth(): " ); s.append( ex.what() ); handleException( s.c_str() ); } } /* ---------------------------------------------------------------- */ /* analyzer_getBwConvergenceTolerance /* /* Return the mixed derivative convergence tolerance only if the convergence indicator is used to compute bandwidth envelopes. Return zero if the spectral residue method is used or if no bandwidth is computed. */ extern "C" double analyzer_getBwConvergenceTolerance( void ) { if ( 0 == ptr_instance ) { handleException( "analyzer_configure must be called before any other analyzer function." ); return 0; } try { return ptr_instance->bwConvergenceTolerance(); } catch( Exception & ex ) { std::string s("Loris exception in analyzer_getBwConvergenceTolerance(): " ); s.append( ex.what() ); handleException( s.c_str() ); } catch( std::exception & ex ) { std::string s("std C++ exception in analyzer_getBwConvergenceTolerance(): " ); s.append( ex.what() ); handleException( s.c_str() ); } return 0; }