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