diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/mp3player.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/mp3player.cpp')
| -rw-r--r-- | mp/src/game/client/mp3player.cpp | 2475 |
1 files changed, 2475 insertions, 0 deletions
diff --git a/mp/src/game/client/mp3player.cpp b/mp/src/game/client/mp3player.cpp new file mode 100644 index 00000000..e9a946cf --- /dev/null +++ b/mp/src/game/client/mp3player.cpp @@ -0,0 +1,2475 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple .mp3 player example
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#if 0
+#include "mp3player.h"
+#include "KeyValues.h"
+#include "filesystem.h"
+
+#include "vgui_controls/MenuButton.h"
+#include "vgui_controls/Menu.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/Slider.h"
+#include "vgui_controls/ListPanel.h"
+#include "vgui/IPanel.h"
+#include "vgui/IVGui.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include "vgui_controls/PHandle.h"
+
+#include "vgui_controls/PropertySheet.h"
+#include "vgui_controls/PropertyPage.h"
+#include "vgui_controls/TreeView.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "vgui_controls/DirectorySelectDialog.h"
+#include "checksum_crc.h"
+
+#include "engine/IEngineSound.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+// Singleton
+static CMP3Player *g_pPlayer = NULL;
+
+vgui::Panel *GetSDKRootPanel();
+
+// Time between songs
+#define END_GAP_TIME 1.0f
+
+#define SOUND_ROOT "sound"
+
+#define MUTED_VOLUME 0.02f
+
+#define TREE_TEXT_COLOR Color( 200, 255, 200, 255 )
+#define LIST_TEXT_COLOR TREE_TEXT_COLOR
+
+#define DB_FILENAME "resource/mp3player_db.txt"
+#define MP3_SETTINGS_FILE "resource/mp3settings.txt"
+
+#define MP3_DEFAULT_MP3DIR "c:\\my music"
+
+CMP3Player *GetMP3Player()
+{
+ Assert( g_pPlayer );
+ return g_pPlayer;
+}
+
+static void mp3_f()
+{
+ CMP3Player *player = GetMP3Player();
+ if ( player )
+ {
+ player->SetVisible( !player->IsVisible() );
+ }
+}
+void MP3Player_Create( vgui::VPANEL parent )
+{
+ Assert( !g_pPlayer );
+
+ new CMP3Player( parent, "MP3Player" );
+
+#if 0
+ mp3_f();
+#endif
+}
+
+void MP3Player_Destroy()
+{
+ if ( g_pPlayer )
+ {
+ g_pPlayer->MarkForDeletion();
+ g_pPlayer = NULL;
+ }
+}
+
+static ConCommand mp3( "mp3", mp3_f, "Show/hide mp3 player UI." );
+
+//-----------------------------------------------------------------------------
+// Purpose: This assumes artist/album/file.mp3!!!
+// Input : *relative -
+// *artist -
+// artistlen -
+// *album -
+// albumlen -
+// Output : static bool
+//-----------------------------------------------------------------------------
+static bool SplitArtistAlbum( char const *relative, char *artist, size_t artistlen, char *album, size_t albumlen )
+{
+ artist[ 0 ] = 0;
+ album[ 0 ] = 0;
+ char str[ 512 ];
+ Q_strncpy( str, relative, sizeof( str ) );
+
+ char seps[] = "/\\";
+ char *p = strtok( str, seps );
+ int pos = 0;
+ while ( p )
+ {
+ switch ( pos )
+ {
+ default:
+ break;
+ case 0:
+ Q_strncpy( artist, p, artistlen );
+ break;
+ case 1:
+ Q_strncpy( album, p, albumlen );
+ break;
+ case 2:
+ if ( !Q_stristr( p, ".mp3" ) )
+ {
+ artist[ 0 ] = 0;
+ album[ 0 ] = 0;
+ return false;
+ }
+ return true;
+ break;
+ }
+
+ ++pos;
+ p = strtok( NULL, seps );
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CMP3FileListPage : public PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CMP3FileListPage, PropertyPage );
+
+public:
+
+ CMP3FileListPage( Panel *parent, CMP3Player *player, char const *panelName ) :
+ BaseClass( parent, panelName ),
+ m_pPlayer( player )
+ {
+ m_pList = new ListPanel( this, "FileList" );
+ m_pList->AddColumnHeader( 0, "File", "File", 200, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pList->AddColumnHeader( 1, "Artist", "Artist", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pList->AddColumnHeader( 2, "Album", "Album", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ }
+
+ void Reset()
+ {
+ m_pList->DeleteAllItems();
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pList->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+ m_pList->SetFgColor( LIST_TEXT_COLOR );
+ }
+
+ virtual void PerformLayout()
+ {
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+ m_pList->SetBounds( 0, 0, w, h );
+ }
+
+ void AddSong( int songIndex )
+ {
+ Assert( m_pPlayer );
+
+ const MP3File_t* songInfo = m_pPlayer->GetSongInfo( songIndex );
+ if ( !songInfo )
+ {
+ return;
+ }
+
+ KeyValues *kv = new KeyValues( "LI" );
+ kv->SetString( "File", songInfo->shortname.String() );
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( songInfo->filename, fn, sizeof( fn ) ) )
+ {
+ char artist[ 256 ];
+ char album[ 256 ];
+ if ( SplitArtistAlbum( fn, artist, sizeof( artist ), album, sizeof( album ) ) )
+ {
+ kv->SetString( "Artist", artist );
+ kv->SetString( "Album", album );
+ }
+ }
+ kv->SetInt( "SongIndex", songIndex );
+ m_pList->AddItem( kv, 0, false, false );
+ kv->deleteThis();
+ }
+
+ void GetSelectedSongs( CUtlVector< int >&list )
+ {
+ list.RemoveAll();
+
+ int selCount = m_pList->GetSelectedItemsCount();
+ if ( selCount <= 0 )
+ {
+ return;
+ }
+ for ( int i = 0; i < selCount; ++i )
+ {
+ int itemId = m_pList->GetSelectedItem( 0 );
+ KeyValues *kv = m_pList->GetItem( itemId );
+ if ( !kv )
+ {
+ continue;
+ }
+ int song = kv->GetInt( "SongIndex", -1 );
+ if ( song == -1 )
+ {
+ continue;
+ }
+ list.AddToTail( song );
+ }
+ }
+
+ MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
+
+ virtual void OnCommand( char const *cmd );
+
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" )
+ {
+ CUtlVector< int > songList;
+ GetSelectedSongs( songList );
+ m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_FILELIST, songList );
+ }
+
+private:
+
+ CMP3Player *m_pPlayer;
+ ListPanel *m_pList;
+
+ DHANDLE< Menu > m_hMenu;
+};
+
+void CMP3FileListPage::OnOpenContextMenu( int itemID )
+{
+ if ( m_hMenu.Get() != NULL )
+ {
+ delete m_hMenu.Get();
+ }
+
+ m_hMenu = new Menu( this, "FileListContext" );
+ m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaylistAdd", "addsong", this );
+
+ int x, y;
+ input()->GetCursorPos( x, y );
+
+ m_hMenu->SetPos( x, y );
+ m_hMenu->SetVisible( true );
+}
+
+void CMP3FileListPage::OnCommand( char const *cmd )
+{
+ if ( !Q_stricmp( cmd, "addsong" ) )
+ {
+ // Get selected item
+ int c = m_pList->GetSelectedItemsCount();
+ if ( c > 0 )
+ {
+ int itemId = m_pList->GetSelectedItem( 0 );
+ KeyValues *kv = m_pList->GetItem( itemId );
+ if ( kv )
+ {
+ int songIndex = kv->GetInt( "SongIndex" );
+ m_pPlayer->AddToPlayList( songIndex, false );
+ }
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+class CMP3PlayListPage : public PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CMP3PlayListPage, PropertyPage );
+
+public:
+
+ CMP3PlayListPage( Panel *parent, CMP3Player *player, char const *panelName ) :
+ BaseClass( parent, panelName ),
+ m_pPlayer( player )
+ {
+ m_pList = new ListPanel( this, "PlayList" );
+ m_pList->AddColumnHeader( 0, "File", "File", 400, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pList->AddColumnHeader( 1, "Artist", "Artist", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pList->AddColumnHeader( 2, "Album", "Album", 150, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ }
+
+ void Reset()
+ {
+ m_pList->DeleteAllItems();
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pList->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+ m_pList->SetFgColor( LIST_TEXT_COLOR );
+ }
+
+ virtual void PerformLayout()
+ {
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+ m_pList->SetBounds( 0, 0, w, h );
+ }
+
+ void AddSong( int songIndex )
+ {
+ Assert( m_pPlayer );
+
+ const MP3File_t* songInfo = m_pPlayer->GetSongInfo( songIndex );
+ if ( !songInfo )
+ {
+ return;
+ }
+
+ KeyValues *kv = new KeyValues( "LI" );
+ kv->SetString( "File", songInfo->shortname.String() );
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( songInfo->filename, fn, sizeof( fn ) ) )
+ {
+ char artist[ 256 ];
+ char album[ 256 ];
+ if ( SplitArtistAlbum( fn, artist, sizeof( artist ), album, sizeof( album ) ) )
+ {
+ kv->SetString( "Artist", artist );
+ kv->SetString( "Album", album );
+ }
+ }
+ kv->SetInt( "SongIndex", songIndex );
+ m_pList->AddItem( kv, 0, false, false );
+ kv->deleteThis();
+ }
+
+ void RemoveSong( int songIndex )
+ {
+ // Get selected item
+ int c = m_pList->GetSelectedItemsCount();
+ if ( c > 0 )
+ {
+ int itemId = m_pList->GetSelectedItem( 0 );
+ KeyValues *kv = m_pList->GetItem( itemId );
+ if ( kv && ( kv->GetInt( "SongIndex", -1 ) == songIndex ) )
+ {
+ m_pList->RemoveItem( itemId );
+ }
+ }
+ }
+
+ void GetSelectedSongs( CUtlVector< int >&list )
+ {
+ list.RemoveAll();
+
+ int selCount = m_pList->GetSelectedItemsCount();
+ if ( selCount <= 0 )
+ {
+ return;
+ }
+ for ( int i = 0; i < selCount; ++i )
+ {
+ int itemId = m_pList->GetSelectedItem( 0 );
+ KeyValues *kv = m_pList->GetItem( itemId );
+ if ( !kv )
+ {
+ continue;
+ }
+ int song = kv->GetInt( "SongIndex", -1 );
+ if ( song == -1 )
+ {
+ continue;
+ }
+ list.AddToTail( song );
+ }
+ }
+
+
+ MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
+
+ virtual void OnCommand( char const *cmd );
+
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" )
+ {
+ CUtlVector< int > songList;
+ GetSelectedSongs( songList );
+ m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_PLAYLIST, songList );
+ }
+
+ void OnItemPlaying( int listIndex )
+ {
+ int itemId = m_pList->GetItemIDFromRow( listIndex );
+ m_pList->ClearSelectedItems();
+ m_pList->SetSingleSelectedItem( itemId );
+ }
+
+private:
+
+ CMP3Player *m_pPlayer;
+ ListPanel *m_pList;
+
+ DHANDLE< Menu > m_hMenu;
+};
+
+void CMP3PlayListPage::OnOpenContextMenu( int itemID )
+{
+ if ( m_hMenu.Get() != NULL )
+ {
+ delete m_hMenu.Get();
+ }
+
+ m_hMenu = new Menu( this, "PlayListContext" );
+ m_hMenu->AddMenuItem( "Remove", "#PlayListRemove", "removesong", this );
+ m_hMenu->AddMenuItem( "Clear", "#PlayListClear", "clear", this );
+
+ m_hMenu->AddMenuItem( "Load", "#PlayListLoad", "load", this );
+ m_hMenu->AddMenuItem( "Save", "#PlayListSave", "save", this );
+
+ int x, y;
+ input()->GetCursorPos( x, y );
+
+ m_hMenu->SetPos( x, y );
+ m_hMenu->SetVisible( true );
+}
+
+void CMP3PlayListPage::OnCommand( char const *cmd )
+{
+ if ( !Q_stricmp( cmd, "removesong" ) )
+ {
+ // Get selected item
+ int c = m_pList->GetSelectedItemsCount();
+ if ( c > 0 )
+ {
+ int itemId = m_pList->GetSelectedItem( 0 );
+ KeyValues *kv = m_pList->GetItem( itemId );
+ if ( kv )
+ {
+ int songIndex = kv->GetInt( "SongIndex" );
+ m_pPlayer->RemoveFromPlayList( songIndex );
+ }
+ }
+ }
+ else if ( !Q_stricmp( cmd, "clear" ) )
+ {
+ m_pPlayer->ClearPlayList();
+ }
+ else if ( !Q_stricmp( cmd, "load" ) )
+ {
+ m_pPlayer->OnLoadPlayList();
+ }
+ else if ( !Q_stricmp( cmd, "save" ) )
+ {
+ m_pPlayer->OnSavePlayList();
+ }
+ else if ( !Q_stricmp( cmd, "saveas" ) )
+ {
+ m_pPlayer->OnSavePlayListAs();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+class CMP3FileSheet : public PropertySheet
+{
+ DECLARE_CLASS_SIMPLE( CMP3FileSheet, PropertySheet );
+
+public:
+
+ CMP3FileSheet( CMP3Player *player, char const *panelName );
+
+ void ResetFileList()
+ {
+ if ( m_pFileList )
+ {
+ m_pFileList->Reset();
+ }
+ }
+
+ void AddSongToFileList( int songIndex )
+ {
+ if ( m_pFileList )
+ {
+ m_pFileList->AddSong( songIndex );
+ }
+ }
+
+ void ResetPlayList()
+ {
+ if ( m_pPlayList )
+ {
+ m_pPlayList->Reset();
+ }
+ }
+ void AddSongToPlayList( int songIndex )
+ {
+ if ( m_pPlayList )
+ {
+ m_pPlayList->AddSong( songIndex );
+ }
+ }
+
+ void RemoveSongFromPlayList( int songIndex )
+ {
+ if ( m_pPlayList )
+ {
+ m_pPlayList->RemoveSong( songIndex );
+ }
+ }
+
+ void OnPlayListItemPlaying( int listIndex )
+ {
+ if ( m_pPlayList )
+ {
+ m_pPlayList->OnItemPlaying( listIndex );
+ }
+ }
+
+protected:
+
+ CMP3Player *m_pPlayer;
+
+ CMP3PlayListPage *m_pPlayList;
+ CMP3FileListPage *m_pFileList;
+};
+
+CMP3FileSheet::CMP3FileSheet( CMP3Player *player, char const *panelName ) :
+ BaseClass( (Panel *)player, panelName ),
+ m_pPlayer( player )
+{
+ m_pPlayList = new CMP3PlayListPage( this, player, "PlayList" );
+ m_pFileList = new CMP3FileListPage( this, player, "FileList" );
+
+ AddPage( m_pPlayList, "#PlayListTab" );
+ AddPage( m_pFileList, "#FileListTab" );
+
+ SetActivePage( m_pPlayList );
+}
+
+class CMP3TreeControl : public TreeView
+{
+ DECLARE_CLASS_SIMPLE( CMP3TreeControl, TreeView );
+
+public:
+
+ CMP3TreeControl( CMP3Player *player, char const *panelName );
+
+ int GetSelectedSongIndex();
+
+ MESSAGE_FUNC( OnTreeViewItemSelected, "TreeViewItemSelected" )
+ {
+ CUtlVector< int > songList;
+ int idx = GetSelectedSongIndex();
+ if ( idx != -1 )
+ {
+ songList.AddToTail( idx );
+ }
+
+ m_pPlayer->SelectedSongs( CMP3Player::SONG_FROM_TREE, songList );
+
+ if ( vgui::input()->IsMouseDown( MOUSE_RIGHT ) )
+ {
+ OpenContextMenu();
+ }
+ }
+
+ virtual void OnCommand( char const *cmd );
+
+private:
+ void OpenContextMenu();
+
+
+ CMP3Player *m_pPlayer;
+ DHANDLE< Menu > m_hMenu;
+};
+
+CMP3TreeControl::CMP3TreeControl( CMP3Player *player, char const *panelName ) :
+ BaseClass( (Panel *)player, panelName ),
+ m_pPlayer( player )
+{
+ AddActionSignalTarget( this );
+}
+
+int CMP3TreeControl::GetSelectedSongIndex()
+{
+ CUtlVector< KeyValues * > kv;
+ GetSelectedItemData( kv );
+ if ( !kv.Count() )
+ {
+ return -1;
+ }
+ return kv[ 0 ]->GetInt( "SongIndex", -1 );
+}
+
+void CMP3TreeControl::OpenContextMenu()
+{
+ if ( m_hMenu.Get() != NULL )
+ {
+ delete m_hMenu.Get();
+ }
+
+ m_hMenu = new Menu( this, "TreeContext" );
+ m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaylistAdd", "addsong", this );
+ m_hMenu->AddMenuItem( "AddToPlaylist", "#PlaySong", "playsong", this );
+
+ int x, y;
+ input()->GetCursorPos( x, y );
+
+ m_hMenu->SetPos( x, y );
+ m_hMenu->SetVisible( true );
+}
+
+void CMP3TreeControl::OnCommand( char const *cmd )
+{
+ if ( !Q_stricmp( cmd, "addsong" ) )
+ {
+ // Get selected item
+ int songIndex = GetSelectedSongIndex();
+ if ( songIndex >= 0 )
+ {
+ m_pPlayer->AddToPlayList( songIndex, false );
+ }
+ }
+ else if ( !Q_stricmp( cmd, "playsong" ) )
+ {
+ int songIndex = GetSelectedSongIndex();
+ if ( songIndex >= 0 )
+ {
+ m_pPlayer->AddToPlayList( songIndex, true );
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+class CMP3SongProgress : public Slider
+{
+ DECLARE_CLASS_SIMPLE( CMP3SongProgress, Slider );
+
+public:
+
+ CMP3SongProgress( Panel *parent, char const *panelName ) :
+ BaseClass( parent, panelName )
+ {
+ SetPaintEnabled( false );
+ SetRange( 0, 100 );
+ }
+
+ void SetProgress( float frac )
+ {
+ SetValue( (int)( frac * 100.0f + 0.5f ), false );
+ }
+
+ virtual void PaintBackground()
+ {
+ //BaseClass::PaintBackground();
+
+ int w, h;
+ GetSize( w, h );
+
+ float frac = (float)GetValue() * 0.01f;
+
+ int barend = ( int )( (float)( w - 2 ) * frac + 0.5f );
+
+ surface()->DrawSetColor( GetBgColor() );
+ surface()->DrawFilledRect( 0, 0, w, h );
+ surface()->DrawSetColor( GetFgColor() );
+ surface()->DrawFilledRect( 1, 1, barend, h - 1 );
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetFgColor( TREE_TEXT_COLOR );
+ SetBgColor( pScheme->GetColor( "BorderDark", Color( 0, 0, 0, 255 ) ) );
+ }
+};
+
+CMP3Player::CMP3Player( VPANEL parent, char const *panelName ) :
+ BaseClass( NULL, panelName ),
+ m_SelectionFrom( SONG_FROM_UNKNOWN ),
+ m_bDirty( false ),
+ m_bSettingsDirty( false ),
+ m_PlayListFileName( UTL_INVAL_SYMBOL ),
+ m_bSavingFile( false ),
+ m_bEnableAutoAdvance( true )
+{
+ g_pPlayer = this;
+
+ // Get strings...
+ g_pVGuiLocalize->AddFile( "resource/mp3player_%language%.txt" );
+ SetParent( parent );
+
+ SetMoveable( true );
+ SetSizeable( true );
+ SetMenuButtonVisible( false );
+ SetMinimizeButtonVisible( false );
+ SetMaximizeButtonVisible( false );
+ SetCloseButtonVisible( true );
+
+ m_pOptions = new MenuButton( this, "Menu", "#MP3Menu" );
+
+ Menu *options = new Menu( m_pOptions, "Options" );
+ options->AddMenuItem( "AddDir", "#AddDirectory", new KeyValues( "Command", "command", "adddirectory" ), this );
+ options->AddMenuItem( "AddGame", "#AddGameSongs", new KeyValues( "Command", "command", "addgamesongs" ), this );
+ options->AddMenuItem( "Refresh", "#RefreshDb", new KeyValues( "Command", "command", "refresh" ), this );
+
+ m_pOptions->SetMenu( options );
+
+ m_pTree = new CMP3TreeControl( this, "Tree" );
+ m_pTree->MakeReadyForUse();
+
+ // Make tree use small font
+ IScheme *pscheme = scheme()->GetIScheme( GetScheme() );
+ HFont treeFont = pscheme->GetFont( "DefaultVerySmall" );
+ m_pTree->SetFont( treeFont );
+
+ m_pFileSheet = new CMP3FileSheet( this, "FileSheet" );
+
+ m_pPlay = new Button( this, "Play", "#Play", this, "play" );
+ m_pStop = new Button( this, "Stop", "#Stop", this, "stop" );
+ m_pNext = new Button( this, "NextTrack", "#Next", this, "nexttrack" );
+ m_pPrev = new Button( this, "PrevTrack", "#Prev", this, "prevtrack" );
+ m_pMute = new CheckButton( this, "Mute", "#Mute" );
+ m_pShuffle = new CheckButton( this, "Shuffle", "#Shuffle" );
+
+ m_pVolume = new Slider( this, "Volume" );
+ m_pVolume->SetRange( (int)( MUTED_VOLUME * 100.0f ), 100 );
+ m_pVolume->SetValue( 100 );
+
+ m_pCurrentSong = new Label( this, "SongName", "#NoSong" );
+ m_pDuration = new Label( this, "SongDuration", "" );
+
+ m_pSongProgress = new CMP3SongProgress( this, "Progress" );
+ m_pSongProgress->AddActionSignalTarget( this );
+
+ SetSize( 400, 450 );
+
+ SetMinimumSize( 350, 400 );
+
+ SetTitle( "#MP3PlayerTitle", true );
+
+ LoadControlSettings( "resource/MP3Player.res" );
+
+ m_pCurrentSong->SetText( "#NoSong" );
+ m_pDuration->SetText( "" );
+
+ m_nCurrentFile = -1;
+ m_bFirstTime = true;
+ m_bPlaying = false;
+ m_SongStart = -1.0f;
+ m_nSongGuid = 0;
+ m_nCurrentSong = 0;
+ m_nCurrentPlaylistSong = 0;
+ m_flCurrentVolume = 1.0f;
+ m_bMuted = false;
+
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
+}
+
+CMP3Player::~CMP3Player()
+{
+ if ( m_bDirty )
+ {
+ SaveDb( DB_FILENAME );
+ }
+ if ( m_bSettingsDirty )
+ {
+ SaveSettings();
+ }
+ DeleteSoundDirectories();
+ RemoveTempSounds();
+}
+
+void CMP3Player::DeleteSoundDirectories()
+{
+ int c = m_SoundDirectories.Count();
+ for ( int i = c - 1 ; i >= 0 ; --i )
+ {
+ delete m_SoundDirectories[ i ];
+ }
+ m_SoundDirectories.RemoveAll();
+}
+
+void CMP3Player::RemoveTempSounds()
+{
+ FileFindHandle_t fh;
+
+ char path[ 512 ];
+ Q_strncpy( path, "sound/_mp3/*.mp3", sizeof( path ) );
+
+ char const *fn = g_pFullFileSystem->FindFirstEx( path, "MOD", &fh );
+ if ( fn )
+ {
+ do
+ {
+ if ( fn[0] != '.' )
+ {
+ char ext[ 10 ];
+ Q_ExtractFileExtension( fn, ext, sizeof( ext ) );
+
+ if ( !Q_stricmp( ext, "mp3" ) )
+ {
+ char killname[ 512 ];
+ Q_snprintf( killname, sizeof( killname ), "sound/_mp3/%s", fn );
+ g_pFullFileSystem->RemoveFile( killname, "MOD" );
+ }
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+
+ } while ( fn );
+
+ g_pFullFileSystem->FindClose( fh );
+ }
+}
+
+void CMP3Player::WipeSoundDirectories()
+{
+ int c = m_SoundDirectories.Count();
+ for ( int i = c - 1 ; i >= 0 ; --i )
+ {
+ SoundDirectory_t *sd = m_SoundDirectories[ i ];
+ sd->m_pTree->DeleteSubdirectories();
+ sd->m_pTree->m_FilesInDirectory.RemoveAll();
+ }
+}
+
+void CMP3Player::AddGameSounds( bool recurse )
+{
+ SoundDirectory_t *gamesounds = NULL;
+ int idx = FindSoundDirectory( "" );
+ if ( idx == m_SoundDirectories.InvalidIndex() )
+ {
+ gamesounds = new SoundDirectory_t( m_SoundDirectories.Count() );
+ gamesounds->m_bGameSound = true;
+ gamesounds->m_Root = "";
+ gamesounds->m_pTree = new MP3Dir_t();
+ gamesounds->m_pTree->m_DirName = "Game Sounds";
+ gamesounds->m_pTree->m_FullDirPath = "";
+
+ m_SoundDirectories.AddToTail( gamesounds );
+ }
+ else
+ {
+ gamesounds = m_SoundDirectories[ idx ];
+ if ( recurse )
+ {
+ gamesounds->m_pTree->DeleteSubdirectories();
+ gamesounds->m_pTree->m_FilesInDirectory.RemoveAll();
+ }
+ }
+
+ if ( recurse && gamesounds )
+ {
+ m_nFilesAdded = 0;
+ RecursiveFindMP3Files( gamesounds, SOUND_ROOT, "GAME" );
+ }
+}
+
+void CMP3Player::OnRefresh()
+{
+ CUtlVector< CUtlSymbol > dirnames;
+ int i, c;
+
+ CUtlVector< FileNameHandle_t > m_PlayListFiles;
+
+ int pcount = m_PlayList.Count();
+ for ( i = 0; i < pcount; ++i )
+ {
+ m_PlayListFiles.AddToTail( m_Files[ m_PlayList[ i ] ].filename );
+ }
+
+ m_Files.RemoveAll();
+ WipeSoundDirectories();
+ ClearPlayList();
+
+ c = m_SoundDirectories.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ SoundDirectory_t *sd = m_SoundDirectories[ i ];
+
+ // Now enumerate all .mp3 files in subfolders of this
+ if ( sd->m_bGameSound )
+ {
+ m_nFilesAdded = 0;
+ RecursiveFindMP3Files( sd, SOUND_ROOT, "GAME" );
+ }
+ else
+ {
+ // Add to search path
+ g_pFullFileSystem->AddSearchPath( sd->m_Root.String(), "MP3" );
+ // Don't pollute regular searches...
+ g_pFullFileSystem->MarkPathIDByRequestOnly( "MP3", true );
+
+ m_nFilesAdded = 0;
+ RecursiveFindMP3Files( sd, "", "MP3" );
+ }
+ }
+
+ for ( i = 0; i < pcount; ++i )
+ {
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( m_PlayListFiles[ i ], fn, sizeof( fn ) ) )
+ {
+ // Find index for song
+ int songIndex = FindSong( fn );
+ if ( songIndex >= 0 )
+ {
+ AddToPlayList( songIndex, false );
+ }
+ }
+ }
+
+ PopulateTree();
+
+ m_bDirty = true;
+}
+
+void CMP3Player::SetVisible( bool state )
+{
+ BaseClass::SetVisible( state );
+ if ( m_bFirstTime && state )
+ {
+ MoveToCenterOfScreen();
+
+ m_bFirstTime = false;
+
+ LoadSettings();
+ if ( !RestoreDb( DB_FILENAME ) && m_Files.Count() == 0 )
+ {
+ // Load the "game" stuff
+ OnRefresh();
+ }
+
+ PopulateTree();
+ }
+}
+
+void CMP3Player::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ HFont treeFont = pScheme->GetFont( "DefaultVerySmall" );
+ m_pTree->SetFont( treeFont );
+}
+
+void CMP3Player::OnCommand( char const *cmd )
+{
+ if ( !Q_stricmp( cmd, "OnClose" ) )
+ {
+ SetVisible( false );
+ }
+ else if ( !Q_stricmp( cmd, "play" ) )
+ {
+ OnPlay();
+ }
+ else if ( !Q_stricmp( cmd, "stop" ) )
+ {
+ OnStop();
+ }
+ else if ( !Q_stricmp( cmd, "nexttrack" ) )
+ {
+ OnNextTrack();
+ }
+ else if ( !Q_stricmp( cmd, "prevtrack" ) )
+ {
+ OnPrevTrack();
+ }
+ else if ( !Q_stricmp( cmd, "refresh" ) )
+ {
+ OnRefresh();
+ }
+ else if ( !Q_stricmp( cmd, "adddirectory" ) )
+ {
+ ShowDirectorySelectDialog();
+ }
+ else if ( !Q_stricmp( cmd, "addgamesongs" ) )
+ {
+ AddGameSounds( true );
+ PopulateTree();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+void CMP3Player::SplitFile( CUtlVector< CUtlSymbol >& splitList, char const *relative )
+{
+ char work[ 512 ];
+ Q_strncpy( work, relative, sizeof( work ) );
+ char const *separators = "/\\";
+
+ char *token = strtok( work, separators );
+ while ( token )
+ {
+ CUtlSymbol sym = token;
+ splitList.AddToTail( sym );
+
+ token = strtok( NULL, separators );
+ }
+
+}
+
+MP3Dir_t *CMP3Player::FindOrAddSubdirectory( MP3Dir_t *parent, char const *dirname )
+{
+ Assert( parent );
+
+ int c = parent->m_Subdirectories.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ MP3Dir_t *sub = parent->m_Subdirectories[ i ];
+ if ( !Q_stricmp( sub->m_DirName.String(), dirname ) )
+ {
+ return sub;
+ }
+ }
+
+ // Add a new subdir
+ MP3Dir_t *sub = new MP3Dir_t();
+ sub->m_DirName = dirname;
+ char fullpath[ 512 ];
+ if ( !parent->m_FullDirPath.String()[0] )
+ {
+ Q_snprintf( fullpath, sizeof( fullpath ), "%s", dirname );
+ }
+ else
+ {
+ Q_snprintf( fullpath, sizeof( fullpath ), "%s\\%s", parent->m_FullDirPath.String(), dirname );
+ }
+ sub->m_FullDirPath = fullpath;
+ parent->AddSubDirectory( sub );
+
+ return sub;
+}
+
+int CMP3Player::AddSplitFileToDirectoryTree_R( int songIndex, MP3Dir_t *parent, CUtlVector< CUtlSymbol >& splitList, int level )
+{
+ char const *current = splitList[ level ].String();
+ if ( !current )
+ {
+ return -1;
+ }
+
+ if ( level == splitList.Count() -1 )
+ {
+ // It's a filename, add if not already in list
+ if ( songIndex != -1 &&
+ parent->m_FilesInDirectory.Find( songIndex ) == parent->m_FilesInDirectory.InvalidIndex() )
+ {
+ parent->m_FilesInDirectory.AddToTail( songIndex );
+ }
+ return songIndex;
+ }
+
+ // It's a directory
+ MP3Dir_t *subdir = FindOrAddSubdirectory( parent, current );
+ return AddSplitFileToDirectoryTree_R( songIndex, subdir, splitList, level + 1 );
+}
+
+int CMP3Player::AddFileToDirectoryTree( SoundDirectory_t *dir, char const *relative )
+{
+ // AddSong
+ int songIndex = AddSong( relative, dir->GetIndex() );
+
+ CUtlVector< CUtlSymbol > list;
+ SplitFile( list, relative );
+
+ return AddSplitFileToDirectoryTree_R( songIndex, dir->m_pTree, list, 0 );
+}
+
+void CMP3Player::RecursiveFindMP3Files( SoundDirectory_t *root, char const *current, char const *pathID )
+{
+ FileFindHandle_t fh;
+
+#if 0
+ if ( m_nFilesAdded >= 200 )
+ return;
+#endif
+
+ char path[ 512 ];
+ if ( current[ 0 ] )
+ {
+ Q_snprintf( path, sizeof( path ), "%s/*.*", current );
+ }
+ else
+ {
+ Q_snprintf( path, sizeof( path ), "*.*" );
+ }
+
+ Q_FixSlashes( path );
+
+ char const *fn = g_pFullFileSystem->FindFirstEx( path, pathID, &fh );
+ if ( fn )
+ {
+ do
+ {
+ if ( fn[0] != '.' && Q_strnicmp( fn, "_mp3", 4 ) )
+ {
+ if ( g_pFullFileSystem->FindIsDirectory( fh ) )
+ {
+ char nextdir[ 512 ];
+ if ( current[ 0 ] )
+ {
+ Q_snprintf( nextdir, sizeof( nextdir ), "%s/%s", current, fn );
+ }
+ else
+ {
+ Q_snprintf( nextdir, sizeof( nextdir ), "%s", fn );
+ }
+
+ RecursiveFindMP3Files( root, nextdir, pathID );
+ }
+ else
+ {
+ char ext[ 10 ];
+ Q_ExtractFileExtension( fn, ext, sizeof( ext ) );
+
+ if ( !Q_stricmp( ext, "mp3" ) )
+ {
+ char relative[ 512 ];
+ if ( root->m_bGameSound )
+ {
+ Q_snprintf( relative, sizeof( relative ), "%s/%s", current + Q_strlen( SOUND_ROOT"/" ), fn );
+ }
+ else
+ {
+ if ( current[ 0 ] )
+ {
+ Q_snprintf( relative, sizeof( relative ), "%s/%s", current, fn );
+ }
+ else
+ {
+ Q_snprintf( relative, sizeof( relative ), "%s", fn );
+ }
+ }
+ Msg( "Found '%s/%s'\n", current, fn );
+
+ Q_FixSlashes( relative );
+ ++m_nFilesAdded;
+ AddFileToDirectoryTree( root, relative );
+ }
+ }
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+
+ } while ( fn );
+
+ g_pFullFileSystem->FindClose( fh );
+ }
+}
+
+int CMP3Player::FindSong( char const *relative )
+{
+ Assert( !Q_stristr( relative, "/" ) );
+
+ FileNameHandle_t handle = g_pFullFileSystem->FindOrAddFileName( relative );
+ int c = m_Files.Count();
+ for ( int i = 0 ; i < c ; ++i )
+ {
+ const MP3File_t& mp3 = m_Files[ i ];
+ if ( mp3.filename == handle )
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int CMP3Player::AddSong( char const *relative, int dirnum )
+{
+ int songIndex = FindSong( relative );
+
+ if ( songIndex == -1 )
+ {
+#if 0
+ if ( m_Files.Count() >= 200 )
+ return -1;
+#endif
+
+ MP3File_t mp3;
+
+ Assert( !Q_stristr( relative, "/" ) );
+
+ mp3.filename = g_pFullFileSystem->FindOrAddFileName( relative );
+
+ char shortname[ 256 ];
+ Q_FileBase( relative, shortname, sizeof( shortname ) );
+ Q_SetExtension( shortname, ".mp3", sizeof( shortname ) );
+ mp3.shortname = shortname;
+ mp3.flags = ( dirnum == 0 ) ? MP3File_t::FLAG_FROMGAME : MP3File_t::FLAG_FROMFS;
+ mp3.dirnum = dirnum;
+ songIndex = m_Files.AddToTail( mp3 );
+
+ m_bDirty = true;
+ }
+
+ return songIndex;
+}
+
+void CMP3Player::RecursiveAddToTree( MP3Dir_t *current, int parentIndex )
+{
+ if ( !current )
+ {
+ return;
+ }
+
+ // Add all files at current level and then recurse through any directories
+ int i, c;
+ c = current->m_Subdirectories.Count();
+ for ( i = 0 ; i < c; ++i )
+ {
+ MP3Dir_t *sub = current->m_Subdirectories[ i ];
+ Assert( sub );
+
+ KeyValues *kv = new KeyValues( "TVI" );
+ kv->SetString( "Text", sub->m_DirName.String() );
+ kv->SetPtr( "MP3Dir", sub );
+
+ int index = m_pTree->AddItem( kv, parentIndex );
+ m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
+
+ // Recurse...
+ RecursiveAddToTree( sub, index );
+ }
+
+ // Add raw files
+ c = current->m_FilesInDirectory.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ MP3File_t *song = &m_Files[ current->m_FilesInDirectory[ i ] ];
+
+ KeyValues *kv = new KeyValues( "TVI" );
+
+ kv->SetString( "Text", song->shortname.String() );
+ kv->SetInt( "SongIndex", current->m_FilesInDirectory[ i ] );
+
+ int index = m_pTree->AddItem( kv, parentIndex );
+ m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
+ }
+}
+
+void CMP3Player::OnTreeViewItemSelected()
+{
+ PopulateLists();
+}
+
+void CMP3Player::PopulateTree()
+{
+ m_pTree->RemoveAll();
+
+ // Now populate tree
+ KeyValues *kv = new KeyValues( "TVI" );
+ kv->SetString( "Text", "Songs" );
+
+ int rootIndex = m_pTree->AddItem( kv, -1 );
+ m_pTree->SetItemFgColor( rootIndex, TREE_TEXT_COLOR );
+
+ int dircount = m_SoundDirectories.Count();
+ for ( int dirnum = 0; dirnum < dircount; ++dirnum )
+ {
+ MP3Dir_t *tree = m_SoundDirectories[ dirnum ]->m_pTree;
+ if ( !tree )
+ continue;
+
+ char const *dirname = tree->m_DirName.String();
+
+ kv = new KeyValues( "TVI" );
+ kv->SetString( "Text", dirname );
+
+ int index = m_pTree->AddItem( kv, rootIndex );
+
+ RecursiveAddToTree( tree, index );
+
+ m_pTree->SetItemFgColor( index, TREE_TEXT_COLOR );
+ }
+
+ m_pTree->ExpandItem( rootIndex, true );
+
+ PopulateLists();
+}
+
+// Instead of including windows.h
+extern "C"
+{
+ extern int __stdcall CopyFileA( char *pszSource, char *pszDest, int bFailIfExists );
+};
+
+void CMP3Player::GetLocalCopyOfSong( const MP3File_t &mp3, char *outsong, size_t outlen )
+{
+ outsong[ 0 ] = 0;
+ char fn[ 512 ];
+ if ( !g_pFullFileSystem->String( mp3.filename, fn, sizeof( fn ) ) )
+ {
+ return;
+ }
+
+ if ( mp3.flags == MP3File_t::FLAG_FROMGAME )
+ {
+ Q_FixSlashes( fn );
+ Q_strncpy( outsong, fn, outlen );
+ return;
+ }
+
+ // Get temp filename from crc
+ CRC32_t crc;
+ CRC32_Init( &crc );
+ CRC32_ProcessBuffer( &crc, fn, Q_strlen( fn ) );
+ CRC32_Final( &crc );
+
+ char hexname[ 16 ];
+ Q_binarytohex( (const byte *)&crc, sizeof( crc ), hexname, sizeof( hexname ) );
+
+ char hexfilename[ 512 ];
+ Q_snprintf( hexfilename, sizeof( hexfilename ), "sound/_mp3/%s.mp3", hexname );
+
+ Q_FixSlashes( hexfilename );
+
+ if ( g_pFullFileSystem->FileExists( hexfilename, "MOD" ) )
+ {
+ Q_snprintf( outsong, outlen, "_mp3/%s.mp3", hexname );
+ }
+ else
+ {
+ // Make a local copy
+ char mp3_temp_path[ 512 ];
+ Q_snprintf( mp3_temp_path, sizeof( mp3_temp_path ), "sound/_mp3" );
+ g_pFullFileSystem->CreateDirHierarchy( mp3_temp_path, "MOD" );
+
+ char destpath[ 512 ];
+ Q_snprintf( destpath, sizeof( destpath ), "%s/%s", engine->GetGameDirectory(), hexfilename );
+ Q_FixSlashes( destpath );
+
+ char sourcepath[ 512 ];
+
+ Assert( mp3.dirnum >= 0 && mp3.dirnum < m_SoundDirectories.Count() );
+ SoundDirectory_t *sdir = m_SoundDirectories[ mp3.dirnum ];
+ Q_snprintf( sourcepath, sizeof( sourcepath ), "%s/%s", sdir->m_Root.String(), fn );
+ Q_FixSlashes( sourcepath );
+
+ // !!!HACK HACK:
+ // Total hack right now, using windows OS calls to copy file to full destination
+ int success = ::CopyFileA( sourcepath, destpath, TRUE );
+ if ( success > 0 )
+ {
+ Q_snprintf( outsong, outlen, "_mp3/%s.mp3", hexname );
+ }
+ }
+
+ Q_FixSlashes( outsong );
+}
+
+void CMP3Player::PlaySong( int songIndex, float skipTime /*= 0.0f */ )
+{
+ MP3File_t& song = m_Files[ songIndex ];
+
+ float volume = 1.0f;
+
+ char soundname[ 512 ];
+
+ soundname[ 0 ] = 0;
+
+ if ( song.playbackfilename == (FileNameHandle_t)0 )
+ {
+ GetLocalCopyOfSong( song, soundname, sizeof( soundname ) );
+ if ( !soundname[ 0 ] )
+ {
+ return;
+ }
+
+ Assert( !Q_stristr( soundname, "/" ) );
+ song.playbackfilename = g_pFullFileSystem->FindOrAddFileName( soundname );
+
+
+ }
+ else
+ {
+ if ( !g_pFullFileSystem->String( song.playbackfilename, soundname, sizeof( soundname ) ) )
+ {
+ return;
+ }
+ }
+
+ // Msg( "Playing '%s'\n", soundname );
+
+ if ( !soundname[ 0 ] )
+ {
+ return;
+ }
+
+ if ( m_bPlaying )
+ {
+ OnStop();
+ }
+
+ char drymix[ 512 ];
+ Q_snprintf( drymix, sizeof( drymix ), "#%s", soundname );
+
+ enginesound->EmitAmbientSound(
+ drymix,
+ volume,
+ PITCH_NORM,
+ 0,
+ skipTime == 0.0f ? 0.0f : ( gpGlobals->curtime + skipTime ) );
+
+ m_nSongGuid = enginesound->GetGuidForLastSoundEmitted();
+
+ m_nCurrentSong = songIndex;
+ m_bPlaying = true;
+ m_LastSong = song.playbackfilename;
+ m_SongStart = gpGlobals->realtime;
+ m_flSongDuration = GetMP3Duration( soundname );
+
+ m_pCurrentSong->SetText( song.shortname.String() );
+
+ m_nSongMinutes = (int)( m_flSongDuration / 60.0f );
+ m_nSongSeconds = (int)( m_flSongDuration - (float)( m_nSongMinutes * 60 ) );
+
+ char durationstr[ 256 ];
+ Q_snprintf( durationstr, sizeof( durationstr ), "0:00 / %i:%02i", m_nSongMinutes, m_nSongSeconds );
+
+ m_pDuration->SetText( durationstr );
+
+ m_pSongProgress->SetProgress( 0.0f );
+}
+
+void CMP3Player::OnStop()
+{
+ if ( m_bPlaying )
+ {
+ m_bPlaying = false;
+
+ if ( m_nSongGuid != 0 )
+ {
+ enginesound->StopSoundByGuid( m_nSongGuid );
+ m_nSongGuid = 0;
+ }
+
+ m_LastSong = (FileNameHandle_t)0;
+ m_pCurrentSong->SetText( "#NoSong" );
+ m_pSongProgress->SetProgress( 0.0f );
+ m_pDuration->SetText( "" );
+ }
+}
+
+float CMP3Player::GetMP3Duration( char const *songname )
+{
+ return enginesound->GetSoundDuration( songname );
+}
+
+void CMP3Player::SelectedSongs( SongListSource_t from, CUtlVector< int >& songIndexList )
+{
+ m_SelectedSongs.RemoveAll();
+ m_SelectionFrom = from;
+
+ int i, c;
+ c = songIndexList.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ m_SelectedSongs.AddToTail( songIndexList[ i ] );
+ }
+}
+
+void CMP3Player::OnPlay()
+{
+ int c = m_SelectedSongs.Count();
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ int songIndex = m_SelectedSongs[ i ];
+ if ( songIndex < 0 || songIndex >= m_Files.Count() )
+ {
+ continue;
+ }
+ if ( m_SelectionFrom == SONG_FROM_PLAYLIST )
+ {
+ // Can only play one song at a time from playlist...
+ PlaySong( songIndex );
+ break;
+ }
+ else
+ {
+ AddToPlayList( songIndex, i == 0 );
+ }
+ }
+}
+
+void CMP3Player::OnTick()
+{
+ BaseClass::OnTick();
+
+ if ( !m_bPlaying )
+ {
+ return;
+ }
+
+ float newVol = (float)m_pVolume->GetValue() / 100.0f;
+
+ bool volumeChanged = ( newVol != m_flCurrentVolume );
+ if ( volumeChanged )
+ {
+ m_flCurrentVolume = newVol;
+ }
+ bool muteChanged = m_bMuted != m_pMute->IsSelected();
+ if ( muteChanged )
+ {
+ m_bMuted = m_pMute->IsSelected();
+ }
+
+ if ( m_nSongGuid == 0 )
+ {
+ return;
+ }
+
+ bool playing = enginesound->IsSoundStillPlaying( m_nSongGuid );
+ if ( playing )
+ {
+ if ( muteChanged )
+ {
+ if ( m_bMuted )
+ {
+ OnChangeVolume( MUTED_VOLUME );
+ }
+ else
+ {
+ OnChangeVolume( m_flCurrentVolume );
+ }
+ }
+
+ if ( volumeChanged )
+ {
+ // Msg( "set volume %f\n", m_flCurrentVolume );
+ OnChangeVolume( m_flCurrentVolume );
+ }
+
+ if ( m_flSongDuration >= 0.001f )
+ {
+ float elapsed = gpGlobals->realtime - m_SongStart;
+
+ float frac = elapsed / m_flSongDuration;
+ frac = clamp( frac, 0.0f, 1.0f );
+ m_pSongProgress->SetProgress( frac );
+
+ int minutes = ( int ) ( elapsed / 60.0f );
+ int seconds = (int)( elapsed - ( 60 * minutes ) );
+ char durationstr[ 256 ];
+ Q_snprintf( durationstr, sizeof( durationstr ), "%i:%02i / %i:%02i", minutes, seconds, m_nSongMinutes, m_nSongSeconds );
+
+ m_pDuration->SetText( durationstr );
+ }
+ return;
+ }
+
+ if ( !m_bEnableAutoAdvance )
+ {
+ // If we got disconnected completely, reset the flag
+ if ( !engine->IsConnected() )
+ {
+ m_bEnableAutoAdvance = true;
+ }
+ return;
+ }
+
+ // No song playing...
+ m_nSongGuid = 0;
+ OnNextTrack();
+}
+
+void CMP3Player::OnChangeVolume( float newVol )
+{
+ if ( !m_bPlaying )
+ {
+ return;
+ }
+
+ if ( !m_nSongGuid )
+ return;
+
+ enginesound->SetVolumeByGuid( m_nSongGuid, newVol );
+}
+
+void CMP3Player::GoToNextSong( int skip )
+{
+ bool shuffle = m_pShuffle->IsSelected();
+
+ int nextSong = 0;
+
+ if ( m_PlayList.Count() > 0 )
+ {
+ if ( shuffle )
+ {
+ m_nCurrentPlaylistSong = random->RandomInt( 0, m_PlayList.Count() - 1 );
+ }
+ else
+ {
+ m_nCurrentPlaylistSong = ( m_nCurrentPlaylistSong + skip ) % m_PlayList.Count();
+ if ( m_nCurrentPlaylistSong < 0 )
+ {
+ m_nCurrentPlaylistSong = m_PlayList.Count() - 1;
+ }
+ }
+ nextSong = m_PlayList[ m_nCurrentPlaylistSong ];
+
+ m_pFileSheet->OnPlayListItemPlaying( m_nCurrentPlaylistSong );
+ }
+ else
+ {
+ if ( shuffle )
+ {
+ nextSong = random->RandomInt( 0, m_Files.Count() - 1 );
+ }
+ else
+ {
+ nextSong = ( m_nCurrentSong + skip ) % m_Files.Count();
+ if ( nextSong < 0 )
+ {
+ nextSong = m_Files.Count() - 1;
+ }
+ }
+ }
+
+ PlaySong( nextSong );
+}
+
+void CMP3Player::OnNextTrack()
+{
+ if ( m_Files.Count() == 0 )
+ {
+ return;
+ }
+
+ GoToNextSong( +1 );
+}
+
+void CMP3Player::OnPrevTrack()
+{
+ if ( m_Files.Count() == 0 )
+ {
+ return;
+ }
+
+ GoToNextSong( -1 );
+}
+
+void CMP3Player::RemoveFSSongs()
+{
+ int c = m_Files.Count();
+ for ( int i = c - 1; i >= 0; --i )
+ {
+ MP3File_t& mp3 = m_Files[ i ];
+ if ( mp3.flags == MP3File_t::FLAG_FROMGAME )
+ continue;
+
+ m_Files.Remove( i );
+ }
+}
+
+int CMP3Player::FindSoundDirectory( char const *fullpath )
+{
+ CUtlSymbol sym = fullpath;
+ int c = m_SoundDirectories.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ if ( sym == m_SoundDirectories[ i ]->m_Root )
+ return i;
+ }
+
+ return m_SoundDirectories.InvalidIndex();
+}
+
+SoundDirectory_t *CMP3Player::AddSoundDirectory( char const *fullpath, bool recurse )
+{
+ // RemoveFSSongs();
+ m_bDirty = true;
+ m_bSettingsDirty = true;
+
+ CUtlSymbol sym = fullpath;
+ int sdi = FindSoundDirectory( fullpath );
+ if ( sdi == m_SoundDirectories.InvalidIndex() )
+ {
+ SoundDirectory_t *sounddir = new SoundDirectory_t( m_SoundDirectories.Count() );
+ sounddir->m_bGameSound = false;
+ sounddir->m_Root = sym;
+ sounddir->m_pTree = new MP3Dir_t();
+ sounddir->m_pTree->m_DirName = fullpath;
+ sounddir->m_pTree->m_FullDirPath = fullpath;
+
+ sdi = m_SoundDirectories.AddToTail( sounddir );
+
+ // Add to search path
+ g_pFullFileSystem->AddSearchPath( fullpath, "MP3" );
+ // Don't pollute regular searches...
+ g_pFullFileSystem->MarkPathIDByRequestOnly( "MP3", true );
+
+ // Now enumerate all .mp3 files in subfolders of this
+ if ( recurse )
+ {
+ m_nFilesAdded = 0;
+ RecursiveFindMP3Files( sounddir, "", "MP3" );
+ }
+ }
+
+ return m_SoundDirectories[ sdi ];
+}
+
+void CMP3Player::PopulateLists()
+{
+ CUtlVector< KeyValues * > kv;
+ m_pTree->GetSelectedItemData( kv );
+ if ( !kv.Count() )
+ {
+ return;
+ }
+
+ MP3Dir_t *dir = static_cast< MP3Dir_t * >( kv[ 0 ]->GetPtr( "MP3Dir", 0 ) );
+ if ( !dir )
+ {
+ return;
+ }
+
+ int i, c;
+ c = dir->m_FilesInDirectory.Count();
+ if ( !c )
+ {
+ return;
+ }
+
+ m_pFileSheet->ResetFileList();
+ for ( i = 0; i < c ; ++i )
+ {
+ m_pFileSheet->AddSongToFileList( dir->m_FilesInDirectory[ i ] );
+ }
+}
+
+MP3File_t *CMP3Player::GetSongInfo( int songIndex )
+{
+ if ( songIndex < 0 || songIndex >= m_Files.Count() )
+ {
+ return NULL;
+ }
+ return &m_Files[ songIndex ];
+}
+
+void CMP3Player::AddToPlayList( int songIndex, bool playNow )
+{
+ m_pFileSheet->AddSongToPlayList( songIndex );
+ m_PlayList.AddToTail( songIndex );
+
+ if ( playNow )
+ {
+ PlaySong( songIndex );
+ SetPlayListSong( m_PlayList.Count() - 1 );
+ }
+
+ // refresh the playlist
+}
+
+void CMP3Player::RemoveFromPlayList( int songIndex )
+{
+ m_pFileSheet->RemoveSongFromPlayList( songIndex );
+ m_PlayList.FindAndRemove( songIndex );
+
+ SetPlayListSong( m_nCurrentPlaylistSong );
+}
+
+void CMP3Player::ClearPlayList()
+{
+ m_pFileSheet->ResetPlayList();
+ m_PlayList.RemoveAll();
+ m_nCurrentPlaylistSong = 0;
+}
+
+void CMP3Player::OnLoadPlayList()
+{
+ ShowFileOpenDialog( false );
+}
+
+void CMP3Player::OnSavePlayList()
+{
+ if ( UTL_INVAL_SYMBOL == m_PlayListFileName )
+ {
+ OnSavePlayListAs();
+ return;
+ }
+
+ SavePlayList( m_PlayListFileName.String() );
+}
+
+void CMP3Player::OnSavePlayListAs()
+{
+ ShowFileOpenDialog( true );
+}
+
+void CMP3Player::RestoreSongs( KeyValues *songs )
+{
+ Assert( m_Files.Count() == 0 );
+
+ for ( KeyValues *song = songs->GetFirstSubKey(); song != NULL; song = song->GetNextKey() )
+ {
+ int flags = 0;
+ int game = song->GetInt( "fromgame", 0 );
+ if ( game )
+ {
+ flags |= MP3File_t::FLAG_FROMGAME;
+ }
+ int fs = song->GetInt( "fromfs", 0 );
+ if ( fs )
+ {
+ flags |= MP3File_t::FLAG_FROMFS;
+ }
+
+ int subdir = song->GetInt( "subdirindex", 0 );
+
+ char shortname[ 512 ];
+ char filename[ 512 ];
+
+ Q_strncpy( shortname, song->GetString( "short", "" ), sizeof( shortname ) );
+ Q_strncpy( filename, song->GetString( "filename", "" ), sizeof( filename ) );
+
+ MP3File_t file;
+ file.dirnum = subdir;
+ file.flags = flags;
+ file.shortname = shortname;
+ file.filename = g_pFullFileSystem->FindOrAddFileName( filename );
+ m_Files.AddToTail( file );
+ }
+}
+
+void CMP3Player::RestoreDirectory( KeyValues *dir, SoundDirectory_t *sd )
+{
+ for ( KeyValues *kv = dir->GetFirstSubKey(); kv; kv = kv->GetNextKey() )
+ {
+ if ( !Q_stricmp( kv->GetName(), "name" ) )
+ {
+ sd->m_Root = kv->GetString();
+ }
+ else if ( !Q_stricmp( kv->GetName(), "gamesounds" ) )
+ {
+ sd->m_bGameSound = kv->GetInt() ? true : false;
+ }
+ else if ( !Q_stricmp( kv->GetName(), "dirname" ) )
+ {
+ sd->m_pTree->m_DirName = kv->GetString();
+ }
+ else if ( !Q_stricmp( kv->GetName(), "fullpath" ) )
+ {
+ sd->m_pTree->m_FullDirPath = kv->GetString();
+ }
+ else if ( !Q_stricmp( kv->GetName(), "files" ) )
+ {
+ for ( KeyValues *f = kv->GetFirstSubKey(); f != NULL; f = f->GetNextKey() )
+ {
+ if ( !Q_stricmp( f->GetName(), "file" ) )
+ {
+ int songIndex = f->GetInt();
+ if ( songIndex >= 0 && songIndex < m_Files.Count() )
+ {
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( m_Files[ songIndex ].filename, fn, sizeof( fn ) ) )
+ {
+ AddFileToDirectoryTree( sd, fn );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Warning( "Unknown key '%s'\n", kv->GetName() );
+ }
+ }
+}
+
+void CMP3Player::RestoreDirectories( KeyValues *dirs )
+{
+ for ( KeyValues *dir = dirs->GetFirstSubKey(); dir != NULL; dir = dir->GetNextKey() )
+ {
+ char const *dirpath = dir->GetString( "fullpath", "" );
+ if ( dirpath )
+ {
+ int sdi = FindSoundDirectory( dirpath );
+ if ( sdi == m_SoundDirectories.InvalidIndex() )
+ {
+ SoundDirectory_t *sd = AddSoundDirectory( dirpath, false );
+ sdi = sd->GetIndex();
+ }
+ RestoreDirectory( dir, m_SoundDirectories[ sdi ] );
+ }
+ }
+}
+
+bool CMP3Player::RestoreDb( char const *filename )
+{
+ KeyValues *kv = new KeyValues( "db" );
+ Assert( kv );
+ if ( !kv->LoadFromFile( g_pFullFileSystem, filename, "MOD" ) )
+ {
+ Warning( "Unable to load '%s'\n", filename );
+ return false;
+ }
+
+ KeyValues *songs = kv;
+
+ Assert( !Q_stricmp( songs->GetName(), "songs" ) );
+ RestoreSongs( songs );
+ KeyValues *dirs = songs->GetNextKey();
+ Assert( !Q_stricmp( dirs->GetName(), "directories" ) );
+ RestoreDirectories( dirs );
+
+ kv->deleteThis();
+
+ return true;
+}
+
+void bpr( int level, CUtlBuffer& buf, char const *fmt, ... )
+{
+ char txt[ 4096 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ _vsnprintf( txt, sizeof( txt ) - 1, fmt, argptr );
+ va_end( argptr );
+
+ int indent = 2;
+ for ( int i = 0; i < ( indent * level ); ++i )
+ {
+ buf.Printf( " " );
+ }
+ buf.Printf( "%s", txt );
+}
+
+void CMP3Player::SaveDbFile( int level, CUtlBuffer& buf, MP3File_t *file, int filenumber )
+{
+ bpr( level, buf, "file\n" );
+ bpr( level, buf, "{\n" );
+
+ bpr( level + 1, buf, "filenumber %i\n", filenumber );
+
+ if ( file->flags & MP3File_t::FLAG_FROMGAME )
+ {
+ bpr( level + 1, buf, "fromgame 1\n" );
+ }
+ if ( file->flags & MP3File_t::FLAG_FROMFS )
+ {
+ bpr( level + 1, buf, "fromfs 1\n" );
+ }
+
+ bpr( level + 1, buf, "subdirindex %i\n", file->dirnum );
+
+ bpr( level + 1, buf, "short \"%s\"\n", file->shortname.String() );
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( file->filename, fn, sizeof( fn ) ) )
+ {
+ bpr( level + 1, buf, "filename \"%s\"\n", fn );
+ }
+ else
+ {
+ Assert( 0 );
+ }
+
+ bpr( level, buf, "}\n" );
+}
+
+void CMP3Player::FlattenDirectoryFileList_R( MP3Dir_t *dir, CUtlVector< int >& list )
+{
+ int i, c;
+ c = dir->m_FilesInDirectory.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ int songIndex = dir->m_FilesInDirectory[ i ];
+ if ( list.Find( songIndex ) == list.InvalidIndex() )
+ {
+ list.AddToTail( songIndex );
+ }
+ }
+
+ c = dir->m_Subdirectories.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ FlattenDirectoryFileList_R( dir->m_Subdirectories[ i ], list );
+ }
+}
+
+void CMP3Player::SaveDbDirectory( int level, CUtlBuffer& buf, SoundDirectory_t *sd )
+{
+ bpr( level, buf, "directory\n" );
+ bpr( level, buf, "{\n" );
+
+ bpr( level + 1, buf, "gamesounds %i\n", sd->m_bGameSound ? 1 : 0 );
+ bpr( level + 1, buf, "name \"%s\"\n", sd->m_Root.String() );
+ bpr( level + 1, buf, "dirname \"%s\"\n", sd->m_pTree->m_DirName.String() );
+ bpr( level + 1, buf, "fullpath \"%s\"\n", sd->m_pTree->m_FullDirPath.String() );
+
+ CUtlVector< int > files;
+ if ( sd->m_pTree )
+ {
+ FlattenDirectoryFileList_R( sd->m_pTree, files );
+ }
+
+ int i, c;
+
+ c = files.Count();
+ if ( c > 0 )
+ {
+ bpr( level + 1, buf, "files\n" );
+ bpr( level + 1, buf, "{\n" );
+ for ( i = 0; i < c; ++i )
+ {
+ bpr( level + 2, buf, "file %i\n", files[ i ] );
+ }
+ bpr( level + 1, buf, "}\n" );
+ }
+
+ bpr( level, buf, "}\n" );
+}
+
+void CMP3Player::SaveDb( char const *filename )
+{
+ int i, c;
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "// mp3 database, automatically generated\n" );
+
+ bpr( 0, buf, "songs\n{\n" );
+
+ c = m_Files.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ MP3File_t* file = &m_Files[ i ];
+ SaveDbFile( 1, buf, file, i );
+ }
+
+ bpr( 0, buf, "}\n" );
+
+ bpr( 0, buf, "directories\n{\n" );
+
+ c = m_SoundDirectories.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ SoundDirectory_t *sd = m_SoundDirectories[ i ];
+
+ if ( sd->m_pTree )
+ {
+ SaveDbDirectory( 1, buf, sd );
+ }
+ }
+
+ bpr( 0, buf, "}\n" );
+
+ FileHandle_t fh = g_pFullFileSystem->Open( filename, "wb" );
+ if ( FILESYSTEM_INVALID_HANDLE != fh )
+ {
+ g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh );
+ g_pFullFileSystem->Close( fh );
+ m_bDirty = false;
+ }
+ else
+ {
+ Warning( "Unable to open '%s' for writing\n", filename );
+ }
+}
+
+void CMP3Player::OnSave()
+{
+ SaveDb( DB_FILENAME );
+}
+
+void CMP3Player::OnSliderMoved()
+{
+ if ( !m_bPlaying )
+ {
+ return;
+ }
+
+// The engine only allows 4 seconds of skip ahead right now and you have to be connected to get it to work
+// until this is relaxed we can't do this this way...
+#if 0
+ float frac = (float)m_pSongProgress->GetValue() / 100.0f;
+
+ float offset = frac * m_flSongDuration;
+ PlaySong( m_nCurrentSong, -offset );
+#endif
+}
+
+void CMP3Player::LoadPlayList( char const *filename )
+{
+ KeyValues *kv = new KeyValues( "playlist" );
+ Assert( kv );
+ if ( !kv->LoadFromFile( g_pFullFileSystem, filename, "MOD" ) )
+ {
+ Warning( "Unable to load '%s'\n", MP3_SETTINGS_FILE );
+ return;
+ }
+
+ m_PlayListFileName = filename;
+
+ for ( KeyValues *song = kv->GetFirstSubKey(); song != NULL; song = song->GetNextKey() )
+ {
+ if ( !Q_stricmp( song->GetName(), "song" ) )
+ {
+ char const *songname = song->GetString( "relativepath" );
+ if ( !songname || !songname[ 0 ] )
+ continue;
+
+ char const *dirname = song->GetString( "directory" );
+ int flags = 0;
+ int game = song->GetInt( "fromgame", 0 );
+ if ( game )
+ {
+ flags |= MP3File_t::FLAG_FROMGAME;
+ }
+ int fs = song->GetInt( "fromfs", 0 );
+ if ( fs )
+ {
+ flags |= MP3File_t::FLAG_FROMFS;
+ }
+
+ int songIndex = -1;
+
+ // Find index
+ int idx = FindSong( songname );
+ if ( idx == -1 )
+ {
+ // See if directory exists...
+ if ( flags & MP3File_t::FLAG_FROMGAME )
+ {
+ songIndex = AddSong( songname, 0 );
+ }
+ else if ( dirname )
+ {
+ SoundDirectory_t *sd = NULL;
+ int dirnum = FindSoundDirectory( dirname );
+ if ( dirnum == -1 )
+ {
+ sd = AddSoundDirectory( dirname, false );
+ }
+ else
+ {
+ sd = m_SoundDirectories[ dirnum ];
+ }
+
+ if ( sd )
+ {
+ songIndex = AddFileToDirectoryTree( sd, songname );
+ }
+ }
+ }
+ else
+ {
+ songIndex = idx;
+ }
+
+ if ( songIndex >= 0 )
+ {
+ m_PlayList.AddToTail( songIndex );
+ }
+ }
+ }
+
+ kv->deleteThis();
+
+ PopulateTree();
+ PopulateLists();
+}
+
+void CMP3Player::SavePlayList( char const *filename )
+{
+ FileHandle_t fh = g_pFullFileSystem->Open( filename, "wb" );
+ if ( FILESYSTEM_INVALID_HANDLE != fh )
+ {
+ m_PlayListFileName = filename;
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "// mp3 playlist\n" );
+
+ bpr( 0, buf, "playlist\n{\n" );
+
+ int c = m_PlayList.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ MP3File_t& song = m_Files[ m_PlayList[ i ] ];
+ char fn[ 512 ];
+ if ( g_pFullFileSystem->String( song.filename, fn, sizeof( fn ) ) )
+ {
+ char dirname[ 512 ];
+ dirname[0]=0;
+ if ( song.dirnum >= 0 )
+ {
+ SoundDirectory_t *sd = m_SoundDirectories[ song.dirnum ];
+
+ Q_strncpy( dirname, sd->m_Root.String(), sizeof( dirname ) );
+ }
+
+ bpr( 1, buf, "song\n" );
+ {
+ bpr( 2, buf, "%s 1\n", song.flags == MP3File_t::FLAG_FROMFS ? "fromfs" : "fromgame" );
+
+ if ( dirname[0])
+ {
+ bpr( 2, buf, "directory \"%s\"\n", dirname );
+ }
+ bpr( 2, buf, "relativepath \"%s\"\n", fn );
+ }
+ bpr( 1, buf, "\n" );
+ }
+ }
+
+ bpr( 0, buf, "}\n" );
+
+ g_pFullFileSystem->Close( fh );
+
+ SetMostRecentPlayList( filename );
+ }
+}
+
+void CMP3Player::SetMostRecentPlayList( char const *filename )
+{
+ m_PlayListFileName = filename;
+ m_bSettingsDirty = true;
+}
+
+void CMP3Player::LoadSettings()
+{
+ KeyValues *kv = new KeyValues( "settings" );
+ Assert( kv );
+ if ( !kv->LoadFromFile( g_pFullFileSystem, MP3_SETTINGS_FILE, "MOD" ) )
+ {
+ Warning( "Unable to load '%s'\n", MP3_SETTINGS_FILE );
+ return;
+ }
+
+ char const *filename = kv->GetString( "mostrecentplaylist", "" );
+ if ( filename && filename[ 0 ] )
+ {
+ LoadPlayList( filename );
+ }
+
+ KeyValues *dirs = kv->FindKey( "directories", false );
+ if ( dirs )
+ {
+ for ( KeyValues *sub = dirs; sub ; sub = sub->GetNextKey() )
+ {
+ char const *dirname = sub->GetString( "dirname", "" );
+ if ( dirname && dirname[ 0 ] )
+ {
+ AddSoundDirectory( dirname, false );
+ }
+ else if ( dirname )
+ {
+ AddGameSounds( false );
+ }
+ }
+ }
+
+ kv->deleteThis();
+
+ m_bSettingsDirty = false;
+}
+
+void CMP3Player::ShowFileOpenDialog( bool saving )
+{
+ m_bSavingFile = saving;
+ if ( m_hSaveLoadPlaylist.Get() )
+ {
+ m_hSaveLoadPlaylist.Get()->MarkForDeletion();
+ }
+
+ m_hSaveLoadPlaylist = new FileOpenDialog( this, "Choose Playlist", !saving );
+ if ( m_hSaveLoadPlaylist.Get() )
+ {
+ m_hSaveLoadPlaylist->SetStartDirectory( "resource/" );
+ m_hSaveLoadPlaylist->AddFilter( "*.txt", "Playlists", true );
+ m_hSaveLoadPlaylist->DoModal( m_bSavingFile );
+ }
+}
+
+void CMP3Player::OnFileSelected( char const *fullpath )
+{
+ if ( m_bSavingFile )
+ {
+ SavePlayList( fullpath );
+ m_PlayListFileName = fullpath;
+ }
+ else
+ {
+ m_PlayListFileName = fullpath;
+ LoadPlayList( fullpath );
+ m_nCurrentPlaylistSong = 0;
+ }
+
+ if ( m_hSaveLoadPlaylist.Get() )
+ {
+ m_hSaveLoadPlaylist.Get()->MarkForDeletion();
+ }
+}
+
+
+void CMP3Player::ShowDirectorySelectDialog()
+{
+ if ( m_hDirectorySelect.Get() )
+ {
+ m_hDirectorySelect.Get()->MarkForDeletion();
+ }
+
+ m_hDirectorySelect = new DirectorySelectDialog( this, "Choose Directory" );
+ if ( m_hDirectorySelect.Get() )
+ {
+ m_hDirectorySelect->MakeReadyForUse();
+ m_hDirectorySelect->SetStartDirectory( MP3_DEFAULT_MP3DIR );
+ m_hDirectorySelect->SetFgColor( TREE_TEXT_COLOR );
+ m_hDirectorySelect->DoModal();
+ }
+}
+
+void CMP3Player::OnDirectorySelected( KeyValues *params )
+{
+ if ( m_hDirectorySelect.Get() )
+ {
+ m_hDirectorySelect.Get()->MarkForDeletion();
+ }
+
+ char const *fullpath = params->GetString( "dir", "" );
+ if ( fullpath && fullpath[ 0 ] )
+ {
+ char dir[ 512 ];
+ Q_strncpy( dir, fullpath, sizeof( dir ) );
+ Q_StripTrailingSlash( dir );
+ AddSoundDirectory( dir, true );
+ PopulateTree();
+ m_bDirty = true;
+ }
+}
+
+void CMP3Player::SaveSettings()
+{
+ if ( !m_bSettingsDirty )
+ {
+ return;
+ }
+
+ m_bSettingsDirty = false;
+
+ FileHandle_t fh = g_pFullFileSystem->Open( MP3_SETTINGS_FILE, "wb" );
+ if ( FILESYSTEM_INVALID_HANDLE != fh )
+ {
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "// mp3 settings, automatically generated\n" );
+
+ bpr( 0, buf, "settings\n{\n" );
+
+ // FIXME: Move to function if there are more settings to save...
+ if ( UTL_INVAL_SYMBOL != m_PlayListFileName )
+ {
+ bpr( 1, buf, "mostrecentplaylist \"%s\"\n", m_PlayListFileName.String() );
+ }
+
+ int c;
+ c = m_SoundDirectories.Count();
+ if ( c > 0 )
+ {
+ bpr( 1, buf, "directories\n" );
+ bpr( 1, buf, "{\n" );
+
+ for ( int i = 0; i < c; ++i )
+ {
+ SoundDirectory_t *sd = m_SoundDirectories[ i ];
+ Assert( sd );
+
+ bpr( 2, buf, "dirname \"%s\"\n", sd->m_Root.String() );
+ }
+
+ bpr( 1, buf, "}\n" );
+ }
+
+ bpr( 0, buf, "}\n" );
+
+ g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh );
+ g_pFullFileSystem->Close( fh );
+ }
+}
+
+void CMP3Player::SetPlayListSong( int listIndex )
+{
+ if ( m_PlayList.Count() > 0 )
+ {
+ m_nCurrentPlaylistSong = listIndex % m_PlayList.Count();
+ }
+ else
+ {
+ m_nCurrentPlaylistSong = 0;
+ }
+}
+
+void CMP3Player::EnableAutoAdvance( bool state )
+{
+ m_bEnableAutoAdvance = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The purpose of this is that when a changelevel occurs, the engine calls
+// StopAllSounds several times, and the OnTick handler thinks the song has finished playing
+// and so it moves to the next song. This causes the play list to skip ahead by > 1 song during a level
+// change.
+//-----------------------------------------------------------------------------
+class CMP3PlayerGameSystem : public CAutoGameSystem
+{
+public:
+ CMP3PlayerGameSystem()
+ {
+ }
+
+ virtual void LevelInitPreEntity()
+ {
+ g_pPlayer->EnableAutoAdvance( true );
+ }
+
+ virtual void LevelShutdownPostEntity()
+ {
+ // If we are still connected, disable auto advance until we get into the next level
+ if ( engine->IsConnected() )
+ {
+ g_pPlayer->EnableAutoAdvance( false );
+ }
+ }
+};
+
+static CMP3PlayerGameSystem g_MP3Helper;
+
+#else
+
+void MP3Player_Create( vgui::VPANEL parent )
+{
+}
+
+void MP3Player_Destroy()
+{
+}
+
+#endif
|