#ifndef INCLUDE_MORPHER_H
#define INCLUDE_MORPHER_H
/*
 * 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
 *
 *
 * Morpher.h
 *
 * Definition of class Morpher.
 *
 * Kelly Fitz, 15 Oct 1999
 * loris@cerlsoundgroup.org
 *
 * http://www.cerlsoundgroup.org/Loris/
 *
 */
#include "PartialList.h"
#include "Partial.h"

#include <memory>   // for auto_ptr

//  begin namespace
namespace Loris {

class Envelope;

// ---------------------------------------------------------------------------
//  Class Morpher
//
//! Class Morpher performs sound morphing and Partial parameter
//! envelope interpolation according to a trio of frequency, amplitude,
//! and bandwidth morphing functions, described by Envelopes.
//! Sound morphing is achieved by interpolating the time-varying 
//! frequencies, amplitudes, and bandwidths of corresponding partials 
//! obtained from reassigned bandwidth-enhanced analysis of the source 
//! and target sounds. Partial correspondences may be established by 
//! labeling, using instances of the Channelizer and Distiller classes.
//!
//! The Morpher collects morphed Partials in a PartialList, that is
//! accessible to clients.
//!
//! For more information about sound morphing using 
//! the Reassigned Bandwidth-Enhanced Additive Sound 
//! Model, refer to the Loris website: 
//! www.cerlsoundgroup.org/Loris/.
//! 
//! Morpher is a leaf class, do not subclass.
//
class Morpher
{
//  -- instance variables --

    std::auto_ptr< Envelope > _freqFunction;  //!   frequency morphing function
    std::auto_ptr< Envelope > _ampFunction;   //!   amplitude morphing function
    std::auto_ptr< Envelope > _bwFunction;    //!   bandwidth morphing function
    
    PartialList _partials;                    //!   collect Partials here
    
    Partial _srcRefPartial;         //! reference Partials
    Partial _tgtRefPartial;         //! for source and target sounds when 
                                    //! morphing sequences of labeled Partials,
                                    //! default (empty Partial) implies no 
                                    //! reference Partial is used

    double _freqFixThresholdDb;     //! amplitude threshold below which Partial
                                    //! frequencies are corrected according to
                                    //! a reference Partial, if specified.
    
    double _logMorphShape;          //! shaping parameter that controls the 
                                    //! shape of the logarithmic morphing function,
                                    //! mostly when one of the source values
                                    //! is equal to zero. 
                                    //! Only relevant when _doLogAmpMorphing is true.
                                    //!
                                    //! Don't use this for anything, just leave it 
                                    //! at the default.
                                                            
    double _minBreakpointGapSec;    //! the minimum time gap between two Breakpoints
                                    //! in the morphed Partials. Morphing two
                                    //! Partials can generate a third Partial having
                                    //! Breakpoints arbitrarily close together in time,
                                    //! and this makes morphs huge. Raising this 
                                    //! threshold limits the Breakpoint density in
                                    //! the morphed Partials. 
                                    //! Default is 1/10 ms.
                                    
                                    
    bool _doLogAmpMorphing;         //! if true (default), amplitudes and bandwidths 
                                    //! are morphed in the log domain, if false they 
                                    //! are morphed in the linear domain.
                                    
    bool _doLogFreqMorphing;        //! if true, frequencies are morphed in the log 
                                    //! domain, if false (default) they  are morphed  
                                    //! in the linear domain.
    
    
//  -- public interface --
public:
//  -- construction --

    //! Construct a new Morpher using the same morphing envelope for 
    //! frequency, amplitude, and bandwidth (noisiness).
    //! 
    //! \param  f is the Envelope to clone for all three morphing 
    //!            functions.
    Morpher( const Envelope & f );

    //! Construct a new Morpher using the specified morphing envelopes for
    //! frequency, amplitude, and bandwidth (noisiness).
    //!
    //! \param  ff is the Envelope to clone for the frequency morphing function
    //! \param  af is the Envelope to clone for the amplitude morphing function
    //! \param  bwf is the Envelope to clone for the bandwidth morphing function    
    Morpher( const Envelope & ff, const Envelope & af, const Envelope & bwf );

    //! Construct a new Morpher that is a duplicate of rhs.
    //!
    //! \param  rhs is the Morpher to duplicate
    Morpher( const Morpher & rhs );
    
