📄 phonemeeditor_closecaption.cpp
字号:
SetDirty( true );
PushUndo();
TraversePhrases( ITER_MoveSelectedPhrases, dt );
CloseCaption_CleanupPhrases( false );
PushRedo();
redraw();
}
int PhonemeEditor::CloseCaption_FindPhraseForTime( float time )
{
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *pCurrent = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( time < pCurrent->GetStartTime() )
continue;
if ( time > pCurrent->GetEndTime() )
continue;
return i;
}
return -1;
}
void PhonemeEditor::CloseCaption_DeselectPhrases( void )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
for ( int i = 0 ; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *w = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
Assert( w );
w->SetSelected( false );
}
}
void PhonemeEditor::CloseCaption_SnapPhrases( void )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )- 1; i++ )
{
CCloseCaptionPhrase *current = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
CCloseCaptionPhrase *next = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i + 1 );
if ( !current->GetSelected() || !next->GetSelected() )
continue;
// Move next phrase to end of current
next->SetStartTime( current->GetEndTime() );
}
redraw();
}
void PhonemeEditor::CloseCaption_SeparatePhrases( void )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
// Three pixels
double time_epsilon = ( 1.0f / GetPixelsPerSecond() ) * 6;
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )- 1; i++ )
{
CCloseCaptionPhrase *current = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
CCloseCaptionPhrase *next = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i + 1 );
if ( !current->GetSelected() || !next->GetSelected() )
continue;
// Close enough?
if ( fabs( current->GetEndTime() - next->GetStartTime() ) > time_epsilon )
{
Con_Printf( "Can't split %s and %s, already split apart\n",
current->GetStream(), next->GetStream() );
continue;
}
// Offset next phrase start time a bit
next->SetStartTime( next->GetStartTime() + time_epsilon );
break;
}
redraw();
}
CCloseCaptionPhrase *PhonemeEditor::CloseCaption_GetPhraseUnderMouse( int mx, int my )
{
if ( GetMode() != MODE_CLOSECAPTION )
return NULL;
// Deterime if phoneme boundary is under the cursor
//
if ( !m_pWaveFile )
return NULL;
RECT rc;
GetWorkspaceRect( rc );
if ( !CloseCaption_IsMouseOverRow( my ) )
return NULL;
float starttime = m_nLeftOffset / GetPixelsPerSecond();
float endtime = w2() / GetPixelsPerSecond() + starttime;
for ( int k = 0; k < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); k++ )
{
CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, k );
float t1 = phrase->GetStartTime();
float t2 = phrase->GetEndTime();
float frac1 = ( t1 - starttime ) / ( endtime - starttime );
float frac2 = ( t2 - starttime ) / ( endtime - starttime );
frac1 = min( 1.0f, frac1 );
frac1 = max( 0.0f, frac1 );
frac2 = min( 1.0f, frac2 );
frac2 = max( 0.0f, frac2 );
if ( frac1 == frac2 )
continue;
int x1 = ( int )( frac1 * w2() );
int x2 = ( int )( frac2 * w2() );
if ( mx >= x1 && mx <= x2 )
{
return phrase;
}
}
return NULL;
}
void PhonemeEditor::CloseCaption_GetTrayTopBottom( RECT& rc )
{
RECT wkrc;
GetWorkspaceRect( wkrc );
int workspaceheight = wkrc.bottom - wkrc.top;
rc.top = wkrc.top + workspaceheight/ 2 + 2;
rc.bottom = rc.top + ( m_nTickHeight + 2 );
}
void PhonemeEditor::CloseCaption_GetPhraseRect( const CCloseCaptionPhrase *phrase, RECT& rc )
{
CloseCaption_GetTrayTopBottom( rc );
rc.left = GetMouseForTime( phrase->GetStartTime() );
rc.right = GetMouseForTime( phrase->GetEndTime() );
}
CCloseCaptionPhrase *PhonemeEditor::CloseCaption_GetClickedPhrase( void )
{
if ( m_nClickedPhrase < 0 )
return NULL;
if ( m_nClickedPhrase >= m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ))
return NULL;
CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, m_nClickedPhrase );
return phrase;
}
int PhonemeEditor::CloseCaption_GetClickedPhraseToken( void )
{
if ( !CloseCaption_GetClickedPhrase() )
return -1;
return m_nClickedPhraseToken;
}
void PhonemeEditor::CloseCaption_SelectNextPhrase( int direction )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
CountSelected();
if ( m_nSelectedPhraseCount != 1 )
{
// Selected first phrase then
if ( m_nSelectedPhraseCount == 0 && m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )> 0 )
{
CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, direction ? m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )- 1 : 0 );
phrase->SetSelected( true );
m_nSelectedPhraseCount = 1;
}
else
{
return;
}
}
Con_Printf( "Move to next phrase %s\n", direction == -1 ? "left" : "right" );
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( !phrase )
continue;
if ( m_nSelectedPhraseCount == 1 )
{
if ( !phrase->GetSelected() )
continue;
}
// Deselect phrase
phrase->SetSelected( false );
// Deselect this one and move
int nextphrase = i + direction;
if ( nextphrase < 0 )
{
nextphrase = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )- 1;
}
else if ( nextphrase >= m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ))
{
nextphrase = 0;
}
phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, nextphrase );
phrase->SetSelected( true );
redraw();
return;
}
}
void PhonemeEditor::CloseCaption_ShiftSelectedPhrase( int direction )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
CountSelected();
switch ( m_nSelectedPhraseCount )
{
case 1:
break;
case 0:
Con_Printf( "Can't shift phrases, none selected\n" );
return;
default:
Con_Printf( "Can only shift one phrase at a time via keyboard\n" );
return;
}
RECT rc;
GetWorkspaceRect( rc );
// Determine start/stop positions
int totalsamples = (int)( m_pWaveFile->GetRunningLength() * m_pWaveFile->SampleRate() );
float starttime = m_nLeftOffset / GetPixelsPerSecond();
float endtime = w2() / GetPixelsPerSecond() + starttime;
float timeperpixel = ( endtime - starttime ) / (float)( rc.right - rc.left );
float movetime = timeperpixel * (float)direction;
float maxmove = CloseCaption_ComputeMaxPhraseShift( direction > 0 ? true : false, false );
if ( direction > 0 )
{
if ( movetime > maxmove )
{
movetime = maxmove;
Con_Printf( "Further shift is blocked on right\n" );
}
}
else
{
if ( movetime < -maxmove )
{
movetime = -maxmove;
Con_Printf( "Further shift is blocked on left\n" );
}
}
if ( fabs( movetime ) < 0.0001f )
return;
SetDirty( true );
PushUndo();
TraversePhrases( ITER_MoveSelectedPhrases, movetime );
PushRedo();
redraw();
Con_Printf( "Shift phrase %s\n", direction == -1 ? "left" : "right" );
}
void PhonemeEditor::CloseCaption_ExtendSelectedPhraseEndTime( int direction )
{
if ( GetMode() != MODE_CLOSECAPTION )
return;
CountSelected();
if ( m_nSelectedPhraseCount != 1 )
return;
RECT rc;
GetWorkspaceRect( rc );
// Determine start/stop positions
int totalsamples = (int)( m_pWaveFile->GetRunningLength() * m_pWaveFile->SampleRate() );
float starttime = m_nLeftOffset / GetPixelsPerSecond();
float endtime = w2() / GetPixelsPerSecond() + starttime;
float timeperpixel = ( endtime - starttime ) / (float)( rc.right - rc.left );
float movetime = timeperpixel * (float)direction;
SetDirty( true );
PushUndo();
TraversePhrases( ITER_ExtendSelectedPhraseEndTimes, movetime );
PushRedo();
redraw();
Con_Printf( "Extend phrase end %s\n", direction == -1 ? "left" : "right" );
}
float PhonemeEditor::CloseCaption_GetTimeGapToNextPhrase( bool forward, CCloseCaptionPhrase *currentPhrase, CCloseCaptionPhrase **ppNextPhrase /*= NULL*/ )
{
if ( ppNextPhrase )
{
*ppNextPhrase = NULL;
}
if ( !currentPhrase )
return 0.0f;
int phrasenum = CloseCaption_IndexOfPhrase( currentPhrase );
if ( phrasenum == -1 )
return 0.0f;
// Go in correct direction
int newphrasenum = phrasenum + ( forward ? 1 : -1 );
// There is no next phrase
if ( newphrasenum >= m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ))
{
return PLENTY_OF_TIME;
}
// There is no previous phrase
if ( newphrasenum < 0 )
{
return PLENTY_OF_TIME;
}
if ( ppNextPhrase )
{
*ppNextPhrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, newphrasenum );
}
// Otherwise, figure out time gap
if ( forward )
{
float currentEnd = currentPhrase->GetEndTime();
float nextStart = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, newphrasenum )->GetStartTime();
return ( nextStart - currentEnd );
}
else
{
float previousEnd = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, newphrasenum )->GetEndTime();
float currentStart = currentPhrase->GetStartTime();
return ( currentStart - previousEnd );
}
Assert( 0 );
return 0.0f;
}
int PhonemeEditor::CloseCaption_IndexOPhrase( CCloseCaptionPhrase *phrase )
{
for ( int i = 0 ; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
if ( m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i ) == phrase )
return i;
}
return -1;
}
CCloseCaptionPhrase *PhonemeEditor::CloseCaption_GetSelectedPhrase( void )
{
CountSelected();
if ( m_nSelectedPhraseCount != 1 )
return NULL;
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *w = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( !w || !w->GetSelected() )
continue;
return w;
}
return NULL;
}
bool PhonemeEditor::CloseCaption_AreSelectedPhrasesContiguous( void )
{
CountSelected();
if ( m_nSelectedPhraseCount < 1 )
return false;
if ( m_nSelectedPhraseCount == 1 )
return true;
// Find first selected phrase
int runcount = 0;
bool parity = false;
for ( int i = 0 ; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( !phrase )
continue;
if ( phrase->GetSelected() )
{
if ( !parity )
{
parity = true;
runcount++;
}
}
else
{
if ( parity )
{
parity = false;
}
}
}
if ( runcount == 1 )
return true;
return false;
}
float PhonemeEditor::CloseCaption_ComputeMaxPhraseShift( bool forward, bool allowcrop )
{
// skipping selected phrases, figure out max time shift of phrases before they selection touches any
// unselected phrases
// if allowcrop is true, then the maximum extends up to end of next phrase
float maxshift = PLENTY_OF_TIME;
if ( forward )
{
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *phrase1 = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( !phrase1 || !phrase1->GetSelected() )
continue;
CCloseCaptionPhrase *phrase2 = NULL;
for ( int search = i + 1; search < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); search++ )
{
CCloseCaptionPhrase *check = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, search );
if ( !check || check->GetSelected() )
continue;
phrase2 = check;
break;
}
if ( phrase2 )
{
float shift;
if ( allowcrop )
{
shift = phrase2->GetEndTime() - phrase1->GetEndTime();
}
else
{
shift = phrase2->GetStartTime() - phrase1->GetEndTime();
}
if ( shift < maxshift )
{
maxshift = shift;
}
}
}
}
else
{
for ( int i = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )-1; i >= 0; i-- )
{
CCloseCaptionPhrase *phrase1 = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
if ( !phrase1 || !phrase1->GetSelected() )
continue;
CCloseCaptionPhrase *phrase2 = NULL;
for ( int search = i - 1; search >= 0 ; search-- )
{
CCloseCaptionPhrase *check = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, search );
if ( !check || check->GetSelected() )
continue;
phrase2 = check;
break;
}
if ( phrase2 )
{
float shift;
if ( allowcrop )
{
shift = phrase1->GetStartTime() - phrase2->GetStartTime();
}
else
{
shift = phrase1->GetStartTime() - phrase2->GetEndTime();
}
if ( shift < maxshift )
{
maxshift = shift;
}
}
else if ( i == 0 )
{
maxshift = phrase1->GetStartTime();
}
}
}
return maxshift;
}
bool PhonemeEditor::CloseCaption_FindSpanningPhrases( float time, CCloseCaptionPhrase **pp1, CCloseCaptionPhrase **pp2 )
{
Assert( pp1 && pp2 );
*pp1 = NULL;
*pp2 = NULL;
// Three pixels
double time_epsilon = ( 1.0f / GetPixelsPerSecond() ) * 4;
CCloseCaptionPhrase *previous = NULL;
for ( int i = 0; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
{
CCloseCaptionPhrase *current = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
double dt;
if ( !previous )
{
dt = fabs( current->GetStartTime() - time );
if ( dt < time_epsilon )
{
*pp2 = current;
return true;
}
}
else
{
int found = 0;
dt = fabs( previous->GetEndTime() - time );
if ( dt < time_epsilon )
{
*pp1 = previous;
found++;
}
dt = fabs( current->GetStartTime() - time );
if ( dt < time_epsilon )
{
*pp2 = current;
found++;
}
if ( found != 0 )
{
return true;
}
}
previous = current;
}
if ( m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ) > 0 )
{
CCloseCaptionPhrase *last = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, m_Tags.GetCloseCaptionPhraseCount(CC_ENGLISH)-1 );
float dt;
dt = fabs( last->GetEndTime() - time );
if ( dt < time_epsilon )
{
*pp1 = last;
return true;
}
}
return false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -