diff options
Diffstat (limited to 'src/loris/Collator.C')
-rw-r--r-- | src/loris/Collator.C | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/loris/Collator.C b/src/loris/Collator.C new file mode 100644 index 0000000..1cbddbf --- /dev/null +++ b/src/loris/Collator.C @@ -0,0 +1,190 @@ +/* + * 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 + * + * + * Collator.h + * + * Definition of class Collator. + * + * Kelly Fitz, 29 April 2005 + * loris@cerlsoundgroup.org + * + * http://www.cerlsoundgroup.org/Loris/ + * + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include "Collator.h" +#include "Breakpoint.h" +#include "BreakpointUtils.h" +#include "LorisExceptions.h" +#include "Partial.h" +#include "PartialList.h" +#include "PartialUtils.h" +#include "Notifier.h" + +#include <algorithm> +#include <functional> +#include <utility> + +// begin namespace +namespace Loris { + + +// --------------------------------------------------------------------------- +// Collator constructor +// --------------------------------------------------------------------------- +//! Construct a new Collator using the specified fade and gap times +//! between Partials. When two Partials are joined, the collated Partial +//! fades out at the end of the earlier Partial and back in again +//! at the onset of the later one. The fade time is the time over +//! which these fades occur. By default, use a 5 ms fade time. +//! The gap time is the additional time over which a Partial faded +//! out must remain at zero amplitude before it can fade back in. +//! By default, use a gap time of one millisecond, to +//! prevent a pair of arbitrarily close null Breakpoints being +//! inserted. (Defaults are copied from the Distiller.) +//! +//! \param partialFadeTime is the time (in seconds) over +//! which Partials joined by distillation fade to +//! and from zero amplitude. Default is 0.005 (one +//! millisecond). +//! \param partialSilentTime is the minimum duration (in seconds) +//! of the silent (zero-amplitude) gap between two +//! Partials joined by distillation. (Default is +//! 0.001 (one millisecond). +Collator::Collator( double partialFadeTime, double partialSilentTime ) : + _fadeTime( partialFadeTime ), + _gapTime( partialSilentTime ) +{ + if ( _fadeTime <= 0.0 ) + { + Throw( InvalidArgument, "Collator fade time must be positive." ); + } + if ( _gapTime <= 0.0 ) + { + Throw( InvalidArgument, "Collator gap time must be positive." ); + } +} + +// -- helpers -- + +// --------------------------------------------------------------------------- +// helper predicates +// --------------------------------------------------------------------------- +static bool ends_earlier( const Partial & lhs, const Partial & rhs ) +{ + return lhs.endTime() < rhs.endTime(); +} + +struct ends_before : public std::unary_function< const Partial, bool > +{ + double t; + ends_before( double time ) : t( time ) {} + + bool operator() ( const Partial & p ) const + { return p.endTime() < t; } +}; + +// --------------------------------------------------------------------------- +// collateAux +// --------------------------------------------------------------------------- +//! Collate unlabeled (zero labeled) Partials into the smallest +//! possible number of Partials that does not combine any temporally +//! overlapping Partials. The unlabeled Partials are +//! collated in-place. +// +void Collator::collateAux( PartialList & unlabeled ) +{ + debugger << "Collator found " << unlabeled.size() + << " unlabeled Partials, collating..." << endl; + + // sort Partials by end time: + // thanks to Ulrike Axen for this optimal algorithm! + unlabeled.sort( ends_earlier ); + + // invariant: + // Partials in the range [partials.begin(), endcollated) + // are the collated Partials. + PartialList::iterator endcollated = unlabeled.begin(); + while ( endcollated != unlabeled.end() ) + { + // find a collated Partial that ends + // before this one begins. + // There must be a gap of at least + // twice the _fadeTime, because this algorithm + // does not remove any null Breakpoints, and + // because Partials joined in this way might + // be far apart in frequency. + const double clearance = (2.*_fadeTime) + _gapTime; + PartialList::iterator it = + std::find_if( unlabeled.begin(), endcollated, + ends_before( endcollated->startTime() - clearance) ); + + // if no such Partial exists, then this Partial + // becomes one of the collated ones, otherwise, + // insert two null Breakpoints, and then all + // the Breakpoints in this Partial: + if ( it != endcollated ) + { + Partial & addme = *endcollated; + Partial & collated = *it; + Assert( &addme != &collated ); + + // insert a null at the (current) end + // of collated: + double nulltime1 = collated.endTime() + _fadeTime; + Breakpoint null1( collated.frequencyAt(nulltime1), 0., + collated.bandwidthAt(nulltime1), collated.phaseAt(nulltime1) ); + collated.insert( nulltime1, null1 ); + + // insert a null at the beginning of + // of the current Partial: + double nulltime2 = addme.startTime() - _fadeTime; + Assert( nulltime2 >= nulltime1 ); + Breakpoint null2( addme.frequencyAt(nulltime2), 0., + addme.bandwidthAt(nulltime2), addme.phaseAt(nulltime2) ); + collated.insert( nulltime2, null2 ); + + // insert all the Breakpoints in addme + // into collated: + Partial::iterator addme_it; + for ( addme_it = addme.begin(); addme_it != addme.end(); ++addme_it ) + { + collated.insert( addme_it.time(), addme_it.breakpoint() ); + } + + // remove this Partial from the list: + endcollated = unlabeled.erase( endcollated ); + } + else + { + ++endcollated; + } + } + + debugger << "...now have " << unlabeled.size() << endl; +} + +} // end of namespace Loris |