    //! Destroy this Morpher.
    ~Morpher( void );
    
   //! Make this Morpher a duplicate of rhs.
    //!
    //! \param  rhs is the Morpher to duplicate
    Morpher & operator= ( const Morpher & rhs );

//  -- morphed parameter computation --

//  -- Partial morphing --

    //! Morph a pair of Partials to yield a new morphed Partial. 
    //! Dummy Partials (having no Breakpoints) don't contribute to the
    //! morph, except to cause their opposite to fade out. 
    //! Either (or neither) the source or target Partial may be a dummy 
    //! Partial (no Breakpoints), but not both. The morphed
    //! Partial has Breakpoints at times corresponding to every Breakpoint 
    //! in both source Partials, omitting Breakpoints that would be
    //!   closer than the minBreakpointGap to their predecessor. 
    //! The new morphed Partial is assigned the specified label and returned.
    //!
    //! \param  src is the Partial corresponding to a morph function
    //!         value of 0, evaluated at the specified time.
    //! \param  tgt is the Partial corresponding to a morph function
    //!         value of 1, evaluated at the specified time.
    //! \param  assignLabel is the label assigned to the morphed Partial
    //! \return the morphed Partial
    Partial morphPartials( Partial src, Partial tgt, int assignLabel );
    
    //! Bad legacy name for morphPartials.
    //! \deprecated Use morphPartials instead.
    Partial morphPartial( Partial src, Partial tgt, int assignLabel )
        { return morphPartials( src, tgt, assignLabel ); }

    //! Morph two sounds (collections of Partials labeled to indicate
    //! correspondences) into a single labeled collection of Partials.
    //! Unlabeled Partials (having label 0) are crossfaded. The morphed
    //! and crossfaded Partials are stored in the Morpher's PartialList.
    //!
    //! The Partials in the first range are treated as components of the 
    //! source sound, corresponding to a morph function value of 0, and  
    //! those in the second are treated as components of the target sound, 
    //! corresponding to a morph function value of 1.
    //!
    //! \sa     crossfade, morphPartials
    //!
    //! \param  beginSrc is the beginning of the sequence of Partials
    //!         corresponding to a morph function value of 0.
    //! \param  endSrc is (one past) the end of the sequence of Partials
    //!         corresponding to a morph function value of 0.
    //! \param  beginTgt is the beginning of the sequence of Partials
    //!         corresponding to a morph function value of 1.
    //! \param  endTgt is (one past) the end of the sequence of Partials
    //!         corresponding to a morph function value of 1.
    void morph( PartialList::const_iterator beginSrc, 
                PartialList::const_iterator endSrc,
                PartialList::const_iterator beginTgt, 
                PartialList::const_iterator endTgt );

    //! Crossfade Partials with no correspondences.
    //!
    //! Unlabeled Partials (having the specified label) are considered to 
    //! have no correspondences, so they are just faded out, and not 
    //! actually morphed. Consistent with the morphing behavior, 
    //! crossfaded Partials are thinned, if necssary, so that no
    //! two Breakpoints are closer in time than the minBreakpointGap.
    //!
    //! The Partials in the first range are treated as components of the 
    //! source sound, corresponding to a morph function value of 0, and  
    //! those in the second are treated as components of the target sound, 
    //! corresponding to a morph function value of 1.
    //!
    //! The crossfaded Partials are stored in the Morpher's PartialList.
    //!
    //! \param  beginSrc is the beginning of the sequence of Partials
    //!         corresponding to a morph function value of 0.
    //! \param  endSrc is (one past) the end of the sequence of Partials
    //!         corresponding to a morph function value of 0.
    //! \param  beginTgt is the beginning of the sequence of Partials
    //!         corresponding to a morph function value of 1.
    //! \param  endTgt is (one past) the end of the sequence of Partials
    //!         corresponding to a morph function value of 1.
    //! \param  label is the label to associate with unlabeled
    //!         Partials (default is 0).
    void crossfade( PartialList::const_iterator beginSrc, 
                    PartialList::const_iterator endSrc,
                    PartialList::const_iterator beginTgt, 
                    PartialList::const_iterator endTgt,
                    Partial::label_type label = 0 );


