Sequencer - Identify overrides where inputs would cause trouble
This commit is contained in:
parent
ec34bcc9bb
commit
5080866cbe
3 changed files with 153 additions and 34 deletions
34
c-sync.cc
34
c-sync.cc
|
@ -254,6 +254,40 @@ float T_SyncCurve::computeValue(
|
||||||
return it->computeValue( timeUnits - prevSegStart );
|
return it->computeValue( timeUnits - prevSegStart );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E_SyncCurveMatch T_SyncCurve::matches(
|
||||||
|
T_SyncCurve const& other ) const noexcept
|
||||||
|
{
|
||||||
|
const auto tSegs{ this->segments.size( ) };
|
||||||
|
const auto oSegs{ other.segments.size( ) };
|
||||||
|
const auto nSegs{ std::min( tSegs , oSegs ) };
|
||||||
|
for ( auto i = 0u ; i < nSegs ; i ++ ) {
|
||||||
|
auto const& tDur{ this->segments[ i ].durations };
|
||||||
|
auto const& oDur{ other.segments[ i ].durations };
|
||||||
|
const bool lastSeg{ i == nSegs - 1 };
|
||||||
|
if ( !lastSeg && tDur.size( ) != oDur.size( ) ) {
|
||||||
|
return E_SyncCurveMatch::MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto nd{ std::min( tDur.size( ) , oDur.size( ) ) };
|
||||||
|
for ( auto j = 0u ; j < nd ; j ++ ) {
|
||||||
|
if ( tDur[ j ] != oDur[ j ] ) {
|
||||||
|
return E_SyncCurveMatch::MISMATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( tDur.size( ) != oDur.size( ) ) {
|
||||||
|
return tDur.size( ) < oDur.size( )
|
||||||
|
? E_SyncCurveMatch::LASTSEG_SHORT
|
||||||
|
: E_SyncCurveMatch::LASTSEG_LONG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( tSegs == oSegs ) {
|
||||||
|
return E_SyncCurveMatch::IDENTICAL;
|
||||||
|
}
|
||||||
|
return tSegs < oSegs
|
||||||
|
? E_SyncCurveMatch::MATCHING_SHORT
|
||||||
|
: E_SyncCurveMatch::MATCHING_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*= T_SyncCurves =============================================================*/
|
/*= T_SyncCurves =============================================================*/
|
||||||
|
|
||||||
|
|
34
c-sync.hh
34
c-sync.hh
|
@ -51,6 +51,34 @@ struct T_SyncSegment
|
||||||
};
|
};
|
||||||
M_LSHIFT_OP( T_StringBuilder , T_SyncSegment::E_SegmentType );
|
M_LSHIFT_OP( T_StringBuilder , T_SyncSegment::E_SegmentType );
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Possible results when trying to check whether two curves have a similar
|
||||||
|
// structure.
|
||||||
|
enum class E_SyncCurveMatch
|
||||||
|
{
|
||||||
|
// Both curves have the same structure.
|
||||||
|
IDENTICAL ,
|
||||||
|
|
||||||
|
// One of the curves has less information than the other, but the
|
||||||
|
// information in the shortest curve matches the corresponding
|
||||||
|
// information in the longest curve (i.e. it is only missing
|
||||||
|
// segments). _SHORT/_LONG indicate that the curve for which the
|
||||||
|
// comparison method was called is the shortest/longest (resp.)
|
||||||
|
MATCHING_SHORT ,
|
||||||
|
MATCHING_LONG ,
|
||||||
|
|
||||||
|
// One of the curves has less information than the other, and its
|
||||||
|
// last segment is shorter than the corresponding segment in the
|
||||||
|
// longest record (but its end matches a point in the longest curve's
|
||||||
|
// segment).
|
||||||
|
LASTSEG_SHORT ,
|
||||||
|
LASTSEG_LONG ,
|
||||||
|
|
||||||
|
// The curves do not match.
|
||||||
|
MISMATCH
|
||||||
|
};
|
||||||
|
|
||||||
// An input curve
|
// An input curve
|
||||||
struct T_SyncCurve
|
struct T_SyncCurve
|
||||||
{
|
{
|
||||||
|
@ -69,8 +97,14 @@ struct T_SyncCurve
|
||||||
|
|
||||||
// Compute the value at the specified time.
|
// Compute the value at the specified time.
|
||||||
float computeValue( float timeUnits ) const noexcept;
|
float computeValue( float timeUnits ) const noexcept;
|
||||||
|
|
||||||
|
// Compare this curve to another.
|
||||||
|
E_SyncCurveMatch matches(
|
||||||
|
T_SyncCurve const& other ) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
// All configured curves. Some may not actually correspond to an input and may
|
// All configured curves. Some may not actually correspond to an input and may
|
||||||
// have been defined for inputs that have been removed temporarily (e.g.
|
// have been defined for inputs that have been removed temporarily (e.g.
|
||||||
// because some include was commented out), in which case we don't want to
|
// because some include was commented out), in which case we don't want to
|
||||||
|
|
119
ui-sequencer.cc
119
ui-sequencer.cc
|
@ -259,6 +259,7 @@ struct T_SyncViewImpl_
|
||||||
void displayInputSelector( ) noexcept;
|
void displayInputSelector( ) noexcept;
|
||||||
void displayOverrideSelector( ) noexcept;
|
void displayOverrideSelector( ) noexcept;
|
||||||
|
|
||||||
|
// Selection display/edition windows
|
||||||
void displayTrackWindow( ) noexcept;
|
void displayTrackWindow( ) noexcept;
|
||||||
void displaySegmentWindow( ) noexcept;
|
void displaySegmentWindow( ) noexcept;
|
||||||
void displayPointWindow( ) noexcept;
|
void displayPointWindow( ) noexcept;
|
||||||
|
@ -1321,6 +1322,24 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An override can be selected directly if the inputs that are part of
|
||||||
|
* it are consistent.
|
||||||
|
*
|
||||||
|
* A pair of inputs are consistent if
|
||||||
|
* - one or both inputs do not have curve information attached;
|
||||||
|
* - the durations and segment boundaries of the shortest curve
|
||||||
|
* attached to the inputs match the boundaries and durations from the
|
||||||
|
* other input's curve OR the last segment is shorter but its end
|
||||||
|
* matches the location of one of the points in the corresponding
|
||||||
|
* segment of the other curve.
|
||||||
|
*
|
||||||
|
* If the inputs are not consistent, it will be necessary to reset
|
||||||
|
* some of their curves; best option would be to try and be clever, but
|
||||||
|
* a temporary measure (resetting all curves to match the structure of
|
||||||
|
* the first longest curve) would work.
|
||||||
|
*/
|
||||||
|
|
||||||
BeginChild( "content" );
|
BeginChild( "content" );
|
||||||
Common::Sync( ).visitOverrides( [&]( T_SyncOverrideVisitor::T_Element element , const bool exit ) {
|
Common::Sync( ).visitOverrides( [&]( T_SyncOverrideVisitor::T_Element element , const bool exit ) {
|
||||||
if ( element.hasType< T_SyncOverrideSection* >( ) ) {
|
if ( element.hasType< T_SyncOverrideSection* >( ) ) {
|
||||||
|
@ -1330,47 +1349,79 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
|
||||||
}
|
}
|
||||||
if ( exit ) {
|
if ( exit ) {
|
||||||
TreePop( );
|
TreePop( );
|
||||||
} else {
|
return true;
|
||||||
return TreeNodeEx( &sos.cTitle[ 0 ] ,
|
|
||||||
ImGuiTreeNodeFlags_DefaultOpen );
|
|
||||||
}
|
}
|
||||||
} else if ( exit ) {
|
return TreeNodeEx( &sos.cTitle[ 0 ] ,
|
||||||
auto const& ov{ *element.value< A_SyncOverride* >( ) };
|
ImGuiTreeNodeFlags_DefaultOpen );
|
||||||
auto const& id{ ov.id( ) };
|
}
|
||||||
auto const& in{ ov.inputNames( ) };
|
if ( ! exit ) {
|
||||||
const bool present{ sOverrides.contains( id ) };
|
return false;
|
||||||
const bool hasCurves{ !present && [&](){
|
}
|
||||||
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
|
||||||
if ( sCurves.contains( in[ i ] ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}() };
|
|
||||||
|
|
||||||
if ( hasCurves ) {
|
auto const& ov{ *element.value< A_SyncOverride* >( ) };
|
||||||
PushDisabled( );
|
auto const& id{ ov.id( ) };
|
||||||
}
|
auto const& in{ ov.inputNames( ) };
|
||||||
|
const bool present{ sOverrides.contains( id ) };
|
||||||
bool select{ present };
|
const bool hasCurves{ !present && [&](){
|
||||||
if ( Checkbox( ov.title( ) , &select ) ) {
|
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
||||||
if ( select ) {
|
if ( sCurves.contains( in[ i ] ) ) {
|
||||||
sOverrides.add( id );
|
return true;
|
||||||
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
|
||||||
sCurves.add( in[ i ] , true );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sOverrides.remove( id );
|
|
||||||
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
|
||||||
sCurves.remove( in[ i ] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}() };
|
||||||
|
|
||||||
if ( hasCurves ) {
|
// FIXME MOVE THIS \/ //
|
||||||
PopDisabled( );
|
bool bad{ false };
|
||||||
|
for ( auto i = 0u ; i < in.size( ) - 1 && !bad ; i ++ ) {
|
||||||
|
T_SyncCurve const* const c0{
|
||||||
|
Common::Sync( ).getCurve( in[ i ] )
|
||||||
|
};
|
||||||
|
if ( !c0 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for ( auto j = i + 1 ; j < in.size( ) && !bad ; j ++ ) {
|
||||||
|
T_SyncCurve const* const c1{
|
||||||
|
Common::Sync( ).getCurve( in[ j ] )
|
||||||
|
};
|
||||||
|
if ( !c1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto res{ c0->matches( *c1 ) };
|
||||||
|
bad = ( res == E_SyncCurveMatch::MISMATCH );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME MOVE THIS /\ //
|
||||||
|
|
||||||
|
if ( hasCurves ) {
|
||||||
|
PushDisabled( );
|
||||||
|
}
|
||||||
|
if ( bad ) {
|
||||||
|
PushStyleColor( ImGuiCol_Text , 0xff0000ff );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool select{ present };
|
||||||
|
if ( Checkbox( ov.title( ) , &select ) ) {
|
||||||
|
if ( select ) {
|
||||||
|
sOverrides.add( id );
|
||||||
|
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
||||||
|
sCurves.add( in[ i ] , true );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sOverrides.remove( id );
|
||||||
|
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
|
||||||
|
sCurves.remove( in[ i ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bad ) {
|
||||||
|
PopStyleColor( );
|
||||||
|
}
|
||||||
|
if ( hasCurves ) {
|
||||||
|
PopDisabled( );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
EndChild( );
|
EndChild( );
|
||||||
|
|
Loading…
Reference in a new issue