// --------------------------------------------------------------------------- // Cropper function call operator // --------------------------------------------------------------------------- // Trim a Partial by removing Breakpoints outside a specified time span. // Insert a Breakpoint at the boundary when cropping occurs. // void Cropper::operator()( Partial & p ) const { // crop beginning of Partial Partial::iterator it = p.findAfter( minTime ); if ( it != p.begin() ) // Partial begins earlier than minTime { if ( it != p.end() ) // Partial ends later than minTime { Breakpoint bp = p.parametersAt( minTime ); it = p.insert( minTime, bp ); } it = p.erase( p.begin(), it ); } // crop end of Partial it = p.findAfter( maxTime ); if ( it != p.end() ) // Partial ends later than maxTime { if ( it != p.begin() ) // Partial begins earlier than maxTime { Breakpoint bp = p.parametersAt( maxTime ); it = p.insert( maxTime, bp ); ++it; // advance, we don't want to cut this one off } it = p.erase( it, p.end() ); } }
// --------------------------------------------------------------------------- // distillOne // --------------------------------------------------------------------------- // Distill a list of Partials having a common label // into a single Partial with that label, and append it // to the distilled collection. If an empty list of Partials // is passed, then an empty Partial having the specified // label is appended. // void Distiller::distillOne( PartialList & partials, Partial::label_type label, PartialList & distilled ) { debugger << "Distiller found " << partials.size() << " Partials labeled " << label << endl; Partial newp; newp.setLabel( label ); if ( partials.size() == 1 ) { // trivial if there is only one partial to distill newp = partials.front(); } else if ( partials.size() > 0 ) // it will be an empty Partial otherwise { // sort Partials by duration, longer // Partials will be prefered: partials.sort( distillSorter ); // keep the longest Partial: PartialList::iterator it = partials.begin(); newp = *it; fadeInAndOut( newp, _fadeTime ); // Iterate over remaining Partials: for ( ++it; it != partials.end(); ++it ) { fadeInAndOut( *it, _fadeTime ); std::pair< Partial::iterator, Partial::iterator > range = findContribution( *it, newp, _fadeTime, _gapTime ); Partial::iterator cb = range.first, ce = range.second; // There can only be one contributing regions because // (and only because) the partials are sorted by length // first! // merge Breakpoints into the new Partial, if // there are any that contribute, otherwise // just absorb the current Partial as noise: if ( cb != ce ) { // absorb the non-contributing part: if ( ce != it->end() ) { Partial absorbMe( --Partial::iterator(ce), it->end() ); // shouldn't this just be ce? newp.absorb( absorbMe ); // There cannot be a non-contributing part // at the beginning of the Partial too, because // we always retain the beginning of the Partial. // If findContribution were changed, then // we might also want to absorb the beginning. // // Partial absorbMeToo( it->begin(), cb ); // newp.absorb( absorbMeToo ); } // merge the contributing part: merge( cb, ce, newp, _fadeTime, _gapTime ); } else { // no contribution, absorb the whole thing: newp.absorb( *it ); } } } // take the null Breakpoints off the ends // should check whether this is appropriate? if ( 0 == newp.begin().breakpoint().amplitude() ) { newp.erase( newp.begin() ); } Partial::iterator lastBpPos = --(Partial::iterator(newp.end())); if ( 0 == lastBpPos.breakpoint().amplitude() ) { newp.erase( lastBpPos ); } // insert the new Partial in the distilled collection // in label order: distilled.insert( std::lower_bound( distilled.begin(), distilled.end(), newp, PartialUtils::compareLabelLess() ), newp ); }
// --------------------------------------------------------------------------- // merge (STATIC) // --------------------------------------------------------------------------- // Merge the Breakpoints in the specified iterator range into the // distilled Partial. The beginning of the range may overlap, and // will replace, some non-zero-amplitude portion of the distilled // Partial. Assume that there is no such overlap at the end of the // range (could check), because findContribution only leaves overlap // at the beginning of the range. // static void merge( Partial::const_iterator beg, Partial::const_iterator end, Partial & destPartial, double fadeTime, double gapTime = 0. ) { // absorb energy in distilled Partial that overlaps the // range to merge: Partial toMerge( beg, end ); toMerge.absorb( destPartial ); fadeInAndOut( toMerge, fadeTime ); // find the first Breakpoint in destPartial that is after the // range of merged Breakpoints, plus the required gap: Partial::iterator removeEnd = destPartial.findAfter( toMerge.endTime() + gapTime ); // if this Breakpoint has non-zero amplitude, need to leave time // for a fade in: while ( removeEnd != destPartial.end() && removeEnd.breakpoint().amplitude() != 0 && removeEnd.time() < toMerge.endTime() + gapTime + fadeTime ) { ++removeEnd; } // find the first Breakpoint in the destination Partial that needs // to be removed because it is in the overlap region: Partial::iterator removeBegin = destPartial.findAfter( toMerge.startTime() - gapTime ); // if beforeMerge has non-zero amplitude, need to leave time // for a fade out: if ( removeBegin != destPartial.begin() ) { Partial::iterator beforeMerge = --Partial::iterator(removeBegin); while ( removeBegin != destPartial.begin() && beforeMerge.breakpoint().amplitude() != 0 && beforeMerge.time() > toMerge.startTime() - gapTime - fadeTime ) { --removeBegin; if ( beforeMerge != destPartial.begin() ) { --beforeMerge; } } } // remove the Breakpoints in the merge range from destPartial: double rbt = (removeBegin != destPartial.end())?(removeBegin.time()):(destPartial.endTime()); double ret = (removeEnd != destPartial.end())?(removeEnd.time()):(destPartial.endTime()); Assert( rbt <= ret ); destPartial.erase( removeBegin, removeEnd ); // how about doing the fades here instead? // fade in if necessary: if ( removeEnd != destPartial.end() && removeEnd.breakpoint().amplitude() != 0 ) { Assert( removeEnd.time() - fadeTime > toMerge.endTime() ); // update removeEnd so that we don't remove this // null we are inserting: destPartial.insert( removeEnd.time() - fadeTime, BreakpointUtils::makeNullBefore( removeEnd.breakpoint(), fadeTime ) ); } if ( removeEnd != destPartial.begin() ) { Partial::iterator beforeMerge = --Partial::iterator(removeEnd); if ( beforeMerge.breakpoint().amplitude() > 0 ) { Assert( beforeMerge.time() + fadeTime < toMerge.startTime() ); destPartial.insert( beforeMerge.time() + fadeTime, BreakpointUtils::makeNullAfter( beforeMerge.breakpoint(), fadeTime ) ); } } // insert the Breakpoints in the range: for ( Partial::const_iterator insert = toMerge.begin(); insert != toMerge.end(); ++insert ) { destPartial.insert( insert.time(), insert.breakpoint() ); } }