    //! Compute morphed parameter values at the specified time, using
    //! the source and target Breakpoints (assumed to correspond exactly
    //! to the specified time).
    //!
    //! \param  srcBkpt is the Breakpoint corresponding to a morph function
    //!         value of 0.
    //! \param  tgtBkpt is the Breakpoint corresponding to a morph function
    //!         value of 1.
    //! \param  time is the time corresponding to srcBkpt (used
    //!         to evaluate the morphing functions and tgtPartial).
    //! \return the morphed Breakpoint
    //
    Breakpoint
    morphBreakpoints( Breakpoint srcBkpt, Breakpoint tgtBkpt, 
                      double time  ) const;
                               
    //! Compute morphed parameter values at the specified time, using
    //! the source Breakpoint (assumed to correspond exactly to the
    //! specified time) and the target Partial (whose parameters are
    //! examined at the specified time).
    //!
    //! DEPRECATED do not use.
    //!
    //! \pre    the target Partial may not be a dummy Partial (no Breakpoints).
    //!
    //! \param  bp is the Breakpoint corresponding to a morph function
    //!         value of 0.
    //! \param  tgtPartial is the Partial corresponding to a morph function
    //!         value of 1, evaluated at the specified time.
    //! \param  time is the time corresponding to srcBkpt (used
    //!         to evaluate the morphing functions and tgtPartial).
    //! \return the morphed Breakpoint
    Breakpoint 
    morphSrcBreakpoint( const Breakpoint & bp, const Partial & tgtPartial, 
                        double time ) const;

    //! Compute morphed parameter values at the specified time, using
    //! the target Breakpoint (assumed to correspond exactly to the
    //! specified time) and the source Partial (whose parameters are
    //! examined at the specified time).
    //!
    //! DEPRECATED do not use.
    //!
    //! \pre    the source Partial may not be a dummy Partial (no Breakpoints).
    //!
    //! \param  bp is the Breakpoint corresponding to a morph function
    //!         value of 1.
    //! \param  srcPartial is the Partial corresponding to a morph function
    //!         value of 0, evaluated at the specified time.
    //! \param  time is the time corresponding to srcBkpt (used
    //!         to evaluate the morphing functions and tgtPartial).
    //! \return the morphed Breakpoint
    Breakpoint 
    morphTgtBreakpoint( const Breakpoint & bp, const Partial & srcPartial, 
                        double time ) const;

    //! Compute morphed parameter values at the specified time, using
    //! the source Breakpoint, assumed to correspond exactly to the
    //! specified time, and assuming that there is no corresponding 
    //! target Partial, so the source Breakpoint should be simply faded.
    //!
    //! \param  bp is the Breakpoint corresponding to a morph function
    //!         value of 0.
    //! \param  time is the time corresponding to bp (used
    //!         to evaluate the morphing functions).
    //! \return the faded Breakpoint
    Breakpoint fadeSrcBreakpoint( Breakpoint bp, double time ) const;

    //! Compute morphed parameter values at the specified time, using
    //! the target Breakpoint, assumed to correspond exactly to the
    //! specified time, and assuming that there is not corresponding 
    //! source Partial, so the target Breakpoint should be simply faded.
    //!
    //! \param  bp is the Breakpoint corresponding to a morph function
    //!         value of 1.
    //! \param  time is the time corresponding to bp (used
    //!         to evaluate the morphing functions).
    //! \return the faded Breakpoint
    Breakpoint fadeTgtBreakpoint( Breakpoint bp, double time ) const;
    
//  -- morphing function access/mutation --

    //! Assign a new frequency morphing envelope to this Morpher.
    void setFrequencyFunction( const Envelope & f );
    
    //! Assign a new amplitude morphing envelope to this Morpher.
    void setAmplitudeFunction( const Envelope & f );
    
    //! Assign a new bandwidth morphing envelope to this Morpher.
    void setBandwidthFunction( const Envelope & f );

    //! Return a reference to this Morpher's frequency morphing envelope.
    const Envelope & frequencyFunction( void ) const;
    
    //! Return a reference to this Morpher's amplitude morphing envelope.
    const Envelope & amplitudeFunction( void ) const;
    
    //! Return a reference to this Morpher's bandwidth morphing envelope.
    const Envelope & bandwidthFunction( void ) const;
    
    //! Return the shaping parameter for the amplitude moprhing
    //! function (only used in log-amplitude morphing).
	//!                                                           
    //! DEPRECATED
    double amplitudeShape( void ) const;
    
