Update of /cvsroot/loris/Loris/src
In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv16228/src
Modified Files:
BreakpointUtils.C Partial.C Resampler.C Resampler.h SdifFile.C
Synthesizer.C Synthesizer.h
Log Message:
Fixed several sources of phase errors in synthesis. Use Breakpoint time
quantizing (in Resampler) to correctly move Breakpoints to sample instants
before synthesizing each Partial, and use fixFrequency to correct the
frequency envelopes after quanitizing the times. Synthesis accuracy is
much improved, residuals are smaller. Also changed the behavior of
Partial::phaseAt to return the synthesized phase, that is, the phase
computed forward from the preceeding Breakpoint, as would be synthesized.
Fixed a bug in SDIF export that was triggered by this phaseAt change,
now export Breakpoint data exactly, instead of using parametersAt data.
Index: Synthesizer.h
===================================================================
RCS file: /cvsroot/loris/Loris/src/Synthesizer.h,v
retrieving revision 1.50
retrieving revision 1.51
diff -C2 -d -r1.50 -r1.51
*** Synthesizer.h 2 Jan 2010 04:55:12 -0000 1.50
--- Synthesizer.h 10 Jan 2010 07:09:27 -0000 1.51
***************
*** 160,164 ****
//! Partial, p, including fade out at the end.
//! \throw InvalidPartial if the Partial has negative start time.
! void synthesize( const Partial & p );
//! Function call operator: same as synthesize( p ).
--- 160,164 ----
//! Partial, p, including fade out at the end.
//! \throw InvalidPartial if the Partial has negative start time.
! void synthesize( Partial p );
//! Function call operator: same as synthesize( p ).
Index: SdifFile.C
===================================================================
RCS file: /cvsroot/loris/Loris/src/SdifFile.C,v
retrieving revision 1.56
retrieving revision 1.57
diff -C2 -d -r1.56 -r1.57
*** SdifFile.C 2 Jan 2010 04:55:12 -0000 1.56
--- SdifFile.C 10 Jan 2010 07:09:27 -0000 1.57
***************
*** 1914,1923 ****
// For enhanced format we use exact timing; the activeIndices only includes
// partials that have breakpoints in this frame.
! // For sine-only format we resample at frame times.
Assert( par->endTime() >= frameTime );
! double tim = enhanced ? par->findAfter( frameTime ).time() : frameTime;
!
// Must have phase between 0 and 2*Pi.
! double phas = par->phaseAt( tim );
if (phas < 0)
{
--- 1914,1935 ----
// For enhanced format we use exact timing; the activeIndices only includes
// partials that have breakpoints in this frame.
! // For sine-only format we resample at frame times, for enhanced, use
! // the Breakpoints themselves.
Assert( par->endTime() >= frameTime );
! double tim = frameTime;
! Breakpoint params;
! if ( enhanced )
! {
! Partial::const_iterator pos = par->findAfter( frameTime );
! tim = pos.time();
! params = pos.breakpoint();
! }
! else
! {
! params = par->parametersAt( frameTime );
! }
!
// Must have phase between 0 and 2*Pi.
! double phas = params.phase();
if (phas < 0)
{
***************
*** 1927,1936 ****
// Fill in values for this row of matrix data.
*rowDataPtr++ = index; // first row of matrix (standard)
! *rowDataPtr++ = par->frequencyAt( tim ); // second row of matrix (standard)
! *rowDataPtr++ = par->amplitudeAt( tim ); // third row of matrix (standard)
*rowDataPtr++ = phas; // fourth row of matrix (standard)
if (enhanced)
{
! *rowDataPtr++ = par->bandwidthAt( tim ); // fifth row of matrix (loris)
*rowDataPtr++ = tim - frameTime; // sixth row of matrix (loris)
}
--- 1939,1948 ----
// Fill in values for this row of matrix data.
*rowDataPtr++ = index; // first row of matrix (standard)
! *rowDataPtr++ = params.frequency(); // second row of matrix (standard)
! *rowDataPtr++ = params.amplitude(); // third row of matrix (standard)
*rowDataPtr++ = phas; // fourth row of matrix (standard)
if (enhanced)
{
! *rowDataPtr++ = params.bandwidth(); // fifth row of matrix (loris)
*rowDataPtr++ = tim - frameTime; // sixth row of matrix (loris)
}
Index: Synthesizer.C
===================================================================
RCS file: /cvsroot/loris/Loris/src/Synthesizer.C,v
retrieving revision 1.69
retrieving revision 1.70
diff -C2 -d -r1.69 -r1.70
*** Synthesizer.C 2 Jan 2010 04:55:12 -0000 1.69
--- Synthesizer.C 10 Jan 2010 07:09:27 -0000 1.70
***************
*** 45,48 ****
--- 45,50 ----
#include "Notifier.h"
#include "Partial.h"
+ #include "Resampler.h"
+ #include "phaseFix.h"
#include <algorithm>
***************
*** 210,214 ****
//
void
! Synthesizer::synthesize( const Partial & p )
{
if ( p.numBreakpoints() == 0 )
--- 212,216 ----
//
void
! Synthesizer::synthesize( Partial p )
{
if ( p.numBreakpoints() == 0 )
***************
*** 227,230 ****
--- 229,243 ----
<< p.initialPhase() << " starting frequency "
<< p.first().frequency() << endl;
+
+ // better to compute this only once:
+ const double OneOverSrate = 1. / m_srateHz;
+
+
+ // use a Resampler to quantize the Breakpoint times and
+ // correct the phases:
+ Resampler quantizer( OneOverSrate );
+ quantizer.setPhaseCorrect( true );
+ quantizer.quantize( p );
+
// resize the sample buffer if necessary:
***************
*** 240,246 ****
// m_fadeTimeSec before the Partial's startTime, but not before 0:
double itime = ( m_fadeTimeSec < p.startTime() ) ? ( p.startTime() - m_fadeTimeSec ) : 0.;
! index_type currentSamp = index_type( itime * m_srateHz );
// reset the oscillator:
m_osc.resetEnvelopes( BreakpointUtils::makeNullBefore( p.first(), p.startTime() - itime ), m_srateHz );
--- 253,262 ----
// m_fadeTimeSec before the Partial's startTime, but not before 0:
double itime = ( m_fadeTimeSec < p.startTime() ) ? ( p.startTime() - m_fadeTimeSec ) : 0.;
! index_type currentSamp = index_type( (itime * m_srateHz) + 0.5 ); // cheap rounding
// reset the oscillator:
+ // all that really needs to happen here is setting the frequency
+ // correctly, the phase will be reset again in the loop over
+ // Breakpoints below, and the amp and bw can start at 0.
m_osc.resetEnvelopes( BreakpointUtils::makeNullBefore( p.first(), p.startTime() - itime ), m_srateHz );
***************
*** 252,258 ****
double prevFrequency = p.first().frequency();
- // better to compute this only once:
- const double OneOverSrate = 1. / m_srateHz;
-
// synthesize linear-frequency segments until
// there aren't any more Breakpoints to make segments:
--- 268,271 ----
***************
*** 260,264 ****
for ( Partial::const_iterator it = p.begin(); it != p.end(); ++it )
{
! index_type tgtSamp = index_type( it.time() * m_srateHz );
Assert( tgtSamp >= currentSamp );
--- 273,277 ----
for ( Partial::const_iterator it = p.begin(); it != p.end(); ++it )
{
! index_type tgtSamp = index_type( (it.time() * m_srateHz) + 0.5 ); // cheap rounding
Assert( tgtSamp >= currentSamp );
***************
*** 285,291 ****
m_osc.oscillate( bufferBegin + currentSamp, bufferBegin + tgtSamp,
! it.breakpoint(), m_srateHz );
currentSamp = tgtSamp;
prevFrequency = it.breakpoint().frequency();
}
--- 298,307 ----
m_osc.oscillate( bufferBegin + currentSamp, bufferBegin + tgtSamp,
! it.breakpoint(), m_srateHz );
currentSamp = tgtSamp;
+
+ // remember the frequency, may need it to reset the
+ // phase if a Null Breakpoint is encountered:
prevFrequency = it.breakpoint().frequency();
}
***************
*** 293,297 ****
// render a fade out segment:
m_osc.oscillate( bufferBegin + currentSamp, bufferBegin + endSamp,
! BreakpointUtils::makeNullAfter( p.last(), m_fadeTimeSec ), m_srateHz );
}
--- 309,313 ----
// render a fade out segment:
m_osc.oscillate( bufferBegin + currentSamp, bufferBegin + endSamp,
! BreakpointUtils::makeNullAfter( p.last(), m_fadeTimeSec ), m_srateHz );
}
Index: Resampler.h
===================================================================
RCS file: /cvsroot/loris/Loris/src/Resampler.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** Resampler.h 2 Jan 2010 04:55:12 -0000 1.13
--- Resampler.h 10 Jan 2010 07:09:27 -0000 1.14
***************
*** 39,42 ****
--- 39,43 ----
#include "PartialList.h"
+ #include "LinearEnvelope.h"
// begin namespace
***************
*** 62,88 ****
// --- lifecycle ---
! //! Construct a new Resampler using the specified sampling
! //! interval and sparse resampling.
//!
//! \param sampleInterval is the resampling interval in seconds,
//! Breakpoint data is computed at integer multiples of
//! sampleInterval seconds.
//! \throw InvalidArgument if sampleInterval is not positive.
explicit Resampler( double sampleInterval );
! // use compiler-generated copy/assign/destroy
!
! // --- parameters ---
! //! Select dense or sparse resampling.
//!
! //! \param useDense is a boolean flag indicating that dense
! //! resamping (Breakpoint at every integer multiple of the
! //! resampling interval) should be performed. If false (the
! //! default), sparse resampling (Breakpoints only at multiples
! //! of the resampling interval near Breakpoint times in the
! //! original Partial) is performed.
! void setDenseResampling( bool useDense );
//! Specify phase-corrected resampling, or not. If phase
//! correct, Partial frequencies are altered slightly
--- 63,133 ----
// --- lifecycle ---
! //! Initialize a Resampler having the specified uniform sampling
! //! interval. Enable phase-correct resampling, in which frequencies
! //! of resampled Partials are modified (using fixFrequency) such
! //! that the resampled phases are achieved in synthesis. Phase-
! //! correct resampling can be disabled using setPhaseCorrect.
! //!
! //! Resampled Partials will be composed of Breakpoints at every
! //! integer multiple of the resampling interval.
! //!
! //! \sa setPhaseCorrect
! //! \sa fixFrequency
//!
//! \param sampleInterval is the resampling interval in seconds,
//! Breakpoint data is computed at integer multiples of
//! sampleInterval seconds.
+ //!
//! \throw InvalidArgument if sampleInterval is not positive.
explicit Resampler( double sampleInterval );
! //! Initialize a Resampler having the specified timing envelope.
! //! The timing envelope represents a map of Breakpoint times in
! //! resampled Partials onto parameter sampling instants in the
! //! original Partials. Phase-correct resampling is not generally
! //! possible using a nontrivial timing envelope, use the functions
! //! declared in phasefix.h to correct the phases and frequencies
! //! of resampled Partials.
! //!
! //! Resampled Partials will be composed of Breakpoints at times
! //! corresponding to the timing envelope breakpoints.
! //!
! //! \param timingEnv is the timing envelope, a map of Breakpoint
! //! times in resampled Partials onto parameter sampling
! //! instants in the original Partials.
! //!
! //! \throw InvalidArgument if timingEnv has any negative breakpoint
! //! times or values.
! explicit Resampler( const LinearEnvelope & timingEnv );
! //! Initialize a Resampler having the specified timing envelope,
! //! uniformly sampled at the sampling interval.
! //! The timing envelope represents a map of Breakpoint times in
! //! resampled Partials onto parameter sampling instants in the
! //! original Partials. Phase-correct resampling is not generally
! //! possible using a nontrivial timing envelope, use the functions
! //! declared in phasefix.h to correct the phases and frequencies
! //! of resampled Partials.
//!
! //! Resampled Partials will be composed of Breakpoints at every
! //! integer multiple of the resampling interval.
! //!
! //! \param timingEnv is the timing envelope, a map of Breakpoint
! //! times in resampled Partials onto parameter sampling
! //! instants in the original Partials.
! //! \param sampleInterval is the resampling interval in seconds,
! //! Breakpoint data is computed at integer multiples of
! //! sampleInterval seconds.
! //!
! //! \throw InvalidArgument if sampleInterval is not positive.
! //! \throw InvalidArgument if timingEnv has any negative breakpoint
! //! times or values.
! Resampler( const LinearEnvelope & timingEnv, double sampleInterval );
!
!
! // --- use compiler-generated copy/assign/destroy ---
+ // --- parameters ---
+
//! Specify phase-corrected resampling, or not. If phase
//! correct, Partial frequencies are altered slightly
***************
*** 118,121 ****
--- 163,179 ----
resample( p );
}
+
+
+ //! DCUMENT ME
+ //! The Breakpoint times in the resampled Partial will comprise a
+ //! sparse sequence of integer multiples of the sampling interval,
+ //! beginning with the multiple nearest to the Partial's start time and
+ //! ending with the multiple nearest to the Partial's end time, and including
+ //! only multiples that are near to Breakpoint times in the original Partial.
+ //! Resampling is performed in-place.
+ //!
+ //! \param p is the Partial to resample
+ void quantize( Partial & p ) const;
+
//! Resample all Partials in the specified (half-open) range using this
***************
*** 155,159 ****
resample( begin, end );
}
!
// -- static members --
--- 213,242 ----
resample( begin, end );
}
!
!
! //! DOCUMENT ME
! //! Quantize all Partials in the specified (half-open) range using this
! //! Resampler's stored sampling interval,
! //! The Breakpoint times in the resampled Partial will comprise a
! //! sparse sequence of integer multiples of the sampling interval,
! //! beginning with the multiple nearest to the Partial's start time and
! //! ending with the multiple nearest to the Partial's end time, and including
! //! only multiples that are near to Breakpoint times in the original Partial.
! //! Resampling is performed in-place.
! //!
! //! \param begin is the beginning of the range of Partials to quantize
! //! \param end is (one-past) the end of the range of Partials to quantize
! //!
! //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end
! //! must be PartialList::iterators, otherwise they can be any type
! //! of iterators over a sequence of Partials.
! #if ! defined(NO_TEMPLATE_MEMBERS)
! template<typename Iter>
! void quantize( Iter begin, Iter end ) const;
! #else
! inline
! void quantize( PartialList::iterator begin, PartialList::iterator end ) const;
! #endif
!
// -- static members --
***************
*** 195,204 ****
private:
//! the resampling interval in seconds
double interval_;
-
- //! boolean selecting dense or sparse resampling
- //! (default is false)
- bool dense_;
//! boolean flag selecting phase-corrected resampling
--- 278,286 ----
private:
+ //! the timing envelope for resampling
+ LinearEnvelope timing_;
+
//! the resampling interval in seconds
double interval_;
//! boolean flag selecting phase-corrected resampling
***************
*** 242,245 ****
--- 324,362 ----
// ---------------------------------------------------------------------------
+ // quantize (sequence of Partials)
+ // ---------------------------------------------------------------------------
+ //! DOCUMENT ME
+ //! Quantize all Partials in the specified (half-open) range using this
+ //! Resampler's stored sampling interval,
+ //! The Breakpoint times in the resampled Partial will comprise a
+ //! sparse sequence of integer multiples of the sampling interval,
+ //! beginning with the multiple nearest to the Partial's start time and
+ //! ending with the multiple nearest to the Partial's end time, and including
+ //! only multiples that are near to Breakpoint times in the original Partial.
+ //! Resampling is performed in-place.
+ //!
+ //! \param begin is the beginning of the range of Partials to quantize
+ //! \param end is (one-past) the end of the range of Partials to quantize
+ //!
+ //! If compiled with NO_TEMPLATE_MEMBERS defined, then begin and end
+ //! must be PartialList::iterators, otherwise they can be any type
+ //! of iterators over a sequence of Partials.
+ //
+ #if ! defined(NO_TEMPLATE_MEMBERS)
+ template<typename Iter>
+ void Resampler::quantize( Iter begin, Iter end ) const
+ #else
+ inline
+ void Resampler::quantize( PartialList::iterator begin, PartialList::iterator end ) const
+ #endif
+ {
+ while ( begin != end )
+ {
+ quantize( *begin++ );
+ }
+ }
+
+
+ // ---------------------------------------------------------------------------
// resample (static)
// ---------------------------------------------------------------------------
***************
*** 279,284 ****
{
Resampler instance( sampleInterval );
! instance.setDenseResampling( denseResampling );
! instance.resample( begin, end );
}
--- 396,408 ----
{
Resampler instance( sampleInterval );
!
! if ( denseResampling )
! {
! instance.resample( begin, end );
! }
! else
! {
! instance.quantize( begin, end );
! }
}
Index: BreakpointUtils.C
===================================================================
RCS file: /cvsroot/loris/Loris/src/BreakpointUtils.C,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** BreakpointUtils.C 2 Jan 2010 04:55:12 -0000 1.13
--- BreakpointUtils.C 10 Jan 2010 07:09:27 -0000 1.14
***************
*** 61,65 ****
// adjust phase
double dp = 2. * Pi * fadeTime * bp.frequency();
! ret.setPhase( std::fmod( ret.phase() - dp, 2. * Pi ) );
ret.setAmplitude(0.);
ret.setBandwidth(0.);
--- 61,65 ----
// adjust phase
double dp = 2. * Pi * fadeTime * bp.frequency();
! ret.setPhase( std::fmod( bp.phase() - dp, 2. * Pi ) );
ret.setAmplitude(0.);
ret.setBandwidth(0.);
***************
*** 80,84 ****
// adjust phase
double dp = 2. * Pi * fadeTime * bp.frequency();
! ret.setPhase( std::fmod( ret.phase() + dp, 2. * Pi ) );
ret.setAmplitude(0.);
ret.setBandwidth(0.);
--- 80,84 ----
// adjust phase
double dp = 2. * Pi * fadeTime * bp.frequency();
! ret.setPhase( std::fmod( bp.phase() + dp, 2. * Pi ) );
ret.setAmplitude(0.);
ret.setBandwidth(0.);
Index: Resampler.C
===================================================================
RCS file: /cvsroot/loris/Loris/src/Resampler.C,v
retrieving revision 1.20
retrieving revision 1.21
diff -C2 -d -r1.20 -r1.21
*** Resampler.C 2 Jan 2010 04:55:12 -0000 1.20
--- Resampler.C 10 Jan 2010 07:09:27 -0000 1.21
***************
*** 43,46 ****
--- 43,47 ----
#include "Resampler.h"
#include "Breakpoint.h"
+ #include "LinearEnvelope.h"
#include "LorisExceptions.h"
#include "Notifier.h"
***************
*** 54,69 ****
// helper declarations:
! static void resample_dense( Partial & p, double interval );
! static void resample_sparse( Partial & p, double interval );
static void insert_resampled_at( Partial & newp, const Partial & p,
! double curtime, double interval );
! static bool check_error_at( Partial & newp, const Partial & p,
! double time, double interval );
// ---------------------------------------------------------------------------
! // constructor
// ---------------------------------------------------------------------------
! //! Construct a new Resampler using the specified sampling
! //! interval and sparse resampling.
//!
//! \param sampleInterval is the resampling interval in seconds,
--- 55,101 ----
// helper declarations:
! static void resample_dense( Partial & p, const LinearEnvelope & env, double interval );
! static void resample_sparse( Partial & p, const LinearEnvelope & env );
static void insert_resampled_at( Partial & newp, const Partial & p,
! double sampleTime, double insertTime );
!
! /*
! new ideas
!
! use linear envelope to specify timing (possibly warped, line slope 1
! for plain old uniform resampling)
!
! dense resampling samples then envelope uniformly at the specified interval,
! envelope determines the time at which the original partial is sampled
!
! sparse resampling samples only the breakpoints in the envelope (interval
! is zero in this case)
!
! sparse sampling, by this definition, makes no sense without an envelope
! specification
!
! This is a different definition of sparse resampling from the old one.
! What the hell good was the old one? Could that be useful for anything?
!
! NEXT STEP
! Revisit the default values for parameters, and define necessary
! constructors and members related to the timing envelope.
! */
!
// ---------------------------------------------------------------------------
! // constructor - sampling interval
// ---------------------------------------------------------------------------
! //! Initialize a Resampler having the specified uniform sampling
! //! interval. Enable phase-correct resampling, in which frequencies
! //! of resampled Partials are modified (using fixFrequency) such
! //! that the resampled phases are achieved in synthesis. Phase-
! //! correct resampling can be disabled using setPhaseCorrect.
! //!
! //! Resampled Partials will be composed of Breakpoints at every
! //! integer multiple of the resampling interval.
! //!
! //! \sa setPhaseCorrect
! //! \sa fixFrequency
//!
//! \param sampleInterval is the resampling interval in seconds,
***************
*** 73,103 ****
//
Resampler::Resampler( double sampleInterval ) :
! interval_( sampleInterval ),
! dense_( false ),
! phaseCorrect_( true )
{
! if ( sampleInterval <= 0. )
! {
Throw( InvalidArgument, "Resampler sample interval must be positive." );
! }
}
// ---------------------------------------------------------------------------
! // setDenseResampling
// ---------------------------------------------------------------------------
! //! Select dense or sparse resampling.
//!
! //! \param useDense is a boolean flag indicating that dense
! //! resamping (Breakpoint at every integer multiple of the
! //! resampling interval) should be performed. If false (the
! //! default), sparse resampling (Breakpoints only at multiples
! //! of the resampling interval near Breakpoint times in the
! //! original Partial) is performed.
//
! void Resampler::setDenseResampling( bool useDense )
{
! dense_ = useDense;
}
// ---------------------------------------------------------------------------
// setPhaseCorrect
--- 105,190 ----
//
Resampler::Resampler( double sampleInterval ) :
! interval_( sampleInterval ),
! phaseCorrect_( true )
{
! if ( sampleInterval <= 0. )
! {
Throw( InvalidArgument, "Resampler sample interval must be positive." );
! }
}
// ---------------------------------------------------------------------------
! // constructor - timing envelope
// ---------------------------------------------------------------------------
! //! Initialize a Resampler having the specified timing envelope.
! //! The timing envelope represents a map of Breakpoint times in
! //! resampled Partials onto parameter sampling instants in the
! //! original Partials. Phase-correct resampling is not generally
! //! possible using a nontrivial timing envelope, use the functions
! //! declared in phasefix.h to correct the phases and frequencies
! //! of resampled Partials.
//!
! //! Resampled Partials will be composed of Breakpoints at times
! //! corresponding to the timing envelope breakpoints.
! //!
! //! \param timingEnv is the timing envelope, a map of Breakpoint
! //! times in resampled Partials onto parameter sampling
! //! instants in the original Partials.
! //! \throw InvalidArgument if timingEnv has any negative breakpoint
! //! times or values.
//
! Resampler::Resampler( const LinearEnvelope & timingEnv ) :
! timing_( timingEnv ),
! interval_( 0 ),
! phaseCorrect_( false )
{
! // check the timing envelope for negative times or values
! }
!
! // ---------------------------------------------------------------------------
! // constructor - timing envelope and sampling interval
! // ---------------------------------------------------------------------------
! //! Initialize a Resampler having the specified timing envelope,
! //! uniformly sampled at the sampling interval.
! //! The timing envelope represents a map of Breakpoint times in
! //! resampled Partials onto parameter sampling instants in the
! //! original Partials. Phase-correct resampling is not generally
! //! possible using a nontrivial timing envelope, use the functions
! //! declared in phasefix.h to correct the phases and frequencies
! //! of resampled Partials.
! //!
! //! Resampled Partials will be composed of Breakpoints at every
! //! integer multiple of the resampling interval.
! //!
! //! \param timingEnv is the timing envelope, a map of Breakpoint
! //! times in resampled Partials onto parameter sampling
! //! instants in the original Partials.
! //! \param sampleInterval is the resampling interval in seconds,
! //! Breakpoint data is computed at integer multiples of
! //! sampleInterval seconds.
! //!
! //! \throw InvalidArgument if sampleInterval is not positive.
! //! \throw InvalidArgument if timingEnv has any negative breakpoint
! //! times or values.
! Resampler::Resampler( const LinearEnvelope & timingEnv, double sampleInterval ) :
! timing_( timingEnv ),
! interval_( sampleInterval ),
! phaseCorrect_( false )
! {
! if ( sampleInterval <= 0. )
! {
! Throw( InvalidArgument, "Resampler sample interval must be positive." );
! }
!
! // HEY!!! check the timing envelope for negative times or values
! /*
! if ( 0 > timingEnv.begin()->first )
! {
! Throw( InvalidArgument, "Resampler timing envelope must not have negative." );
! }
! */
}
+
// ---------------------------------------------------------------------------
// setPhaseCorrect
***************
*** 137,172 ****
Resampler::resample( Partial & p ) const
{
! if ( dense_ )
{
! resample_dense( p, interval_ );
}
else
{
! resample_sparse( p, interval_ );
}
if ( phaseCorrect_ )
{
- // To damp or not to damp?
- // When correcting phase, use damping if the resampling
- // interval is less than the length of a period, otherwise
- // don't damp the correction.
- //
- // No, maybe damping is always needed for small intervals?
- // This smooth fade is a kludge that seems to work.
- //
- // Used to do this each time a Breakpoint was inserted, but
- // it amounts to the same thing as just doing it at the end.
- // fixFrequency doesn't currently allow specification of
- // the damping, may need to add that back later.
- /*
- double damping = 0.5;
- const double MAGICKLUDGE = 0.012;
- if ( interval > MAGICKLUDGE )
- {
- damping += std::min( 0.5, 100 * (interval - MAGICKLUDGE) );
- }
- // debugger << "damping is " << damping << endl;
- */
fixFrequency( p ); // use default maxFixPct
}
--- 224,247 ----
Resampler::resample( Partial & p ) const
{
! debugger << "resampling Partial labeled " << p.label()
! << " having " << p.numBreakpoints()
! << " Breakpoints" << endl;
!
!
! if ( 0 != interval_ )
{
! resample_dense( p, timing_, interval_ );
}
else
{
! resample_sparse( p, timing_ );
}
+ debugger << "resampled Partial has " << p.numBreakpoints()
+ << " Breakpoints" << endl;
+
+
if ( phaseCorrect_ )
{
fixFrequency( p ); // use default maxFixPct
}
***************
*** 184,195 ****
//!
//! \param p is the Partial to resample
//! \param interval is the resamping interval in seconds
//
! static void resample_dense( Partial & p, double interval )
{
- debugger << "resampling Partial labeled " << p.label()
- << " having " << p.numBreakpoints()
- << " Breakpoints" << endl;
-
// create the new Partial:
Partial newp;
--- 259,269 ----
//!
//! \param p is the Partial to resample
+ //! \param env is the timing envelope
//! \param interval is the resamping interval in seconds
//
! static
! void
! resample_dense( Partial & p, const LinearEnvelope & env, double interval )
{
// create the new Partial:
Partial newp;
***************
*** 202,213 ****
// resample:
! for ( double tim = firstTime; tim < stopTime; tim += interval )
{
! insert_resampled_at( newp, p, tim, interval );
}
!
! debugger << "resamplied Partial has " << newp.numBreakpoints()
! << " Breakpoints" << endl;
!
// store the new Partial:
p = newp;
--- 276,289 ----
// resample:
! for ( double tins = firstTime; tins < stopTime; tins += interval )
{
! double tsamp = tins;
! if ( 0 != env.size() )
! {
! tsamp = env.valueAt( tins );
! }
! insert_resampled_at( newp, p, tsamp, tins );
}
!
// store the new Partial:
p = newp;
***************
*** 218,221 ****
--- 294,346 ----
// ---------------------------------------------------------------------------
//! Helper function to perform sparse resampling at a specified interval.
+ //! Sample the origial Partial only at breakpoints in the timing envelope.
+ //! \param p is the Partial to resample
+ //! \param env is the timing envelope
+ //! \param interval is the resamping interval in seconds
+ //
+ static
+ void
+ resample_sparse( Partial & p, const LinearEnvelope & env )
+ {
+ if ( 0 == env.size() )
+ {
+ Throw( InvalidArgument,
+ "Sparse resampling requires a timing envelope specification." );
+ }
+
+ // create the new Partial:
+ Partial newp;
+ newp.setLabel( p.label() );
+
+ // find time of first breakpoint for the resampled envelope:
+ LinearEnvelope::const_iterator it = env.begin();
+ while( it->first < p.startTime() )
+ {
+ ++it;
+ }
+
+ // resample:
+ while ( it != env.end() )
+ {
+ double tins = it->first;
+ double tsamp = tins;
+ if ( 0 != env.size() )
+ {
+ tsamp = env.valueAt( tins );
+ }
+ insert_resampled_at( newp, p, tsamp, tins );
+
+ ++it;
+ }
+
+ // store the new Partial:
+ p = newp;
+ }
+
+
+
+ // ---------------------------------------------------------------------------
+ // quantize
+ // ---------------------------------------------------------------------------
//! The Breakpoint times in the resampled Partial will comprise a
//! sparse sequence of integer multiples of the sampling interval,
***************
*** 226,237 ****
//!
//! \param p is the Partial to resample
- //! \param interval is the resamping interval in seconds
//
! static void resample_sparse( Partial & p, double interval )
{
! debugger << "resampling Partial labeled " << p.label()
<< " having " << p.numBreakpoints()
<< " Breakpoints" << endl;
// create the new Partial:
Partial newp;
--- 351,370 ----
//!
//! \param p is the Partial to resample
//
! void Resampler::quantize( Partial & p ) const
{
! debugger << "quantizing Partial labeled " << p.label()
<< " having " << p.numBreakpoints()
<< " Breakpoints" << endl;
+ // for phase-correct quantization, first make the phases correct by
+ // fixing them from the initial phase, then quantize the Breakpoint
+ // times, then afterwards, adjust the frequencies to match
+ // the interpolated phases:
+ if ( phaseCorrect_ )
+ {
+ fixPhaseForward( p.begin(), --p.end() );
+ }
+
// create the new Partial:
Partial newp;
***************
*** 240,301 ****
// resample:
double curtime = 0;
! double halfstep = .5 * interval;
Partial::const_iterator iter = p.begin();
!
! unsigned int countSkippedSteps = 0;
! double prevInsertTime = 0;
!
while( iter != p.end() )
{
double bpt = iter.time();
-
- debugger << " ----------------------- \n"
- << "considering bp at time " << bpt
- << " and amplitude " << iter->amplitude()
- << "\nquanitzation step time is " << curtime
- << endl;
-
if ( bpt < curtime - halfstep )
{
! // advance Breakpoint iterator:
++iter;
!
! debugger << "skipping bp" << endl;
! }
else if (curtime < bpt - halfstep)
{
! // advance current time:
! curtime += interval;
!
! ++countSkippedSteps;
!
! debugger << "skipping quantization step" << endl;
}
else
{
! insert_resampled_at( newp, p, curtime, interval );
!
! // check for errors introduced by skippint steps
! if ( ( 0 < countSkippedSteps ) &&
! check_error_at( newp, p, curtime-interval, interval ) )
! {
! insert_resampled_at( newp, p, curtime-interval, interval );
! }
! if ( ( 1 < countSkippedSteps ) &&
! check_error_at( newp, p, prevInsertTime+interval, interval ) )
! {
! insert_resampled_at( newp, p, prevInsertTime+interval, interval );
! }
!
! prevInsertTime = curtime;
! countSkippedSteps = 0;
!
! // advance the Breakpoint iterator and the current time:
++iter;
! curtime += interval;
}
}
! debugger << "resampled Partial has " << newp.numBreakpoints()
<< " Breakpoints" << endl;
--- 373,411 ----
// resample:
double curtime = 0;
! double halfstep = .5 * interval_;
Partial::const_iterator iter = p.begin();
!
while( iter != p.end() )
{
double bpt = iter.time();
if ( bpt < curtime - halfstep )
{
! // advance Breakpoint iterator, no new Breakpoint:
++iter;
! }
else if (curtime < bpt - halfstep)
{
! // advance current time, no new Breakpoint:
! curtime += interval_;
}
else
{
! // insert another Breakpoints and advance the Breakpoint
! // iterator and the current time:
! insert_resampled_at( newp, p, curtime, curtime );
++iter;
! curtime += interval_;
}
}
! // for phase-correct quantization, adjust the frequencies to match
! // the interpolated phases:
! if ( phaseCorrect_ )
! {
! fixFrequency( newp, 1 );
! }
!
!
! debugger << "quantized Partial has " << newp.numBreakpoints()
<< " Breakpoints" << endl;
***************
*** 311,414 ****
static void
insert_resampled_at( Partial & newp, const Partial & p,
! double curtime, double interval )
{
// make a resampled Breakpoint:
! Breakpoint newbp = p.parametersAt( curtime );
// handle end points to reduce error at ends
! if ( curtime < p.startTime() )
{
newbp.setAmplitude( p.first().amplitude() );
}
! else if ( curtime > p.endTime() )
{
newbp.setAmplitude( p.last().amplitude() );
}
! /*
! double overrideAmp =
! p.findNearest( curtime ).breakpoint().amplitude();
! newbp.setAmplitude( overrideAmp );
! */
!
! /*
! Used to do this here, now do it all at once in resample.
!
! #if defined(PHASE_CORRECT)
! if ( newp.numBreakpoints() != 0 )
! {
! double dt = curtime - newp.endTime();
!
! // To damp or not to damp?
! // When correcting phase, use damping if the resampling
! // interval is less than the length of a period, otherwise
! // don't damp the correction.
! //
! // No, maybe damping is always needed for small intervals?
! // This smooth fade is a kludge that seems to work.
! double damping = 0.5;
! const double MAGICKLUDGE = 0.012;
! if ( dt > MAGICKLUDGE )
! {
! damping += std::min( 0.5, 100 * (dt - MAGICKLUDGE) );
! }
!
! matchPhaseFwd( newp.last(), newbp, dt, damping );
! }
! #endif
! */
!
! newp.insert( curtime, newbp );
debugger << "inserted Breakpoint having amplitude " << newbp.amplitude()
! << " at time " << curtime << endl;
! }
!
! // ---------------------------------------------------------------------------
! // check_error_at (helper)
! // ---------------------------------------------------------------------------
! // Sparse resampling helper for correcting errors introduced by skipping
! // quantization steps. Fix by not skipping so many!
! //
! static bool
! check_error_at( Partial & newp, const Partial & p,
! double time, double interval )
! {
! // don't insert extra Breakpoints past the ends
! // of the Partial
! if ( time < p.startTime() || time > p.endTime() )
! {
! return false;
! }
!
! Breakpoint original = p.parametersAt( time, interval );
! Breakpoint resampled = newp.parametersAt( time );
!
! // amplitude tolerance is 1% of original
! const double eps = 1E-6;
! double ampErr = std::fabs( original.amplitude() - resampled.amplitude() ) /
! ( original.amplitude() + eps );
! if ( ampErr > 0.01 )
! {
! return true;
! }
!
! // frequency tolerance is 1% of original
! double freqErr = std::fabs( original.frequency() - resampled.frequency() ) /
! ( original.frequency() );
! if ( freqErr > 0.01 )
! {
! return true;
! }
!
! // bandwidth tolerance is 10% of original
! double bwErr = std::fabs( original.bandwidth() - resampled.bandwidth() ) /
! ( original.bandwidth() + eps );
! if ( bwErr > 0.1 )
! {
! return true;
! }
!
! return false;
}
--- 421,444 ----
static void
insert_resampled_at( Partial & newp, const Partial & p,
! double sampleTime, double insertTime )
{
// make a resampled Breakpoint:
! Breakpoint newbp = p.parametersAt( sampleTime );
// handle end points to reduce error at ends
! if ( sampleTime < p.startTime() )
{
newbp.setAmplitude( p.first().amplitude() );
}
! else if ( sampleTime > p.endTime() )
{
newbp.setAmplitude( p.last().amplitude() );
}
+
! newp.insert( insertTime, newbp );
debugger << "inserted Breakpoint having amplitude " << newbp.amplitude()
! << " at time " << insertTime << endl;
}
Index: Partial.C
===================================================================
RCS file: /cvsroot/loris/Loris/src/Partial.C,v
retrieving revision 1.71
retrieving revision 1.72
diff -C2 -d -r1.71 -r1.72
*** Partial.C 2 Jan 2010 04:55:12 -0000 1.71
--- Partial.C 10 Jan 2010 07:09:27 -0000 1.72
***************
*** 274,278 ****
/*
// this allows Breakpoints to be inserted arbitrarily
! // cloase together, which is no good, can cause trouble later:
std::pair< container_type::iterator, bool > result =
--- 274,278 ----
/*
// this allows Breakpoints to be inserted arbitrarily
! // close together, which is no good, can cause trouble later:
std::pair< container_type::iterator, bool > result =
***************
*** 764,767 ****
--- 764,781 ----
}
+
+ // ---------------------------------------------------------------------------
+ // wrapPi
+ // ---------------------------------------------------------------------------
+ // O'Donnell's phase wrapping function.
+ //
+ static inline double wrapPi( double x )
+ {
+ using namespace std; // floor should be in std
+ #define ROUND(x) (floor(.5 + (x)))
+ const double TwoPi = 2.0*Pi;
+ return x + ( TwoPi * ROUND(-x/TwoPi) );
+ }
+
// ---------------------------------------------------------------------------
// phaseAt
***************
*** 790,810 ****
if ( it == begin() )
{
! // time is before the onset of the Partial:
double dp = 2. * Pi * (it.time() - time) * it.breakpoint().frequency();
! return std::fmod( it.breakpoint().phase() - dp, 2. * Pi);
}
else if (it == end() )
{
! // time is past the end of the Partial:
! // ( first decrement iterator to get the tail Breakpoint)
--it;
double dp = 2. * Pi * (time - it.time()) * it.breakpoint().frequency();
! return std::fmod( it.breakpoint().phase() + dp, 2. * Pi );
}
else
{
! // interpolate between it and its predeccessor
! // (we checked already that it is not begin):
const Breakpoint & hi = it.breakpoint();
double hitime = it.time();
--- 804,824 ----
if ( it == begin() )
{
! // time is before the onset of the Partial:
double dp = 2. * Pi * (it.time() - time) * it.breakpoint().frequency();
! return wrapPi( it.breakpoint().phase() - dp );
}
else if (it == end() )
{
! // time is past the end of the Partial:
! // ( first decrement iterator to get the tail Breakpoint)
--it;
double dp = 2. * Pi * (time - it.time()) * it.breakpoint().frequency();
! return wrapPi( it.breakpoint().phase() + dp );
}
else
{
! // interpolate between it and its predeccessor
! // (we checked already that it is not begin):
const Breakpoint & hi = it.breakpoint();
double hitime = it.time();
***************
*** 815,834 ****
( ( 1. - alpha ) * lo.frequency() );
! // need to keep fmod in here because other stuff
! // (Spc export and sdif export, for example) rely
! // on it:
! if ( alpha < 0.5 )
! {
! double favg = 0.5 * ( lo.frequency() + finterp );
! double dp = 2. * Pi * (time - lotime) * favg;
! return std::fmod( lo.phase() + dp, 2. * Pi );
! }
! else
! {
! double favg = 0.5 * ( hi.frequency() + finterp );
! double dp = 2. * Pi * (hitime - time) * favg;
! return std::fmod( hi.phase() - dp, 2. * Pi );
! }
!
}
}
--- 829,840 ----
( ( 1. - alpha ) * lo.frequency() );
! // frequency is interpolated to the specified time,
! // interpolated phase is computed from the frequency
! // and offset from the phase of the preceding Breakpoint:
! double favg = 0.5 * ( lo.frequency() + finterp );
! double dp = 2. * Pi * (time - lotime) * favg;
!
! // wrap phase, because other code depends on it:
! return wrapPi( lo.phase() + dp );
}
}
***************
*** 919,923 ****
double dp = 2. * Pi * (it.time() - time) * it.breakpoint().frequency();
! double ph = std::fmod( it.breakpoint().phase() - dp, 2. * Pi);
return Breakpoint( it.breakpoint().frequency(), amp,
--- 925,929 ----
double dp = 2. * Pi * (it.time() - time) * it.breakpoint().frequency();
! double ph = wrapPi( it.breakpoint().phase() - dp );
return Breakpoint( it.breakpoint().frequency(), amp,
***************
*** 941,945 ****
double dp = 2. * Pi * (time - it.time()) * it.breakpoint().frequency();
! double ph = std::fmod( it.breakpoint().phase() + dp, 2. * Pi );
return Breakpoint( it.breakpoint().frequency(), amp,
--- 947,951 ----
double dp = 2. * Pi * (time - it.time()) * it.breakpoint().frequency();
! double ph = wrapPi( it.breakpoint().phase() + dp );
return Breakpoint( it.breakpoint().frequency(), amp,
***************
*** 967,971 ****
double favg = 0.5 * ( lo.frequency() + finterp );
double dp = 2. * Pi * (time - lotime) * favg;
! ph = std::fmod( lo.phase() + dp, 2. * Pi );
}
else
--- 973,977 ----
double favg = 0.5 * ( lo.frequency() + finterp );
double dp = 2. * Pi * (time - lotime) * favg;
! ph = wrapPi( lo.phase() + dp );
}
else
***************
*** 973,977 ****
double favg = 0.5 * ( hi.frequency() + finterp );
double dp = 2. * Pi * (hitime - time) * favg;
! ph = std::fmod( hi.phase() - dp, 2. * Pi );
}
--- 979,983 ----
double favg = 0.5 * ( hi.frequency() + finterp );
double dp = 2. * Pi * (hitime - time) * favg;
! ph = wrapPi( hi.phase() - dp );
}
|