summaryrefslogtreecommitdiff
path: root/utils/vcd_sound_check
diff options
context:
space:
mode:
Diffstat (limited to 'utils/vcd_sound_check')
-rw-r--r--utils/vcd_sound_check/StdAfx.cpp15
-rw-r--r--utils/vcd_sound_check/cbase.h19
-rw-r--r--utils/vcd_sound_check/vcd_sound_check.cpp801
-rw-r--r--utils/vcd_sound_check/vcd_sound_check.vpc120
4 files changed, 955 insertions, 0 deletions
diff --git a/utils/vcd_sound_check/StdAfx.cpp b/utils/vcd_sound_check/StdAfx.cpp
new file mode 100644
index 0000000..33588d5
--- /dev/null
+++ b/utils/vcd_sound_check/StdAfx.cpp
@@ -0,0 +1,15 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// stdafx.cpp : source file that includes just the standard includes
+// vcd_sound_check.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "cbase.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/utils/vcd_sound_check/cbase.h b/utils/vcd_sound_check/cbase.h
new file mode 100644
index 0000000..fdc1217
--- /dev/null
+++ b/utils/vcd_sound_check/cbase.h
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: // vcd_sound_check cbase.h
+//
+//=============================================================================//
+
+#ifndef CBASE_H
+#define CBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/strtools.h"
+#include "vstdlib/random.h"
+#include "sharedInterface.h"
+
+extern class ISoundEmitterSystemBase *soundemitter;
+
+#endif // CBASE_H
diff --git a/utils/vcd_sound_check/vcd_sound_check.cpp b/utils/vcd_sound_check/vcd_sound_check.cpp
new file mode 100644
index 0000000..afb0fd3
--- /dev/null
+++ b/utils/vcd_sound_check/vcd_sound_check.cpp
@@ -0,0 +1,801 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: vcd_sound_check.cpp : Defines the entry point for the console application.
+//
+//=============================================================================//
+#include "cbase.h"
+#include <stdio.h>
+#include <windows.h>
+#include "tier0/dbg.h"
+#include "utldict.h"
+#include "tier1/UtlLinkedList.h"
+#include "filesystem.h"
+#include "FileSystem_Tools.h"
+#include "KeyValues.h"
+#include "cmdlib.h"
+#include "scriplib.h"
+#include "vstdlib/random.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "choreoscene.h"
+#include "choreoevent.h"
+#include "choreoactor.h"
+#include "choreochannel.h"
+#include "iscenetokenprocessor.h"
+
+bool uselogfile = false;
+
+struct AnalysisData
+{
+ CUtlSymbolTable symbols;
+};
+
+static AnalysisData g_Analysis;
+
+IFileSystem *filesystem = NULL;
+static CUniformRandomStream g_Random;
+IUniformRandomStream *random = &g_Random;
+
+ISoundEmitterSystemBase *soundemitter = NULL;
+
+static bool spewed = false;
+static bool spewmoveto = false;
+static bool vcdonly= false;
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for parsing scene data file
+//-----------------------------------------------------------------------------
+class CSceneTokenProcessor : public ISceneTokenProcessor
+{
+public:
+ const char *CurrentToken( void );
+ bool GetToken( bool crossline );
+ bool TokenAvailable( void );
+ void Error( const char *fmt, ... );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CSceneTokenProcessor::CurrentToken( void )
+{
+ return token;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : crossline -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSceneTokenProcessor::GetToken( bool crossline )
+{
+ return ::GetToken( crossline ) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSceneTokenProcessor::TokenAvailable( void )
+{
+ return ::TokenAvailable() ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CSceneTokenProcessor::Error( const char *fmt, ... )
+{
+ char string[ 2048 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ Q_vsnprintf( string, sizeof(string), fmt, argptr );
+ va_end( argptr );
+
+ Warning( "%s", string );
+ Assert(0);
+}
+
+static CSceneTokenProcessor g_TokenProcessor;
+
+SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
+{
+ spewed = true;
+
+ printf( "%s", pMsg );
+ OutputDebugString( pMsg );
+
+ if ( type == SPEW_ERROR )
+ {
+ printf( "\n" );
+ OutputDebugString( "\n" );
+ }
+
+ return SPEW_CONTINUE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : depth -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void vprint( int depth, const char *fmt, ... )
+{
+ char string[ 8192 ];
+ va_list va;
+ va_start( va, fmt );
+ vsprintf( string, fmt, va );
+ va_end( va );
+
+ FILE *fp = NULL;
+
+ if ( uselogfile )
+ {
+ fp = fopen( "log.txt", "ab" );
+ }
+
+ while ( depth-- > 0 )
+ {
+ printf( " " );
+ OutputDebugString( " " );
+ if ( fp )
+ {
+ fprintf( fp, " " );
+ }
+ }
+
+ ::printf( "%s", string );
+ OutputDebugString( string );
+
+ if ( fp )
+ {
+ char *p = string;
+ while ( *p )
+ {
+ if ( *p == '\n' )
+ {
+ fputc( '\r', fp );
+ }
+ fputc( *p, fp );
+ p++;
+ }
+ fclose( fp );
+ }
+}
+
+void logprint( char const *logfile, const char *fmt, ... )
+{
+ char string[ 8192 ];
+ va_list va;
+ va_start( va, fmt );
+ vsprintf( string, fmt, va );
+ va_end( va );
+
+ FILE *fp = NULL;
+ static bool first = true;
+ if ( first )
+ {
+ first = false;
+ fp = fopen( logfile, "wb" );
+ }
+ else
+ {
+ fp = fopen( logfile, "ab" );
+ }
+ if ( fp )
+ {
+ char *p = string;
+ while ( *p )
+ {
+ if ( *p == '\n' )
+ {
+ fputc( '\r', fp );
+ }
+ fputc( *p, fp );
+ p++;
+ }
+ fclose( fp );
+ }
+}
+
+
+void Con_Printf( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ vprint( 0, output );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void printusage( void )
+{
+ vprint( 0, "usage: vcd_sound_check <.wav root directory> <scenes root directory>\n\
+ \t-v = verbose output\n\
+ \t-m = spew moveto info\n\
+ \t-o = spew vcd overlap info only\n\
+ \t-l = log to file log.txt\n\
+ \ne.g.: vcd_sound_check -l u:/hl2/hl2/sound/vo u:/hl2/hl2/scenes\n" );
+
+ // Exit app
+ exit( 1 );
+}
+
+void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension )
+{
+ WIN32_FIND_DATA wfd;
+
+ char directory[ 256 ];
+ char filename[ 256 ];
+ HANDLE ff;
+
+ sprintf( directory, "%s\\*.*", dir );
+
+ if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
+ return;
+
+ int extlen = strlen( extension );
+
+ do
+ {
+ if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+
+ if ( wfd.cFileName[ 0 ] == '.' )
+ continue;
+
+ // Recurse down directory
+ sprintf( filename, "%s\\%s", dir, wfd.cFileName );
+ BuildFileList_R( files, filename, extension );
+ }
+ else
+ {
+ int len = strlen( wfd.cFileName );
+ if ( len > extlen )
+ {
+ if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) )
+ {
+ char filename[ MAX_PATH ];
+ Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
+ _strlwr( filename );
+
+ Q_FixSlashes( filename );
+
+ CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
+ files.AddToTail( sym );
+
+ if ( !( files.Count() % 3000 ) )
+ {
+ vprint( 0, "...found %i .%s files\n", files.Count(), extension );
+ }
+ }
+ }
+ }
+ } while ( FindNextFile( ff, &wfd ) );
+}
+
+void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension )
+{
+ files.RemoveAll();
+ BuildFileList_R( files, rootdir, extension );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CheckLogFile( void )
+{
+ if ( uselogfile )
+ {
+ _unlink( "log.txt" );
+ vprint( 0, " Outputting to log.txt\n" );
+ }
+}
+
+void PrintHeader()
+{
+ vprint( 0, "Valve Software - vcd_sound_check.exe (%s)\n", __DATE__ );
+ vprint( 0, "--- Voice Wav File .vcd Checker ---\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: For each .wav file in the list, see if any vcd file in the list references it
+// First build an index of .wav to .vcd mappings, then search wav list and print results
+// Input : vcdfiles -
+// wavfiles -
+//-----------------------------------------------------------------------------
+
+struct VCDList
+{
+ VCDList()
+ {
+ }
+
+ VCDList( const VCDList& src )
+ {
+ int c = src.vcds.Count();
+ for ( int i = 0 ; i < c; i++ )
+ {
+ vcds.AddToTail( src.vcds[ i ] );
+ }
+ }
+
+ VCDList& operator =( const VCDList& src )
+ {
+ if ( this == &src )
+ return *this;
+
+ int c = src.vcds.Count();
+ for ( int i = 0 ; i < c; i++ )
+ {
+ vcds.AddToTail( src.vcds[ i ] );
+ }
+
+ return *this;
+ }
+
+ CUtlVector< CUtlSymbol > vcds;
+};
+
+static int ecounter = 0;
+
+void SpewMoveto( bool first, char const *vcdname, CChoreoEvent *e )
+{
+ if ( !spewmoveto )
+ return;
+
+ //
+
+ if ( first )
+ {
+ ecounter = 0;
+ }
+
+ logprint( "moveto.txt", "\"%s\",%i,\"%s\",%.3f,\"%s\",%s\n",
+ vcdname,
+ ++ecounter,
+ e->GetName(),
+ e->GetStartTime(),
+ e->GetParameters(),
+ e->IsResumeCondition() ? "YES" : "no" );
+}
+
+static bool ChoreEventStartTimeLessFunc( CChoreoEvent * const &p1, CChoreoEvent * const &p2 )
+{
+ CChoreoEvent *e1;
+ CChoreoEvent *e2;
+
+ e1 = const_cast< CChoreoEvent * >( p1 );
+ e2 = const_cast< CChoreoEvent * >( p2 );
+
+ return e1->GetStartTime() < e2->GetStartTime();
+}
+
+static bool IsFlexTrackBeingUsed( CChoreoEvent *event, char const *trackName )
+{
+ int tc = event->GetNumFlexAnimationTracks();
+ for ( int track = 0; track < tc; ++track )
+ {
+ CFlexAnimationTrack *t = event->GetFlexAnimationTrack( track );
+ if ( !t->IsTrackActive() )
+ {
+ continue;
+ }
+
+ int sampleCountNormal = t->GetNumSamples( 0 );
+ int sampleCountBalance = 0;
+ if ( t->IsComboType() )
+ {
+ sampleCountBalance = t->GetNumSamples( 1 );
+ }
+
+ if ( !sampleCountNormal && !sampleCountBalance )
+ continue;
+
+ // Otherwise, see if the test track has this as an active track
+ if ( !Q_stricmp( t->GetFlexControllerName(), trackName ) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool EventCollidesWithRows( CUtlLinkedList< CChoreoEvent*, int >& list, CChoreoEvent *event, char *trackName, size_t trackNameLength )
+{
+ float st = event->GetStartTime();
+ float ed = event->GetEndTime();
+
+ for ( int i = list.Head(); i != list.InvalidIndex(); i = list.Next( i ) )
+ {
+ CChoreoEvent *test = list[ i ];
+
+ float teststart = test->GetStartTime();
+ float testend = test->GetEndTime();
+
+ // See if spans overlap
+ if ( teststart >= ed )
+ continue;
+ if ( testend <= st )
+ continue;
+
+ // Now see if they deal with the same flex controller
+ int tc = event->GetNumFlexAnimationTracks();
+ for ( int track = 0; track < tc; ++track )
+ {
+ CFlexAnimationTrack *t = event->GetFlexAnimationTrack( track );
+ if ( !t->IsTrackActive() )
+ {
+ continue;
+ }
+
+ int sampleCountNormal = t->GetNumSamples( 0 );
+ int sampleCountBalance = 0;
+ if ( t->IsComboType() )
+ {
+ sampleCountBalance = t->GetNumSamples( 1 );
+ }
+
+ if ( !sampleCountNormal && !sampleCountBalance )
+ continue;
+
+ // Otherwise, see if the test track has this as an active track
+ if ( IsFlexTrackBeingUsed( test, t->GetFlexControllerName() ) )
+ {
+ Q_strncpy( trackName, t->GetFlexControllerName(), trackNameLength );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+}
+
+void CheckForOverlappingFlexTracks( CChoreoScene *scene )
+{
+ for ( int a = 0; a < scene->GetNumActors(); ++a )
+ {
+ CChoreoActor *actor = scene->GetActor( a );
+
+ CUtlRBTree< CChoreoEvent * > actorFlexEvents( 0, 0, ChoreEventStartTimeLessFunc );
+
+ for ( int c = 0; c < actor->GetNumChannels(); ++c )
+ {
+ CChoreoChannel *channel = actor->GetChannel( c );
+
+ for ( int e = 0 ; e < channel->GetNumEvents(); ++e )
+ {
+ CChoreoEvent *event = channel->GetEvent( e );
+
+ if ( event->GetType() != CChoreoEvent::FLEXANIMATION )
+ continue;
+
+ actorFlexEvents.Insert( event );
+ }
+ }
+
+ CUtlVector< CUtlLinkedList< CChoreoEvent*, int > > rows;
+
+ bool done = false;
+ int i;
+ // Now check for overlaps
+ for ( i = actorFlexEvents.FirstInorder(); i != actorFlexEvents.InvalidIndex() && !done; i = actorFlexEvents.NextInorder( i ) )
+ {
+ CChoreoEvent *e = actorFlexEvents[ i ];
+ if ( !rows.Count() )
+ {
+ rows.AddToTail();
+
+ CUtlLinkedList< CChoreoEvent*, int >& list = rows[ 0 ];
+ list.AddToHead( e );
+ continue;
+ }
+
+ // Does it come totally after what's in rows[0]?
+ int rowCount = rows.Count();
+ bool addrow = true;
+
+ for ( int j = 0; j < rowCount; j++ )
+ {
+ CUtlLinkedList< CChoreoEvent*, int >& list = rows[ j ];
+
+ char offender[ 256 ];
+ if ( !EventCollidesWithRows( list, e, offender, sizeof( offender ) ) )
+ {
+ // Update row event list
+ list.AddToHead( e );
+ addrow = false;
+ break;
+ }
+ else
+ {
+ Msg( "[%s] has overlapping events for actor [%s] [%s] [flex: %s]\n",
+ scene->GetFilename(), actor->GetName(), e->GetName(), offender );
+ done = true;
+ }
+ }
+
+ if ( addrow )
+ {
+ // Add a new row
+ int idx = rows.AddToTail();
+ CUtlLinkedList< CChoreoEvent *, int >& list = rows[ idx ];
+ list.AddToHead( e );
+ }
+ }
+
+ // Assert( rows.Count() <= 1 );
+ }
+}
+
+void ProcessVCD( CUtlDict< VCDList, int >& database, CUtlSymbol& vcdname )
+{
+ // vprint( 0, "Processing '%s'\n", g_Analysis.symbols.String( vcdname ) );
+
+ // Load the .vcd
+ char fullname[ 512 ];
+ Q_snprintf( fullname, sizeof( fullname ), "%s", g_Analysis.symbols.String( vcdname ) );
+
+ LoadScriptFile( fullname );
+
+ CChoreoScene *scene = ChoreoLoadScene( fullname, NULL, &g_TokenProcessor, Con_Printf );
+ if ( scene )
+ {
+ bool first = true;
+ // Now iterate the events looking for speak events
+ int c = scene->GetNumEvents();
+ for ( int i = 0; i < c; i++ )
+ {
+ CChoreoEvent *e = scene->GetEvent( i );
+
+ if ( e->GetType() == CChoreoEvent::MOVETO )
+ {
+ SpewMoveto( first, fullname, e );
+ first = false;
+ }
+
+ if ( e->GetType() != CChoreoEvent::SPEAK )
+ continue;
+
+ // Look up sound in sound emitter system
+ char const *wavename = soundemitter->GetWavFileForSound( e->GetParameters(), NULL );
+ if ( !wavename || !wavename[ 0 ] )
+ {
+ continue;
+ }
+
+ char fullwavename[ 512 ];
+ Q_snprintf( fullwavename, sizeof( fullwavename ), "%ssound\\%s",
+ gamedir, wavename );
+ Q_FixSlashes( fullwavename );
+
+ // Now add to proper slot
+ VCDList *entry = NULL;
+
+ // Add vcd to database
+ int slot = database.Find( fullwavename );
+ if ( slot == database.InvalidIndex() )
+ {
+ VCDList nullEntry;
+ slot = database.Insert( fullwavename, nullEntry );
+ }
+
+ entry = &database[ slot ];
+ if ( entry->vcds.Find( vcdname ) == entry->vcds.InvalidIndex() )
+ {
+ entry->vcds.AddToTail( vcdname );
+ }
+ }
+
+ if ( vcdonly )
+ {
+ CheckForOverlappingFlexTracks( scene );
+ }
+ }
+
+ delete scene;
+}
+
+void CorrelateWavsAndVCDs( CUtlVector< CUtlSymbol >& vcdfiles, CUtlVector< CUtlSymbol >& wavfiles )
+{
+ CUtlDict< VCDList, int > database;
+
+ int i;
+ int c = vcdfiles.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ CUtlSymbol& vcdname = vcdfiles[ i ];
+
+ // Load the .vcd and update the database
+ ProcessVCD( database, vcdname );
+ }
+
+ if ( vcdonly )
+ return;
+
+ vprint( 0, "Found %i wav files in %i vcds\n",
+ database.Count(), vcdfiles.Count() );
+
+ // Now look for any wavfiles that weren't in the database
+ int ecount = 0;
+
+ c = wavfiles.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ CUtlSymbol& wavename = wavfiles[ i ];
+
+ int idx = database.Find( g_Analysis.symbols.String( wavename ) );
+ if ( idx != database.InvalidIndex() )
+ {
+ VCDList *listentry = &database[ idx ];
+ int vcdcount = listentry->vcds.Count();
+ if ( vcdcount >= 2 && verbose )
+ {
+ vprint( 0, " wave '%s' used by multiple .vcds:\n", g_Analysis.symbols.String( wavename ) );
+ int j;
+ for ( j = 0; j < vcdcount; j++ )
+ {
+ vprint( 1, "%i -- '%s'\n", j+1, g_Analysis.symbols.String( listentry->vcds[ j ] ) );
+ }
+ }
+ continue;
+ }
+
+ vprint( 0, "%i -- '%s' not referenced by .vcd\n",
+ ++ecount, g_Analysis.symbols.String( wavename ) );
+ }
+
+ vprint( 0, "\nSummary: found %i/%i (%.2f percent) .wav errors\n", ecount, c, 100.0 * ecount / max( c, 1 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : argc -
+// argv[] -
+// Output : int
+//-----------------------------------------------------------------------------
+int main( int argc, char* argv[] )
+{
+ SpewOutputFunc( SpewFunc );
+ SpewActivate( "vcd_sound_check", 2 );
+
+ int i=1;
+ for ( i ; i<argc ; i++)
+ {
+ if ( argv[ i ][ 0 ] == '-' )
+ {
+ switch( argv[ i ][ 1 ] )
+ {
+ case 'l':
+ uselogfile = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'm':
+ spewmoveto = true;
+ break;
+ case 'o':
+ vcdonly = true;
+ break;
+ default:
+ printusage();
+ break;
+ }
+ }
+ }
+
+ if ( argc < 3 || ( i != argc ) )
+ {
+ PrintHeader();
+ printusage();
+ }
+
+ CheckLogFile();
+
+ PrintHeader();
+
+ vprint( 0, " Looking for .wav files not referenced in .vcd files...\n" );
+
+ char sounddir[ 256 ];
+ char vcddir[ 256 ];
+ strcpy( sounddir, argv[ i - 2 ] );
+ strcpy( vcddir, argv[ i - 1 ] );
+ if ( !strstr( sounddir, "sound" ) )
+ {
+ vprint( 0, "Sound dir %s looks invalid (format: u:/tf2/hl2/sound/vo)\n", sounddir );
+ return 0;
+ }
+ if ( !strstr( vcddir, "scenes" ) )
+ {
+ vprint( 0, ".vcd dir %s looks invalid (format: u:/tf2/hl2/scenes)\n", vcddir );
+ return 0;
+ }
+
+ char workingdir[ 256 ];
+ workingdir[0] = 0;
+ Q_getwd( workingdir, sizeof( workingdir ) );
+
+ // If they didn't specify -game on the command line, use VPROJECT.
+ CmdLib_InitFileSystem( workingdir );
+
+ CSysModule *pSoundEmitterModule = g_pFullFileSystem->LoadModule( "soundemittersystem.dll" );
+ if ( !pSoundEmitterModule )
+ {
+ vprint( 0, "Sys_LoadModule( soundemittersystem.dll ) failed!\n" );
+ return 0;
+ }
+
+ CreateInterfaceFn hSoundEmitterFactory = Sys_GetFactory( pSoundEmitterModule );
+ if ( !hSoundEmitterFactory )
+ {
+ vprint( 0, "Sys_GetFactory on soundemittersystem.dll failed!\n" );
+ return 0;
+ }
+
+ soundemitter = ( ISoundEmitterSystemBase * )hSoundEmitterFactory( SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL );
+ if ( !soundemitter )
+ {
+ vprint( 0, "Couldn't get interface %s from soundemittersystem.dll!\n", SOUNDEMITTERSYSTEM_INTERFACE_VERSION );
+ return 0;
+ }
+
+ filesystem = (IFileSystem *)(CmdLib_GetFileSystemFactory()( FILESYSTEM_INTERFACE_VERSION, NULL ));
+ if ( !filesystem )
+ {
+ AssertMsg( 0, "Failed to create/get IFileSystem" );
+ return 1;
+ }
+
+ Q_FixSlashes( gamedir );
+ Q_strlower( gamedir );
+
+ vprint( 0, "game dir %s\nsounds dir %s\nvcd dir %s\n\n",
+ gamedir,
+ sounddir,
+ vcddir );
+
+ Q_StripTrailingSlash( sounddir );
+ Q_StripTrailingSlash( vcddir );
+
+
+ filesystem->RemoveFile( "moveto.txt", "GAME" );
+ //
+ //ProcessMaterialsDirectory( vmtdir );
+
+ vprint( 0, "Initializing sound emitter system\n" );
+ soundemitter->Connect( FileSystem_GetFactory() );
+ soundemitter->Init();
+
+ vprint( 0, "Loaded %i sounds\n", soundemitter->GetSoundCount() );
+
+ vprint( 0, "Building list of .vcd files\n" );
+ CUtlVector< CUtlSymbol > vcdfiles;
+ BuildFileList( vcdfiles, vcddir, ".vcd" );
+ vprint( 0, "found %i .vcd files\n\n", vcdfiles.Count() );
+
+ vprint( 0, "Building list of known .wav files\n" );
+ CUtlVector< CUtlSymbol > wavfiles;
+ BuildFileList( wavfiles, sounddir, ".wav" );
+ vprint( 0, "found %i .wav files\n\n", wavfiles.Count() );
+
+ CorrelateWavsAndVCDs( vcdfiles, wavfiles );
+
+ soundemitter->Shutdown();
+ soundemitter = 0;
+ g_pFullFileSystem->UnloadModule( pSoundEmitterModule );
+
+ FileSystem_Term();
+
+ return 0;
+} \ No newline at end of file
diff --git a/utils/vcd_sound_check/vcd_sound_check.vpc b/utils/vcd_sound_check/vcd_sound_check.vpc
new file mode 100644
index 0000000..0bfc4ab
--- /dev/null
+++ b/utils/vcd_sound_check/vcd_sound_check.vpc
@@ -0,0 +1,120 @@
+//-----------------------------------------------------------------------------
+// VCD_SOUND_CHECK.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,$SRCDIR\utils\vcd_sound_check,$SRCDIR\game\shared,..\common"
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $Create/UsePCHThroughFile "cbase.h"
+ $PrecompiledHeaderFile "Debug/vcd_sound_check.pch"
+ }
+}
+
+$Project "Vcd_sound_check"
+{
+ $Folder "Source Files"
+ {
+ $File "vcd_sound_check.cpp"
+
+ $File "..\common\cmdlib.cpp" \
+ "$SRCDIR\public\filesystem_helpers.cpp" \
+ "$SRCDIR\public\filesystem_init.cpp" \
+ "..\common\filesystem_tools.cpp" \
+ "$SRCDIR\public\interpolatortypes.cpp" \
+ "$SRCDIR\game\shared\interval.cpp" \
+ "..\common\scriplib.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Not Using Precompiled Headers"
+ }
+ }
+ }
+
+ $File "StdAfx.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
+ }
+ }
+ }
+
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\filesystem_helpers.h"
+ $File "$SRCDIR\game\shared\ichoreoeventcallback.h"
+ $File "$SRCDIR\game\shared\iscenetokenprocessor.h"
+ $File "..\common\scriplib.h"
+ $File "$SRCDIR\public\mathlib\amd3dx.h"
+ $File "$SRCDIR\public\tier0\basetypes.h"
+ $File "cbase.h"
+ $File "$SRCDIR\game\shared\choreoactor.h"
+ $File "$SRCDIR\game\shared\choreochannel.h"
+ $File "$SRCDIR\game\shared\choreoevent.h"
+ $File "$SRCDIR\game\shared\choreoscene.h"
+ $File "..\common\cmdlib.h"
+ $File "$SRCDIR\public\Color.h"
+ $File "$SRCDIR\public\tier0\commonmacros.h"
+ $File "$SRCDIR\public\tier1\convar.h"
+ $File "$SRCDIR\public\tier0\dbg.h"
+ $File "$SRCDIR\game\shared\ExpressionSample.h"
+ $File "$SRCDIR\public\tier0\fasttimer.h"
+ $File "$SRCDIR\public\filesystem.h"
+ $File "..\common\filesystem_tools.h"
+ $File "$SRCDIR\public\appframework\IAppSystem.h"
+ $File "$SRCDIR\public\tier0\icommandline.h"
+ $File "$SRCDIR\public\engine\IEngineSound.h"
+ $File "$SRCDIR\public\vstdlib\IKeyValuesSystem.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "$SRCDIR\public\interpolatortypes.h"
+ $File "$SRCDIR\game\shared\interval.h"
+ $File "$SRCDIR\public\irecipientfilter.h"
+ $File "$SRCDIR\public\tier1\KeyValues.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "$SRCDIR\public\tier0\mem.h"
+ $File "$SRCDIR\public\tier0\memdbgoff.h"
+ $File "$SRCDIR\public\tier0\memdbgon.h"
+ $File "$SRCDIR\public\networkvar.h"
+ $File "$SRCDIR\public\tier0\platform.h"
+ $File "$SRCDIR\public\tier0\protected_things.h"
+ $File "$SRCDIR\public\vstdlib\random.h"
+ $File "$SRCDIR\game\shared\sharedInterface.h"
+ $File "$SRCDIR\public\soundchars.h"
+ $File "$SRCDIR\public\soundflags.h"
+ $File "$SRCDIR\public\string_t.h"
+ $File "$SRCDIR\public\tier1\strtools.h"
+ $File "$SRCDIR\public\tier1\utldict.h"
+ $File "$SRCDIR\public\tier1\utllinkedlist.h"
+ $File "$SRCDIR\public\tier1\utlmemory.h"
+ $File "$SRCDIR\public\tier1\utlrbtree.h"
+ $File "$SRCDIR\public\tier1\utlsymbol.h"
+ $File "$SRCDIR\public\tier1\utlvector.h"
+ $File "$SRCDIR\public\mathlib\vector.h"
+ $File "$SRCDIR\public\mathlib\vector2d.h"
+ $File "$SRCDIR\public\vstdlib\vstdlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib choreoobjects
+ $Lib mathlib
+ $Lib tier2
+ }
+}