    //! Set the shaping parameter for the amplitude moprhing
    //! function (only used in log-amplitude morphing).
	//! Only relevant when _doLogAmpMorphing is true.
	//! Don't use this for anything, just leave it 
	//! at the default.
	//!                                                           
    //! DEPRECATED
    void setAmplitudeShape( double x );
    
    //!	Enable (or disable) log-domain amplitude and bandwidth morphing.
    //! Default is true.
    void enableLogAmpMorphing( bool enable = true ) { _doLogAmpMorphing = enable; }
    
    //!	Enable (or disable) log-domain frequency morphing.
    //! Default is false.
    void enableLogFreqMorphing( bool enable = true )  { _doLogFreqMorphing = enable; }
    
    
    //! Return the minimum time gap (secs) between two Breakpoints
    //! in the morphed Partials. Morphing two
    //! Partials can generate a third Partial having
    //! Breakpoints arbitrarily close together in time,
    //! and this makes morphs huge. Raising this 
    //! threshold limits the Breakpoint density in
    //! the morphed Partials. Default is 1/10 ms.
    double minBreakpointGap( void ) const;

    //! Set the minimum time gap (secs) between two Breakpoints
    //! in the morphed Partials. Morphing two
    //! Partials can generate a third Partial having
    //! Breakpoints arbitrarily close together in time,
    //! and this makes morphs huge. Raising this 
    //! threshold limits the Breakpoint density in
    //! the morphed Partials. Default is 1/10 ms.
    //!
    //! \param  x is the new minimum gap in seconds, it must be 
    //!         positive
    //! \throw  InvalidArgument if the specified gap is not positive
    void setMinBreakpointGap( double x );


//  -- reference Partial label access/mutation --
    
    //! Return the Partial to be used as a reference
    //! Partial for the source sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference Partial
    //! should be used for the source sequence.
    const Partial & sourceReferencePartial( void ) const;
    
    //! Return the Partial to be used as a reference
    //! Partial for the source sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference Partial
    //! should be used for the source sequence.
    Partial & sourceReferencePartial( void );
    
    //! Return the Partial to be used as a reference
    //! Partial for the target sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference Partial
    //! should be used for the target sequence.
    const Partial & targetReferencePartial( void ) const;

    //! Return the Partial to be used as a reference
    //! Partial for the target sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference Partial
    //! should be used for the target sequence.
    Partial & targetReferencePartial( void );
    
    //! Specify the Partial to be used as a reference
    //! Partial for the source sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! The specified Partial must be labeled with its harmonic number.
    //! A default (empty) Partial indicates that no reference 
    //! Partial should be used for the source sequence.
    void setSourceReferencePartial( const Partial & p = Partial() );
    
    //! Specify the Partial to be used as a reference
    //! Partial for the source sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference 
    //! Partial should be used for the source sequence.
    //!
    //! \param  partials a sequence of Partials to search
    //!         for the reference Partial
    //! \param  refLabel the label of the Partial in partials
    //!         that should be selected as the reference
    void setSourceReferencePartial( const PartialList & partials, 
                                    Partial::label_type refLabel );
    
    //! Specify the Partial to be used as a reference
    //! Partial for the target sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! The specified Partial must be labeled with its harmonic number.
    //! A default (empty) Partial indicates that no reference 
    //! Partial should be used for the target sequence.
    void setTargetReferencePartial( const Partial & p = Partial() );

    //! Specify the Partial to be used as a reference
    //! Partial for the target sequence in a morph of two Partial
    //! sequences. The reference partial is used to compute 
    //! frequencies for very low-amplitude Partials whose frequency
    //! estimates are not considered reliable. The reference Partial
    //! is considered to have good frequency estimates throughout.
    //! A default (empty) Partial indicates that no reference 
    //! Partial should be used for the target sequence.
    //!
    //! \param  partials a sequence of Partials to search
    //!         for the reference Partial
    //! \param  refLabel the label of the Partial in partials
    //!         that should be selected as the reference
    void setTargetReferencePartial( const PartialList & partials, 
                                    Partial::label_type refLabel );
    
//  -- PartialList access --

    //! Return a reference to this Morpher's list of morphed Partials.
    PartialList & partials( void ); 

    //! Return a const reference to this Morpher's list of morphed Partials.
    const PartialList & partials( void ) const; 

//  -- global morphing defaults and constants --

    //! Amplitude threshold (dB) below which 
    //! Partial frequencies are corrected using
    //! the reference Partial frequency envelope
    //! (if specified).
    static const double DefaultFixThreshold;

