You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
9.6 KiB
385 lines
9.6 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
|
||
|
#ifndef MP3PLAYER_H
|
||
|
#define MP3PLAYER_H
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#pragma once
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// The MP3 player has a menu button for setting options, opening files, etc.
|
||
|
// it has a tree control to show the high level categories
|
||
|
// It has a property sheet to switch between the file view and the current playlist
|
||
|
// it has a list view to show the actual files in either view
|
||
|
|
||
|
#include "vgui_controls/Frame.h"
|
||
|
#include "filesystem.h"
|
||
|
#include "utlsymbol.h"
|
||
|
|
||
|
// Forward declarations
|
||
|
namespace vgui
|
||
|
{
|
||
|
class MenuButton;
|
||
|
class Button;
|
||
|
class Slider;
|
||
|
class IScheme;
|
||
|
class FileOpenDialog;
|
||
|
class DirectorySelectDialog;
|
||
|
};
|
||
|
|
||
|
class CMP3FileSheet;
|
||
|
class CMP3TreeControl;
|
||
|
class CMP3SongProgress;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: This is the core MP3 file element
|
||
|
//-----------------------------------------------------------------------------
|
||
|
struct MP3File_t
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
FLAG_UNKNOWN = 0,
|
||
|
// File came from steam cache/game data, rather than the user's "My Music" folder...
|
||
|
FLAG_FROMGAME,
|
||
|
// File came from directory outside of game data directory
|
||
|
FLAG_FROMFS
|
||
|
};
|
||
|
|
||
|
MP3File_t()
|
||
|
{
|
||
|
filename = 0;
|
||
|
playbackfilename = 0;
|
||
|
flags = FLAG_UNKNOWN;
|
||
|
dirnum = -1;
|
||
|
shortname = UTL_INVAL_SYMBOL;
|
||
|
}
|
||
|
|
||
|
int flags;
|
||
|
FileNameHandle_t filename;
|
||
|
FileNameHandle_t playbackfilename; // in case we had to make a local copy somewhere else...
|
||
|
CUtlSymbol shortname;
|
||
|
int dirnum;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: A directory has a name, 0 or more subdirectories and 0 or more mp3 files in it
|
||
|
//-----------------------------------------------------------------------------
|
||
|
struct MP3Dir_t
|
||
|
{
|
||
|
MP3Dir_t() :
|
||
|
m_DirName( UTL_INVAL_SYMBOL ),
|
||
|
m_FullDirPath( UTL_INVAL_SYMBOL )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~MP3Dir_t()
|
||
|
{
|
||
|
DeleteSubdirectories();
|
||
|
}
|
||
|
|
||
|
void DeleteSubdirectories()
|
||
|
{
|
||
|
int i, c;
|
||
|
|
||
|
c = m_Subdirectories.Count();
|
||
|
for ( i = c - 1; i >= 0 ; --i )
|
||
|
{
|
||
|
delete m_Subdirectories[ i ];
|
||
|
}
|
||
|
m_Subdirectories.RemoveAll();
|
||
|
}
|
||
|
|
||
|
MP3Dir_t( const MP3Dir_t& src )
|
||
|
{
|
||
|
m_DirName = src.m_DirName;
|
||
|
m_FullDirPath = src.m_FullDirPath;
|
||
|
|
||
|
int i, c;
|
||
|
|
||
|
c = src.m_Subdirectories.Count();
|
||
|
for ( i = 0; i < c; ++i )
|
||
|
{
|
||
|
MP3Dir_t *subCopy = new MP3Dir_t( *src.m_Subdirectories[ i ] );
|
||
|
m_Subdirectories.AddToTail( subCopy );
|
||
|
}
|
||
|
|
||
|
c = src.m_FilesInDirectory.Count();
|
||
|
for ( i = 0; i < c; ++i )
|
||
|
{
|
||
|
m_FilesInDirectory.AddToTail( src.m_FilesInDirectory[ i ] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MP3Dir_t &operator =( const MP3Dir_t& src )
|
||
|
{
|
||
|
if ( this == &src )
|
||
|
{
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
m_DirName = src.m_DirName;
|
||
|
m_FullDirPath = src.m_FullDirPath;
|
||
|
|
||
|
DeleteSubdirectories();
|
||
|
|
||
|
m_FilesInDirectory.RemoveAll();
|
||
|
|
||
|
int i, c;
|
||
|
|
||
|
c = src.m_Subdirectories.Count();
|
||
|
for ( i = 0; i < c; ++i )
|
||
|
{
|
||
|
// make a copy
|
||
|
MP3Dir_t *subCopy = new MP3Dir_t( *src.m_Subdirectories[ i ] );
|
||
|
m_Subdirectories.AddToTail( subCopy );
|
||
|
}
|
||
|
|
||
|
c = src.m_FilesInDirectory.Count();
|
||
|
for ( i = 0; i < c; ++i )
|
||
|
{
|
||
|
m_FilesInDirectory.AddToTail( src.m_FilesInDirectory[ i ] );
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
void AddSubDirectory( MP3Dir_t *sub )
|
||
|
{
|
||
|
m_Subdirectories.AddToTail( sub );
|
||
|
}
|
||
|
|
||
|
CUtlSymbol m_DirName; // "artist"
|
||
|
CUtlSymbol m_FullDirPath; // "artist/album
|
||
|
CUtlVector< MP3Dir_t * > m_Subdirectories;
|
||
|
CUtlVector< int > m_FilesInDirectory;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: A sound directory is a root directory which is recursed looking for .mp3
|
||
|
// We assume that the folders under the sound directory are configured as artist/album/filename.mp3...
|
||
|
//-----------------------------------------------------------------------------
|
||
|
struct SoundDirectory_t
|
||
|
{
|
||
|
explicit SoundDirectory_t( int index ) :
|
||
|
m_nIndex( index ),
|
||
|
m_Root( UTL_INVAL_SYMBOL ),
|
||
|
m_pTree( 0 ),
|
||
|
m_bGameSound( false )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~SoundDirectory_t()
|
||
|
{
|
||
|
delete m_pTree;
|
||
|
}
|
||
|
|
||
|
void SetTree( MP3Dir_t *tree )
|
||
|
{
|
||
|
if ( m_pTree )
|
||
|
{
|
||
|
delete m_pTree;
|
||
|
}
|
||
|
m_pTree = tree;
|
||
|
}
|
||
|
|
||
|
int GetIndex() const { return m_nIndex; }
|
||
|
|
||
|
int m_nIndex;
|
||
|
CUtlSymbol m_Root;
|
||
|
MP3Dir_t *m_pTree;
|
||
|
bool m_bGameSound;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: A VGui based .mp3 player
|
||
|
//-----------------------------------------------------------------------------
|
||
|
class CMP3Player : public vgui::Frame
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CMP3Player, vgui::Frame );
|
||
|
|
||
|
public:
|
||
|
|
||
|
// Construction
|
||
|
CMP3Player( vgui::VPANEL parent, char const *panelName );
|
||
|
~CMP3Player();
|
||
|
|
||
|
virtual void SetVisible( bool );
|
||
|
|
||
|
// Lookup data
|
||
|
MP3File_t *GetSongInfo( int songIndex );
|
||
|
|
||
|
// Static singleton accessor
|
||
|
static CMP3Player *GetMP3Player();
|
||
|
|
||
|
void AddToPlayList( int songIndex, bool playNow );
|
||
|
void RemoveFromPlayList( int songIndex );
|
||
|
|
||
|
void ClearPlayList();
|
||
|
void OnLoadPlayList();
|
||
|
void OnSavePlayList();
|
||
|
void OnSavePlayListAs();
|
||
|
|
||
|
void SetPlayListSong( int listIndex );
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
SONG_FROM_UNKNOWN = 0,
|
||
|
SONG_FROM_TREE,
|
||
|
SONG_FROM_FILELIST,
|
||
|
SONG_FROM_PLAYLIST
|
||
|
} SongListSource_t;
|
||
|
|
||
|
void SelectedSongs( SongListSource_t from, CUtlVector< int >& songIndexList );
|
||
|
|
||
|
void EnableAutoAdvance( bool state );
|
||
|
|
||
|
protected:
|
||
|
virtual void OnCommand( char const *cmd );
|
||
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||
|
virtual void OnTick();
|
||
|
|
||
|
MESSAGE_FUNC( OnTreeViewItemSelected, "TreeViewItemSelected" );
|
||
|
MESSAGE_FUNC( OnSliderMoved, "SliderMoved" );
|
||
|
|
||
|
void PopulateTree();
|
||
|
void PopulateLists();
|
||
|
void RecursiveAddToTree( MP3Dir_t *current, int parentIndex );
|
||
|
void DeleteSoundDirectories();
|
||
|
// Leave root objects, clear all subdirs
|
||
|
void WipeSoundDirectories();
|
||
|
|
||
|
// Remove the _mp3/a45ef65a.mp3 style temp sounds
|
||
|
void RemoveTempSounds();
|
||
|
|
||
|
void SplitFile( CUtlVector< CUtlSymbol >& splitList, char const *relative );
|
||
|
int AddSplitFileToDirectoryTree_R( int songIndex, MP3Dir_t *parent, CUtlVector< CUtlSymbol >& splitList, int level );
|
||
|
|
||
|
MP3Dir_t *FindOrAddSubdirectory( MP3Dir_t *parent, char const *dirname );
|
||
|
|
||
|
int AddFileToDirectoryTree( SoundDirectory_t *dir, char const *relative );
|
||
|
void RecursiveFindMP3Files( SoundDirectory_t *root, char const *current, char const *pathID );
|
||
|
|
||
|
int AddSong( char const *relative, int dirnum );
|
||
|
void RemoveFSSongs(); // Remove all non-built-in .mp3s
|
||
|
int FindSong( char const *relative );
|
||
|
|
||
|
void PlaySong( int songIndex, float skipTime = 0.0f );
|
||
|
void GetLocalCopyOfSong( const MP3File_t &mp3, char *outsong, size_t outlen );
|
||
|
float GetMP3Duration( char const *songname );
|
||
|
void OnNextTrack();
|
||
|
void OnPrevTrack();
|
||
|
|
||
|
void OnPlay();
|
||
|
void OnStop();
|
||
|
void OnChangeVolume( float newVol );
|
||
|
|
||
|
void AddGameSounds( bool recurse );
|
||
|
SoundDirectory_t *AddSoundDirectory( char const *fullpath, bool recurse );
|
||
|
int FindSoundDirectory( char const *fullpath );
|
||
|
|
||
|
bool RestoreDb( char const *filename );
|
||
|
void SaveDb( char const *filename );
|
||
|
|
||
|
void SaveDbFile( int level, CUtlBuffer& buf, MP3File_t *file, int filenumber );
|
||
|
void FlattenDirectoryFileList_R( MP3Dir_t *dir, CUtlVector< int >& list );
|
||
|
void SaveDbDirectory( int level, CUtlBuffer& buf, SoundDirectory_t *sd );
|
||
|
|
||
|
void RestoreSongs( KeyValues *songs );
|
||
|
void RestoreDirectories( KeyValues *dirs );
|
||
|
void RestoreDirectory( KeyValues *dir, SoundDirectory_t *sd );
|
||
|
|
||
|
void LoadPlayList( char const *filename );
|
||
|
void SavePlayList( char const *filename );
|
||
|
|
||
|
void SetMostRecentPlayList( char const *filename );
|
||
|
|
||
|
void SaveSettings();
|
||
|
void LoadSettings();
|
||
|
|
||
|
// Refresh all directories, built-in sounds
|
||
|
void OnRefresh();
|
||
|
void OnSave();
|
||
|
|
||
|
MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
|
||
|
void ShowFileOpenDialog( bool saving );
|
||
|
MESSAGE_FUNC_PARAMS( OnDirectorySelected, "DirectorySelected", params );
|
||
|
void ShowDirectorySelectDialog();
|
||
|
|
||
|
void GoToNextSong( int skip );
|
||
|
|
||
|
// Data
|
||
|
private:
|
||
|
|
||
|
// UI elements
|
||
|
vgui::MenuButton *m_pOptions;
|
||
|
CMP3TreeControl *m_pTree;
|
||
|
CMP3FileSheet *m_pFileSheet;
|
||
|
vgui::Label *m_pCurrentSong;
|
||
|
vgui::Label *m_pDuration;
|
||
|
CMP3SongProgress *m_pSongProgress;
|
||
|
vgui::Button *m_pPlay;
|
||
|
vgui::Button *m_pStop;
|
||
|
vgui::Button *m_pNext, *m_pPrev; // moving between tracks
|
||
|
vgui::CheckButton *m_pMute;
|
||
|
vgui::CheckButton *m_pShuffle;
|
||
|
vgui::Slider *m_pVolume;
|
||
|
|
||
|
// Raw list of all known files
|
||
|
CUtlVector< MP3File_t > m_Files;
|
||
|
int m_nFilesAdded;
|
||
|
// Indices into m_Files for currently playing songs
|
||
|
CUtlVector< int > m_PlayList;
|
||
|
// Where in the list we are...
|
||
|
int m_nCurrentPlaylistSong;
|
||
|
CUtlSymbol m_PlayListFileName;
|
||
|
|
||
|
int m_nCurrentFile;
|
||
|
// Flag for one-time init
|
||
|
bool m_bFirstTime;
|
||
|
int m_nCurrentSong;
|
||
|
FileNameHandle_t m_LastSong;
|
||
|
float m_flCurrentVolume;
|
||
|
bool m_bMuted;
|
||
|
|
||
|
// Currently playing a song?
|
||
|
bool m_bPlaying;
|
||
|
int m_nSongGuid;
|
||
|
// Song start time
|
||
|
float m_SongStart;
|
||
|
// Estimated song diration
|
||
|
float m_flSongDuration;
|
||
|
// For the UI
|
||
|
int m_nSongMinutes;
|
||
|
int m_nSongSeconds;
|
||
|
|
||
|
// List of all added directories
|
||
|
CUtlVector< SoundDirectory_t * > m_SoundDirectories;
|
||
|
|
||
|
// Selection set
|
||
|
CUtlVector< int > m_SelectedSongs;
|
||
|
SongListSource_t m_SelectionFrom;
|
||
|
|
||
|
// Is database dirty?
|
||
|
bool m_bDirty;
|
||
|
// Are settings dirty?
|
||
|
bool m_bSettingsDirty;
|
||
|
|
||
|
// File dialog
|
||
|
vgui::DHANDLE< vgui::FileOpenDialog > m_hSaveLoadPlaylist;
|
||
|
// Type of dialog
|
||
|
bool m_bSavingFile;
|
||
|
|
||
|
// Directory selection dialog
|
||
|
vgui::DHANDLE< vgui::DirectorySelectDialog > m_hDirectorySelect;
|
||
|
|
||
|
bool m_bEnableAutoAdvance;
|
||
|
};
|
||
|
|
||
|
#endif // !MP3PLAYER_H
|