669 lines
17 KiB
C++
669 lines
17 KiB
C++
#include "externals.hh"
|
|
|
|
#include "common.hh"
|
|
#include "c-syncedit.hh"
|
|
|
|
|
|
/*= T_UndoSyncChanges ========================================================*/
|
|
|
|
void T_UndoSyncChanges::undo( ) const noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
const auto n{ changes_.size( ) };
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
auto const& c( changes_[ i ] );
|
|
if ( c.before ) {
|
|
sync.setCurve( *c.before );
|
|
} else {
|
|
sync.removeCurve( c.inputId );
|
|
}
|
|
}
|
|
}
|
|
|
|
void T_UndoSyncChanges::redo( ) const noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
const auto n{ changes_.size( ) };
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
auto const& c( changes_[ i ] );
|
|
if ( c.after ) {
|
|
sync.setCurve( *c.after );
|
|
} else {
|
|
sync.removeCurve( c.inputId );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
T_UndoSyncChanges& T_UndoSyncChanges::curveCreation(
|
|
T_SyncCurve curve ) noexcept
|
|
{
|
|
#ifndef NDEBUG
|
|
{
|
|
const auto n{ changes_.size( ) };
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
assert( changes_[ i ].inputId != curve.name );
|
|
}
|
|
}
|
|
#endif
|
|
changes_.addNew( true , std::move( curve ) );
|
|
return *this;
|
|
}
|
|
|
|
T_UndoSyncChanges& T_UndoSyncChanges::curveDeletion(
|
|
T_SyncCurve curve ) noexcept
|
|
{
|
|
#ifndef NDEBUG
|
|
{
|
|
const auto n{ changes_.size( ) };
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
assert( changes_[ i ].inputId != curve.name );
|
|
}
|
|
}
|
|
#endif
|
|
changes_.addNew( std::move( curve ) );
|
|
return *this;
|
|
}
|
|
|
|
T_UndoSyncChanges& T_UndoSyncChanges::curveReplacement(
|
|
T_SyncCurve before ,
|
|
T_SyncCurve after ) noexcept
|
|
{
|
|
assert( before.name == after.name );
|
|
#ifndef NDEBUG
|
|
{
|
|
const auto n{ changes_.size( ) };
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
assert( changes_[ i ].inputId != before.name );
|
|
}
|
|
}
|
|
#endif
|
|
changes_.addNew( std::move( before ) , std::move( after ) );
|
|
return *this;
|
|
}
|
|
|
|
|
|
/*= T_UndoDurationChanges ====================================================*/
|
|
|
|
T_UndoDurationChanges::T_UndoDurationChanges(
|
|
const uint32_t units ,
|
|
const uint32_t oldUnits ,
|
|
const float unitSize ,
|
|
const float oldUnitSize ) noexcept
|
|
: T_UndoSyncChanges( ) ,
|
|
unitsBefore_{ oldUnits } ,
|
|
unitsAfter_{ units } ,
|
|
uSizeBefore_{ oldUnitSize } ,
|
|
uSizeAfter_{ unitSize }
|
|
{ }
|
|
|
|
void T_UndoDurationChanges::undo( ) const noexcept
|
|
{
|
|
Common::Sync( ).setDuration( uSizeBefore_ , unitsBefore_ );
|
|
T_UndoSyncChanges::undo( );
|
|
}
|
|
|
|
void T_UndoDurationChanges::redo( ) const noexcept
|
|
{
|
|
Common::Sync( ).setDuration( uSizeAfter_ , unitsAfter_ );
|
|
T_UndoSyncChanges::redo( );
|
|
}
|
|
|
|
|
|
/*= SyncEditor ===============================================================*/
|
|
|
|
namespace {
|
|
|
|
T_SyncCurve SESDScaleCurve_(
|
|
const float uSizeBefore ,
|
|
const float uSizeAfter ,
|
|
T_SyncCurve const& curve ) noexcept
|
|
{
|
|
T_SyncCurve nCurve;
|
|
nCurve.name = curve.name;
|
|
for ( auto const& segment : curve.segments ) {
|
|
const auto nsid{ nCurve.segments.add( segment ) };
|
|
T_SyncSegment& nSeg{ nCurve.segments[ nsid ] };
|
|
const auto nd{ nSeg.durations.size( ) };
|
|
for ( auto i = 0u ; i < nd ; i ++ ) {
|
|
const float duration{ nSeg.durations[ i ] * uSizeBefore };
|
|
nSeg.durations[ i ] = std::max( 1u , uint32_t( std::roundf(
|
|
duration / uSizeAfter ) ) );
|
|
#if 0
|
|
printf( "initial duration %f (%d units) ; new duration %f (%d units)\n" ,
|
|
duration , segment.durations[ i ] ,
|
|
uSizeAfter * nSeg.durations[ i ] ,
|
|
nSeg.durations[ i ] );
|
|
#endif
|
|
}
|
|
}
|
|
return nCurve;
|
|
}
|
|
|
|
} // namespace <anon>
|
|
|
|
void SyncEditor::SetDuration(
|
|
const uint32_t units ,
|
|
const float uSize ,
|
|
const bool scaleCurves ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
const float oldUnitSize{ sync.durationUnitSize( ) };
|
|
const uint32_t oldUnits{ sync.durationUnits( ) };
|
|
if ( oldUnits == units && oldUnitSize == uSize ) {
|
|
return;
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoDurationChanges& >(
|
|
Common::Undo( ).add< T_UndoDurationChanges >(
|
|
units , oldUnits ,
|
|
uSize , oldUnitSize ) ) };
|
|
sync.setDuration( uSize , units );
|
|
if ( !scaleCurves || uSize == oldUnitSize ) {
|
|
return;
|
|
}
|
|
|
|
auto const& curves( sync.curves( ) );
|
|
for ( auto const& curve : curves ) {
|
|
auto nc{ SESDScaleCurve_( oldUnitSize , uSize , curve ) };
|
|
undo.curveReplacement( curve , nc );
|
|
sync.setCurve( std::move( nc ) );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::ReplaceCurve(
|
|
T_SyncCurve replacement ) noexcept
|
|
{
|
|
auto* const curve{ Common::Sync( ).getCurve( replacement.name ) };
|
|
if ( !curve ) {
|
|
return;
|
|
}
|
|
|
|
// Create undo entry
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
undo.curveReplacement( *curve , replacement );
|
|
Common::Sync( ).setCurve( std::move( replacement ) );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::DeleteCurve(
|
|
T_SyncTrackId const& id ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
|
|
auto const* const ovr{ id.isOverride ? sync.getOverride( id.id ) : nullptr };
|
|
if ( id.isOverride && !ovr ) {
|
|
return;
|
|
}
|
|
|
|
const uint32_t nCurves{ ovr ? ovr->inputNames( ).size( ) : 1 };
|
|
T_String cNames[ nCurves ];
|
|
if ( ovr ) {
|
|
bool hasNonNull{ false };
|
|
for ( auto i = 0u ; i < nCurves ; i ++ ) {
|
|
cNames[ i ] = ovr->inputNames( )[ i ];
|
|
hasNonNull = hasNonNull || sync.getCurve( cNames[ i ] );
|
|
}
|
|
if ( !hasNonNull ) {
|
|
return;
|
|
}
|
|
} else {
|
|
if ( !sync.getCurve( id.id ) ) {
|
|
return;
|
|
}
|
|
cNames[ 0 ] = id.id;
|
|
}
|
|
|
|
// Create undo entry
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
|
|
// Delete curves
|
|
for ( T_String const& cn : cNames ) {
|
|
auto const* const curve{ sync.getCurve( cn ) };
|
|
if ( curve ) {
|
|
undo.curveDeletion( *curve );
|
|
Common::Sync( ).removeCurve( cn );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::AppendSegment(
|
|
T_SyncTrackId const& id ,
|
|
uint32_t nsDuration ) noexcept
|
|
{
|
|
assert( nsDuration > 0 );
|
|
|
|
auto& sync{ Common::Sync( ) };
|
|
|
|
auto const* const ovr{ id.isOverride ? sync.getOverride( id.id ) : nullptr };
|
|
if ( id.isOverride && !ovr ) {
|
|
return;
|
|
}
|
|
|
|
const uint32_t nCurves{ ovr ? ovr->inputNames( ).size( ) : 1 };
|
|
T_SyncCurve const* curves[ nCurves ];
|
|
T_String cNames[ nCurves ];
|
|
if ( ovr ) {
|
|
for ( auto i = 0u ; i < nCurves ; i ++ ) {
|
|
cNames[ i ] = ovr->inputNames( )[ i ];
|
|
curves[ i ] = sync.getCurve( cNames[ i ] );
|
|
}
|
|
} else {
|
|
cNames[ 0 ] = id.id;
|
|
curves[ 0 ] = sync.getCurve( id.id );
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
|
|
for ( auto i = 0u ; i < nCurves ; i ++ ) {
|
|
auto const* const curve{ curves[ i ] };
|
|
if ( curve && !curve->segments.empty( ) ) {
|
|
const float lastValue{ [&](){
|
|
auto const& lSeg{ curve->segments.last( ) };
|
|
return lSeg.values.last( );
|
|
}( ) };
|
|
auto nCurve{ *curve };
|
|
auto& nSeg{ nCurve.segments.addNew( ) };
|
|
nSeg.type = T_SyncSegment::LINEAR;
|
|
nSeg.values.add( lastValue );
|
|
nSeg.values.add( lastValue );
|
|
nSeg.durations.add( nsDuration );
|
|
|
|
undo.curveReplacement( *curve , nCurve );
|
|
sync.setCurve( std::move( nCurve ) );
|
|
} else {
|
|
T_SyncCurve nCurve;
|
|
nCurve.name = cNames[ i ];
|
|
|
|
const auto value{ sync.inputs( )[
|
|
sync.inputPos( cNames[ i ] ) ] };
|
|
auto& nSeg{ nCurve.segments.addNew( ) };
|
|
nSeg.type = T_SyncSegment::LINEAR;
|
|
nSeg.values.add( value );
|
|
nSeg.values.add( value );
|
|
nSeg.durations.add( nsDuration );
|
|
|
|
undo.curveCreation( nCurve );
|
|
sync.setCurve( std::move( nCurve ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::DeleteSegment(
|
|
T_SyncTrackId const& id ,
|
|
const uint32_t segmentIndex ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
|
|
auto const* const ovr{ id.isOverride ? sync.getOverride( id.id ) : nullptr };
|
|
if ( id.isOverride && !ovr ) {
|
|
return;
|
|
}
|
|
|
|
const auto nc{ ovr ? ovr->inputNames( ).size( ) : 1 };
|
|
T_SyncCurve const* curves[ nc ];
|
|
if ( ovr ) {
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
curves[ i ] = sync.getCurve( ovr->inputNames( )[ i ] );
|
|
}
|
|
} else {
|
|
curves[ 0 ] = sync.getCurve( id.id );
|
|
}
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
if ( !curves[ i ] || segmentIndex >= curves[ i ]->segments.size( ) ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
if ( curves[ i ]->segments.size( ) == 1 ) {
|
|
undo.curveDeletion( *curves[ i ] );
|
|
sync.removeCurve( curves[ i ]->name );
|
|
} else {
|
|
auto nCurve{ *curves[ i ] };
|
|
nCurve.segments.remove( segmentIndex );
|
|
undo.curveReplacement( *curves[ i ] , nCurve );
|
|
sync.setCurve( std::move( nCurve ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::SetSegmentType(
|
|
T_SyncCurve const& initial ,
|
|
const uint32_t segmentIndex ,
|
|
const T_SyncSegment::E_SegmentType newType ) noexcept
|
|
{
|
|
assert( segmentIndex < initial.segments.size( ) );
|
|
T_SyncSegment const& iSegment{ initial.segments[ segmentIndex ] };
|
|
if ( iSegment.type == newType ) {
|
|
return;
|
|
}
|
|
|
|
// Create new curve
|
|
T_SyncCurve copy{ initial };
|
|
copy.segments[ segmentIndex ].type = newType;
|
|
|
|
// Create undo entry
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
undo.curveReplacement( initial , copy );
|
|
|
|
// Replace curve
|
|
Common::Sync( ).setCurve( std::move( copy ) );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::SetSegmentTypes(
|
|
A_SyncOverride const& ovr ,
|
|
const uint32_t segmentIndex ,
|
|
const T_SyncSegment::E_SegmentType newType ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
auto const& iNames{ ovr.inputNames( ) };
|
|
const auto nc{ iNames.size( ) };
|
|
{
|
|
auto nSame{ 0u };
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
auto const* const c{ sync.getCurve( iNames[ i ] ) };
|
|
assert( c );
|
|
assert( segmentIndex < c->segments.size( ) );
|
|
T_SyncSegment const& iSegment{ c->segments[ segmentIndex ] };
|
|
if ( iSegment.type == newType ) {
|
|
nSame ++;
|
|
}
|
|
}
|
|
if ( nSame == nc ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
auto const* const c{ sync.getCurve( iNames[ i ] ) };
|
|
if ( c->segments[ segmentIndex ].type == newType ) {
|
|
continue;
|
|
}
|
|
T_SyncCurve copy{ *c };
|
|
copy.segments[ segmentIndex ].type = newType;
|
|
undo.curveReplacement( *c , copy );
|
|
sync.setCurve( std::move( copy ) );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::InsertPoint(
|
|
T_SyncTrackId const& id ,
|
|
const uint32_t segmentIndex ,
|
|
const uint32_t pointIndex ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
auto const* const ovr{ id.isOverride ? sync.getOverride( id.id ) : nullptr };
|
|
if ( id.isOverride && !ovr ) {
|
|
return;
|
|
}
|
|
|
|
const auto nc{ ovr ? ovr->inputNames( ).size( ) : 1 };
|
|
T_SyncCurve const* curves[ nc ];
|
|
if ( ovr ) {
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
curves[ i ] = sync.getCurve( ovr->inputNames( )[ i ] );
|
|
}
|
|
} else {
|
|
curves[ 0 ] = sync.getCurve( id.id );
|
|
}
|
|
|
|
for ( auto const* curve : curves ) {
|
|
if ( !curve || segmentIndex >= curve->segments.size( ) ) {
|
|
return;
|
|
}
|
|
auto const& segment{ curve->segments[ segmentIndex ] };
|
|
if ( pointIndex == 0 || pointIndex > segment.values.size( )
|
|
|| segment.durations[ pointIndex - 1 ] == 1 ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
|
|
for ( auto const* curve : curves ) {
|
|
auto c{ *curve };
|
|
auto& ns{ c.segments[ segmentIndex ] };
|
|
|
|
const auto hd{ ns.durations[ pointIndex - 1 ] / 2 };
|
|
const float hv{ ns.computeValue( ns.findTimeOfPoint( pointIndex - 1 ) + hd ) };
|
|
|
|
ns.durations[ pointIndex - 1 ] -= hd;
|
|
ns.durations.insert( pointIndex - 1 , hd );
|
|
ns.values.insert( pointIndex , hv );
|
|
undo.curveReplacement( *curve , c );
|
|
sync.setCurve( std::move( c ) );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void SyncEditor::DeletePoint(
|
|
T_SyncTrackId const& id ,
|
|
const uint32_t segmentIndex ,
|
|
const uint32_t pointIndex ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
auto const* const ovr{ id.isOverride ? sync.getOverride( id.id ) : nullptr };
|
|
if ( id.isOverride && !ovr ) {
|
|
return;
|
|
}
|
|
|
|
const auto nc{ ovr ? ovr->inputNames( ).size( ) : 1 };
|
|
T_SyncCurve const* curves[ nc ];
|
|
if ( ovr ) {
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
curves[ i ] = sync.getCurve( ovr->inputNames( )[ i ] );
|
|
}
|
|
} else {
|
|
curves[ 0 ] = sync.getCurve( id.id );
|
|
}
|
|
|
|
for ( auto const* curve : curves ) {
|
|
if ( !curve || segmentIndex >= curve->segments.size( ) ) {
|
|
return;
|
|
}
|
|
auto const& segment{ curve->segments[ segmentIndex ] };
|
|
if ( pointIndex == 0 || pointIndex >= segment.values.size( ) ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
for ( auto const* curve : curves ) {
|
|
auto c{ *curve };
|
|
auto& ns{ c.segments[ segmentIndex ] };
|
|
ns.durations[ pointIndex ] += ns.durations[ pointIndex - 1 ];
|
|
ns.durations.remove( pointIndex - 1 );
|
|
ns.values.remove( pointIndex );
|
|
|
|
undo.curveReplacement( *curve , c );
|
|
sync.setCurve( std::move( c ) );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
namespace {
|
|
|
|
bool MOCRequiresChanges_(
|
|
ebcl::T_Set< T_String > const& iNames ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
const auto nInputs{ iNames.size( ) };
|
|
|
|
for ( auto i = 0u ; i < nInputs ; i ++ ) {
|
|
auto const* const c0{ sync.getCurve( iNames[ i ] ) };
|
|
if ( !c0 ) {
|
|
continue;
|
|
}
|
|
for ( auto j = i + 1 ; j < nInputs ; j ++ ) {
|
|
auto const* const c1{ sync.getCurve( iNames[ j ] ) };
|
|
if ( !c1 || c1->matches( *c0 ) != E_SyncCurveMatch::IDENTICAL ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
T_SyncCurve const& MOCFindLongest_(
|
|
ebcl::T_Set< T_String > const& iNames ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
const auto nInputs{ iNames.size( ) };
|
|
uint32_t longestLen{ 0 };
|
|
T_SyncCurve const* longest{ nullptr };
|
|
for ( auto i = 0u ; i < nInputs ; i ++ ) {
|
|
auto const* const c{ sync.getCurve( iNames[ i ] ) };
|
|
const auto l{ c ? c->points( ) : 0 };
|
|
if ( l > longestLen ) {
|
|
longestLen = l;
|
|
longest = c;
|
|
}
|
|
}
|
|
assert( longest );
|
|
return *longest;
|
|
}
|
|
|
|
}
|
|
|
|
void SyncEditor::MakeOverrideConsistent(
|
|
T_String const& id ) noexcept
|
|
{
|
|
auto& sync{ Common::Sync( ) };
|
|
auto const* const src{ sync.getOverride( id ) };
|
|
if ( !src ) {
|
|
return;
|
|
}
|
|
|
|
// Check whether it's actually necessary to enact changes
|
|
if ( !MOCRequiresChanges_( src->inputNames( ) ) ) {
|
|
return;
|
|
}
|
|
|
|
// Prepate undo structure
|
|
auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
|
|
Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
|
|
|
|
// Find longest curve
|
|
auto const& iNames{ src->inputNames( ) };
|
|
const auto nInputs{ iNames.size( ) };
|
|
T_SyncCurve const& longest{ MOCFindLongest_( iNames ) };
|
|
|
|
// For other curves:
|
|
for ( auto i = 0u ; i < nInputs ; i ++ ) {
|
|
auto const& name{ iNames[ i ] };
|
|
if ( name == longest.name ) {
|
|
continue;
|
|
}
|
|
T_SyncCurve const* const ori{ sync.getCurve( iNames[ i ] ) };
|
|
|
|
if ( !ori ) {
|
|
// If missing, create it with the same structure
|
|
const float v{ sync.inputs( )[ sync.inputPos( iNames[ i ] ) ] };
|
|
T_SyncCurve nc;
|
|
nc.name = name;
|
|
for ( auto const& ss : longest.segments ) {
|
|
auto& ns{ nc.segments.addNew( ) };
|
|
ns.type = ss.type;
|
|
ns.durations = ss.durations;
|
|
ns.values.resize( ss.values.size( ) , v );
|
|
}
|
|
sync.setCurve( nc );
|
|
undo.curveCreation( std::move( nc ) );
|
|
continue;
|
|
}
|
|
|
|
// If identical, don't change anything
|
|
const auto diff{ ori->matches( longest ) };
|
|
assert( diff != E_SyncCurveMatch::LASTSEG_LONG
|
|
&& diff != E_SyncCurveMatch::MATCHING_LONG );
|
|
if ( diff == E_SyncCurveMatch::IDENTICAL ) {
|
|
continue;
|
|
}
|
|
|
|
T_SyncCurve nc;
|
|
nc.name = name;
|
|
if ( diff == E_SyncCurveMatch::MISMATCH ) {
|
|
// Recreate it completely, keeping the values but using
|
|
// the timings from the longest curve.
|
|
auto oss{ 0u } , osp{ 0u };
|
|
auto lv{ 0.f };
|
|
|
|
for ( auto const& ss : longest.segments ) {
|
|
auto& ns{ nc.segments.addNew( ) };
|
|
ns.type = ss.type;
|
|
ns.durations = ss.durations;
|
|
for ( auto j = 0u ; j < ss.values.size( ) ; j ++ ) {
|
|
if ( oss < ori->segments.size( ) ) {
|
|
lv = ori->segments[ oss ].values[ osp++ ];
|
|
if ( osp == ori->segments[ oss ].values.size( ) ) {
|
|
osp = 0;
|
|
oss ++;
|
|
}
|
|
}
|
|
ns.values.add( lv );
|
|
}
|
|
}
|
|
|
|
undo.curveReplacement( *ori , nc );
|
|
sync.setCurve( std::move( nc ) );
|
|
continue;
|
|
}
|
|
assert( diff == E_SyncCurveMatch::LASTSEG_SHORT
|
|
|| diff == E_SyncCurveMatch::MATCHING_SHORT );
|
|
|
|
// Copy the segments from the original, as they match.
|
|
for ( auto const& os : ori->segments ) {
|
|
nc.segments.add( os );
|
|
}
|
|
|
|
if ( diff == E_SyncCurveMatch::LASTSEG_SHORT ) {
|
|
// The last segment is too short, repeat last value
|
|
// with the correct durations
|
|
auto const& ols{ longest.segments[ nc.segments.size( ) - 1 ] };
|
|
auto& ls{ nc.segments.last( ) };
|
|
while ( ls.durations.size( ) < ols.durations.size( ) ) {
|
|
ls.durations.add( ols.durations[ ls.durations.size( ) ] );
|
|
ls.values.add( ls.values.last( ) );
|
|
}
|
|
}
|
|
|
|
// Add missing segments
|
|
const float lv{ nc.segments.last( ).values.last( ) };
|
|
while ( nc.segments.size( ) < longest.segments.size( ) ) {
|
|
auto const& os{ longest.segments[ nc.segments.size( ) - 1 ] };
|
|
auto& ns{ nc.segments.addNew( ) };
|
|
ns.type = os.type;
|
|
ns.durations = os.durations;
|
|
ns.values.resize( os.values.size( ) , lv );
|
|
}
|
|
undo.curveReplacement( *ori , nc );
|
|
sync.setCurve( std::move( nc ) );
|
|
}
|
|
}
|