    //! Default amplitude shaping parameter, used in
    //! interpolateLogAmplitudes to perform logarithmic 
    //! amplitude morphs. 
    //!
    //! Compile Loris with LINEAR_AMP_MORPHS defined for
    //! legacy-style linear amplitude morphs by default.
    //!
    //! Change from default using setAmplitudeShape.
    static const double DefaultAmpShape;    

    //! Default minimum time (sec) between Breakpoints in 
    //! morphed Partials. 
    //! Change from default using setMinBreakpointGap.
    static const double DefaultBreakpointGap;

private:
    
//  -- helper --

    //  PartialCorrespondence represents a map from non-zero Partial 
    //  labels to pairs of pointers to Partials that should be morphed 
    //  into a single Partial that is assigned that label. 
    //  MorphingPair is a pair of pointers to Partials that are
    //  initialized to zero, and it is the element type for the
    //  PartialCorrespondence map.
    struct MorphingPair
    {
        Partial src;
        Partial tgt;    
    };
    typedef std::map< Partial::label_type, MorphingPair > PartialCorrespondence;
    
    //! Helper function that performs the morph between corresponding pairs
    //! of Partials identified in a PartialCorrespondence. Called by the
    //! morph() implementation accepting two sequences of Partials.
    void morph_aux( PartialCorrespondence & correspondence );
    
    //! Compute morphed parameter values at the specified time, using
    //! the source Breakpoint (assumed to correspond exactly to the
    //! specified time) and the target Partial (whose parameters are
    //! examined at the specified time). Append the morphed Breakpoint
    //! to newp only if the target should contribute to the morph at
    //! the specified time.
    //!
    //! \pre    the target Partial may not be a dummy Partial (no Breakpoints).
    //!
    //! \param  srcBkpt is the Breakpoint corresponding to a morph function
    //!         value of 0.
    //! \param  tgtPartial is the Partial corresponding to a morph function
    //!         value of 1, evaluated at the specified time.
    //! \param  time is the time corresponding to srcBkpt (used
    //!         to evaluate the morphing functions and tgtPartial).
    //! \param  newp is the morphed Partial under construction, the morphed
    //!         Breakpoint is added to this Partial.
    //
    void appendMorphedSrc( Breakpoint srcBkpt, const Partial & tgtPartial, 
                           double time, Partial & newp  );
                           
    //! Compute morphed parameter values at the specified time, using
    //! the target Breakpoint (assumed to correspond exactly to the
    //! specified time) and the source Partial (whose parameters are
    //! examined at the specified time). Append the morphed Breakpoint
    //! to newp only if the target should contribute to the morph at
    //! the specified time.
    //!
    //! \pre    the source Partial may not be a dummy Partial (no Breakpoints).
    //!
    //! \param  tgtBkpt is the Breakpoint corresponding to a morph function
    //!         value of 1.
    //! \param  srcPartial is the Partial corresponding to a morph function
    //!         value of 0, evaluated at the specified time.
    //! \param  time is the time corresponding to srcBkpt (used
    //!         to evaluate the morphing functions and srcPartial).
    //! \param  newp is the morphed Partial under construction, the morphed
    //!         Breakpoint is added to this Partial.
    //
    void appendMorphedTgt( Breakpoint tgtBkpt, const Partial & srcPartial, 
                           double time, Partial & newp  );
                           
                           
	//!	Parameterinterpolation helpers.
	Breakpoint 
	interpolateParameters( const Breakpoint & srcBkpt, const Breakpoint & tgtBkpt,
                           double fweight, double aweight, double bweight ) const;

	double interpolateAmplitude( double srcAmp, double tgtAmp, double alpha ) const;
	double interpolateBandwidth( double srcBw, double tgtBw, double alpha ) const;
	double interpolateFrequency( double srcFreq, double tgtFreq, double alpha ) const;
	double interpolatePhase( double srcphase, double tgtphase, double alpha ) const;
	

	//	Recompute phases for a morphed Partial, so that the synthesized phases 
	//	match the source phases as closesly as possible at times when the 
	//	frequency morphing function is equal to 0 or 1. 
	void fixMorphedPhases( Partial & newp ) const;                           

};  //  end of class Morpher

}   //  end of namespace Loris

#endif /* ndef INCLUDE_MORPHER_H */
