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.

2476 lines
52 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: A simple .mp3 player example
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #if 0
  8. #include "mp3player.h"
  9. #include "keyvalues.h"
  10. #include "filesystem.h"
  11. #include "vgui_controls/MenuButton.h"
  12. #include "vgui_controls/Menu.h"
  13. #include "vgui_controls/Button.h"
  14. #include "vgui_controls/CheckButton.h"
  15. #include "vgui_controls/Slider.h"
  16. #include "vgui_controls/ListPanel.h"
  17. #include "vgui/IPanel.h"
  18. #include "vgui/IVgui.h"
  19. #include "vgui/ISurface.h"
  20. #include "vgui/IInput.h"
  21. #include "vgui/ILocalize.h"
  22. #include "vgui_controls/PHandle.h"
  23. #include "vgui_controls/PropertySheet.h"
  24. #include "vgui_controls/PropertyPage.h"
  25. #include "vgui_controls/TreeView.h"
  26. #include "vgui_controls/FileOpenDialog.h"
  27. #include "vgui_controls/DirectorySelectDialog.h"
  28. #include "checksum_crc.h"
  29. #include "engine/IEngineSound.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. using namespace vgui;
  33. // Singleton
  34. static CMP3Player *g_pPlayer = NULL;
  35. vgui::Panel *GetSDKRootPanel();
  36. // Time between songs
  37. #define END_GAP_TIME 1.0f
  38. #define SOUND_ROOT "sound"
  39. #define MUTED_VOLUME 0.02f
  40. #define TREE_TEXT_COLOR Color( 200, 255, 200, 255 )
  41. #define LIST_TEXT_COLOR TREE_TEXT_COLOR
  42. #define DB_FILENAME "resource/mp3player_db.txt"
  43. #define MP3_SETTINGS_FILE "resource/mp3settings.txt"
  44. #define MP3_DEFAULT_MP3DIR "c:\\my music"
  45. CMP3Player *GetMP3Player()
  46. {
  47. Assert( g_pPlayer );
  48. return g_pPlayer;
  49. }
  50. static void mp3_f()
  51. {
  52. CMP3Player *player = GetMP3Player();
  53. if ( player )
  54. {
  55. player->SetVisible( !player->IsVisible() );
  56. }
  57. }
  58. void MP3Player_Create( vgui::VPANEL parent )
  59. {
  60. Assert( !g_pPlayer );
  61. new CMP3Player( parent, "MP3Player" );
  62. #if 0
  63. mp3_f();
  64. #endif
  65. }
  66. void MP3Player_Destroy()
  67. {
  68. if ( g_pPlayer )
  69. {
  70. g_pPlayer->MarkForDeletion();
  71. g_pPlayer = NULL;
  72. }
  73. }
  74. static ConCommand mp3( "mp3", mp3_f, "Show/hide mp3 player UI." );
  75. //-----------------------------------------------------------------------------
  76. // Purpose: This assumes artist/album/file.mp3!!!
  77. // Input : *relative -
  78. // *artist -
  79. // artistlen -
  80. // *album -
  81. // albumlen -
  82. // Output : static bool
  83. //-----------------------------------------------------------------------------
  84. static bool SplitArtistAlbum( char const *relative, char *artist, size_t artistlen, char *album, size_t albumlen )
  85. {
  86. artist[ 0 ] = 0;
  87. album[ 0 ] = 0;
  88. char str[ 512 ];
  89. Q_strncpy( str, relative, sizeof( str ) );
  90. char seps[] = "/\\";
  91. char *p = strtok( str, seps );
  92. int pos = 0;
  93. while ( p )
  94. {
  95. switch ( pos )
  96. {
  97. default:
  98. break;
  99. case 0:
  100. Q_strncpy( artist, p, artistlen );
  101. break;
  102. case 1:
  103. Q_strncpy( album, p, albumlen );
  104. break;
  105. case 2:
  106. if ( !Q_stristr( p, ".mp3" ) )
  107. {
  108. artist[ 0 ] = 0;
  109. album[ 0 ] = 0;
  110. return false;
  111. }
  112. return true;
  113. break;
  114. }
  115. ++pos;
  116. p = strtok( NULL, seps );
  117. }
  118. return false;
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. //-----------------------------------------------------------------------------
  123. class CMP3FileListPage : public PropertyPage
  124. {
  125. DECLARE_CLASS_SIMPLE( CMP3FileListPage, PropertyPage );
  126. public:
  127. CMP3FileListPage( Panel *parent, CMP3Player *player, char const *panelName ) :
  128. BaseClass( parent, panelName ),
  129. m_pPlayer( player )
  130. {
  131. m_pList = new ListPanel( this, "FileList" );
  132. m_pList->AddColumnHeader( 0, "File", "File", 200, ListPanel::COLUMN_RESIZEWITHWINDOW );
  133. m_pList->AddColumnHeader( 1, "Artist", "Artist", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
  134. m_pList->AddColumnHeader( 2, "Album", "Album", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
  135. }
  136. void Reset()
  137. {
  138. m_pList->DeleteAllItems();
  139. }
  140. virtual void ApplySchemeSettings( IScheme *pScheme )
  141. {
  142. BaseClass::ApplySchemeSettings( pScheme );
  143. m_pList->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
  144. m_pList->SetFgColor( LIST_TEXT_COLOR );
  145. }
  146. virtual void PerformLayout()
  147. {
  148. BaseClass::PerformLayout();
  149. int w, h;
  150. GetSize( w, h );
  151. m_pList->SetBounds( 0, 0, w, h );
  152. }
  153. void AddSong( int songIndex )
  154. {
  155. Assert( m_pPlayer );
  156. const MP3File_t* songInfo = m_pPlayer->GetSongInfo( songIndex );
  157. if ( !songInfo )
  158. {
  159. return;
  160. }
  161. KeyValues *kv = new KeyValues( "LI" );
  162. kv->SetString( "File", songInfo->shortname.String() );
  163. char fn[ 512 ];
  164. if ( g_pFullFileSystem->String( songInfo->filename, fn, sizeof( fn ) ) )
  165. {
  166. char artist[ 256 ];
  167. char album[ 256 ];
  168. if ( SplitArtistAlbum( fn, artist, sizeof( artist ), album, sizeof( album ) ) )
  169. {
  170. kv->SetString( "Artist", artist );
  171. kv->SetString( "Album", album );
  172. }
  173. }
  174. kv->SetInt( "SongIndex", songIndex );
  175. m_pList->AddItem( kv, 0, false, false );
  176. kv->deleteThis();
  177. }
  178. void GetSelectedSongs( CUtlVector< int >&list )
  179. {
  180. list.RemoveAll();
  181. int selCount = m_pList->GetSelectedItemsCount();
  182. if ( selCount <= 0 )
  183. {
  184. return;
  185. }
  186. for ( int i = 0; i < selCount; ++i )
  187. {
  188. int itemId = m_pList->GetSelectedItem( 0 );
  189. KeyValues *kv = m_pList->GetItem( itemId );
  190. if ( !kv )
  191. {
  192. continue;
  193. }
  194. int song = kv->GetInt( "SongIndex", -1 );
  195. if ( song == -1 )
  196. {
  197. continue;
  198. }
  199. list.AddToTail( song );
  200. }
  201. }
  202. MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
  203. virtual void OnCommand( char const *cmd );
  204. MESSAGE_FUNC( OnItemSelected, "ItemSelected" )
  205. {
  206. CUtlVector< int > songList;
  207. GetSelectedSongs( songList );
  208. m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_FILELIST, songList );
  209. }
  210. private:
  211. CMP3Player *m_pPlayer;
  212. ListPanel *m_pList;
  213. DHANDLE< Menu > m_hMenu;
  214. };
  215. void CMP3FileListPage::OnOpenContextMenu( int itemID )
  216. {
  217. if ( m_hMenu.Get() != NULL )
  218. {
  219. delete m_hMenu.Get();
  220. }
  221. m_hMenu = new Menu( this, "FileListContext" );
  222. m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaylistAdd", "addsong", this );
  223. int x, y;
  224. input()->GetCursorPos( x, y );
  225. m_hMenu->SetPos( x, y );
  226. m_hMenu->SetVisible( true );
  227. }
  228. void CMP3FileListPage::OnCommand( char const *cmd )
  229. {
  230. if ( !Q_stricmp( cmd, "addsong" ) )
  231. {
  232. // Get selected item
  233. int c = m_pList->GetSelectedItemsCount();
  234. if ( c > 0 )
  235. {
  236. int itemId = m_pList->GetSelectedItem( 0 );
  237. KeyValues *kv = m_pList->GetItem( itemId );
  238. if ( kv )
  239. {
  240. int songIndex = kv->GetInt( "SongIndex" );
  241. m_pPlayer->AddToPlayList( songIndex, false );
  242. }
  243. }
  244. }
  245. else
  246. {
  247. BaseClass::OnCommand( cmd );
  248. }
  249. }
  250. class CMP3PlayListPage : public PropertyPage
  251. {
  252. DECLARE_CLASS_SIMPLE( CMP3PlayListPage, PropertyPage );
  253. public:
  254. CMP3PlayListPage( Panel *parent, CMP3Player *player, char const *panelName ) :
  255. BaseClass( parent, panelName ),
  256. m_pPlayer( player )
  257. {
  258. m_pList = new ListPanel( this, "PlayList" );
  259. m_pList->AddColumnHeader( 0, "File", "File", 400, ListPanel::COLUMN_RESIZEWITHWINDOW );
  260. m_pList->AddColumnHeader( 1, "Artist", "Artist", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
  261. m_pList->AddColumnHeader( 2, "Album", "Album", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
  262. }
  263. void Reset()
  264. {
  265. m_pList->DeleteAllItems();
  266. }
  267. virtual void ApplySchemeSettings( IScheme *pScheme )
  268. {
  269. BaseClass::ApplySchemeSettings( pScheme );
  270. m_pList->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
  271. m_pList->SetFgColor( LIST_TEXT_COLOR );
  272. }
  273. virtual void PerformLayout()
  274. {
  275. BaseClass::PerformLayout();
  276. int w, h;
  277. GetSize( w, h );
  278. m_pList->SetBounds( 0, 0, w, h );
  279. }
  280. void AddSong( int songIndex )
  281. {
  282. Assert( m_pPlayer );
  283. const MP3File_t* songInfo = m_pPlayer->GetSongInfo( songIndex );
  284. if ( !songInfo )
  285. {
  286. return;
  287. }
  288. KeyValues *kv = new KeyValues( "LI" );
  289. kv->SetString( "File", songInfo->shortname.String() );
  290. char fn[ 512 ];
  291. if ( g_pFullFileSystem->String( songInfo->filename, fn, sizeof( fn ) ) )
  292. {
  293. char artist[ 256 ];
  294. char album[ 256 ];
  295. if ( SplitArtistAlbum( fn, artist, sizeof( artist ), album, sizeof( album ) ) )
  296. {
  297. kv->SetString( "Artist", artist );
  298. kv->SetString( "Album", album );
  299. }
  300. }
  301. kv->SetInt( "SongIndex", songIndex );
  302. m_pList->AddItem( kv, 0, false, false );
  303. kv->deleteThis();
  304. }
  305. void RemoveSong( int songIndex )
  306. {
  307. // Get selected item
  308. int c = m_pList->GetSelectedItemsCount();
  309. if ( c > 0 )
  310. {
  311. int itemId = m_pList->GetSelectedItem( 0 );
  312. KeyValues *kv = m_pList->GetItem( itemId );
  313. if ( kv && ( kv->GetInt( "SongIndex", -1 ) == songIndex ) )
  314. {
  315. m_pList->RemoveItem( itemId );
  316. }
  317. }
  318. }
  319. void GetSelectedSongs( CUtlVector< int >&list )
  320. {
  321. list.RemoveAll();
  322. int selCount = m_pList->GetSelectedItemsCount();
  323. if ( selCount <= 0 )
  324. {
  325. return;
  326. }
  327. for ( int i = 0; i < selCount; ++i )
  328. {
  329. int itemId = m_pList->GetSelectedItem( 0 );
  330. KeyValues *kv = m_pList->GetItem( itemId );
  331. if ( !kv )
  332. {
  333. continue;
  334. }
  335. int song = kv->GetInt( "SongIndex", -1 );
  336. if ( song == -1 )
  337. {
  338. continue;
  339. }
  340. list.AddToTail( song );
  341. }
  342. }
  343. MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
  344. virtual void OnCommand( char const *cmd );
  345. MESSAGE_FUNC( OnItemSelected, "ItemSelected" )
  346. {
  347. CUtlVector< int > songList;
  348. GetSelectedSongs( songList );
  349. m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_PLAYLIST, songList );
  350. }
  351. void OnItemPlaying( int listIndex )
  352. {
  353. int itemId = m_pList->GetItemIDFromRow( listIndex );
  354. m_pList->ClearSelectedItems();
  355. m_pList->SetSingleSelectedItem( itemId );
  356. }
  357. private:
  358. CMP3Player *m_pPlayer;
  359. ListPanel *m_pList;
  360. DHANDLE< Menu > m_hMenu;
  361. };
  362. void CMP3PlayListPage::OnOpenContextMenu( int itemID )
  363. {
  364. if ( m_hMenu.Get() != NULL )
  365. {
  366. delete m_hMenu.Get();
  367. }
  368. m_hMenu = new Menu( this, "PlayListContext" );
  369. m_hMenu->AddMenuItem( "Remove", "#PlayListRemove", "removesong", this );
  370. m_hMenu->AddMenuItem( "Clear", "#PlayListClear", "clear", this );
  371. m_hMenu->AddMenuItem( "Load", "#PlayListLoad", "load", this );
  372. m_hMenu->AddMenuItem( "Save", "#PlayListSave", "save", this );
  373. int x, y;
  374. input()->GetCursorPos( x, y );
  375. m_hMenu->SetPos( x, y );
  376. m_hMenu->SetVisible( true );
  377. }
  378. void CMP3PlayListPage::OnCommand( char const *cmd )
  379. {
  380. if ( !Q_stricmp( cmd, "removesong" ) )
  381. {
  382. // Get selected item
  383. int c = m_pList->GetSelectedItemsCount();
  384. if ( c > 0 )
  385. {
  386. int itemId = m_pList->GetSelectedItem( 0 );
  387. KeyValues *kv = m_pList->GetItem( itemId );
  388. if ( kv )
  389. {
  390. int songIndex = kv->GetInt( "SongIndex" );
  391. m_pPlayer->RemoveFromPlayList( songIndex );
  392. }
  393. }
  394. }
  395. else if ( !Q_stricmp( cmd, "clear" ) )
  396. {
  397. m_pPlayer->ClearPlayList();
  398. }
  399. else if ( !Q_stricmp( cmd, "load" ) )
  400. {
  401. m_pPlayer->OnLoadPlayList();
  402. }
  403. else if ( !Q_stricmp( cmd, "save" ) )
  404. {
  405. m_pPlayer->OnSavePlayList();
  406. }
  407. else if ( !Q_stricmp( cmd, "saveas" ) )
  408. {
  409. m_pPlayer->OnSavePlayListAs();
  410. }
  411. else
  412. {
  413. BaseClass::OnCommand( cmd );
  414. }
  415. }
  416. class CMP3FileSheet : public PropertySheet
  417. {
  418. DECLARE_CLASS_SIMPLE( CMP3FileSheet, PropertySheet );
  419. public:
  420. CMP3FileSheet( CMP3Player *player, char const *panelName );
  421. void ResetFileList()
  422. {
  423. if ( m_pFileList )
  424. {
  425. m_pFileList->Reset();
  426. }
  427. }
  428. void AddSongToFileList( int songIndex )
  429. {
  430. if ( m_pFileList )
  431. {
  432. m_pFileList->AddSong( songIndex );
  433. }
  434. }
  435. void ResetPlayList()
  436. {
  437. if ( m_pPlayList )
  438. {
  439. m_pPlayList->Reset();
  440. }
  441. }
  442. void AddSongToPlayList( int songIndex )
  443. {
  444. if ( m_pPlayList )
  445. {
  446. m_pPlayList->AddSong( songIndex );
  447. }
  448. }
  449. void RemoveSongFromPlayList( int songIndex )
  450. {
  451. if ( m_pPlayList )
  452. {
  453. m_pPlayList->RemoveSong( songIndex );
  454. }
  455. }
  456. void OnPlayListItemPlaying( int listIndex )
  457. {
  458. if ( m_pPlayList )
  459. {
  460. m_pPlayList->OnItemPlaying( listIndex );
  461. }
  462. }
  463. protected:
  464. CMP3Player *m_pPlayer;
  465. CMP3PlayListPage *m_pPlayList;
  466. CMP3FileListPage *m_pFileList;
  467. };
  468. CMP3FileSheet::CMP3FileSheet( CMP3Player *player, char const *panelName ) :
  469. BaseClass( (Panel *)player, panelName ),
  470. m_pPlayer( player )
  471. {
  472. m_pPlayList = new CMP3PlayListPage( this, player, "PlayList" );
  473. m_pFileList = new CMP3FileListPage( this, player, "FileList" );
  474. AddPage( m_pPlayList, "#PlayListTab" );
  475. AddPage( m_pFileList, "#FileListTab" );
  476. SetActivePage( m_pPlayList );
  477. }
  478. class CMP3TreeControl : public TreeView
  479. {
  480. DECLARE_CLASS_SIMPLE( CMP3TreeControl, TreeView );
  481. public:
  482. CMP3TreeControl( CMP3Player *player, char const *panelName );
  483. int GetSelectedSongIndex();
  484. MESSAGE_FUNC( OnTreeViewItemSelected, "TreeViewItemSelected" )
  485. {
  486. CUtlVector< int > songList;
  487. int idx = GetSelectedSongIndex();
  488. if ( idx != -1 )
  489. {
  490. songList.AddToTail( idx );
  491. }
  492. m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_TREE, songList );
  493. if ( vgui::input()->IsMouseDown( MOUSE_RIGHT ) )
  494. {
  495. OpenContextMenu();
  496. }
  497. }
  498. virtual void OnCommand( char const *cmd );
  499. private:
  500. void OpenContextMenu();
  501. CMP3Player *m_pPlayer;
  502. DHANDLE< Menu > m_hMenu;
  503. };
  504. CMP3TreeControl::CMP3TreeControl( CMP3Player *player, char const *panelName ) :
  505. BaseClass( (Panel *)player, panelName ),
  506. m_pPlayer( player )
  507. {
  508. AddActionSignalTarget( this );
  509. }
  510. int CMP3TreeControl::GetSelectedSongIndex()
  511. {
  512. CUtlVector< KeyValues * > kv;
  513. GetSelectedItemData( kv );
  514. if ( !kv.Count() )
  515. {
  516. return -1;
  517. }
  518. return kv[ 0 ]->GetInt( "SongIndex", -1 );
  519. }
  520. void CMP3TreeControl::OpenContextMenu()
  521. {
  522. if ( m_hMenu.Get() != NULL )
  523. {
  524. delete m_hMenu.Get();
  525. }
  526. m_hMenu = new Menu( this, "TreeContext" );
  527. m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaylistAdd", "addsong", this );
  528. m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaySong", "playsong", this );
  529. int x, y;
  530. input()->GetCursorPos( x, y );
  531. m_hMenu->SetPos( x, y );
  532. m_hMenu->SetVisible( true );
  533. }
  534. void CMP3TreeControl::OnCommand( char const *cmd )
  535. {
  536. if ( !Q_stricmp( cmd, "addsong" ) )
  537. {
  538. // Get selected item
  539. int songIndex = GetSelectedSongIndex();
  540. if ( songIndex >= 0 )
  541. {
  542. m_pPlayer->AddToPlayList( songIndex, false );
  543. }
  544. }
  545. else if ( !Q_stricmp( cmd, "playsong" ) )
  546. {
  547. int songIndex = GetSelectedSongIndex();
  548. if ( songIndex >= 0 )
  549. {
  550. m_pPlayer->AddToPlayList( songIndex, true );
  551. }
  552. }
  553. else
  554. {
  555. BaseClass::OnCommand( cmd );
  556. }
  557. }
  558. class CMP3SongProgress : public Slider
  559. {
  560. DECLARE_CLASS_SIMPLE( CMP3SongProgress, Slider );
  561. public:
  562. CMP3SongProgress( Panel *parent, char const *panelName ) :
  563. BaseClass( parent, panelName )
  564. {
  565. SetPaintEnabled( false );
  566. SetRange( 0, 100 );
  567. }
  568. void SetProgress( float frac )
  569. {
  570. SetValue( (int)( frac * 100.0f + 0.5f ), false );
  571. }
  572. virtual void PaintBackground()
  573. {
  574. //BaseClass::PaintBackground();
  575. int w, h;
  576. GetSize( w, h );
  577. float frac = (float)GetValue() * 0.01f;
  578. int barend = ( int )( (float)( w - 2 ) * frac + 0.5f );
  579. surface()->DrawSetColor( GetBgColor() );
  580. surface()->DrawFilledRect( 0, 0, w, h );
  581. surface()->DrawSetColor( GetFgColor() );
  582. surface()->DrawFilledRect( 1, 1, barend, h - 1 );
  583. }
  584. virtual void ApplySchemeSettings( IScheme *pScheme )
  585. {
  586. BaseClass::ApplySchemeSettings( pScheme );
  587. SetFgColor( TREE_TEXT_COLOR );
  588. SetBgColor( pScheme->GetColor( "BorderDark", Color( 0, 0, 0, 255 ) ) );
  589. }
  590. };
  591. CMP3Player::CMP3Player( VPANEL parent, char const *panelName ) :
  592. BaseClass( NULL, panelName ),
  593. m_SelectionFrom( SONG_FROM_UNKNOWN ),
  594. m_bDirty( false ),
  595. m_bSettingsDirty( false ),
  596. m_PlayListFileName( UTL_INVAL_SYMBOL ),
  597. m_bSavingFile( false ),
  598. m_bEnableAutoAdvance( true )
  599. {
  600. g_pPlayer = this;
  601. // Get strings...
  602. g_pVGuiLocalize->AddFile( "resource/mp3player_%language%.txt" );
  603. SetParent( parent );
  604. SetMoveable( true );
  605. SetSizeable( true );
  606. SetMenuButtonVisible( false );
  607. SetMinimizeButtonVisible( false );
  608. SetMaximizeButtonVisible( false );
  609. SetCloseButtonVisible( true );
  610. m_pOptions = new MenuButton( this, "Menu", "#MP3Menu" );
  611. Menu *options = new Menu( m_pOptions, "Options" );
  612. options->AddMenuItem( "AddDir", "#AddDirectory", new KeyValues( "Command", "command", "adddirectory" ), this );
  613. options->AddMenuItem( "AddGame", "#AddGameSongs", new KeyValues( "Command", "command", "addgamesongs" ), this );
  614. options->AddMenuItem( "Refresh", "#RefreshDb", new KeyValues( "Command", "command", "refresh" ), this );
  615. m_pOptions->SetMenu( options );
  616. m_pTree = new CMP3TreeControl( this, "Tree" );
  617. m_pTree->MakeReadyForUse();
  618. // Make tree use small font
  619. IScheme *pscheme = scheme()->GetIScheme( GetScheme() );
  620. HFont treeFont = pscheme->GetFont( "DefaultVerySmall" );
  621. m_pTree->SetFont( treeFont );
  622. m_pFileSheet = new CMP3FileSheet( this, "FileSheet" );
  623. m_pPlay = new Button( this, "Play", "#Play", this, "play" );
  624. m_pStop = new Button( this, "Stop", "#Stop", this, "stop" );
  625. m_pNext = new Button( this, "NextTrack", "#Next", this, "nexttrack" );
  626. m_pPrev = new Button( this, "PrevTrack", "#Prev", this, "prevtrack" );
  627. m_pMute = new CheckButton( this, "Mute", "#Mute" );
  628. m_pShuffle = new CheckButton( this, "Shuffle", "#Shuffle" );
  629. m_pVolume = new Slider( this, "Volume" );
  630. m_pVolume->SetRange( (int)( MUTED_VOLUME * 100.0f ), 100 );
  631. m_pVolume->SetValue( 100 );
  632. m_pCurrentSong = new Label( this, "SongName", "#NoSong" );
  633. m_pDuration = new Label( this, "SongDuration", "" );
  634. m_pSongProgress = new CMP3SongProgress( this, "Progress" );
  635. m_pSongProgress->AddActionSignalTarget( this );
  636. SetSize( 400, 450 );
  637. SetMinimumSize( 350, 400 );
  638. SetTitle( "#MP3PlayerTitle", true );
  639. LoadControlSettings( "resource/MP3Player.res" );
  640. m_pCurrentSong->SetText( "#NoSong" );
  641. m_pDuration->SetText( "" );
  642. m_nCurrentFile = -1;
  643. m_bFirstTime = true;
  644. m_bPlaying = false;
  645. m_SongStart = -1.0f;
  646. m_nSongGuid = 0;
  647. m_nCurrentSong = 0;
  648. m_nCurrentPlaylistSong = 0;
  649. m_flCurrentVolume = 1.0f;
  650. m_bMuted = false;
  651. vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
  652. }
  653. CMP3Player::~CMP3Player()
  654. {
  655. if ( m_bDirty )
  656. {
  657. SaveDb( DB_FILENAME );
  658. }
  659. if ( m_bSettingsDirty )
  660. {
  661. SaveSettings();
  662. }
  663. DeleteSoundDirectories();
  664. RemoveTempSounds();
  665. }
  666. void CMP3Player::DeleteSoundDirectories()
  667. {
  668. int c = m_SoundDirectories.Count();
  669. for ( int i = c - 1 ; i >= 0 ; --i )
  670. {
  671. delete m_SoundDirectories[ i ];
  672. }
  673. m_SoundDirectories.RemoveAll();
  674. }
  675. void CMP3Player::RemoveTempSounds()
  676. {
  677. FileFindHandle_t fh;
  678. char path[ 512 ];
  679. Q_strncpy( path, "sound/_mp3/*.mp3", sizeof( path ) );
  680. char const *fn = g_pFullFileSystem->FindFirstEx( path, "MOD", &fh );
  681. if ( fn )
  682. {
  683. do
  684. {
  685. if ( fn[0] != '.' )
  686. {
  687. char ext[ 10 ];
  688. Q_ExtractFileExtension( fn, ext, sizeof( ext ) );
  689. if ( !Q_stricmp( ext, "mp3" ) )
  690. {
  691. char killname[ 512 ];
  692. Q_snprintf( killname, sizeof( killname ), "sound/_mp3/%s", fn );
  693. g_pFullFileSystem->RemoveFile( killname, "MOD" );
  694. }
  695. }
  696. fn = g_pFullFileSystem->FindNext( fh );
  697. } while ( fn );
  698. g_pFullFileSystem->FindClose( fh );
  699. }
  700. }
  701. void CMP3Player::WipeSoundDirectories()
  702. {
  703. int c = m_SoundDirectories.Count();
  704. for ( int i = c - 1 ; i >= 0 ; --i )
  705. {
  706. SoundDirectory_t *sd = m_SoundDirectories[ i ];
  707. sd->m_pTree->DeleteSubdirectories();
  708. sd->m_pTree->m_FilesInDirectory.RemoveAll();
  709. }
  710. }
  711. void CMP3Player::AddGameSounds( bool recurse )
  712. {
  713. SoundDirectory_t *gamesounds = NULL;
  714. int idx = FindSoundDirectory( "" );
  715. if ( idx == m_SoundDirectories.InvalidIndex() )
  716. {
  717. gamesounds = new SoundDirectory_t( m_SoundDirectories.Count() );
  718. gamesounds->m_bGameSound = true;
  719. gamesounds->m_Root = "";
  720. gamesounds->m_pTree = new MP3Dir_t();
  721. gamesounds->m_pTree->m_DirName = "Game Sounds";
  722. gamesounds->m_pTree->m_FullDirPath = "";
  723. m_SoundDirectories.AddToTail( gamesounds );
  724. }
  725. else
  726. {
  727. gamesounds = m_SoundDirectories[ idx ];
  728. if ( recurse )
  729. {
  730. gamesounds->m_pTree->DeleteSubdirectories();
  731. gamesounds->m_pTree->m_FilesInDirectory.RemoveAll();
  732. }
  733. }
  734. if ( recurse && gamesounds )
  735. {
  736. m_nFilesAdded = 0;
  737. RecursiveFindMP3Files( gamesounds, SOUND_ROOT, "GAME" );
  738. }
  739. }
  740. void CMP3Player::OnRefresh()
  741. {
  742. CUtlVector< CUtlSymbol > dirnames;
  743. int i, c;
  744. CUtlVector< FileNameHandle_t > m_PlayListFiles;
  745. int pcount = m_PlayList.Count();
  746. for ( i = 0; i < pcount; ++i )
  747. {
  748. m_PlayListFiles.AddToTail( m_Files[ m_PlayList[ i ] ].filename );
  749. }
  750. m_Files.RemoveAll();
  751. WipeSoundDirectories();
  752. ClearPlayList();
  753. c = m_SoundDirectories.Count();
  754. for ( i = 0; i < c; ++i )
  755. {
  756. SoundDirectory_t *sd = m_SoundDirectories[ i ];
  757. // Now enumerate all .mp3 files in subfolders of this
  758. if ( sd->m_bGameSound )
  759. {
  760. m_nFilesAdded = 0;
  761. RecursiveFindMP3Files( sd, SOUND_ROOT, "GAME" );
  762. }
  763. else
  764. {
  765. // Add to search path
  766. g_pFullFileSystem->AddSearchPath( sd->m_Root.String(), "MP3" );
  767. // Don't pollute regular searches...
  768. g_pFullFileSystem->MarkPathIDByRequestOnly( "MP3", true );
  769. m_nFilesAdded = 0;
  770. RecursiveFindMP3Files( sd, "", "MP3" );
  771. }
  772. }
  773. for ( i = 0; i < pcount; ++i )
  774. {
  775. char fn[ 512 ];
  776. if ( g_pFullFileSystem->String( m_PlayListFiles[ i ], fn, sizeof( fn ) ) )
  777. {
  778. // Find index for song
  779. int songIndex = FindSong( fn );
  780. if ( songIndex >= 0 )
  781. {
  782. AddToPlayList( songIndex, false );
  783. }
  784. }
  785. }
  786. PopulateTree();
  787. m_bDirty = true;
  788. }
  789. void CMP3Player::SetVisible( bool state )
  790. {
  791. BaseClass::SetVisible( state );
  792. if ( m_bFirstTime && state )
  793. {
  794. MoveToCenterOfScreen();
  795. m_bFirstTime = false;
  796. LoadSettings();
  797. if ( !RestoreDb( DB_FILENAME ) && m_Files.Count() == 0 )
  798. {
  799. // Load the "game" stuff
  800. OnRefresh();
  801. }
  802. PopulateTree();
  803. }
  804. }
  805. void CMP3Player::ApplySchemeSettings(IScheme *pScheme)
  806. {
  807. BaseClass::ApplySchemeSettings(pScheme);
  808. HFont treeFont = pScheme->GetFont( "DefaultVerySmall" );
  809. m_pTree->SetFont( treeFont );
  810. }
  811. void CMP3Player::OnCommand( char const *cmd )
  812. {
  813. if ( !Q_stricmp( cmd, "OnClose" ) )
  814. {
  815. SetVisible( false );
  816. }
  817. else if ( !Q_stricmp( cmd, "play" ) )
  818. {
  819. OnPlay();
  820. }
  821. else if ( !Q_stricmp( cmd, "stop" ) )
  822. {
  823. OnStop();
  824. }
  825. else if ( !Q_stricmp( cmd, "nexttrack" ) )
  826. {
  827. OnNextTrack();
  828. }
  829. else if ( !Q_stricmp( cmd, "prevtrack" ) )
  830. {
  831. OnPrevTrack();
  832. }
  833. else if ( !Q_stricmp( cmd, "refresh" ) )
  834. {
  835. OnRefresh();
  836. }
  837. else if ( !Q_stricmp( cmd, "adddirectory" ) )
  838. {
  839. ShowDirectorySelectDialog();
  840. }
  841. else if ( !Q_stricmp( cmd, "addgamesongs" ) )
  842. {
  843. AddGameSounds( true );
  844. PopulateTree();
  845. }
  846. else
  847. {
  848. BaseClass::OnCommand( cmd );
  849. }
  850. }
  851. void CMP3Player::SplitFile( CUtlVector< CUtlSymbol >& splitList, char const *relative )
  852. {
  853. char work[ 512 ];
  854. Q_strncpy( work, relative, sizeof( work ) );
  855. char const *separators = "/\\";
  856. char *token = strtok( work, separators );
  857. while ( token )
  858. {
  859. CUtlSymbol sym = token;
  860. splitList.AddToTail( sym );
  861. token = strtok( NULL, separators );
  862. }
  863. }
  864. MP3Dir_t *CMP3Player::FindOrAddSubdirectory( MP3Dir_t *parent, char const *dirname )
  865. {
  866. Assert( parent );
  867. int c = parent->m_Subdirectories.Count();
  868. for ( int i = 0; i < c; ++i )
  869. {
  870. MP3Dir_t *sub = parent->m_Subdirectories[ i ];
  871. if ( !Q_stricmp( sub->m_DirName.String(), dirname ) )
  872. {
  873. return sub;
  874. }
  875. }
  876. // Add a new subdir
  877. MP3Dir_t *sub = new MP3Dir_t();
  878. sub->m_DirName = dirname;
  879. char fullpath[ 512 ];
  880. if ( !parent->m_FullDirPath.String()[0] )
  881. {
  882. Q_snprintf( fullpath, sizeof( fullpath ), "%s", dirname );
  883. }
  884. else
  885. {
  886. Q_snprintf( fullpath, sizeof( fullpath ), "%s\\%s", parent->m_FullDirPath.String(), dirname );
  887. }
  888. sub->m_FullDirPath = fullpath;
  889. parent->AddSubDirectory( sub );
  890. return sub;
  891. }
  892. int CMP3Player::AddSplitFileToDirectoryTree_R( int songIndex, MP3Dir_t *parent, CUtlVector< CUtlSymbol >& splitList, int level )
  893. {
  894. char const *current = splitList[ level ].String();
  895. if ( !current )
  896. {
  897. return -1;
  898. }
  899. if ( level == splitList.Count() -1 )
  900. {
  901. // It's a filename, add if not already in list
  902. if ( songIndex != -1 &&
  903. parent->m_FilesInDirectory.Find( songIndex ) == parent->m_FilesInDirectory.InvalidIndex() )
  904. {
  905. parent->m_FilesInDirectory.AddToTail( songIndex );
  906. }
  907. return songIndex;
  908. }
  909. // It's a directory
  910. MP3Dir_t *subdir = FindOrAddSubdirectory( parent, current );
  911. return AddSplitFileToDirectoryTree_R( songIndex, subdir, splitList, level + 1 );
  912. }
  913. int CMP3Player::AddFileToDirectoryTree( SoundDirectory_t *dir, char const *relative )
  914. {
  915. // AddSong
  916. int songIndex = AddSong( relative, dir->GetIndex() );
  917. CUtlVector< CUtlSymbol > list;
  918. SplitFile( list, relative );
  919. return AddSplitFileToDirectoryTree_R( songIndex, dir->m_pTree, list, 0 );
  920. }
  921. void CMP3Player::RecursiveFindMP3Files( SoundDirectory_t *root, char const *current, char const *pathID )
  922. {
  923. FileFindHandle_t fh;
  924. #if 0
  925. if ( m_nFilesAdded >= 200 )
  926. return;
  927. #endif
  928. char path[ 512 ];
  929. if ( current[ 0 ] )
  930. {
  931. Q_snprintf( path, sizeof( path ), "%s/*.*", current );
  932. }
  933. else
  934. {
  935. Q_snprintf( path, sizeof( path ), "*.*" );
  936. }
  937. Q_FixSlashes( path );
  938. char const *fn = g_pFullFileSystem->FindFirstEx( path, pathID, &fh );
  939. if ( fn )
  940. {
  941. do
  942. {
  943. if ( fn[0] != '.' && Q_strnicmp( fn, "_mp3", 4 ) )
  944. {
  945. if ( g_pFullFileSystem->FindIsDirectory( fh ) )
  946. {
  947. char nextdir[ 512 ];
  948. if ( current[ 0 ] )
  949. {
  950. Q_snprintf( nextdir, sizeof( nextdir ), "%s/%s", current, fn );
  951. }
  952. else
  953. {
  954. Q_snprintf( nextdir, sizeof( nextdir ), "%s", fn );
  955. }
  956. RecursiveFindMP3Files( root, nextdir, pathID );
  957. }
  958. else
  959. {
  960. char ext[ 10 ];
  961. Q_ExtractFileExtension( fn, ext, sizeof( ext ) );
  962. if ( !Q_stricmp( ext, "mp3" ) )
  963. {
  964. char relative[ 512 ];
  965. if ( root->m_bGameSound )
  966. {
  967. Q_snprintf( relative, sizeof( relative ), "%s/%s", current + Q_strlen( SOUND_ROOT"/" ), fn );
  968. }
  969. else
  970. {
  971. if ( current[ 0 ] )
  972. {
  973. Q_snprintf( relative, sizeof( relative ), "%s/%s", current, fn );
  974. }
  975. else
  976. {
  977. Q_snprintf( relative, sizeof( relative ), "%s", fn );
  978. }
  979. }
  980. Msg( "Found '%s/%s'\n", current, fn );
  981. Q_FixSlashes( relative );
  982. ++m_nFilesAdded;
  983. AddFileToDirectoryTree( root, relative );
  984. }
  985. }
  986. }
  987. fn = g_pFullFileSystem->FindNext( fh );
  988. } while ( fn );
  989. g_pFullFileSystem->FindClose( fh );
  990. }
  991. }
  992. int CMP3Player::FindSong( char const *relative )
  993. {
  994. Assert( !Q_stristr( relative, "/" ) );
  995. FileNameHandle_t handle = g_pFullFileSystem->FindOrAddFileName( relative );
  996. int c = m_Files.Count();
  997. for ( int i = 0 ; i < c ; ++i )
  998. {
  999. const MP3File_t& mp3 = m_Files[ i ];
  1000. if ( mp3.filename == handle )
  1001. {
  1002. return i;
  1003. }
  1004. }
  1005. return -1;
  1006. }
  1007. int CMP3Player::AddSong( char const *relative, int dirnum )
  1008. {
  1009. int songIndex = FindSong( relative );
  1010. if ( songIndex == -1 )
  1011. {
  1012. #if 0
  1013. if ( m_Files.Count() >= 200 )
  1014. return -1;
  1015. #endif
  1016. MP3File_t mp3;
  1017. Assert( !Q_stristr( relative, "/" ) );
  1018. mp3.filename = g_pFullFileSystem->FindOrAddFileName( relative );
  1019. char shortname[ 256 ];
  1020. Q_FileBase( relative, shortname, sizeof( shortname ) );
  1021. Q_SetExtension( shortname, ".mp3", sizeof( shortname ) );
  1022. mp3.shortname = shortname;
  1023. mp3.flags = ( dirnum == 0 ) ? MP3File_t::FLAG_FROMGAME : MP3File_t::FLAG_FROMFS;
  1024. mp3.dirnum = dirnum;
  1025. songIndex = m_Files.AddToTail( mp3 );
  1026. m_bDirty = true;
  1027. }
  1028. return songIndex;
  1029. }
  1030. void CMP3Player::RecursiveAddToTree( MP3Dir_t *current, int parentIndex )
  1031. {
  1032. if ( !current )
  1033. {
  1034. return;
  1035. }
  1036. // Add all files at current level and then recurse through any directories
  1037. int i, c;
  1038. c = current->m_Subdirectories.Count();
  1039. for ( i = 0 ; i < c; ++i )
  1040. {
  1041. MP3Dir_t *sub = current->m_Subdirectories[ i ];
  1042. Assert( sub );
  1043. KeyValues *kv = new KeyValues( "TVI" );
  1044. kv->SetString( "Text", sub->m_DirName.String() );
  1045. kv->SetPtr( "MP3Dir", sub );
  1046. int index = m_pTree->AddItem( kv, parentIndex );
  1047. m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
  1048. // Recurse...
  1049. RecursiveAddToTree( sub, index );
  1050. }
  1051. // Add raw files
  1052. c = current->m_FilesInDirectory.Count();
  1053. for ( i = 0; i < c; ++i )
  1054. {
  1055. MP3File_t *song = &m_Files[ current->m_FilesInDirectory[ i ] ];
  1056. KeyValues *kv = new KeyValues( "TVI" );
  1057. kv->SetString( "Text", song->shortname.String() );
  1058. kv->SetInt( "SongIndex", current->m_FilesInDirectory[ i ] );
  1059. int index = m_pTree->AddItem( kv, parentIndex );
  1060. m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
  1061. }
  1062. }
  1063. void CMP3Player::OnTreeViewItemSelected()
  1064. {
  1065. PopulateLists();
  1066. }
  1067. void CMP3Player::PopulateTree()
  1068. {
  1069. m_pTree->RemoveAll();
  1070. // Now populate tree
  1071. KeyValues *kv = new KeyValues( "TVI" );
  1072. kv->SetString( "Text", "Songs" );
  1073. int rootIndex = m_pTree->AddItem( kv, -1 );
  1074. m_pTree->SetItemFgColor( rootIndex, TREE_TEXT_COLOR );
  1075. int dircount = m_SoundDirectories.Count();
  1076. for ( int dirnum = 0; dirnum < dircount; ++dirnum )
  1077. {
  1078. MP3Dir_t *tree = m_SoundDirectories[ dirnum ]->m_pTree;
  1079. if ( !tree )
  1080. continue;
  1081. char const *dirname = tree->m_DirName.String();
  1082. kv = new KeyValues( "TVI" );
  1083. kv->SetString( "Text", dirname );
  1084. int index = m_pTree->AddItem( kv, rootIndex );
  1085. RecursiveAddToTree( tree, index );
  1086. m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
  1087. }
  1088. m_pTree->ExpandItem( rootIndex, true );
  1089. PopulateLists();
  1090. }
  1091. // Instead of including windows.h
  1092. extern "C"
  1093. {
  1094. extern int __stdcall CopyFileA( char *pszSource, char *pszDest, int bFailIfExists );
  1095. };
  1096. void CMP3Player::GetLocalCopyOfSong( const MP3File_t &mp3, char *outsong, size_t outlen )
  1097. {
  1098. outsong[ 0 ] = 0;
  1099. char fn[ 512 ];
  1100. if ( !g_pFullFileSystem->String( mp3.filename, fn, sizeof( fn ) ) )
  1101. {
  1102. return;
  1103. }
  1104. if ( mp3.flags == MP3File_t::FLAG_FROMGAME )
  1105. {
  1106. Q_FixSlashes( fn );
  1107. Q_strncpy( outsong, fn, outlen );
  1108. return;
  1109. }
  1110. // Get temp filename from crc
  1111. CRC32_t crc;
  1112. CRC32_Init( &crc );
  1113. CRC32_ProcessBuffer( &crc, fn, Q_strlen( fn ) );
  1114. CRC32_Final( &crc );
  1115. char hexname[ 16 ];
  1116. Q_binarytohex( (const byte *)&crc, sizeof( crc ), hexname, sizeof( hexname ) );
  1117. char hexfilename[ 512 ];
  1118. Q_snprintf( hexfilename, sizeof( hexfilename ), "sound/_mp3/%s.mp3", hexname );
  1119. Q_FixSlashes( hexfilename );
  1120. if ( g_pFullFileSystem->FileExists( hexfilename, "MOD" ) )
  1121. {
  1122. Q_snprintf( outsong, outlen, "_mp3/%s.mp3", hexname );
  1123. }
  1124. else
  1125. {
  1126. // Make a local copy
  1127. char mp3_temp_path[ 512 ];
  1128. Q_snprintf( mp3_temp_path, sizeof( mp3_temp_path ), "sound/_mp3" );
  1129. g_pFullFileSystem->CreateDirHierarchy( mp3_temp_path, "MOD" );
  1130. char destpath[ 512 ];
  1131. Q_snprintf( destpath, sizeof( destpath ), "%s/%s", engine->GetGameDirectory(), hexfilename );
  1132. Q_FixSlashes( destpath );
  1133. char sourcepath[ 512 ];
  1134. Assert( mp3.dirnum >= 0 && mp3.dirnum < m_SoundDirectories.Count() );
  1135. SoundDirectory_t *sdir = m_SoundDirectories[ mp3.dirnum ];
  1136. Q_snprintf( sourcepath, sizeof( sourcepath ), "%s/%s", sdir->m_Root.String(), fn );
  1137. Q_FixSlashes( sourcepath );
  1138. // !!!HACK HACK:
  1139. // Total hack right now, using windows OS calls to copy file to full destination
  1140. int success = ::CopyFileA( sourcepath, destpath, TRUE );
  1141. if ( success > 0 )
  1142. {
  1143. Q_snprintf( outsong, outlen, "_mp3/%s.mp3", hexname );
  1144. }
  1145. }
  1146. Q_FixSlashes( outsong );
  1147. }
  1148. void CMP3Player::PlaySong( int songIndex, float skipTime /*= 0.0f */ )
  1149. {
  1150. MP3File_t& song = m_Files[ songIndex ];
  1151. float volume = 1.0f;
  1152. char soundname[ 512 ];
  1153. soundname[ 0 ] = 0;
  1154. if ( song.playbackfilename == (FileNameHandle_t)0 )
  1155. {
  1156. GetLocalCopyOfSong( song, soundname, sizeof( soundname ) );
  1157. if ( !soundname[ 0 ] )
  1158. {
  1159. return;
  1160. }
  1161. Assert( !Q_stristr( soundname, "/" ) );
  1162. song.playbackfilename = g_pFullFileSystem->FindOrAddFileName( soundname );
  1163. }
  1164. else
  1165. {
  1166. if ( !g_pFullFileSystem->String( song.playbackfilename, soundname, sizeof( soundname ) ) )
  1167. {
  1168. return;
  1169. }
  1170. }
  1171. // Msg( "Playing '%s'\n", soundname );
  1172. if ( !soundname[ 0 ] )
  1173. {
  1174. return;
  1175. }
  1176. if ( m_bPlaying )
  1177. {
  1178. OnStop();
  1179. }
  1180. char drymix[ 512 ];
  1181. Q_snprintf( drymix, sizeof( drymix ), "#%s", soundname );
  1182. enginesound->EmitAmbientSound(
  1183. drymix,
  1184. volume,
  1185. PITCH_NORM,
  1186. 0,
  1187. skipTime == 0.0f ? 0.0f : ( gpGlobals->curtime + skipTime ) );
  1188. m_nSongGuid = enginesound->GetGuidForLastSoundEmitted();
  1189. m_nCurrentSong = songIndex;
  1190. m_bPlaying = true;
  1191. m_LastSong = song.playbackfilename;
  1192. m_SongStart = gpGlobals->realtime;
  1193. m_flSongDuration = GetMP3Duration( soundname );
  1194. m_pCurrentSong->SetText( song.shortname.String() );
  1195. m_nSongMinutes = (int)( m_flSongDuration / 60.0f );
  1196. m_nSongSeconds = (int)( m_flSongDuration - (float)( m_nSongMinutes * 60 ) );
  1197. char durationstr[ 256 ];
  1198. Q_snprintf( durationstr, sizeof( durationstr ), "0:00 / %i:%02i", m_nSongMinutes, m_nSongSeconds );
  1199. m_pDuration->SetText( durationstr );
  1200. m_pSongProgress->SetProgress( 0.0f );
  1201. }
  1202. void CMP3Player::OnStop()
  1203. {
  1204. if ( m_bPlaying )
  1205. {
  1206. m_bPlaying = false;
  1207. if ( m_nSongGuid != 0 )
  1208. {
  1209. enginesound->StopSoundByGuid( m_nSongGuid );
  1210. m_nSongGuid = 0;
  1211. }
  1212. m_LastSong = (FileNameHandle_t)0;
  1213. m_pCurrentSong->SetText( "#NoSong" );
  1214. m_pSongProgress->SetProgress( 0.0f );
  1215. m_pDuration->SetText( "" );
  1216. }
  1217. }
  1218. float CMP3Player::GetMP3Duration( char const *songname )
  1219. {
  1220. return enginesound->GetSoundDuration( songname );
  1221. }
  1222. void CMP3Player::SelectedSongs( SongListSource_t from, CUtlVector< int >& songIndexList )
  1223. {
  1224. m_SelectedSongs.RemoveAll();
  1225. m_SelectionFrom = from;
  1226. int i, c;
  1227. c = songIndexList.Count();
  1228. for ( i = 0; i < c; ++i )
  1229. {
  1230. m_SelectedSongs.AddToTail( songIndexList[ i ] );
  1231. }
  1232. }
  1233. void CMP3Player::OnPlay()
  1234. {
  1235. int c = m_SelectedSongs.Count();
  1236. for ( int i = 0 ; i < c; ++i )
  1237. {
  1238. int songIndex = m_SelectedSongs[ i ];
  1239. if ( songIndex < 0 || songIndex >= m_Files.Count() )
  1240. {
  1241. continue;
  1242. }
  1243. if ( m_SelectionFrom == SONG_FROM_PLAYLIST )
  1244. {
  1245. // Can only play one song at a time from playlist...
  1246. PlaySong( songIndex );
  1247. break;
  1248. }
  1249. else
  1250. {
  1251. AddToPlayList( songIndex, i == 0 );
  1252. }
  1253. }
  1254. }
  1255. void CMP3Player::OnTick()
  1256. {
  1257. BaseClass::OnTick();
  1258. if ( !m_bPlaying )
  1259. {
  1260. return;
  1261. }
  1262. float newVol = (float)m_pVolume->GetValue() / 100.0f;
  1263. bool volumeChanged = ( newVol != m_flCurrentVolume );
  1264. if ( volumeChanged )
  1265. {
  1266. m_flCurrentVolume = newVol;
  1267. }
  1268. bool muteChanged = m_bMuted != m_pMute->IsSelected();
  1269. if ( muteChanged )
  1270. {
  1271. m_bMuted = m_pMute->IsSelected();
  1272. }
  1273. if ( m_nSongGuid == 0 )
  1274. {
  1275. return;
  1276. }
  1277. bool playing = enginesound->IsSoundStillPlaying( m_nSongGuid );
  1278. if ( playing )
  1279. {
  1280. if ( muteChanged )
  1281. {
  1282. if ( m_bMuted )
  1283. {
  1284. OnChangeVolume( MUTED_VOLUME );
  1285. }
  1286. else
  1287. {
  1288. OnChangeVolume( m_flCurrentVolume );
  1289. }
  1290. }
  1291. if ( volumeChanged )
  1292. {
  1293. // Msg( "set volume %f\n", m_flCurrentVolume );
  1294. OnChangeVolume( m_flCurrentVolume );
  1295. }
  1296. if ( m_flSongDuration >= 0.001f )
  1297. {
  1298. float elapsed = gpGlobals->realtime - m_SongStart;
  1299. float frac = elapsed / m_flSongDuration;
  1300. frac = clamp( frac, 0.0f, 1.0f );
  1301. m_pSongProgress->SetProgress( frac );
  1302. int minutes = ( int ) ( elapsed / 60.0f );
  1303. int seconds = (int)( elapsed - ( 60 * minutes ) );
  1304. char durationstr[ 256 ];
  1305. Q_snprintf( durationstr, sizeof( durationstr ), "%i:%02i / %i:%02i", minutes, seconds, m_nSongMinutes, m_nSongSeconds );
  1306. m_pDuration->SetText( durationstr );
  1307. }
  1308. return;
  1309. }
  1310. if ( !m_bEnableAutoAdvance )
  1311. {
  1312. // If we got disconnected completely, reset the flag
  1313. if ( !engine->IsConnected() )
  1314. {
  1315. m_bEnableAutoAdvance = true;
  1316. }
  1317. return;
  1318. }
  1319. // No song playing...
  1320. m_nSongGuid = 0;
  1321. OnNextTrack();
  1322. }
  1323. void CMP3Player::OnChangeVolume( float newVol )
  1324. {
  1325. if ( !m_bPlaying )
  1326. {
  1327. return;
  1328. }
  1329. if ( !m_nSongGuid )
  1330. return;
  1331. enginesound->SetVolumeByGuid( m_nSongGuid, newVol );
  1332. }
  1333. void CMP3Player::GoToNextSong( int skip )
  1334. {
  1335. bool shuffle = m_pShuffle->IsSelected();
  1336. int nextSong = 0;
  1337. if ( m_PlayList.Count() > 0 )
  1338. {
  1339. if ( shuffle )
  1340. {
  1341. m_nCurrentPlaylistSong = random->RandomInt( 0, m_PlayList.Count() - 1 );
  1342. }
  1343. else
  1344. {
  1345. m_nCurrentPlaylistSong = ( m_nCurrentPlaylistSong + skip ) % m_PlayList.Count();
  1346. if ( m_nCurrentPlaylistSong < 0 )
  1347. {
  1348. m_nCurrentPlaylistSong = m_PlayList.Count() - 1;
  1349. }
  1350. }
  1351. nextSong = m_PlayList[ m_nCurrentPlaylistSong ];
  1352. m_pFileSheet->OnPlayListItemPlaying( m_nCurrentPlaylistSong );
  1353. }
  1354. else
  1355. {
  1356. if ( shuffle )
  1357. {
  1358. nextSong = random->RandomInt( 0, m_Files.Count() - 1 );
  1359. }
  1360. else
  1361. {
  1362. nextSong = ( m_nCurrentSong + skip ) % m_Files.Count();
  1363. if ( nextSong < 0 )
  1364. {
  1365. nextSong = m_Files.Count() - 1;
  1366. }
  1367. }
  1368. }
  1369. PlaySong( nextSong );
  1370. }
  1371. void CMP3Player::OnNextTrack()
  1372. {
  1373. if ( m_Files.Count() == 0 )
  1374. {
  1375. return;
  1376. }
  1377. GoToNextSong( +1 );
  1378. }
  1379. void CMP3Player::OnPrevTrack()
  1380. {
  1381. if ( m_Files.Count() == 0 )
  1382. {
  1383. return;
  1384. }
  1385. GoToNextSong( -1 );
  1386. }
  1387. void CMP3Player::RemoveFSSongs()
  1388. {
  1389. int c = m_Files.Count();
  1390. for ( int i = c - 1; i >= 0; --i )
  1391. {
  1392. MP3File_t& mp3 = m_Files[ i ];
  1393. if ( mp3.flags == MP3File_t::FLAG_FROMGAME )
  1394. continue;
  1395. m_Files.Remove( i );
  1396. }
  1397. }
  1398. int CMP3Player::FindSoundDirectory( char const *fullpath )
  1399. {
  1400. CUtlSymbol sym = fullpath;
  1401. int c = m_SoundDirectories.Count();
  1402. for ( int i = 0; i < c; ++i )
  1403. {
  1404. if ( sym == m_SoundDirectories[ i ]->m_Root )
  1405. return i;
  1406. }
  1407. return m_SoundDirectories.InvalidIndex();
  1408. }
  1409. SoundDirectory_t *CMP3Player::AddSoundDirectory( char const *fullpath, bool recurse )
  1410. {
  1411. // RemoveFSSongs();
  1412. m_bDirty = true;
  1413. m_bSettingsDirty = true;
  1414. CUtlSymbol sym = fullpath;
  1415. int sdi = FindSoundDirectory( fullpath );
  1416. if ( sdi == m_SoundDirectories.InvalidIndex() )
  1417. {
  1418. SoundDirectory_t *sounddir = new SoundDirectory_t( m_SoundDirectories.Count() );
  1419. sounddir->m_bGameSound = false;
  1420. sounddir->m_Root = sym;
  1421. sounddir->m_pTree = new MP3Dir_t();
  1422. sounddir->m_pTree->m_DirName = fullpath;
  1423. sounddir->m_pTree->m_FullDirPath = fullpath;
  1424. sdi = m_SoundDirectories.AddToTail( sounddir );
  1425. // Add to search path
  1426. g_pFullFileSystem->AddSearchPath( fullpath, "MP3" );
  1427. // Don't pollute regular searches...
  1428. g_pFullFileSystem->MarkPathIDByRequestOnly( "MP3", true );
  1429. // Now enumerate all .mp3 files in subfolders of this
  1430. if ( recurse )
  1431. {
  1432. m_nFilesAdded = 0;
  1433. RecursiveFindMP3Files( sounddir, "", "MP3" );
  1434. }
  1435. }
  1436. return m_SoundDirectories[ sdi ];
  1437. }
  1438. void CMP3Player::PopulateLists()
  1439. {
  1440. CUtlVector< KeyValues * > kv;
  1441. m_pTree->GetSelectedItemData( kv );
  1442. if ( !kv.Count() )
  1443. {
  1444. return;
  1445. }
  1446. MP3Dir_t *dir = static_cast< MP3Dir_t * >( kv[ 0 ]->GetPtr( "MP3Dir", 0 ) );
  1447. if ( !dir )
  1448. {
  1449. return;
  1450. }
  1451. int i, c;
  1452. c = dir->m_FilesInDirectory.Count();
  1453. if ( !c )
  1454. {
  1455. return;
  1456. }
  1457. m_pFileSheet->ResetFileList();
  1458. for ( i = 0; i < c ; ++i )
  1459. {
  1460. m_pFileSheet->AddSongToFileList( dir->m_FilesInDirectory[ i ] );
  1461. }
  1462. }
  1463. MP3File_t *CMP3Player::GetSongInfo( int songIndex )
  1464. {
  1465. if ( songIndex < 0 || songIndex >= m_Files.Count() )
  1466. {
  1467. return NULL;
  1468. }
  1469. return &m_Files[ songIndex ];
  1470. }
  1471. void CMP3Player::AddToPlayList( int songIndex, bool playNow )
  1472. {
  1473. m_pFileSheet->AddSongToPlayList( songIndex );
  1474. m_PlayList.AddToTail( songIndex );
  1475. if ( playNow )
  1476. {
  1477. PlaySong( songIndex );
  1478. SetPlayListSong( m_PlayList.Count() - 1 );
  1479. }
  1480. // refresh the playlist
  1481. }
  1482. void CMP3Player::RemoveFromPlayList( int songIndex )
  1483. {
  1484. m_pFileSheet->RemoveSongFromPlayList( songIndex );
  1485. m_PlayList.FindAndRemove( songIndex );
  1486. SetPlayListSong( m_nCurrentPlaylistSong );
  1487. }
  1488. void CMP3Player::ClearPlayList()
  1489. {
  1490. m_pFileSheet->ResetPlayList();
  1491. m_PlayList.RemoveAll();
  1492. m_nCurrentPlaylistSong = 0;
  1493. }
  1494. void CMP3Player::OnLoadPlayList()
  1495. {
  1496. ShowFileOpenDialog( false );
  1497. }
  1498. void CMP3Player::OnSavePlayList()
  1499. {
  1500. if ( UTL_INVAL_SYMBOL == m_PlayListFileName )
  1501. {
  1502. OnSavePlayListAs();
  1503. return;
  1504. }
  1505. SavePlayList( m_PlayListFileName.String() );
  1506. }
  1507. void CMP3Player::OnSavePlayListAs()
  1508. {
  1509. ShowFileOpenDialog( true );
  1510. }
  1511. void CMP3Player::RestoreSongs( KeyValues *songs )
  1512. {
  1513. Assert( m_Files.Count() == 0 );
  1514. for ( KeyValues *song = songs->GetFirstSubKey(); song != NULL; song = song->GetNextKey() )
  1515. {
  1516. int flags = 0;
  1517. int game = song->GetInt( "fromgame", 0 );
  1518. if ( game )
  1519. {
  1520. flags |= MP3File_t::FLAG_FROMGAME;
  1521. }
  1522. int fs = song->GetInt( "fromfs", 0 );
  1523. if ( fs )
  1524. {
  1525. flags |= MP3File_t::FLAG_FROMFS;
  1526. }
  1527. int subdir = song->GetInt( "subdirindex", 0 );
  1528. char shortname[ 512 ];
  1529. char filename[ 512 ];
  1530. Q_strncpy( shortname, song->GetString( "short", "" ), sizeof( shortname ) );
  1531. Q_strncpy( filename, song->GetString( "filename", "" ), sizeof( filename ) );
  1532. MP3File_t file;
  1533. file.dirnum = subdir;
  1534. file.flags = flags;
  1535. file.shortname = shortname;
  1536. file.filename = g_pFullFileSystem->FindOrAddFileName( filename );
  1537. m_Files.AddToTail( file );
  1538. }
  1539. }
  1540. void CMP3Player::RestoreDirectory( KeyValues *dir, SoundDirectory_t *sd )
  1541. {
  1542. for ( KeyValues *kv = dir->GetFirstSubKey(); kv; kv = kv->GetNextKey() )
  1543. {
  1544. if ( !Q_stricmp( kv->GetName(), "name" ) )
  1545. {
  1546. sd->m_Root = kv->GetString();
  1547. }
  1548. else if ( !Q_stricmp( kv->GetName(), "gamesounds" ) )
  1549. {
  1550. sd->m_bGameSound = kv->GetBool();
  1551. }
  1552. else if ( !Q_stricmp( kv->GetName(), "dirname" ) )
  1553. {
  1554. sd->m_pTree->m_DirName = kv->GetString();
  1555. }
  1556. else if ( !Q_stricmp( kv->GetName(), "fullpath" ) )
  1557. {
  1558. sd->m_pTree->m_FullDirPath = kv->GetString();
  1559. }
  1560. else if ( !Q_stricmp( kv->GetName(), "files" ) )
  1561. {
  1562. for ( KeyValues *f = kv->GetFirstSubKey(); f != NULL; f = f->GetNextKey() )
  1563. {
  1564. if ( !Q_stricmp( f->GetName(), "file" ) )
  1565. {
  1566. int songIndex = f->GetInt();
  1567. if ( songIndex >= 0 && songIndex < m_Files.Count() )
  1568. {
  1569. char fn[ 512 ];
  1570. if ( g_pFullFileSystem->String( m_Files[ songIndex ].filename, fn, sizeof( fn ) ) )
  1571. {
  1572. AddFileToDirectoryTree( sd, fn );
  1573. }
  1574. }
  1575. }
  1576. }
  1577. }
  1578. else
  1579. {
  1580. Warning( "Unknown key '%s'\n", kv->GetName() );
  1581. }
  1582. }
  1583. }
  1584. void CMP3Player::RestoreDirectories( KeyValues *dirs )
  1585. {
  1586. for ( KeyValues *dir = dirs->GetFirstSubKey(); dir != NULL; dir = dir->GetNextKey() )
  1587. {
  1588. char const *dirpath = dir->GetString( "fullpath", "" );
  1589. if ( dirpath )
  1590. {
  1591. int sdi = FindSoundDirectory( dirpath );
  1592. if ( sdi == m_SoundDirectories.InvalidIndex() )
  1593. {
  1594. SoundDirectory_t *sd = AddSoundDirectory( dirpath, false );
  1595. sdi = sd->GetIndex();
  1596. }
  1597. RestoreDirectory( dir, m_SoundDirectories[ sdi ] );
  1598. }
  1599. }
  1600. }
  1601. bool CMP3Player::RestoreDb( char const *filename )
  1602. {
  1603. KeyValues *kv = new KeyValues( "db" );
  1604. Assert( kv );
  1605. if ( !kv->LoadFromFile( g_pFullFileSystem, filename, "MOD" ) )
  1606. {
  1607. Warning( "Unable to load '%s'\n", filename );
  1608. return false;
  1609. }
  1610. KeyValues *songs = kv;
  1611. Assert( !Q_stricmp( songs->GetName(), "songs" ) );
  1612. RestoreSongs( songs );
  1613. KeyValues *dirs = songs->GetNextKey();
  1614. Assert( !Q_stricmp( dirs->GetName(), "directories" ) );
  1615. RestoreDirectories( dirs );
  1616. kv->deleteThis();
  1617. return true;
  1618. }
  1619. void bpr( int level, CUtlBuffer& buf, PRINTF_FORMAT_STRING char const *fmt, ... )
  1620. {
  1621. char txt[ 4096 ];
  1622. va_list argptr;
  1623. va_start( argptr, fmt );
  1624. _vsnprintf( txt, sizeof( txt ) - 1, fmt, argptr );
  1625. va_end( argptr );
  1626. int indent = 2;
  1627. for ( int i = 0; i < ( indent * level ); ++i )
  1628. {
  1629. buf.Printf( " " );
  1630. }
  1631. buf.Printf( "%s", txt );
  1632. }
  1633. void CMP3Player::SaveDbFile( int level, CUtlBuffer& buf, MP3File_t *file, int filenumber )
  1634. {
  1635. bpr( level, buf, "file\n" );
  1636. bpr( level, buf, "{\n" );
  1637. bpr( level + 1, buf, "filenumber %i\n", filenumber );
  1638. if ( file->flags & MP3File_t::FLAG_FROMGAME )
  1639. {
  1640. bpr( level + 1, buf, "fromgame 1\n" );
  1641. }
  1642. if ( file->flags & MP3File_t::FLAG_FROMFS )
  1643. {
  1644. bpr( level + 1, buf, "fromfs 1\n" );
  1645. }
  1646. bpr( level + 1, buf, "subdirindex %i\n", file->dirnum );
  1647. bpr( level + 1, buf, "short \"%s\"\n", file->shortname.String() );
  1648. char fn[ 512 ];
  1649. if ( g_pFullFileSystem->String( file->filename, fn, sizeof( fn ) ) )
  1650. {
  1651. bpr( level + 1, buf, "filename \"%s\"\n", fn );
  1652. }
  1653. else
  1654. {
  1655. Assert( 0 );
  1656. }
  1657. bpr( level, buf, "}\n" );
  1658. }
  1659. void CMP3Player::FlattenDirectoryFileList_R( MP3Dir_t *dir, CUtlVector< int >& list )
  1660. {
  1661. int i, c;
  1662. c = dir->m_FilesInDirectory.Count();
  1663. for ( i = 0; i < c; ++i )
  1664. {
  1665. int songIndex = dir->m_FilesInDirectory[ i ];
  1666. if ( list.Find( songIndex ) == list.InvalidIndex() )
  1667. {
  1668. list.AddToTail( songIndex );
  1669. }
  1670. }
  1671. c = dir->m_Subdirectories.Count();
  1672. for ( i = 0; i < c; ++i )
  1673. {
  1674. FlattenDirectoryFileList_R( dir->m_Subdirectories[ i ], list );
  1675. }
  1676. }
  1677. void CMP3Player::SaveDbDirectory( int level, CUtlBuffer& buf, SoundDirectory_t *sd )
  1678. {
  1679. bpr( level, buf, "directory\n" );
  1680. bpr( level, buf, "{\n" );
  1681. bpr( level + 1, buf, "gamesounds %i\n", sd->m_bGameSound ? 1 : 0 );
  1682. bpr( level + 1, buf, "name \"%s\"\n", sd->m_Root.String() );
  1683. bpr( level + 1, buf, "dirname \"%s\"\n", sd->m_pTree->m_DirName.String() );
  1684. bpr( level + 1, buf, "fullpath \"%s\"\n", sd->m_pTree->m_FullDirPath.String() );
  1685. CUtlVector< int > files;
  1686. if ( sd->m_pTree )
  1687. {
  1688. FlattenDirectoryFileList_R( sd->m_pTree, files );
  1689. }
  1690. int i, c;
  1691. c = files.Count();
  1692. if ( c > 0 )
  1693. {
  1694. bpr( level + 1, buf, "files\n" );
  1695. bpr( level + 1, buf, "{\n" );
  1696. for ( i = 0; i < c; ++i )
  1697. {
  1698. bpr( level + 2, buf, "file %i\n", files[ i ] );
  1699. }
  1700. bpr( level + 1, buf, "}\n" );
  1701. }
  1702. bpr( level, buf, "}\n" );
  1703. }
  1704. void CMP3Player::SaveDb( char const *filename )
  1705. {
  1706. int i, c;
  1707. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1708. buf.Printf( "// mp3 database, automatically generated\n" );
  1709. bpr( 0, buf, "songs\n{\n" );
  1710. c = m_Files.Count();
  1711. for ( i = 0; i < c; ++i )
  1712. {
  1713. MP3File_t* file = &m_Files[ i ];
  1714. SaveDbFile( 1, buf, file, i );
  1715. }
  1716. bpr( 0, buf, "}\n" );
  1717. bpr( 0, buf, "directories\n{\n" );
  1718. c = m_SoundDirectories.Count();
  1719. for ( i = 0; i < c; ++i )
  1720. {
  1721. SoundDirectory_t *sd = m_SoundDirectories[ i ];
  1722. if ( sd->m_pTree )
  1723. {
  1724. SaveDbDirectory( 1, buf, sd );
  1725. }
  1726. }
  1727. bpr( 0, buf, "}\n" );
  1728. FileHandle_t fh = g_pFullFileSystem->Open( filename, "wb" );
  1729. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1730. {
  1731. g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh );
  1732. g_pFullFileSystem->Close( fh );
  1733. m_bDirty = false;
  1734. }
  1735. else
  1736. {
  1737. Warning( "Unable to open '%s' for writing\n", filename );
  1738. }
  1739. }
  1740. void CMP3Player::OnSave()
  1741. {
  1742. SaveDb( DB_FILENAME );
  1743. }
  1744. void CMP3Player::OnSliderMoved()
  1745. {
  1746. if ( !m_bPlaying )
  1747. {
  1748. return;
  1749. }
  1750. // The engine only allows 4 seconds of skip ahead right now and you have to be connected to get it to work
  1751. // until this is relaxed we can't do this this way...
  1752. #if 0
  1753. float frac = (float)m_pSongProgress->GetValue() / 100.0f;
  1754. float offset = frac * m_flSongDuration;
  1755. PlaySong( m_nCurrentSong, -offset );
  1756. #endif
  1757. }
  1758. void CMP3Player::LoadPlayList( char const *filename )
  1759. {
  1760. KeyValues *kv = new KeyValues( "playlist" );
  1761. Assert( kv );
  1762. if ( !kv->LoadFromFile( g_pFullFileSystem, filename, "MOD" ) )
  1763. {
  1764. Warning( "Unable to load '%s'\n", MP3_SETTINGS_FILE );
  1765. return;
  1766. }
  1767. m_PlayListFileName = filename;
  1768. for ( KeyValues *song = kv->GetFirstSubKey(); song != NULL; song = song->GetNextKey() )
  1769. {
  1770. if ( !Q_stricmp( song->GetName(), "song" ) )
  1771. {
  1772. char const *songname = song->GetString( "relativepath" );
  1773. if ( !songname || !songname[ 0 ] )
  1774. continue;
  1775. char const *dirname = song->GetString( "directory" );
  1776. int flags = 0;
  1777. int game = song->GetInt( "fromgame", 0 );
  1778. if ( game )
  1779. {
  1780. flags |= MP3File_t::FLAG_FROMGAME;
  1781. }
  1782. int fs = song->GetInt( "fromfs", 0 );
  1783. if ( fs )
  1784. {
  1785. flags |= MP3File_t::FLAG_FROMFS;
  1786. }
  1787. int songIndex = -1;
  1788. // Find index
  1789. int idx = FindSong( songname );
  1790. if ( idx == -1 )
  1791. {
  1792. // See if directory exists...
  1793. if ( flags & MP3File_t::FLAG_FROMGAME )
  1794. {
  1795. songIndex = AddSong( songname, 0 );
  1796. }
  1797. else if ( dirname )
  1798. {
  1799. SoundDirectory_t *sd = NULL;
  1800. int dirnum = FindSoundDirectory( dirname );
  1801. if ( dirnum == -1 )
  1802. {
  1803. sd = AddSoundDirectory( dirname, false );
  1804. }
  1805. else
  1806. {
  1807. sd = m_SoundDirectories[ dirnum ];
  1808. }
  1809. if ( sd )
  1810. {
  1811. songIndex = AddFileToDirectoryTree( sd, songname );
  1812. }
  1813. }
  1814. }
  1815. else
  1816. {
  1817. songIndex = idx;
  1818. }
  1819. if ( songIndex >= 0 )
  1820. {
  1821. m_PlayList.AddToTail( songIndex );
  1822. }
  1823. }
  1824. }
  1825. kv->deleteThis();
  1826. PopulateTree();
  1827. PopulateLists();
  1828. }
  1829. void CMP3Player::SavePlayList( char const *filename )
  1830. {
  1831. FileHandle_t fh = g_pFullFileSystem->Open( filename, "wb" );
  1832. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1833. {
  1834. m_PlayListFileName = filename;
  1835. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1836. buf.Printf( "// mp3 playlist\n" );
  1837. bpr( 0, buf, "playlist\n{\n" );
  1838. int c = m_PlayList.Count();
  1839. for ( int i = 0; i < c; ++i )
  1840. {
  1841. MP3File_t& song = m_Files[ m_PlayList[ i ] ];
  1842. char fn[ 512 ];
  1843. if ( g_pFullFileSystem->String( song.filename, fn, sizeof( fn ) ) )
  1844. {
  1845. char dirname[ 512 ];
  1846. dirname[0]=0;
  1847. if ( song.dirnum >= 0 )
  1848. {
  1849. SoundDirectory_t *sd = m_SoundDirectories[ song.dirnum ];
  1850. Q_strncpy( dirname, sd->m_Root.String(), sizeof( dirname ) );
  1851. }
  1852. bpr( 1, buf, "song\n" );
  1853. {
  1854. bpr( 2, buf, "%s 1\n", song.flags == MP3File_t::FLAG_FROMFS ? "fromfs" : "fromgame" );
  1855. if ( dirname[0])
  1856. {
  1857. bpr( 2, buf, "directory \"%s\"\n", dirname );
  1858. }
  1859. bpr( 2, buf, "relativepath \"%s\"\n", fn );
  1860. }
  1861. bpr( 1, buf, "\n" );
  1862. }
  1863. }
  1864. bpr( 0, buf, "}\n" );
  1865. g_pFullFileSystem->Close( fh );
  1866. SetMostRecentPlayList( filename );
  1867. }
  1868. }
  1869. void CMP3Player::SetMostRecentPlayList( char const *filename )
  1870. {
  1871. m_PlayListFileName = filename;
  1872. m_bSettingsDirty = true;
  1873. }
  1874. void CMP3Player::LoadSettings()
  1875. {
  1876. KeyValues *kv = new KeyValues( "settings" );
  1877. Assert( kv );
  1878. if ( !kv->LoadFromFile( g_pFullFileSystem, MP3_SETTINGS_FILE, "MOD" ) )
  1879. {
  1880. Warning( "Unable to load '%s'\n", MP3_SETTINGS_FILE );
  1881. return;
  1882. }
  1883. char const *filename = kv->GetString( "mostrecentplaylist", "" );
  1884. if ( filename && filename[ 0 ] )
  1885. {
  1886. LoadPlayList( filename );
  1887. }
  1888. KeyValues *dirs = kv->FindKey( "directories", false );
  1889. if ( dirs )
  1890. {
  1891. for ( KeyValues *sub = dirs; sub ; sub = sub->GetNextKey() )
  1892. {
  1893. char const *dirname = sub->GetString( "dirname", "" );
  1894. if ( dirname && dirname[ 0 ] )
  1895. {
  1896. AddSoundDirectory( dirname, false );
  1897. }
  1898. else if ( dirname )
  1899. {
  1900. AddGameSounds( false );
  1901. }
  1902. }
  1903. }
  1904. kv->deleteThis();
  1905. m_bSettingsDirty = false;
  1906. }
  1907. void CMP3Player::ShowFileOpenDialog( bool saving )
  1908. {
  1909. m_bSavingFile = saving;
  1910. if ( m_hSaveLoadPlaylist.Get() )
  1911. {
  1912. m_hSaveLoadPlaylist.Get()->MarkForDeletion();
  1913. }
  1914. m_hSaveLoadPlaylist = new FileOpenDialog( this, "Choose Playlist", !saving );
  1915. if ( m_hSaveLoadPlaylist.Get() )
  1916. {
  1917. m_hSaveLoadPlaylist->SetDeleteSelfOnClose( false );
  1918. m_hSaveLoadPlaylist->SetStartDirectory( "resource/" );
  1919. m_hSaveLoadPlaylist->AddFilter( "*.txt", "Playlists", true );
  1920. m_hSaveLoadPlaylist->DoModal( m_bSavingFile );
  1921. }
  1922. }
  1923. void CMP3Player::OnFileSelected( char const *fullpath )
  1924. {
  1925. if ( m_bSavingFile )
  1926. {
  1927. SavePlayList( fullpath );
  1928. m_PlayListFileName = fullpath;
  1929. }
  1930. else
  1931. {
  1932. m_PlayListFileName = fullpath;
  1933. LoadPlayList( fullpath );
  1934. m_nCurrentPlaylistSong = 0;
  1935. }
  1936. if ( m_hSaveLoadPlaylist.Get() )
  1937. {
  1938. m_hSaveLoadPlaylist.Get()->MarkForDeletion();
  1939. }
  1940. }
  1941. void CMP3Player::ShowDirectorySelectDialog()
  1942. {
  1943. if ( m_hDirectorySelect.Get() )
  1944. {
  1945. m_hDirectorySelect.Get()->MarkForDeletion();
  1946. }
  1947. m_hDirectorySelect = new DirectorySelectDialog( this, "Choose Directory" );
  1948. if ( m_hDirectorySelect.Get() )
  1949. {
  1950. m_hDirectorySelect->MakeReadyForUse();
  1951. m_hDirectorySelect->SetStartDirectory( MP3_DEFAULT_MP3DIR );
  1952. m_hDirectorySelect->SetFgColor( TREE_TEXT_COLOR );
  1953. m_hDirectorySelect->DoModal();
  1954. }
  1955. }
  1956. void CMP3Player::OnDirectorySelected( KeyValues *params )
  1957. {
  1958. if ( m_hDirectorySelect.Get() )
  1959. {
  1960. m_hDirectorySelect.Get()->MarkForDeletion();
  1961. }
  1962. char const *fullpath = params->GetString( "dir", "" );
  1963. if ( fullpath && fullpath[ 0 ] )
  1964. {
  1965. char dir[ 512 ];
  1966. Q_strncpy( dir, fullpath, sizeof( dir ) );
  1967. Q_StripTrailingSlash( dir );
  1968. AddSoundDirectory( dir, true );
  1969. PopulateTree();
  1970. m_bDirty = true;
  1971. }
  1972. }
  1973. void CMP3Player::SaveSettings()
  1974. {
  1975. if ( !m_bSettingsDirty )
  1976. {
  1977. return;
  1978. }
  1979. m_bSettingsDirty = false;
  1980. FileHandle_t fh = g_pFullFileSystem->Open( MP3_SETTINGS_FILE, "wb" );
  1981. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1982. {
  1983. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1984. buf.Printf( "// mp3 settings, automatically generated\n" );
  1985. bpr( 0, buf, "settings\n{\n" );
  1986. // FIXME: Move to function if there are more settings to save...
  1987. if ( UTL_INVAL_SYMBOL != m_PlayListFileName )
  1988. {
  1989. bpr( 1, buf, "mostrecentplaylist \"%s\"\n", m_PlayListFileName.String() );
  1990. }
  1991. int c;
  1992. c = m_SoundDirectories.Count();
  1993. if ( c > 0 )
  1994. {
  1995. bpr( 1, buf, "directories\n" );
  1996. bpr( 1, buf, "{\n" );
  1997. for ( int i = 0; i < c; ++i )
  1998. {
  1999. SoundDirectory_t *sd = m_SoundDirectories[ i ];
  2000. Assert( sd );
  2001. bpr( 2, buf, "dirname \"%s\"\n", sd->m_Root.String() );
  2002. }
  2003. bpr( 1, buf, "}\n" );
  2004. }
  2005. bpr( 0, buf, "}\n" );
  2006. g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh );
  2007. g_pFullFileSystem->Close( fh );
  2008. }
  2009. }
  2010. void CMP3Player::SetPlayListSong( int listIndex )
  2011. {
  2012. if ( m_PlayList.Count() > 0 )
  2013. {
  2014. m_nCurrentPlaylistSong = listIndex % m_PlayList.Count();
  2015. }
  2016. else
  2017. {
  2018. m_nCurrentPlaylistSong = 0;
  2019. }
  2020. }
  2021. void CMP3Player::EnableAutoAdvance( bool state )
  2022. {
  2023. m_bEnableAutoAdvance = state;
  2024. }
  2025. //-----------------------------------------------------------------------------
  2026. // Purpose: The purpose of this is that when a changelevel occurs, the engine calls
  2027. // StopAllSounds several times, and the OnTick handler thinks the song has finished playing
  2028. // and so it moves to the next song. This causes the play list to skip ahead by > 1 song during a level
  2029. // change.
  2030. //-----------------------------------------------------------------------------
  2031. class CMP3PlayerGameSystem : public CAutoGameSystem
  2032. {
  2033. public:
  2034. CMP3PlayerGameSystem()
  2035. {
  2036. }
  2037. virtual void LevelInitPreEntity()
  2038. {
  2039. g_pPlayer->EnableAutoAdvance( true );
  2040. }
  2041. virtual void LevelShutdownPostEntity()
  2042. {
  2043. // If we are still connected, disable auto advance until we get into the next level
  2044. if ( engine->IsConnected() )
  2045. {
  2046. g_pPlayer->EnableAutoAdvance( false );
  2047. }
  2048. }
  2049. };
  2050. static CMP3PlayerGameSystem g_MP3Helper;
  2051. #else
  2052. void MP3Player_Create( vgui::VPANEL parent )
  2053. {
  2054. }
  2055. void MP3Player_Destroy()
  2056. {
  2057. }
  2058. #endif