Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1182 lines
25 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include <windows.h>
  8. #include "resource.h"
  9. #include "wavefile.h"
  10. #include "wavebrowser.h"
  11. #include "SoundEmitterSystem/isoundemittersystembase.h"
  12. #include "ifaceposersound.h"
  13. #include "snd_wave_source.h"
  14. #include "filesystem.h"
  15. #include "tabwindow.h"
  16. #include "inputproperties.h"
  17. #include "choreowidgetdrawhelper.h"
  18. #include "ifileloader.h"
  19. #include "tier2/riff.h"
  20. #include "UtlBuffer.h"
  21. #include "ChoreoEvent.h"
  22. CWaveBrowser *g_pWaveBrowser = NULL;
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Implements the RIFF i/o interface on stdio
  25. //-----------------------------------------------------------------------------
  26. class StdIOReadBinary : public IFileReadBinary
  27. {
  28. public:
  29. FileHandle_t open( const char *pFileName )
  30. {
  31. return filesystem->Open( pFileName, "rb" );
  32. }
  33. int read( void *pOutput, int size, FileHandle_t file )
  34. {
  35. if ( !file )
  36. return 0;
  37. return filesystem->Read( pOutput, size, file );
  38. }
  39. void seek( FileHandle_t file, int pos )
  40. {
  41. if ( !file )
  42. return;
  43. filesystem->Seek( file, pos, FILESYSTEM_SEEK_HEAD );
  44. }
  45. unsigned int tell( FileHandle_t file )
  46. {
  47. if ( !file )
  48. return 0;
  49. return filesystem->Tell( file );
  50. }
  51. unsigned int size( FileHandle_t file )
  52. {
  53. if ( !file )
  54. return 0;
  55. return filesystem->Size( file );
  56. }
  57. void close( FileHandle_t file )
  58. {
  59. if ( !file )
  60. return;
  61. filesystem->Close( file );
  62. }
  63. };
  64. class StdIOWriteBinary : public IFileWriteBinary
  65. {
  66. public:
  67. FileHandle_t create( const char *pFileName )
  68. {
  69. return filesystem->Open( pFileName, "wb" );
  70. }
  71. int write( void *pData, int size, FileHandle_t file )
  72. {
  73. return filesystem->Write( pData, size, file );
  74. }
  75. void close( FileHandle_t file )
  76. {
  77. filesystem->Close( file );
  78. }
  79. void seek( FileHandle_t file, int pos )
  80. {
  81. filesystem->Seek( file, pos, FILESYSTEM_SEEK_HEAD );
  82. }
  83. unsigned int tell( FileHandle_t file )
  84. {
  85. return filesystem->Tell( file );
  86. }
  87. };
  88. static StdIOReadBinary io_in;
  89. static StdIOWriteBinary io_out;
  90. #define RIFF_WAVE MAKEID('W','A','V','E')
  91. #define WAVE_FMT MAKEID('f','m','t',' ')
  92. #define WAVE_DATA MAKEID('d','a','t','a')
  93. #define WAVE_FACT MAKEID('f','a','c','t')
  94. #define WAVE_CUE MAKEID('c','u','e',' ')
  95. //-----------------------------------------------------------------------------
  96. // Purpose:
  97. // Input : &walk -
  98. //-----------------------------------------------------------------------------
  99. static void SceneManager_ParseSentence( CSentence& sentence, IterateRIFF &walk )
  100. {
  101. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  102. buf.EnsureCapacity( walk.ChunkSize() );
  103. walk.ChunkRead( buf.Base() );
  104. buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() );
  105. sentence.InitFromDataChunk( buf.Base(), buf.TellPut() );
  106. }
  107. bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io )
  108. {
  109. sentence.Reset();
  110. InFileRIFF riff( wavfile, io );
  111. // UNDONE: Don't use printf to handle errors
  112. if ( riff.RIFFName() != RIFF_WAVE )
  113. {
  114. return false;
  115. }
  116. // set up the iterator for the whole file (root RIFF is a chunk)
  117. IterateRIFF walk( riff, riff.RIFFSize() );
  118. // This chunk must be first as it contains the wave's format
  119. // break out when we've parsed it
  120. bool found = false;
  121. while ( walk.ChunkAvailable() && !found )
  122. {
  123. switch( walk.ChunkName() )
  124. {
  125. case WAVE_VALVEDATA:
  126. {
  127. found = true;
  128. SceneManager_ParseSentence( sentence, walk );
  129. }
  130. break;
  131. }
  132. walk.ChunkNext();
  133. }
  134. return true;
  135. }
  136. bool SceneManager_LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence )
  137. {
  138. return SceneManager_LoadSentenceFromWavFileUsingIO( wavfile, sentence, io_in );
  139. }
  140. enum
  141. {
  142. // Controls
  143. IDC_SB_LISTVIEW = 101,
  144. IDC_SB_FILETREE,
  145. // Messages
  146. IDC_SB_PLAY = 1000,
  147. };
  148. enum
  149. {
  150. COL_WAV = 0,
  151. COL_DUCKED,
  152. COL_PHONEMES,
  153. COL_SENTENCE
  154. };
  155. class CWaveList : public mxListView
  156. {
  157. public:
  158. CWaveList( mxWindow *parent, int id = 0 )
  159. : mxListView( parent, 0, 0, 0, 0, id )
  160. {
  161. // Add column headers
  162. insertTextColumn( COL_WAV, 300, "WAV" );
  163. insertTextColumn( COL_DUCKED, 50, "Ducked" );
  164. insertTextColumn( COL_PHONEMES, 120, "Words [ Phonemes ]" );
  165. insertTextColumn( COL_SENTENCE, 300, "Sentence Text" );
  166. }
  167. };
  168. class CWaveFileTree : public mxTreeView
  169. {
  170. public:
  171. CWaveFileTree( mxWindow *parent, int id = 0 ) : mxTreeView( parent, 0, 0, 0, 0, id ),
  172. m_Paths( 0, 0, FileTreeLessFunc )
  173. {
  174. }
  175. void Clear()
  176. {
  177. removeAll();
  178. m_Paths.RemoveAll();
  179. }
  180. void FindOrAddSubdirectory( char const *subdir )
  181. {
  182. FileTreePath fp;
  183. Q_strcpy( fp.path, subdir );
  184. if ( m_Paths.Find( fp ) != m_Paths.InvalidIndex() )
  185. return;
  186. m_Paths.Insert( fp );
  187. }
  188. mxTreeViewItem *FindOrAddChildItem( mxTreeViewItem *parent, char const *child )
  189. {
  190. mxTreeViewItem *p = getFirstChild( parent );
  191. if ( !p )
  192. {
  193. return add( parent, child );
  194. }
  195. while ( p )
  196. {
  197. if ( !Q_stricmp( getLabel( p ), child ) )
  198. return p;
  199. p = getNextChild( p );
  200. }
  201. return add( parent, child );
  202. }
  203. void _PopulateTree( int pathId, char const *path )
  204. {
  205. char sz[ 512 ];
  206. Q_strcpy( sz, path );
  207. char *p = sz;
  208. // Start at root
  209. mxTreeViewItem *cur = NULL;
  210. // Tokenize path
  211. while ( p && p[0] )
  212. {
  213. char *slash = Q_strstr( p, "/" );
  214. if ( !slash )
  215. {
  216. slash = Q_strstr( p, "\\" );
  217. }
  218. char *check = p;
  219. if ( slash )
  220. {
  221. *slash = 0;
  222. // see if a child of current already exists with this name
  223. p = slash + 1;
  224. }
  225. else
  226. {
  227. p = NULL;
  228. }
  229. Assert( check );
  230. cur = FindOrAddChildItem( cur, check );
  231. }
  232. setUserData( cur, (void *)pathId );
  233. }
  234. char const *GetSelectedPath( void )
  235. {
  236. mxTreeViewItem *tvi = getSelectedItem();
  237. unsigned int id = (unsigned int)getUserData( tvi );
  238. if ( id < 0 || id >= m_Paths.Count() )
  239. {
  240. Assert( 0 );
  241. return "";
  242. }
  243. return m_Paths[ id ].path;
  244. }
  245. void PopulateTree()
  246. {
  247. int i;
  248. for ( i = m_Paths.FirstInorder(); i != m_Paths.InvalidIndex(); i = m_Paths.NextInorder( i ) )
  249. {
  250. _PopulateTree( i, m_Paths[ i ].path );
  251. }
  252. mxTreeViewItem *p = getFirstChild( NULL );
  253. setOpen( p, true );
  254. }
  255. struct FileTreePath
  256. {
  257. char path[ MAX_PATH ];
  258. };
  259. static bool FileTreeLessFunc( const FileTreePath &lhs, const FileTreePath &rhs )
  260. {
  261. return Q_stricmp( lhs.path, rhs.path ) < 0;
  262. }
  263. CUtlRBTree< FileTreePath, int > m_Paths;
  264. };
  265. #pragma optimize( "", off )
  266. class CWaveOptionsWindow : public mxWindow
  267. {
  268. typedef mxWindow BaseClass;
  269. public:
  270. enum
  271. {
  272. IDC_PLAYSOUND = 1000,
  273. IDC_STOP_SOUNDS,
  274. IDC_SEARCH,
  275. IDC_CANCELSEARCH,
  276. };
  277. CWaveOptionsWindow( CWaveBrowser *browser ) : BaseClass( browser, 0, 0, 0, 0 ), m_pBrowser( browser )
  278. {
  279. FacePoser_AddWindowStyle( this, WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
  280. m_szSearchString[0]=0;
  281. m_pPlay = new mxButton( this, 0, 0, 0, 0, "Play", IDC_PLAYSOUND );
  282. m_pStopSounds = new mxButton( this, 0, 0, 0, 0, "Stop Sounds", IDC_STOP_SOUNDS );
  283. m_pSearch = new mxLineEdit( this, 0, 0, 0, 0, "", IDC_SEARCH );
  284. m_pCancelSearch = new mxButton( this, 0, 0, 0, 0, "Cancel", IDC_CANCELSEARCH );
  285. }
  286. bool PaintBackground( void )
  287. {
  288. redraw();
  289. return false;
  290. }
  291. virtual void redraw()
  292. {
  293. CChoreoWidgetDrawHelper drawHelper( this, RGBToColor( GetSysColor( COLOR_BTNFACE ) ) );
  294. }
  295. virtual int handleEvent( mxEvent *event )
  296. {
  297. int iret = 0;
  298. switch ( event->event )
  299. {
  300. default:
  301. break;
  302. case mxEvent::Size:
  303. {
  304. iret = 1;
  305. int split = 120;
  306. int x = 1;
  307. m_pPlay->setBounds( x, 1, split, h2() - 2 );
  308. x += split + 10;
  309. m_pStopSounds->setBounds( x, 1, split, h2()-2 );
  310. x += split + 10;
  311. m_pCancelSearch->setBounds( x, 1, split, h2() - 2 );
  312. x += split + 10;
  313. m_pSearch->setBounds( x, 0, split * 3, h2() - 1 );
  314. x += split * 3 + 10;
  315. }
  316. break;
  317. case mxEvent::KeyDown:
  318. switch ( event->action )
  319. {
  320. default:
  321. break;
  322. case IDC_SEARCH:
  323. {
  324. if ( event->event == mxEvent::KeyDown )
  325. {
  326. OnSearch();
  327. }
  328. iret = 1;
  329. };
  330. break;
  331. }
  332. break;
  333. case mxEvent::Action:
  334. {
  335. switch ( event->action )
  336. {
  337. case IDC_STOP_SOUNDS:
  338. {
  339. iret = 1;
  340. sound->StopAll();
  341. }
  342. break;
  343. case IDC_SEARCH:
  344. iret = 1;
  345. break;
  346. case IDC_PLAYSOUND:
  347. {
  348. iret = 1;
  349. m_pBrowser->OnPlay();
  350. }
  351. break;
  352. case IDC_CANCELSEARCH:
  353. {
  354. iret = 1;
  355. OnCancelSearch();
  356. }
  357. break;
  358. default:
  359. break;
  360. }
  361. }
  362. break;
  363. }
  364. return iret;
  365. }
  366. char const *GetSearchString()
  367. {
  368. return m_szSearchString;
  369. }
  370. void OnSearch()
  371. {
  372. m_pSearch->getText( m_szSearchString, sizeof( m_szSearchString ) );
  373. m_pBrowser->OnSearch();
  374. }
  375. void OnCancelSearch()
  376. {
  377. m_szSearchString[ 0 ] = 0;
  378. m_pSearch->clear();
  379. m_pBrowser->OnCancelSearch();
  380. }
  381. private:
  382. mxButton *m_pStopSounds;
  383. mxButton *m_pPlay;
  384. mxLineEdit *m_pSearch;
  385. mxButton *m_pCancelSearch;
  386. CWaveBrowser *m_pBrowser;
  387. char m_szSearchString[ 256 ];
  388. };
  389. #pragma optimize( "", on )
  390. //-----------------------------------------------------------------------------
  391. // Purpose:
  392. // Input : *parent -
  393. //-----------------------------------------------------------------------------
  394. CWaveBrowser::CWaveBrowser( mxWindow *parent )
  395. : IFacePoserToolWindow( "WaveBrowser", "Waves" ), mxWindow( parent, 0, 0, 0, 0 )
  396. {
  397. SetAutoProcess( false );
  398. m_bTextSearch = false;
  399. m_nPrevProcessed = -1;
  400. m_pListView = new CWaveList( this, IDC_SB_LISTVIEW );
  401. m_pOptions = new CWaveOptionsWindow( this );
  402. m_pFileTree = new CWaveFileTree( this, IDC_SB_FILETREE );
  403. //HIMAGELIST list = CreateImageList();
  404. // Associate the image list with the tree-view control.
  405. //m_pListView->setImageList( (void *)list );
  406. LoadAllSounds();
  407. PopulateTree( NULL );
  408. }
  409. #define CX_ICON 16
  410. #define CY_ICON 16
  411. HIMAGELIST CWaveBrowser::CreateImageList()
  412. {
  413. HIMAGELIST list;
  414. list = ImageList_Create( CX_ICON, CY_ICON,
  415. FALSE, NUM_IMAGES, 0 );
  416. // Load the icon resources, and add the icons to the image list.
  417. HICON hicon;
  418. int slot;
  419. #if defined( _DEBUG )
  420. int c = 0;
  421. #endif
  422. /*
  423. hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE));
  424. slot = ImageList_AddIcon(list, hicon);
  425. Assert( slot == c++ );
  426. DeleteObject( hicon );
  427. hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE_CHECKEDOUT));
  428. slot = ImageList_AddIcon(list, hicon);
  429. Assert( slot == c++ );
  430. DeleteObject( hicon );
  431. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT));
  432. slot = ImageList_AddIcon(list, hicon);
  433. Assert( slot == c++ );
  434. DeleteObject( hicon );
  435. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT_CHECKEDOUT));
  436. slot = ImageList_AddIcon(list, hicon);
  437. Assert( slot == c++ );
  438. DeleteObject( hicon );
  439. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE));
  440. slot = ImageList_AddIcon(list, hicon);
  441. Assert( slot == c++ );
  442. DeleteObject( hicon );
  443. */
  444. // hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE_CHECKEDOUT));
  445. // slot = ImageList_AddIcon(list, hicon);
  446. // Assert( slot == c++ );
  447. // DeleteObject( hicon );
  448. /*
  449. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD));
  450. slot = ImageList_AddIcon(list, hicon);
  451. Assert( slot == c++ );
  452. DeleteObject( hicon );
  453. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD_CHECKEDOUT ));
  454. slot = ImageList_AddIcon(list, hicon);
  455. Assert( slot == c++ );
  456. DeleteObject( hicon );
  457. */
  458. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV));
  459. slot = ImageList_AddIcon(list, hicon);
  460. Assert( slot == c++ );
  461. DeleteObject( hicon );
  462. /*
  463. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV_CHECKEDOUT));
  464. slot = ImageList_AddIcon(list, hicon);
  465. Assert( slot == c++ );
  466. DeleteObject( hicon );
  467. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK));
  468. slot = ImageList_AddIcon(list, hicon);
  469. Assert( slot == c++ );
  470. DeleteObject( hicon );
  471. hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK_CHECKEDOUT));
  472. slot = ImageList_AddIcon(list, hicon);
  473. Assert( slot == c++ );
  474. DeleteObject( hicon );
  475. */
  476. return list;
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose:
  480. //-----------------------------------------------------------------------------
  481. void CWaveBrowser::OnDelete()
  482. {
  483. RemoveAllSounds();
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose:
  487. // Input : *event -
  488. // Output : int
  489. //-----------------------------------------------------------------------------
  490. int CWaveBrowser::handleEvent( mxEvent *event )
  491. {
  492. int iret = 0;
  493. if ( HandleToolEvent( event ) )
  494. {
  495. return iret;
  496. }
  497. switch ( event->event )
  498. {
  499. default:
  500. break;
  501. case mxEvent::Action:
  502. {
  503. iret = 1;
  504. switch ( event->action )
  505. {
  506. default:
  507. {
  508. iret = 0;
  509. }
  510. break;
  511. case IDC_SB_LISTVIEW:
  512. {
  513. SetActiveTool( this );
  514. bool rightmouse = ( event->flags == mxEvent::RightClicked ) ? true : false;
  515. bool doubleclicked = ( event->flags == mxEvent::DoubleClicked ) ? true : false;
  516. if ( rightmouse )
  517. {
  518. ShowContextMenu();
  519. }
  520. else if ( doubleclicked )
  521. {
  522. if ( m_pListView->getNumSelected() == 1 )
  523. {
  524. int index = m_pListView->getNextSelectedItem( -1 );
  525. if ( index >= 0 )
  526. {
  527. CWaveFile *wav = (CWaveFile *)m_pListView->getUserData( index, 0 );
  528. if ( wav )
  529. {
  530. wav->Play();
  531. }
  532. }
  533. }
  534. }
  535. }
  536. break;
  537. case IDC_SB_FILETREE:
  538. {
  539. SetActiveTool( this );
  540. PopulateTree( m_pFileTree->GetSelectedPath() );
  541. }
  542. break;
  543. case IDC_SB_PLAY:
  544. {
  545. OnPlay();
  546. }
  547. break;
  548. }
  549. }
  550. break;
  551. case mxEvent::Size:
  552. {
  553. int optionsh = 20;
  554. m_pOptions->setBounds( 0, 0, w2(), optionsh );
  555. int filetreewidth = 175;
  556. m_pFileTree->setBounds( 0, optionsh, filetreewidth, h2() - optionsh );
  557. m_pListView->setBounds( filetreewidth, optionsh, w2() - filetreewidth, h2() - optionsh );
  558. iret = 1;
  559. }
  560. break;
  561. case mxEvent::Close:
  562. {
  563. iret = 1;
  564. }
  565. break;
  566. }
  567. return iret;
  568. }
  569. static bool NameLessFunc( CWaveFile *const& name1, CWaveFile *const& name2 )
  570. {
  571. if ( Q_stricmp( name1->GetName(), name2->GetName() ) < 0 )
  572. return true;
  573. return false;
  574. }
  575. #define SOUND_PREFIX_LEN 6
  576. //-----------------------------------------------------------------------------
  577. // Finds all .wav files in a particular directory
  578. //-----------------------------------------------------------------------------
  579. bool CWaveBrowser::LoadWaveFilesInDirectory( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName, int nDirectoryNameLen )
  580. {
  581. Assert( Q_strnicmp( pDirectoryName, "sound", 5 ) == 0 );
  582. char *pWildCard;
  583. pWildCard = ( char * )stackalloc( nDirectoryNameLen + 7 );
  584. Q_snprintf( pWildCard, nDirectoryNameLen + 7, "%s/*.wav", pDirectoryName );
  585. if ( !filesystem )
  586. {
  587. return false;
  588. }
  589. FileFindHandle_t findHandle;
  590. const char *pFileName = filesystem->FindFirst( pWildCard, &findHandle );
  591. while( pFileName )
  592. {
  593. if( !filesystem->FindIsDirectory( findHandle ) )
  594. {
  595. // Strip off the 'sound/' part of the name.
  596. char *pFileNameWithPath;
  597. int nAllocSize = nDirectoryNameLen + Q_strlen(pFileName) + 2;
  598. pFileNameWithPath = (char *)stackalloc( nAllocSize );
  599. Q_snprintf( pFileNameWithPath, nAllocSize, "%s/%s", &pDirectoryName[SOUND_PREFIX_LEN], pFileName );
  600. Q_strnlwr( pFileNameWithPath, nAllocSize );
  601. CWaveFile *wav = new CWaveFile( pFileNameWithPath );
  602. soundlist.Insert( pFileNameWithPath, wav );
  603. /*
  604. if ( !(soundlist.Count() % 500 ) )
  605. {
  606. Con_Printf( "CWaveBrowser: loaded %i sounds\n", soundlist.Count() );
  607. }
  608. */
  609. }
  610. pFileName = filesystem->FindNext( findHandle );
  611. }
  612. m_pFileTree->FindOrAddSubdirectory( &pDirectoryName[ SOUND_PREFIX_LEN ] );
  613. filesystem->FindClose( findHandle );
  614. return true;
  615. }
  616. bool CWaveBrowser::InitDirectoryRecursive( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName )
  617. {
  618. // Compute directory name length
  619. int nDirectoryNameLen = Q_strlen( pDirectoryName );
  620. if (!LoadWaveFilesInDirectory( soundlist, pDirectoryName, nDirectoryNameLen ) )
  621. return false;
  622. char *pWildCard = ( char * )stackalloc( nDirectoryNameLen + 4 );
  623. strcpy(pWildCard, pDirectoryName);
  624. strcat(pWildCard, "/*.");
  625. int nPathStrLen = nDirectoryNameLen + 1;
  626. FileFindHandle_t findHandle;
  627. const char *pFileName = filesystem->FindFirst( pWildCard, &findHandle );
  628. while( pFileName )
  629. {
  630. if ((pFileName[0] != '.') || (pFileName[1] != '.' && pFileName[1] != 0))
  631. {
  632. if( filesystem->FindIsDirectory( findHandle ) )
  633. {
  634. int fileNameStrLen = Q_strlen( pFileName );
  635. char *pFileNameWithPath = ( char * )stackalloc( nPathStrLen + fileNameStrLen + 1 );
  636. memcpy( pFileNameWithPath, pWildCard, nPathStrLen );
  637. pFileNameWithPath[nPathStrLen] = '\0';
  638. strcat( pFileNameWithPath, pFileName );
  639. if (!InitDirectoryRecursive( soundlist, pFileNameWithPath ))
  640. return false;
  641. }
  642. }
  643. pFileName = filesystem->FindNext( findHandle );
  644. }
  645. return true;
  646. }
  647. void CWaveBrowser::LoadAllSounds()
  648. {
  649. RemoveAllSounds();
  650. Con_Printf( "Building list of all .wavs in sound/ folder\n" );
  651. InitDirectoryRecursive( m_AllSounds, "sound" );
  652. m_pFileTree->PopulateTree();
  653. }
  654. void CWaveBrowser::RemoveAllSounds()
  655. {
  656. int c = m_AllSounds.Count();
  657. for ( int i = 0; i < c; i++ )
  658. {
  659. CWaveFile *wav = m_AllSounds[ i ];
  660. delete wav;
  661. }
  662. m_AllSounds.RemoveAll();
  663. m_Scripts.RemoveAll();
  664. m_CurrentSelection.RemoveAll();
  665. m_pFileTree->Clear();
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Purpose:
  669. //-----------------------------------------------------------------------------
  670. void CWaveBrowser::PopulateTree( char const *subdirectory )
  671. {
  672. int i;
  673. CUtlRBTree< CWaveFile *, int > m_Sorted( 0, 0, NameLessFunc );
  674. bool check_load_sentence_data = false;
  675. char const *texttofind = NULL;
  676. if ( m_bTextSearch )
  677. {
  678. subdirectory = NULL;
  679. texttofind = GetSearchString();
  680. }
  681. int len = 0;
  682. if ( subdirectory )
  683. {
  684. len = Q_strlen( subdirectory );
  685. check_load_sentence_data = ( Q_strstr( subdirectory, "/" ) || subdirectory[0] ) ? true : false;
  686. }
  687. int c = m_AllSounds.Count();
  688. for ( i = 0; i < c; i++ )
  689. {
  690. CWaveFile *wav = m_AllSounds[ i ];
  691. char const *name = wav->GetName();
  692. if ( subdirectory )
  693. {
  694. if ( Q_strnicmp( subdirectory, wav->GetName(), len ) )
  695. continue;
  696. }
  697. if ( m_bTextSearch && texttofind )
  698. {
  699. if ( !Q_stristr( name, texttofind ) )
  700. continue;
  701. }
  702. m_Sorted.Insert( wav );
  703. }
  704. char prevSelectedName[ 512 ];
  705. prevSelectedName[ 0 ] = 0;
  706. if ( m_pListView->getNumSelected() == 1 )
  707. {
  708. int selectedItem = m_pListView->getNextSelectedItem( 0 );
  709. if ( selectedItem >= 0 )
  710. {
  711. // Grab wave name of previously selected item
  712. Q_strcpy( prevSelectedName, m_pListView->getLabel( selectedItem, 0 ) );
  713. }
  714. }
  715. // Repopulate tree
  716. m_pListView->removeAll();
  717. int loadcount = 0;
  718. m_pListView->setDrawingEnabled( false );
  719. int selectedSlot = -1;
  720. CUtlVector< CWaveFile * > list;
  721. for ( i = m_Sorted.FirstInorder(); i != m_Sorted.InvalidIndex(); i = m_Sorted.NextInorder( i ) )
  722. {
  723. CWaveFile *wav = m_Sorted[ i ];
  724. char const *name = wav->GetName();
  725. int slot = m_pListView->add( name );
  726. if ( !Q_stricmp( prevSelectedName, name ) )
  727. {
  728. selectedSlot = slot;
  729. }
  730. if ( ( check_load_sentence_data || m_bTextSearch ) &&
  731. !wav->HasLoadedSentenceInfo() && !wav->IsAsyncLoading() )
  732. {
  733. wav->SetAsyncLoading( true );
  734. list.AddToTail( wav );
  735. }
  736. // m_pListView->setImage( slot, COL_WAV, wav->GetIconIndex() );
  737. m_pListView->setUserData( slot, COL_WAV, (void *)wav );
  738. if ( wav->HasLoadedSentenceInfo() )
  739. {
  740. m_pListView->setLabel( slot, COL_DUCKED, wav->GetVoiceDuck() ? "yes" : "no" );
  741. m_pListView->setLabel( slot, COL_PHONEMES, wav->GetPhonemeCount() || wav->GetWordCount() ? va( "%i [ %i ]", wav->GetWordCount(), wav->GetPhonemeCount() ) : "" );
  742. m_pListView->setLabel( slot, COL_SENTENCE, wav->GetSentenceText() );
  743. }
  744. else
  745. {
  746. m_pListView->setLabel( slot, COL_SENTENCE, "(loading...)" );
  747. }
  748. ++loadcount;
  749. }
  750. m_pListView->setDrawingEnabled( true );
  751. if ( selectedSlot != -1 )
  752. {
  753. m_pListView->setSelected( selectedSlot, true );
  754. m_pListView->scrollToItem( selectedSlot );
  755. }
  756. if ( list.Count() > 0 )
  757. {
  758. fileloader->AddWaveFilesToThread( list );
  759. }
  760. // Con_Printf( "CWaveBrowser: selected %i sounds\n", loadcount );
  761. }
  762. void CWaveBrowser::RepopulateTree()
  763. {
  764. PopulateTree( m_pFileTree->GetSelectedPath() );
  765. }
  766. void CWaveBrowser::BuildSelectionList( CUtlVector< CWaveFile * >& selected )
  767. {
  768. selected.RemoveAll();
  769. int idx = -1;
  770. do
  771. {
  772. idx = m_pListView->getNextSelectedItem( idx );
  773. if ( idx != -1 )
  774. {
  775. CWaveFile *wav = (CWaveFile *)m_pListView->getUserData( idx, 0 );
  776. if ( wav )
  777. {
  778. selected.AddToTail( wav );
  779. }
  780. }
  781. } while ( idx != -1 );
  782. }
  783. void CWaveBrowser::ShowContextMenu( void )
  784. {
  785. SetActiveTool( this );
  786. BuildSelectionList( m_CurrentSelection );
  787. if ( m_CurrentSelection.Count() <= 0 )
  788. return;
  789. POINT pt;
  790. GetCursorPos( &pt );
  791. ScreenToClient( (HWND)getHandle(), &pt );
  792. // New scene, edit comments
  793. mxPopupMenu *pop = new mxPopupMenu();
  794. if ( m_CurrentSelection.Count() == 1 )
  795. {
  796. pop->add ("&Play", IDC_SB_PLAY );
  797. // pop->addSeparator();
  798. }
  799. // pop->add( "Import Sentence Data", IDC_SB_IMPORTSENTENCE );
  800. // pop->add( "Export Sentence Data", IDC_SB_EXPORTSENTENCE );
  801. pop->popup( this, pt.x, pt.y );
  802. }
  803. void CWaveBrowser::OnPlay()
  804. {
  805. SetActiveTool( this );
  806. BuildSelectionList( m_CurrentSelection );
  807. if ( m_CurrentSelection.Count() == 1 )
  808. {
  809. CWaveFile *wav = m_CurrentSelection[ 0 ];
  810. if ( wav )
  811. {
  812. wav->Play();
  813. }
  814. }
  815. }
  816. static void SplitFileName( char const *in, char *path, int maxpath, char *filename, int maxfilename )
  817. {
  818. char drive[_MAX_DRIVE];
  819. char dir[_MAX_DIR];
  820. char fname[_MAX_FNAME];
  821. char ext[_MAX_EXT];
  822. _splitpath( in, drive, dir, fname, ext );
  823. if ( dir[0] )
  824. {
  825. Q_snprintf( path, maxpath, "\\%s", dir );
  826. }
  827. else
  828. {
  829. path[0] = 0;
  830. }
  831. Q_snprintf( filename, maxfilename, "%s%s", fname, ext );
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose:
  835. // Input : *se -
  836. //-----------------------------------------------------------------------------
  837. void CWaveBrowser::JumpToItem( CWaveFile *wav )
  838. {
  839. SetActiveTool( this );
  840. char path[ 256 ];
  841. char filename[ 256 ];
  842. SplitFileName( wav->GetFileName(), path, sizeof( path ), filename, sizeof( filename ) );
  843. char *usepath = path + Q_strlen( "/sound/" );
  844. PopulateTree( usepath );
  845. int idx = 0;
  846. int c = m_pListView->getItemCount();
  847. for ( ; idx < c; idx++ )
  848. {
  849. CWaveFile *item = (CWaveFile *)m_pListView->getUserData( idx, 0 );
  850. if ( !Q_stricmp( item->GetFileName(), wav->GetFileName() ) )
  851. {
  852. break;
  853. }
  854. }
  855. if ( idx < c )
  856. {
  857. m_pListView->scrollToItem( idx );
  858. }
  859. }
  860. CWaveFile *CWaveBrowser::FindEntry( char const *wavname, bool jump /*= false*/ )
  861. {
  862. int idx = m_AllSounds.Find( wavname );
  863. if ( idx != m_AllSounds.InvalidIndex() )
  864. {
  865. CWaveFile *wav = m_AllSounds[ idx ];
  866. if ( jump )
  867. {
  868. JumpToItem( wav );
  869. }
  870. return wav;
  871. }
  872. return NULL;
  873. }
  874. int CWaveBrowser::GetSoundCount() const
  875. {
  876. return m_AllSounds.Count();
  877. }
  878. CWaveFile *CWaveBrowser::GetSound( int index )
  879. {
  880. if ( index < 0 || index >= (int)m_AllSounds.Count() )
  881. return NULL;
  882. return m_AllSounds[ index ];
  883. }
  884. void CWaveBrowser::OnSearch()
  885. {
  886. SetActiveTool( this );
  887. m_bTextSearch = true;
  888. PopulateTree( GetSearchString());
  889. }
  890. void CWaveBrowser::OnCancelSearch()
  891. {
  892. SetActiveTool( this );
  893. m_bTextSearch = false;
  894. PopulateTree( m_pFileTree->GetSelectedPath() );
  895. }
  896. char const *CWaveBrowser::GetSearchString()
  897. {
  898. return m_pOptions->GetSearchString();
  899. }
  900. void CWaveBrowser::Think( float dt )
  901. {
  902. int pending = fileloader->GetPendingLoadCount();
  903. if ( pending != m_nPrevProcessed )
  904. {
  905. m_nPrevProcessed = pending;
  906. // Put into suffix of window title
  907. if ( pending == 0 )
  908. {
  909. SetSuffix( "" );
  910. }
  911. else
  912. {
  913. SetSuffix( va( " - %i", pending ) );
  914. }
  915. }
  916. int c = fileloader->ProcessCompleted();
  917. if ( c > 0 )
  918. {
  919. RepopulateTree();
  920. }
  921. }
  922. void CWaveBrowser::SetEvent( CChoreoEvent *event )
  923. {
  924. if ( event->GetType() != CChoreoEvent::SPEAK )
  925. return;
  926. SetCurrent( FacePoser_TranslateSoundName( event->GetParameters() ) );
  927. }
  928. void CWaveBrowser::SetCurrent( char const *filename )
  929. {
  930. // Get sound name and look up .wav from it
  931. char const *p = filename;
  932. if ( p &&
  933. ( !Q_strnicmp( p, "sound/", 6 ) || !Q_strnicmp( p, "sound\\", 6 ) ) )
  934. {
  935. p += 6;
  936. }
  937. char fn[ 512 ];
  938. Q_strncpy( fn, p, sizeof( fn ) );
  939. Q_FixSlashes( fn );
  940. int i;
  941. int c = m_pListView->getItemCount();
  942. for ( i = 0; i < c; ++i )
  943. {
  944. CWaveFile *wav = reinterpret_cast< CWaveFile * >( m_pListView->getUserData( i, COL_WAV ) );
  945. if ( !wav )
  946. continue;
  947. char fixed[ 512 ];
  948. Q_strncpy( fixed, wav->GetName(), sizeof( fixed ) );
  949. Q_FixSlashes( fixed );
  950. if ( !Q_stricmp( fixed, fn ) )
  951. {
  952. m_pListView->scrollToItem( i );
  953. m_pListView->setSelected( i, true );
  954. }
  955. else
  956. {
  957. m_pListView->setSelected( i, false );
  958. }
  959. }
  960. }