diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/mp3player.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/mp3player.cpp')
| -rw-r--r-- | mp/src/game/client/mp3player.cpp | 4950 |
1 files changed, 2475 insertions, 2475 deletions
diff --git a/mp/src/game/client/mp3player.cpp b/mp/src/game/client/mp3player.cpp index e9a946cf..929419dd 100644 --- a/mp/src/game/client/mp3player.cpp +++ b/mp/src/game/client/mp3player.cpp @@ -1,2475 +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
+//========= 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 |