// ---------------------------------------------------------------------------
//	fixPhaseBefore
//
//! Recompute phases of all Breakpoints earlier than the specified time 
//! so that the synthesize phases of those earlier Breakpoints matches 
//! the stored phase, and the synthesized phase at the specified
//! time matches the stored (not recomputed) phase.
//! 
//! Backward phase-fixing stops if a null (zero-amplitude) Breakpoint
//! is encountered, because nulls are interpreted as phase reset points
//! in Loris. If a null is encountered, the remainder of the Partial
//! (the front part) is fixed in the forward direction, beginning at
//! the start of the Partial.
//!
//! \param p    The Partial whose phases should be fixed.
//! \param t    The time before which phases should be adjusted.
//
void fixPhaseBefore( Partial & p, double t )
{
    if ( 1 < p.numBreakpoints() )
    {
        Partial::iterator pos = p.findNearest( t );
        Assert( pos != p.end() );

        fixPhaseBackward( p.begin(), pos );
    }
}
// ---------------------------------------------------------------------------
//	fixPhaseAfter
//
//! Recompute phases of all Breakpoints later than the specified time 
//! so that the synthesize phases of those later Breakpoints matches 
//! the stored phase, as long as the synthesized phase at the specified
//! time matches the stored (not recomputed) phase.
//! 
//! Phase fixing is only applied to non-null (nonzero-amplitude) Breakpoints,
//! because null Breakpoints are interpreted as phase reset points in 
//! Loris. If a null is encountered, its phase is simply left unmodified,
//! and future phases wil be recomputed from that one.
//!
//! \param p    The Partial whose phases should be fixed.
//! \param t    The time after which phases should be adjusted.
//
void fixPhaseAfter( Partial & p, double t )
{
    //  nothing to do it there are not at least
    //  two Breakpoints in the Partial   
    if ( 1 < p.numBreakpoints() )
    {
        Partial::iterator pos = p.findNearest( t );
        Assert( pos != p.end() );

        fixPhaseForward( pos, --p.end() );
    }
}
// ---------------------------------------------------------------------------
//  fixPhaseBetween
//
//!	Fix the phase travel between two times by adjusting the
//!	frequency and phase of Breakpoints between those two times.
//!
//!	This algorithm assumes that there is nothing interesting about the
//!	phases of the intervening Breakpoints, and modifies their frequencies 
//!	as little as possible to achieve the correct amount of phase travel 
//!	such that the frequencies and phases at the specified times
//!	match the stored values. The phases of all the Breakpoints between 
//! the specified times are recomputed.
//!
//! THIS DOES NOT YET TREAT NULL BREAKPOINTS DIFFERENTLY FROM OTHERS.
//!
//! \pre        There must be at least one Breakpoint in the
//!             Partial between the specified times tbeg and tend.
//! \post       The phases and frequencies of the Breakpoints in the 
//!             range have been recomputed such that an oscillator
//!             initialized to the parameters of the first Breakpoint
//!             will arrive at the parameters of the last Breakpoint,
//!             and all the intervening Breakpoints will be matched.
//!	\param p    The partial whose phases and frequencies will be recomputed. 
//!             The Breakpoint at this position is unaltered.
//! \param tbeg The phases and frequencies of Breakpoints later than the 
//!             one nearest this time will be modified.
//! \param tend The phases and frequencies of Breakpoints earlier than the 
//!             one nearest this time will be modified. Should be greater 
//!             than tbeg, or else they will be swapped.
//
void fixPhaseBetween( Partial & p, double tbeg, double tend )
{
    if ( tbeg > tend )
    {
        std::swap( tbeg, tend );
    }

    // for Partials that do not extend over the entire
    // specified time range, just recompute phases from
    // beginning or end of the range:
    if ( p.endTime() < tend )
    {
        // OK if start time is also after tbeg, will
        // just recompute phases from start of p.
        fixPhaseAfter( p, tbeg );
    }
    else if ( p.startTime() > tbeg )
    {
        fixPhaseBefore( p, tend );
    }
    else
    {
        // invariant:
        // p begins before tbeg and ends after tend.
        Partial::iterator b = p.findNearest( tbeg );
        Partial::iterator e = p.findNearest( tend );

        // if there is a null Breakpoint n between b and e, then
        // should fix forward from b to n, and backward from
        // e to n. Otherwise, do this complicated thing.
        Partial::iterator nullbp = std::find_if( b, e, BreakpointUtils::isNull );
        if ( nullbp != e )
        {
            fixPhaseForward( b, nullbp );
            fixPhaseBackward( nullbp, e );
        }
        else
        {
            fixPhaseBetween( b, e );
        }
    }
}
// ---------------------------------------------------------------------------
//	fixPhaseForward
//
//! Recompute phases of all Breakpoints later than the specified time 
//! so that the synthesize phases of those later Breakpoints matches 
//! the stored phase, as long as the synthesized phase at the specified
//! time matches the stored (not recomputed) phase. Breakpoints later than
//! tend are unmodified.
//! 
//! Phase fixing is only applied to non-null (nonzero-amplitude) Breakpoints,
//! because null Breakpoints are interpreted as phase reset points in 
//! Loris. If a null is encountered, its phase is simply left unmodified,
//! and future phases wil be recomputed from that one.
//!
//! HEY Is this interesting, in general? Why would you want to do this?
//!
//! \param p    The Partial whose phases should be fixed.
//! \param tbeg The phases and frequencies of Breakpoints later than the 
//!             one nearest this time will be modified.
//! \param tend The phases and frequencies of Breakpoints earlier than the 
//!             one nearest this time will be modified. Should be greater 
//!             than tbeg, or else they will be swapped.
//
void fixPhaseForward( Partial & p, double tbeg, double tend )
{
    if ( tbeg > tend )
    {
        std::swap( tbeg, tend );
    }
    
    //  nothing to do it there are not at least
    //  two Breakpoints in the Partial   
    if ( 1 < p.numBreakpoints() )
    {
        //  find the positions nearest tbeg and tend
        Partial::iterator posbeg = p.findNearest( tbeg );
        Partial::iterator posend = p.findNearest( tend );
        
        //  if the positions are different, and tend is
        //  the end, back it up
        if ( posbeg != posend && posend == p.end() )
        {
            --posend;
        }
        fixPhaseForward( posbeg, posend );
    }
}