// --------------------------------------------------------------------------- // construction // --------------------------------------------------------------------------- //! Construct a new fundamental FrequencyReference derived from the //! specified half-open (STL-style) range of Partials that lies //! within the speficied average frequency range. Construct the //! reference envelope with approximately numSamps points. //! //! \param begin The beginning of a range of Partials from which to //! construct a frequency refence envelope. //! \param end The end of a range of Partials from which to //! construct a frequency refence envelope. //! \param minFreq The minimum expected fundamental frequency. //! \param maxFreq The maximum expected fundamental frequency. //! \param numSamps The approximate number of estimate of the //! fundamental frequency from which to construct the //! frequency reference envelope. // FrequencyReference::FrequencyReference( PartialList::const_iterator begin, PartialList::const_iterator end, double minFreq, double maxFreq, long numSamps ) : _env( new LinearEnvelope() ) { if ( numSamps < 1 ) { Throw( InvalidArgument, "A frequency reference envelope must have a positive number of samples." ); } // sanity: if ( maxFreq < minFreq ) { std::swap( minFreq, maxFreq ); } #ifdef Loris_Debug debugger << "Finding frequency reference envelope in range " << debugger << minFreq << " to " << maxFreq << " Hz, from " << debugger << std::distance(begin,end) << " Partials" << std::endl; #endif FundamentalFromPartials est = createEstimator(); std::pair< double, double > span = PartialUtils::timeSpan( begin, end ); double dt = ( span.second - span.first ) / ( numSamps + 1 ); *_env = est.buildEnvelope( begin, end, span.first, span.second, dt, minFreq, maxFreq, Confidence ); }
// --------------------------------------------------------------------------- // construction // --------------------------------------------------------------------------- //! Construct a new fundamental FrequencyReference derived from the //! specified half-open (STL-style) range of Partials that lies //! within the speficied average frequency range. Construct the //! reference envelope from fundamental estimates taken every //! five milliseconds. //! //! \param begin The beginning of a range of Partials from which to //! construct a frequency refence envelope. //! \param end The end of a range of Partials from which to //! construct a frequency refence envelope. //! \param minFreq The minimum expected fundamental frequency. //! \param maxFreq The maximum expected fundamental frequency. // FrequencyReference::FrequencyReference( PartialList::const_iterator begin, PartialList::const_iterator end, double minFreq, double maxFreq ) : _env( new LinearEnvelope() ) { // sanity: if ( maxFreq < minFreq ) { std::swap( minFreq, maxFreq ); } #ifdef Loris_Debug debugger << "Finding frequency reference envelope in range " << debugger << minFreq << " to " << maxFreq << " Hz, from " << debugger << std::distance(begin,end) << " Partials" << std::endl; #endif FundamentalFromPartials est = createEstimator(); std::pair< double, double > span = PartialUtils::timeSpan( begin, end ); *_env = est.buildEnvelope( begin, end, span.first, span.second, Interval, minFreq, maxFreq, Confidence ); }
int main( int argc, char * argv[] ) { std::cout << "Unit test for fundamental estimation functions." << endl; std::cout << "Tests FundamentalFromPartials and FundamentalFromSamples." << endl << endl; std::cout << "Relies on AiffFile, Analyzer, Partial, PartialList, and LinearEnvelope." << endl << endl; std::cout << "Built: " << __DATE__ << endl << endl; string path(""); if ( std::getenv("srcdir") ) { path = std::getenv("srcdir"); path = path + "/"; } // --- parameters that are sample-specific --- string fname = path + "clarinet.aiff"; double fmin = 200; double fmax = 500; double res = 415*.8; double win = 415*1.6; double interval = 0.05; // 50 ms const double approx = 414; double x; try { // import (mono) samples std::vector< double > buf; double rate; importSamples( fname, buf, &rate ); // step 1. analyze the samples Analyzer anal( res, win ); anal.buildFundamentalEnv( fmin, fmax ); anal.setHopTime( interval ); cout << "--- step 1 analyzer ---" << endl; cout << "analysis resolution is " << anal.freqResolution() << endl; cout << "window width is " << anal.windowWidth() << endl; cout << "amplitude threshold is " << anal.ampFloor() << endl; cout << "lower bound is " << fmin << endl; cout << "upper bound is " << fmax << endl; PartialList plist = anal.analyze( buf, rate ); LinearEnvelope est1 = anal.fundamentalEnv(); x = dumpEnvelope( est1 ); if ( (approx-1) > x || (approx+1) < x ) { throw std::runtime_error( "that isn't right" ); } double tbeg = est1.begin()->first; double tend = (--est1.end())->first; // step 2. estimate fundamental from Partials FundamentalFromPartials eparts; eparts.setAmpFloor( -65 ); eparts.setAmpRange( 40 ); eparts.setFreqCeiling( 5000 ); cout << "--- step 2 fundamental estimator from partials ---" << endl; cout << "amplitude threshold is " << eparts.ampFloor() << endl; cout << "amplitude range is " << eparts.ampRange() << endl; cout << "frequency ceiling is " << eparts.freqCeiling() << endl; cout << "precision level is " << eparts.precision() << " Hz" << endl; LinearEnvelope est2 = eparts.buildEnvelope( plist, tbeg, tend, interval, fmin, fmax, 0.95 ); x = dumpEnvelope( est2 ); if ( (approx-1) > x || (approx+1) < x ) { throw std::runtime_error( "that isn't right" ); } // step 3. estimate fundamental from the samples FundamentalFromSamples esamps( win ); esamps.setAmpFloor( -65 ); esamps.setAmpRange( 40 ); esamps.setFreqCeiling( 5000 ); cout << "--- step 3 fundamental estimator from samples ---" << endl; cout << "window width is " << esamps.windowWidth() << endl; cout << "amplitude threshold is " << esamps.ampFloor() << endl; cout << "amplitude range is " << esamps.ampRange() << endl; cout << "frequency ceiling is " << esamps.freqCeiling() << endl; cout << "precision level is " << esamps.precision() << " Hz" << endl; LinearEnvelope est3 = esamps.buildEnvelope( buf, rate, tbeg, tend, interval, fmin, fmax, 0.95 ); x = dumpEnvelope( est3 ); if ( (approx-1) > x || (approx+1) < x ) { throw std::runtime_error( "that isn't right" ); } } catch( Exception & ex ) { cout << "Caught Loris exception: " << ex.what() << endl; return 1; } catch( std::exception & ex ) { cout << "Caught std C++ exception: " << ex.what() << endl; return 1; } // return successfully cout << "Fundamental estimation passed all tests." << endl; return 0; return 0; }