aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/mp3player.h
blob: aaaee912d71d24ac472f0e0027d28e5d7a7ef5bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
//========= 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