summaryrefslogtreecommitdiff
path: root/src/loris/Sieve.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/Sieve.C
parent641688b252da468eb374674a0dbaae1bbac70b2b (diff)
downloadsimpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.gz
simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.bz2
simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.zip
Start adding Loris files
Diffstat (limited to 'src/loris/Sieve.C')
-rw-r--r--src/loris/Sieve.C235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/loris/Sieve.C b/src/loris/Sieve.C
new file mode 100644
index 0000000..dc25992
--- /dev/null
+++ b/src/loris/Sieve.C
@@ -0,0 +1,235 @@
+/*
+ * 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
+ *
+ *
+ * Sieve.C
+ *
+ * Implementation of class Sieve.
+ *
+ * Lippold Haken, 20 Jan 2001
+ * loris@cerlsoundgroup.org
+ *
+ * http://www.cerlsoundgroup.org/Loris/
+ *
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "Sieve.h"
+#include "Breakpoint.h"
+#include "LorisExceptions.h"
+#include "Notifier.h"
+#include "Partial.h"
+#include "PartialList.h"
+#include "PartialUtils.h"
+
+#include <algorithm>
+
+// begin namespace
+namespace Loris {
+
+
+// ---------------------------------------------------------------------------
+// Sieve constructor
+// ---------------------------------------------------------------------------
+//! Construct a new Sieve using the specified partial fade
+//! time. If unspecified, the default fade time (same as the
+//! default fade time for the Distiller) is used.
+//!
+//! \param partialFadeTime is the extra time (in seconds)
+//! added to each end of a Partial to accomodate
+//! the fade to and from zero amplitude. Fade time
+//! must be non-negative. A default value is used
+//! if unspecified.
+//! \throw InvalidArgument if partialFadeTime is negative.
+//
+Sieve::Sieve( double partialFadeTime ) :
+ _fadeTime( partialFadeTime )
+{
+ if ( _fadeTime < 0.0 )
+ {
+ Throw( InvalidArgument, "the Partial fade time must be non-negative" );
+ }
+}
+
+// Definition of a comparitor for sorting a collection of pointers
+// to Partials by label (increasing) and duration (decreasing), so
+// that Partial ptrs are arranged by label, with the lowest labels
+// first, and then with the longest Partials having each label
+// before the shorter ones.
+struct SortPartialPtrs :
+ public std::binary_function< const Partial *, const Partial *, bool >
+{
+ bool operator()( const Partial * lhs, const Partial * rhs ) const
+ {
+ return ( lhs->label() != rhs->label() ) ?
+ ( lhs->label() < rhs->label() ) :
+ ( lhs->duration() > rhs->duration() );
+ }
+};
+
+// Definition of predicate for finding the end of a Patial *
+// range having a common label.
+struct PartialPtrLabelNE :
+ public std::unary_function< const Partial *, bool >
+{
+ int label;
+ PartialPtrLabelNE( int l ) : label(l) {}
+
+ bool operator()( const Partial * p ) const
+ { return p->label() != label; }
+};
+
+
+// ---------------------------------------------------------------------------
+// find_overlapping (template function)
+// ---------------------------------------------------------------------------
+// Iterate over a range of Partials (presumably) with same labeling.
+// The range is specified by iterators over a collection of pointers
+// to Partials (not Partials themselves). Return the first position
+// in the specified range corresponding to a Partial that overlaps
+// (in time) the specified Partial, p, or the end of the range if
+// no Partials in the range overlap.
+//
+// Overlap is defined by the minimum time gap between Partials
+// (minGapTime), so Partials that have less then minGapTime
+// between them are considered overlapping.
+//
+template <typename Iter> // Iter is the position of a Partial *
+Iter
+find_overlapping( Partial & p, double minGapTime, Iter start, Iter end)
+{
+ for ( Iter it = start; it != end; ++it )
+ {
+ // skip if other partial is already sifted out.
+ if ( (*it)->label() == 0 )
+ continue;
+
+ // skip the source Partial:
+ // (identity test: compare addresses)
+ // (this is a sanity check, should not happen since
+ // src should be at position end)
+ Assert( (*it) != &p );
+
+ // test for overlap:
+ if ( p.startTime() < (*it)->endTime() + minGapTime &&
+ p.endTime() + minGapTime > (*it)->startTime() )
+ {
+ // Does the overlapping Partial have longer duration?
+ // (this should never be true, since the Partials
+ // are sorted by duration)
+ Assert( p.duration() <= (*it)->duration() );
+
+#if Debug_Loris
+ debugger << "Partial starting " << p.startTime() << ", "
+ << p.begin().breakpoint().frequency() << " ending "
+ << p.endTime() << ", " << (--p.end()).breakpoint().frequency()
+ << " zapped by overlapping Partial starting "
+ << (*it)->startTime() << ", " << (*it)->begin().breakpoint().frequency()
+ << " ending " << (*it)->endTime() << ", "
+ << (--(*it)->end()).breakpoint().frequency() << endl;
+#endif
+ return it;
+ }
+ }
+
+ // no overlapping Partial found:
+ return end;
+}
+
+// ---------------------------------------------------------------------------
+// sift_ptrs (private helper)
+// ---------------------------------------------------------------------------
+//! Sift labeled Partials. If any two Partials having the same (non-zero)
+//! label overlap in time (where overlap includes the fade time at both
+//! ends of each Partial), then set the label of the Partial having the
+//! shorter duration to zero. Sifting is performed on a collection of
+//! pointers to Partials so that the it can be performed without changing
+//! the order of the Partials in the sequence.
+//!
+//! \param ptrs is a collection of pointers to the Partials in the
+//! sequence to be sifted.
+void
+Sieve::sift_ptrs( PartialPtrs & ptrs )
+{
+ // the minimum gap between Partials is twice the
+ // specified fadeTime:
+ double minGapTime = _fadeTime * 2.;
+
+ // sort the collection of pointers to Partials:
+ // (sort is by increasing label, then
+ // decreasing duration)
+ std::sort( ptrs.begin(), ptrs.end(), SortPartialPtrs() );
+
+ PartialPtrs::iterator sift_begin = ptrs.begin();
+ PartialPtrs::iterator sift_end = ptrs.end();
+
+ int zapped = 0;
+
+ // iterate over labels and sift each one:
+ PartialPtrs::iterator lowerbound = sift_begin;
+ while ( lowerbound != sift_end )
+ {
+ int label = (*lowerbound)->label();
+
+ // first the first element in l after sieve_begin
+ // having a label not equal to 'label':
+ PartialPtrs::iterator upperbound =
+ std::find_if( lowerbound, sift_end, PartialPtrLabelNE(label) );
+
+#ifdef Debug_Loris
+ // don't want to compute this iterator distance unless debugging:
+ debugger << "sifting Partials labeled " << label << endl;
+ debugger << "Sieve found " << std::distance( lowerbound, upperbound ) <<
+ " Partials labeled " << label << endl;
+#endif
+ // sift all partials with this label, unless the
+ // label is 0:
+ if ( label != 0 )
+ {
+ PartialPtrs::iterator it;
+ for ( it = lowerbound; it != upperbound; ++it )
+ {
+ // find_overlapping only needs to consider Partials on the
+ // half-open range [lowerbound, it), because all
+ // Partials after it are shorter, thanks to the
+ // sorting of the sift_set:
+ if( it != find_overlapping( **it, minGapTime, lowerbound, it ) )
+ {
+ (*it)->setLabel(0);
+ ++zapped;
+ }
+ }
+ }
+
+ // advance Partial set iterator:
+ lowerbound = upperbound;
+ }
+
+#ifdef Debug_Loris
+ debugger << "Sifted out (relabeled) " << zapped << " of " << ptrs.size() << "." << endl;
+#endif
+}
+
+} // end of namespace Loris
+