⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phonemeeditor_closecaption.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:

	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 + -