diff --git a/Branches/MusicMod/Player/Src/AddDirectory.cpp b/Branches/MusicMod/Player/Src/AddDirectory.cpp new file mode 100644 index 0000000000..fae40764d9 --- /dev/null +++ b/Branches/MusicMod/Player/Src/AddDirectory.cpp @@ -0,0 +1,363 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "AddDirectory.h" +#include "Playlist.h" +#include "Main.h" +#include "InputPlugin.h" +#include +#include +#include +#include + +using namespace std; + + + +HWND WindowBrowse = NULL; + + + +void SearchFolder( TCHAR * szPath ); + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +LPITEMIDLIST GetCurrentFolder() +{ +/* + How To Convert a File Path to an ITEMIDLIST + http://support.microsoft.com/default.aspx?scid=kb;en-us;132750 +*/ + LPITEMIDLIST pidl; + LPSHELLFOLDER pDesktopFolder; + TCHAR szPath[ MAX_PATH ]; +#ifndef PA_UNICODE + OLECHAR olePath[ MAX_PATH ]; +#endif + ULONG chEaten; + ULONG dwAttributes; + HRESULT hr; + + // + // Get the path we need to convert. + // + GetCurrentDirectory( MAX_PATH, szPath ); + + // + // Get a pointer to the Desktop's IShellFolder interface. + // + if( SUCCEEDED( SHGetDesktopFolder( &pDesktopFolder ) ) ) + { + + // + // IShellFolder::ParseDisplayName requires the file name be in + // Unicode. + // +#ifndef PA_UNICODE + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, olePath, MAX_PATH ); +#endif + // + // Convert the path to an ITEMIDLIST. + // + // hr = pDesktopFolder->lpVtbl->ParseDisplayName( + hr = pDesktopFolder->ParseDisplayName( + ( HWND__ * )pDesktopFolder, + NULL, +#ifndef PA_UNICODE + olePath, +#else + szPath, +#endif + &chEaten, + &pidl, + &dwAttributes + ); + + if( FAILED( hr ) ) + { + // Handle error. + return NULL; + } + + // + // pidl now contains a pointer to an ITEMIDLIST for .\readme.txt. + // This ITEMIDLIST needs to be freed using the IMalloc allocator + // returned from SHGetMalloc(). + // + + // release the desktop folder object + // pDesktopFolder->lpVtbl->Release(); + pDesktopFolder->Release(); + + return pidl; + } + else + { + return NULL; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lp ) +{ + TCHAR szClassName[ 8 ] = TEXT( "\0" ); + HWND * hFirstFoundStatic = ( ( HWND * )lp ); + + if( GetClassName( hwnd, szClassName, 7 ) ) + { + if( !_tcscmp( szClassName, TEXT( "Static" ) ) ) + { + if( *hFirstFoundStatic ) + { + // Both found + RECT r1; + GetWindowRect( *hFirstFoundStatic, &r1 ); + + RECT r2; + GetWindowRect( hwnd, &r2 ); + + // First must be taller one + if( r1.bottom - r1.top < r2.bottom - r2.top ) + { + // Swap + RECT r = r1; + HWND h = *hFirstFoundStatic; + + r1 = r2; + *hFirstFoundStatic = hwnd; + + r2 = r; + hwnd = h; + } + + POINT xy2 = { r2.left, r2.top }; + ScreenToClient( WindowBrowse, &xy2 ); + + SetWindowPos( + *hFirstFoundStatic, + NULL, + 0, + 0, + r2.right - r2.left, + r2.bottom - r2.top, + SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER + ); + + SetWindowPos( + hwnd, + NULL, + xy2.x, + xy2.y + ( r2.bottom - r2.top ) - ( r1.bottom - r1.top ), + r1.right - r1.left, + r1.bottom - r1.top, + SWP_NOOWNERZORDER | SWP_NOZORDER + ); + + + return FALSE; // Stop + } + else + { + // First found + *hFirstFoundStatic = hwnd; + } + } + } + + return TRUE; // Continue +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +int CALLBACK BrowseCallbackProc( HWND hwnd, UINT message, LPARAM lp, LPARAM wp ) +{ + switch( message ) + { + case BFFM_INITIALIZED: + { + WindowBrowse = hwnd; + + // Init with curdir + SendMessage( hwnd, BFFM_SETSELECTION, FALSE, ( LPARAM )GetCurrentFolder() ); + + // Swap static dimensions + HWND hFirstFoundStatic = NULL; + EnumChildWindows( hwnd, EnumChildProc, ( LPARAM )&hFirstFoundStatic ); + + break; + } + + case BFFM_SELCHANGED: + { + TCHAR szPath[ MAX_PATH ] = TEXT( "\0" ); + SHGetPathFromIDList( ( LPITEMIDLIST )lp, szPath ); + SendMessage( hwnd, BFFM_SETSTATUSTEXT, 0, ( LPARAM )szPath ); + + break; + } + + case BFFM_VALIDATEFAILED: + return TRUE; + + } + + return 0; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Shows a Browse-For-Folder dialog and recursively adds supported files +/// to the playlist. Files are sorted by full filaname before being added. +//////////////////////////////////////////////////////////////////////////////// +void AddDirectory() +{ + TCHAR szPath[ MAX_PATH ]; + BROWSEINFO bi = { 0 }; + bi.hwndOwner = WindowMain; + bi.pidlRoot = NULL; // Desktop folder + bi.lpszTitle = TEXT( "Please select a directory:" ); + bi.ulFlags = BIF_VALIDATE | BIF_STATUSTEXT; + bi.lpfn = BrowseCallbackProc; + + LPITEMIDLIST pidl = SHBrowseForFolder( &bi ); + if( !pidl ) return; + + // Get path + SHGetPathFromIDList( pidl, szPath ); + + + // Search + SearchFolder( szPath ); + + + // Stay here + SetCurrentDirectory( szPath ); + + + // Free memory used + IMalloc * imalloc = 0; + if( SUCCEEDED( SHGetMalloc( &imalloc ) ) ) + { + imalloc->Free( pidl ); + imalloc->Release(); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +void SearchFolder( TCHAR * szPath ) +{ + // Remove trailing backslash + int iPathLen = ( int )_tcslen( szPath ); + if( iPathLen < 1 ) return; + if( szPath[ iPathLen - 1 ] == TEXT( '\\' ) ) + { + iPathLen--; + } + + // Init working buffer + TCHAR szFullpath[ MAX_PATH ]; + memcpy( szFullpath, szPath, iPathLen * sizeof( TCHAR ) ); + szFullpath[ iPathLen ] = TEXT( '\\' ); + szFullpath[ iPathLen + 1 ] = TEXT( '\0' ); + + // Make pattern + _tcscpy( szFullpath + iPathLen + 1, TEXT( "*" ) ); + + // Find + vector Files; + vector Dirs; + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + hFind = FindFirstFile( szFullpath, &FindFileData ); + if( hFind == INVALID_HANDLE_VALUE ) return; + + do + { + // Skip "." and ".." + if( !_tcscmp( FindFileData.cFileName, TEXT( "." ) ) || + !_tcscmp( FindFileData.cFileName, TEXT( ".." ) ) ) continue; + + // Make full path + _tcscpy( szFullpath + iPathLen + 1, FindFileData.cFileName ); + + // Is directory? + TCHAR * szPartname = new TCHAR[ MAX_PATH ]; + _tcscpy( szPartname, FindFileData.cFileName ); + if( SetCurrentDirectory( szFullpath ) ) + { + // New dir + Dirs.push_back( szPartname ); + continue; + } + + // Search "." + const int iFilenameLen = ( int )_tcslen( FindFileData.cFileName ); + TCHAR * szExt = FindFileData.cFileName + iFilenameLen - 1; + while( ( szExt > FindFileData.cFileName ) && ( *szExt != TEXT( '.' ) ) ) szExt--; + if( *szExt != TEXT( '.' ) ) continue; + szExt++; + + // Check extension + map ::iterator iter = ext_map.find( szExt ); + if( iter == ext_map.end() ) continue; + + // New file + Files.push_back( szPartname ); + } + while( FindNextFile( hFind, &FindFileData ) ); + + FindClose( hFind ); + vector ::iterator iter; + + // Sort and recurse directories + sort( Dirs.begin(), Dirs.end(), TextCompare() ); + iter = Dirs.begin(); + while( iter != Dirs.end() ) + { + TCHAR * szWalk = *iter; + + _tcscpy( szFullpath + iPathLen + 1, szWalk ); + SearchFolder( szFullpath ); + + iter++; + } + + // Sort and add files + sort( Files.begin(), Files.end(), TextCompare() ); + iter = Files.begin(); + while( iter != Files.end() ) + { + TCHAR * szWalk = *iter; + + TCHAR * szKeep = new TCHAR[ MAX_PATH ]; + memcpy( szKeep, szFullpath, ( iPathLen + 1 ) * sizeof( TCHAR ) ); + _tcscpy( szKeep + iPathLen + 1, szWalk ); + playlist->PushBack( szKeep ); + + iter++; + } +} diff --git a/Branches/MusicMod/Player/Src/AddDirectory.h b/Branches/MusicMod/Player/Src/AddDirectory.h new file mode 100644 index 0000000000..8c819cbd63 --- /dev/null +++ b/Branches/MusicMod/Player/Src/AddDirectory.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_ADD_DIRECTORY_H +#define PA_ADD_DIRECTORY_H + + + +#include "Global.h" + + + +void AddDirectory(); + + + +#endif // PA_ADD_DIRECTORY_H diff --git a/Branches/MusicMod/Player/Src/AddFiles.cpp b/Branches/MusicMod/Player/Src/AddFiles.cpp new file mode 100644 index 0000000000..d8367894b2 --- /dev/null +++ b/Branches/MusicMod/Player/Src/AddFiles.cpp @@ -0,0 +1,181 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "AddFiles.h" +#include "InputPlugin.h" +#include "Main.h" +#include "Playlist.h" +#include + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +void AddFiles() +{ + int total = 0; + + int iFilterLen = 0; + + InputPlugin * input; + vector ::iterator iter; + + // Get len +// if( input_plugins.empty() ) return; + iter = input_plugins.begin(); + while( iter != input_plugins.end() ) + { + input = *iter; + if( !input ) iter++; + iFilterLen += input->iFiltersLen; + iter++; + } + +// if( !iFilterLen ) return; + + iFilterLen += 40 + 29 + ( int )ext_map.size() * ( 2 + 4 + 1 ) + 7; + + TCHAR * szFilters = new TCHAR[ iFilterLen ]; + TCHAR * walk = szFilters; + + // ..................1.........1....\....\.1.........1........\.1... + memcpy( walk, TEXT( "All files (*.*)\0*.*\0All supported types\0" ), 40 * sizeof( TCHAR ) ); + walk += 40; + + // Add all extensions as ";*.ext" +// if( ext_map.empty() ) return; + map ::iterator iter_ext = ext_map.begin(); + bool bFirst = true; + while( iter_ext != ext_map.end() ) + { + if( !bFirst ) + { + memcpy( walk, TEXT( ";*." ), 3 * sizeof( TCHAR ) ); + walk += 3; + } + else + { + memcpy( walk, TEXT( "*." ), 2 * sizeof( TCHAR ) ); + walk += 2; + bFirst = false; + } + + TCHAR * szExt = iter_ext->first; + int uLen = ( int )_tcslen( szExt ); + memcpy( walk, szExt, uLen * sizeof( TCHAR ) ); + walk += uLen; + + iter_ext++; + } + + // *walk = TEXT( '\0' ); + // walk++; + + // ..................1..........1... + memcpy( walk, TEXT( ";*.m3u\0" ), 7 * sizeof( TCHAR ) ); + walk += 7; + + // ..................1.........1.........1...........1... + memcpy( walk, TEXT( "Playlist files (*.M3U)\0*.m3u\0" ), 29 * sizeof( TCHAR ) ); + walk += 29; + + // Copy filters + iter = input_plugins.begin(); + while( iter != input_plugins.end() ) + { + input = *iter; + if( !input ) iter++; + memcpy( walk, input->szFilters, input->iFiltersLen * sizeof( TCHAR ) ); + walk += input->iFiltersLen; + iter++; + } + + *walk = TEXT( '\0' ); + walk++; + + +//////////////////////////////////////////////////////////////////////////////// + + static TCHAR szFilenames[ 20001 ]; + *szFilenames = TEXT( '\0' ); // Each time! + + OPENFILENAME ofn; + memset( &ofn, 0, sizeof( OPENFILENAME ) ); + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = WindowMain; + ofn.hInstance = g_hInstance; + ofn.lpstrFilter = szFilters; // "MPEG Layer 3\0*.mp3\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 2; + ofn.lpstrFile = szFilenames; + ofn.nMaxFile = 20000; + ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.nMaxFileTitle = 0, // NULL; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = TEXT( "Add files" ); + + if( !GetOpenFileName( &ofn ) ) return; + + int uDirLen = ( int )_tcslen( szFilenames ); + TCHAR * szDir = szFilenames; + + TCHAR * szFileWalk = szDir + uDirLen + 1; + if( *szFileWalk == TEXT( '\0' ) ) // "\0\0" or just "\0"? + { + // \0\0 -> Single file + if( !_tcsncmp( szDir + uDirLen - 3, TEXT( "m3u" ), 3 ) ) + { + // Playlist file + Playlist::AppendPlaylistFile( szDir ); + } + else + { + // Music file + TCHAR * szKeep = new TCHAR[ uDirLen + 1 ]; + memcpy( szKeep, szDir, uDirLen * sizeof( TCHAR ) ); + szKeep[ uDirLen ] = TEXT( '\0' ); + playlist->PushBack( szKeep ); + } + } + else + { + // \0 -> Several files + int iFileLen; + while( *szFileWalk != TEXT( '\0' ) ) + { + iFileLen = ( int )_tcslen( szFileWalk ); + if( !iFileLen ) return; + + TCHAR * szKeep = new TCHAR[ uDirLen + 1 + iFileLen + 1 ]; + memcpy( szKeep, szDir, uDirLen * sizeof( TCHAR ) ); + szKeep[ uDirLen ] = TEXT( '\\' ); + memcpy( szKeep + uDirLen + 1, szFileWalk, iFileLen * sizeof( TCHAR ) ); + szKeep[ uDirLen + 1 + iFileLen ] = TEXT( '\0' ); + + if( !_tcsncmp( szKeep + uDirLen + 1 + iFileLen - 3, TEXT( "m3u" ), 3 ) ) + { + // Playlist file + Playlist::AppendPlaylistFile( szKeep ); + delete [] szKeep; + } + else + { + // Music file + playlist->PushBack( szKeep ); + } + + szFileWalk += iFileLen + 1; + } + } +} diff --git a/Branches/MusicMod/Player/Src/AddFiles.h b/Branches/MusicMod/Player/Src/AddFiles.h new file mode 100644 index 0000000000..387242ce1a --- /dev/null +++ b/Branches/MusicMod/Player/Src/AddFiles.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_ADD_FILES_H +#define PA_ADD_FILES_H + + + +#include "Global.h" + + + +void AddFiles(); + + + +#endif // PA_ADD_FILES_H diff --git a/Branches/MusicMod/Player/Src/Config.cpp b/Branches/MusicMod/Player/Src/Config.cpp new file mode 100644 index 0000000000..fcfee0bf63 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Config.cpp @@ -0,0 +1,632 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Config.h" +#include "Console.h" +#include + +using namespace std; + + + +map * conf_map = NULL; + + +TCHAR * szIniPath = NULL; +const TCHAR * SECTION = TEXT( "Plainamp" ); + + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfVar::ConfVar( TCHAR * szKey, ConfMode mode ) +{ + // MessageBox( 0, TEXT( "no const @ ConfVar" ), TEXT( "" ), 0 ); + + // Init + const int iLen = ( int )_tcslen( szKey ); + m_szKey = new TCHAR[ iLen + 1 ]; + memcpy( m_szKey, szKey, iLen * sizeof( TCHAR ) ); + m_szKey[ iLen ] = TEXT( '\0' ); + + m_bCopyKey = true; + m_Mode = mode; + + m_bRead = false; + + // Register + if( !conf_map ) conf_map = new map; + conf_map->insert( pair( m_szKey, this ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfVar::ConfVar( const TCHAR * szKey, ConfMode mode ) +{ + // Init + m_szKey = ( TCHAR * )szKey; + + m_bCopyKey = false; + m_Mode = mode; + + m_bRead = false; + + // Register + if( !conf_map ) conf_map = new map; + conf_map->insert( pair( m_szKey, this ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfVar::~ConfVar() +{ + if( m_bCopyKey && m_szKey ) delete [] m_szKey; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfBool::ConfBool( bool * pbData, TCHAR * szKey, ConfMode mode, bool bDefault ) : ConfVar( szKey, mode ) +{ + // MessageBox( 0, TEXT( "no const @ ConfBool" ), TEXT( "" ), 0 ); + + m_pbData = pbData; + m_bDefault = bDefault; + + // *pbData = bDefault; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfBool::ConfBool( bool * pbData, const TCHAR * szKey, ConfMode mode, bool bDefault ) : ConfVar( szKey, mode ) +{ + m_pbData = pbData; + m_bDefault = bDefault; + + // *pbData = bDefault; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfBool::Read() +{ + if( m_bRead || !szIniPath ) return; + + *m_pbData = ( GetPrivateProfileInt( SECTION, m_szKey, ( int )m_bDefault, szIniPath ) != 0 ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfBool::Write() +{ + WritePrivateProfileString( SECTION, m_szKey, *m_pbData ? TEXT( "1" ) : TEXT( "0" ), szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfInt::ConfInt( int * piData, TCHAR * szKey, ConfMode mode, int iDefault ) : ConfVar( szKey, mode ) +{ + MessageBox( 0, TEXT( "no const" ), TEXT( "" ), 0 ); + + m_piData = piData; + m_iDefault = iDefault; + + // *piData = iDefault; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfInt::ConfInt( int * piData, const TCHAR * szKey, ConfMode mode, int iDefault ) : ConfVar( szKey, mode ) +{ + m_piData = piData; + m_iDefault = iDefault; + + // *piData = iDefault; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfInt::Read() +{ + if( m_bRead || !szIniPath ) return; + + *m_piData = GetPrivateProfileInt( SECTION, m_szKey, m_iDefault, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfInt::Write() +{ + TCHAR szNumber[ 12 ] = TEXT( "" ); + _stprintf( szNumber, TEXT( "%i" ), *m_piData ); + WritePrivateProfileString( SECTION, m_szKey, szNumber, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfIntMinMax::ConfIntMinMax( int * piData, TCHAR * szKey, ConfMode mode, int iDefault, int iMin, int iMax ) : ConfInt( piData, szKey, mode, iDefault ) +{ + MessageBox( 0, TEXT( "no const" ), TEXT( "" ), 0 ); + + m_iMin = iMin; + m_iMax = iMax; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfIntMinMax::ConfIntMinMax( int * piData, const TCHAR * szKey, ConfMode mode, int iDefault, int iMin, int iMax ) : ConfInt( piData, szKey, mode, iDefault ) +{ + m_iMin = iMin; + m_iMax = iMax; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfWinPlaceCallback::ConfWinPlaceCallback( WINDOWPLACEMENT * pwpData, TCHAR * szKey, RECT * prDefault, ConfCallback fpCallback ) : ConfVar( szKey, CONF_MODE_INTERNAL ) +{ + MessageBox( 0, TEXT( "no const" ), TEXT( "" ), 0 ); + + m_pwpData = pwpData; + m_prDefault = prDefault; + m_fpCallback = fpCallback; + + pwpData->length = sizeof( WINDOWPLACEMENT ); + pwpData->flags = 0; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfWinPlaceCallback::ConfWinPlaceCallback( WINDOWPLACEMENT * pwpData, const TCHAR * szKey, RECT * prDefault, ConfCallback fpCallback ) : ConfVar( szKey, CONF_MODE_INTERNAL ) +{ + m_pwpData = pwpData; + m_prDefault = prDefault; + m_fpCallback = fpCallback; + + pwpData->length = sizeof( WINDOWPLACEMENT ); + pwpData->flags = 0; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfWinPlaceCallback::Read() +{ + if( m_bRead || !szIniPath ) return; + + POINT ptMinPosition = { -1, -1 }; + POINT ptMaxPosition = { -GetSystemMetrics( SM_CXBORDER ), -GetSystemMetrics( SM_CYBORDER ) }; + + m_pwpData->length = sizeof( WINDOWPLACEMENT ); + m_pwpData->flags = 0; + m_pwpData->ptMinPosition = ptMinPosition; + m_pwpData->ptMaxPosition = ptMaxPosition; + + + TCHAR szOut[ 111 ] = TEXT( "" ); + int iChars = GetPrivateProfileString( SECTION, m_szKey, TEXT( "" ), szOut, 110, szIniPath ); + bool bApplyDefault = true; + if( iChars ) + { + int iFields = _stscanf( + szOut, + TEXT( "(%u,(%i,%i,%i,%i))" ), + &m_pwpData->showCmd, + &m_pwpData->rcNormalPosition.left, + &m_pwpData->rcNormalPosition.top, + &m_pwpData->rcNormalPosition.right, + &m_pwpData->rcNormalPosition.bottom + ); + if( iFields == 5 ) + { + bApplyDefault = false; + } + } + + if( bApplyDefault ) + { + m_pwpData->showCmd = SW_SHOWNORMAL; + m_pwpData->rcNormalPosition = *m_prDefault; + } + + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfWinPlaceCallback::Write() +{ + // Refresh data + if( m_fpCallback ) m_fpCallback( this ); + + TCHAR szData[ 111 ] = TEXT( "" ); + _stprintf( + szData, + TEXT( "(%u,(%i,%i,%i,%i))" ), + m_pwpData->showCmd, + m_pwpData->rcNormalPosition.left, + m_pwpData->rcNormalPosition.top, + m_pwpData->rcNormalPosition.right, + m_pwpData->rcNormalPosition.bottom + ); + WritePrivateProfileString( SECTION, m_szKey, szData, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfBandInfoCallback::ConfBandInfoCallback( BandInfo * pbiData, TCHAR * szKey, BandInfo * pbiDefault, ConfCallback fpCallback ) : ConfVar( szKey, CONF_MODE_INTERNAL ) +{ + MessageBox( 0, TEXT( "no const" ), TEXT( "" ), 0 ); + + m_pbiData = pbiData; + m_pbiDefault = pbiDefault; + m_fpCallback = fpCallback; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfBandInfoCallback::ConfBandInfoCallback( BandInfo * pbiData, const TCHAR * szKey, BandInfo * pbiDefault, ConfCallback fpCallback ) : ConfVar( szKey, CONF_MODE_INTERNAL ) +{ + m_pbiData = pbiData; + m_pbiDefault = pbiDefault; + m_fpCallback = fpCallback; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfBandInfoCallback::Read() +{ + if( m_bRead || !szIniPath ) return; + + int iBreak; + int iVisible; + + TCHAR szOut[ 91 ] = TEXT( "" ); + int iChars = GetPrivateProfileString( SECTION, m_szKey, TEXT( "" ), szOut, 90, szIniPath ); + bool bApplyDefault = true; + if( iChars ) + { + int iFields = _stscanf( + szOut, + TEXT( "(%i,%i,%i,%i)" ), + &m_pbiData->m_iIndex, + &m_pbiData->m_iWidth, + &iBreak, + &iVisible + ); + if( iFields == 4 ) + { + m_pbiData->m_bBreak = ( iBreak != 0 ); + m_pbiData->m_bVisible = ( iVisible != 0 ); + + bApplyDefault = false; + } + } + + if( bApplyDefault ) + { + *m_pbiData = *m_pbiDefault; + } + + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfBandInfoCallback::Write() +{ + // Refresh data + if( m_fpCallback ) m_fpCallback( this ); + + TCHAR szData[ 91 ] = TEXT( "" ); + _stprintf( + szData, + TEXT( "(%i,%i,%i,%i)" ), + m_pbiData->m_iIndex, + m_pbiData->m_iWidth, + ( int )m_pbiData->m_bBreak, + ( int )m_pbiData->m_bVisible + ); + WritePrivateProfileString( SECTION, m_szKey, szData, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool ConfBandInfoCallback::Apply( HWND hRebar, int iBandId ) +{ + const int iOldIndex = ( int )SendMessage( hRebar, RB_IDTOINDEX, iBandId, 0 ); + if( iOldIndex == -1 ) return false; + + int & iNewIndex = m_pbiData->m_iIndex; + if( iOldIndex != iNewIndex ) + { + // Move band + if( !SendMessage( hRebar, RB_MOVEBAND, iOldIndex, iNewIndex ) ) + { + return false; + } + } + + REBARBANDINFO rbbi; + rbbi.cbSize = sizeof( REBARBANDINFO ); + rbbi.fMask = RBBIM_STYLE; + + // Get current info + if( !SendMessage( hRebar, RB_GETBANDINFO, iNewIndex, ( LPARAM )&rbbi ) ) + { + return false; + } + + rbbi.fMask = RBBIM_SIZE | RBBIM_STYLE; + rbbi.cx = m_pbiData->m_iWidth; + if( ( rbbi.fStyle & RBBS_BREAK ) == RBBS_BREAK ) + { + if( !m_pbiData->m_bBreak ) rbbi.fStyle -= RBBS_BREAK; + } + else + { + if( m_pbiData->m_bBreak ) rbbi.fStyle |= RBBS_BREAK; + } + + // Update info + if( !SendMessage( hRebar, RB_SETBANDINFO, iNewIndex, ( LPARAM )&rbbi ) ) + { + return false; + } + + // Show/hide band + if( !SendMessage( hRebar, RB_SHOWBAND, iNewIndex, m_pbiData->m_bVisible ? TRUE : FALSE ) ) + { + return false; + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfString::ConfString( TCHAR * szData, TCHAR * szKey, ConfMode mode, TCHAR * szDefault, int iMaxLen ) : ConfVar( szKey, mode ) +{ + MessageBox( 0, TEXT( "no const" ), TEXT( "" ), 0 ); + + m_szData = szData; + m_szDefault = szDefault; + m_iMaxLen = iMaxLen; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfString::ConfString( TCHAR * szData, const TCHAR * szKey, ConfMode mode, TCHAR * szDefault, int iMaxLen ) : ConfVar( szKey, mode ) +{ + m_szData = szData; + m_szDefault = szDefault; + m_iMaxLen = iMaxLen; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfString::Read() +{ + if( m_bRead || !szIniPath ) return; + + GetPrivateProfileString( SECTION, m_szKey, m_szDefault, m_szData, m_iMaxLen, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfString::Write() +{ + WritePrivateProfileString( SECTION, m_szKey, m_szData, szIniPath ); + m_bRead = true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfCurDir::ConfCurDir( TCHAR * szData, TCHAR * szKey ) : ConfString( szData, szKey, CONF_MODE_INTERNAL, TEXT( "C:\\" ), MAX_PATH ) +{ + +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +ConfCurDir::ConfCurDir( TCHAR * szData, const TCHAR * szKey ) : ConfString( szData, szKey, CONF_MODE_INTERNAL, TEXT( "C:\\" ), MAX_PATH ) +{ + +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfCurDir::Read() +{ + ConfString::Read(); + + // MessageBox( 0, m_szData, TEXT( "CurDir" ), 0 ); + + // Apply + SetCurrentDirectory( m_szData ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ConfCurDir::Write() +{ + // Refresh + GetCurrentDirectory( MAX_PATH, m_szData ); // Note: without trailing slash + + // MessageBox( 0, m_szData, TEXT( "CurDir" ), 0 ); + + ConfString::Write(); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Conf::Init( HINSTANCE hInstance ) +{ + if( szIniPath ) return; + + // Long filename + + szIniPath = new TCHAR[ _MAX_PATH ]; + + TCHAR szFull[ _MAX_PATH ] = TEXT( "" ); + TCHAR szDrive[ _MAX_DRIVE ] = TEXT( "" ); + TCHAR szDir[ _MAX_DIR ] = TEXT( "" ); + + + GetModuleFileName( hInstance, szFull, _MAX_PATH ); + + _tsplitpath( szFull, szDrive, szDir, NULL, NULL ); + + + // Convert short to long path + GetLongPathName( szDir, szDir, _MAX_DIR ); + + // Convert short to long file + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile( szFull, &fd ); + + // Search last dot + TCHAR * szSearch = fd.cFileName + _tcslen( fd.cFileName ) - 1; + while( ( *szSearch != TEXT( '.' ) ) && ( szSearch > fd.cFileName ) ) + { + szSearch--; + } + + // Replace extension + _tcscpy( szSearch, TEXT( ".ini" ) ); + + // Copy full filename + _sntprintf( szIniPath, _MAX_PATH, TEXT( "%s%s%s" ), szDrive, szDir, fd.cFileName ); + + + + // Read all + map::iterator iter = conf_map->begin(); + while( iter != conf_map->end() ) + { + iter->second->Read(); + iter++; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Conf::Write() +{ + if( !szIniPath ) return; + + map::iterator iter = conf_map->begin(); + while( iter != conf_map->end() ) + { + iter->second->Write(); + iter++; + } +} diff --git a/Branches/MusicMod/Player/Src/Config.h b/Branches/MusicMod/Player/Src/Config.h new file mode 100644 index 0000000000..30f4c2bae3 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Config.h @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_CONFIG_H +#define PA_CONFIG_H + + + +#include "Global.h" +#include "OutputPlugin.h" + + + +namespace Conf +{ + void Init( HINSTANCE hInstance ); + void Write(); +}; + + + +enum ConfMode +{ + CONF_MODE_INTERNAL, // Will not be shown to the user + CONF_MODE_PUBLIC +}; + +class ConfVar; +typedef void ( * ConfCallback )( ConfVar * var ); + +struct BandInfo +{ + int m_iIndex; + int m_iWidth; + bool m_bBreak; + bool m_bVisible; +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Config container +//////////////////////////////////////////////////////////////////////////////// +class ConfVar +{ +public: + ConfVar( TCHAR * szKey, ConfMode mode ); + ConfVar( const TCHAR * szKey, ConfMode mode ); + ~ConfVar(); + +protected: + TCHAR * m_szKey; ///< Unique identifier + ConfMode m_Mode; ///< Mode/visibility + bool m_bRead; ///< Initilization flag + + virtual void Read() = 0; + virtual void Write() = 0; + + // virtual void Backup() = 0; ///< Creates a backup and deletes old backup if it exists + // virtual void Restore() = 0; ///< Restores settings from backup and destroys the backup + +private: + bool m_bCopyKey; ///< Keyname is copy (has to be freed on destruction) + + friend void Conf::Init( HINSTANCE hInstance ); + friend void Conf::Write(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Boolean config container +//////////////////////////////////////////////////////////////////////////////// +class ConfBool : public ConfVar +{ +public: + ConfBool( bool * pbData, TCHAR * szKey, ConfMode mode, bool bDefault ); + ConfBool( bool * pbData, const TCHAR * szKey, ConfMode mode, bool bDefault ); + +private: + bool * m_pbData; ///< Target + bool m_bDefault; ///< Default value + + void Read(); + void Write(); + + + friend OutputPlugin::OutputPlugin( TCHAR * szDllpath, bool bKeepLoaded ); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Integer config container +//////////////////////////////////////////////////////////////////////////////// +class ConfInt : public ConfVar +{ +public: + ConfInt( int * piData, TCHAR * szKey, ConfMode mode, int iDefault ); + ConfInt( int * piData, const TCHAR * szKey, ConfMode mode, int iDefault ); + +protected: + int * m_piData; + int m_iDefault; + + void Read(); + void Write(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Integer config container with restricted range +//////////////////////////////////////////////////////////////////////////////// +class ConfIntMinMax : public ConfInt +{ +public: + ConfIntMinMax( int * piData, TCHAR * szKey, ConfMode mode, int iDefault, int iMin, int iMax ); + ConfIntMinMax( int * piData, const TCHAR * szKey, ConfMode mode, int iDefault, int iMin, int iMax ); + +// bool IsValid() { return ( ( *m_piData >= m_iMin ) && ( *m_piData <= m_iMax ) ); } + inline bool IsMin() { return ( *m_piData == m_iMin ); } + inline bool IsMax() { return ( *m_piData == m_iMax ); } + + inline void MakeValidDefault() { if( ( *m_piData < m_iMin ) || ( *m_piData > m_iMax ) ) *m_piData = m_iDefault; } + inline void MakeValidPull() { if( *m_piData < m_iMin ) *m_piData = m_iMin; else if( *m_piData > m_iMax ) *m_piData = m_iMax; } + +private: + int m_iMin; + int m_iMax; + + void Read() { ConfInt::Read(); MakeValidPull(); } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Window placement config container +/// +/// The callback funtion is called on write() +/// so the data written is up to date. +//////////////////////////////////////////////////////////////////////////////// +class ConfWinPlaceCallback : public ConfVar +{ +public: + ConfWinPlaceCallback( WINDOWPLACEMENT * pwpData, TCHAR * szKey, RECT * prDefault, ConfCallback fpCallback ); + ConfWinPlaceCallback( WINDOWPLACEMENT * pwpData, const TCHAR * szKey, RECT * prDefault, ConfCallback fpCallback ); + + inline void TriggerCallback() { if( m_fpCallback ) m_fpCallback( this ); } + inline void RemoveCallback() { m_fpCallback = NULL; } + +private: + WINDOWPLACEMENT * m_pwpData; + RECT * m_prDefault; + ConfCallback m_fpCallback; + + void Read(); + void Write(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Rebar band info config container +/// +/// The callback funtion is called on write() +/// so the data written is up to date. +//////////////////////////////////////////////////////////////////////////////// +class ConfBandInfoCallback : public ConfVar +{ +public: + ConfBandInfoCallback( BandInfo * pbiData, TCHAR * szKey, BandInfo * pbiDefault, ConfCallback fpCallback ); + ConfBandInfoCallback( BandInfo * pbiData, const TCHAR * szKey, BandInfo * pbiDefault, ConfCallback fpCallback ); + + inline void TriggerCallback() { if( m_fpCallback ) m_fpCallback( this ); } + inline void RemoveCallback() { m_fpCallback = NULL; } + + bool Apply( HWND hRebar, int iBandId ); + +private: + BandInfo * m_pbiData; + BandInfo * m_pbiDefault; + ConfCallback m_fpCallback; + + void Read(); + void Write(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// String config container +//////////////////////////////////////////////////////////////////////////////// +class ConfString : public ConfVar +{ +public: + ConfString( TCHAR * szData, TCHAR * szKey, ConfMode mode, TCHAR * szDefault, int iMaxLen ); + ConfString( TCHAR * szData, const TCHAR * szKey, ConfMode mode, TCHAR * szDefault, int iMaxLen ); + +protected: + TCHAR * m_szData; + int m_iMaxLen; + TCHAR * m_szDefault; + + void Read(); + void Write(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Current directory config container +//////////////////////////////////////////////////////////////////////////////// +class ConfCurDir : public ConfString +{ +public: + ConfCurDir( TCHAR * szData, TCHAR * szKey ); + ConfCurDir( TCHAR * szData, const TCHAR * szKey ); + +private: + void Read(); + void Write(); +}; + + + +#endif // PA_CONFIG_H diff --git a/Branches/MusicMod/Player/Src/Console.cpp b/Branches/MusicMod/Player/Src/Console.cpp new file mode 100644 index 0000000000..08868156d4 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Console.cpp @@ -0,0 +1,228 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Console.h" +#include "Font.h" +#include "Main.h" +#include "Config.h" +#include + + + +HWND WindowConsole = NULL; // extern +int iNext = 0; + +const int iMaxEntries = 10000; + + + +WNDPROC WndprocConsoleBackup = NULL; +LRESULT CALLBACK WndprocConsole( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +bool bConsoleVisible; +WINDOWPLACEMENT WinPlaceConsole; + +void WinPlaceConsoleCallback( ConfVar * var ) +{ + if( !IsWindow( WindowConsole ) ) return; + + GetWindowPlacement( WindowConsole, &WinPlaceConsole ); + + // MSDN: If the window identified by the hWnd parameter + // is maximized, the showCmd member is SW_SHOWMAXIMIZED. + // If the window is minimized, showCmd is SW_SHOWMINIMIZED. + // Otherwise, it is SW_SHOWNORMAL. + if( !bConsoleVisible ) + { + WinPlaceConsole.showCmd = SW_HIDE; + } +} + +RECT rConsoleDefault = { 50, 400, 450, 700 }; + +ConfWinPlaceCallback cwpcWinPlaceConsole( + &WinPlaceConsole, + TEXT( "WinPlaceConsole" ), + &rConsoleDefault, + WinPlaceConsoleCallback +); + + + +//////////////////////////////////////////////////////////////////////////////// +/// Creates the console window. +/// Size and visibility is used from config. +/// +/// @return Success flag +//////////////////////////////////////////////////////////////////////////////// +bool Console::Create() +{ + WindowConsole = CreateWindowEx( + WS_EX_TOOLWINDOW | // DWORD dwExStyle + WS_EX_CLIENTEDGE, // + TEXT( "LISTBOX" ), // LPCTSTR lpClassName + TEXT( "Console" ), // LPCTSTR lpWindowName + WS_VSCROLL | // DWORD dwStyle + LBS_DISABLENOSCROLL | // + LBS_EXTENDEDSEL | // + LBS_HASSTRINGS | // + LBS_NOTIFY | // + LBS_NOINTEGRALHEIGHT | // + WS_POPUP | // + WS_OVERLAPPEDWINDOW, // + rConsoleDefault.left, // int x + rConsoleDefault.top, // int y + rConsoleDefault.right - rConsoleDefault.left, // int nWidth + rConsoleDefault.bottom - rConsoleDefault.top, // int nHeight + WindowMain, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + if( !WindowConsole ) return false; + + // A blank line at the bottom will give us more space + SendMessage( WindowConsole, LB_INSERTSTRING, 0, ( LPARAM )TEXT( "" ) ); + + Font::Apply( WindowConsole ); + + bConsoleVisible = ( WinPlaceConsole.showCmd != SW_HIDE ); + SetWindowPlacement( WindowConsole, &WinPlaceConsole ); + + // Exchange window procedure + WndprocConsoleBackup = ( WNDPROC )GetWindowLong( WindowConsole, GWL_WNDPROC ); + if( WndprocConsoleBackup != NULL ) + { + SetWindowLong( WindowConsole, GWL_WNDPROC, ( LONG )WndprocConsole ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Destroys the console window. +/// +/// @return Success flag +//////////////////////////////////////////////////////////////////////////////// +bool Console::Destroy() +{ + if( !WindowConsole ) return false; + DestroyWindow( WindowConsole ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Pops up the console window. +/// +/// @return Success flag +//////////////////////////////////////////////////////////////////////////////// +bool Console::Popup() +{ + if( !WindowConsole ) return false; + if( !IsWindowVisible( WindowConsole ) ) + { + ShowWindow( WindowConsole, SW_SHOW ); + } + + SetActiveWindow( WindowConsole ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Adds a new entry at the end/bottom +/// +/// @param szText Log entry +/// @return Success flag +//////////////////////////////////////////////////////////////////////////////// +bool Console::Append( TCHAR * szText ) +{ + if( !WindowConsole ) return false; + if( iNext > iMaxEntries - 1 ) + { + SendMessage( + WindowConsole, + LB_DELETESTRING, + 0, + 0 + ); + iNext--; + } + + const int uTextLen = ( int )_tcslen( szText ); + TCHAR * szBuffer = new TCHAR[ 11 + uTextLen + 1 ]; + time_t now_time_t = time( NULL ); + struct tm * now_tm = localtime( &now_time_t ); + _tcsftime( szBuffer, 12, TEXT( "%H:%M:%S " ), now_tm ); + memcpy( szBuffer + 11, szText, uTextLen * sizeof( TCHAR ) ); + szBuffer[ 11 + uTextLen ] = TEXT( '\0' ); + + SendMessage( WindowConsole, LB_INSERTSTRING, iNext, ( LPARAM )szBuffer ); + SendMessage( WindowConsole, LB_SETSEL, FALSE, -1 ); + SendMessage( WindowConsole, LB_SETSEL, TRUE, iNext ); + SendMessage( WindowConsole, LB_SETTOPINDEX, iNext, 0 ); + iNext++; + + delete [] szBuffer; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocConsole( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { +/* + case WM_CTLCOLORLISTBOX: + if( ( HWND )lp == WindowConsole ) + { + SetBkColor (( HDC )wp, GetSysColor(COLOR_3DFACE)); + return ( LRESULT )GetSysColorBrush(COLOR_3DFACE); + } + break; +*/ + + case WM_SYSCOMMAND: + // Hide instead of closing + if( ( wp & 0xFFF0 ) == SC_CLOSE ) + { + ShowWindow( hwnd, SW_HIDE ); + return 0; + } + break; + + case WM_DESTROY: + cwpcWinPlaceConsole.TriggerCallback(); + cwpcWinPlaceConsole.RemoveCallback(); + break; + + case WM_SHOWWINDOW: + bConsoleVisible = ( wp == TRUE ); + break; + + } + return CallWindowProc( WndprocConsoleBackup, hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/Console.h b/Branches/MusicMod/Player/Src/Console.h new file mode 100644 index 0000000000..6c7ae14914 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Console.h @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_CONSOLE_H +#define PA_CONSOLE_H + + + +#include "Global.h" + + + +extern HWND WindowConsole; + + +//////////////////////////////////////////////////////////////////////////////// +/// Logging console window +//////////////////////////////////////////////////////////////////////////////// +namespace Console +{ + bool Create(); + bool Destroy(); + + bool Popup(); + + bool Append( TCHAR * szText ); +} + + + +#endif // PA_CONSOLE_H diff --git a/Branches/MusicMod/Player/Src/DspModule.cpp b/Branches/MusicMod/Player/Src/DspModule.cpp new file mode 100644 index 0000000000..5a49715d1e --- /dev/null +++ b/Branches/MusicMod/Player/Src/DspModule.cpp @@ -0,0 +1,136 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "DspModule.h" +#include "Unicode.h" + + + +DspModule ** active_dsp_mods = NULL; // extern +int active_dsp_count = 0; // extern + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +DspModule::DspModule( char * szName, int iIndex, winampDSPModule * mod, DspPlugin * plugin ) +{ + iArrayIndex = -1; + + iNameLen = ( int )strlen( szName ); + this->szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( this->szName, szName, iNameLen ); + this->szName[ iNameLen ] = TEXT( '\0' ); + + this->iIndex = iIndex; + this->mod = mod; + this->plugin = plugin; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspModule::Start( int iIndex ) +{ + if( !mod ) return false; + if( iArrayIndex != -1 ) return false; + if( !mod->Init ) return false; + if( mod->Init( mod ) != 0 ) return false; + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + if( !active_dsp_count ) + { + active_dsp_mods = new DspModule * [ 1 ]; + active_dsp_mods[ 0 ] = this; + iArrayIndex = 0; + } + else + { + if( iIndex < 0 ) + iIndex = 0; + else if( iIndex > active_dsp_count ) + iIndex = active_dsp_count; + + DspModule ** new_active_dsp_mods = new DspModule * [ active_dsp_count + 1 ]; + memcpy( new_active_dsp_mods, active_dsp_mods, iIndex * sizeof( DspModule * ) ); + memcpy( new_active_dsp_mods + iIndex + 1, active_dsp_mods + iIndex, ( active_dsp_count - iIndex ) * sizeof( DspModule * ) ); + for( int i = iIndex + 1; i < active_dsp_count + 1; i++ ) + { + new_active_dsp_mods[ i ]->iArrayIndex = i; + } + new_active_dsp_mods[ iIndex ] = this; + iArrayIndex = iIndex; + delete [] active_dsp_mods; + active_dsp_mods = new_active_dsp_mods; + } + active_dsp_count++; + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspModule::Stop() +{ + if( !mod ) return false; + if( iArrayIndex == -1 ) return false; + if( !mod->Quit ) return true; + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + for( int i = iArrayIndex; i < active_dsp_count - 1; i++ ) + { + active_dsp_mods[ i ] = active_dsp_mods[ i + 1 ]; + active_dsp_mods[ i ]->iArrayIndex = i; + } + active_dsp_count--; + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + mod->Quit( mod ); + + iArrayIndex = -1; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspModule::Config() +{ + if( !mod ) return false; + if( iArrayIndex == -1 ) return false; + if( !mod->Config ) return false; + + mod->Config( mod ); + + return true; +} diff --git a/Branches/MusicMod/Player/Src/DspModule.h b/Branches/MusicMod/Player/Src/DspModule.h new file mode 100644 index 0000000000..5b69b177b1 --- /dev/null +++ b/Branches/MusicMod/Player/Src/DspModule.h @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_DSP_MODULE_H +#define PA_DSP_MODULE_H + + + +#include "Global.h" +#include "DspPlugin.h" +#include "Winamp/Dsp.h" + + + +class DspModule; +class DspPlugin; + +extern DspModule ** active_dsp_mods; +extern int active_dsp_count; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp DSP module wrapper +//////////////////////////////////////////////////////////////////////////////// +class DspModule +{ +public: + inline bool IsActive() { return ( iArrayIndex != -1 ); } + + inline TCHAR * GetName() { return szName; } + inline int GetNameLen() { return iNameLen; } + + DspModule( char * szName, int iIndex, winampDSPModule * mod, DspPlugin * plugin ); +// DspModule( wchar_t * szName, int iIndex, winampVisModule * mod, VisPlugin * plugin ); + + bool Start( int iIndex ); + bool Stop(); + + bool Config(); + +private: + int iArrayIndex; + + TCHAR * szName; + int iNameLen; + + int iIndex; + winampDSPModule * mod; + DspPlugin * plugin; + + + friend int dsp_dosamples( short int * samples, int numsamples, int bps, int nch, int srate ); +}; + + + +#endif // PA_DSP_MODULE_H diff --git a/Branches/MusicMod/Player/Src/DspPlugin.cpp b/Branches/MusicMod/Player/Src/DspPlugin.cpp new file mode 100644 index 0000000000..e7073cda50 --- /dev/null +++ b/Branches/MusicMod/Player/Src/DspPlugin.cpp @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "DspPlugin.h" +#include "Main.h" +#include "Unicode.h" +#include "Console.h" + + + +vector dsp_plugins; // extern +Lock DspLock = Lock( TEXT( "PLAINAMP_DSP_LOCK" ) ); // extern + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +DspPlugin::DspPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) +{ + header = NULL; + + if( !Load() ) + { + return; + } + + if( !bKeepLoaded ) + { + Unload(); + } + + dsp_plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspPlugin::Load() +{ + if( IsLoaded() ) return true; + + // (1) Load DLL + hDLL = LoadLibrary( GetFullpath() ); + if( !hDLL ) return false; + + // (2) Find export + WINAMP_DSP_GETTER winampGetDSPHeader2 = + ( WINAMP_DSP_GETTER )GetProcAddress( hDLL, "winampDSPGetHeader2" ); + if( winampGetDSPHeader2 == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (3) Get header + header = winampGetDSPHeader2(); + if( header == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + +//////////////////////////////////////////////////////////////////////////////// + // Forget old modules or we get them twice + if( !modules.empty() ) + { + modules.clear(); + } +//////////////////////////////////////////////////////////////////////////////// + + if( !szName ) + { + // Note: The prefix is not removed to hide their + // origin at Nullsoft! It just reads easier. + if( !strnicmp( header->description, "nullsoft ", 9 ) ) + { + header->description += 9; + } + iNameLen = ( int )strlen( header->description ); + szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( szName, header->description, iNameLen ); + szName[ iNameLen ] = TEXT( '\0' ); + } + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); + Console::Append( szBuffer ); + + // (4) Get modules + winampDSPModule * mod; + int iFound = 0; + while( true ) + { + mod = header->getModule( iFound ); + if( !mod ) break; + + // (4a) Modify module + mod->hDllInstance = hDLL; + mod->hwndParent = WindowMain; + + // (4b) Add module to list + DspModule * dspmod = new DspModule( + mod->description, // char * szName + iFound, // UINT uIndex + mod, // winampDspModule * mod + this // DspPlugin * plugin + ); + modules.push_back( dspmod ); + iFound++; + + _stprintf( szBuffer, TEXT( " %s" ), dspmod->GetName() ); + Console::Append( szBuffer ); + } + + Console::Append( TEXT( " " ) ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspPlugin::Unload() +{ + if( !IsLoaded() ) return true; + if( IsActive() ) return false; + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Unloading <%s>" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + header = NULL; + + /* + TODO + DspModule * walk; + vector ::iterator iter = modules.begin(); + while( iter != modules.end() ) + { + walk = *iter; + delete [] walk->szName; + delete walk; + + iter++; + } + */ + + FreeLibrary( hDLL ); + hDLL = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool DspPlugin::IsActive() +{ + vector ::iterator iter = modules.begin(); + while( iter != modules.end() ) + { + if( ( *iter )->IsActive() ) return true; + iter++; + } + return false; +} diff --git a/Branches/MusicMod/Player/Src/DspPlugin.h b/Branches/MusicMod/Player/Src/DspPlugin.h new file mode 100644 index 0000000000..afd299a60c --- /dev/null +++ b/Branches/MusicMod/Player/Src/DspPlugin.h @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_DSP_PLUGIN_H +#define PA_DSP_PLUGIN_H + + + +#include "Global.h" +#include "Plugin.h" +#include "Winamp/Dsp.h" +#include "Lock.h" +#include "DspModule.h" +#include + +using namespace std; + + + +typedef winampDSPHeader * ( * WINAMP_DSP_GETTER )( void ); + + + +class DspModule; +class DspPlugin; + +extern vector dsp_plugins; +extern Lock DspLock; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp DSP plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class DspPlugin : public Plugin +{ +public: + DspPlugin( TCHAR * szDllpath, bool bKeepLoaded ); + + bool Load(); + bool Unload(); + + TCHAR * GetTypeString() { return TEXT( "DSP" ); } + int GetTypeStringLen() { return 3; } + PluginType GetType() { return PLUGIN_TYPE_DSP; } + + bool IsActive(); + +private: + winampDSPHeader * header; + vector modules; + + + friend class DspModule; + friend void ContextMenuDsp( DspPlugin * dsp, POINT * p ); +}; + + + +#endif // PA_DSP_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/Emabox/Emabox.cpp b/Branches/MusicMod/Player/Src/Emabox/Emabox.cpp new file mode 100644 index 0000000000..1f1d2bf032 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Emabox/Emabox.cpp @@ -0,0 +1,455 @@ +/*////////////////////////////////////////////////////////////////////////////// +// ExtraMessageBox +// +// Copyright © 2006 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////*/ + + +/* +TODO +* realign/recenter after height change +* tab stop order when adding buttons +* offer extra callback? +* auto click timer (one button after XXX seconds) +* allow several checkboxes? radio buttons? + +MB_YESNO +MB_YESNOCANCEL +--> MB_YESNOALL +--> MB_YESNOCANCELALL +--> MB_DEFBUTTON5 +--> IDNOALL +--> IDYESALL +*/ + + +#include "Emabox.h" + + + +#define FUNCTION_NORMAL 0 +#define FUNCTION_EXTENDED 1 +#define FUNCTION_INDIRECT 2 + + + +const int SPACE_UNDER_CHECKBOX = 10; +const int SPACE_EXTRA_BOTTOM = 4; + +TCHAR * const szNeverAgain = TEXT( "Do not show again" ); +TCHAR * const szRememberChoice = TEXT( "Remember my choice" ); + +DWORD dwTlsSlot = TLS_OUT_OF_INDEXES; + +#ifdef EMA_AUTOINIT +int bEmaInitDone = 0; +#endif + + + +struct StructEmaBoxData +{ + int * bCheckState; + HHOOK hCBT; /* CBT hook handle */ + WNDPROC WndprocMsgBoxBackup; /* Old wndproc */ + UINT uType; /* Message box type */ + HWND hCheck; /* Checkbox handle */ +}; + +typedef struct StructEmaBoxData EmaBoxData; + + + +void RectScreenToClient( const HWND h, RECT * const r ) +{ + POINT p; + RECT after; + + p.x = r->left; + p.y = r->top; + ScreenToClient( h, &p ); + + after.left = p.x; + after.right = p.x + r->right - r->left; + after.top = p.y; + after.bottom = p.y + r->bottom - r->top; + + memcpy( r, &after, sizeof( RECT ) ); +} + + + +LRESULT CALLBACK WndprocMsgBox( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + /* Find data */ + EmaBoxData * const data = ( EmaBoxData * )TlsGetValue( dwTlsSlot ); + + switch( message ) + { + case WM_COMMAND: + if( HIWORD( wp ) == BN_CLICKED ) + { + if( !data->hCheck || ( ( HWND )lp != data->hCheck ) ) break; + + { + const LRESULT res = SendMessage( ( HWND )lp, BM_GETSTATE, 0, 0 ); + const int bCheckedAfter = ( ( res & BST_CHECKED ) == 0 ); + + /* Update external variable */ + *( data->bCheckState ) = bCheckedAfter ? 1 : 0; + + SendMessage( ( HWND )lp, BM_SETCHECK, ( bCheckedAfter ) ? BST_CHECKED : 0, 0 ); + } + } + break; + + case WM_INITDIALOG: + { + /* Add checkbox */ + if( ( data->uType & MB_CHECKMASC ) != 0 ) + { + int SPACE_OVER_CHECKBOX; + HDC hdc; + RECT rw; /* Window rect */ + RECT rc; /* Client rect */ + HWND hText; /* Message handle */ + RECT rt; /* Message rect */ + int iLabelHeight; + TCHAR * szCheckboxLabel; /* Checkbox label */ + + int iWindowWidthBefore; + int iWindowHeightBefore; + int iClientWidthBefore; + int iClientHeightBefore; + int iNeverAgainWidth; + int iNeverAgainHeight; + + + + /* Get original window dimensions */ + GetWindowRect( hwnd, &rw ); + iWindowWidthBefore = rw.right - rw.left; + iWindowHeightBefore = rw.bottom - rw.top; + + GetClientRect( hwnd, &rc ); + iClientWidthBefore = rc.right - rc.left; + iClientHeightBefore = rc.bottom - rc.top; + + + + { + /* Find handle of the text label */ + HWND hFirstStatic; + HWND hSecondStatic; + + hFirstStatic = FindWindowEx( hwnd, NULL, TEXT( "STATIC" ), NULL ); + if( !hFirstStatic ) break; + + hSecondStatic = FindWindowEx( hwnd, hFirstStatic, TEXT( "STATIC" ), NULL ); + if( !hSecondStatic ) + { + /* Only one static means no icon. */ + /* So hFirstStatic must be the text window. */ + hText = hFirstStatic; + } + else + { + TCHAR szBuf[ 2 ] = TEXT( "" ); + if( !GetWindowText( hSecondStatic, szBuf, 2 ) ) break; + + if( *szBuf != TEXT( '\0' ) ) + { + /* Has text so it must be the label */ + hText = hSecondStatic; + } + else + { + hText = hFirstStatic; + } + } + } + + GetWindowRect( hText, &rt ); + RectScreenToClient( hwnd, &rt ); + + iLabelHeight = rt.bottom - rt.top; + + { + /* Get distance between label and the buttons */ + HWND hAnyButton; + RECT rab; + + hAnyButton = FindWindowEx( hwnd, NULL, TEXT( "BUTTON" ), NULL ); + if( !hAnyButton ) break; + + GetWindowRect( hAnyButton, &rab ); + RectScreenToClient( hwnd, &rab ); + + SPACE_OVER_CHECKBOX = rab.top - rt.bottom; + } + + szCheckboxLabel = ( data->uType & MB_CHECKNEVERAGAIN ) + ? EMA_TEXT_NEVER_AGAIN + : EMA_TEXT_REMEMBER_CHOICE; + + /* Add checkbox */ + data->hCheck = CreateWindow( + TEXT( "BUTTON" ), + szCheckboxLabel, + WS_CHILD | + WS_VISIBLE | + WS_TABSTOP | + BS_VCENTER | + BS_CHECKBOX, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + hwnd, + NULL, + GetModuleHandle( NULL ), + NULL + ); + + + /* Set initial check state */ + SendMessage( data->hCheck, BM_SETCHECK, *( data->bCheckState ) ? BST_CHECKED : 0, 0 ); + + { + /* Apply default font */ + const int cyMenuSize = GetSystemMetrics( SM_CYMENUSIZE ); + const int cxMenuSize = GetSystemMetrics( SM_CXMENUSIZE ); + const HFONT hNewFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT ); + HFONT hOldFont; + SIZE size; + + SendMessage( data->hCheck, WM_SETFONT, ( WPARAM )hNewFont, ( LPARAM )TRUE ); + + hdc = GetDC( data->hCheck ); + hOldFont = ( HFONT )SelectObject( hdc, GetStockObject( DEFAULT_GUI_FONT ) ); + GetTextExtentPoint32( hdc, szCheckboxLabel, _tcslen( szCheckboxLabel ), &size ); + SelectObject( hdc, hOldFont ); + ReleaseDC( data->hCheck, hdc ); + + iNeverAgainWidth = cxMenuSize + size.cx + 1; + iNeverAgainHeight = ( cyMenuSize > size.cy ) ? cyMenuSize : size.cy; + } + + MoveWindow( + data->hCheck, + ( iClientWidthBefore - ( iNeverAgainWidth ) ) / 2, + rt.top + iLabelHeight + SPACE_OVER_CHECKBOX, + iNeverAgainWidth, + iNeverAgainHeight, + FALSE + ); + + { + /* Move all buttons down (except the checkbox) */ + const int iDistance = iNeverAgainHeight + SPACE_UNDER_CHECKBOX; + HWND hLastButton = NULL; + RECT rb; + for( ; ; ) + { + hLastButton = FindWindowEx( hwnd, hLastButton, TEXT( "BUTTON" ), NULL ); + if( !hLastButton ) break; + if( hLastButton == data->hCheck ) continue; + + GetWindowRect( hLastButton, &rb ); + RectScreenToClient( hwnd, &rb ); + + MoveWindow( hLastButton, rb.left, rb.top + iDistance, rb.right - rb.left, rb.bottom - rb.top, FALSE ); + } + + + /* Enlarge dialog */ + MoveWindow( hwnd, rw.left, rw.top, iWindowWidthBefore, iWindowHeightBefore + iDistance + SPACE_EXTRA_BOTTOM, FALSE ); + } + } + else + { + data->hCheck = NULL; + } + + /* Modify close button */ + switch( data->uType & MB_CLOSEMASK ) + { + case MB_DISABLECLOSE: + { + const HMENU hSysMenu = GetSystemMenu( hwnd, FALSE ); + EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED ); + } + break; + + case MB_NOCLOSE: + { + const LONG style = GetWindowLong( hwnd, GWL_STYLE ); + if( ( style & WS_SYSMENU ) == 0 ) break; + SetWindowLong( hwnd, GWL_STYLE, ( LONG )( style - WS_SYSMENU ) ); + } + break; + + } + } + break; + + } + return CallWindowProc( data->WndprocMsgBoxBackup, hwnd, message, wp, lp ); +} + + + +/* int bFound = 0; */ + +LRESULT CALLBACK HookprocMsgBox( int code, WPARAM wp, LPARAM lp ) +{ + /* Get hook handle */ + EmaBoxData * const data = ( EmaBoxData * )TlsGetValue( dwTlsSlot ); + + if( code == HCBT_CREATEWND ) + { + /* MSDN says WE CANNOT TRUST "CBT_CREATEWND" */ + /* so we use only the window handle */ + /* and get the class name using "GetClassName". (-> Q106079) */ + HWND hwnd = ( HWND )wp; + + /* Check windowclass */ + TCHAR szClass[ 7 ] = TEXT( "" ); + GetClassName( hwnd, szClass, 7 ); + if( !_tcscmp( szClass, TEXT( "#32770" ) ) ) + { +/* + if( bFound ) + { + return CallNextHookEx( hCBT, code, wp, lp ); + } + + bFound = 1; +*/ + /* Exchange window procedure */ + data->WndprocMsgBoxBackup = ( WNDPROC )GetWindowLong( hwnd, GWL_WNDPROC ); + if( data->WndprocMsgBoxBackup != NULL ) + { + SetWindowLong( hwnd, GWL_WNDPROC, ( LONG )WndprocMsgBox ); + } + } + } + return CallNextHookEx( data->hCBT, code, wp, lp ); +} + + + +int ExtraAllTheSame( const HWND hWnd, const LPCTSTR lpText, const LPCTSTR lpCaption, const UINT uType, const WORD wLanguageId, const LPMSGBOXPARAMS lpMsgBoxParams, int * const pbCheckRes, const int iFunction ) +{ + EmaBoxData * data; + HHOOK hCBT; + int res; + +#ifdef EMA_AUTOINIT + if( !bEmaInitDone ) + { + EmaBoxLive(); + bEmaInitDone = 1; + } +#endif + + /* Create thread data */ + data = ( EmaBoxData * )LocalAlloc( NONZEROLPTR, sizeof( EmaBoxData ) ); + TlsSetValue( dwTlsSlot, data ); + data->bCheckState = pbCheckRes; + data->uType = ( iFunction != FUNCTION_INDIRECT ) ? uType : lpMsgBoxParams->dwStyle; + + /* Setup this-thread-only hook */ + hCBT = SetWindowsHookEx( WH_CBT, &HookprocMsgBox, GetModuleHandle( NULL ), GetCurrentThreadId() ); + + switch( iFunction ) + { + case FUNCTION_NORMAL: + res = MessageBox( hWnd, lpText, lpCaption, uType ); + break; + + case FUNCTION_EXTENDED: + res = MessageBoxEx( hWnd, lpText, lpCaption, uType, wLanguageId ); + break; + + case FUNCTION_INDIRECT: + res = MessageBoxIndirect( lpMsgBoxParams ); + break; + + } + + /* Remove hook */ + if( hCBT != NULL ) UnhookWindowsHookEx( hCBT ); + + /* Destroy thread data */ + LocalFree( ( HLOCAL )data ); + + return res; +} + + + +int EmaBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, int * pbCheckRes ) +{ + /* Check extra flags */ + if( ( uType & MB_EXTRAMASC ) == 0 ) + { + /* No extra */ + return MessageBox( hWnd, lpText, lpCaption, uType ); + } + + return ExtraAllTheSame( hWnd, lpText, lpCaption, uType, 0, NULL, pbCheckRes, FUNCTION_NORMAL ); +} + + + +int EmaBoxEx( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, WORD wLanguageId, int * pbCheckRes ) +{ + /* Check extra flags */ + if( ( uType & MB_EXTRAMASC ) == 0 ) + { + /* No extra */ + return MessageBoxEx( hWnd, lpText, lpCaption, uType, wLanguageId ); + } + + return ExtraAllTheSame( hWnd, lpText, lpCaption, uType, wLanguageId, NULL, pbCheckRes, FUNCTION_EXTENDED ); +} + + + +int EmaBoxIndirect( const LPMSGBOXPARAMS lpMsgBoxParams, int * pbCheckRes ) +{ + /* Check extra flags */ + if( ( lpMsgBoxParams->dwStyle & MB_EXTRAMASC ) == 0 ) + { + /* No extra */ + return MessageBoxIndirect( lpMsgBoxParams ); + } + + return ExtraAllTheSame( NULL, NULL, NULL, 0, 0, lpMsgBoxParams, pbCheckRes, FUNCTION_INDIRECT ); +} + + + +int EmaBoxLive() +{ + dwTlsSlot = TlsAlloc(); + if( dwTlsSlot == TLS_OUT_OF_INDEXES ) return 0; + + return 1; +} + + + +int EmaBoxDie() +{ + if( dwTlsSlot == TLS_OUT_OF_INDEXES ) return 0; + + TlsFree( dwTlsSlot ); + return 1; +} diff --git a/Branches/MusicMod/Player/Src/Emabox/Emabox.h b/Branches/MusicMod/Player/Src/Emabox/Emabox.h new file mode 100644 index 0000000000..28c27d8eb2 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Emabox/Emabox.h @@ -0,0 +1,138 @@ +/*////////////////////////////////////////////////////////////////////////////// +// ExtraMessageBox +// +// Copyright © 2006 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////*/ + + +#ifndef EXTRA_MESSAGE_BOX_H +#define EXTRA_MESSAGE_BOX_H 1 + +#include "EmaboxConfig.h" +#include +#include + + + +/* +== TYPE ============================================================================= +#define MB_TYPEMASK 15 1111 +#define MB_OK 0 0000 +#define MB_OKCANCEL 1 0001 +#define MB_ABORTRETRYIGNORE 2 0010 +#define MB_YESNOCANCEL 3 0011 +#define MB_YESNO 4 0100 +#define MB_RETRYCANCEL 5 0101 +#define MB_CANCELTRYCONTINUE 6 0110 +*/ + +#define MB_YESNOCANCELALL 7 /* 0111 */ +#define MB_YESNOALL 8 /* 1000 */ + +/* +== ICON ============================================================================= +#define MB_ICONMASK 240 11110000 +#define MB_ICONERROR 16 00010000 +#define MB_ICONHAND 16 00010000 +#define MB_ICONSTOP 16 00010000 +#define MB_ICONQUESTION 32 00100000 +#define MB_ICONEXCLAMATION 0x30 00110000 +#define MB_ICONWARNING 0x30 00110000 +#define MB_ICONINFORMATION 64 01000000 +#define MB_ICONASTERISK 64 01000000 +#define MB_USERICON 128 10000000 + +== DEFAULT BUTTON =================================================================== +#define MB_DEFMASK 3840 111100000000 +#define MB_DEFBUTTON1 0 000000000000 +#define MB_DEFBUTTON2 256 000100000000 +#define MB_DEFBUTTON3 512 001000000000 +#define MB_DEFBUTTON4 0x300 001100000000 +*/ + +#define MB_DEFBUTTON5 1024 /* 010000000000 */ +#define MB_DEFBUTTON6 1280 /* 010100000000 */ + +/* +== MODE ============================================================================= +#define MB_MODEMASK 0x00003000 11000000000000 +#define MB_APPLMODAL 0 00000000000000 +#define MB_SYSTEMMODAL 4096 01000000000000 +#define MB_TASKMODAL 0x2000 10000000000000 + +== MISC ============================================================================= +#define MB_MISCMASK 0x0000C000 1100000000000000 +#define MB_HELP 0x4000 0100000000000000 +#define MB_NOFOCUS 0x00008000 1000000000000000 + +== FLAGS ============================================================================ +#define MB_SETFOREGROUND 0x10000 10000000000000000 +#define MB_DEFAULT_DESKTOP_ONLY 0x20000 100000000000000000 +#define MB_TOPMOST 0x40000 1000000000000000000 +#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000 1000000000000000000 +#define MB_SERVICE_NOTIFICATION 0x00040000 1000000000000000000 +#define MB_TOPMOST 0x40000 1000000000000000000 +#define MB_RIGHT 0x80000 10000000000000000000 +#define MB_RTLREADING 0x100000 100000000000000000000 +#define MB_SERVICE_NOTIFICATION 0x00200000 1000000000000000000000 + +== EXTRA FLAGS ====================================================================== +*/ + +#define MB_EXTRAMASC 0xF0000000 /* 11110000000000000000000000000000 */ + +#define MB_CHECKMASC 0xC0000000 /* 11000000000000000000000000000000 */ +#define MB_CHECKNONE 0 /* 00000000000000000000000000000000 */ +#define MB_CHECKNEVERAGAIN 0x40000000 /* 01000000000000000000000000000000 */ +#define MB_CHECKREMEMBERCHOICE 0x80000000 /* 10000000000000000000000000000000 */ + +#define MB_CLOSEMASK 0x30000000 /* 00110000000000000000000000000000 */ +#define MB_NORMALCLOSE 0 /* 00000000000000000000000000000000 */ +#define MB_DISABLECLOSE 0x10000000 /* 00010000000000000000000000000000 */ +#define MB_NOCLOSE 0x20000000 /* 00100000000000000000000000000000 */ + + + +/* Function aliases */ +#define ExtraMessageBoxLive EmaBoxLive +#define ExtraMessageBoxDie EmaBoxDie +#define ExtraMessageBox EmaBox +#define ExtraMessageBoxEx EmaBoxEx +#define ExtraMessageBoxIndirect EmaBoxIndirect + + + +int EmaBoxLive(); + +int EmaBoxDie(); + +int EmaBox( + HWND hWnd, + LPCTSTR lpText, + LPCTSTR lpCaption, + UINT uType, + int * pbCheckRes +); + +int EmaBoxEx( + HWND hWnd, + LPCTSTR lpText, + LPCTSTR lpCaption, + UINT uType, + WORD wLanguageId, + int * pbCheckRes +); + +int EmaBoxIndirect( + const LPMSGBOXPARAMS lpMsgBoxParams, + int * pbCheckRes +); + + + +#endif /* EXTRA_MESSAGE_BOX_H */ diff --git a/Branches/MusicMod/Player/Src/Emabox/EmaboxConfig.h b/Branches/MusicMod/Player/Src/Emabox/EmaboxConfig.h new file mode 100644 index 0000000000..c7730335cd --- /dev/null +++ b/Branches/MusicMod/Player/Src/Emabox/EmaboxConfig.h @@ -0,0 +1,32 @@ +/*////////////////////////////////////////////////////////////////////////////// +// ExtraMessageBox +// +// Copyright © 2006 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////*/ + + +#ifndef EXTRA_MESSAGE_BOX_CONFIG_H +#define EXTRA_MESSAGE_BOX_CONFIG_H 1 + + + +/* Allow laziness */ +#define EMA_AUTOINIT + +/* Allow overwriting message text */ +#ifndef EMA_TEXT_NEVER_AGAIN +# define EMA_TEXT_NEVER_AGAIN szNeverAgain +#endif + +#ifndef EMA_TEXT_REMEMBER_CHOICE +# define EMA_TEXT_REMEMBER_CHOICE szRememberChoice +#endif + + + +#endif /* EXTRA_MESSAGE_BOX_CONFIG_H */ diff --git a/Branches/MusicMod/Player/Src/Embed.cpp b/Branches/MusicMod/Player/Src/Embed.cpp new file mode 100644 index 0000000000..fdfb456e2e --- /dev/null +++ b/Branches/MusicMod/Player/Src/Embed.cpp @@ -0,0 +1,233 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Embed.h" +#include "Console.h" + + + +#define CLASSNAME_EMBED TEXT( "Winamp Gen" ) +#define TITLE_EMBED TEXT( "Embed target" ) + +#define EMBED_WIDTH 320 +#define EMBED_HEIGHT 240 + + + +const TCHAR * const szEmbedTitle = TITLE_EMBED; +bool bEmbedClassRegistered = false; + + +LRESULT CALLBACK WndprocEmbed( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +//////////////////////////////////////////////////////////////////////////////// +/// Creates a new embed window. +/// +/// @param ews Embed window state +/// @return New embed window handle +//////////////////////////////////////////////////////////////////////////////// +HWND Embed::Embed( embedWindowState * ews ) +{ + // Register class + if ( !bEmbedClassRegistered ) + { + WNDCLASS wc = { + 0, // UINT style + WndprocEmbed, // WNDPROC lpfnWndProc + 0, // int cbClsExtra + 0, // int cbWndExtra + g_hInstance, // HINSTANCE hInstance + NULL, // HICON hIcon + LoadCursor( NULL, IDC_ARROW ), // HCURSOR hCursor + ( HBRUSH )COLOR_WINDOW, // HBRUSH hbrBackground + NULL, // LPCTSTR lpszMenuName + CLASSNAME_EMBED // LPCTSTR lpszClassName + }; + + if( !RegisterClass( &wc ) ) return NULL; + + bEmbedClassRegistered = true; + } + + // Create window + HWND WindowEmbed = CreateWindowEx( + WS_EX_WINDOWEDGE | // DWORD dwExStyle + WS_EX_TOOLWINDOW, // + CLASSNAME_EMBED, // LPCTSTR lpClassName + szEmbedTitle, // LPCTSTR lpWindowName + WS_OVERLAPPED | // DWORD dwStyle + WS_CLIPCHILDREN | // + WS_BORDER | // + WS_CAPTION | // + WS_SYSMENU | // + WS_THICKFRAME | // + WS_MINIMIZEBOX | // + WS_MAXIMIZEBOX, // + 10, // int x + 10, // int y + EMBED_WIDTH, // int nWidth + EMBED_HEIGHT, // int nHeight + NULL, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + Console::Append( TEXT( "Embed window born" ) ); + Console::Append( TEXT( " " ) ); + + if( !ews || !ews->me ) return WindowEmbed; + + SetParent( ews->me, WindowEmbed ); + + return WindowEmbed; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +inline bool SameThread( HWND hOther ) +{ + const DWORD dwOtherThreadId = GetWindowThreadProcessId( hOther, NULL ); + const DWORD dwThisThreadId = GetCurrentThreadId(); + return ( dwOtherThreadId == dwThisThreadId ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocEmbed( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ +// static bool bAllowSizeMove = false; + + switch( message ) + { + + case WM_PARENTNOTIFY: + switch( LOWORD( wp ) ) + { + case WM_DESTROY: + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( !SameThread( hChild ) ) + { + // Vis plugin + DestroyWindow( hwnd ); + } + break; + } + + } + break; + + case WM_SIZE: + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( !hChild ) break; + MoveWindow( hChild, 0, 0, LOWORD( lp ), HIWORD( lp ), TRUE ); + break; + } + +/* + case WM_ENTERSIZEMOVE: + bAllowSizeMove = true; + break; + + case WM_EXITSIZEMOVE: + bAllowSizeMove = false; + break; + + case WM_WINDOWPOSCHANGING: + { + WINDOWPOS * pos = ( WINDOWPOS * )lp; + + // Update child + if( IsWindow( WindowEmbedChild = GetWindow( WindowEmbed, GW_CHILD ) ) ) + { + RECT r; + GetClientRect( WindowEmbed, &r ); + MoveWindow( WindowEmbedChild, 0, 0, r.right, r.bottom, TRUE ); + } + + if( !bAllowSizeMove ) + { + // Force SWP_NOMOVE + if( ( pos->flags & SWP_NOMOVE ) == 0 ) + { + pos->flags |= SWP_NOMOVE; + } + + // Force SWP_NOSIZE + if( ( pos->flags & SWP_NOSIZE ) == 0 ) + { + pos->flags |= SWP_NOSIZE; + } + + return 0; + } + + break; + } +*/ + case WM_SHOWWINDOW: + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( wp ) // Shown + { + // Update child size + RECT r; + GetClientRect( hwnd, &r ); + MoveWindow( hChild, 0, 0, r.right, r.bottom, TRUE ); + } + else // Hidden + { + ShowWindow( hChild, SW_HIDE ); + DestroyWindow( hChild ); + } + break; + } + + case WM_SYSCOMMAND: + if( ( wp & 0xFFF0 ) == SC_CLOSE ) + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( SameThread( hChild ) ) + { + // Not a vis plugin + ShowWindow( hwnd, SW_HIDE ); + return 0; + } + } + break; + + case WM_DESTROY: + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( hChild && SameThread( hChild ) ) + { + DestroyWindow( hChild ); + } + + Console::Append( TEXT( "Embed window dead" ) ); + Console::Append( TEXT( " " ) ); + break; + } + + } + return DefWindowProc( hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/Embed.h b/Branches/MusicMod/Player/Src/Embed.h new file mode 100644 index 0000000000..fc1a7d8611 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Embed.h @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_EMBED_H +#define PA_EMBED_H + + + +#include "Global.h" +#include "Winamp/wa_ipc.h" + + + +//////////////////////////////////////////////////////////////////////////////// +/// Embed window service. +/// Winamp provides embed windows so plugins don't have to take care +/// of window skinning. A plugin let's Winamp create an embed window +/// and uses this new window as parent for its own window. +//////////////////////////////////////////////////////////////////////////////// +namespace Embed +{ + HWND Embed( embedWindowState * ews ); +}; + + + +#endif // PA_EMBED_H diff --git a/Branches/MusicMod/Player/Src/Font.cpp b/Branches/MusicMod/Player/Src/Font.cpp new file mode 100644 index 0000000000..a47b217bb9 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Font.cpp @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Font.h" + + + +HFONT hFont = NULL; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Font::Create() +{ + hFont = CreateFont( + -11, // int nHeight + 0, // int nWidth + 0, // int nEscapement + 0, // int nOrientation + FW_REGULAR, // int fnWeight + FALSE, // DWORD fdwItalic + FALSE, // DWORD fdwUnderline + FALSE, // DWORD fdwStrikeOut + ANSI_CHARSET, // DWORD fdwCharSet + OUT_TT_PRECIS, // DWORD fdwOutputPrecision + CLIP_DEFAULT_PRECIS, // DWORD fdwClipPrecision + ANTIALIASED_QUALITY, // DWORD fdwQuality + FF_DONTCARE | DEFAULT_PITCH, // DWORD fdwPitchAndFamily + TEXT( "Verdana" ) // LPCTSTR lpszFace + ); + + return ( hFont != NULL ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Font::Destroy() +{ + if( !hFont ) return false; + DeleteObject( hFont ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Font::Apply( HWND hwnd ) +{ + if( !hFont ) return false; + SendMessage( + hwnd, + WM_SETFONT, + ( WPARAM )hFont, + FALSE + ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +HFONT Font::Get() +{ + return hFont; +} diff --git a/Branches/MusicMod/Player/Src/Font.h b/Branches/MusicMod/Player/Src/Font.h new file mode 100644 index 0000000000..d32bec237e --- /dev/null +++ b/Branches/MusicMod/Player/Src/Font.h @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_FONT_H +#define PA_FONT_H + + + +#include "Global.h" + + + +namespace Font +{ + bool Create(); + bool Destroy(); + + bool Apply( HWND hwnd ); + HFONT Get(); +}; + + + +#endif // PA_FONT_H + diff --git a/Branches/MusicMod/Player/Src/GenPlugin.cpp b/Branches/MusicMod/Player/Src/GenPlugin.cpp new file mode 100644 index 0000000000..53b3d68448 --- /dev/null +++ b/Branches/MusicMod/Player/Src/GenPlugin.cpp @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "GenPlugin.h" +#include "Main.h" +#include "Unicode.h" +#include "Console.h" +#include + + + +vector gen_plugins; // extern + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +GenPlugin::GenPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) +{ + iHookerIndex = -1; + plugin = NULL; + + if( !Load() ) + { + return; + } + + gen_plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool GenPlugin::Load() +{ + if( IsLoaded() ) return true; + + // (1) Load DLL + hDLL = LoadLibrary( GetFullpath() ); + if( !hDLL ) return false; + + // (2) Find export + WINAMP_GEN_GETTER winampGetGeneralPurposePlugin = + ( WINAMP_GEN_GETTER )GetProcAddress( hDLL, "winampGetGeneralPurposePlugin" ); + if( winampGetGeneralPurposePlugin == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (3) Get module + plugin = winampGetGeneralPurposePlugin(); + if( !plugin ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (4) Process module + plugin->hDllInstance = hDLL; + plugin->hwndParent = WindowMain; + + // Note: Some plugins (mainly old ones) set description in init. + // Therefore we init first and copy the name after. + + + // (5) Init + if( plugin->init ) + { + const WNDPROC WndprocBefore = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + plugin->init(); + const WNDPROC WndprocAfter = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + + if( WndprocBefore != WndprocAfter ) + { + WndprocBackup = WndprocBefore; + iHookerIndex = iWndprocHookCounter++; + } + } + + + if( !szName ) + { + // Note: The prefix is not removed to hide their + // origin at Nullsoft! It just reads easier. + if( !strnicmp( plugin->description, "nullsoft ", 9 ) ) + { + plugin->description += 9; + } + + // Get rid of " (xxx.dll)" postfix + char * walk = plugin->description + strlen( plugin->description ) - 5; + while( true ) + { + if( ( walk <= plugin->description ) || strnicmp( walk, ".dll)", 5 ) ) break; + while( ( walk > plugin->description ) && ( *walk != '(' ) ) walk--; + if( walk <= plugin->description ) break; + walk--; + if( ( walk <= plugin->description ) || ( *walk != ' ' ) ) break; + *walk = '\0'; + } + + iNameLen = ( int )strlen( plugin->description ); + szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( szName, plugin->description, iNameLen ); + szName[ iNameLen ] = TEXT( '\0' ); + } + + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + + // Note: Plugins that use a wndproc hook need + // to be unloaded in the inverse loading order. + // This is due to the nature of wndproc hooking. + if( iHookerIndex != -1 ) + { + Console::Append( TEXT( "Wndproc hook added (by plugin)" ) ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool GenPlugin::Unload() +{ + if( !IsLoaded() ) return true; + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Unloading <%s>" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + + // Quit + if( plugin ) + { + if( plugin->quit ) plugin->quit(); + plugin = NULL; + } + + + // Remove wndproc hook + if( ( iHookerIndex != -1 ) && ( iHookerIndex == iWndprocHookCounter - 1 ) ) + { + // If we don't restore it the plugins wndproc will + // still be called which is not there anymore -> crash + SetWindowLong( WindowMain, GWL_WNDPROC, ( LONG )WndprocBackup ); + Console::Append( TEXT( "Wndproc hook removed (by host)" ) ); + Console::Append( TEXT( " " ) ); + + iHookerIndex = -1; + iWndprocHookCounter--; + } + + + FreeLibrary( hDLL ); + hDLL = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool GenPlugin::Config() +{ + if( !IsLoaded() ) return false; + if( !plugin ) return false; + if( !plugin->config ) return false; + + plugin->config(); + + return true; +} diff --git a/Branches/MusicMod/Player/Src/GenPlugin.h b/Branches/MusicMod/Player/Src/GenPlugin.h new file mode 100644 index 0000000000..b32f49536a --- /dev/null +++ b/Branches/MusicMod/Player/Src/GenPlugin.h @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_GEN_PLUGIN_H +#define PA_GEN_PLUGIN_H + + + +#include "Global.h" +#include "Plugin.h" +#include "Winamp/Gen.h" +#include + +using namespace std; + + + +typedef winampGeneralPurposePlugin * ( * WINAMP_GEN_GETTER )( void ); + + + +class GenPlugin; + +extern vector gen_plugins; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp general purpose plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class GenPlugin : public Plugin +{ +public: + GenPlugin( TCHAR * szDllpath, bool bKeepLoaded ); + + bool Load(); + bool Unload(); + + TCHAR * GetTypeString() { return TEXT( "General" ); } + int GetTypeStringLen() { return 7; } + PluginType GetType() { return PLUGIN_TYPE_GEN; } + + inline bool IsActive() { return IsLoaded(); } + + bool Config(); + + inline bool AllowRuntimeUnload() { return ( iHookerIndex == -1 ) || ( iHookerIndex == iWndprocHookCounter - 1 ); } + +private: + winampGeneralPurposePlugin * plugin; +}; + + + +#endif // PA_GEN_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/Global.h b/Branches/MusicMod/Player/Src/Global.h new file mode 100644 index 0000000000..5ac169e1f8 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Global.h @@ -0,0 +1,117 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_GLOBAL_H +#define PA_GLOBAL_H + + + +// #include "ide_devcpp/Plainamp_Private.h" + + + +#ifdef UNICODE +# define PA_UNICODE +#else +# ifdef _UNICODE +# define PA_UNICODE +# endif +#endif + + +// For GetLongPathName +#if _WIN32_WINDOWS < 0x0410 +# undef _WIN32_WINDOWS +# define _WIN32_WINDOWS 0x0410 +#endif + + +#define WIN32_LEAN_AND_MEAN + +/* +#ifndef WINVER +# define WINVER 0x0500 +#else +# if (WINVER < 0x0500) +# undef WINVER +# define WINVER 0x0500 +# endif +#endif +*/ + +#include +#include +#include + + + +#ifndef _WIN32_IE +# define _WIN32_IE 0x0400 +#else +# if (_WIN32_IE < 0x0400) +# undef _WIN32_IE +# define _WIN32_IE 0x0400 +# endif +#endif + +#include + + + + + +extern HINSTANCE g_hInstance; + +extern TCHAR * szHomeDir; +extern int iHomeDirLen; + +extern TCHAR * szPluginDir; +extern int iPluginDirLen; + + + +/* +inline int abs( int x ) +{ + return ( x < 0 ) ? -x : x; +} +*/ + +inline int MIN( int a, int b ) +{ + return ( a < b ) ? a : b; +} + +inline int MAX( int a, int b ) +{ + return ( a > b ) ? a : b; +} + + + + +// Typo help +#define UNIT UINT +#define UINT_PRT UINT_PTR + + + +struct TextCompare +{ + bool operator()( const TCHAR * a, const TCHAR * b ) const + { + return _tcscmp( a, b ) < 0; + } +}; + + +#endif // PA_GLOBAL_H diff --git a/Branches/MusicMod/Player/Src/GlobalVersion.h b/Branches/MusicMod/Player/Src/GlobalVersion.h new file mode 100644 index 0000000000..9b38065f34 --- /dev/null +++ b/Branches/MusicMod/Player/Src/GlobalVersion.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_GLOBAL_VERSION_H +#define PA_GLOBAL_VERSION_H + + + +#define FILE_DESCRIPTION "Plainamp" +#define VER_STRING "0.2.3.1" + + +#define PLAINAMP_TITLE TEXT( FILE_DESCRIPTION ) +#define PLAINAMP_VERSION TEXT( VER_STRING ) +#define PLAINAMP_LONG_TITLE PLAINAMP_TITLE TEXT( " " ) PLAINAMP_VERSION + + + +#endif // PA_GLOBAL_VERSION_H diff --git a/Branches/MusicMod/Player/Src/Input.cpp b/Branches/MusicMod/Player/Src/Input.cpp new file mode 100644 index 0000000000..35b42ea692 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Input.cpp @@ -0,0 +1,477 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Input.h" +#include "Console.h" +#include "Status.h" +#include "Playback.h" +#include "InputPlugin.h" +#include "VisPlugin.h" +#include "DspPlugin.h" +#include "VisCache.h" +#include "Output.h" + +/* +#define FIXED_POINT 16 +#include "kiss_fft/kiss_fftr.h" +*/ + +#include "fftw3/fftw3.h" +#include + + +// #define SKIPPY +#ifndef SKIPPY +# define MAX_DATA_FPS ( 1000 / 12 ) // in_mp3 gives new vis data every 13 ms, so 12 leaves a little space +#else +# define MAX_DATA_FPS ( 1000 / 24 ) // will skip every second frame +#endif + + +#ifdef SKIPPY +bool bLastSkipped = true; +#endif + +int iSpecChannels = 2; +int iWaveChannels = 2; + + +/* +kiss_fft_cfg kiss = { 0 }; +bool bKissInitDone = false; +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int dsp_isactive() +{ +//////////////////////////////////////////////////////////////////////////////// + DspLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + int res = ( active_dsp_count > 0 ); + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + return res; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int dsp_dosamples( short int * samples, int numsamples, int bps, int nch, int srate ) +{ + int num = numsamples; + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + for( int i = 0; i < active_dsp_count; i++ ) + { + // Process + num = active_dsp_mods[ i ]->mod->ModifySamples( + active_dsp_mods[ i ]->mod, + samples, + numsamples, + bps, + nch, + srate + ); + } + +//////////////////////////////////////////////////////////////////////////////// + DspLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + return num; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void SAVSAInit( int maxlatency_in_ms, int srate ) +{ +//////////////////////////////////////////////////////////////////////////////// + VisCache::Create(); + VisCache::EnsureLatency( maxlatency_in_ms ); + VisCache::EnsureDataFps( MAX_DATA_FPS ); + VisCache::Clean(); +//////////////////////////////////////////////////////////////////////////////// +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void SAVSADeInit() +{ + // TODO + // Console::Append( TEXT( "SAVSADeInit" ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void SAAddPCMData( void * PCMData, int nch, int bps, int timestamp ) +{ + // TODO + // Console::Append( TEXT( "SAAddPCMData" ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int SAGetMode() +{ + // TODO + // Console::Append( TEXT( "SAGetMode" ) ); + return 0; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void SAAdd( void * data, int timestamp, int csa ) +{ + // TODO + // Console::Append( TEXT( "SAAdd" ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VSAAddPCMData( void * PCMData, int nch, int bps, int timestamp ) +{ + // TODO + // Console::Append( TEXT( "VSAAddPCMData" ) ); + + + #ifdef SKIPPY + if( bLastSkipped ) + bLastSkipped = false; + else + { + // Skip + bLastSkipped = true; + return; + } + #endif + + +//////////////////////////////////////////////////////////////////////////////// + bool bVisLockLeft = false; + VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + if( active_vis_count ) + { +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); + bVisLockLeft = true; +//////////////////////////////////////////////////////////////////////////////// + + VisCache::NextFrame(); + VisCache::SetWriteTime( timestamp ); + VisCache::SetReadTime( active_input_plugin->plugin->GetOutputTime() ); + + short * source = ( short * )PCMData; + + // Waveform + static unsigned char wave_left[ 576 ]; + static unsigned char wave_right[ 576 ]; + if( nch < 2 ) + { + // Mono + for( int i = 0; i < 576; i++ ) + { + wave_left[ i ] = ( source[ i ] >> 8 ); + } + + VisCache::PutWaveLeft( wave_left ); + } + else + { + int i; + + // Stereo or more + for( i = 0; i < 576; i++ ) + { + wave_left [ i ] = ( source[ i * nch ] >> 8 ); + wave_right[ i ] = ( source[ i * nch + 1 ] >> 8 ); + } + + VisCache::PutWaveLeft( wave_left ); + VisCache::PutWaveRight( wave_right ); + } + + + // TODO: Much to optimize! + + + // Spectrum + static unsigned char spec_left[ 576 ]; + static unsigned char spec_right[ 576 ]; + static fftw_complex * in = NULL; + static fftw_complex * out = NULL; + + if( !in ) + { + in = ( fftw_complex * )fftw_malloc( 576 * sizeof( fftw_complex ) ); + out = ( fftw_complex * )fftw_malloc( 576 * sizeof( fftw_complex ) ); + } + + static const double factor = 1.0 / 65536.0 / sqrt( 2.0 ); + + + // Put left + int index = 0; + for( int i = 0; i < 576; i++ ) + { + in[ i ][ 0 ] = source[ index += nch ]; + in[ i ][ 1 ] = 0.0; + } + + + // Init FFT + fftw_plan p = fftw_plan_dft_1d( 576, in, out, FFTW_FORWARD, FFTW_ESTIMATE ); + + + // Run left + fftw_execute( p ); + + // Get left + for( int i = 0; i < 576; i++ ) + { + if( i & 1 ) + { + spec_left [ i ] = spec_left [ i - 1 ]; + continue; + } + const double re = out[ i >> 1 ][ 0 ]; + const double im = out[ i >> 1 ][ 1 ]; + const double root = sqrt( re*re + im*im ); + const double final = 160.0 * log10( 1.0 + root * factor ); + spec_left[ i ] = ( final < 255.0 ) ? ( unsigned char )final : 255; + } + VisCache::PutSpecLeft( spec_left ); + + + if( nch > 1 ) + { + // Put right + index = 1; + for( int i = 0; i < 576; i++ ) + { + in[ i ][ 0 ] = source[ index += nch ]; + } + + // Run right + fftw_execute( p ); + + // Get right + for( int i = 0; i < 576; i++ ) + { + if( i & 1 ) + { + spec_right[ i ] = spec_right[ i - 1 ]; + continue; + } + const double re = out[ i >> 1 ][ 0 ]; + const double im = out[ i >> 1 ][ 1 ]; + const double root = sqrt( re*re + im*im ); + const double final = 160.0 * log10( 1.0 + root * factor ); + spec_right[ i ] = ( final < 255.0 ) ? ( unsigned char )final : 255; + } + VisCache::PutSpecRight( spec_right ); + } + + + // Cleanup FFT + fftw_destroy_plan( p ); + + // fftw_free(in); + // fftw_free(out); + } + +//////////////////////////////////////////////////////////////////////////////// + if( bVisLockLeft ) VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + for( int i = 0; i < active_vis_count; i++ ) + { + active_vis_mods[ i ]->bAllowRender = true; + } + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int VSAGetMode( int * specNch, int * waveNch ) +{ + iSpecChannels = 0; + iWaveChannels = 0; + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + for( int i = 0; i < active_vis_count; i++ ) + { + const int iSpec = active_vis_mods[ i ]->mod->spectrumNch; + const int iWave = active_vis_mods[ i ]->mod->waveformNch; + + if( iSpec > iSpecChannels ) iSpecChannels = iSpec; + if( iWave > iWaveChannels ) iWaveChannels = iWave; + } + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + *specNch = iSpecChannels; + *waveNch = iWaveChannels; + + return 1; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VSAAdd( void * data, int timestamp ) +{ + #ifdef SKIPPY + if( bLastSkipped ) + bLastSkipped = false; + else + { + // Skip + bLastSkipped = true; + return; + } + #endif + + +//////////////////////////////////////////////////////////////////////////////// + bool bVisLockLeft = false; + VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + if( active_vis_count ) + { +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); + bVisLockLeft = true; +//////////////////////////////////////////////////////////////////////////////// + + VisCache::NextFrame(); + VisCache::SetWriteTime( timestamp ); + VisCache::SetReadTime( active_input_plugin->plugin->GetOutputTime() ); + + unsigned char * source = ( unsigned char * )data; + if( iSpecChannels > 0 ) + { + VisCache::PutSpecLeft( source ); + source += 576; + } + if( iSpecChannels > 1 ) + { + VisCache::PutSpecRight( source ); + source += 576; + } + if( iWaveChannels > 0 ) + { + VisCache::PutWaveLeft( source ); + source += 576; + } + if( iWaveChannels > 1 ) + { + VisCache::PutWaveRight( source ); + } + } + +//////////////////////////////////////////////////////////////////////////////// + if( bVisLockLeft ) VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + for( int i = 0; i < active_vis_count; i++ ) + { + active_vis_mods[ i ]->bAllowRender = true; + } + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VSASetInfo( int nch, int srate ) +{ + // TODO + +//////////////////////////////////////////////////////////////////////////////// + VisCache::Create(); + VisCache::EnsureDataFps( MAX_DATA_FPS ); + VisCache::Clean(); +//////////////////////////////////////////////////////////////////////////////// +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void SetInfo( int bitrate, int srate, int stereo, int synched ) +{ + // TODO + static int last_valid_srate = 0; + + if( bitrate < 0 ) return; + + if( srate < 0 ) + srate = last_valid_srate; + else + last_valid_srate = srate; + + TCHAR szBuffer[ 5000 ] = TEXT( "" ); + _stprintf( szBuffer, TEXT( " %i kbps, %i kHz" ), bitrate, srate ); + StatusUpdate( szBuffer ); +} diff --git a/Branches/MusicMod/Player/Src/Input.h b/Branches/MusicMod/Player/Src/Input.h new file mode 100644 index 0000000000..ff181474f6 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Input.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Global.h" + + + +int dsp_isactive(); +int dsp_dosamples( short int * samples, int numsamples, int bps, int nch, int srate ); +void SAVSAInit( int maxlatency_in_ms, int srate ); +void SAVSADeInit(); +void SAAddPCMData( void * PCMData, int nch, int bps, int timestamp ); +int SAGetMode(); +void SAAdd(void * data, int timestamp, int csa ); +void VSAAddPCMData( void * PCMData, int nch, int bps, int timestamp ); +int VSAGetMode( int * specNch, int * waveNch ); +void VSAAdd( void * data, int timestamp ); +void VSASetInfo( int nch, int srate ); +void SetInfo( int bitrate, int srate, int stereo, int synched ); diff --git a/Branches/MusicMod/Player/Src/InputPlugin.cpp b/Branches/MusicMod/Player/Src/InputPlugin.cpp new file mode 100644 index 0000000000..d6daa31cfe --- /dev/null +++ b/Branches/MusicMod/Player/Src/InputPlugin.cpp @@ -0,0 +1,374 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "InputPlugin.h" +#include "Console.h" +#include "Main.h" +#include "Input.h" +#include "Unicode.h" + + + +map ext_map; // extern +vector input_plugins; // extern +InputPlugin * active_input_plugin = NULL; // extern + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +InputPlugin::InputPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) +{ + iHookerIndex = -1; + + szFilters = NULL; + iFiltersLen = 0; + plugin = NULL; + + if( !Load() ) + { + return; + } + + if( !bKeepLoaded ) + { + Unload(); + } + + input_plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +InputPlugin::~InputPlugin() +{ + if( szFilters ) delete [] szFilters; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::Load() +{ + if( IsLoaded() ) return true; + + + // (1) Load DLL + hDLL = LoadLibrary( GetFullpath() ); + if( !hDLL ) return false; + + // (2) Find export + WINAMP_INPUT_GETTER winampGetInModule2 = + ( WINAMP_INPUT_GETTER )GetProcAddress( hDLL, "winampGetInModule2" ); + if( winampGetInModule2 == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (3) Get module + plugin = winampGetInModule2(); + if( plugin == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (4) Process module + plugin->hDllInstance = hDLL; + plugin->hMainWindow = WindowMain; + + plugin->SAVSAInit = SAVSAInit; + plugin->SAVSADeInit = SAVSADeInit; + plugin->SAAddPCMData = SAAddPCMData; + plugin->SAGetMode = SAGetMode; + plugin->SAAdd = SAAdd; + plugin->VSAAddPCMData = VSAAddPCMData; + plugin->VSAGetMode = VSAGetMode; + plugin->VSAAdd = VSAAdd; + plugin->VSASetInfo = VSASetInfo; + + plugin->dsp_dosamples = dsp_dosamples; + plugin->dsp_isactive = dsp_isactive; + + plugin->SetInfo = SetInfo; + + + if( !szName ) + { + // Note: The prefix is not removed to hide their + // origin at Nullsoft! It just reads easier. + if( !strnicmp( plugin->description, "nullsoft ", 9 ) ) + { + plugin->description += 9; + if( !strnicmp( plugin->description, "mpeg(layer1-3/ct aac+/dolby aac) ", 33 ) ) + { + plugin->description += ( 33 - 5 ); + memcpy( plugin->description, "MPEG", 4 * sizeof( char ) ); + } + } + iNameLen = ( int )strlen( plugin->description ); + szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( szName, plugin->description, iNameLen ); + szName[ iNameLen ] = TEXT( '\0' ); + } + + + + // (5) Init + const WNDPROC WndprocBefore = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + plugin->Init(); + const WNDPROC WndprocAfter = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + + if( WndprocBefore != WndprocAfter ) + { + WndprocBackup = WndprocBefore; + iHookerIndex = iWndprocHookCounter++; + } + + + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); + Console::Append( szBuffer ); + + + Integrate(); + + + // Note: Plugins that use a wndproc hook need + // to be unloaded in the inverse loading order. + // This is due to the nature of wndproc hooking. + if( iHookerIndex != -1 ) + { + Console::Append( TEXT( "Wndproc hook added (by plugin)" ) ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::Integrate() +{ + if( !IsLoaded() ) return false; + + // (6) Build filter + + // (6a) First pass: get needed buffer length + int needed = 0; + int len = 0; + bool even = false; + char * walk = plugin->FileExtensions; + while( ( len = ( int )strlen( walk ) ) > 0 ) + { + len++; // For '\0' + if( even ) + { + // Extensions e.g. "mp3;mp2;mp1" + // Worst case "a;b;c" (5) --> "*.a;*.b;*.c" (11) + needed += ( 3 * len ); + } + else + { + // Filter name e.g. "MPEG audio files" + needed += len; + } + even = !even; + walk += len; + } + szFilters = new TCHAR[ needed + 1 ]; + TCHAR * walk_out = szFilters; + + // (6b) Once again with copy + walk = plugin->FileExtensions; + even = false; + while( true ) + { + // Check extensions + char * start_filter = walk; + const int len_filter = ( int )strlen( walk ); + if( len_filter == 0 ) + { + // End reached + break; + } + walk += len_filter + 1; + + // Check filter name + char * start_display = walk; + int len_display = ( int )strlen( walk ); + if( len_display == 0 ) + { + break; + } + walk += ++len_display; + + // Append filter name + ToTchar( walk_out, start_display, len_display ); + TCHAR szBuffer[ 5000 ]; + *(walk_out + len_display) = TEXT( '\0' ); + _stprintf( szBuffer, TEXT( " %s" ), walk_out ); + Console::Append( szBuffer ); + walk_out += len_display; + + // Convert and append extensions + char * walk_filter = start_filter; + char * last_filter = start_filter; + int len; + while( true ) + { + if( ( *walk_filter == ';' ) || ( *walk_filter == '\0' ) ) + { + len = ( walk_filter - last_filter ); + if( len < 1 ) + { + break; + } + + // Add extension to map + TCHAR * szExt = new TCHAR[ len + 1 ]; + ToTchar( szExt, last_filter, len ); + szExt[ len ] = TEXT( '\0' ); + _tcslwr( szExt ); + + ext_map.insert( pair( szExt, this ) ); + + // Append extension as "*.ext[;\0]" + len++; // Also copy ';' and '\0' + memcpy( walk_out, TEXT( "*." ), 2 * sizeof( TCHAR ) ); + walk_out += 2; + ToTchar( walk_out, last_filter, len ); + walk_out += len; + + // Any more extensions? + if( *walk_filter == '\0' ) + { + break; + } + last_filter = walk_filter + 1; + } + walk_filter++; + } + + if( *walk == '\0' ) + { + *walk_out = TEXT( '\0' ); + iFiltersLen = walk_out - szFilters; + + break; + } + } + + Console::Append( TEXT( " " ) ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::DisIntegrate() +{ + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::Unload() +{ + if( !IsLoaded() ) return true; + + + DisIntegrate(); + + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Unloading <%s>" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + // Quit + if( plugin ) + { + if( plugin->Quit ) plugin->Quit(); + plugin->outMod = NULL; + plugin = NULL; + } + + // Remove wndproc hook + if( ( iHookerIndex != -1 ) && ( iHookerIndex == iWndprocHookCounter - 1 ) ) + { + // If we don't restore it the plugins wndproc will + // still be called which is not there anymore -> crash + SetWindowLong( WindowMain, GWL_WNDPROC, ( LONG )WndprocBackup ); + Console::Append( TEXT( "Wndproc hook removed (by host)" ) ); + Console::Append( TEXT( " " ) ); + + iHookerIndex = -1; + iWndprocHookCounter--; + } + + FreeLibrary( hDLL ); + hDLL = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::About( HWND hParent ) +{ + if( !plugin ) return false; + if( !plugin->About ) return false; + + plugin->About( hParent ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +bool InputPlugin::Config( HWND hParent ) +{ + if( !plugin ) return false; + if( !plugin->Config ) return false; + + plugin->Config( hParent ); + + // TODO: File extension could have changed (e.g. in_mp3) + // So we have to process ext_map here... + + return true; +} diff --git a/Branches/MusicMod/Player/Src/InputPlugin.h b/Branches/MusicMod/Player/Src/InputPlugin.h new file mode 100644 index 0000000000..83e93d511a --- /dev/null +++ b/Branches/MusicMod/Player/Src/InputPlugin.h @@ -0,0 +1,94 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_INPUT_PLUGIN_H +#define PA_INPUT_PLUGIN_H + + + +#include "Global.h" +#include "Plugin.h" +#include "Playback.h" +#include "Playlist.h" +#include "Winamp/In2.h" +#include +#include + +using namespace std; + + + +typedef In_Module * ( * WINAMP_INPUT_GETTER )( void ); + + + +class InputPlugin; + +extern map ext_map; +extern vector input_plugins; +extern InputPlugin * active_input_plugin; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp input plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class InputPlugin : public Plugin +{ +public: + InputPlugin( TCHAR * szDllpath, bool bKeepLoaded ); + ~InputPlugin(); + + bool Load(); + bool Unload(); + + TCHAR * GetTypeString() { return TEXT( "Input" ); } + int GetTypeStringLen() { return 5; } + PluginType GetType() { return PLUGIN_TYPE_INPUT; } + + inline bool IsActive() { return false; } + + bool About( HWND hParent ); + bool Config( HWND hParent ); + +private: + TCHAR * szFilters; + int iFiltersLen; + In_Module * plugin; + + bool Integrate(); + bool DisIntegrate(); + + + // TODO + friend bool OpenPlay( TCHAR * szFilename, int iNumber ); + friend bool Playback_PrevOrNext( bool bPrevOrNext ); + friend bool Playback::Play(); + friend bool Playback::Pause(); + friend bool Playback::Stop(); + friend bool Playback::UpdateSeek(); + friend int Playback::PercentToMs( float fPercent ); + friend bool Playback::SeekPercent( float fPercent ); + friend bool SeekRelative( int ms ); + friend void Playback_Volume_Set( int iVol ); + friend bool Playback::Pan::Set( int iPan ); + friend void Playback_Eq_Set( int iPresetIndex ); + + friend void AddFiles(); + friend void VSAAdd( void * data, int timestamp ); + friend void VSAAddPCMData( void * PCMData, int nch, int bps, int timestamp ); + friend int Playlist::GetTitle( int iIndex, char * szAnsiTitle, int iChars ); +}; + + + +#endif // PA_INPUT_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/Lock.cpp b/Branches/MusicMod/Player/Src/Lock.cpp new file mode 100644 index 0000000000..8590b944d0 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Lock.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +// #include "Lock.h" + + +// Code moved to for inlining! diff --git a/Branches/MusicMod/Player/Src/Lock.h b/Branches/MusicMod/Player/Src/Lock.h new file mode 100644 index 0000000000..113c93f50e --- /dev/null +++ b/Branches/MusicMod/Player/Src/Lock.h @@ -0,0 +1,111 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_LOCK_H +#define PA_LOCK_H + + + +#include "Global.h" + + + +// INFO: http://www.devarticles.com/c/a/Cplusplus/Multithreading-in-C/3/ + + +// #define LOCK_USES_MUTEX + + + +//////////////////////////////////////////////////////////////////////////////// +/// Lock for thread synchronization +//////////////////////////////////////////////////////////////////////////////// +class Lock +{ +public: + Lock( TCHAR * szName ); + ~Lock(); + + void Enter(); + void Leave(); + +private: +#ifndef LOCK_USES_MUTEX + CRITICAL_SECTION * m_pCrit; +#else + HANDLE hLock; +#endif +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Creates a new named lock. +/// Note: Don't use the same name for several locks +//////////////////////////////////////////////////////////////////////////////// +inline Lock::Lock( TCHAR * szName ) +{ +#ifndef LOCK_USES_MUTEX + m_pCrit = new CRITICAL_SECTION; + InitializeCriticalSection( m_pCrit ); +#else + hLock = CreateMutex( NULL, TRUE, szName ); + ReleaseMutex( hLock ); +#endif +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +inline Lock::~Lock() +{ +#ifndef LOCK_USES_MUTEX + DeleteCriticalSection( m_pCrit ); + delete [] m_pCrit; +#else + CloseHandle( hLock ); +#endif +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Closes lock. +//////////////////////////////////////////////////////////////////////////////// +inline void Lock::Enter() +{ +#ifndef LOCK_USES_MUTEX + EnterCriticalSection( m_pCrit ); +#else + WaitForSingleObject( hLock, INFINITE ); +#endif +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Opens lock. +//////////////////////////////////////////////////////////////////////////////// +inline void Lock::Leave() +{ +#ifndef LOCK_USES_MUTEX + LeaveCriticalSection( m_pCrit ); +#else + ReleaseMutex( hLock ); +#endif +} + + + +#endif // PA_LOCK_H diff --git a/Branches/MusicMod/Player/Src/Main.cpp b/Branches/MusicMod/Player/Src/Main.cpp new file mode 100644 index 0000000000..813bbeb359 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Main.cpp @@ -0,0 +1,757 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Main.h" +#include "GlobalVersion.h" +#include "Playlist.h" +#include "Console.h" +#include "Status.h" +#include "Rebar.h" +#include "Playback.h" +#include "PluginManager.h" +#include "DspModule.h" +#include "VisModule.h" +#include "InputPlugin.h" +#include "OutputPlugin.h" +#include "InputPlugin.h" +#include "AddDirectory.h" +#include "AddFiles.h" +#include "Winamp.h" +#include "Winamp/wa_ipc.h" +#include "Config.h" +#include + + +#define CLASSNAME_MAIN TEXT( "Winamp v1.x" ) +#define MAIN_TITLE PLAINAMP_LONG_TITLE + +#define MAIN_WIDTH 731 +#define MAIN_HEIGHT 562 + + + +HWND WindowMain = NULL; // extern +HMENU main_context_menu = NULL; // extern +HMENU play_context_menu = NULL; +HMENU opts_context_menu = NULL; +HMENU playback_context_menu = NULL; + + + +LRESULT CALLBACK WndprocMain( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +WINDOWPLACEMENT WinPlaceMain; + +void WinPlaceMainCallback( ConfVar * var ) +{ + if( !IsWindow( WindowMain ) ) return; + GetWindowPlacement( WindowMain, &WinPlaceMain ); +} + +const int cxScreen = GetSystemMetrics( SM_CXFULLSCREEN ); +const int cyScreen = GetSystemMetrics( SM_CYFULLSCREEN ); + +RECT rMainDefault = { + ( cxScreen - MAIN_WIDTH ) / 2, + ( cyScreen - MAIN_HEIGHT ) / 2, + ( cxScreen - MAIN_WIDTH ) / 2 + MAIN_WIDTH, + ( cyScreen - MAIN_HEIGHT ) / 2 + MAIN_HEIGHT +}; + +ConfWinPlaceCallback cwpcWinPlaceMain( + &WinPlaceMain, + TEXT( "WinPlaceMain" ), + &rMainDefault, + WinPlaceMainCallback +); + + +bool bMinimizeToTray; +ConfBool cbMinimizeToTray( &bMinimizeToTray, TEXT( "MinimizeToTray" ), CONF_MODE_PUBLIC, true ); + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool BuildMainWindow() +{ + // Register class + WNDCLASS wc = { + 0, // UINT style + WndprocMain, // WNDPROC lpfnWndProc + 0, // int cbClsExtra + 0, // int cbWndExtra + g_hInstance, // HINSTANCE hInstance + LoadIcon( g_hInstance, TEXT( "IDI_ICON1" ) ), // HICON hIcon + LoadCursor( NULL, IDC_ARROW ), // HCURSOR hCursor + ( HBRUSH )COLOR_WINDOW, // HBRUSH hbrBackground + NULL, // LPCTSTR lpszMenuName + CLASSNAME_MAIN // LPCTSTR lpszClassName + }; + + if( !RegisterClass( &wc ) ) return false; + + // Create window + WindowMain = CreateWindowEx( + WS_EX_WINDOWEDGE, // DWORD dwExStyle + CLASSNAME_MAIN, // LPCTSTR lpClassName + MAIN_TITLE, // LPCTSTR lpWindowName + WS_OVERLAPPED | // DWORD dwStyle +// WS_VISIBLE | // + WS_CLIPCHILDREN | // + WS_BORDER | // + WS_SYSMENU | // + WS_THICKFRAME | // + WS_MINIMIZEBOX | // + WS_MAXIMIZEBOX, // + rMainDefault.left, // int x + rMainDefault.top, // int y + rMainDefault.right - rMainDefault.left, // int nWidth + rMainDefault.bottom - rMainDefault.top, // int nHeight + NULL, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + + if( !WindowMain ) + { + UnregisterClass( CLASSNAME_MAIN, g_hInstance ); + return false; + } + + + + + // Build context menu + HMENU main_menu = CreateMenu(); + HMENU plainamp_menu = CreatePopupMenu(); + HMENU playback_menu = CreatePopupMenu(); + HMENU playlist_menu = CreatePopupMenu(); + HMENU windows_menu = CreatePopupMenu(); + + // Plainamp + AppendMenu( plainamp_menu, MF_STRING, WINAMP_OPTIONS_PREFS, TEXT( "Preferences \tCtrl+P" ) ); + AppendMenu( plainamp_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + AppendMenu( plainamp_menu, MF_STRING, WINAMP_HELP_ABOUT, TEXT( "&About\tCtrl+F1" ) ); + AppendMenu( plainamp_menu, MF_STRING, WINAMP_FILE_QUIT, TEXT( "&Exit \tAlt+F4" ) ); + + // Playback + AppendMenu( playback_menu, MF_STRING, WINAMP_BUTTON1, TEXT( "Pre&vious \tZ" ) ); + AppendMenu( playback_menu, MF_STRING, WINAMP_BUTTON2, TEXT( "&Play\tX" ) ); + AppendMenu( playback_menu, MF_STRING, WINAMP_BUTTON3, TEXT( "P&ause\tC" ) ); + AppendMenu( playback_menu, MF_STRING, WINAMP_BUTTON4, TEXT( "&Stop\tV" ) ); + AppendMenu( playback_menu, MF_STRING, WINAMP_BUTTON5, TEXT( "&Next\tB" ) ); + + // Playlist + AppendMenu( playlist_menu, MF_STRING, ID_PE_OPEN, TEXT( "&Open\tCtrl+O" ) ); + AppendMenu( playlist_menu, MF_STRING, ID_PE_SAVEAS, TEXT( "&Save as\tCtrl+S" ) ); + AppendMenu( playlist_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + AppendMenu( playlist_menu, MF_STRING, WINAMP_FILE_PLAY, TEXT( "Add &files\tL" ) ); + AppendMenu( playlist_menu, MF_STRING, WINAMP_FILE_DIR, TEXT( "Add &directory\tShift+L" ) ); + AppendMenu( playlist_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + AppendMenu( playlist_menu, MF_STRING, PLAINAMP_PL_REM_SEL, TEXT( "Remove selected\tDel" ) ); + AppendMenu( playlist_menu, MF_STRING, PLAINAMP_PL_REM_CROP, TEXT( "Remove unselected \tCtrl+Del" ) ); + AppendMenu( playlist_menu, MF_STRING, ID_PE_CLEAR, TEXT( "Remove all\tCtrl+Shift+Del" ) ); + AppendMenu( playlist_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + AppendMenu( playlist_menu, MF_STRING, ID_PE_SELECTALL, TEXT( "Select &all\tCtrl+A" ) ); + AppendMenu( playlist_menu, MF_STRING, ID_PE_NONE, TEXT( "Select &zero\tCtrl+Shift+A" ) ); + AppendMenu( playlist_menu, MF_STRING, ID_PE_INVERT, TEXT( "Select &invert\tCtrl+I" ) ); + + // Windows + AppendMenu( windows_menu, MF_STRING, MENU_MAIN_WINDOWS_CONSOLE, TEXT( "&Console" ) ); + AppendMenu( windows_menu, MF_STRING, MENU_MAIN_WINDOWS_MANAGER, TEXT( "Plugin &Manager" ) ); + + // Main + AppendMenu( main_menu, MF_STRING | MF_POPUP, ( UINT_PTR )plainamp_menu, TEXT( "&Plainamp" ) ); + AppendMenu( main_menu, MF_STRING | MF_POPUP, ( UINT_PTR )playback_menu, TEXT( "Play&back" ) ); + AppendMenu( main_menu, MF_STRING | MF_POPUP, ( UINT_PTR )playlist_menu, TEXT( "Play&list" ) ); + AppendMenu( main_menu, MF_STRING | MF_POPUP, ( UINT_PTR )windows_menu, TEXT( "&Windows" ) ); + + SetMenu( WindowMain, main_menu ); + +//////////////////////////////////////////////////////////////////////////////// + + main_context_menu = CreatePopupMenu(); + AppendMenu( main_context_menu, MF_STRING, WINAMP_HELP_ABOUT, TEXT( "Plainamp" ) ); + + AppendMenu( main_context_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + + play_context_menu = CreatePopupMenu(); + AppendMenu( play_context_menu, MF_STRING, WINAMP_FILE_PLAY, TEXT( "Files \tL" ) ); + AppendMenu( play_context_menu, MF_STRING, WINAMP_FILE_DIR, TEXT( "Folder \tShift+L" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_POPUP, ( UINT_PTR )play_context_menu, TEXT( "Play" ) ); + + AppendMenu( main_context_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED | MF_CHECKED, WINAMP_MAIN_WINDOW, TEXT( "Main Window\tAlt+W" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED | MF_CHECKED, WINAMP_OPTIONS_PLEDIT, TEXT( "Playlist Editor\tAlt+E" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED, WINAMP_OPTIONS_EQ, TEXT( "Equalizer\tAlt+G" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED, WINAMP_OPTIONS_VIDEO, TEXT( "Video\tAlt+V" ) ); + AppendMenu( main_context_menu, MF_STRING, PLAINAMP_TOGGLE_CONSOLE, TEXT( "Console" ) ); + AppendMenu( main_context_menu, MF_STRING, PLAINAMP_TOGGLE_MANAGER, TEXT( "Plugin Manager" ) ); + + +/* + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED, MENU_MAIN_CONTEXT_MANAGER, TEXT( "Plugin Manager" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_DISABLED | MF_GRAYED, MENU_MAIN_CONTEXT_CONSOLE, TEXT( "Console" ) ); +*/ + AppendMenu( main_context_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + + opts_context_menu = CreatePopupMenu(); + AppendMenu( opts_context_menu, MF_STRING, WINAMP_OPTIONS_PREFS, TEXT( "Preferences \tCtrl+P" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_POPUP, ( UINT_PTR )opts_context_menu, TEXT( "Options" ) ); + + playback_context_menu = CreatePopupMenu(); + AppendMenu( playback_context_menu, MF_STRING, WINAMP_BUTTON1, TEXT( "Previous \tZ" ) ); + AppendMenu( playback_context_menu, MF_STRING, WINAMP_BUTTON2, TEXT( "Play\tX" ) ); + AppendMenu( playback_context_menu, MF_STRING, WINAMP_BUTTON3, TEXT( "Pause\tC" ) ); + AppendMenu( playback_context_menu, MF_STRING, WINAMP_BUTTON4, TEXT( "Stop\tV" ) ); + AppendMenu( playback_context_menu, MF_STRING, WINAMP_BUTTON5, TEXT( "Next\tB" ) ); + AppendMenu( main_context_menu, MF_STRING | MF_POPUP, ( UINT_PTR )playback_context_menu, TEXT( "Playback" ) ); + + AppendMenu( main_context_menu, MF_SEPARATOR | MF_DISABLED | MF_GRAYED, ( UINT_PTR )-1, NULL ); + + AppendMenu( main_context_menu, MF_STRING, WINAMP_FILE_QUIT, TEXT( "Exit" ) ); + + + Toolbar::Create(); + BuildMainStatus(); + Playlist::Create(); + + + SetWindowPlacement( WindowMain, &WinPlaceMain ); + + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void About( HWND hParent ) +{ + // For info goto + // http://predef.sourceforge.net/precomp.html + + TCHAR szBuildDetails[ 1000 ] = ""; + +#ifdef __GNUC__ + _stprintf( szBuildDetails, + TEXT( "\n\n\nGNU GCC " __VERSION__ "\n" __DATE__ ) + ); +#else +# ifdef _MSC_VER + _stprintf( + szBuildDetails, + TEXT( "\n\n\nMicrosoft Visual C++ %i.%i\n" __DATE__ ), + _MSC_VER / 100 - 6, + ( _MSC_VER % 100 ) / 10 + ); +# endif +#endif + + TCHAR szBuffer[ 1000 ]; + _stprintf( + szBuffer, + PLAINAMP_LONG_TITLE TEXT( "\n" + "\n" + "Copyright © 2005 Sebastian Pipping \n" + "\n" + "\n" + "--> http://www.hartwork.org" + "%s" + ), + szBuildDetails + ); + + MessageBox( + hParent, + szBuffer, + TEXT( "About" ), + MB_ICONINFORMATION + ); +} + +#define TRAY_MAIN_ID 13 +#define TRAY_MSG ( WM_USER + 1 ) + + + +NOTIFYICONDATA nid; + +bool AddTrayIcon( HWND hwnd ) +{ + ZeroMemory( &nid, sizeof( NOTIFYICONDATA ) ); + nid.cbSize = sizeof( NOTIFYICONDATA ); + nid.hWnd = hwnd; + nid.uID = TRAY_MAIN_ID; + nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage = TRAY_MSG; + nid.hIcon = LoadIcon( g_hInstance, TEXT( "IDI_ICON1" ) ); + _tcscpy( nid.szTip, TEXT( "Plainamp" ) ); + + return ( Shell_NotifyIcon( NIM_ADD, &nid ) != 0 ); +} + +void RemoveTrayIcon() +{ + Shell_NotifyIcon( NIM_DELETE, &nid ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocMain( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + // Tool windows are hidden on minimize/re-shown on restore + static bool bConsoleTodo = false; + static bool bManagerTodo = false; + + static bool bRemoveIcon = false; + + switch( message ) + { + case WM_SETFOCUS: + // To re-"blue" + SetFocus( WindowPlaylist ); + break; + + case WM_CREATE: + // Note: [WindowMain] is not valid yet but [hwnd] is! + Console::Create(); + PluginManager::Build(); + break; + + case WM_NOTIFY: + { + NMHDR * hdr = ( NMHDR * )lp; + + switch( hdr->code ) + { + case LVN_GETDISPINFO: + { + LV_DISPINFO * lpdi = ( LV_DISPINFO * )lp; + playlist->Fill( lpdi->item ); + } + return 0; +/* + case LVN_ODCACHEHINT: + { + LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam; + / + This sample doesn't use this notification, but this is sent when the + ListView is about to ask for a range of items. On this notification, + you should load the specified items into your local cache. It is still + possible to get an LVN_GETDISPINFO for an item that has not been cached, + therefore, your application must take into account the chance of this + occurring. + / + } + return 0; + + case LVN_ODFINDITEM: + { + LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam; + / + This sample doesn't use this notification, but this is sent when the + ListView needs a particular item. Return -1 if the item is not found. + / + } + return 0; +*/ + case NM_CUSTOMDRAW: + { + NMLVCUSTOMDRAW * custom = ( NMLVCUSTOMDRAW * )lp; + + switch( custom->nmcd.dwDrawStage ) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + return CDRF_NOTIFYSUBITEMDRAW; + + case ( CDDS_SUBITEM | CDDS_ITEMPREPAINT ): + { + // This is the prepaint stage for an item. Here's where we set the + // item's text color. Our return value will tell Windows to draw the + // item itself, but it will use the new color we set here. + // We'll cycle the colors through red, green, and light blue. + + if( custom->nmcd.dwItemSpec == playlist->GetCurIndex() ) + { + custom->clrTextBk = RGB( 225, 225, 225 ); + } + else + { + if( custom->nmcd.dwItemSpec & 1 ) + custom->clrTextBk = RGB( 245, 248, 250 ); + else + custom->clrTextBk = RGB( 255, 255, 255 ); + } + + if( custom->iSubItem == 0 ) + custom->clrText = RGB( 255, 0, 0 ); + else + custom->clrText = RGB( 0, 0, 0 ); + + +/* + if ( (custom->nmcd.dwItemSpec % 3) == 0 ) + crText = RGB(255,0,0); + else if ( (custom->nmcd.dwItemSpec % 3) == 1 ) + crText = RGB(0,255,0); + else + crText = RGB(128,128,255); + + // Store the color back in the NMLVCUSTOMDRAW struct. + custom->clrText = crText; +*/ + // Tell Windows to paint the control itself. + } + /* + custom->clrText = RGB( 190, 190, 190 ); + custom->clrTextBk = RGB( 255, 0, 0 );*/ + return CDRF_DODEFAULT; + + + } + break; + + } + + /* + case RBN_CHILDSIZE: + { + NMREBARCHILDSIZE * chs = ( NMREBARCHILDSIZE * )lp; + const int width_client = chs->rcChild.right - chs->rcChild.left; + int diff = width_client - 120; + if( diff > 0 ) + { + const int width_band = chs->rcBand.right - chs->rcBand.left; + // chs->rcChild.right = chs->rcChild.left + 120; + + DEBUGF( 1000, "CHILDSIZE [%i] [%i]", chs->uBand, width_band ); + + const int client_band_diff = width_band - width_client; + chs->rcBand.right = chs->rcBand.left + 120 + client_band_diff; + // chs->uBand + + + REBARBANDINFO rbbi; + rbbi.cbSize = sizeof( REBARBANDINFO ); + rbbi.fMask = RBBIM_SIZE; + rbbi.cx = 154; //width_band + diff; + LRESULT lResult = SendMessage( + rebar, + RB_SETBANDINFO, + chs->uBand, + ( LPARAM )( REBARBANDINFO * )&rbbi + ); + + } + break; + } + */ + case RBN_HEIGHTCHANGE: + { + const int iRebarHeightBefore = iRebarHeight; + RECT r; + GetWindowRect( WindowRebar, &r ); + iRebarHeight = r.bottom - r.top; + + InvalidateRect( WindowRebar, NULL, TRUE ); + InvalidateRect( WindowPlaylist, NULL, TRUE ); + + RECT client; + GetClientRect( WindowMain, &client ); + PostMessage( + hwnd, + WM_SIZE, + SIZE_RESTORED, + ( client.right - client.left ) << 16 | + ( client.bottom - client.top ) + ); + + break; + } + } + break; + } + + case WM_SYSKEYDOWN: + switch( wp ) // [Alt]+[...] + { + case VK_UP: + case VK_DOWN: + SetFocus( WindowPlaylist ); + SendMessage( WindowPlaylist, message, wp, lp ); + break; + } + break; + + case WM_KEYDOWN: + case WM_KEYUP: + SetFocus( WindowPlaylist ); + SendMessage( WindowPlaylist, message, wp, lp ); + break; + + case WM_COMMAND: + { + const int code = HIWORD( wp ); + switch( code ) + { + case 1: // also == CBN_SELCHANGE + { + if( ( HWND )lp == WindowOrder ) + { + LRESULT res = SendMessage( WindowOrder, CB_GETCURSEL, 0, 0 ); + if( res == CB_ERR ) break; + Playback::Order::SetMode( ( int )res ); + } + else if( ( HWND )lp == WindowEq ) + { + LRESULT res = SendMessage( WindowEq, CB_GETCURSEL, 0, 0 ); + if( res == CB_ERR ) break; + Playback::Eq::SetIndex( ( int )( res - 1 ) ); + } + + return WndprocWinamp( hwnd, message, wp, lp ); + } + + case 0: + { + // Menu + const int id = LOWORD( wp ); + switch( id ) + { + case MENU_MAIN_WINDOWS_CONSOLE: + Console::Popup(); + break; + + case MENU_MAIN_WINDOWS_MANAGER: + PluginManager::Popup(); + break; + + } +/* + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "default 1 id = <%i>" ), id ); + MessageBox( 0, szBuffer, "", 0 ); +*/ + return WndprocWinamp( hwnd, message, wp, lp ); + } + + default: + return WndprocWinamp( hwnd, message, wp, lp ); + } + break; + } + + case WM_GETMINMAXINFO: + { + MINMAXINFO * mmi = ( MINMAXINFO * )lp; + mmi->ptMinTrackSize.x = 400; + mmi->ptMinTrackSize.y = 300; + return 0; + } + + case WM_SIZE: + { + // Resize children + RECT client; + GetClientRect( WindowMain, &client ); + + const int iClientWidth = client.right - client.left; + const int iClientHeight = client.bottom - client.top; + const int iPlaylistHeight = iClientHeight - iRebarHeight - iStatusHeight; + + if( WindowRebar ) + MoveWindow( WindowRebar, 0, 0, iClientWidth, iRebarHeight, TRUE ); + if( WindowPlaylist ) + { + MoveWindow( WindowPlaylist, 0, iRebarHeight, iClientWidth, iPlaylistHeight, TRUE ); + playlist->Resize( WindowMain ); + } + if( WindowStatus ) + MoveWindow( WindowStatus, 0, iRebarHeight + iPlaylistHeight, iClientWidth, iStatusHeight, TRUE ); + break; + } + + case WM_TIMER: + Playback::UpdateSeek(); + break; + + case WM_CONTEXTMENU: + PostMessage( hwnd, WM_COMMAND, WINAMP_MAINMENU, 0 ); + break; + + case WM_CLOSE: + { + // Clean shutdown + + // Stop + Playback::Stop(); + + // Dsp + DspLock.Enter(); + for( int d = active_dsp_count - 1; d >= 0; d-- ) + { + DspLock.Leave(); + active_dsp_mods[ d ]->Stop(); + DspLock.Enter(); + } + DspLock.Leave(); + + + // Vis + VisLock.Enter(); + for( int v = active_vis_count - 1; v >= 0; v-- ) + { + VisLock.Leave(); + active_vis_mods[ v ]->Stop(); + VisLock.Enter(); + } + VisLock.Leave(); + } + break; + + case WM_DESTROY: + { + // Save playlist + TCHAR * szPlaylistMind = new TCHAR[ iHomeDirLen + 12 + 1 ]; + memcpy( szPlaylistMind, szHomeDir, iHomeDirLen * sizeof( TCHAR ) ); + memcpy( szPlaylistMind + iHomeDirLen, TEXT( "Plainamp.m3u" ), 12 * sizeof( TCHAR ) ); + szPlaylistMind[ iHomeDirLen + 12 ] = TEXT( '\0' ); + + Playlist::ExportPlaylistFile( szPlaylistMind ); + + delete [] szPlaylistMind; + + + cwpcWinPlaceMain.TriggerCallback(); + cwpcWinPlaceMain.RemoveCallback(); + + Console::Destroy(); + PluginManager::Destroy(); + + if( bRemoveIcon ) + { + RemoveTrayIcon(); + bRemoveIcon = false; + } + + PostQuitMessage( 0 ); + return 0; + } + + case WM_ACTIVATEAPP: + { + if( wp != TRUE ) break; + + // Also bring console/manager to front + const bool bConsoleVisible = ( IsWindowVisible( WindowConsole ) == TRUE ); + const bool bManagerVisible = ( IsWindowVisible( WindowManager ) == TRUE ); + const bool bMainTodo = ( bConsoleVisible || bManagerVisible ); + + if( bConsoleVisible ) BringWindowToTop( WindowConsole ); + if( bManagerVisible ) BringWindowToTop( WindowManager ); + if( bMainTodo ) BringWindowToTop( WindowMain ); + + break; + } + + case WM_SYSCOMMAND: + switch( ( wp & 0xFFF0 ) ) + { + case SC_CLOSE: + if( !SendMessage( WindowMain, WM_WA_IPC, 0, IPC_HOOK_OKTOQUIT ) ) + { + return 0; + } + break; + + case SC_MINIMIZE: + { + // Hide console/manager on minimize + bConsoleTodo = ( IsWindowVisible( WindowConsole ) == TRUE ); + if( bConsoleTodo ) ShowWindow( WindowConsole, SW_HIDE ); + + bManagerTodo = ( IsWindowVisible( WindowManager ) == TRUE ); + if( bManagerTodo ) ShowWindow( WindowManager, SW_HIDE ); + + if( bMinimizeToTray ) + { + if( !bRemoveIcon ) + { + bRemoveIcon = AddTrayIcon( hwnd ); + } + + ShowWindow( hwnd, FALSE ); + return 0; + } + + break; + } + + case SC_RESTORE: + { + const LRESULT res = DefWindowProc( hwnd, message, wp, lp ); + + // Unhide console/manager + const bool bMainTodo = ( bConsoleTodo || bManagerTodo ); + if( bConsoleTodo ) ShowWindow( WindowConsole, SW_SHOW ); + if( bManagerTodo ) ShowWindow( WindowManager, SW_SHOW ); + if( bMainTodo ) BringWindowToTop( WindowMain ); + + return res; + } + } + break; + + case TRAY_MSG: + switch( lp ) + { + case WM_RBUTTONDOWN: // TODO: context menu instead + case WM_LBUTTONDOWN: + if( IsWindowVisible( hwnd ) == FALSE ) + { + ShowWindow( hwnd, TRUE ); + } + break; + + case WM_RBUTTONUP: // TODO: context menu instead + case WM_LBUTTONUP: + if( bRemoveIcon ) + { + RemoveTrayIcon(); + bRemoveIcon = false; + } + break; + + } + return 0; + + default: + return WndprocWinamp( hwnd, message, wp, lp ); + } + return DefWindowProc( hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/Main.h b/Branches/MusicMod/Player/Src/Main.h new file mode 100644 index 0000000000..68fb4bbdee --- /dev/null +++ b/Branches/MusicMod/Player/Src/Main.h @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_MAIN_H +#define PA_MAIN_H + + + +#include "Global.h" +#include "Winamp/wa_msgids.h" + + + +// TODO + + + +#define MENU_MAIN_WINDOWS_CONSOLE 41 +#define MENU_MAIN_WINDOWS_MANAGER 42 + +#define MENU_MAIN_CONTEXT_MANAGER WINAMP_MAIN_WINDOW // first window, for gen_dl +#define MENU_MAIN_CONTEXT_CONSOLE WINAMP_OPTIONS_VIDEO // last window, for gen_template + + +#define PLAINAMP_TOGGLE_CONSOLE 50001 +#define PLAINAMP_TOGGLE_MANAGER 50002 + + + + +extern HWND WindowMain; +extern HMENU main_context_menu; + + + +bool BuildMainWindow(); +void About( HWND hParent ); +LRESULT CALLBACK WndprocMain( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +#endif // PA_MAIN_H diff --git a/Branches/MusicMod/Player/Src/Output.cpp b/Branches/MusicMod/Player/Src/Output.cpp new file mode 100644 index 0000000000..d640c0e80d --- /dev/null +++ b/Branches/MusicMod/Player/Src/Output.cpp @@ -0,0 +1,367 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Output.h" +#include "OutputPlugin.h" +#include "Console.h" +#include + + + +int iNullSampleRate; +int iNullSumBytesPerSample; +int iNullWrittenMillis; +bool bNullPlaying; +int bNullPaused; +DWORD dwNullOpenTimestamp; +DWORD dwNullPauseTimestamp; + +const int NULL_DEFAULT_LATENCY = 1000; + + +int Output_Open( int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms ); +void Output_Close(); +int Output_Write( char * buf, int len ); +int Output_CanWrite(); +int Output_IsPlaying(); +int Output_Pause( int pause ); +void Output_SetVolume( int volume ); +void Output_SetPan( int pan ); +void Output_Flush( int t ); +int Output_GetOutputTime(); +int Output_GetWrittenTime(); + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +Out_Module output_server = { + OUT_VER, // int version + "Plainamp Output Server", // char * description; + 0x7fffffff, // int id + NULL, // HWND hMainWindow + NULL, // HINSTANCE hDllInstance + NULL, // void (*Config)(HWND hwndParent); + NULL, // void (*About)(HWND hwndParent); + NULL, // void (*Init)(); + NULL, // void (*Quit)(); + Output_Open, // int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); + Output_Close, // void (*Close)(); + Output_Write, // int (*Write)(char *buf, int len); + Output_CanWrite, // int (*CanWrite)(); + Output_IsPlaying, // int (*IsPlaying)(); + Output_Pause, // int (*Pause)(int pause); + Output_SetVolume, // void (*SetVolume)(int volume); + Output_SetPan, // void (*SetPan)(int pan); + Output_Flush, // void (*Flush)(int t); + Output_GetOutputTime, // int (*GetOutputTime)(); + Output_GetWrittenTime, // int (*GetWrittenTime)(); +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Output_Open( int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms ) +{ + if( active_output_count > 0 ) + { + // Maximum + int res = 0; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->Open( samplerate, numchannels, bitspersamp, bufferlenms, prebufferms ); + if( res_temp > res ) res = res_temp; + } + return res; + } + else + { + iNullSampleRate = samplerate; + iNullSumBytesPerSample = numchannels * ( bitspersamp / 8 ); + iNullWrittenMillis = 0; + bNullPlaying = false; + bNullPaused = 0; + dwNullOpenTimestamp = GetTickCount(); + + return NULL_DEFAULT_LATENCY; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Output_Close() +{ + if( active_output_count > 0 ) + { + for( int i = 0; i < active_output_count; i++ ) + { + active_output_plugins[ i ]->plugin->Close(); + } + } + else + { + bNullPlaying = false; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Output_Write( char * buf, int len ) +{ + if( active_output_count > 0 ) + { + // Maximum + int res = 0; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->Write( buf, len ); + if( res_temp > res ) res = res_temp; + } + return res; + } + else + { + if( iNullWrittenMillis == 0 ) + { + dwNullOpenTimestamp = GetTickCount(); + bNullPlaying = true; + } + + iNullWrittenMillis += ( len / iNullSumBytesPerSample ) * 1000 / iNullSampleRate; + return 0; // 0 == Success + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Output_CanWrite() +{ + if( active_output_count > 0 ) + { + // Minimum + int res = 0x7fffffff; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->CanWrite(); + if( res_temp < res ) res = res_temp; + } + return res; + } + else + { + const int diff = Output_GetWrittenTime() - Output_GetOutputTime(); + if( diff >= NULL_DEFAULT_LATENCY ) + { + return 0; + } + else + { + return ( NULL_DEFAULT_LATENCY - diff ) * iNullSumBytesPerSample * iNullSampleRate / 1000; + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Output_IsPlaying() +{ + if( active_output_count > 0 ) + { + // Maximum + int res = 0; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->IsPlaying(); + if( res_temp > res ) res = res_temp; + } + return res; + } + else + { + return ( Output_GetOutputTime() < Output_GetWrittenTime() ) ? 1 : 0; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Output_Pause( int pause ) +{ + if( active_output_count > 0 ) + { + // Maximum + int res = 0; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->Pause( pause ); + if( res_temp > res ) res = res_temp; + } + return res; + } + else + { + int res = bNullPaused; + if( pause && !bNullPaused ) + { + // Playback should be paused + dwNullPauseTimestamp = GetTickCount(); + bNullPaused = 1; + } + else if( !pause && bNullPaused ) + { + // Playback should be continued + // Add the gap length to the open timestamp like no gap exists + dwNullOpenTimestamp += ( GetTickCount() - dwNullPauseTimestamp ); + bNullPaused = 0; + } + return res; // Previous state + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Output_SetVolume( int volume ) +{ + for( int i = 0; i < active_output_count; i++ ) + { + active_output_plugins[ i ]->plugin->SetVolume( volume ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Output_SetPan( int pan ) +{ + for( int i = 0; i < active_output_count; i++ ) + { + active_output_plugins[ i ]->plugin->SetPan( pan ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Output_Flush( int t ) +{ + if( active_output_count > 0 ) + { + for( int i = 0; i < active_output_count; i++ ) + { + active_output_plugins[ i ]->plugin->Flush( t ); + } + } + else + { + dwNullOpenTimestamp = GetTickCount() - t; + iNullWrittenMillis = t; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Returns the number of milliseconds the song would be at +/// if we had zero latency. This value is never bigger than +/// the one returned by Output_GetWrittenTime(). +//////////////////////////////////////////////////////////////////////////////// +int Output_GetOutputTime() // <= GetWrittenTime() +{ + if( active_output_count > 0 ) + { + // Minimum + int res = 0x7fffffff; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->GetOutputTime(); + if( res_temp < res ) res = res_temp; + } + return res; + } + else + { + if( bNullPlaying ) + { + int res; + if( bNullPaused ) + { + res = dwNullPauseTimestamp - dwNullOpenTimestamp; + } + else + { + res = GetTickCount() - dwNullOpenTimestamp; + } + return MIN( res, iNullWrittenMillis ); + } + else + { + return 0; + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Returns the number of milliseconds already written. +/// Due to latency this value is always bigger than +/// the value returned by Output_GetOutputTime(). +//////////////////////////////////////////////////////////////////////////////// +int Output_GetWrittenTime() +{ + if( active_output_count > 0 ) + { + // Maximum + int res = 0; + int res_temp; + for( int i = 0; i < active_output_count; i++ ) + { + res_temp = active_output_plugins[ i ]->plugin->GetWrittenTime(); + if( res_temp > res ) res = res_temp; + } + return res; + } + else + { + return iNullWrittenMillis; + } +} diff --git a/Branches/MusicMod/Player/Src/Output.h b/Branches/MusicMod/Player/Src/Output.h new file mode 100644 index 0000000000..f12803a873 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Output.h @@ -0,0 +1,27 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_OUTPUT_H +#define PA_OUTPUT_H + + + +#include "Global.h" +#include "Winamp/Out.h" + + + +extern Out_Module output_server; + + + +#endif // PA_OUTPUT_H diff --git a/Branches/MusicMod/Player/Src/OutputPlugin.cpp b/Branches/MusicMod/Player/Src/OutputPlugin.cpp new file mode 100644 index 0000000000..b58ce2b1a3 --- /dev/null +++ b/Branches/MusicMod/Player/Src/OutputPlugin.cpp @@ -0,0 +1,296 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "OutputPlugin.h" +#include "Main.h" +#include "Unicode.h" +#include "Console.h" +#include "Config.h" +#include "Playback.h" + + + +vector output_plugins; // extern +OutputPlugin ** active_output_plugins = NULL; // extern +int active_output_count = 0; // extern + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +OutputPlugin::OutputPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) +{ + iHookerIndex = -1; + + bActive = false; + iArrayIndex = -1; + plugin = NULL; + + if( !Load() ) + { + return; + } + +//////////////////////////////////////////////////////////////////////////////// + // Quick hack!!! + TCHAR * szBuffer = new TCHAR[ 500 ]; // NOT LOCAL!!! + _stprintf( szBuffer, TEXT( "OutputPluginActive___%s" ), GetFilename() ); + ConfBool * cbActive = new ConfBool( &bActive, szBuffer, CONF_MODE_INTERNAL, false ); + cbActive->Read(); + + if( bActive ) + { + bActive = false; + Start(); + } + else + { + if( !bKeepLoaded ) + { + // Note: out_ds seems to do weird things + // when unloaded here!? + // So out_ds keeps loaded for now. + if( _tcscmp( GetFilename(), TEXT( "out_ds.dll" ) ) ) + { + Unload(); + } + } + } + // Quick hack!!! +//////////////////////////////////////////////////////////////////////////////// + + + output_plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::Load() +{ + if( IsLoaded() ) return true; + + // (1) Load DLL + hDLL = LoadLibrary( GetFullpath() ); + if( !hDLL ) return false; + + // (2) Find export + WINAMP_OUTPUT_GETTER winampGetOutModule = + ( WINAMP_OUTPUT_GETTER )GetProcAddress( hDLL, "winampGetOutModule" ); + if( winampGetOutModule == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (3) Get module + plugin = winampGetOutModule(); + if( !plugin ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (4) Process module + plugin->hDllInstance = hDLL; + plugin->hMainWindow = WindowMain; + + if( !szName ) + { + // Note: The prefix is not removed to hide their + // origin at Nullsoft! It just reads easier. + if( !strnicmp( plugin->description, "nullsoft ", 9 ) ) + { + plugin->description += 9; + } + iNameLen = ( int )strlen( plugin->description ); + szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( szName, plugin->description, iNameLen ); + szName[ iNameLen ] = TEXT( '\0' ); + } + + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + if( plugin->Init ) + { + // Init + const WNDPROC WndprocBefore = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + plugin->Init(); + const WNDPROC WndprocAfter = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); + + if( WndprocBefore != WndprocAfter ) + { + WndprocBackup = WndprocBefore; + iHookerIndex = iWndprocHookCounter++; + } + + + // Note: Plugins that use a wndproc hook need + // to be unloaded in the inverse loading order. + // This is due to the nature of wndproc hooking. + if( iHookerIndex != -1 ) + { + Console::Append( TEXT( "Wndproc hook added (by plugin)" ) ); + } + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::Unload() +{ + if( !IsLoaded() ) return true; + if( bActive && Playback::IsPlaying() ) return false; + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Unloading <%s>" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + // Quit + if( plugin ) + { + if( plugin->Quit ) plugin->Quit(); + plugin = NULL; + } + + // Remove wndproc hook + if( ( iHookerIndex != -1 ) && ( iHookerIndex == iWndprocHookCounter - 1 ) ) + { + // If we don't restore it the plugins wndproc will + // still be called which is not there anymore -> crash + SetWindowLong( WindowMain, GWL_WNDPROC, ( LONG )WndprocBackup ); + Console::Append( TEXT( "Wndproc hook removed (by host)" ) ); + Console::Append( TEXT( " " ) ); + + iHookerIndex = -1; + iWndprocHookCounter--; + } + + FreeLibrary( hDLL ); + hDLL = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::About( HWND hParent ) +{ + if( !IsLoaded() ) return false; + if( !plugin ) return false; + if( !plugin->About ) return false; + + plugin->About( hParent ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::Config( HWND hParent ) +{ + if( !IsLoaded() ) return false; + if( !plugin ) return false; + if( !plugin->Config ) return false; + + plugin->Config( hParent ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::Start() +{ + if( !IsLoaded() ) return false; + if( bActive ) return true; + + if( active_output_count ) + { + active_output_plugins = ( OutputPlugin ** )realloc( active_output_plugins, ( active_output_count + 1 ) * sizeof( OutputPlugin * ) ); + active_output_plugins[ active_output_count ] = this; + iArrayIndex = active_output_count; + active_output_count++; + } + else + { + active_output_plugins = ( OutputPlugin ** )malloc( sizeof( OutputPlugin * ) ); + active_output_plugins[ 0 ] = this; + iArrayIndex = 0; + active_output_count = 1; + } + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Output plugin <%s> activated" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + bActive = true; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OutputPlugin::Stop() +{ + if( !IsLoaded() ) return true; + if( !bActive ) return true; + + const int iMaxIndex = active_output_count - 1; + if( iArrayIndex < iMaxIndex ) + { + active_output_plugins[ iArrayIndex ] = active_output_plugins[ iMaxIndex ]; + active_output_plugins[ iArrayIndex ]->iArrayIndex = iArrayIndex; + } + iArrayIndex = -1; + active_output_count--; + + // TODO Flush? + // TODO Close? + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Output plugin <%s> deactivated" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + bActive = false; + + return true; +} diff --git a/Branches/MusicMod/Player/Src/OutputPlugin.h b/Branches/MusicMod/Player/Src/OutputPlugin.h new file mode 100644 index 0000000000..fbbfce418a --- /dev/null +++ b/Branches/MusicMod/Player/Src/OutputPlugin.h @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_OUTPUT_PLUGIN_H +#define PA_OUTPUT_PLUGIN_H + + + +#include "Global.h" +#include "Plugin.h" +#include "Winamp/Out.h" +#include + +using namespace std; + + + +typedef Out_Module * ( * WINAMP_OUTPUT_GETTER )( void ); + + +class OutputPlugin; + +extern vector output_plugins; +extern OutputPlugin ** active_output_plugins; +extern int active_output_count; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp output plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class OutputPlugin : public Plugin +{ +public: + OutputPlugin( TCHAR * szDllpath, bool bKeepLoaded ); + + bool Load(); + bool Unload(); + + TCHAR * GetTypeString() { return TEXT( "Output" ); } + int GetTypeStringLen() { return 6; } + PluginType GetType() { return PLUGIN_TYPE_OUTPUT; } + + inline bool IsActive() { return bActive; } + + bool About( HWND hParent ); + bool Config( HWND hParent ); + + bool Start(); + bool Stop(); + +private: + bool bActive; + int iArrayIndex; + Out_Module * plugin; + + + // TODO + friend bool OpenPlay( TCHAR * szFilename, int iNumber ); + + friend int Output_Open( int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms ); + friend void Output_Close(); + friend int Output_Write( char * buf, int len ); + friend int Output_CanWrite(); + friend int Output_IsPlaying(); + friend int Output_Pause( int pause ); + friend void Output_SetVolume( int volume ); + friend void Output_SetPan( int pan ); + friend void Output_Flush( int t ); + friend int Output_GetOutputTime(); + friend int Output_GetWrittenTime(); +}; + + + +#endif // PA_OUTPUT_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/Path.cpp b/Branches/MusicMod/Player/Src/Path.cpp new file mode 100644 index 0000000000..956489bccc --- /dev/null +++ b/Branches/MusicMod/Player/Src/Path.cpp @@ -0,0 +1,243 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Path.h" +#include +#include + +using namespace std; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Applies a virtual root to a filename +/// +/// Example: +/// Rootpath: "C:\111\222\333\" +/// Filename before: "C:\111\444\test.mp3" +/// Filename after: "..\..\444\test.mp3" +//////////////////////////////////////////////////////////////////////////////// +bool ApplyRootToFilename( TCHAR * szRootpath, TCHAR * szFilename ) +{ + // returns modified flag + + int iFilenameLen = ( int )_tcslen( szFilename ); + int iRootLen = ( int )_tcslen( szRootpath ); + + // Too short? + if( ( iRootLen < 2 ) || ( iFilenameLen < 4 ) ) + { + return false; + } + + // Ensure trailing backslash + bool bDelOnRet = false; + TCHAR * szFinalRoot; + TCHAR * szFinalRootBackup; + if( szRootpath[ iRootLen - 1 ] != TEXT( '\\' ) ) + { + szFinalRoot = new TCHAR[ iRootLen + 2 ]; + memcpy( szFinalRoot, szRootpath, iRootLen * sizeof( TCHAR ) ); + memcpy( szFinalRoot + iRootLen, TEXT( "\\\0" ), 2 * sizeof( TCHAR ) ); + iRootLen++; + szFinalRootBackup = szFinalRoot; + bDelOnRet = true; + } + else + { + szFinalRoot = szRootpath; + szFinalRootBackup = NULL; + bDelOnRet = false; + } + + + // Different drives? + if( _totlower( *szFilename ) != _totlower( *szFinalRoot ) ) + { + if( bDelOnRet ) delete [] szFinalRootBackup; + return false; + } + + + // Skip drive + if( _tcsnicmp( szFilename, szFinalRoot, 3 ) ) + { + szFinalRoot += 3; + iRootLen -= 3; + + memmove( szFilename, szFilename + 3, ( iFilenameLen - 2 ) * sizeof( TCHAR ) ); // Plus \0 + iFilenameLen -=3; + } + + + int iBackslashLast = -1; + + int iCompLen; // Maximum chars to compare + if( iRootLen > iFilenameLen ) + iCompLen = iFilenameLen; + else + iCompLen = iRootLen; + + + // Walk while equal + int i = 0; + while( i < iCompLen ) + { + if( ( szFilename[ i ] == TEXT( '\\' ) ) && ( szFinalRoot[ i ] == TEXT( '\\' ) ) ) + { + iBackslashLast = i; + i++; + } + else if( _totlower( szFilename[ i ] ) == _totlower( szFinalRoot[ i ] ) ) + { + i++; + } + else + { + break; + } + } + + + // Does the filename contain the full root? + int iLevelDiff = 0; + if( i != iCompLen ) + { + // Calculate level difference + for( i = iBackslashLast + 1; i < iRootLen; i++ ) + { + if( szFinalRoot[ i ] == TEXT( '\\' ) ) + { + iLevelDiff++; + } + } + } + + + if( iBackslashLast == -1 ) + { + if( bDelOnRet ) delete [] szFinalRootBackup; + return false; + } + + + TCHAR * szSource = szFilename + iBackslashLast + 1; + if( iLevelDiff > 0 ) + { + const int iExtraCharsForPrefix = ( 3 * iLevelDiff ) - iBackslashLast - 1; + const int iCharsToMove = iFilenameLen - iBackslashLast; // One more for '\0' + memmove( szSource + iExtraCharsForPrefix, szSource, sizeof( TCHAR ) * iCharsToMove ); + + TCHAR * szWalk = szFilename; + while( iLevelDiff-- ) + { + memcpy( szWalk, TEXT( "..\\" ), 3 * sizeof( TCHAR ) ); + szWalk += 3; + } + } + else + { + const int iCharsToMove = iFilenameLen - iBackslashLast; // One more for '\0' + memmove( szFilename, szSource, sizeof( TCHAR ) * iCharsToMove ); + } + + + if( bDelOnRet ) delete [] szFinalRootBackup; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Compresses filenames (inplace) +/// +/// Example: +/// Before "C:\111\222\..\333\.\444\..\..\test.mp3" +/// After "C:\111\test.mp3" +//////////////////////////////////////////////////////////////////////////////// +bool UnbloatFilename( TCHAR * szFullpath, bool bFixTooDeep ) +{ + int iLen = ( int )_tcslen( szFullpath ); + bool bModified = false; + + // Exclude drive letter from conversion "C:\" + if( ( iLen > 3 ) && !_tcsnicmp( szFullpath + 1, TEXT( ":\\" ), 2 ) ) + { + szFullpath += 3; + iLen -= 3; + } + + vector< TCHAR * > after_backslash; + TCHAR * end = szFullpath + iLen; + TCHAR * szWalk = szFullpath; + + while( true ) + { + if( !_tcsnicmp( szWalk, TEXT( "..\\" ), 3 ) ) + { + TCHAR * szAfterBackslashLast; + + if( after_backslash.empty() ) + { + // Getting here means we go deeper than root level e.g. "../test" + if( bFixTooDeep ) + { + szAfterBackslashLast = szWalk; + } + else + { + break; + } + } + else + { + szAfterBackslashLast = after_backslash.back(); + after_backslash.pop_back(); + } + + const int iBytesToCopy = end - szWalk - ( 3 * sizeof( TCHAR ) ); + const int iBytesLess = szWalk + ( 3 * sizeof( TCHAR ) ) - szAfterBackslashLast; + + memmove( szAfterBackslashLast, szWalk + 3, iBytesToCopy ); + + char * byte_end = ( char * )end; + byte_end -= iBytesLess; + end = byte_end; + *end = TEXT( '\0' ); + + szWalk = szAfterBackslashLast; + + bModified = true; + } + else if( !_tcsnicmp( szWalk, TEXT( ".\\" ), 2 ) ) + { + const int iBytesToCopy = end - szWalk - ( 2 * sizeof( TCHAR ) ); + memmove( szWalk, szWalk + 2, iBytesToCopy ); + end -= 2; + *end = TEXT( '\0' ); + + bModified = true; + } + else + { + + if( szWalk >= end ) break; + after_backslash.push_back( szWalk ); + + // Jump after next backslash + while( ( szWalk < end ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk++; + szWalk++; + } + } + + return bModified; +} diff --git a/Branches/MusicMod/Player/Src/Path.h b/Branches/MusicMod/Player/Src/Path.h new file mode 100644 index 0000000000..63b510dd48 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Path.h @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PATH_H +#define PA_PATH_H + + + +#ifndef PLAINAMP_TESTING +# include "Global.h" +#else +# include "../Testing/GlobalTest.h" +#endif + + + +bool ApplyRootToFilename( TCHAR * szRootpath, TCHAR * szFilename ); +bool UnbloatFilename( TCHAR * szFullpath, bool bFixTooDeep ); + + + +#endif // PA_PATH_H diff --git a/Branches/MusicMod/Player/Src/Playback.cpp b/Branches/MusicMod/Player/Src/Playback.cpp new file mode 100644 index 0000000000..9ea3912d4a --- /dev/null +++ b/Branches/MusicMod/Player/Src/Playback.cpp @@ -0,0 +1,695 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Playback.h" +#include "InputPlugin.h" +#include "Output.h" +#include "Playlist.h" +#include "Console.h" +#include "Unicode.h" +#include "Rebar.h" +#include "Main.h" +#include "Config.h" +#include "Status.h" + + + +int iCurVol = 255; +ConfIntMinMax ciCurVol( &iCurVol, TEXT( "Volume" ), CONF_MODE_INTERNAL, 255, 0, 255 ); + +int iCurPan = 0; +ConfIntMinMax ciCurPan( &iCurPan, TEXT( "Panning" ), CONF_MODE_INTERNAL, 0, -127, 127 ); + + + +#define VOLUME_STEP ( 255 / 10 ) + + + +bool bPlaying = false; +bool bPaused = false; + +bool bTimerRunning = false; + + + +// Only for reference comparison!!! +TCHAR * szCurrentFilename = NULL; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void EnableTimer( bool bEnabled ) +{ + if( bEnabled == bTimerRunning ) return; + + if( bEnabled ) + { + SetTimer( WindowMain, TIMER_SEEK_UPDATE, 1000, NULL ); + } + else + { + KillTimer( WindowMain, TIMER_SEEK_UPDATE ); + StatusReset(); + } + + bTimerRunning = bEnabled; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool OpenPlay( TCHAR * szFilename, int iNumber ) +{ + // TODO: cleanup!!! + + if( !szFilename ) return false; + szCurrentFilename = szFilename; + + // TODO: non-file support + + // Get extension + const int iLen = ( int )_tcslen( szFilename ); + TCHAR * walk = szFilename + iLen - 1; + while( ( walk >= szFilename ) && ( *walk != TEXT( '.' ) ) ) walk--; + walk++; + + const int iExtLen = ( int )_tcslen( walk ); + TCHAR * szExt = new TCHAR[ iExtLen + 1 ]; + memcpy( szExt, walk, iExtLen * sizeof( TCHAR ) ); + szExt[ iExtLen ] = TEXT( '\0' ); + + // Get input plugin from extension map + map ::iterator iter = + ext_map.find( szExt ); + delete [] szExt; + if( iter == ext_map.end() ) + { + Console::Append( TEXT( "ERROR: Extension not supported" ) ); + Console::Append( " " ); + return false; + } + + InputPlugin * old_input = active_input_plugin; + active_input_plugin = iter->second; + + if( old_input ) + { + // if( active_input_plugin != old_input ) ----> TODO unload old plugin + + // Some output plugins require a call to Close() before each + // call to Open(). Calling Input::Stop() will make the input plugin + // call Output::Close() and thus solve this problem. + old_input->plugin->Stop(); + } + + if( !active_input_plugin->plugin ) + { + Console::Append( TEXT( "ERROR: Input plugin is NULL" ) ); + Console::Append( " " ); + return false; + } + + // Connect + active_input_plugin->plugin->outMod = &output_server; // output->plugin; + + // Re-apply volume and panning + active_input_plugin->plugin->SetVolume( iCurVol ); + active_input_plugin->plugin->SetPan( iCurPan ); + Playback::Eq::Reapply(); + + // Play + +#ifdef PA_UNICODE + // Filename + const int iFilenameLen = _tcslen( szFilename ); + char * szTemp = new char[ iFilenameLen + 1 ]; + ToAnsi( szTemp, szFilename, iFilenameLen ); + szTemp[ iFilenameLen ] = '\0'; + + // Ansi Title + char szAnsiTitle[ 2000 ] = "\0"; + int length_in_ms; + active_input_plugin->plugin->GetFileInfo( szTemp, szAnsiTitle, &length_in_ms ); + const int iAnsiTitleLen = strlen( szAnsiTitle ); + + // Unicode title + TCHAR szTitle[ 2000 ]; + ToTchar( szTitle, szAnsiTitle, iFilenameLen, iAnsiTitleLen ); + szTitle[ iAnsiTitleLen ] = TEXT( "\0" ); + + active_input_plugin->plugin->Play( szTemp ); + delete [] szTemp; +#else + // Title + TCHAR szTitle[ 2000 ] = TEXT( "\0" ); + int length_in_ms; + active_input_plugin->plugin->GetFileInfo( szFilename, szTitle, &length_in_ms ); + + active_input_plugin->plugin->Play( szFilename ); +#endif + + bPlaying = true; + bPaused = false; + + // Title + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "%i. %s - Plainamp" ), iNumber, szTitle ); + SetWindowText( WindowMain, szBuffer ); + +/* + TCHAR * szBasename = szFilename + uLen - 1; + while( ( szBasename > szFilename ) && ( *szBasename != TEXT( '\\' ) ) ) szBasename--; + szBasename++; +*/ + + // Timer ON + EnableTimer( true ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback_PrevOrNext( bool bPrevOrNext ) +{ + // todo: prev/next in pause mode? + + if( !active_input_plugin ) return false; + if( !active_input_plugin->plugin ) return false; + + int iNextIndex = playlist->GetCurIndex(); + int iMaxIndex = playlist->GetMaxIndex(); + if( iMaxIndex < 0 || iNextIndex < 0 ) return false; + + bool res; + if( bPrevOrNext ) + res = Playback::Order::Prev( iNextIndex, iMaxIndex ); + else + res = Playback::Order::Next( iNextIndex, iMaxIndex ); + + if( res ) + { + if( bPlaying ) + { + // NOT TWICE active_input_plugin->plugin->Stop(); + bPlaying = false; + bPaused = false; + + // Timer OFF + EnableTimer( false ); + } + + TCHAR * szFilename = Playlist::GetFilename( iNextIndex ); + if( !szFilename ) return false; + + playlist->SetCurIndex( iNextIndex ); + + return OpenPlay( szFilename, iNextIndex + 1 ); + } + else + { + return false; + } + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Prev() +{ + return Playback_PrevOrNext( true ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Play() +{ + static int iLastIndex = -1; + if( bPlaying ) + { + if( !active_input_plugin ) return false; + if( !active_input_plugin->plugin ) return false; + + const int iIndex = playlist->GetCurIndex(); + if( iIndex < 0 ) return false; + +/* + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "OLD [%i] NEW [%i]" ), iLastIndex, iIndex ); + SetWindowText( WindowMain, szBuffer ); +*/ + + // Same track/file as before? + TCHAR * szFilename = Playlist::GetFilename( iIndex ); + if( szFilename != szCurrentFilename ) + { + // New track! + + // Stop + // NOT TWICE active_input_plugin->plugin->Stop(); + + // Timer OFF + EnableTimer( false ); + + // Get filename + if( !szFilename ) + { + Console::Append( TEXT( "ERROR: Could not resolve filename" ) ); + Console::Append( " " ); + return false; + } + + // Play + iLastIndex = iIndex; + bPlaying = OpenPlay( szFilename, iIndex + 1 ); + bPaused = false; + } + else + { + // Same track! + if( bPaused ) + { + // Unpause + active_input_plugin->plugin->UnPause(); + bPaused = false; + + // Timer ON + EnableTimer( true ); + } + else + { + // Restart at beginning + active_input_plugin->plugin->SetOutputTime( 0 ); + } + } + } + else + { + const int iIndex = playlist->GetCurIndex(); + if( iIndex < 0 ) return false; + + // Get filename + TCHAR * szFilename = Playlist::GetFilename( iIndex ); + if( !szFilename ) + { + Console::Append( TEXT( "ERROR: Could not resolve filename" ) ); + Console::Append( " " ); + return false; + } + + // Play + iLastIndex = iIndex; + bPlaying = OpenPlay( szFilename, iIndex + 1 ); + bPaused = false; + } + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Pause() +{ + if( !bPlaying ) return false; + if( !active_input_plugin ) return false; + if( !active_input_plugin->plugin ) return false; + + if( bPaused ) + { + // Unpause + active_input_plugin->plugin->UnPause(); + bPaused = false; + + // Timer ON + EnableTimer( true ); + } + else + { + // Pause + active_input_plugin->plugin->Pause(); + bPaused = true; + + // Timer OFF + EnableTimer( false ); + } + +// Console::Append( TEXT( "Playback::Pause" ) ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Stop() +{ + if( !bPlaying ) return false; + + // Stop + if( active_input_plugin && active_input_plugin->plugin ) + { + active_input_plugin->plugin->Stop(); + } + active_input_plugin = NULL; // QUICK FIX + + bPlaying = false; + bPaused = false; + + // Timer OFF + EnableTimer( false ); + + // Reset seekbar + Playback::UpdateSeek(); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Next() +{ + return Playback_PrevOrNext( false ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::IsPlaying() +{ + return bPlaying; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::IsPaused() +{ + return bPaused; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::UpdateSeek() +{ + static bool bSliderEnabledBefore = false; + bool bSliderEnabledAfter; + + if( !WindowSeek ) return false; + + int iVal = 0; + + if( !active_input_plugin || !active_input_plugin->plugin ) + { + if( bSliderEnabledBefore ) + { + // Update slider + PostMessage( WindowSeek, TBM_SETPOS, ( WPARAM )( TRUE ), iVal ); + + // Disable slider + EnableWindow( WindowSeek, FALSE ); + bSliderEnabledBefore = false; + } + } + else + { + const int ms_len = active_input_plugin->plugin->GetLength(); + if( ms_len ) + { + const int ms_cur = active_input_plugin->plugin->GetOutputTime(); + iVal = ( ms_cur * 1000 ) / ms_len; + + if( iVal > 1000 ) iVal = 0; + } + + if( !bSliderEnabledBefore ) + { + EnableWindow( WindowSeek, TRUE ); + bSliderEnabledBefore = true; + } + + // Update slider + PostMessage( WindowSeek, TBM_SETPOS, ( WPARAM )( TRUE ), iVal ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playback::PercentToMs( float fPercent ) +{ + if( !active_input_plugin ) return -1; + if( !active_input_plugin->plugin ) return -1; + + const int ms_len = active_input_plugin->plugin->GetLength(); + const int ms_res = ( int )( ms_len * fPercent / 100.0f ); + return ms_res; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::SeekPercent( float fPercent ) +{ + // TODO update slider, NOT HERE!!! + + if( !bPlaying ) return false; + if( bPaused ) return false; // TODO: apply seek when unpausing + if( !active_input_plugin ) return false; + if( !active_input_plugin->plugin ) return false; + + if( fPercent < 0.0f ) + fPercent = 0.0f; + else if( fPercent > 100.0f ) + fPercent = 100.0f; + + const int ms_len = active_input_plugin->plugin->GetLength(); + const int ms_cur = ( int )( ms_len * fPercent / 100.0f ); + active_input_plugin->plugin->SetOutputTime( ms_cur ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool SeekRelative( int ms ) +{ + if( !bPlaying ) return false; + if( bPaused ) return false; // TODO: apply seek when unpausing + if( !active_input_plugin ) return false; + if( !active_input_plugin->plugin ) return false; + + const int ms_len = active_input_plugin->plugin->GetLength(); + const int ms_old = active_input_plugin->plugin->GetOutputTime(); + int ms_new = ms_old + ms; + + if( ms_new < 0 ) + ms_new = 0; + else if( ms_new > ms_len ) + ms_new = ms_len; + + if( ms_new == ms_old ) return true; + active_input_plugin->plugin->SetOutputTime( ms_new ); + + /* + // PROGRESS + // PostMessage( hwnd, PBM_SETPOS , ( WPARAM )( iVal ), 0 ); + // TARCKBAR + PostMessage( wnd_pos, TBM_SETPOS, ( WPARAM )( TRUE ), ms_cur * 1000 / ms_len ); + */ + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Forward() +{ + return SeekRelative( 5000 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Rewind() +{ + return SeekRelative( -5000 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void Playback::NotifyTrackEnd() +{ + bPlaying = false; + bPaused = false; + + // Timer + EnableTimer( false ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playback::Volume::Get() +{ + return iCurVol; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline void Playback_Volume_Set( int iVol ) +{ + if( active_input_plugin && active_input_plugin->plugin ) + { + active_input_plugin->plugin->SetVolume( iVol ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Volume::Set( int iVol ) +{ + const int iCurVolBackup = iCurVol; + iCurVol = iVol; + ciCurVol.MakeValidPull(); + + if( iCurVol != iCurVolBackup ) + { + Playback_Volume_Set( iCurVol ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Volume::Up() +{ + if( ciCurVol.IsMax() ) return true; + + const int iCurVolBackup = iCurVol; + iCurVol += VOLUME_STEP; + ciCurVol.MakeValidPull(); + + if( iCurVol != iCurVolBackup ) + { + Console::Append( TEXT( "Volume UP" ) ); + Playback_Volume_Set( iCurVol ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Volume::Down() +{ + if( ciCurVol.IsMin() ) return true; + + const int iCurVolBackup = iCurVol; + iCurVol -= VOLUME_STEP; + ciCurVol.MakeValidPull(); + + if( iCurVol != iCurVolBackup ) + { + Console::Append( TEXT( "Volume DOWN" ) ); + Playback_Volume_Set( iCurVol ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playback::Pan::Get() +{ + return iCurPan; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Pan::Set( int iPan ) +{ + const int iCurPanBackup = iCurPan; + iCurPan = iPan; + ciCurPan.MakeValidPull(); + + if( ( iCurPan != iCurPanBackup ) && active_input_plugin && active_input_plugin->plugin ) + { + active_input_plugin->plugin->SetPan( iCurPan ); + } + + return true; +} diff --git a/Branches/MusicMod/Player/Src/Playback.h b/Branches/MusicMod/Player/Src/Playback.h new file mode 100644 index 0000000000..86c3f11cb3 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Playback.h @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PLAYBACK_H +#define PA_PLAYBACK_H + + + +#include "Global.h" + + + +#define ORDER_SINGLE 0 +#define ORDER_SINGLE_REPEAT 1 +#define ORDER_NORMAL 2 +#define ORDER_NORMAL_REPEAT 3 +#define ORDER_INVERSE 4 +#define ORDER_INVERSE_REPEAT 5 +#define ORDER_RANDOM 6 + +#define ORDER_FIRST ORDER_SINGLE +#define ORDER_LAST ORDER_RANDOM + +#define ORDER_DEFAULT ORDER_NORMAL_REPEAT + + +#define TIMER_SEEK_UPDATE 1 + + + +typedef bool ( * PresetCallback )( TCHAR * ); + + +namespace Playback +{ + bool Prev(); + bool Play(); + bool Pause(); + bool Stop(); + bool Next(); + + bool IsPlaying(); + bool IsPaused(); + + bool UpdateSeek(); + int PercentToMs( float fPercent ); + bool SeekPercent( float fPercent ); + bool Forward(); + bool Rewind(); + + void NotifyTrackEnd(); + + namespace Volume + { + int Get(); + bool Set( int iVol ); + bool Up(); + bool Down(); + }; + + namespace Pan + { + int Get(); + bool Set( int iPan ); + }; + + namespace Order + { + int GetCurMode(); + bool SetMode( int iMode ); + + TCHAR * GetModeName( int iMode ); +// int GetModeNameLen( int iMode ); + + bool Next( int & iCur, int iMax ); + bool Prev( int & iCur, int iMax ); + }; + + namespace Eq + { + // 63 -> -12db + // 31 -> 0 + // 0 -> +12db + // bool Get( char * eq_data ); + // bool Set( bool bOn, char * pData, int iPreamp ); + int GetCurIndex(); + bool SetIndex( int iPresetIndex ); + + bool Reapply(); + + bool ReadPresets( PresetCallback AddPreset ); + }; +}; + + + +#endif // PA_PLAYBACK_H diff --git a/Branches/MusicMod/Player/Src/PlaybackEq.cpp b/Branches/MusicMod/Player/Src/PlaybackEq.cpp new file mode 100644 index 0000000000..ee779e5545 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaybackEq.cpp @@ -0,0 +1,223 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Playback.h" +#include "InputPlugin.h" +#include "Console.h" +#include "Config.h" +#include + +using namespace std; + + + +vector eq_vec; + + + +// Note: CurPresetFixed will be renamed to CurPreset when +// custom presets are implemented. This hopefully avoids +// migration trouble. + +int iCurPreset; // -1 means EQ off +ConfInt ciCurPreset( &iCurPreset, TEXT( "CurPresetFixed" ), CONF_MODE_INTERNAL, -1 ); + +bool bPreventDistortion; // Automatic preamp adjustment +ConfBool cbPreventDistortion( &bPreventDistortion, TEXT( "PreventDistortion" ), CONF_MODE_PUBLIC, true ); + + + +//////////////////////////////////////////////////////////////////////////////// +// PRE valid index +//////////////////////////////////////////////////////////////////////////////// +void Playback_Eq_Set( int iPresetIndex ) +{ + if( active_input_plugin && active_input_plugin->plugin ) + { + if( iPresetIndex == -1 ) // == EQ disabled + { + char data[ 10 ] = { 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }; + active_input_plugin->plugin->EQSet( 0, data, 31 ); + } + else + { + char data[ 10 ]; + memcpy( data, eq_vec[ iPresetIndex ], sizeof( char ) * 10 ); + + if( bPreventDistortion ) + { + // Search minimum (most amplifying band) + int iMin = 63; + int i; + for( i = 0; i < 10; i++ ) + { + if( data[ i ] < iMin ) iMin = data[ i ]; + } + + if( iMin < 31 ) // Possible distortion + { + // Adjust preamp to prevent distortion + active_input_plugin->plugin->EQSet( 1, data, 31 + ( 31 - iMin ) ); + } + else + { + if( iMin > 31 ) // Lower than necessary + { + // Push to zero level so we get + // more volume without distortion + const int iSub = iMin - 31; + for( i = 0; i < 10; i++ ) + { + data[ i ] -= iSub; + } + } + active_input_plugin->plugin->EQSet( 1, data, 31 ); + } + } + else + { + active_input_plugin->plugin->EQSet( 1, data, 31 ); + } + } + } +} + + + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Eq::Set( bool bOn, char * pData, int iPreamp ) +{ + if( active_input_plugin && active_input_plugin->plugin ) + { + char data[ 10 ]; + memcpy( data, pData, sizeof( char ) * 10 ); + active_input_plugin->plugin->EQSet( bOn ? 1 : 0, data, iPreamp ); + } + return true; +} +*/ + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playback::Eq::GetCurIndex() +{ + return iCurPreset; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Eq::SetIndex( int iPresetIndex ) +{ + if( iPresetIndex >= ( int )eq_vec.size() ) return false; + Playback_Eq_Set( iPresetIndex ); + iCurPreset = iPresetIndex; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Eq::Reapply() +{ + Playback_Eq_Set( iCurPreset ); + return true; +} + + + +// Note: Most of these are the exact presets used in Winamp. +// I do not expect any legal trouble with this but +// in case I am wrong please let me know and I will +// remove them. + +char eq_classical [ 10 ] = { 31, 31, 31, 31, 31, 31, 44, 44, 44, 48 }; +char eq_club [ 10 ] = { 31, 31, 26, 22, 22, 22, 26, 31, 31, 31 }; +char eq_dance [ 10 ] = { 16, 20, 28, 32, 32, 42, 44, 44, 32, 32 }; +char eq_full_bass [ 10 ] = { 16, 16, 16, 22, 29, 39, 46, 49, 50, 50 }; +char eq_full_bass_treble[ 10 ] = { 20, 22, 31, 44, 40, 29, 18, 14, 12, 12 }; +char eq_full_treble [ 10 ] = { 48, 48, 48, 39, 27, 14, 6, 6, 6, 4 }; +char eq_headphones [ 10 ] = { 24, 14, 23, 38, 36, 29, 24, 16, 11, 8 }; +char eq_laptop [ 10 ] = { 24, 14, 23, 38, 36, 29, 24, 16, 11, 8 }; +char eq_large_hall [ 10 ] = { 15, 15, 22, 22, 31, 40, 40, 40, 31, 31 }; +char eq_live [ 10 ] = { 40, 31, 25, 23, 22, 22, 25, 27, 27, 28 }; +char eq_more_bass [ 10 ] = { 22, 22, 22, 22, 22, 22, 26, 31, 31, 31 }; +char eq_party [ 10 ] = { 20, 20, 31, 31, 31, 31, 31, 31, 20, 20 }; +char eq_pop [ 10 ] = { 35, 24, 20, 19, 23, 34, 36, 36, 35, 35 }; +char eq_reggae [ 10 ] = { 31, 31, 33, 42, 31, 21, 21, 31, 31, 31 }; +char eq_rock [ 10 ] = { 19, 24, 41, 45, 38, 25, 17, 14, 14, 14 }; +char eq_ska [ 10 ] = { 36, 40, 39, 33, 25, 22, 17, 16, 14, 16 }; +char eq_soft [ 10 ] = { 24, 29, 34, 36, 34, 25, 18, 16, 14, 12 }; +char eq_soft_rock [ 10 ] = { 25, 25, 28, 33, 39, 41, 38, 33, 27, 17 }; +char eq_techno [ 10 ] = { 19, 22, 31, 41, 40, 31, 19, 16, 16, 17 }; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Eq::ReadPresets( PresetCallback AddPreset ) +{ + if( AddPreset == NULL ) return false; + + eq_vec.push_back( eq_classical ); AddPreset( TEXT( "Classical" ) ); + eq_vec.push_back( eq_club ); AddPreset( TEXT( "Club" ) ); + eq_vec.push_back( eq_dance ); AddPreset( TEXT( "Dance" ) ); + eq_vec.push_back( eq_full_bass ); AddPreset( TEXT( "Full Bass" ) ); + eq_vec.push_back( eq_full_bass_treble ); AddPreset( TEXT( "Full Bass & Treble" ) ); + eq_vec.push_back( eq_full_treble ); AddPreset( TEXT( "Full Treble" ) ); + eq_vec.push_back( eq_headphones ); AddPreset( TEXT( "Headphones" ) ); + eq_vec.push_back( eq_laptop ); AddPreset( TEXT( "Laptop Speakers" ) ); + eq_vec.push_back( eq_large_hall ); AddPreset( TEXT( "Large Hall" ) ); + eq_vec.push_back( eq_live ); AddPreset( TEXT( "Live" ) ); + eq_vec.push_back( eq_more_bass ); AddPreset( TEXT( "More Bass" ) ); + eq_vec.push_back( eq_party ); AddPreset( TEXT( "Party" ) ); + eq_vec.push_back( eq_pop ); AddPreset( TEXT( "Pop" ) ); + eq_vec.push_back( eq_reggae ); AddPreset( TEXT( "Reggae" ) ); + eq_vec.push_back( eq_rock ); AddPreset( TEXT( "Rock" ) ); + eq_vec.push_back( eq_ska ); AddPreset( TEXT( "Ska" ) ); + eq_vec.push_back( eq_soft ); AddPreset( TEXT( "Soft" ) ); + eq_vec.push_back( eq_soft_rock ); AddPreset( TEXT( "Soft Rock" ) ); + eq_vec.push_back( eq_techno ); AddPreset( TEXT( "Techno" ) ); + + // Fix invalid indices + if( iCurPreset < -1 ) + { + iCurPreset = -1; + } + else + { + const int iLen = ( int )eq_vec.size(); + if( iCurPreset >= iLen ) + { + iCurPreset = iLen - 1; + } + } + + // TODO load/save eqf files + // GPL eqf loading from koders.com + // equalizer.c / xmms2 A Gtk2 port of xmms.(xmms2) + // equalizer.c / Digital Disco System(dds) + + return true; +} diff --git a/Branches/MusicMod/Player/Src/PlaybackOrder.cpp b/Branches/MusicMod/Player/Src/PlaybackOrder.cpp new file mode 100644 index 0000000000..50e09a5da2 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaybackOrder.cpp @@ -0,0 +1,205 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + + +#include "Playback.h" +#include "Config.h" +#include +#include + + + +int iCurOrder = ORDER_DEFAULT; +ConfIntMinMax ciCurOrder( &iCurOrder, TEXT( "Order" ), CONF_MODE_INTERNAL, ORDER_DEFAULT, ORDER_FIRST, ORDER_LAST ); + +bool bRandomReady = false; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playback::Order::GetCurMode() +{ + return iCurOrder; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Order::SetMode( int iMode ) +{ + iCurOrder = iMode; + ciCurOrder.MakeValidDefault(); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +TCHAR * Playback::Order::GetModeName( int iMode ) +{ + switch( iMode ) + { + case ORDER_SINGLE: return TEXT( " Single" ); + case ORDER_SINGLE_REPEAT: return TEXT( " Single + Repeat" ); + case ORDER_NORMAL: return TEXT( " Normal" ); + case ORDER_NORMAL_REPEAT: return TEXT( " Normal + Repeat" ); + case ORDER_INVERSE: return TEXT( " Inverse" ); + case ORDER_INVERSE_REPEAT: return TEXT( " Inverse + Repeat" ); + case ORDER_RANDOM: return TEXT( " Random" ); + default: return NULL; + } +} + +/* +int Playback::Order::GetModeNameLen( int iMode ) +{ + switch( uMode ) + { + case ORDER_SINGLE: return 7; + case ORDER_SINGLE_REPEAT: return 16; + case ORDER_NORMAL: return 7; + case ORDER_NORMAL_REPEAT: return 16; + case ORDER_INVERSE: return 8; + case ORDER_INVERSE_REPEAT: return 17; + case ORDER_RANDOM: return 7; + default: return 0; + } +} +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool NextNormal( int & iCur, int iMax ) +{ + if( iCur >= iMax ) return false; + iCur++; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool NextNormalRepeat( int & iCur, int iMax ) +{ + if( iCur >= iMax ) + iCur = 0; + else + iCur++; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool NextInverse( int & iCur, int iMax ) +{ + if( iCur <= 0 ) return false; + iCur--; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool NextInverseRepeat( int & iCur, int iMax ) +{ + if( iCur <= 0 ) + iCur = iMax; + else + iCur--; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool NextRandom( int & iCur, int iMax ) +{ + if( iMax < 2 ) return false; + + if( !bRandomReady ) + { + srand( ( unsigned )time( NULL ) ); + bRandomReady = true; + } + + const int iNew = ( int )( rand() / ( float )RAND_MAX * iMax ); + if( iNew != iCur ) + iCur = iNew; + else + { + if( iCur >= iMax ) + iCur = 0; + else + iCur++; + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Order::Next( int & iCur, int iMax ) +{ + switch( iCurOrder ) + { + case ORDER_SINGLE: return false; + case ORDER_SINGLE_REPEAT: return true; + case ORDER_NORMAL: return NextNormal( iCur, iMax ); + case ORDER_NORMAL_REPEAT: return NextNormalRepeat( iCur, iMax ); + case ORDER_INVERSE: return NextInverse( iCur, iMax ); + case ORDER_INVERSE_REPEAT: return NextInverseRepeat( iCur, iMax ); + case ORDER_RANDOM: return NextRandom( iCur, iMax ); + default: return false; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playback::Order::Prev( int & iCur, int iMax ) +{ + switch( iCurOrder ) + { + case ORDER_SINGLE: return false; + case ORDER_SINGLE_REPEAT: return true; + case ORDER_NORMAL: return NextInverse( iCur, iMax ); + case ORDER_NORMAL_REPEAT: return NextInverseRepeat( iCur, iMax ); + case ORDER_INVERSE: return NextNormal( iCur, iMax ); + case ORDER_INVERSE_REPEAT: return NextNormalRepeat( iCur, iMax ); + case ORDER_RANDOM: return NextRandom( iCur, iMax ); + default: return false; + } +} + diff --git a/Branches/MusicMod/Player/Src/Playlist.cpp b/Branches/MusicMod/Player/Src/Playlist.cpp new file mode 100644 index 0000000000..bdfdf9e4a1 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Playlist.cpp @@ -0,0 +1,1347 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Playlist.h" +#include "AddDirectory.h" +#include "Rebar.h" +#include "Main.h" +#include "Status.h" +#include "Console.h" +#include "Font.h" +#include "Playback.h" +#include "InputPlugin.h" +#include "Prefs.h" +#include "Config.h" +#include "Unicode.h" +#include "Path.h" +#include "commdlg.h" + + + + + + + + +HWND WindowPlaylist = NULL; // extern +// WNDPROC WndprocPlaylistBackup = NULL; + +// int iCurIndex = -1; +// int iMaxIndex = -1; + + + +// LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); +void Playlist_SelectSingle( int iIndex ); + + +struct PlaylistEntry +{ + TCHAR * szFilename; + // More to come +}; + +/* +/////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playlist::GetCurIndex() +{ + return iCurIndex; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playlist::GetMaxIndex() +{ + return iMaxIndex; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::SetCurIndex( int iIndex ) +{ + if( iIndex < 0 || iIndex > iMaxIndex ) return false; + + iCurIndex = iIndex; + if( bPlaylistFollow ) + { + Playlist_SelectSingle( iCurIndex ); + } + + return true; +} +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::Create() +{ + if( WindowPlaylist ) return false; + + PlaylistView::Create(); + +/* + RECT ClientMain; + GetClientRect( WindowMain, &ClientMain ); + + const int iClientHeight = ClientMain.bottom - ClientMain.top; + const int iClientWidth = ClientMain.right - ClientMain.left; + const int iPlaylistHeight = iClientHeight - iRebarHeight - iStatusHeight; + + WindowPlaylist = CreateWindowEx( + WS_EX_CLIENTEDGE, + TEXT( "LISTBOX" ), + NULL, + WS_VSCROLL | + LBS_DISABLENOSCROLL | + LBS_EXTENDEDSEL | + LBS_HASSTRINGS | + LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | + WS_CHILD | + WS_VISIBLE, // + 0, + iRebarHeight, // + -2, + iClientWidth, + iPlaylistHeight, + WindowMain, + NULL, + g_hInstance, + NULL + ); + + // Exchange window procedure + WndprocPlaylistBackup = ( WNDPROC )GetWindowLong( WindowPlaylist, GWL_WNDPROC ); + if( WndprocPlaylistBackup != NULL ) + { + SetWindowLong( WindowPlaylist, GWL_WNDPROC, ( LONG )WndprocPlaylist ); + } +*/ + Font::Apply( WindowPlaylist ); + + + TCHAR * szPlaylistMind = new TCHAR[ iHomeDirLen + 12 + 1 ]; + memcpy( szPlaylistMind, szHomeDir, iHomeDirLen * sizeof( TCHAR ) ); + memcpy( szPlaylistMind + iHomeDirLen, TEXT( "Plainamp.m3u" ), 12 * sizeof( TCHAR ) ); + szPlaylistMind[ iHomeDirLen + 12 ] = TEXT( '\0' ); + + Playlist::AppendPlaylistFile( szPlaylistMind ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline void Playlist_SelectSingle( int iIndex ) +{ + SendMessage( + WindowPlaylist, + LB_SETSEL, + FALSE, + -1 + ); + + SendMessage( + WindowPlaylist, + LB_SETSEL, + TRUE, + iIndex + ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline bool Playlist_IsSelected( int iIndex ) +{ + return ( 0 != SendMessage( + WindowPlaylist, + LB_GETSEL, + ( WPARAM )iIndex, + 0 + ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline bool Playlist_SelectModify( int iIndex, bool bSelected ) +{ + return ( LB_ERR != SendMessage( + WindowPlaylist, + LB_SETSEL, + ( WPARAM )( bSelected ? TRUE : FALSE ), + iIndex + ) ); +} + + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist_Remove( int iIndex ) +{ + if( iIndex < 0 || iIndex > iMaxIndex ) return false; + + // Get entry data + PlaylistEntry * entry = ( PlaylistEntry * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + iIndex, + 0 + ); + + // Free data + if( entry ) + { + if( entry->szFilename ) delete [] entry->szFilename; + delete entry; + } + + SendMessage( + WindowPlaylist, + LB_DELETESTRING, + iIndex, + 0 + ); + + if( iIndex < iCurIndex ) + iCurIndex--; + if( ( iIndex == iCurIndex ) && ( iCurIndex == iMaxIndex ) ) + iCurIndex = iMaxIndex - 1; + iMaxIndex--; + + return true; +} +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline int Playlist_GetCount() +{ + return ( int )SendMessage( + WindowPlaylist, + LB_GETCOUNT, + 0, + 0 + ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline int Playlist_GetCaretIndex() +{ + return ( int )SendMessage( + WindowPlaylist, + LB_GETCARETINDEX, + 0, + 0 + ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline bool Playlist_SetCaretIndex( int iIndex ) +{ + return ( LB_OKAY == SendMessage( + WindowPlaylist, + LB_SETCARETINDEX, + ( WPARAM )iIndex, + FALSE + ) ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +inline int Playlist_GetSelCount() +{ + return ( int )SendMessage( + WindowPlaylist, + LB_GETSELCOUNT, + 0, + 0 + ); +} + + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playlist_MouseToIndex() +{ + POINT p; + GetCursorPos( &p ); + ScreenToClient( WindowPlaylist, &p ); + + int iIndex = ( int )SendMessage( + WindowPlaylist, + LB_ITEMFROMPOINT, + 0, + p.x | ( p.y << 16 ) + ); + + if( ( iIndex < 0 ) || ( iIndex > iMaxIndex ) ) + return -1; + else + return iIndex; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::Clear() +{ + if( iMaxIndex < 0 ) return false; + + int iCount = iMaxIndex + 1; + while( iCount-- ) + { + Playlist_Remove( iCount ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::RemoveSelected() +{ + int iSelCount = Playlist_GetSelCount(); + if( iSelCount < 0 ) return false; + + // Which items are selected? + int * sel = new int[ iSelCount ]; + LRESULT lResult = SendMessage( + WindowPlaylist, + LB_GETSELITEMS, + ( WPARAM )iSelCount, + ( LPARAM )sel + ); + + // Remove + if( lResult > 0 ) + { + while( lResult-- ) + { + int iIndex = sel[ lResult ]; + Playlist_Remove( iIndex ); + } + } + + delete [] sel; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::Crop() +{ + int iAllCount = Playlist_GetCount(); + if( iAllCount < 1 ) return false; + + int iSelCount = Playlist_GetSelCount(); + if( iSelCount < 0 ) + { + return false; + } + else if( iSelCount == 0 ) + { + // None selected + return Clear(); + } + + // Which items are selected? + int * sel = new int[ iSelCount ]; + LRESULT lResult = SendMessage( + WindowPlaylist, + LB_GETSELITEMS, + ( WPARAM )iSelCount, + ( LPARAM )sel + ); + + int iLowerEqualIndex = iSelCount - 1; + for( int i = iAllCount - 1; i >= 0; i-- ) + { + while( ( sel[ iLowerEqualIndex ] > i ) && ( iLowerEqualIndex > 0 ) ) + { + iLowerEqualIndex--; + } + + if( i != sel[ iLowerEqualIndex ] ) + { + // Not selected -> remove + Playlist_Remove( i ); + } + } + + delete [] sel; + return true; +} +*/ + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist_MoveSel( bool bUpOrDown ) +{ + static bool bMoving = false; + if( bMoving ) return false; + + bMoving = true; + + const int iSelCount = Playlist_GetSelCount(); + if( iSelCount < 0 ) + { + // No items selected + bMoving = false; + return false; + } + + // Which items are selected? + int * sel = new int[ iSelCount ]; + LRESULT lResult = SendMessage( + WindowPlaylist, + LB_GETSELITEMS, + ( WPARAM )iSelCount, + ( LPARAM )sel + ); + + if( lResult <= 0 ) + { + // Nothing to move + delete [] sel; + bMoving = false; + return false; + } + + if( ( bUpOrDown && ( sel[ 0 ] == 0 ) ) || + ( !bUpOrDown && ( sel[ iSelCount - 1 ] == iMaxIndex ) ) ) + { + // Cannot move + delete [] sel; + bMoving = false; + return false; + } + + const int iOldTop = ( int )SendMessage( + WindowPlaylist, + LB_GETTOPINDEX, + 0, + 0 + ); + + // 1 _2_[3][4][5] 6 7 [8] 9 + // --> 1 [3][4][5]_2_ 6 [8]_7_ 9 + + // Redrawing OFF + // SendMessage( WindowPlaylist, WM_SETREDRAW, ( WPARAM )FALSE, 0 ); + + int i = ( bUpOrDown ? 0 : iSelCount - 1 ); + do + { + // Backup the jumper + PlaylistEntry * entry_old = ( PlaylistEntry * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + sel[ i ] + ( bUpOrDown ? -1 : 1 ), + 0 + ); + + do + { + // Copy on + PlaylistEntry * entry_new = ( PlaylistEntry * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + sel[ i ], + 0 + ); + + int iDest = sel[ i ] + ( bUpOrDown ? -1 : 1 ); + + // Update entry display == delete, insert, set data + SendMessage( + WindowPlaylist, + LB_DELETESTRING, + iDest, + 0 + ); + iDest = ( int )SendMessage( + WindowPlaylist, + LB_INSERTSTRING, + iDest, + ( LPARAM )entry_new->szFilename + ); + SendMessage( + WindowPlaylist, + LB_SETITEMDATA, + iDest, + ( LPARAM )entry_new + ); + + if( sel[ i ] == iCurIndex ) + { + iCurIndex += ( bUpOrDown ? -1 : 1 ); + } + + i += ( bUpOrDown ? 1 : -1 ); + } while( bUpOrDown + ? + ( i < iSelCount ) && ( sel[ i - 1 ] + 1 == sel[ i ] ) + : + ( i >= 0 ) && ( sel[ i + 1 ] - 1 == sel[ i ] ) + ); + + // Place the jumper + int iLast = ( bUpOrDown ? sel[ i - 1 ] : sel[ i + 1 ] ); + + // Update entry display == delete, insert, set data + SendMessage( + WindowPlaylist, + LB_DELETESTRING, + iLast, + 0 + ); + iLast = ( int )SendMessage( + WindowPlaylist, + LB_INSERTSTRING, + iLast, + ( LPARAM )entry_old->szFilename + ); + SendMessage( + WindowPlaylist, + LB_SETITEMDATA, + iLast, + ( LPARAM )entry_old + ); + } while( bUpOrDown + ? + ( i < iSelCount ) + : + ( i >= 0 ) + ); + + // Select new indices (old selection went away on insert/delete + if( bUpOrDown ) + { + for( i = 0; i < iSelCount; i++ ) + SendMessage( WindowPlaylist, LB_SETSEL, TRUE, sel[ i ] - 1 ); + } + else + { + for( i = 0; i < iSelCount; i++ ) + SendMessage( WindowPlaylist, LB_SETSEL, TRUE, sel[ i ] + 1 ); + } + + // Prevent scrolling + SendMessage( + WindowPlaylist, + LB_SETTOPINDEX, + ( WPARAM )iOldTop, + 0 + ); + + // Redrawing ON + // SendMessage( WindowPlaylist, WM_SETREDRAW, ( WPARAM )TRUE, 0 ); + + + delete [] sel; + bMoving = false; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + + static bool bDragging = false; + static bool bMoveLock = false; + static int iDragStartY; + static int iItemHeight = 0x7fffffff; + + switch( message ) + { + case WM_MOUSEMOVE: + { + if( !bDragging || bMoveLock ) break; + bMoveLock = true; + + const int y = HIWORD( lp ); + const int diff = y - iDragStartY; + if( abs( diff ) > iItemHeight / 2 ) + { + iDragStartY += ( ( diff > 0 ) ? iItemHeight : -iItemHeight ); + Playlist_MoveSel( diff < 0 ); + } + + bMoveLock = false; + break; + } + + case WM_LBUTTONDOWN: + { + if( GetKeyState( VK_MENU ) >= 0 ) break; + + // Dragging ON + iDragStartY = HIWORD( lp ); + iItemHeight = ( int )SendMessage( + WindowPlaylist, + LB_GETITEMHEIGHT, + 0, + 0 + ); + bDragging = true; + + return 0; + } + + case WM_LBUTTONUP: + // Dragging OFF + bDragging = false; + break; + + case WM_SYSKEYDOWN: + switch( wp ) // [Alt]+[...] + { + case VK_UP: + Playlist_MoveSel( true ); + break; + + case VK_DOWN: + Playlist_MoveSel( false ); + break; + } + break; + + case WM_CHAR: + case WM_KEYUP: + // SMALL LETTERS!!!!!! + switch( wp ) + { + case 'z': + case 'y': + case 'x': + case 'c': + case 'v': + case 'b': + case 'l': + return 0; + } + break; + + case WM_KEYDOWN: + { + const bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 ); + const bool bControl = ( ( GetKeyState( VK_CONTROL ) & 0x8000 ) != 0 ); + // const bool bAlt = ( ( GetKeyState( VK_MENU ) & 0x8000 ) != 0 ); + + + switch( wp ) + { + case VK_LEFT: + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_REW5S, 0 ); + return 0; + + case VK_RIGHT: + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_FFWD5S, 0 ); + return 0; + + case VK_UP: + if( bControl && !bShift ) + { + // Move caret not selection + const int iCaretBefore = Playlist_GetCaretIndex(); + if( iCaretBefore > 0 ) + { + Playlist_SetCaretIndex( iCaretBefore - 1 ); + } + else if( ( iCaretBefore == 0 ) && bInfinitePlaylist ) + { + Playlist_SetCaretIndex( iMaxIndex ); + } + return 0; + } + else + { + if( bInfinitePlaylist ) + { + if( Playlist_GetCaretIndex() != 0 ) break; + Playlist_SelectSingle( iMaxIndex ); + return 0; // Or it will increase one more + } + } + break; + + case VK_DOWN: + if( bControl && !bShift ) + { + // Move caret not selection + const int iCaretBefore = Playlist_GetCaretIndex(); + if( ( iCaretBefore < iMaxIndex ) && ( iCaretBefore >= 0 ) ) + { + Playlist_SetCaretIndex( iCaretBefore + 1 ); + } + else if( ( iCaretBefore == iMaxIndex ) && bInfinitePlaylist ) + { + Playlist_SetCaretIndex( 0 ); + } + return 0; + } + else + { + if( bInfinitePlaylist ) + { + if( Playlist_GetCaretIndex() != iMaxIndex ) break; + Playlist_SelectSingle( 0 ); + return 0; // Or it will increase one more + } + } + break; + + case VK_SPACE: + if( bControl && !bShift ) + { + const int iCaret = Playlist_GetCaretIndex(); + if( iCaret == -1 ) return 0; + bool bSelected = Playlist_IsSelected( iCaret ); + Playlist_SelectModify( iCaret, !bSelected ); + } + return 0; + + case VK_DELETE: + { + if( bShift ) break; + + if( bControl ) + playlist->RemoveSelected( false ); + else + playlist->RemoveSelected( true ); + + break; + } + + case VK_RETURN: + iCurIndex = Playlist_GetCaretIndex(); + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 ); + return 0; + + case 'Y': + case 'Z': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON1, 0 ); + return 0; + + case 'X': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 ); + return 0; + + case 'C': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON3, 0 ); + return 0; + + case 'V': + // Todo modifiers pressed? -> fadeout/... + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON4, 0 ); + return 0; + + case 'B': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON5, 0 ); + return 0; + / + case 'J': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_JUMPFILE, 0 ); + return 0; + / + case 'L': + if( bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, bShift ? WINAMP_FILE_DIR : WINAMP_FILE_PLAY, 0 ); + return 0; + } + break; + } + + case WM_LBUTTONDBLCLK: + iCurIndex = Playlist_MouseToIndex(); + if( iCurIndex < 0 ) break; + Playback::Play(); + Playback::UpdateSeek(); + break; + + } + return CallWindowProc( WndprocPlaylistBackup, hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::Add( int iIndex, TCHAR * szDisplay, TCHAR * szFilename ) +{ + iMaxIndex++; + if( iIndex < 0 || iIndex > iMaxIndex ) iIndex = iMaxIndex; + if( iIndex <= iCurIndex ) + { + iCurIndex++; + } + + // Create entry data + PlaylistEntry * new_entry = new PlaylistEntry; + new_entry->szFilename = szFilename; + + iIndex = ( int )SendMessage( + WindowPlaylist, + LB_INSERTSTRING, // LB_ADDSTRING, + iIndex, + ( LPARAM )szDisplay + ); + + // Associate data + SendMessage( + WindowPlaylist, + LB_SETITEMDATA, + iIndex, + ( LPARAM )new_entry + ); + + return true; +} +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// Opens a dialog box and loads the playlist if is [true], +/// or saves the playlist if it is [false]. +//////////////////////////////////////////////////////////////////////////////// +bool Playlist_DialogBoth( bool bOpenOrSave ) +{ + TCHAR szFilters[] = TEXT( + "All files (*.*)\0*.*\0" + "Playlist files (*.M3U)\0*.m3u\0" + "\0" + ); + TCHAR szFilename[ MAX_PATH ] = TEXT( "\0" ); + + OPENFILENAME ofn; + memset( &ofn, 0, sizeof( OPENFILENAME ) ); + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = WindowMain; + ofn.hInstance = g_hInstance; + ofn.lpstrFilter = szFilters; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 2; + ofn.lpstrFile = szFilename; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER | + OFN_ENABLESIZING | + ( bOpenOrSave ? OFN_FILEMUSTEXIST : OFN_OVERWRITEPROMPT ) | + OFN_PATHMUSTEXIST | + OFN_HIDEREADONLY; + ofn.nMaxFileTitle = 0, + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = ( bOpenOrSave ? TEXT( "Open playlist" ) : TEXT( "Save playlist" ) ); + + if( bOpenOrSave ) + { + if( !GetOpenFileName( &ofn ) ) return false; + } + else + { + if( !GetSaveFileName( &ofn ) ) return false; + } + + if( bOpenOrSave ) + { + // Open + const int iFilenameLen = ( int )_tcslen( szFilename ); + if( !_tcsncmp( szFilename + iFilenameLen - 3, TEXT( "m3u" ), 3 ) ) + { + // Playlist file + playlist->RemoveAll(); + Playlist::AppendPlaylistFile( szFilename ); + Playback::Play(); + } + } + else + { + // TODO: Check extension, ask for appending if missing + + // Save + Playlist::ExportPlaylistFile( szFilename ); + } + + return true; + +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Opens a dialog box and loads the selected playlist +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::DialogOpen() +{ + return Playlist_DialogBoth( true ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Opens a dialog box and saves the playlist to the filename selected +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::DialogSaveAs() +{ + return Playlist_DialogBoth( false ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::AppendPlaylistFile( TCHAR * szFilename ) +{ + // Open playlist file + HANDLE hFile = CreateFile( + szFilename, // LPCTSTR lpFileName + FILE_READ_DATA, // DWORD dwDesiredAccess + FILE_SHARE_READ, // DWORD dwShareMode + NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes + OPEN_EXISTING, // DWORD dwCreationDisposition + FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes + NULL // HANDLE hTemplateFile + ); + + if( hFile == INVALID_HANDLE_VALUE ) + { + // MessageBox( 0, TEXT( "Could not read playlist file" ), TEXT( "Error" ), MB_ICONERROR ); + return false; + } + + const bool bEmptyBefore = ( playlist->GetSize() == 0 ); + + + // Remove filename from so we can + // use it as relative directory root + TCHAR * szWalk = szFilename + _tcslen( szFilename ) - 1; + while( ( szWalk > szFilename ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk--; + szWalk++; + *szWalk = TEXT( '\0' ); + + TCHAR * szBaseDir = szFilename; + const int iBaseDirLen = ( int )_tcslen( szBaseDir ); + + + DWORD iSizeBytes = GetFileSize( hFile, NULL ); + if( iSizeBytes <= 0 ) + { + CloseHandle( hFile ); + return false; + } + + // Allocate + char * rawdata = new char[ iSizeBytes + 1 ]; // One more so we can write '\0' on EOF + DWORD iBytesRead; + + // Read whole file + ReadFile( + hFile, // HANDLE hFile + rawdata, // LPVOID lpBuffer + iSizeBytes, // DWORD nNumberOfBytesToRead + &iBytesRead, // LPDWORD lpNumberOfBytesRead + NULL // LPOVERLAPPED lpOverlapped + ); + + if( iBytesRead < iSizeBytes ) + { + delete [] rawdata; + CloseHandle( hFile ); + + MessageBox( 0, TEXT( "Could not read whole file" ), TEXT( "Error" ), MB_ICONERROR ); + return false; + } + + // Parse file content + + // File must be + // * M3U + // * ANSI + + char * walk = rawdata; + const char * eof = rawdata + iSizeBytes; + + char * beg = rawdata; + char * end; + + while( true ) + { + // Find newline or eof + while( ( walk < eof ) && ( *walk != '\015' ) && ( *walk != '\012' ) ) walk++; + end = walk; + + if( ( end - beg > 2 ) && ( *beg != '#' ) ) + { + TCHAR * szKeep; + if( beg[ 1 ] == ':' ) + { + // TODO: Better detection, network path? + + // Absolute path + const int iLen = end - beg; + szKeep = new TCHAR[ iLen + 1 ]; + ToTchar( szKeep, beg, iLen ); + szKeep[ iLen ] = TEXT( '\0' ); + } + else + { + // Skip initial so we don't get a double backslash in between + while( ( beg[ 0 ] == '\\' ) && ( beg < end ) ) beg++; + + // Relative path + const int iSecondLen = end - beg; + szKeep = new TCHAR[ iBaseDirLen + iSecondLen + 1 ]; + memcpy( szKeep, szBaseDir, iBaseDirLen * sizeof( TCHAR ) ); + ToTchar( szKeep + iBaseDirLen, beg, iSecondLen ); + + szKeep[ iBaseDirLen + iSecondLen ] = TEXT( '\0' ); + + UnbloatFilename( szKeep, false ); + } + + // if( !Add( iMaxIndex + 1, szKeep, szKeep ) ) break; + playlist->PushBack( szKeep ); + } + + // Skip newlines + while( ( walk < eof ) && ( ( *walk == '\015' ) || ( *walk == '\012' ) ) ) walk++; + if( walk == eof ) + { + break; + } + + beg = walk; + } + + delete [] rawdata; + CloseHandle( hFile ); +/* + if( bEmptyBefore ) + { + iCurIndex = 0; + } +*/ + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::ExportPlaylistFile( TCHAR * szFilename ) +{ + // Open playlist file + HANDLE hFile = CreateFile( + szFilename, // LPCTSTR lpFileName + FILE_WRITE_DATA, // DWORD dwDesiredAccess + 0, // DWORD dwShareMode + NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes + CREATE_ALWAYS, // DWORD dwCreationDisposition + FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes + NULL // HANDLE hTemplateFile + ); + + if( hFile == INVALID_HANDLE_VALUE ) + { + MessageBox( 0, TEXT( "Could not write playlist file" ), TEXT( "Error" ), MB_ICONERROR ); + return false; + } + + + // Remove filename from so we can + // use it as relative directory root + TCHAR * szWalk = szFilename + _tcslen( szFilename ) - 1; + while( ( szWalk > szFilename ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk--; + szWalk++; + *szWalk = TEXT( '\0' ); + + TCHAR * szBaseDir = szFilename; + const int iBaseDirLen = ( int )_tcslen( szBaseDir ); + + + char * rawdata = new char[ ( playlist->GetMaxIndex() + 1 ) * ( MAX_PATH + 2 ) ]; + char * walk = rawdata; + + // Write playlist to buffer + const int iMaxMax = playlist->GetMaxIndex(); + for( int i = 0; i <= iMaxMax; i++ ) + { + // Get + TCHAR * szEntry = GetFilename( i ); + if( !szEntry ) break; + int iEntryLen = ( int )_tcslen( szEntry ); + + // Copy + TCHAR * szTemp = new TCHAR[ iEntryLen + 1 ]; + memcpy( szTemp, szEntry, iEntryLen * sizeof( TCHAR ) ); + szTemp[ iEntryLen ] = TEXT( '\0' ); + + // Convert + if( ApplyRootToFilename( szBaseDir, szTemp ) ) + { + // Update length or we are writing too much + iEntryLen = ( int )_tcslen( szTemp ); + } + + // Copy +#ifdef PA_UNICODE + ToAnsi( walk, szTemp, iEntryLen ); +#else + memcpy( walk, szTemp, iEntryLen ); +#endif + + delete [] szTemp; + + walk += iEntryLen; + memcpy( walk, "\015\012", 2 ); + walk += 2; + } + + const DWORD iSizeBytes = walk - rawdata; + DWORD iBytesRead; + WriteFile( + hFile, // HANDLE hFile, + rawdata, // LPCVOID lpBuffer, + iSizeBytes, // DWORD nNumberOfBytesToWrite, + &iBytesRead, // LPDWORD lpNumberOfBytesWritten, + NULL // LPOVERLAPPED lpOverlapped + ); + + if( iBytesRead < iSizeBytes ) + { + delete [] rawdata; + CloseHandle( hFile ); + + MessageBox( 0, TEXT( "Could not write whole file" ), TEXT( "Error" ), MB_ICONERROR ); + return false; + } + + delete [] rawdata; + CloseHandle( hFile ); + + return true; +} + + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::Append( TCHAR * szDisplay, TCHAR * szFilename ) +{ + return Add( iMaxIndex + 1, szDisplay, szFilename ); +} +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +TCHAR * Playlist::GetFilename( int iIndex ) +{ + // if( iIndex < 0 || iIndex > iMaxIndex ) return NULL; + +/* + PlaylistEntry * entry = ( PlaylistEntry * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + iIndex, + 0 + ); + + return ( entry ? entry->szFilename : NULL ); + */ + + return ( TCHAR * )playlist->Get( iIndex ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playlist::GetFilename( int iIndex, char * szAnsiFilename, int iChars ) +{ + // if( iIndex < 0 || iIndex > iMaxIndex ) return 0; + /* + PlaylistEntry * entry = ( PlaylistEntry * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + iIndex, + 0 + ); + if( !entry || !entry->szFilename ) return 0; + + TCHAR * & szFilename = entry->szFilename; + */ + TCHAR * szFilename = ( TCHAR * )playlist->Get( iIndex ); + + const int iFilenameLen = ( int )_tcslen( szFilename ); + const int iCopyLen = ( iFilenameLen < iChars ) ? iFilenameLen : iChars; + +#ifdef PA_UNICODE + ToAnsi( szAnsiFilename, szFilename, iCopyLen ); +#else + memcpy( szAnsiFilename, szFilename, iCopyLen ); +#endif + + szAnsiFilename[ iCopyLen ] = '\0'; + return iCopyLen; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int Playlist::GetTitle( int iIndex, char * szAnsiTitle, int iChars ) +{ + // if( iIndex < 0 || iIndex > iMaxIndex ) return 0; + /* + TCHAR * szFilename = ( TCHAR * )SendMessage( + WindowPlaylist, + LB_GETITEMDATA, + iIndex, + 0 + ); + if( !szFilename ) return 0; + */ + TCHAR * szFilename = ( TCHAR * )playlist->Get( iIndex ); + + // Get extension + const int iFilenameLen = ( int )_tcslen( szFilename ); + TCHAR * szExt = szFilename + iFilenameLen - 1; + while( ( szExt > szFilename ) && ( *szExt != TEXT( '.' ) ) ) szExt--; + szExt++; + + // Get plugin for extension + map ::iterator iter = ext_map.find( szExt ); + if( iter == ext_map.end() ) return 0; + InputPlugin * input_plugin = iter->second; + +#ifdef PA_UNICODE + // Filename + char * szTemp = new char[ iFilenameLen + 1 ]; + ToAnsi( szTemp, szFilename, iFilenameLen ); + szTemp[ iFilenameLen ] = '\0'; + + // Ansi Title + char szTitle[ 2000 ] = "\0"; + int length_in_ms; + input_plugin->plugin->GetFileInfo( szTemp, szTitle, &length_in_ms ); + const int iTitleLen = strlen( szTitle ); + memcpy( szAnsiTitle, szTitle, iChars * sizeof( char ) ); + szTitle[ iChars ] = '\0'; +#else + char szTitle[ 2000 ] = "\0"; + int length_in_ms; + input_plugin->plugin->GetFileInfo( szFilename, szTitle, &length_in_ms ); + const int iTitleLen = ( int )strlen( szAnsiTitle ); + memcpy( szAnsiTitle, szTitle, iChars * sizeof( char ) ); + szTitle[ iChars ] = '\0'; +#endif + + return ( iTitleLen < iChars ) ? iTitleLen : iChars; +} + + +/* +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::SelectZero() +{ + SendMessage( + WindowPlaylist, + LB_SETSEL, + FALSE, + -1 + ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Playlist::SelectAll() +{ + SendMessage( + WindowPlaylist, + LB_SETSEL, + TRUE, + -1 + ); + return true; +} +*/ diff --git a/Branches/MusicMod/Player/Src/Playlist.h b/Branches/MusicMod/Player/Src/Playlist.h new file mode 100644 index 0000000000..a56ffe373d --- /dev/null +++ b/Branches/MusicMod/Player/Src/Playlist.h @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PLAYLIST_H +#define PA_PLAYLIST_H + + + +#include "Global.h" +#include "PlaylistControler.h" +#include "PlaylistView.h" + + +#define PLAINAMP_PL_REM_SEL 50004 +#define PLAINAMP_PL_REM_CROP 50005 + + + +extern HWND WindowPlaylist; + +extern PlaylistControler * playlist; + +namespace Playlist +{ + bool Create(); +/* + int GetCurIndex(); + int GetMaxIndex(); + bool SetCurIndex( int iIndex ); +*/ + TCHAR * GetFilename( int iIndex ); + + int GetFilename( int iIndex, char * szAnsiFilename, int iChars ); + int GetTitle( int iIndex, char * szAnsiTitle, int iChars ); + + bool DialogOpen(); + bool DialogSaveAs(); + + bool AppendPlaylistFile( TCHAR * szFilename ); + bool ExportPlaylistFile( TCHAR * szFilename ); +/* + bool Append( TCHAR * szDisplay, TCHAR * szFilename ); + bool Add( int iIndex, TCHAR * szDisplay, TCHAR * szFilename ); + + bool Clear(); // aka RemoveAll() + bool RemoveSelected(); + bool Crop(); // aka RemoveUnselected + + bool SelectZero(); + bool SelectAll(); +*/ +}; + + + +#endif // PA_PLAYLIST_H diff --git a/Branches/MusicMod/Player/Src/PlaylistControler.cpp b/Branches/MusicMod/Player/Src/PlaylistControler.cpp new file mode 100644 index 0000000000..f0a67d5a4e --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaylistControler.cpp @@ -0,0 +1,451 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "PlaylistControler.h" +#include "Config.h" +#include "Font.h" + +bool bPlaylistFollow; +ConfBool cbPlaylistFollow( &bPlaylistFollow, TEXT( "PlaylistFollow" ), CONF_MODE_PUBLIC, true ); + + +void PlaylistControler::MoveSelected( int iDistance ) +{ + if( iDistance == -1 ) + { + if( ListView_GetItemState( _hView, 0, LVIS_SELECTED ) ) + { + // Cannot move upwards + return; + } + } + else if( iDistance == 1 ) + { + if( ListView_GetItemState( _hView, _database.GetMaxIndex(), LVIS_SELECTED ) ) + { + // Cannot move downwards + return; + } + } + else + { + // More distance maybe later + return; + } + + const int iFocus = ListView_GetNextItem( _hView, ( UINT )-1, LVIS_FOCUSED ); + + // Negative is to the top + LRESULT iBefore = 0; + LRESULT iAfter = -2; // Extra value to check after big for-loop + + for( ; ; ) + { + // Count + LRESULT iAfter = ListView_GetNextItem( _hView, iBefore - 1, LVNI_SELECTED ); + if( iAfter == -1 ) break; // No more selections selected + + LRESULT iFirst = iAfter; + + // Search end of selection block + iBefore = iAfter + 1; + for( ; ; ) + { + iAfter = ListView_GetNextItem( _hView, iBefore - 1, LVNI_SELECTED ); + if( iAfter == iBefore ) + { + // Keep searching + iBefore++; + } + else + { + // End found (iBefore is the first not selected) + const int iSelSize = iBefore - iFirst; + if( iDistance == -1 ) + { + // Updwards + const int iOldIndex = iFirst - 1; + const int iNewIndex = iOldIndex + iSelSize; + + TCHAR * szData = ( TCHAR * )_database.Get( iOldIndex ); + _database.Erase( iOldIndex ); + _database.Insert( iNewIndex, szData ); + + ListView_SetItemState( _hView, iOldIndex, LVIS_SELECTED, LVIS_SELECTED ); + ListView_SetItemState( _hView, iNewIndex, 0, LVIS_SELECTED ); + ListView_RedrawItems( _hView, iOldIndex, iNewIndex ); + } + else + { + // Downwards + const int iOldIndex = iFirst + iSelSize; + const int iNewIndex = iFirst; + + TCHAR * szData = ( TCHAR * )_database.Get( iOldIndex ); + _database.Erase( iOldIndex ); + _database.Insert( iNewIndex, szData ); + + ListView_SetItemState( _hView, iOldIndex, LVIS_SELECTED, LVIS_SELECTED ); + ListView_SetItemState( _hView, iNewIndex, 0, LVIS_SELECTED ); + ListView_RedrawItems( _hView, iNewIndex, iOldIndex ); + } + + iBefore++; + break; + } + } + } + + if( iAfter != -2 ) return; // Nothing was selected so nothing was moved + ListView_SetItemState( _hView, iFocus + iDistance, LVIS_FOCUSED, LVIS_FOCUSED ); + + Refresh(); +} + +int PlaylistControler::GetCurIndex() +{ + return _database.GetCurIndex(); +} + +int PlaylistControler::GetMaxIndex() +{ + return _database.GetMaxIndex(); +} + +int PlaylistControler::GetSize() +{ + return _database.GetSize(); +} + +void PlaylistControler::SetCurIndex( int iIndex ) +{ + const int iCurIndexBefore = _database.GetCurIndex(); + _database.SetCurIndex( iIndex ); + + if( bPlaylistFollow ) + { + ListView_SetItemState( _hView, ( UINT )-1, 0, LVIS_SELECTED | LVIS_FOCUSED ); + ListView_SetItemState( _hView, iIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); + } + + if( iCurIndexBefore != -1 ) + ListView_RedrawItems( _hView, iCurIndexBefore, iCurIndexBefore ); + ListView_RedrawItems( _hView, iIndex, iIndex ); +} + +// Returns on digit count change +bool PlaylistControler::FixDigitsMore() +{ + const int iCountAfter = _database.GetSize(); + const int iDigitsBefore = _iDigits; + while( iCountAfter > _iDigitMax ) + { + _iDigitMin *= 10; // 10 -> 100 + _iDigitMax = _iDigitMax * 10 + 9; // 99 -> 999 + _iDigits++; // 2 -> 3 + } + + + return ( ( _iDigits != iDigitsBefore ) + || ( iCountAfter == 1 ) ); // Force update when first item is inserted +} + +// Returns on digit count change +bool PlaylistControler::FixDigitsLess() +{ + const int iCountAfter = _database.GetSize(); + const int iDigitsBefore = _iDigits; + while( ( iCountAfter < _iDigitMin ) && ( _iDigits > 1 ) ) + { + _iDigitMin /= 10; // 999 -> 99 + _iDigitMax /= 10; // 100 -> 10 + _iDigits--; // 3 -> 2 + } + + return ( _iDigits != iDigitsBefore ); +} + + +void PlaylistControler::Refresh() +{ + AutosizeColumns(); + + const int iFirst = ListView_GetTopIndex( _hView ); + const int iLast = iFirst + ListView_GetCountPerPage( _hView ); + + ListView_RedrawItems( _hView, iFirst, iLast ); +} + +PlaylistControler::PlaylistControler( HWND hView, bool bEnableZeroPadding, int * piIndexSlave ) +{ + _hView = hView; + + _bZeroPadding = bEnableZeroPadding; + _iDigits = 1; + _iDigitMin = 1; + _iDigitMax = 9; + + _database.SetCurIndexSlave( piIndexSlave ); + + Refresh(); + + // TODO clear list view here??? +} + + +void PlaylistControler::PushBack( TCHAR * szText ) +{ + const int iSize = _database.GetMaxIndex(); + + _database.PushBack( szText ); + ListView_SetItemCount( _hView, _database.GetSize() ); + + if( FixDigitsMore() ) Refresh(); +} + +void PlaylistControler::Insert( int i, TCHAR * szText ) +{ + const int iSize = _database.GetMaxIndex(); + + _database.Insert( i, szText ); + ListView_SetItemCount( _hView, _database.GetSize() ); + + if( FixDigitsMore() ) Refresh(); +} + +void PlaylistControler::RemoveAll() +{ + _database.Clear(); + ListView_DeleteAllItems( _hView ); + + if( FixDigitsLess() ) Refresh(); +} + +void PlaylistControler::RemoveSelected( bool bPositive ) +{ + SendMessage( _hView, WM_SETREDRAW, FALSE, 0 ); + + if( bPositive ) + { + LRESULT iWalk = 0; + for( ; ; ) + { + // MSDN: The specified item itself is excluded from the search. + iWalk = ListView_GetNextItem( _hView, iWalk - 1, LVNI_SELECTED ); + if( iWalk != -1 ) + { + _database.Erase( iWalk ); + ListView_DeleteItem( _hView, iWalk ); + } + else + { + break; + } + } + } + else + { + LRESULT iBefore = 0; + LRESULT iAfter = 0; + for( ; ; ) + { + // MSDN: The specified item itself is excluded from the search. + iAfter = ListView_GetNextItem( _hView, iBefore - 1, LVNI_SELECTED ); + if( iAfter != -1 ) + { + // is the first selected + // so we delete all before and restart + // at the beginning + const int iDelIndex = iBefore; + for( int i = iBefore; i < iAfter; i++ ) + { + _database.Erase( iDelIndex ); + ListView_DeleteItem( _hView, iDelIndex ); + } + + iBefore++; // Exclude the one we found selected right before + } + else + { + if( iBefore == 0 ) + { + // All selected + _database.Clear(); + ListView_DeleteAllItems( _hView ); + } + else + { + const int iSize = _database.GetSize(); + const int iDelIndex = iBefore; + for( int i = iBefore; i < iSize; i++ ) + { + _database.Erase( iDelIndex ); + ListView_DeleteItem( _hView, iDelIndex ); + } + } + + break; + } + } + } + + bool bRefresh = FixDigitsLess(); + + SendMessage( _hView, WM_SETREDRAW, TRUE, 0 ); + + if( bRefresh ) Refresh(); +} + +void PlaylistControler::SelectAll( bool bPositive ) +{ + ListView_SetItemState( _hView, ( UINT )-1, bPositive ? LVIS_SELECTED : 0, LVIS_SELECTED ); +} + +void PlaylistControler::SelectInvert() +{ + SendMessage( _hView, WM_SETREDRAW, FALSE, 0 ); + + const int iOneTooMuch = _database.GetSize(); + for( int i = 0; i < iOneTooMuch; i++ ) + { + ListView_SetItemState( + _hView, + i, + ( ListView_GetItemState( _hView, i, LVIS_SELECTED ) == LVIS_SELECTED ) + ? 0 + : LVIS_SELECTED, + LVIS_SELECTED + ); + + } + + SendMessage( _hView, WM_SETREDRAW, TRUE, 0 ); +} + +const TCHAR * PlaylistControler::Get( int i ) +{ + return _database.Get( i ); +} + +void PlaylistControler::Fill( LVITEM & request ) +{ + if( ( request.mask & LVIF_TEXT ) == 0 ) return; + if( request.iSubItem ) + { + // Text + _sntprintf( request.pszText, request.cchTextMax, TEXT( "%s" ), _database.Get( request.iItem ) ); + } + else + { + // Number + if( _bZeroPadding ) + { + TCHAR szFormat[ 6 ]; + _stprintf( szFormat, TEXT( "%%0%dd" ), _iDigits ); + _sntprintf( request.pszText, request.cchTextMax, szFormat, request.iItem + 1 ); + } + else + { + _sntprintf( request.pszText, request.cchTextMax, TEXT( "%d" ), request.iItem + 1 ); + } + } +} + +void PlaylistControler::EnableZeroPadding( bool bActive ) +{ + if( bActive == _bZeroPadding ) return; + + LVCOLUMN col; + memset( &col, 0, sizeof( LVCOLUMN ) ); + col.mask = LVCF_FMT; + + if( bActive ) + { + // TODO recalculation yes/no? + /* + int iSize = _database.GetSize(); + if( iSize != 0 ) + { + int iDigits = 0; + while( iSize > 0 ) + { + iSize /= 10; + iDigits++; + } + + _iDigits = iSize; + _iDigitMin = 1; + _iDigitMax = 9; + while( iSize-- > 0 ) + { + _iDigitMin *= 10; + _iDigitMax = _iDigitMax * 10 + 9; + } + } + else + { + _iDigits = 1; + _iDigitMin = 1; + _iDigitMax = 9; + } + */ + + col.fmt = LVCFMT_LEFT; + ListView_SetColumn( _hView, 0, &col ); + + Refresh(); + } + else + { + col.fmt = LVCFMT_RIGHT; + ListView_SetColumn( _hView, 0, &col ); + + Refresh(); + } + _bZeroPadding = bActive; +} + +void PlaylistControler::AutosizeColumns() +{ + RECT r; + if( !GetClientRect( _hView, &r ) ) return; + + if( _bZeroPadding ) + { + ListView_SetColumnWidth( _hView, 0, LVSCW_AUTOSIZE ); + const int iWidth = ListView_GetColumnWidth( _hView, 0 ); + ListView_SetColumnWidth( _hView, 1, r.right - r.left - iWidth ); + } + else + { + HDC hdc = GetDC( _hView ); + const HFONT hOldFont = ( HFONT )SelectObject( hdc, Font::Get() ); + SIZE size; + BOOL res = GetTextExtentPoint32( hdc, TEXT( "0" ), 1, &size ); + SelectObject( hdc, hOldFont ); + ReleaseDC( _hView, hdc ); + const int iWidth = res ? ( int )( size.cx * ( _iDigits + 0.25f ) ) : 120; + ListView_SetColumnWidth( _hView, 0, iWidth ); + ListView_SetColumnWidth( _hView, 1, r.right - r.left - iWidth ); + } +} + +void PlaylistControler::Resize( HWND hParent ) +{ + /* + RECT rc; + GetClientRect( hParent, &rc ); + MoveWindow( _hView, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE ); + */ + + AutosizeColumns(); +} diff --git a/Branches/MusicMod/Player/Src/PlaylistControler.h b/Branches/MusicMod/Player/Src/PlaylistControler.h new file mode 100644 index 0000000000..cc85f5e317 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaylistControler.h @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PLAYLIST_CONTROLER_H +#define PLAYLIST_CONTROLER_H 1 + +#include +#include +#include +#include "PlaylistModel.h" + + + +// TODO: column width update on scrollbar show/hide + +class PlaylistControler +{ + PlaylistModel _database; + HWND _hView; + + bool _bZeroPadding; + int _iDigits; // 3 + int _iDigitMin; // 100 + int _iDigitMax; // 999 + +private: + bool FixDigitsMore(); + bool FixDigitsLess(); + void Refresh(); + void AutosizeColumns(); + +public: + PlaylistControler( HWND hView, bool bEnableZeroPadding, int * piIndexSlave ); + + void MoveSelected( int iDistance ); + + int GetCurIndex(); + int GetMaxIndex(); + int GetSize(); + void SetCurIndex( int iIndex ); + + void PushBack( TCHAR * szText ); + void Insert( int i, TCHAR * szText ); + void RemoveAll(); + void RemoveSelected( bool bPositive ); + void SelectAll( bool bPositive ); + void SelectInvert(); + + const TCHAR * Get( int i ); + + void Fill( LVITEM & request ); + void EnableZeroPadding( bool bActive ); + void Resize( HWND hParent ); +}; + +#endif // PLAYLIST_CONTROLER_H diff --git a/Branches/MusicMod/Player/Src/PlaylistModel.h b/Branches/MusicMod/Player/Src/PlaylistModel.h new file mode 100644 index 0000000000..c850772e20 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaylistModel.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PLAYLIST_MODEL_H +#define PLAYLIST_MODEL_H 1 + +#include +#include +#include +using namespace std; + + + +class PlaylistModel +{ + vector _database; + int _iCurIndex; + int * _piCurIndex; + +public: + PlaylistModel() + { + _piCurIndex = &_iCurIndex; + } + + PlaylistModel( int * piIndexSlave ) + { + _piCurIndex = piIndexSlave; + } + + void SetCurIndexSlave( int * piIndexSlave ) + { + // *piIndexSlave = *_piCurIndex; + _piCurIndex = piIndexSlave; + } + + void PushBack( TCHAR * szText ) + { + _database.push_back( szText ); + } + + void Insert( int i, TCHAR * szText ) + { + if( i <= *_piCurIndex ) ( *_piCurIndex )++; + _database.insert( _database.begin() + i, szText ); + } + + void Erase( int i ) + { + if( i < *_piCurIndex ) ( *_piCurIndex )--; + _database.erase( _database.begin() + i ); + } + + const TCHAR * Get( int i ) + { + if( 0 > i || i >= ( int )_database.size() ) + { + static const TCHAR * szError = TEXT( "INDEX OUT OF RANGE" ); + return szError; + } + + return _database[ i ]; + } + + void Clear() + { + _database.clear(); + *_piCurIndex = -1; + } + + int GetMaxIndex() + { + return _database.size() - 1; + } + + int GetCurIndex() + { + return *_piCurIndex; + } + + void SetCurIndex( int iIndex ) + { + if( 0 > iIndex || iIndex >= ( int )_database.size() ) return; + *_piCurIndex = iIndex; + } + + int GetSize() + { + return _database.size(); + } +}; + + +#endif // PLAYLIST_MODEL_H diff --git a/Branches/MusicMod/Player/Src/PlaylistView.cpp b/Branches/MusicMod/Player/Src/PlaylistView.cpp new file mode 100644 index 0000000000..db3fec3cee --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaylistView.cpp @@ -0,0 +1,772 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Playlist.h" +#include "Main.h" +#include "Status.h" +#include "Rebar.h" +#include "Playback.h" +#include "Config.h" +#include "Util.h" + +WNDPROC WndprocPlaylistBackup = NULL; +LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + +PlaylistControler * playlist = NULL; // extern + +bool bPlaylistEntryNumberZeroPadding; +ConfBool cbPlaylistEntryNumberZeroPadding( &bPlaylistEntryNumberZeroPadding, TEXT( "PlaylistEntryNumberZeroPadding" ), CONF_MODE_PUBLIC, true ); + +int iCurPlaylistPosition; +ConfInt ciCurPlaylistPosition( &iCurPlaylistPosition, TEXT( "CurPlaylistPosition" ), CONF_MODE_INTERNAL, -1 ); + +bool bInfinitePlaylist; +ConfBool cbInfinitePlaylist( &bInfinitePlaylist, TEXT( "InfinitePlaylist" ), CONF_MODE_PUBLIC, false ); + + +void PlaylistView::Create() +{ + RECT ClientMain; + GetClientRect( WindowMain, &ClientMain ); + + const int iClientHeight = ClientMain.bottom - ClientMain.top; + const int iClientWidth = ClientMain.right - ClientMain.left; + const int iPlaylistHeight = iClientHeight - iRebarHeight - iStatusHeight; + + + + LoadCommonControls(); + + + DWORD dwStyle; + // HWND WindowPlaylist; + BOOL bSuccess = TRUE; + + dwStyle = WS_TABSTOP | + WS_CHILD | + WS_BORDER | + WS_VISIBLE | + LVS_AUTOARRANGE | // TODO + LVS_REPORT | + LVS_OWNERDATA | + LVS_NOCOLUMNHEADER ; + + WindowPlaylist = CreateWindowEx( WS_EX_CLIENTEDGE, // ex style + WC_LISTVIEW, // class name - defined in commctrl.h + TEXT( "" ), // dummy text + dwStyle, // style + 0, + iRebarHeight, // + -2, + iClientWidth, + iPlaylistHeight, + WindowMain, // parent + NULL, // ID + g_hInstance, // instance + NULL); // no extra data + + if(!WindowPlaylist) return; // TODO + + +playlist = new PlaylistControler( WindowPlaylist, bPlaylistEntryNumberZeroPadding, &iCurPlaylistPosition ); + + + // Exchange window procedure + WndprocPlaylistBackup = ( WNDPROC )GetWindowLong( WindowPlaylist, GWL_WNDPROC ); + if( WndprocPlaylistBackup != NULL ) + { + SetWindowLong( WindowPlaylist, GWL_WNDPROC, ( LONG )WndprocPlaylist ); + } + + + ListView_SetExtendedListViewStyle( WindowPlaylist, LVS_EX_FULLROWSELECT ); // | LVS_EX_GRIDLINES ); + playlist->Resize( WindowMain ); + +/* + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/listview/structures/lvcolumn.asp + * + * Remarks: + * If a column is added to a list-view control with index 0 (the leftmost column) + * and with LVCFMT_RIGHT or LVCFMT_CENTER specified, the text is not right-aligned + * or centered. The text in the index 0 column is left-aligned. Therefore if you + * keep inserting columns with index 0, the text in all columns are left-aligned. + * If you want the first column to be right-aligned or centered you can make a dummy + * column, then insert one or more columns with index 1 or higher and specify the + * alignment you require. Finally delete the dummy column. + */ + +LV_COLUMN lvColumn; +memset( &lvColumn, 0, sizeof( LV_COLUMN ) ); +lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; + +// Number column (with dummy hack) +lvColumn.fmt = LVCFMT_LEFT; +lvColumn.cx = 0; +lvColumn.pszText = TEXT( "" ); +ListView_InsertColumn( WindowPlaylist, 0, &lvColumn ); +lvColumn.fmt = LVCFMT_RIGHT; +lvColumn.cx = 120; +lvColumn.pszText = TEXT( "" ); +ListView_InsertColumn( WindowPlaylist, 1, &lvColumn ); +ListView_DeleteColumn( WindowPlaylist, 0 ); + +// Entry +lvColumn.fmt = LVCFMT_LEFT; +lvColumn.cx = 120; +lvColumn.pszText = TEXT( "Filename" ); +ListView_InsertColumn(WindowPlaylist, 1, &lvColumn); + + + +/* +stupid test code + +SCROLLINFO scrollinfo; +ZeroMemory( &scrollinfo, sizeof( SCROLLINFO ) ); +scrollinfo.cbSize = sizeof( SCROLLINFO ); +scrollinfo.fMask = 0; // SIF_DISABLENOSCROLL; + +if( !GetScrollInfo( WindowPlaylist, SB_VERT, &scrollinfo ) ) +{ + MessageBox( 0, "ERROR", "", 0 ); +} +else +{ + MessageBox( 0, "OKAY", "", 0 ); + scrollinfo.fMask = SIF_DISABLENOSCROLL; + SetScrollInfo( WindowPlaylist, SB_VERT, &scrollinfo, TRUE ); +} + +if( !ShowScrollBar( WindowPlaylist, SB_VERT, TRUE ) ) +{ + MessageBox( 0, "ERROR ShowScrollBar", "", 0 ); +} + + +SCROLLBARINFO scrollbarinfo; +scrollbarinfo.cbSize = sizeof( SCROLLBARINFO ); +if( !GetScrollBarInfo( WindowPlaylist, OBJID_VSCROLL, &scrollbarinfo ) ) +{ + MessageBox( 0, "ERROR GetScrollBarInfo", "", 0 ); +} +*/ + +} + + + + + + + + + +// Dragging +static int iItemHeight = 15; +static int iDragStartY = 0; +static bool bDragging = false; + +// Liquid selection +static bool bLiquidSelecting = false; +static int iLastTouched = -1; + +// Liquid or range selection +static int iSelAnchor = -1; + +LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + /* + * Click, click and click + * + * [Alt] [Ctrl] [Shift] Action + * -------+---------+---------+----------------------- + * X | X | X | + * X | X | | + * X | | X | + * X | | | + * | X | X | Range selection + * | X | | Toggle selection + * | | X | Range selection + * | | | Single selection + * + * + * Click, hold and move + * + * [Alt] [Ctrl] [Shift] Action + * -------+---------+---------+----------------------- + * X | X | X | Selection move + * X | X | | Selection move + * X | | X | Selection move + * X | | | Selection move + * | X | X | + * | X | | + * | | X | + * | | | Liquid selection + */ + + static bool bCapturing = true; + + switch( message ) + { +/* + case WM_CAPTURECHANGED: + if( bCapturing && ( GetCapture() != WindowPlaylist ) ) + { + MessageBox( 0, TEXT( "Capture stolen" ), TEXT( "" ), 0 ); + } + break; +*/ + case WM_MOUSEMOVE: + if( bLiquidSelecting ) + { + LVHITTESTINFO hittest; + memset( &hittest, 0, sizeof( LVHITTESTINFO ) ); + hittest.pt.x = LOWORD( lp ); + hittest.pt.y = HIWORD( lp ); + const int iIndex = ( int )ListView_HitTest( WindowPlaylist, &hittest ); + if( iIndex == -1 ) return 0; + if( iIndex == iLastTouched ) return 0; + + // Note: Update this as early as possible! + // We cannot be sure this code is + // not called two or three times at the + // same time without losing much speed + // but this at least lowers the chance + const int iLastTouchedBackup = iLastTouched; + iLastTouched = iIndex; + + const bool bControl = ( ( GetKeyState( VK_CONTROL ) & 0x8000 ) != 0 ); + + + + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVIS_FOCUSED ); + ListView_SetItemState( WindowPlaylist, iIndex, LVIS_FOCUSED, LVIS_FOCUSED ); + + // Below anchor? + if( iIndex > iSelAnchor ) + { + if( iIndex > iLastTouchedBackup ) + { + // iSelAnchor + // .. + // iLastTouchedBackup + // .. + // >> iIndex << + if( iLastTouchedBackup > iSelAnchor ) + { + // Select downwards + for( int i = iLastTouchedBackup + 1; i <= iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + + // iLastTouchedBackup + // .. + // iSelAnchor + // .. + // >> iIndex << + else + { + // Unselect downwards + for( int i = iLastTouchedBackup; i < iSelAnchor; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + + // Select downwards + for( int i = iSelAnchor + 1; i <= iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + } + else // iIndex < iLastTouchedBackup + { + // iSelAnchor + // .. + // >> iIndex << + // .. + // iLastTouchedBackup + + // Unselect upwards + for( int i = iLastTouchedBackup; i > iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + + // Above anchor? + else if( iIndex < iSelAnchor ) + { + if( iIndex < iLastTouchedBackup ) + { + // >> iIndex << + // .. + // iSelAnchor + // .. + // iLastTouchedBackup + if( iIndex < iLastTouchedBackup ) + { + // Unselect upwards + for( int i = iLastTouchedBackup; i > iSelAnchor; i-- ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + + // Select upwards + for( int i = iSelAnchor - 1; i >= iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + + // >> iIndex << + // .. + // iLastTouchedBackup + // .. + // iSelAnchor + else // iIndex < iLastTouchedBackup + { + // Select upwards + for( int i = iLastTouchedBackup - 1; i >= iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + } + else // iIndex > iLastTouchedBackup + { + // iLastTouchedBackup + // .. + // >> iIndex << + // .. + // iSelAnchor + + // Unselect downwards + for( int i = iLastTouchedBackup; i < iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + + // At anchor + else // iIndex == iSelAnchor + { + if( iIndex < iLastTouchedBackup ) + { + // iSelAnchor / >> iIndex << + // .. + // iLastTouchedBackup + + // Unselect upwards + for( int i = iLastTouchedBackup; i > iSelAnchor; i-- ) + { + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + else // iIndex > iLastTouchedBackup + { + // iLastTouchedBackup + // .. + // iSelAnchor / >> iIndex << + + // Unselect downwards + for( int i = iLastTouchedBackup; i < iSelAnchor; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + } + else if( bDragging ) + { + static bool bMoveLock = false; + + if( bMoveLock ) return 0; + bMoveLock = true; + + const int y = HIWORD( lp ); + const int diff = y - iDragStartY; + if( abs( diff ) > iItemHeight / 2 ) + { + iDragStartY += ( ( diff > 0 ) ? iItemHeight : -iItemHeight ); + playlist->MoveSelected( ( diff > 0 ) ? +1 : -1 ); + } + + bMoveLock = false; + } + return 0; + + case WM_LBUTTONDOWN: + { + static int iLastClicked = -1; + static bool bLastClickNoneOrShift = true; + + + SetFocus( hwnd ); // TODO monitor focus loss + + LVHITTESTINFO hittest; + memset( &hittest, 0, sizeof( LVHITTESTINFO ) ); + GetCursorPos( &hittest.pt ); + ScreenToClient( hwnd, &hittest.pt ); + const int iIndex = ( int )ListView_HitTest( WindowPlaylist, &hittest ); + if( iIndex == -1 ) return 0; + + const bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 ); + const bool bControl = ( ( GetKeyState( VK_CONTROL ) & 0x8000 ) != 0 ); + const bool bAlt = ( ( GetKeyState( VK_MENU ) & 0x8000 ) != 0 ); + + // [Shift] or [Shift]+[Ctrl]? + if( bShift ) + { + if( bAlt ) return 0; + + // Last click usable as selection anchor? + if( !bLastClickNoneOrShift ) + { + // Treat as normal click + iSelAnchor = iIndex; + iLastClicked = iIndex; + + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVIS_SELECTED | LVIS_FOCUSED ); + ListView_SetItemState( WindowPlaylist, iIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); + + bLiquidSelecting = true; + bLastClickNoneOrShift = true; + + return 0; + } + + if( iIndex != iLastClicked ) + { + // Below anchor? + if( iIndex > iSelAnchor ) + { + // Below last click? + if( iIndex > iLastClicked ) + { + // Other side of anchor? + if( iLastClicked < iSelAnchor ) + { + // Unselect downwards + for( int i = iLastClicked; i < iSelAnchor; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + + // Select downwards + for( int i = iSelAnchor; i <= iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + + // Same side of anchor? + else + { + // Select downwards + for( int i = iLastClicked + 1; i <= iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + } + + // Above last click? + else // iIndex < iLastClicked + { + // Unselect upwards + for( int i = iLastClicked; i > iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + + // Above anchor? + else if( iIndex < iSelAnchor ) + { + // Above last clicked? + if( iIndex < iLastClicked ) + { + // Other side of anchor? + if( iLastClicked > iSelAnchor ) + { + // Unselect upwards + for( int i = iLastClicked; i > iSelAnchor; i-- ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + + // Select upwards + for( int i = iSelAnchor; i >= iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + + // Same side of anchor? + else + { + // Select upwards + for( int i = iLastClicked - 1; i >= iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, LVIS_SELECTED, LVIS_SELECTED ); + } + } + + // Below last clicked? + else // iIndex > iLastClicked + { + // Unselect downwards + for( int i = iLastClicked; i < iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + + // At anchor + else // iIndex == iSelAnchor + { + if( iLastClicked < iSelAnchor ) + { + // Unselect downwards + for( int i = iLastClicked; i < iIndex; i++ ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + else if( iLastClicked > iSelAnchor ) + { + // Unselect upwards + for( int i = iLastClicked; i > iIndex; i-- ) + ListView_SetItemState( WindowPlaylist, i, 0, LVIS_SELECTED ); + } + } + + iLastClicked = iIndex; + + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVIS_FOCUSED ); + ListView_SetItemState( WindowPlaylist, iIndex, LVIS_FOCUSED, LVIS_FOCUSED ); + } + + bLastClickNoneOrShift = true; + } + + // [Ctrl]? + else if( bControl ) + { + if( bAlt ) return 0; + + iLastTouched = iIndex; + + // Toggle selection + const bool bSelected = ( ListView_GetItemState( WindowPlaylist, iIndex, LVIS_SELECTED ) == LVIS_SELECTED ); + ListView_SetItemState( WindowPlaylist, iIndex, bSelected ? 0 : LVIS_SELECTED, LVIS_SELECTED ); + + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVIS_FOCUSED ); + ListView_SetItemState( WindowPlaylist, iIndex, LVIS_FOCUSED, LVIS_FOCUSED ); + + bLastClickNoneOrShift = false; + } + + // [Alt]? + else if( bAlt ) + { + // Update item height + RECT rc; + GetClientRect( WindowPlaylist, &rc ); + const int iItemsPerPage = ListView_GetCountPerPage( WindowPlaylist ); + iItemHeight = ( rc.bottom - rc.top ) / iItemsPerPage; + + iDragStartY = hittest.pt.y; + bDragging = true; + + bCapturing = true; + SetCapture( WindowPlaylist ); + } + + // No modifiers? + else + { + iSelAnchor = iIndex; + iLastClicked = iIndex; + + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVIS_SELECTED | LVIS_FOCUSED ); + ListView_SetItemState( WindowPlaylist, iIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); + + bLiquidSelecting = true; + bLastClickNoneOrShift = true; + + bCapturing = true; + SetCapture( WindowPlaylist ); + } + } + return 0; + + case WM_LBUTTONUP: + bLiquidSelecting = false; + bDragging = false; + + bCapturing = false; + ReleaseCapture(); + + return 0; + + case WM_SYSKEYDOWN: + switch( wp ) // [Alt]+[...] + { + case VK_UP: + playlist->MoveSelected( -1 ); + break; + + case VK_DOWN: + playlist->MoveSelected( +1 ); + break; + + } + break; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + case WM_CHAR: + case WM_KEYUP: + // SMALL LETTERS!!!!!! + switch( wp ) + { + case 'z': + case 'y': + case 'x': + case 'c': + case 'v': + case 'b': + case 'l': + return 0; + } + break; + + case WM_KEYDOWN: + { + const bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 ); + const bool bControl = ( ( GetKeyState( VK_CONTROL ) & 0x8000 ) != 0 ); + + // Note: [Alt] goes to WM_SYSKEYDOWN instead + // const bool bAlt = ( ( GetKeyState( VK_MENU ) & 0x8000 ) != 0 ); + + + switch( wp ) + { + case VK_LEFT: + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_REW5S, 0 ); + return 0; + + case VK_RIGHT: + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_FFWD5S, 0 ); + return 0; + + case VK_UP: + if( bInfinitePlaylist ) + { + // First item has focus? + if( ListView_GetNextItem( WindowPlaylist, ( UINT )-1, LVNI_FOCUSED ) != 0 ) break; + + if( bControl && !bShift ) + { + // Move caret only + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVNI_FOCUSED ); + ListView_SetItemState( WindowPlaylist, playlist->GetMaxIndex(), LVNI_FOCUSED, LVNI_FOCUSED ); + return 0; + } + else + { + // Move Caret and selection + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVNI_FOCUSED ); + ListView_SetItemState( WindowPlaylist, playlist->GetMaxIndex() - 1, LVNI_FOCUSED, LVNI_FOCUSED ); + wp = VK_DOWN; + } + } + break; + + case VK_DOWN: + if( bInfinitePlaylist ) + { + // Last item has focus? + if( ListView_GetNextItem( WindowPlaylist, playlist->GetMaxIndex() - 1, LVNI_FOCUSED ) == -1 ) break; + + if( bControl && !bShift ) + { + // Move caret only + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVNI_FOCUSED ); + ListView_SetItemState( WindowPlaylist, 0, LVNI_FOCUSED, LVNI_FOCUSED ); + return 0; + } + else + { + // Workaround + ListView_SetItemState( WindowPlaylist, ( UINT )-1, 0, LVNI_FOCUSED ); + ListView_SetItemState( WindowPlaylist, 1, LVNI_FOCUSED, LVNI_FOCUSED ); + wp = VK_UP; + } + } + break; + + case VK_DELETE: + { + if( bShift ) break; + + if( bControl ) + playlist->RemoveSelected( false ); + else + playlist->RemoveSelected( true ); + + break; + } + + case VK_RETURN: + playlist->SetCurIndex( ListView_GetNextItem( WindowPlaylist, ( UINT )-1, LVIS_FOCUSED ) ); + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 ); + return 0; + + case 'Y': + case 'Z': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON1, 0 ); + return 0; + + case 'X': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 ); + return 0; + + case 'C': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON3, 0 ); + return 0; + + case 'V': + // Todo modifiers pressed? -> fadeout/... + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON4, 0 ); + return 0; + + case 'B': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON5, 0 ); + return 0; + /* + case 'J': + if( bShift || bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, WINAMP_JUMPFILE, 0 ); + return 0; + */ + case 'L': + if( bControl ) return 0; + SendMessage( WindowMain, WM_COMMAND, bShift ? WINAMP_FILE_DIR : WINAMP_FILE_PLAY, 0 ); + return 0; + } + break; + } + + case WM_LBUTTONDBLCLK: + // iCurIndex = Playlist_MouseToIndex(); + + LVHITTESTINFO hittest; + memset( &hittest, 0, sizeof( LVHITTESTINFO ) ); + GetCursorPos( &hittest.pt ); + ScreenToClient( hwnd, &hittest.pt ); + const int iIndex = ( int )ListView_HitTest( WindowPlaylist, &hittest ); + if( iIndex == -1 ) break; + + playlist->SetCurIndex( iIndex ); + + Playback::Play(); + Playback::UpdateSeek(); + + break; + + } + + return CallWindowProc( WndprocPlaylistBackup, hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/PlaylistView.h b/Branches/MusicMod/Player/Src/PlaylistView.h new file mode 100644 index 0000000000..5783ef9075 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PlaylistView.h @@ -0,0 +1,27 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PLAYLIST_VIEW_H +#define PLAYLIST_VIEW_H 1 + + +#include "Global.h" + +namespace PlaylistView +{ + void Create(); + + +}; + + +#endif // PLAYLIST_VIEW_H diff --git a/Branches/MusicMod/Player/Src/Plugin.cpp b/Branches/MusicMod/Player/Src/Plugin.cpp new file mode 100644 index 0000000000..f6c9c31080 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Plugin.cpp @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Plugin.h" +#include "InputPlugin.h" +#include "OutputPlugin.h" +#include "VisPlugin.h" +#include "DspPlugin.h" +#include "GenPlugin.h" + + + +vector plugins; // extern + +int Plugin::iWndprocHookCounter = 0; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +Plugin::Plugin( TCHAR * szDllpath ) +{ + hDLL = NULL; + szName = NULL; + iNameLen = 0; + + + iFullpathLen = ( int )_tcslen( szDllpath ); + szFullpath = new TCHAR[ iFullpathLen + 1 ]; + memcpy( szFullpath, szDllpath, iFullpathLen * sizeof( TCHAR ) ); + szFullpath[ iFullpathLen ] = TEXT( '\0' ); + + TCHAR * walk = szFullpath + iFullpathLen - 1; + while( ( *walk != TEXT( '\\') ) && ( walk >= szFullpath ) ) walk--; + if( *walk == TEXT( '\\') ) walk++; + + szFilename = walk; + iFilenameLen = iFullpathLen - ( walk - szFullpath ); + _tcslwr( szFilename ); + + plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +Plugin::~Plugin() +{ + if( szFullpath ) delete [] szFullpath; + if( szName ) delete [] szName; +} diff --git a/Branches/MusicMod/Player/Src/Plugin.h b/Branches/MusicMod/Player/Src/Plugin.h new file mode 100644 index 0000000000..4caed22ea2 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Plugin.h @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PLUGIN_H +#define PA_PLUGIN_H + + + +#include "Global.h" +#include + +using namespace std; + + +class Plugin; +extern vector plugins; + + + +enum PluginType +{ + PLUGIN_TYPE_INPUT, + PLUGIN_TYPE_OUTPUT, + PLUGIN_TYPE_VIS, + PLUGIN_TYPE_DSP, + PLUGIN_TYPE_GEN +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class Plugin +{ +public: + Plugin( TCHAR * szDllpath ); + ~Plugin(); + + virtual bool Load() = 0; + virtual bool Unload() = 0; + + virtual TCHAR * GetTypeString() = 0; + virtual int GetTypeStringLen() = 0; + virtual PluginType GetType() = 0; + +// void AllowUnload( bool bAllow ) { bAllowUnload = bAllow; } + inline bool IsLoaded() { return ( hDLL != NULL ); } + virtual bool IsActive() = 0; + + inline TCHAR * GetFullpath() { return szFullpath; } + // inline int GetFullpathLen() { return iFilenameLen; } + + inline TCHAR * GetFilename() { return szFilename; } + inline int GetFilenameLen() { return iFilenameLen; } + inline TCHAR * GetName() { return szName; } + inline int GetNameLen() { return iNameLen; } + + template< class PluginKind > + static bool FindAll( TCHAR * szPath, TCHAR * szPattern, bool bKeepLoaded ); + +protected: + HINSTANCE hDLL; ///< Library handle + TCHAR * szName; ///< Name + int iNameLen; ///< Length of name (in characters) + + BOOL iHookerIndex; ///< Window hook index (0..HC-1). Only last can be unloaded + WNDPROC WndprocBackup; ///< Window procedure backup. Is restored when unloading. Only valid for + static int iWndprocHookCounter; ///< Number of window hooks (=HC) + +private: + TCHAR * szFullpath; ///< Full path e.g. "C:\test.dll" + TCHAR * szFilename; ///< Filename e.g. "test.dll" + int iFullpathLen; ///< Length of full path (in characters) + int iFilenameLen; ///< Length of filename (in characters) +}; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +template< class PluginKind > +bool Plugin::FindAll( TCHAR * szPath, TCHAR * szPattern, bool bKeepLoaded ) +{ + const int uPathLen = ( int )_tcslen( szPath ); + const int uPatternLen = ( int )_tcslen( szPattern ); + + TCHAR * szFullPattern = new TCHAR[ uPathLen + 1 + uPatternLen + 1 ]; + memcpy( szFullPattern, szPath, uPathLen * sizeof( TCHAR ) ); + szFullPattern[ uPathLen ] = TEXT( '\\' ); + memcpy( szFullPattern + uPathLen + 1, szPattern, uPatternLen * sizeof( TCHAR ) ); + szFullPattern[ uPathLen + 1 + uPatternLen ] = TEXT( '\0' ); + + + WIN32_FIND_DATA fd; + HANDLE hFind = FindFirstFile( szFullPattern, &fd ); + if( hFind == INVALID_HANDLE_VALUE ) + { + delete [] szFullPattern; + return false; + } + + do + { + const int iFilenameLen = ( int )_tcslen( fd.cFileName ); + + TCHAR * szFullpath = new TCHAR[ uPathLen + 1 + iFilenameLen + 1 ]; + memcpy( szFullpath, szPath, uPathLen * sizeof( TCHAR ) ); + szFullpath[ uPathLen ] = TEXT( '\\' ); + memcpy( szFullpath + uPathLen + 1, fd.cFileName, iFilenameLen * sizeof( TCHAR ) ); + szFullpath[ uPathLen + 1 + iFilenameLen ] = TEXT( '\0' ); + + +//////////////////////////////////////////////////////////////////////////////// + new PluginKind( szFullpath, bKeepLoaded ); +//////////////////////////////////////////////////////////////////////////////// + + + delete [] szFullpath; + } + while( FindNextFile( hFind, &fd ) ); + + FindClose( hFind ); + + + delete [] szFullPattern; + return true; +} + + + +#endif // PA_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/PluginManager.cpp b/Branches/MusicMod/Player/Src/PluginManager.cpp new file mode 100644 index 0000000000..432fc33130 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PluginManager.cpp @@ -0,0 +1,1143 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "PluginManager.h" +#include "Plugin.h" +#include "InputPlugin.h" +#include "OutputPlugin.h" +#include "VisPlugin.h" +#include "DspPlugin.h" +#include "GenPlugin.h" +#include "Console.h" +#include "Main.h" +#include "Util.h" +#include "Config.h" + + + +#define MENU_INPUT_CONFIG 1 +#define MENU_INPUT_ABOUT 2 + +#define MENU_OUTPUT_CONFIG 1 +#define MENU_OUTPUT_ABOUT 2 +#define MENU_OUTPUT_SEP 3 +#define MENU_OUTPUT_ACTIVE 4 +#define MENU_OUTPUT_LOAD 5 + +#define MENU_GEN_CONFIG 1 +#define MENU_GEN_SEP 2 +#define MENU_GEN_LOAD 3 + + + +HWND WindowManager = NULL; // extern +HWND WindowListView = NULL; + + +WNDPROC WndprocListViewBackup = NULL; +LRESULT CALLBACK WndprocListView( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + +LRESULT CALLBACK WndprocManager( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + +HMENU input_menu = NULL; +HMENU output_menu = NULL; +HMENU gen_menu = NULL; + + + +bool bManagerGrid; +ConfBool cbManagerGrid( &bManagerGrid, "ManagerGrid", CONF_MODE_PUBLIC, true ); + +bool bManagerVisible; +WINDOWPLACEMENT WinPlaceManager; + +void WinPlaceManagerCallback( ConfVar * var ) +{ + if( !IsWindow( WindowManager ) ) return; + + GetWindowPlacement( WindowManager, &WinPlaceManager ); + + // MSDN: If the window identified by the hWnd parameter + // is maximized, the showCmd member is SW_SHOWMAXIMIZED. + // If the window is minimized, showCmd is SW_SHOWMINIMIZED. + // Otherwise, it is SW_SHOWNORMAL. + if( !bManagerVisible ) + { + WinPlaceManager.showCmd = SW_HIDE; + } +} + +RECT rManagerDefault = { 500, 400, 1000, 700 }; + +ConfWinPlaceCallback cwpcWinPlaceManager( + &WinPlaceManager, + TEXT( "WinPlaceManager" ), + &rManagerDefault, + WinPlaceManagerCallback +); + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +#define CLASSNAME_PAPMC TEXT( "PLAINAMP_PMC" ) +#define PAPMC_TITLE TEXT( "Plugin Manager" ) + +bool PluginManager::Build() +{ + LoadCommonControls(); + + // Register class + WNDCLASS wc = { + 0, // UINT style + WndprocManager, // WNDPROC lpfnWndProc + 0, // int cbClsExtra + 0, // int cbWndExtra + g_hInstance, // HINSTANCE hInstance + NULL, // HICON hIcon + LoadCursor( NULL, IDC_ARROW ), // HCURSOR hCursor + ( HBRUSH )COLOR_WINDOW, // HBRUSH hbrBackground + NULL, // LPCTSTR lpszMenuName + CLASSNAME_PAPMC // LPCTSTR lpszClassName + }; + + if( !RegisterClass( &wc ) ) return false; + + WindowManager = CreateWindowEx( + WS_EX_TOOLWINDOW, // DWORD dwExStyle + CLASSNAME_PAPMC, // LPCTSTR lpClassName + PAPMC_TITLE, // LPCTSTR lpWindowName + WS_OVERLAPPEDWINDOW | // DWORD dwStyle + WS_CLIPCHILDREN, // + rManagerDefault.left, // int x + rManagerDefault.top, // int y + rManagerDefault.right - rManagerDefault.left, // int nWidth + rManagerDefault.bottom - rManagerDefault.top, // int nHeight + NULL, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + RECT r; + GetClientRect( WindowManager, &r ); + + WindowListView = CreateWindowEx( + WS_EX_CLIENTEDGE, // DWORD dwExStyle + WC_LISTVIEW, // LPCTSTR lpClassName + NULL, // LPCTSTR lpWindowName + WS_VSCROLL | // DWORD dwStyle + LVS_REPORT | // + LVS_SORTASCENDING | // + LVS_SINGLESEL | // + WS_CHILD | // + WS_VISIBLE, // + 0, // int x + 0, // int y + r.right - r.left, // int nWidth + r.bottom - r.top, // int nHeight + WindowManager, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + if( !WindowListView ) return false; + + ListView_SetExtendedListViewStyle( + WindowListView, + LVS_EX_FULLROWSELECT | + ( bManagerGrid ? LVS_EX_GRIDLINES : 0 ) | + LVS_EX_HEADERDRAGDROP + ); + + // (0) File + LVCOLUMN lvc = { + LVCF_TEXT | LVCF_WIDTH | LVCF_FMT, // UINT mask; + LVCFMT_LEFT, // int fmt; + 100, // int cx; + TEXT( "File" ), // LPTSTR pszText; + 5, // int cchTextMax; + 0, // int iSubItem; + 0, // int iOrder; + 0 // int iImage; + }; + ListView_InsertColumn( WindowListView, 0, &lvc ); + + // (1) Status + lvc.pszText = TEXT( "Status" ); + lvc.cchTextMax = 7; + ListView_InsertColumn( WindowListView, 1, &lvc ); + + // (2) Name + lvc.cx = 220; + lvc.pszText = TEXT( "Name" ); + lvc.cchTextMax = 5; + ListView_InsertColumn( WindowListView, 2, &lvc ); + + + // (3) Type + lvc.pszText = TEXT( "Type" ); + lvc.cchTextMax = 5; + ListView_InsertColumn( WindowListView, 3, &lvc ); + + + bManagerVisible = ( WinPlaceManager.showCmd != SW_HIDE ); + SetWindowPlacement( WindowManager, &WinPlaceManager ); + + + // Exchange window procedure + WndprocListViewBackup = ( WNDPROC )GetWindowLong( WindowListView, GWL_WNDPROC ); + if( WndprocListViewBackup != NULL ) + { + SetWindowLong( WindowListView, GWL_WNDPROC, ( LONG )WndprocListView ); + } + + + // Build context menu + input_menu = CreatePopupMenu(); + AppendMenu( input_menu, MF_STRING, MENU_INPUT_CONFIG, TEXT( "Config" ) ); + AppendMenu( input_menu, MF_STRING, MENU_INPUT_ABOUT, TEXT( "About" ) ); + + output_menu = CreatePopupMenu(); + AppendMenu( output_menu, MF_STRING, MENU_OUTPUT_CONFIG, TEXT( "Config" ) ); + AppendMenu( output_menu, MF_STRING, MENU_OUTPUT_ABOUT, TEXT( "About" ) ); + AppendMenu( output_menu, MF_SEPARATOR | MF_GRAYED | MF_DISABLED, MENU_OUTPUT_SEP, NULL ); + AppendMenu( output_menu, MF_STRING, MENU_OUTPUT_ACTIVE, TEXT( "Active" ) ); + AppendMenu( output_menu, MF_STRING, MENU_OUTPUT_LOAD, TEXT( " " ) ); + + gen_menu = CreatePopupMenu(); + AppendMenu( gen_menu, MF_STRING, MENU_GEN_CONFIG, TEXT( "Config" ) ); + AppendMenu( gen_menu, MF_SEPARATOR | MF_GRAYED | MF_DISABLED, MENU_GEN_SEP, NULL ); + AppendMenu( gen_menu, MF_STRING, MENU_GEN_LOAD, TEXT( " " ) ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool PluginManager::Fill() +{ + if( !WindowListView ) return false; + + LVITEM lvi; + memset( &lvi, 0, sizeof( LVITEM ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM; + + Plugin * plugin; + int iIndex; + vector::iterator iter = plugins.begin(); + while( iter != plugins.end() ) + { +lvi.mask = LVIF_TEXT | LVIF_PARAM; + + plugin = *iter; + lvi.iItem = 0; + lvi.lParam = ( LPARAM )plugin; + + // (0) File + + lvi.iSubItem = 0; + lvi.pszText = plugin->GetFilename(); + lvi.cchTextMax = plugin->GetFilenameLen() + 1; + iIndex = ListView_InsertItem( WindowListView, &lvi ); + lvi.iItem = iIndex; +lvi.mask = LVIF_TEXT; + + // (1) Status + lvi.iSubItem = 1; + if( plugin->IsLoaded() ) + { + if( plugin->IsActive() ) + { + lvi.pszText = TEXT( "Active" ); + } + else + { + lvi.pszText = TEXT( "Loaded" ); + } + lvi.cchTextMax = 7; + } + else + { + lvi.pszText = TEXT( "Not loaded" ); + lvi.cchTextMax = 11; + } + ListView_SetItem( WindowListView, &lvi ); + + // (2) Name + lvi.iSubItem = 2; + lvi.pszText = plugin->GetName(); + lvi.cchTextMax = plugin->GetNameLen() + 1; + ListView_SetItem( WindowListView, &lvi ); + + // (3) Type + lvi.iSubItem = 3; + lvi.pszText = plugin->GetTypeString(); + lvi.cchTextMax = plugin->GetTypeStringLen() + 1; + ListView_SetItem( WindowListView, &lvi ); + + iter++; + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool PluginManager::Destroy() +{ + if( !WindowListView ) return false; + + DestroyWindow( WindowManager ); + DestroyMenu( input_menu ); + DestroyMenu( output_menu ); + DestroyMenu( gen_menu ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool PluginManager::Popup() +{ + if( !WindowListView ) return false; + if( !IsWindowVisible( WindowManager ) ) + ShowWindow( WindowManager, SW_SHOW ); + + SetActiveWindow( WindowManager ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void UpdatePluginStatus( Plugin * plugin, bool bLoaded, bool bActive ) +{ + LVFINDINFO lvfi = { + LVFI_PARAM, // UINT flags + NULL, // LPCTSTR psz + ( LPARAM )plugin, // LPARAM lParam + POINT(), // POINT pt + 0 // UINT vkDirection + }; + + int iIndex = ListView_FindItem( WindowListView, -1, &lvfi ); + if( iIndex != -1 ) + { + LVITEM lvi; + memset( &lvi, 0, sizeof( LVITEM ) ); + lvi.mask = LVIF_TEXT; + lvi.iItem = iIndex; + lvi.iSubItem = 1; + if( bLoaded ) + { + if( bActive ) + { + lvi.pszText = TEXT( "Active" ); + } + else + { + lvi.pszText = TEXT( "Loaded" ); + } + lvi.cchTextMax = 7; + } + else + { + lvi.pszText = TEXT( "Not loaded" ); + lvi.cchTextMax = 11; + } + ListView_SetItem( WindowListView, &lvi ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuInput( InputPlugin * input, POINT * p ) +{ + BOOL iIndex = TrackPopupMenu( + input_menu, + TPM_LEFTALIGN | + TPM_TOPALIGN | + TPM_NONOTIFY | + TPM_RETURNCMD | + TPM_RIGHTBUTTON, + p->x, + p->y, + 0, + WindowManager, + NULL + ); + + switch( iIndex ) + { + case MENU_INPUT_ABOUT: + input->About( WindowManager ); + break; + + case MENU_INPUT_CONFIG: + input->Config( WindowManager ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuOutput( OutputPlugin * output, POINT * p ) +{ + const bool bLoaded = output->IsLoaded(); + const bool bActive = output->IsActive(); + + EnableMenuItem( + output_menu, + MENU_OUTPUT_CONFIG, + bLoaded ? MF_ENABLED : MF_GRAYED | MF_DISABLED + ); + EnableMenuItem( + output_menu, + MENU_OUTPUT_ABOUT, + bLoaded ? MF_ENABLED : MF_GRAYED | MF_DISABLED + ); + EnableMenuItem( + output_menu, + MENU_OUTPUT_ACTIVE, + bLoaded ? MF_ENABLED : MF_GRAYED | MF_DISABLED + ); + CheckMenuItem( + output_menu, + MENU_OUTPUT_ACTIVE, + bActive ? MF_CHECKED : MF_UNCHECKED + ); + + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof( MENUITEMINFO ); + mii.fMask = MIIM_STATE | MIIM_STRING; + mii.fState = bActive ? MFS_GRAYED | MFS_DISABLED : MFS_ENABLED; + mii.dwTypeData = ( LPTSTR )( bLoaded ? TEXT( "Unload" ) : TEXT( "Load" ) ); + mii.cch = bLoaded ? 7 : 5; + + SetMenuItemInfo( + output_menu, // HMENU hMenu + MENU_OUTPUT_LOAD, // UINT uItem + FALSE, // BOOL fByPosition, + &mii // LPMENUITEMINFO lpmii + ); + + + BOOL iIndex = TrackPopupMenu( + output_menu, + TPM_LEFTALIGN | + TPM_TOPALIGN | + TPM_NONOTIFY | + TPM_RETURNCMD | + TPM_RIGHTBUTTON, + p->x, + p->y, + 0, + WindowManager, + NULL + ); + + switch( iIndex ) + { + case MENU_OUTPUT_CONFIG: + output->Config( WindowManager ); + break; + + case MENU_OUTPUT_ABOUT: + output->About( WindowManager ); + break; + + case MENU_OUTPUT_ACTIVE: + { + if( Playback::IsPlaying() ) + { + MessageBox( WindowManager, TEXT( "Cannot do this while playing!" ), TEXT( "Error" ), MB_ICONERROR ); + break; + } + + if( bActive ) + output->Stop(); + else + output->Start(); + + const bool bActiveNew = output->IsActive(); + if( bActiveNew != bActive ) + { + UpdatePluginStatus( output, bLoaded, bActiveNew ); + } + + break; + } + + case MENU_OUTPUT_LOAD: + { + if( bLoaded ) + output->Unload(); + else + output->Load(); + + const bool bLoadedNew = output->IsLoaded(); + if( bLoadedNew != bLoaded ) + { + UpdatePluginStatus( output, bLoadedNew, bActive ); + } + + break; + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuVis( VisPlugin * vis, POINT * p ) +{ + HMENU vis_menu = CreatePopupMenu(); + + const bool bLoaded = vis->IsLoaded(); + const bool bPluginActive = vis->IsActive(); + + VisModule * mod; + HMENU * menus = NULL; + + const int iModCount = ( int )vis->modules.size(); + if( iModCount == 1 ) + { + // Single module + mod = vis->modules[ 0 ]; + const UINT uFlagsActive = MF_STRING | + ( mod->IsActive() ? MF_CHECKED : MF_UNCHECKED ) | + ( bLoaded ? MF_ENABLED : MF_DISABLED | MF_GRAYED ); + const UINT uFlagsConfig = MF_STRING | + ( bLoaded ? MF_ENABLED : MF_DISABLED | MF_GRAYED ); + AppendMenu( vis_menu, uFlagsActive, 1, TEXT( "Active" ) ); + AppendMenu( vis_menu, uFlagsConfig, 2, TEXT( "Config" ) ); + } + else + { + // Two or more + menus = new HMENU[ iModCount ]; + int iIndex = 0; + vector ::iterator iter = vis->modules.begin(); + while( iter != vis->modules.end() ) + { + mod = *iter; + + menus[ iIndex ] = CreatePopupMenu(); + UINT uFlags = MF_STRING | ( mod->IsActive() ? MF_CHECKED : MF_UNCHECKED ); + AppendMenu( menus[ iIndex ], uFlags, iIndex * 2 + 1, TEXT( "Active" ) ); + AppendMenu( menus[ iIndex ], MF_STRING, iIndex * 2 + 2, TEXT( "Config" ) ); + + uFlags = MF_STRING | MF_POPUP | ( ( !bLoaded || ( bPluginActive && !mod->IsActive() ) ) ? MF_GRAYED | MF_DISABLED : 0 ); + AppendMenu( vis_menu, uFlags, ( UINT_PTR )menus[ iIndex ], mod->GetName() ); + + iIndex++; + iter++; + } + } + + + + const int iPos = ( int )vis->modules.size() * 2 + 1; + AppendMenu( vis_menu, MF_SEPARATOR | MF_GRAYED | MF_DISABLED, iPos, NULL ); + + AppendMenu( + vis_menu, + MF_STRING | ( bPluginActive ? MF_DISABLED | MF_GRAYED : MF_ENABLED ), + iPos + 1, + bLoaded ? TEXT( "Unload" ) : TEXT( "Load" ) + ); + + + BOOL iIndex = TrackPopupMenu( + vis_menu, // HMENU hMenu + TPM_LEFTALIGN | // UINT uFlags + TPM_TOPALIGN | // . + TPM_NONOTIFY | // . + TPM_RETURNCMD | // . + TPM_RIGHTBUTTON, // . + p->x, // int x + p->y, // int y + 0, // int nReserved + WindowManager, // HWND hWnd + NULL // HWND prcRect + ); + + if( iIndex ) + { + if( iIndex >= iPos ) + { + // Load/unload + if( bLoaded ) + vis->Unload(); + else + vis->Load(); + + const bool bLoadedNew = vis->IsLoaded(); + + if( bLoadedNew != bLoaded ) + UpdatePluginStatus( vis, bLoadedNew, FALSE ); + } + else + { + int iWhich = ( iIndex - 1 ) / 2; + if( iIndex & 1 ) + { + // Active + const bool bPluginActive = vis->IsActive(); + + if( !vis->modules[ iWhich ]->IsActive() ) + vis->modules[ iWhich ]->Start(); + else + vis->modules[ iWhich ]->Stop(); + + const bool bPluginActiveNew = vis->IsActive(); + + if( bPluginActiveNew && ( bPluginActiveNew != bPluginActive ) ) + UpdatePluginStatus( vis, TRUE, bPluginActiveNew ); + } + else + { + // Config + vis->modules[ iWhich ]->Config(); + } + } + } + + DestroyMenu( vis_menu ); + if( iModCount > 1 ) + { + for( int i = 0; i < iModCount; i++ ) + DestroyMenu( menus[ i ] ); + delete [] menus; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuDsp( DspPlugin * dsp, POINT * p ) +{ + HMENU context_menu = CreatePopupMenu(); + + const bool bLoaded = dsp->IsLoaded(); + const bool bPluginActive = dsp->IsActive(); + + DspModule * mod; + + HMENU * menus = NULL; + + HMENU * add_rem_menus = NULL; + + const int iEach = ( 3 * active_dsp_count + 2 ); + + const int iModCount = ( int )dsp->modules.size(); + if( iModCount == 1 ) + { + // Single module + mod = dsp->modules[ 0 ]; + + add_rem_menus = new HMENU[ 2 ]; + add_rem_menus[ 0 ] = CreatePopupMenu(); + add_rem_menus[ 1 ] = CreatePopupMenu(); + + int i; + TCHAR szHere[ 12 ]; + for( i = 0; i < active_dsp_count; i++ ) + { + TCHAR * szName = active_dsp_mods[ i ]->GetName(); + + // Entry for "Add" + _stprintf( szHere, TEXT( "Here (%i)" ), i + 1 ); + AppendMenu( + add_rem_menus[ 0 ], + MF_STRING, + 2 * i + 1, + szHere + ); + AppendMenu( + add_rem_menus[ 0 ], + MF_STRING | MF_DISABLED | MF_GRAYED, + 2 * i + 2, + szName + ); + + // Entry for "Remove" + AppendMenu( + add_rem_menus[ 1 ], + MF_STRING, + 2 * active_dsp_count + 2 + i, + szName + ); + } + _stprintf( szHere, TEXT( "Here (%i)" ), i + 1 ); + AppendMenu( + add_rem_menus[ 0 ], + MF_STRING, + 2 * i + 1, + szHere + ); + + + // Main entries + const UINT uFlagsAdd = MF_STRING | MF_POPUP | + ( ( bLoaded && !mod->IsActive() ) ? 0 : MF_DISABLED | MF_GRAYED ); + const UINT uFlagsRemove = MF_STRING | MF_POPUP | + ( ( bLoaded && active_dsp_count ) ? 0 : MF_GRAYED | MF_DISABLED ); + const UINT uFlagsConfig = MF_STRING | + ( ( bLoaded && mod->IsActive() ) ? 0 : MF_DISABLED | MF_GRAYED ); + + AppendMenu( + context_menu, + uFlagsAdd, + ( UINT_PTR )add_rem_menus[ 0 ], + TEXT( "Add" ) + ); + AppendMenu( + context_menu, + uFlagsRemove, + ( UINT_PTR )add_rem_menus[ 1 ], + TEXT( "Remove" ) + ); + AppendMenu( + context_menu, + uFlagsConfig, + 3 * active_dsp_count + 1 + 1, + TEXT( "Config" ) + ); + } + else + { + // Two or more + menus = new HMENU[ iModCount ]; + add_rem_menus = new HMENU[ 2 * iModCount ]; + + int iIndex = 0; + vector ::iterator iter = dsp->modules.begin(); + while( iter != dsp->modules.end() ) + { + mod = *iter; + + menus[ iIndex ] = CreatePopupMenu(); + + add_rem_menus[ 2 * iIndex ] = CreatePopupMenu(); + add_rem_menus[ 2 * iIndex + 1 ] = CreatePopupMenu(); + + int i; + TCHAR szHere[ 12 ]; + for( i = 0; i < active_dsp_count; i++ ) + { + TCHAR * szName = active_dsp_mods[ i ]->GetName(); + + // Entry for "Add" + _stprintf( szHere, TEXT( "Here (%i)" ), i + 1 ); + AppendMenu( + add_rem_menus[ 2 * iIndex ], + MF_STRING, + ( iIndex * iEach ) + ( 2 * i + 1 ), + szHere + ); + AppendMenu( + add_rem_menus[ 2 * iIndex ], + MF_STRING | MF_DISABLED | MF_GRAYED, + ( iIndex * iEach ) + ( 2 * i + 2 ), + szName + ); + + // Entry for "Remove" + AppendMenu( + add_rem_menus[ 2 * iIndex + 1 ], + MF_STRING, + ( iIndex * iEach ) + ( 2 * active_dsp_count + 2 + i ), + szName + ); + } + _stprintf( szHere, TEXT( "Here (%i)" ), i + 1 ); + AppendMenu( + add_rem_menus[ 2 * iIndex ], + MF_STRING, + ( iIndex * iEach ) + ( 2 * i + 1 ), + szHere + ); + + AppendMenu( + menus[ iIndex ], + MF_STRING | MF_POPUP | ( mod->IsActive() ? MF_DISABLED | MF_GRAYED : 0 ), + ( UINT_PTR )add_rem_menus[ 2 * iIndex ], + TEXT( "Add" ) + ); + AppendMenu( + menus[ iIndex ], + MF_STRING | MF_POPUP | ( active_dsp_count ? 0 : MF_GRAYED | MF_DISABLED ), + ( UINT_PTR )add_rem_menus[ 2 * iIndex + 1 ], + TEXT( "Remove" ) + ); + AppendMenu( + menus[ iIndex ], + MF_STRING | ( mod->IsActive() ? 0 : MF_DISABLED | MF_GRAYED ), + ( iIndex * iEach ) + ( 3 * active_dsp_count + 1 + 1 ), + TEXT( "Config" ) + ); + AppendMenu( context_menu, MF_STRING | MF_POPUP | ( bLoaded ? 0 : ( MF_DISABLED | MF_GRAYED ) ), ( UINT_PTR )menus[ iIndex ], mod->GetName() ); + + iIndex++; + iter++; + } + } + + + const int iPos = ( int )dsp->modules.size() * ( 3 * active_dsp_count + 1 + 1 ) + 1; + AppendMenu( context_menu, MF_SEPARATOR | MF_GRAYED | MF_DISABLED, iPos, NULL ); + + UINT uFlags = MF_STRING; + + AppendMenu( + context_menu, + uFlags | ( bPluginActive ? MF_DISABLED | MF_GRAYED : MF_ENABLED ), + iPos + 1, + bLoaded ? TEXT( "Unload" ) : TEXT( "Load" ) + ); + + + BOOL iIndex = TrackPopupMenu( + context_menu, // HMENU hMenu + TPM_LEFTALIGN | // UINT uFlags + TPM_TOPALIGN | // . + TPM_NONOTIFY | // . + TPM_RETURNCMD | // . + TPM_RIGHTBUTTON, // . + p->x, // int x + p->y, // int y + 0, // int nReserved + WindowManager, // HWND hWnd + NULL // HWND prcRect + ); + + /* + + Example menu + + Mod1 + Add + Here [ 1] + Active1 [ 2] + Here [ 3] + Active2 [ 4] + Here [ 5] + Remove + Active1 [ 6] + Active2 [ 7] + Config [ 8] + Mod2 + Add + Here [ 9] + Active1 [10] + ... + --- + Load/Unload [11] + + */ + + + if( iIndex ) + { + if( iIndex >= iPos ) + { + // Load/unload + if( bLoaded ) + dsp->Unload(); + else + dsp->Load(); + + const bool bLoadedNew = dsp->IsLoaded(); + + if( bLoadedNew != bLoaded ) + UpdatePluginStatus( dsp, bLoadedNew, FALSE ); + } + else + { + int iWhichMod = ( iIndex - 1 ) / iEach; + int iRem = iIndex % iEach; + if( iRem == 0 ) + { + // Config + dsp->modules[ iWhichMod ]->Config(); + + } + else if( iRem < 2 * active_dsp_count + 2 ) + { + // Add module + const bool bPluginActive = dsp->IsActive(); + + dsp->modules[ iWhichMod ]->Start( iRem / 2 ); + + const bool bPluginActiveNew = dsp->IsActive(); + if( bPluginActiveNew != bPluginActive ) + { + UpdatePluginStatus( dsp, TRUE, bPluginActiveNew ); + } + } + else + { + // Remove module + const bool bPluginActive = dsp->IsActive(); + + iWhichMod = iRem - ( 2 * active_dsp_count + 2 ); +/* + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "REM <%i> <%i>" ), iIndex, iWhichMod ); + Console::Append( szBuffer ); +*/ + active_dsp_mods[ iWhichMod ]->Stop(); + + const bool bPluginActiveNew = dsp->IsActive(); + if( bPluginActiveNew != bPluginActive ) + { + UpdatePluginStatus( dsp, TRUE, bPluginActiveNew ); + } + } + } + } + + DestroyMenu( context_menu ); + if( iModCount > 1 ) + { + for( int i = 0; i < iModCount; i++ ) + DestroyMenu( menus[ i ] ); + delete [] menus; + } + + for( int j = 0; j < iModCount; j++ ) + DestroyMenu( add_rem_menus[ j ] ); + delete [] add_rem_menus; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuGen( GenPlugin * gen, POINT * p ) +{ + const bool bLoaded = gen->IsLoaded(); + + EnableMenuItem( + gen_menu, + MENU_GEN_CONFIG, + bLoaded ? MF_ENABLED : MF_GRAYED | MF_DISABLED + ); + + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof( MENUITEMINFO ); + mii.fMask = MIIM_STATE | MIIM_STRING; + mii.fState = gen->AllowRuntimeUnload() ? MFS_ENABLED : MFS_GRAYED | MFS_DISABLED; + mii.dwTypeData = ( LPTSTR )( bLoaded ? TEXT( "Unload" ) : TEXT( "Load and activate" ) ); + mii.cch = bLoaded ? 7 : 18; + + SetMenuItemInfo( + gen_menu, // HMENU hMenu + MENU_GEN_LOAD, // UINT uItem + FALSE, // BOOL fByPosition, + &mii // LPMENUITEMINFO lpmii + ); + + + BOOL iIndex = TrackPopupMenu( + gen_menu, + TPM_LEFTALIGN | + TPM_TOPALIGN | + TPM_NONOTIFY | + TPM_RETURNCMD | + TPM_RIGHTBUTTON, + p->x, + p->y, + 0, + WindowManager, + NULL + ); + + switch( iIndex ) + { + case MENU_GEN_CONFIG: + gen->Config(); + break; + + case MENU_GEN_LOAD: + { + if( bLoaded ) + gen->Unload(); + else + gen->Load(); + + const bool bLoadedNew = gen->IsLoaded(); + if( bLoadedNew != bLoaded ) + { + UpdatePluginStatus( gen, bLoadedNew, bLoadedNew ); + } + + break; + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenu( Plugin * plugin, POINT * p ) +{ + if( !plugin ) return; + + switch( plugin->GetType() ) + { + case PLUGIN_TYPE_INPUT: + ContextMenuInput( ( InputPlugin * )plugin, p ); + break; + + case PLUGIN_TYPE_OUTPUT: + ContextMenuOutput( ( OutputPlugin * )plugin, p ); + break; + + case PLUGIN_TYPE_VIS: + ContextMenuVis( ( VisPlugin * )plugin, p ); + break; + + case PLUGIN_TYPE_DSP: + ContextMenuDsp( ( DspPlugin * )plugin, p ); + break; + + case PLUGIN_TYPE_GEN: + ContextMenuGen( ( GenPlugin * )plugin, p ); + break; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocListView( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + static bool bContextOpen = false; + + switch( message ) + { + case WM_CONTEXTMENU: + { + if( ( HWND )wp != WindowListView ) break; + if( bContextOpen ) break; + bContextOpen = true; +//////////////////////////////////////////////////////////////////////////////// + + POINT p = { LOWORD( lp ), HIWORD( lp ) }; + ScreenToClient( WindowListView, &p ); + + // Which item? + LVHITTESTINFO hti; + memset( &hti, 0, sizeof( LVHITTESTINFO ) ); + hti.pt = p; + ListView_HitTest( WindowListView, &hti ); + + // Which plugin? + LVITEM lvi; + memset( &lvi, 0, sizeof( LVITEM ) ); + lvi.mask = LVIF_PARAM; + lvi.iItem = hti.iItem; + lvi.iSubItem = 0; + + if( !ListView_GetItem( WindowListView, &lvi ) ) + { + bContextOpen = false; + break; + } + Plugin * plugin = ( Plugin * )lvi.lParam; + + // Context menu + p.x = LOWORD( lp ); + p.y = HIWORD( lp ); + ContextMenu( plugin, &p ); + +//////////////////////////////////////////////////////////////////////////////// + bContextOpen = false; + break; + } + } + return CallWindowProc( WndprocListViewBackup, hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocManager( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_SIZE: + { + // Resize children + RECT client; + GetClientRect( WindowManager, &client ); + + if( WindowListView ) + MoveWindow( WindowListView, 0, 0, client.right - client.left, client.bottom - client.top, TRUE ); + break; + } + + case WM_SYSCOMMAND: + if( ( wp & 0xFFF0 ) == SC_CLOSE ) + { + ShowWindow( hwnd, SW_HIDE ); + return 0; + } + break; + + case WM_DESTROY: + cwpcWinPlaceManager.TriggerCallback(); + cwpcWinPlaceManager.RemoveCallback(); + break; + + case WM_SHOWWINDOW: + bManagerVisible = ( wp == TRUE ); + break; + } + return DefWindowProc( hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/PluginManager.h b/Branches/MusicMod/Player/Src/PluginManager.h new file mode 100644 index 0000000000..e68fb6d311 --- /dev/null +++ b/Branches/MusicMod/Player/Src/PluginManager.h @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PLUGIN_MANAGER_H +#define PA_PLUGIN_MANAGER_H + + + +#include "Global.h" +#include "Plugin.h" + + + +extern HWND WindowManager; + + + +void UpdatePluginStatus( Plugin * plugin, bool bLoaded, bool bActive ); + + + +namespace PluginManager +{ + bool Build(); + bool Fill(); + bool Destroy(); + + bool Popup(); +}; + + + +#endif // PA_PLUGIN_MANAGER_H diff --git a/Branches/MusicMod/Player/Src/Prefs.cpp b/Branches/MusicMod/Player/Src/Prefs.cpp new file mode 100644 index 0000000000..79f85b7c6f --- /dev/null +++ b/Branches/MusicMod/Player/Src/Prefs.cpp @@ -0,0 +1,565 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Prefs.h" +#include "Util.h" +#include "Font.h" +#include "Console.h" +#include + +using namespace std; + + +#define CLASSNAME_PREFS TEXT( "CLASSNAME_PREFS" ) +#define TITLE_PREFS TEXT( "Preferences" ) + + +#define PAGE_WIDTH 409 +#define PAGE_HEIGHT 400 + + +#define GAP_LEFT 4 +#define GAP_RIGHT 5 +#define GAP_TOP 4 +#define GAP_BOTTOM 5 +#define SPLITTER_WIDTH 6 +#define SPLITTER_HEIGHT 6 + +#define BOTTOM_SPACE 36 + +#define BUTTON_WIDTH 80 + + +#define PREFS_WIDTH 606 +#define PREFS_HEIGHT ( GAP_TOP + PAGE_HEIGHT + BOTTOM_SPACE ) + + + +struct PrefRecCompare +{ + bool operator()( const prefsDlgRec * a, const prefsDlgRec * b ) const + { + if( a->hInst < b->hInst ) return true; + if( a->dlgID < b->dlgID ) return true; + return strcmp( a->name, b->name ) < 0; + } +}; + + +map rec_to_item; + + +struct AllWeNeed +{ + prefsDlgRec * PageData; + HWND hwnd; +}; + + + +HWND WindowPrefs = NULL; +HWND WindowPage = NULL; +HWND WindowTree = NULL; +HWND ButtonClose = NULL; + +HTREEITEM root = NULL; + +HWND hCurrentPage = NULL; +// bool bKeepFocus = false; + + +LRESULT CALLBACK WndprocPrefs( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); +LRESULT CALLBACK WndprocTree( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); +WNDPROC WndprocTreeBackup = NULL; + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs::Create() +{ + if( WindowPrefs ) return false; + + // Register class + WNDCLASS wc = { + 0, // UINT style + WndprocPrefs, // WNDPROC lpfnWndProc + 0, // int cbClsExtra + 0, // int cbWndExtra + g_hInstance, // HINSTANCE hInstance + NULL, // HICON hIcon + LoadCursor( NULL, IDC_ARROW ), // HCURSOR hCursor + ( HBRUSH )COLOR_WINDOW, // HBRUSH hbrBackground + NULL, // LPCTSTR lpszMenuName + CLASSNAME_PREFS // LPCTSTR lpszClassName + }; + + if( !RegisterClass( &wc ) ) return false; + + const int cxScreen = GetSystemMetrics( SM_CXFULLSCREEN ); + const int cyScreen = GetSystemMetrics( SM_CYFULLSCREEN ); + + // Create window + WindowPrefs = CreateWindowEx( + WS_EX_WINDOWEDGE | // DWORD dwExStyle + WS_EX_TOOLWINDOW, // + CLASSNAME_PREFS, // LPCTSTR lpClassName + TITLE_PREFS, // LPCTSTR lpWindowName + WS_OVERLAPPED | // DWORD dwStyle +// WS_VISIBLE | // + WS_CLIPCHILDREN | // + WS_SYSMENU, // + ( cxScreen - PREFS_WIDTH ) / 2, // int x + ( cyScreen - PREFS_HEIGHT ) / 2, // int y + PREFS_WIDTH, // int nWidth + PREFS_HEIGHT, // int nHeight + NULL, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + + if( !WindowPrefs ) + { + UnregisterClass( CLASSNAME_PREFS, g_hInstance ); + return false; + } + + + RECT r; + GetClientRect( WindowPrefs, &r ); + + +//////////////////////////////////////////////////////////////////////////////// + const int iWidth = PREFS_WIDTH * 2 - r.right; + const int iHeight = PREFS_HEIGHT * 2 - r.bottom; + SetWindowPos( + WindowPrefs, + NULL, + ( cxScreen - iWidth ) / 2, + ( cyScreen - iHeight ) / 2, + iWidth, + iHeight, + SWP_NOZORDER + ); + GetClientRect( WindowPrefs, &r ); +//////////////////////////////////////////////////////////////////////////////// + + + LoadCommonControls(); + + const int iTreeWidth = ( r.right - r.left ) - PAGE_WIDTH - GAP_LEFT - GAP_RIGHT - SPLITTER_WIDTH; + + WindowTree = CreateWindowEx( + WS_EX_CLIENTEDGE, // DWORD dwExStyle + WC_TREEVIEW, // LPCTSTR lpClassName + NULL, // LPCTSTR lpWindowName + WS_VSCROLL | // DWORD dwStyle + WS_VISIBLE | // + WS_CHILD | // + WS_TABSTOP | // + TVS_HASLINES | // + TVS_LINESATROOT | // + TVS_HASBUTTONS | // + TVS_SHOWSELALWAYS | // + TVS_DISABLEDRAGDROP | // + TVS_NONEVENHEIGHT, // + GAP_LEFT, // int x + GAP_TOP, // int y + iTreeWidth, // int nWidth + PAGE_HEIGHT, // int nHeight + WindowPrefs, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + if( !WindowTree ) + { + ; //... + } + + Font::Apply( WindowTree ); + + // Exchange window procedure + WndprocTreeBackup = ( WNDPROC )GetWindowLong( WindowTree, GWL_WNDPROC ); + if( WndprocTreeBackup != NULL ) + { + SetWindowLong( WindowTree, GWL_WNDPROC, ( LONG )WndprocTree ); + } + + + const int iPageLeft = GAP_LEFT + iTreeWidth + SPLITTER_WIDTH; + + WindowPage = CreateWindowEx( + 0, // DWORD dwExStyle + TEXT( "Static" ), // LPCTSTR lpClassName + TEXT( "Nothing to see here" ), // LPCTSTR lpWindowName + WS_TABSTOP | // DWORD dwStyle + WS_VISIBLE | // + WS_CHILD | // + SS_CENTER | // + SS_CENTERIMAGE, // + iPageLeft, // int x + GAP_TOP, // int y + PAGE_WIDTH, // int nWidth + PAGE_HEIGHT, // int nHeight + WindowPrefs, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + if( !WindowPage ) + { + ; //... + } + + Font::Apply( WindowPage ); + + + const int iButtonLeft = ( r.right - r.left ) - GAP_RIGHT - BUTTON_WIDTH - 1; + const int iButtonTop = ( r.bottom - r.top ) - BOTTOM_SPACE + SPLITTER_HEIGHT; + + + ButtonClose = CreateWindowEx( + 0, // DWORD dwExStyle + TEXT( "Button" ), // LPCTSTR lpClassName + TEXT( "Close" ), // LPCTSTR lpWindowName + WS_TABSTOP | // DWORD dwStyle + WS_VISIBLE | // + WS_CHILD | // + BS_PUSHBUTTON | // + BS_TEXT | // + BS_VCENTER, // + iButtonLeft, // int x + iButtonTop, // int y + BUTTON_WIDTH, // int nWidth + BOTTOM_SPACE - SPLITTER_HEIGHT - GAP_BOTTOM, // int nHeight + WindowPrefs, // HWND hWndParent + NULL, // HMENU hMenu + g_hInstance, // HINSTANCE hInstance + NULL // LPVOID lpParam + ); + + Font::Apply( ButtonClose ); + + AllWeNeed * awn_root = new AllWeNeed; +// memset( &awn_root->PageData, 0, sizeof( prefsDlgRec ) ); + awn_root->PageData = NULL; + awn_root->hwnd = NULL; + + TV_INSERTSTRUCT tvi = { + root, // HTREEITEM hParent + TVI_SORT, // HTREEITEM hInsertAfter + { + TVIF_PARAM | TVIF_STATE | TVIF_TEXT, // UINT mask + NULL, // HTREEITEM hItem + TVIS_EXPANDED | TVIS_SELECTED, // UINT state + 0, // UINT stateMask + TEXT( "General" ), // LPSTR pszText + 8, // int cchTextMax + 0, // int iImage + 0, // int iSelectedImage + 0, // int cChildren + ( LPARAM )awn_root // LPARAM lParam + } + }; + + root = TreeView_InsertItem( WindowTree, &tvi ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs::Destroy() +{ + if( !WindowPrefs ) return false; + + DestroyWindow( WindowPrefs ); + UnregisterClass( CLASSNAME_PREFS, g_hInstance ); + WindowPrefs = NULL; + + DestroyWindow( WindowTree ); + WindowTree = NULL; + + DestroyWindow( WindowPage ); + WindowPage = NULL; + + DestroyWindow( ButtonClose ); + ButtonClose = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs_Show( HTREEITEM item ) +{ + if( !WindowPrefs ) return false; + + // Select and load associated page + TreeView_SelectItem( WindowTree, item ); + + if( !IsWindowVisible( WindowPrefs ) ) + { + ShowWindow( WindowPrefs, SW_SHOW ); + } + + SetActiveWindow( WindowPrefs ); + SetFocus( WindowTree ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs::Show() +{ + return Prefs_Show( root ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs::Show( prefsDlgRec * PageData ) +{ + map::iterator iter = rec_to_item.find( PageData ); + if( iter != rec_to_item.end() ) + { + return Prefs_Show( iter->second ); + } + else + { + return Prefs_Show( root ); + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Prefs::AddPage( prefsDlgRec * PageData ) +{ + // TODO unicode! + if( !WindowPrefs ) return false; + + // Backup + char * NameBackup = new char[ strlen( PageData->name ) + 1 ]; + strcpy( NameBackup, PageData->name ); + prefsDlgRec * PageDataBackup = new prefsDlgRec; + memcpy( PageDataBackup, PageData, sizeof( prefsDlgRec ) ); + PageDataBackup->name = NameBackup; + + AllWeNeed * awn = new AllWeNeed; + awn->PageData = PageDataBackup; + awn->hwnd = NULL; + + TV_INSERTSTRUCT tvi = { + root, // HTREEITEM hParent + TVI_SORT, // HTREEITEM hInsertAfter + { // + TVIF_PARAM | TVIF_STATE | TVIF_TEXT, // UINT mask + NULL, // HTREEITEM hItem + TVIS_EXPANDED | TVIS_SELECTED, // UINT state + 0, // UINT stateMask + PageDataBackup->name, // LPSTR pszText + ( int )strlen( PageDataBackup->name ) + 1, // int cchTextMax + 0, // int iImage + 0, // int iSelectedImage + 0, // int cChildren + ( LPARAM )awn // LPARAM lParam + } + }; + + HTREEITEM new_item = TreeView_InsertItem( WindowTree, &tvi ); + + TreeView_Expand( WindowTree, root, TVE_EXPAND ); + + rec_to_item.insert( pair( PageDataBackup, new_item ) ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocPrefs( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_NOTIFY: + { + NMHDR * nmhdr = ( NMHDR * )lp; + if( ( nmhdr->hwndFrom == WindowTree ) && ( nmhdr->code == TVN_SELCHANGING ) ) + { + NMTREEVIEW * nmtv = ( NMTREEVIEW * )lp; + TVITEM * OldPage = &nmtv->itemOld; + TVITEM * NewPage = &nmtv->itemNew; + + // Destroy old window + AllWeNeed * old_awn = ( AllWeNeed * )OldPage->lParam; + if( old_awn && old_awn->hwnd && IsWindow( old_awn->hwnd ) ) + { + DestroyWindow( old_awn->hwnd ); + old_awn->hwnd = NULL; + } + + // Create new window + AllWeNeed * new_awn = ( AllWeNeed * )NewPage->lParam; + if( new_awn ) + { + prefsDlgRec * PageData = new_awn->PageData; + if( PageData && PageData->hInst ) // root has NULL here + { + if( !PageData->proc ) + { + MessageBox( 0, TEXT( "proc NULL" ), TEXT( "" ), 0 ); + PageData->proc = ( void * )WndprocPrefs; + } + +/* + RECT r; + GetWindowRect( WindowPage, &r ); + const int iWidth = r.right - r.left; + const int iHeight = r.bottom - r.top; + POINT p = { r.left, r.top }; + ScreenToClient( WindowPrefs, &p ); + MoveWindow( WindowPage, p.x, p.y, iWidth - 10, iHeight - 10, FALSE ); +*/ +// bKeepFocus = true; + + HWND hPage = CreateDialog( + PageData->hInst, // HINSTANCE hInstance, + ( LPCTSTR )PageData->dlgID, // LPCTSTR lpTemplate, + WindowPage, // HWND hWndParent, + ( DLGPROC )PageData->proc // DLGPROC lpDialogFunc + ); + new_awn->hwnd = hPage; + +// MoveWindow( WindowPage, p.x, p.y, iWidth, iHeight, FALSE ); + + ShowWindow( hPage, SW_SHOW ); + UpdateWindow( hPage ); + SetFocus( WindowTree ); +/* + SetActiveWindow( hPage ); + SetActiveWindow( hwnd ); +*/ + hCurrentPage = hPage; +// bKeepFocus = false; + } +/* + else + { + MessageBox( 0, TEXT( "hInst NULL" ), TEXT( "" ), 0 ); + } +*/ + } + else + { + MessageBox( 0, TEXT( "awn NULL" ), TEXT( "" ), 0 ); + } + } + break; + } + + case WM_COMMAND: + switch( HIWORD( wp ) ) + { + case BN_CLICKED: + if( ( HWND )lp == ButtonClose ) + { + PostMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 ); + } + break; + } + break; + + case WM_SYSCOMMAND: + if( ( wp & 0xFFF0 ) == SC_CLOSE ) + { + ShowWindow( hwnd, SW_HIDE ); + + // Destroy current page so the settings are saved + // (currently be selecting the empty page + TreeView_SelectItem( WindowTree, root ); + +/* + if( hCurrentPage && IsWindow( hCurrentPage ) ) + { + DestroyWindow( hCurrentPage ); + hCurrentPage = NULL; + } +*/ + return 0; + } + break; + + case WM_KEYDOWN: + switch( wp ) + { + case VK_ESCAPE: + PostMessage( WindowPrefs, WM_SYSCOMMAND, SC_CLOSE, 0 ); + break; + + } + break; +/* + case WM_KILLFOCUS: + if( bKeepFocus ) + { + return 1; + } + break; +*/ + } + + return DefWindowProc( hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocTree( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_KEYDOWN: + switch( wp ) + { + case VK_ESCAPE: + PostMessage( WindowPrefs, WM_SYSCOMMAND, SC_CLOSE, 0 ); + break; + + } + break; + + } + return CallWindowProc( WndprocTreeBackup, hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/Prefs.h b/Branches/MusicMod/Player/Src/Prefs.h new file mode 100644 index 0000000000..4100d48760 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Prefs.h @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_PREFS_H +#define PA_PREFS_H + + + +#include "Global.h" +#include "Winamp/wa_ipc.h" + + + +namespace Prefs +{ + bool Create(); + bool Destroy(); + + bool Show(); + bool Show( prefsDlgRec * PageData ); + + bool AddPage( prefsDlgRec * PageData ); +}; + + + +#endif // PA_PREFS_H diff --git a/Branches/MusicMod/Player/Src/Rebar.cpp b/Branches/MusicMod/Player/Src/Rebar.cpp new file mode 100644 index 0000000000..572b2baff9 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Rebar.cpp @@ -0,0 +1,1441 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Rebar.h" +#include "Font.h" +#include "Main.h" +#include "Playlist.h" +#include "Playback.h" +#include "Console.h" +#include "Util.h" +#include "Config.h" + +#include "Winamp/wa_ipc.h" +#include "resrc1.h" + + + +#define BAND_ORDER 1 +#define BAND_EQ 2 +#define BAND_SEEK 3 +#define BAND_VOL 4 +#define BAND_PAN 5 +#define BAND_BUTTONS 6 +#define BAND_VIS 7 + +#define BAND_FIRST BAND_ORDER +#define BAND_LAST BAND_VIS + + +#define IMAGE_PREV 0 +#define IMAGE_PLAY 1 +#define IMAGE_PAUSE 2 +#define IMAGE_STOP 3 +#define IMAGE_NEXT 4 +#define IMAGE_OPEN 5 + + +HWND WindowRebar = NULL; // extern +int iRebarHeight = 40; // extern + + +HMENU rebar_menu = NULL; + + +WNDPROC WndprocRebarBackup = NULL; +LRESULT CALLBACK WndprocRebar( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + +HWND WindowOrder = NULL; // extern +HWND WindowEq = NULL; // extern + + +HWND WindowSeek = NULL; // extern +WNDPROC WndprocSeekBackup = NULL; +LRESULT CALLBACK WndprocSeek( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + +HWND WindowVol = NULL; +WNDPROC WndprocVolBackup = NULL; +LRESULT CALLBACK WndprocVol( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + +HWND WindowPan = NULL; +WNDPROC WndprocPanBackup = NULL; +LRESULT CALLBACK WndprocPan( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + +HWND WindowButtons = NULL; + +HWND WindowVis = NULL; // extern +WNDPROC WndprocVisBackup = NULL; +LRESULT CALLBACK WndprocVis( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + + +bool Rebar_BuildOrderBand(); +bool Rebar_BuildEqBand(); +bool Rebar_BuildSeekBand(); +bool Rebar_BuildVolBand(); +bool Rebar_BuildPanBand(); +bool Rebar_BuildButtonsBand(); +bool Rebar_BuildVisBand(); + +BandInfo biOrderBand = { 0 }; +BandInfo biEqBand = { 0 }; +BandInfo biSeekBand = { 0 }; +BandInfo biVolBand = { 0 }; +BandInfo biPanBand = { 0 }; +BandInfo biButtonsBand = { 0 }; +BandInfo biVisBand = { 0 }; + +const BandInfo biOrderBandDefault = { 0, 184, true, true }; +const BandInfo biVolBandDefault = { 1, 450, false, true }; +const BandInfo biPanBandDefault = { 2, 138, false, true }; +const BandInfo biEqBandDefault = { 3, 170, true, true }; +const BandInfo biVisBandDefault = { 4, 350, false, true }; +const BandInfo biButtonsBandDefault = { 5, 147, true, true }; +const BandInfo biSeekBandDefault = { 6, 373, false, true }; + + +void BandCallback( ConfVar * var ); + +ConfBandInfoCallback cbiOrderBand ( &biOrderBand, TEXT( "OrderBand" ), ( BandInfo * )&biOrderBandDefault, BandCallback ); +ConfBandInfoCallback cbiEqBand ( &biEqBand, TEXT( "EqBand" ), ( BandInfo * )&biEqBandDefault, BandCallback ); +ConfBandInfoCallback cbiSeekBand ( &biSeekBand, TEXT( "SeekBand" ), ( BandInfo * )&biSeekBandDefault, BandCallback ); +ConfBandInfoCallback cbiVolBand ( &biVolBand, TEXT( "VolBand" ), ( BandInfo * )&biVolBandDefault, BandCallback ); +ConfBandInfoCallback cbiPanBand ( &biPanBand, TEXT( "PanBand" ), ( BandInfo * )&biPanBandDefault, BandCallback ); +ConfBandInfoCallback cbiButtonsBand( &biButtonsBand, TEXT( "ButtonsBand" ), ( BandInfo * )&biButtonsBandDefault, BandCallback ); +ConfBandInfoCallback cbiVisBand ( &biVisBand, TEXT( "VisBand" ), ( BandInfo * )&biVisBandDefault, BandCallback ); + +bool bInvertPanSlider; +ConfBool cbInvertPanSlider( &bInvertPanSlider, TEXT( "InvertPanSlider" ), CONF_MODE_PUBLIC, false ); + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void BandCallback( ConfVar * var ) +{ + BandInfo * band; + int id; + + if( var == &cbiOrderBand ) + { + band = &biOrderBand; + id = BAND_ORDER; + } + else if( var == &cbiEqBand ) + { + band = &biEqBand; + id = BAND_EQ; + } + else if( var == &cbiSeekBand ) + { + band = &biSeekBand; + id = BAND_SEEK; + } + else if( var == &cbiVolBand ) + { + band = &biVolBand; + id = BAND_VOL; + } + else if( var == &cbiPanBand ) + { + band = &biPanBand; + id = BAND_PAN; + } + else if( var == &cbiButtonsBand ) + { + band = &biButtonsBand; + id = BAND_BUTTONS; + } + else if( var == &cbiVisBand ) + { + band = &biVisBand; + id = BAND_VIS; + } + else + { + return; + } + + band->m_iIndex = ( int )SendMessage( WindowRebar, RB_IDTOINDEX, id, 0 ); + if( band->m_iIndex == -1 ) return; + + REBARBANDINFO rbbi; + rbbi.cbSize = sizeof( REBARBANDINFO ); + rbbi.fMask = RBBIM_SIZE | RBBIM_STYLE; + SendMessage( WindowRebar, RB_GETBANDINFO, band->m_iIndex, ( LPARAM )&rbbi ); + + band->m_iWidth = rbbi.cx; + band->m_bBreak = ( ( rbbi.fStyle & RBBS_BREAK ) == RBBS_BREAK ); + band->m_bVisible = ( ( rbbi.fStyle & RBBS_HIDDEN ) != RBBS_HIDDEN ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Toolbar::Create() +{ + LoadCommonControls(); + + WindowRebar = CreateWindowEx( + WS_EX_TOOLWINDOW | + WS_EX_LEFT | + WS_EX_LTRREADING | + WS_EX_RIGHTSCROLLBAR, + REBARCLASSNAME, + NULL, + WS_CHILD | + WS_VISIBLE | + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN | + WS_BORDER | + RBS_VARHEIGHT | + RBS_BANDBORDERS | + RBS_DBLCLKTOGGLE | // RBS_AUTOSIZE + CCS_TOP | + CCS_NOPARENTALIGN | + CCS_NODIVIDER, // | CCS_ADJUSTABLE, + 0, + 0, + 0, + 0, + WindowMain, + NULL, + g_hInstance, + NULL + ); + +/* + #define STYLE 1 + #if STYLE == 1 + // Normal + MoveWindow( rebar, 0, 0, width, 30, TRUE ); + #elif STYLE == 2 + // Left ONLY + MoveWindow( rebar, 1, 0, width - 1, 30, TRUE ); + #endif +*/ + + REBARINFO rbi = { + sizeof( REBARINFO ), // UINT cbSize; + 0, // UINT fMask + NULL // HIMAGELIST himl + }; + + if( !SendMessage( WindowRebar, RB_SETBARINFO, 0, ( LPARAM )&rbi ) ) + { + return false; + } + + // Exchange window procedure + WndprocRebarBackup = ( WNDPROC )GetWindowLong( WindowRebar, GWL_WNDPROC ); + if( WndprocRebarBackup != NULL ) + { + SetWindowLong( WindowRebar, GWL_WNDPROC, ( LONG )WndprocRebar ); + } + + rebar_menu = CreatePopupMenu(); + AppendMenu( rebar_menu, MF_STRING, BAND_BUTTONS, TEXT( "Buttons" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_EQ, TEXT( "Equalizer" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_ORDER, TEXT( "Order" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_PAN, TEXT( "Panning" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_SEEK, TEXT( "Seekbar" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_VIS, TEXT( "Visualization" ) ); + AppendMenu( rebar_menu, MF_STRING, BAND_VOL, TEXT( "Volume" ) ); + + Rebar_BuildOrderBand(); + Rebar_BuildEqBand(); + Rebar_BuildSeekBand(); + Rebar_BuildVolBand(); + Rebar_BuildPanBand(); + Rebar_BuildButtonsBand(); + Rebar_BuildVisBand(); + + cbiOrderBand.Apply ( WindowRebar, BAND_ORDER ); + cbiEqBand.Apply ( WindowRebar, BAND_EQ ); + cbiSeekBand.Apply ( WindowRebar, BAND_SEEK ); + cbiVolBand.Apply ( WindowRebar, BAND_VOL ); + cbiPanBand.Apply ( WindowRebar, BAND_PAN ); + cbiButtonsBand.Apply( WindowRebar, BAND_BUTTONS ); + cbiVisBand.Apply ( WindowRebar, BAND_VIS ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildOrderBand() +{ + if( !WindowRebar ) return false; + + WindowOrder = CreateWindowEx( + 0, + TEXT( "COMBOBOX" ), + TEXT( "" ), + CBS_HASSTRINGS | + CBS_DROPDOWNLIST | + WS_CHILD, + 0, + 0, + 133, + 200, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowOrder ) return false; + + // Add mode names + TCHAR * szName; + for( int i = ORDER_FIRST; i <= ORDER_LAST; i++ ) + { + szName = Playback::Order::GetModeName( i ); + SendMessage( WindowOrder, CB_ADDSTRING, 0, ( LPARAM )szName ); + } + + // Initial value + SendMessage( WindowOrder, CB_SETCURSEL, Playback::Order::GetCurMode(), 0 ); + + RECT rc; + GetWindowRect( WindowOrder, &rc ); + + REBARBANDINFO rbBand; + rbBand.cbSize = sizeof( REBARBANDINFO ); + rbBand.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbBand.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biOrderBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbBand.lpText = TEXT( " Order " ); + rbBand.hwndChild = WindowOrder; + rbBand.cxMinChild = rc.right - rc.left; + rbBand.cyMinChild = 21; // IMP + rbBand.cx = biOrderBand.m_iWidth; + rbBand.wID = BAND_ORDER; + rbBand.cyChild = 21; + rbBand.cyMaxChild = 21; + rbBand.cyIntegral = 1; + rbBand.cxIdeal = 200; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbBand ); + + Font::Apply( WindowOrder ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool AddPreset( TCHAR * szPresetName ) +{ + const int iLen = _tcslen( szPresetName ); + TCHAR * szFinal = new TCHAR[ iLen + 2 + 1 ]; + szFinal[ 0 ] = TEXT( ' ' ); + szFinal[ iLen + 1 ] = TEXT( ' ' ); + szFinal[ iLen + 2 ] = TEXT( '\0' ); + memcpy( szFinal + 1, szPresetName, iLen * sizeof( TCHAR ) ); + + SendMessage( WindowEq, CB_ADDSTRING, 0, ( LPARAM )szFinal ); + + delete [] szFinal; + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildEqBand() +{ + if( !WindowRebar ) return false; + + WindowEq = CreateWindowEx( + 0, + TEXT( "COMBOBOX" ), + TEXT( "" ), + CBS_HASSTRINGS | + CBS_DROPDOWNLIST | + WS_CHILD, + 0, + 0, + 133, + 300, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowEq ) return false; + + // Add preset names + SendMessage( WindowEq, CB_ADDSTRING, 0, ( LPARAM )TEXT( " Disabled " ) ); + Playback::Eq::ReadPresets( AddPreset ); + + // Initial value + SendMessage( WindowEq, CB_SETCURSEL, Playback::Eq::GetCurIndex() + 1, 0 ); + + // TODO Disabled + // EnableWindow( WindowEq, FALSE ); + + + RECT rc; + GetWindowRect( WindowEq, &rc ); + + REBARBANDINFO rbBand; + rbBand.cbSize = sizeof( REBARBANDINFO ); + rbBand.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbBand.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biEqBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbBand.lpText = TEXT( " EQ " ); + rbBand.hwndChild = WindowEq; + rbBand.cxMinChild = rc.right - rc.left; + rbBand.cyMinChild = 21; // IMP + rbBand.cx = biEqBand.m_iWidth; + rbBand.wID = BAND_EQ; + rbBand.cyChild = 21; + rbBand.cyMaxChild = 21; + rbBand.cyIntegral = 1; + rbBand.cxIdeal = 200; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbBand ); + + Font::Apply( WindowEq ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildSeekBand() +{ + if( !WindowRebar ) return false; + + WindowSeek = CreateWindowEx( + 0, + TRACKBAR_CLASS, + TEXT( "" ), + WS_CHILD | + WS_DISABLED | + TBS_HORZ | + TBS_NOTICKS | + TBS_FIXEDLENGTH | + TBS_BOTH, + 0, + 0, + 300, + 21, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + // Range + SendMessage( + WindowSeek, + TBM_SETRANGE, + TRUE, + ( LPARAM )MAKELONG( 0, 999 ) + ); + + // Thumb size + SendMessage( + WindowSeek, + TBM_SETTHUMBLENGTH, + 14, + 0 + ); + + // Exchange window procedure + WndprocSeekBackup = ( WNDPROC )GetWindowLong( WindowSeek, GWL_WNDPROC ); + if( WndprocSeekBackup != NULL ) + { + SetWindowLong( WindowSeek, GWL_WNDPROC, ( LONG )WndprocSeek ); + } + + + REBARBANDINFO rbbi_seek; + rbbi_seek.cbSize = sizeof( REBARBANDINFO ); + rbbi_seek.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi_seek.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biSeekBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbbi_seek.lpText = " Pos"; + rbbi_seek.hwndChild = WindowSeek; + rbbi_seek.cxMinChild = 100; + rbbi_seek.cyMinChild = 21; // IMP + rbbi_seek.cx = biSeekBand.m_iWidth; + rbbi_seek.wID = BAND_SEEK; + rbbi_seek.cyChild = 21; + rbbi_seek.cyMaxChild = 21; + rbbi_seek.cyIntegral = 1; + rbbi_seek.cxIdeal = 300; + + + // Add band + SendMessage( + WindowRebar, + RB_INSERTBAND, + ( WPARAM )-1, + ( LPARAM )&rbbi_seek + ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildVolBand() +{ + if( !WindowRebar ) return false; + + WindowVol = CreateWindowEx( + 0, + TRACKBAR_CLASS, + TEXT( "" ), + WS_CHILD | + TBS_HORZ | + TBS_NOTICKS | + TBS_FIXEDLENGTH | + TBS_BOTH, + 0, + 0, + 200, + 21, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowVol ) return false; + + // Range + SendMessage( WindowVol, TBM_SETRANGE, TRUE, ( LPARAM )MAKELONG( 0, 255 ) ); + + // Initial value + SendMessage( WindowVol, TBM_SETPOS, TRUE, Playback::Volume::Get() ); + + // Thumbs size + SendMessage( WindowVol, TBM_SETTHUMBLENGTH, 14, 0 ); + + // Exchange window procedure + WndprocVolBackup = ( WNDPROC )GetWindowLong( WindowVol, GWL_WNDPROC ); + if( WndprocVolBackup != NULL ) + { + SetWindowLong( WindowVol, GWL_WNDPROC, ( LONG )WndprocVol ); + } + + + REBARBANDINFO rbbi_vol; + rbbi_vol.cbSize = sizeof( REBARBANDINFO ); + rbbi_vol.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi_vol.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biVolBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbbi_vol.lpText = TEXT( " Vol" ); + rbbi_vol.hwndChild = WindowVol; + rbbi_vol.cxMinChild = 100; + rbbi_vol.cyMinChild = 21; // IMP + rbbi_vol.cx = biVolBand.m_iWidth; + rbbi_vol.wID = BAND_VOL; + rbbi_vol.cyChild = 21; + rbbi_vol.cyMaxChild = 21; + rbbi_vol.cyIntegral = 1; + rbbi_vol.cxIdeal = 100; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbbi_vol ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildPanBand() +{ + if( !WindowRebar ) return false; + + WindowPan = CreateWindowEx( + 0, + TRACKBAR_CLASS, + TEXT( "" ), + WS_CHILD | + TBS_HORZ | + TBS_NOTICKS | + TBS_FIXEDLENGTH | + TBS_BOTH, + 0, + 0, + 200, + 21, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowPan ) return false; + + // Range + SendMessage( WindowPan, TBM_SETRANGE, TRUE, ( LPARAM )MAKELONG( -127, 127 ) ); + + // Initial value + const int iCurPan = Playback::Pan::Get(); + SendMessage( WindowPan, TBM_SETPOS, TRUE, bInvertPanSlider ? -iCurPan : iCurPan ); + + // Thumb size + SendMessage( WindowPan, TBM_SETTHUMBLENGTH, 14, 0 ); + + + // Exchange window procedure + WndprocPanBackup = ( WNDPROC )GetWindowLong( WindowPan, GWL_WNDPROC ); + if( WndprocPanBackup != NULL ) + { + SetWindowLong( WindowPan, GWL_WNDPROC, ( LONG )WndprocPan ); + } + + + REBARBANDINFO rbbi_pan; + rbbi_pan.cbSize = sizeof( REBARBANDINFO ); + rbbi_pan.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi_pan.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biPanBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbbi_pan.lpText = TEXT( " Pan" ); + rbbi_pan.hwndChild = WindowPan; + rbbi_pan.cxMinChild = 100; + rbbi_pan.cyMinChild = 21; // IMP + rbbi_pan.cx = biPanBand.m_iWidth; + rbbi_pan.wID = BAND_PAN; + rbbi_pan.cyChild = 21; + rbbi_pan.cyMaxChild = 21; + rbbi_pan.cyIntegral = 1; + rbbi_pan.cxIdeal = 100; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbbi_pan ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildButtonsBand() +{ + if( !WindowRebar ) return false; + + WindowButtons = CreateWindowEx( + 0, + TOOLBARCLASSNAME, + TEXT( "" ), + WS_CHILD | + TBSTYLE_FLAT | + CCS_NORESIZE | // Means we care about the size ourselves + CCS_NOPARENTALIGN | // Make it work with the rebar control + CCS_NODIVIDER, // No divider on top + 0, + 0, + 100, + 21, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowButtons ) return false; + + SendMessage( WindowButtons, TB_BUTTONSTRUCTSIZE, ( WPARAM )sizeof( TBBUTTON ), 0 ); + + TBBUTTON tb_button[ 7 ]; + + // Make image list, TODO delete later + HIMAGELIST hImages = ImageList_LoadBitmap( + GetModuleHandle( NULL ), // HINSTANCE hi + MAKEINTRESOURCE( IDB_BITMAP1 ), // LPCTSTR lpbmp + 14, // int cx + 6, // int cGrow + RGB( 255, 000, 255 ) // COLORREF crMask + ); + + SendMessage( WindowButtons, TB_SETIMAGELIST, 0, ( LPARAM )hImages ); + // SendMessage( WindowButtons, TB_SETHOTIMAGELIST, 0, ( LPARAM )hImages ); + // SendMessage( WindowButtons, TB_SETDISABLEDIMAGELIST, 0, ( LPARAM )hImages ); + + // Build buttons + tb_button[ 0 ].iBitmap = IMAGE_PREV; + tb_button[ 0 ].idCommand = WINAMP_BUTTON1; + tb_button[ 0 ].fsState = TBSTATE_ENABLED; + tb_button[ 0 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 0 ].dwData = 0; + tb_button[ 0 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Previous" )); + + tb_button[ 1 ].iBitmap = IMAGE_PLAY; + tb_button[ 1 ].idCommand = WINAMP_BUTTON2; + tb_button[ 1 ].fsState = TBSTATE_ENABLED; + tb_button[ 1 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 1 ].dwData = 0; + tb_button[ 1 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Play" )); + + tb_button[ 2 ].iBitmap = IMAGE_PAUSE; + tb_button[ 2 ].idCommand = WINAMP_BUTTON3; + tb_button[ 2 ].fsState = TBSTATE_ENABLED; + tb_button[ 2 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 2 ].dwData = 0; + tb_button[ 2 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Pause" )); + + tb_button[ 3 ].iBitmap = IMAGE_STOP; + tb_button[ 3 ].idCommand = WINAMP_BUTTON4; + tb_button[ 3 ].fsState = TBSTATE_ENABLED; + tb_button[ 3 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 3 ].dwData = 0; + tb_button[ 3 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Stop" )); + + tb_button[ 4 ].iBitmap = IMAGE_NEXT; + tb_button[ 4 ].idCommand = WINAMP_BUTTON5; + tb_button[ 4 ].fsState = TBSTATE_ENABLED; + tb_button[ 4 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 4 ].dwData = 0; + tb_button[ 4 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Next" )); + + tb_button[ 5 ].iBitmap = 0; + tb_button[ 5 ].idCommand = -1; + tb_button[ 5 ].fsState = TBSTATE_ENABLED; + tb_button[ 5 ].fsStyle = TBSTYLE_SEP; + tb_button[ 5 ].dwData = 0; + tb_button[ 5 ].iString = 0; + + tb_button[ 6 ].iBitmap = IMAGE_OPEN; + tb_button[ 6 ].idCommand = WINAMP_FILE_PLAY; + tb_button[ 6 ].fsState = TBSTATE_ENABLED; + tb_button[ 6 ].fsStyle = TBSTYLE_BUTTON; + tb_button[ 6 ].dwData = 0; + tb_button[ 6 ].iString = SendMessage( WindowButtons, TB_ADDSTRING, 0, ( LPARAM )TEXT( "Open" )); + + // Add buttons + SendMessage( WindowButtons, TB_SETBUTTONSIZE, 0, MAKELONG( 14, 14 ) ); + SendMessage( WindowButtons, TB_ADDBUTTONS, 7, ( LPARAM )( LPTBBUTTON )&tb_button ); + + // Disable labels + SendMessage( WindowButtons, TB_SETMAXTEXTROWS, 0, 0 ); + + // Resize + RECT r; + GetWindowRect( WindowButtons, &r ); + SetWindowPos( WindowButtons, NULL, 0, 0, 134, r.bottom - r.top, SWP_NOMOVE ); + GetWindowRect( WindowButtons, &r ); + + REBARBANDINFO rbbi_buttons; + rbbi_buttons.cbSize = sizeof( REBARBANDINFO ); + rbbi_buttons.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + // RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi_buttons.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biButtonsBand.m_bBreak ? RBBS_BREAK : 0 ); + + // rbbi_buttons.lpText = TEXT( " Playback" ); + rbbi_buttons.hwndChild = WindowButtons; + rbbi_buttons.cxMinChild = r.right - r.left; + rbbi_buttons.cyMinChild = 21; // IMP + rbbi_buttons.cx = r.right - r.left; + rbbi_buttons.wID = BAND_BUTTONS; + rbbi_buttons.cyChild = 21; + rbbi_buttons.cyMaxChild = 21; + rbbi_buttons.cyIntegral = 1; + rbbi_buttons.cxIdeal = r.right - r.left; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbbi_buttons ); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool Rebar_BuildVisBand() +{ + if( !WindowRebar ) return false; + + WindowVis = CreateWindowEx( + WS_EX_STATICEDGE, + TEXT( "STATIC" ), + TEXT( "" ), + WS_CHILD | SS_CENTER, + 0, + 0, + 100, + 21, + WindowRebar, + NULL, + g_hInstance, + NULL + ); + + if( !WindowVis ) return false; + Font::Apply( WindowVis ); + + // Resize + RECT r; + GetWindowRect( WindowButtons, &r ); +// SetWindowPos( WindowButtons, NULL, 0, 0, 146, r.bottom - r.top, SWP_NOMOVE ); +// GetWindowRect( WindowButtons, &r ); + + REBARBANDINFO rbbi_buttons; + rbbi_buttons.cbSize = sizeof( REBARBANDINFO ); + rbbi_buttons.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + RBBIM_CHILD | // The hwndChild member is valid or must be filled. + RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi_buttons.fStyle = RBBS_GRIPPERALWAYS | + RBBS_CHILDEDGE | + ( biVisBand.m_bBreak ? RBBS_BREAK : 0 ); + + rbbi_buttons.lpText = TEXT( " Vis " ); + rbbi_buttons.hwndChild = WindowVis; + rbbi_buttons.cxMinChild = r.right - r.left; + rbbi_buttons.cyMinChild = 21; // IMP + rbbi_buttons.cx = r.right - r.left; + rbbi_buttons.wID = BAND_VIS; + rbbi_buttons.cyChild = 21; + rbbi_buttons.cyMaxChild = 21; + rbbi_buttons.cyIntegral = 1; + rbbi_buttons.cxIdeal = r.right - r.left; + + // Add band + SendMessage( WindowRebar, RB_INSERTBAND, ( WPARAM )-1, ( LPARAM )&rbbi_buttons ); + + // Exchange window procedure + WndprocVisBackup = ( WNDPROC )GetWindowLong( WindowVis, GWL_WNDPROC ); + if( WndprocVisBackup != NULL ) + { + SetWindowLong( WindowVis, GWL_WNDPROC, ( LONG )WndprocVis ); + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ContextMenuRebar( POINT * p ) +{ + REBARBANDINFO rbbi; + rbbi.cbSize = sizeof( REBARBANDINFO ); + rbbi.fMask = RBBIM_STYLE; + + bool bBandVisible[ BAND_LAST - BAND_FIRST + 1 ] = { 0 }; // ID to visibility + int iBandIndex [ BAND_LAST - BAND_FIRST + 1 ] = { 0 }; // ID to Index + + for( int i = BAND_FIRST; i <= BAND_LAST; i++ ) + { + const int iArrayIndex = i - BAND_FIRST; + + // Get index + iBandIndex[ iArrayIndex ] = ( int )SendMessage( WindowRebar, RB_IDTOINDEX, i, 0 ); + if( iBandIndex[ iArrayIndex ] == -1 ) break; + + // Get info + if( !SendMessage( WindowRebar, RB_GETBANDINFO, iBandIndex[ iArrayIndex ], ( LPARAM )&rbbi ) ) + { + break; + } + + bBandVisible[ iArrayIndex ] = ( ( rbbi.fStyle & RBBS_HIDDEN ) != RBBS_HIDDEN ); + + // Update menu item + CheckMenuItem( + rebar_menu, + i, + bBandVisible[ iArrayIndex ] ? MF_CHECKED : MF_UNCHECKED + ); + } + + BOOL iIndex = TrackPopupMenu( + rebar_menu, + TPM_LEFTALIGN | + TPM_TOPALIGN | + TPM_NONOTIFY | + TPM_RETURNCMD | + TPM_RIGHTBUTTON, + p->x, + p->y, + 0, + WindowRebar, + NULL + ); + + // Toggle visibility + if( ( iIndex >= BAND_FIRST ) && ( iIndex <= BAND_LAST ) ) + { + const int iArrayIndex = iIndex - BAND_FIRST; + SendMessage( WindowRebar, RB_SHOWBAND, iBandIndex[ iArrayIndex ], bBandVisible[ iArrayIndex ] ? FALSE : TRUE ); + + // Turn off vis child + if( iIndex == BAND_VIS ) + { + HWND hChild = GetWindow( WindowVis, GW_CHILD ); + if( IsWindow( hChild ) ) + { + SendMessage( hChild, WM_DESTROY, 0, 0 ); + } + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocRebar( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_CONTEXTMENU: + { + POINT p; + GetCursorPos( &p ); + ContextMenuRebar( &p ); + return 0; + } + + case WM_DESTROY: + cbiOrderBand.TriggerCallback(); + cbiOrderBand.RemoveCallback(); + cbiEqBand.TriggerCallback(); + cbiEqBand.RemoveCallback(); + cbiSeekBand.TriggerCallback(); + cbiSeekBand.RemoveCallback(); + cbiVolBand.TriggerCallback(); + cbiVolBand.RemoveCallback(); + cbiPanBand.TriggerCallback(); + cbiPanBand.RemoveCallback(); + cbiButtonsBand.TriggerCallback(); + cbiButtonsBand.RemoveCallback(); + cbiVisBand.TriggerCallback(); + cbiVisBand.RemoveCallback(); + break; + + } + return CallWindowProc( WndprocRebarBackup, hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocSeek( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + static bool bDown = false; + static int iLastVal = 0; + + switch( message ) + { + case WM_LBUTTONDOWN: + { + SetFocus( hwnd ); + + // Capture mouse + SetCapture( hwnd ); + bDown = true; + + // NO BREAK! + } + case WM_MOUSEMOVE: + { + if( !bDown ) break; + if( !Playback::IsPlaying() ) return 0; // Deny slider move + + RECT r; + GetWindowRect( hwnd, &r ); + + const int iWidth = r.right - r.left; + if( !iWidth ) return 0; + int iVal = 1000 * MAX( 0, MIN( ( short )LOWORD( lp ), iWidth ) ) / iWidth; + + // Snap + if( ( short )LOWORD( lp ) < 7 ) + { + iVal = 0; + } + else if( abs( iWidth - ( short )LOWORD( lp ) ) < 7 ) + { + iVal = 999; + } + + // Update slider + PostMessage( hwnd, TBM_SETPOS, ( WPARAM )( TRUE ), iVal ); + + // Seek + iLastVal = iVal; + Playback::SeekPercent( iLastVal / 10.0f ); + + // TODO: Seek on slide ON/OFF + + + return 0; + } + case WM_LBUTTONUP: + case WM_NCLBUTTONUP: + { + // Release capture + bDown = false; + ReleaseCapture(); + + if( !Playback::IsPlaying() ) return 0; + + int ms = Playback::PercentToMs( iLastVal / 10.0f ); + if( ms < 0 ) break; + + int h = ms / 3600000; + int m = ( ms / 60000 ) % 60; + int s = ( ms / 1000 ) % 60; + ms = ms % 1000; + + + TCHAR szBuffer[ 5000 ]; + + /* + bool bShowMs = false; + + if( h ) + { + if( bShowMs ) + { + */ + + // 00:00:00.000 + _stprintf( szBuffer, TEXT( "Jumped to %02i:%02i:%02i.%03i" ), h, m, s, ms ); + Console::Append( szBuffer ); + Console::Append( " " ); + + /* + + } + else + { + // 00:00:00 + } + } + else if( m ) + { + if( bShowMs ) + { + // 00:00.000 + } + else + { + // 00:00 + } + } + else + { + if( bShowMs ) + { + // 00.000 + } + else + { + // 00s + } + } + */ + + return 0; + } + + case WM_KEYDOWN: + case WM_KEYUP: + SendMessage( WindowPlaylist, message, wp, lp ); + return 0; + + } + return CallWindowProc( WndprocSeekBackup, hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocVol( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + static bool bDown = false; + static int iLastVal = 0; + + switch( message ) + { + case WM_LBUTTONDOWN: + SetFocus( hwnd ); + + // Capture mouse + SetCapture( hwnd ); + bDown = true; + + // NO BREAK! + + case WM_MOUSEMOVE: + { + if( !bDown ) break; + + RECT r; + GetWindowRect( hwnd, &r ); + + const int iWidth = r.right - r.left; + if( !iWidth ) return 0; + const int x = ( int )( short )LOWORD( lp ); + int iVal = 255 * x / ( int )iWidth; + + if( iVal < 0 ) + iVal = 0; + else if( ( iVal > 255 ) || ( abs( iWidth - x ) < 7 ) ) // Snap + iVal = 255; + + // Update slider + PostMessage( hwnd, TBM_SETPOS , ( WPARAM )( TRUE ), iVal ); + + // Apply volume + iLastVal = iVal; + Playback::Volume::Set( iLastVal ); + + return 0; + } + case WM_LBUTTONUP: + case WM_NCLBUTTONUP: + { + // Release capture + bDown = false; + ReleaseCapture(); + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Volume changed to %i%%" ), iLastVal * 100 / 255 ); + Console::Append( szBuffer ); + Console::Append( " " ); + + return 0; + } + } + return CallWindowProc( WndprocVolBackup, hwnd, message, wp, lp ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocPan( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + static bool bDown = false; + static int iLastVal = 0; + + switch( message ) + { + case WM_LBUTTONDOWN: + SetFocus( hwnd ); + + // Capture mouse + SetCapture( hwnd ); + bDown = true; + + // NO BREAK! + + case WM_MOUSEMOVE: + { + if( !bDown ) break; + + RECT r; + GetWindowRect( hwnd, &r ); + + const int iWidth = r.right - r.left; + if( !iWidth ) return 0; + const int x = ( int )( short )LOWORD( lp ); + int iVal = 254 * x / ( int )iWidth - 127; + + if( iVal < -127 ) + iVal = -127; + else if( iVal > 127 ) + iVal = 127; + else if( abs( ( int )iWidth / 2 - x ) < 7 ) // Snap + iVal = 0; + + // Update slider + PostMessage( hwnd, TBM_SETPOS , ( WPARAM )( TRUE ), iVal ); + + // Invert if needed (slider needs original value!) + if( bInvertPanSlider ) + { + iVal = -iVal; + } + + // Apply panning + iLastVal = iVal; + Playback::Pan::Set( iVal ); + + return 0; + } + case WM_LBUTTONUP: + case WM_NCLBUTTONUP: + { + // Release capture + bDown = false; + ReleaseCapture(); + + TCHAR szBuffer[ 5000 ]; + if( iLastVal < 0 ) + _stprintf( szBuffer, TEXT( "Panning changed to %i%% left" ), -iLastVal * 100 / 127 ); + else if( iLastVal == 0 ) + _stprintf( szBuffer, TEXT( "Panning changed to center" ) ); + else // if( iLastVal > 0 ) + _stprintf( szBuffer, TEXT( "Panning changed to %i%% right" ), iLastVal * 100 / 127 ); + Console::Append( szBuffer ); + Console::Append( " " ); + + return 0; + } + } + return CallWindowProc( WndprocPanBackup, hwnd, message, wp, lp ); +} + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocVis( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_SHOWWINDOW: + { + if( wp == FALSE ) + { + const HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( !IsWindow( hChild ) ) break; + + // Strange workaround + ShowWindow( hChild, FALSE ); + SetParent( hChild, NULL ); + PostMessage( hChild, WM_SYSCOMMAND, SC_CLOSE, 0 ); + } + } + break; + + case WM_SIZE: + { + // Resize vis child + HWND hChild = GetWindow( hwnd, GW_CHILD ); + if( !IsWindow( hChild ) ) break; + MoveWindow( hChild, 0, 0, LOWORD( lp ), HIWORD( lp ), TRUE ); + } + break; + } + return CallWindowProc( WndprocVisBackup, hwnd, message, wp, lp ); +} + + +///////////////////////// + + + + /* + // Create the toolbar control to be added. + // hwndTB = CreateToolbar(hwndOwner, dwStyle); + + // Get the height of the toolbar. + dwBtnSize = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0,0); + + // Set values unique to the band with the toolbar. + rbBand.lpText = "Tool Bar"; + rbBand.hwndChild = hwndTB; + rbBand.cxMinChild = 0; + rbBand.cyMinChild = HIWORD(dwBtnSize); + rbBand.cx = 250; + + // Add the band that has the toolbar. + SendMessage(rebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + */ + + +/////////////////////////////////////// + +/* +void band_dummy() +{ + REBARBANDINFO rbbi3; + rbbi3.cbSize = sizeof( REBARBANDINFO ); + rbbi3.fMask = 0 | + // RBBIM_BACKGROUND | // The hbmBack member is valid or must be filled. + // RBBIM_CHILD | // The hwndChild member is valid or must be filled. + // RBBIM_CHILDSIZE | // The cxMinChild, cyMinChild, cyChild, cyMaxChild, and cyIntegral members are valid or must be filled. + // RBBIM_COLORS | // The clrFore and clrBack members are valid or must be filled. + // RBBIM_HEADERSIZE | // Version 4.71. The cxHeader member is valid or must be filled. + RBBIM_IDEALSIZE | // Version 4.71. The cxIdeal member is valid or must be filled. + RBBIM_ID | // The wID member is valid or must be filled. + // RBBIM_IMAGE | // The iImage member is valid or must be filled. + // RBBIM_LPARAM | // Version 4.71. The lParam member is valid or must be filled. + RBBIM_SIZE | // The cx member is valid or must be filled. + RBBIM_STYLE | // The fStyle member is valid or must be filled. + RBBIM_TEXT | // The lpText member is valid or must be filled. + 0; + + rbbi3.fStyle = RBBS_GRIPPERALWAYS; // | RBBS_BREAK; + rbbi3.lpText = " "; //NULL; // "Dummy"; + rbbi3.hwndChild = NULL; + rbbi3.cxMinChild = 10; //rc.right - rc.left; + rbbi3.cyMinChild = 21; // IMP + rbbi3.cx = 300; + rbbi3.wID = BAND_ID_DUMMY; + rbbi3.cyChild = 21; //rc.bottom - rc.top; + rbbi3.cyMaxChild = 21; // rc.bottom - rc.top; + rbbi3.cyIntegral = 1; + rbbi3.cxIdeal = 700; //rc.right - rc.left; + + // Add the band that has the combo box. + SendMessage( + rebar, + RB_INSERTBAND, + ( WPARAM )-1, + ( LPARAM )&rbbi3 + ); +} +*/ diff --git a/Branches/MusicMod/Player/Src/Rebar.h b/Branches/MusicMod/Player/Src/Rebar.h new file mode 100644 index 0000000000..e2f1feb685 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Rebar.h @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_TOOLBAR_H +#define PA_TOOLBAR_H + + + +#include "Global.h" + + + +extern HWND WindowRebar; +extern HWND WindowOrder; +extern HWND WindowEq; +extern HWND WindowSeek; + +extern HWND WindowVis; + +extern int iRebarHeight; + + + +namespace Toolbar +{ + bool Create(); +}; + + + +#endif // PA_TOOLBAR_H diff --git a/Branches/MusicMod/Player/Src/Resources/Buttons.bmp b/Branches/MusicMod/Player/Src/Resources/Buttons.bmp new file mode 100644 index 0000000000..3fb32f69cd Binary files /dev/null and b/Branches/MusicMod/Player/Src/Resources/Buttons.bmp differ diff --git a/Branches/MusicMod/Player/Src/Resources/Plainamp.ico b/Branches/MusicMod/Player/Src/Resources/Plainamp.ico new file mode 100644 index 0000000000..dbe09766af Binary files /dev/null and b/Branches/MusicMod/Player/Src/Resources/Plainamp.ico differ diff --git a/Branches/MusicMod/Player/Src/Resources/resrc1.aps b/Branches/MusicMod/Player/Src/Resources/resrc1.aps new file mode 100644 index 0000000000..9270c80c07 Binary files /dev/null and b/Branches/MusicMod/Player/Src/Resources/resrc1.aps differ diff --git a/Branches/MusicMod/Player/Src/Resources/resrc1.h b/Branches/MusicMod/Player/Src/Resources/resrc1.h new file mode 100644 index 0000000000..832fdbce47 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Resources/resrc1.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resrc1.rc +// +#define IDB_BITMAP1 102 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Branches/MusicMod/Player/Src/Resources/resrc1.rc b/Branches/MusicMod/Player/Src/Resources/resrc1.rc new file mode 100644 index 0000000000..70e368093b --- /dev/null +++ b/Branches/MusicMod/Player/Src/Resources/resrc1.rc @@ -0,0 +1,131 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "Plainamp.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,2,3,1 + PRODUCTVERSION 0,2,3,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Hartwork Project (http://www.hartwork.org)" + VALUE "FileDescription", "Plainamp" + VALUE "FileVersion", "0, 2, 3, 1" + VALUE "InternalName", "Plainamp" + VALUE "LegalCopyright", "Copyright (C) 2005 Sebastian Pipping" + VALUE "ProductName", "Plainamp" + VALUE "ProductVersion", "0, 2, 3, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP "Buttons.bmp" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Branches/MusicMod/Player/Src/Status.cpp b/Branches/MusicMod/Player/Src/Status.cpp new file mode 100644 index 0000000000..b12b98e128 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Status.cpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Status.h" +#include "Main.h" +#include "Util.h" +#include "GlobalVersion.h" + + + +int iStatusHeight = 40; // extern +HWND WindowStatus = NULL; // extern + +const TCHAR * const szStatusDefault = TEXT( " " ) PLAINAMP_LONG_TITLE; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool BuildMainStatus() +{ + LoadCommonControls(); + + WindowStatus = CreateWindowEx( + 0, + STATUSCLASSNAME, + szStatusDefault, + WS_CHILD | + WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + WindowMain, + NULL, + g_hInstance, + NULL + ); + + if( !WindowStatus ) return false; + + RECT r = { 0, 0, 0, 0 }; + GetWindowRect( WindowStatus, &r ); + iStatusHeight = r.bottom - r.top; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool StatusUpdate( TCHAR * szText ) +{ + if( !WindowStatus ) return false; + SetWindowText( WindowStatus, szText ); + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void StatusReset() +{ + if( !WindowStatus ) return; + SetWindowText( WindowStatus, szStatusDefault ); +} diff --git a/Branches/MusicMod/Player/Src/Status.h b/Branches/MusicMod/Player/Src/Status.h new file mode 100644 index 0000000000..08e12d3527 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Status.h @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_STATUS_H +#define PA_STATUS_H + + + +#include "Global.h" + + + +extern int iStatusHeight; +extern HWND WindowStatus; + + + +bool BuildMainStatus(); +bool StatusUpdate( TCHAR * szText ); +void StatusReset(); + + + +#endif // PA_STATUS_H diff --git a/Branches/MusicMod/Player/Src/Unicode.cpp b/Branches/MusicMod/Player/Src/Unicode.cpp new file mode 100644 index 0000000000..e332100b3d --- /dev/null +++ b/Branches/MusicMod/Player/Src/Unicode.cpp @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Unicode.h" + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ToAnsi( char * szDest, wchar_t * szSource, int iLen ) +{ + char * const szBytesource = ( char * )szSource; + for( int i = 0; i < iLen; i++ ) + { + szDest[ i ] = szBytesource[ 2 * i + 1 ]; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +/* +void ToUnicode( wchar_t * szDest, char * szSource, int iLen ) +{ + for( int i = 0; i < iLen; i++ ) + { + szDest[ i ] = ( wchar_t )szSource[ i ]; + } +} +*/ + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ToTchar( TCHAR * szDest, wchar_t * szSource, int iLen ) +{ +#ifdef PA_UNICODE + memcpy( szDest, szSource, 2 * iLen ); +#else + char * const stByteSource = ( TCHAR * )szSource; + for( int i = 0; i < iLen; i++ ) + { + szDest[ i ] = stByteSource[ 2 * i + 1 ]; + } +#endif +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void ToTchar( TCHAR * szDest, char * szSource, int iLen ) +{ +#ifdef PA_UNICODE + for( int i = 0; i < iLen; i++ ) + { + szDest[ i ] = szSource[ 2 * i + 1 ]; + } +#else + memcpy( szDest, szSource, iLen ); +#endif +} diff --git a/Branches/MusicMod/Player/Src/Unicode.h b/Branches/MusicMod/Player/Src/Unicode.h new file mode 100644 index 0000000000..55a1770e49 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Unicode.h @@ -0,0 +1,29 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_UNICODE_H +#define PA_UNICODE_H + + + +#include "Global.h" + + + +void ToAnsi( char * szDest, wchar_t * szSource, int iLen ); +// void ToUnicode( wchar_t * szDest, char * szSource, int iLen ) +void ToTchar( TCHAR * szDest, wchar_t * szSource, int iLen ); +void ToTchar( TCHAR * szDest, char * szSource, int iLen ); + + + +#endif // PA_UNICODE_H diff --git a/Branches/MusicMod/Player/Src/Util.cpp b/Branches/MusicMod/Player/Src/Util.cpp new file mode 100644 index 0000000000..26c5deb3dc --- /dev/null +++ b/Branches/MusicMod/Player/Src/Util.cpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Util.h" + + + +#ifndef ICC_STANDARD_CLASSES +# define ICC_STANDARD_CLASSES 0x00004000 +#endif + + + +bool bLoaded = false; +bool bAvailable = false; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool LoadCommonControls() +{ + if( bLoaded ) return bAvailable; + + INITCOMMONCONTROLSEX icce = { + sizeof( INITCOMMONCONTROLSEX ), + ICC_BAR_CLASSES | // Statusbar, trackbar, toolbar + ICC_COOL_CLASSES | // Rebar + ICC_LISTVIEW_CLASSES | // Listview + ICC_STANDARD_CLASSES | // + ICC_TREEVIEW_CLASSES // Treeview + }; + + bLoaded = true; + bAvailable = ( InitCommonControlsEx( &icce ) == TRUE ); + + return bAvailable; +} diff --git a/Branches/MusicMod/Player/Src/Util.h b/Branches/MusicMod/Player/Src/Util.h new file mode 100644 index 0000000000..5bee2a9d2c --- /dev/null +++ b/Branches/MusicMod/Player/Src/Util.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_UTIL_H +#define PA_UTIL_H + + + +#include "Global.h" + + + +bool LoadCommonControls(); + + + +#endif // PA_UTIL_H diff --git a/Branches/MusicMod/Player/Src/VisCache.cpp b/Branches/MusicMod/Player/Src/VisCache.cpp new file mode 100644 index 0000000000..37d5d1497b --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisCache.cpp @@ -0,0 +1,303 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "VisCache.h" +#include "Console.h" +#include "malloc.h" + + + +unsigned char * SpecCacheLeft; +unsigned char * SpecCacheRight; +unsigned char * WaveCacheLeft; +unsigned char * WaveCacheRight; + +int iWritePos; +int iWriteOffset; // == iWritePos * 576 + +int iVisLatency; +int iDataFps; +int iCacheLen; + +bool bReady = false; + +int iReadTimeMs = 0; +int iWriteTimeMs = 0; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache_Resize( int iLatency, int iFps ) +{ + // if( !bReady ) return; + + const int iNewCacheLen = ( iFps * iLatency ) / 1000 + 1; +/* +TCHAR szBuffer[ 5000 ]; +_stprintf( szBuffer, TEXT( "RESIZE ( %i * %i ) / 1000 + 1 === %i" ), iFps, iLatency, iNewCacheLen ); +Console::Append( szBuffer ); +*/ + const int iByteNewCacheLen = iNewCacheLen * 576; + if( !iCacheLen ) + { + // First time + SpecCacheLeft = ( unsigned char * )malloc( iByteNewCacheLen ); +// memset( SpecCacheLeft, 0, iByteNewCacheLen ); + SpecCacheRight = ( unsigned char * )malloc( iByteNewCacheLen ); +// memset( SpecCacheRight, 0, iByteNewCacheLen ); + WaveCacheLeft = ( unsigned char * )malloc( iByteNewCacheLen ); +// memset( WaveCacheLeft, 0, iByteNewCacheLen ); + WaveCacheRight = ( unsigned char * )malloc( iByteNewCacheLen ); +// memset( WaveCacheRight, 0, iByteNewCacheLen ); + } + else if( iNewCacheLen > iCacheLen ) + { + // Grow + const int iByteCacheLen = iCacheLen * 576; + const int iByteClearLen = ( iNewCacheLen - iCacheLen ) * 576; + + SpecCacheLeft = ( unsigned char * )realloc( SpecCacheLeft, iByteNewCacheLen ); +// memset( SpecCacheLeft + iByteCacheLen, 0, iByteClearLen ); + SpecCacheRight = ( unsigned char * )realloc( SpecCacheRight, iByteNewCacheLen ); +// memset( SpecCacheRight + iByteCacheLen, 0, iByteClearLen ); + WaveCacheLeft = ( unsigned char * )realloc( WaveCacheLeft, iByteNewCacheLen ); +// memset( WaveCacheLeft + iByteCacheLen, 0, iByteClearLen ); + WaveCacheRight = ( unsigned char * )realloc( WaveCacheRight, iByteNewCacheLen ); +// memset( WaveCacheRight + iByteCacheLen, 0, iByteClearLen ); + } + + iCacheLen = iNewCacheLen; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::Create() +{ + if( bReady ) return; + + iWritePos = 0; + iWriteOffset = 0; + + iVisLatency = 50; + iDataFps = 40; + iCacheLen = 0; + + bReady = true; + + + VisCache_Resize( iVisLatency, iDataFps ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::Destroy() +{ + if( !bReady ) return; + + if( SpecCacheLeft ) free( SpecCacheLeft ); + if( SpecCacheRight ) free( SpecCacheRight ); + if( WaveCacheLeft ) free( WaveCacheLeft ); + if( WaveCacheRight ) free( WaveCacheRight ); + + bReady = false; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::EnsureLatency( int iLatency ) +{ + if( !bReady ) return; + + if( iLatency <= iVisLatency ) return; + + VisCache_Resize( + iLatency, + iDataFps + ); + iVisLatency = iLatency; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::EnsureDataFps( int iFps ) +{ + if( !bReady ) return; + if( iFps <= iDataFps ) return; + + VisCache_Resize( + iVisLatency, + iFps + ); + iDataFps = iFps; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::Clean() +{ + if( !bReady ) return; + + const int iByteCacheLen = iCacheLen * 576; + memset( SpecCacheLeft, 0, iByteCacheLen ); + memset( SpecCacheRight, 0, iByteCacheLen ); + memset( WaveCacheLeft, 0, iByteCacheLen ); + memset( WaveCacheRight, 0, iByteCacheLen ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::SetReadTime( int ms ) +{ + iReadTimeMs = ms; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::SetWriteTime( int ms ) +{ + iWriteTimeMs = ms; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int VisCache::LatencyToOffset( int iLatency ) +{ + int iFrame = iWritePos - 1 - ( ( iWriteTimeMs - iReadTimeMs - iLatency ) * iDataFps ) / 1000; + if( iFrame < 0 ) iFrame += iCacheLen; + return iFrame * 576; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::NextFrame() +{ + iWritePos++; + if( iWritePos >= iCacheLen ) iWritePos = 0; + iWriteOffset = iWritePos * 576; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::PutSpecLeft( unsigned char * data ) +{ + if( !bReady ) return; + memcpy( SpecCacheLeft + iWriteOffset, data, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::PutSpecRight( unsigned char * data ) +{ + if( !bReady ) return; + memcpy( SpecCacheRight + iWriteOffset, data, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::PutWaveLeft( unsigned char * data ) +{ + if( !bReady ) return; + memcpy( WaveCacheLeft + iWriteOffset, data, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::PutWaveRight( unsigned char * data ) +{ + if( !bReady ) return; + memcpy( WaveCacheRight + iWriteOffset, data, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::GetSpecLeft( unsigned char * dest, int iOffset ) +{ + if( !bReady ) return; + memcpy( dest, SpecCacheLeft + iOffset, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::GetSpecRight( unsigned char * dest, int iOffset ) +{ + if( !bReady ) return; + memcpy( dest, SpecCacheRight + iOffset, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::GetWaveLeft( unsigned char * dest, int iOffset ) +{ + if( !bReady ) return; + memcpy( dest, WaveCacheLeft + iOffset, 576 ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void VisCache::GetWaveRight( unsigned char * dest, int iOffset ) +{ + if( !bReady ) return; + memcpy( dest, WaveCacheRight + iOffset, 576 ); +} diff --git a/Branches/MusicMod/Player/Src/VisCache.h b/Branches/MusicMod/Player/Src/VisCache.h new file mode 100644 index 0000000000..f093d5d089 --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisCache.h @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_VIS_CACHE_H +#define PA_VIS_CACHE_H + + +#include "Global.h" + + + +namespace VisCache +{ + void Create(); + void Destroy(); + + void EnsureLatency( int iLatency ); // TODO + void EnsureDataFps( int iFps ); // TODO + + void Clean(); + + void SetReadTime( int ms ); + void SetWriteTime( int ms ); + + int LatencyToOffset( int iLatency ); + void NextFrame(); + + void PutSpecLeft( unsigned char * data ); + void PutSpecRight( unsigned char * data ); + void PutWaveLeft( unsigned char * data ); + void PutWaveRight( unsigned char * data ); + + void GetSpecLeft( unsigned char * dest, int iOffset ); + void GetSpecRight( unsigned char * dest, int iOffset ); + void GetWaveLeft( unsigned char * dest, int iOffset ); + void GetWaveRight( unsigned char * dest, int iOffset ); +}; + + + +#endif // PA_VIS_CACHE_H diff --git a/Branches/MusicMod/Player/Src/VisModule.cpp b/Branches/MusicMod/Player/Src/VisModule.cpp new file mode 100644 index 0000000000..fce981a0f7 --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisModule.cpp @@ -0,0 +1,358 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "VisModule.h" +#include "Console.h" +#include "Unicode.h" +#include "Playback.h" +#include "VisCache.h" +#include "PluginManager.h" +#include + + +VisModule ** active_vis_mods = NULL; // extern +int active_vis_count = 0; // extern + + +/* +BOOL CALLBACK EnumThreadWndProc( HWND hwnd, LPARAM lp ) +{ +// MessageBox( 0, "EnumThreadWndProc", "", 0 ); + DestroyWindow( hwnd ); +} +*/ + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +void PlugThread( PVOID pvoid ) +{ + // TODO: cleanup!!! + + Console::Append( TEXT( "Visualization thread born" ) ); + Console::Append( " " ); + + VisModule * mod = ( VisModule * )pvoid; + if( !mod ) return; + if( mod->mod->Init( mod->mod ) != 0 ) return; + + + VisCache::Create(); + + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + active_vis_count++; + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + + bool bKeepItGoing = true; + + + bool bQuitCalled = false; + + int iLast = GetTickCount(); + + // Message loop + MSG msg; + msg.message = WM_QUIT + 1; // Must be != WM_QUIT + do + { + if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + if( msg.message == WM_QUIT ) + { +//////////////////////////////////////////////////////////////////////////////// + // Stop + if( !bQuitCalled ) + { + mod->mod->Quit( mod->mod ); + bQuitCalled = true; + } +//////////////////////////////////////////////////////////////////////////////// + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + + if( msg.message == WM_CLOSE || ( ( msg.message == WM_SYSCOMMAND ) && ( msg.wParam == SC_CLOSE ) ) ) + { +//////////////////////////////////////////////////////////////////////////////// + // Stop + if( !bQuitCalled ) + { + mod->mod->Quit( mod->mod ); + bQuitCalled = true; + } +//////////////////////////////////////////////////////////////////////////////// + } + } + + if( bKeepItGoing ) + { + // Variant A + const int iNow = GetTickCount(); + if( iNow - iLast > mod->mod->delayMs ) + { + if( Playback::IsPlaying() ) + { + if( mod->bAllowRender ) + { + mod->bAllowRender = false; + + + const int iOffset = VisCache::LatencyToOffset( mod->mod->latencyMs ); + + switch( mod->mod->spectrumNch ) + { + case 2: + VisCache::GetSpecRight( mod->mod->spectrumData[ 1 ], iOffset ); + case 1: + VisCache::GetSpecLeft( mod->mod->spectrumData[ 0 ], iOffset ); + } + + switch( mod->mod->waveformNch ) + { + case 2: + VisCache::GetWaveRight( mod->mod->waveformData[ 1 ], iOffset ); + case 1: + VisCache::GetWaveLeft( mod->mod->waveformData[ 0 ], iOffset ); + } + + if( mod->mod->Render( mod->mod ) != 0 ) + { +//////////////////////////////////////////////////////////////////////////////// + // Stop + if( !bQuitCalled ) + { + // TODO: milkdrop doesn#t save window position + // when quit using manual plugin stop + + mod->mod->Quit( mod->mod ); + bQuitCalled = true; + } +//////////////////////////////////////////////////////////////////////////////// +/* + // Destroy all windows belonging to this thread + // This will lead to WM_QUIT automatically + EnumThreadWindows( GetCurrentThreadId(), EnumThreadWndProc, 0 ); + bKeepItGoing = false; +*/ + } + + + iLast = iNow; + } + } + else + { + if( mod->mod->Render( mod->mod ) != 0 ) + { +//////////////////////////////////////////////////////////////////////////////// + // Stop + if( !bQuitCalled ) + { + mod->mod->Quit( mod->mod ); + bQuitCalled = true; + } +//////////////////////////////////////////////////////////////////////////////// +/* + // Destroy all windows belonging to this thread + // This will lead to WM_QUIT automatically + EnumThreadWindows( GetCurrentThreadId(), EnumThreadWndProc, 0 ); + bKeepItGoing = false; +*/ + } + + iLast = iNow; + } + } + +//////////////////////////////////////////////////////////////////////////////// + bool bVisLockLeft = false; + VisLock.Enter(); +//////////////////////////////////////////////////////////////////////////////// + + if( mod->bShouldQuit ) + { + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Leave(); + bVisLockLeft = true; +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// + // Stop + if( !bQuitCalled ) + { + mod->mod->Quit( mod->mod ); + bQuitCalled = true; + } +//////////////////////////////////////////////////////////////////////////////// +/* + // Destroy all windows belonging to this thread + // This will lead to WM_QUIT automatically + EnumThreadWindows( GetCurrentThreadId(), EnumThreadWndProc, 0 ); + bKeepItGoing = false; +*/ + } + +//////////////////////////////////////////////////////////////////////////////// + if( !bVisLockLeft ) + { + VisLock.Leave(); + } +//////////////////////////////////////////////////////////////////////////////// + } + + Sleep( 1 ); + } + while( msg.message != WM_QUIT ); + + mod->bShouldQuit = false; + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); + if( ( active_vis_count > 1 ) && ( mod->iArrayIndex < active_vis_count - 1 ) ) + { + active_vis_mods[ mod->iArrayIndex ] = active_vis_mods[ active_vis_count - 1 ]; + active_vis_mods[ mod->iArrayIndex ]->iArrayIndex = mod->iArrayIndex; + } + active_vis_count--; + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + mod->iArrayIndex = -1; + +/* + // Stop + mod->mod->Quit( mod->mod ); +*/ + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); + mod->bActive = false; + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + UpdatePluginStatus( mod->plugin, true, mod->plugin->IsActive() ); + + Console::Append( TEXT( "Visualization thread dead" ) ); + Console::Append( " " ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +VisModule::VisModule( char * szName, int iIndex, winampVisModule * mod, VisPlugin * plugin ) +{ + iArrayIndex = -1; + bActive = false; + bShouldQuit = false; + bAllowRender = false; + + iNameLen = ( int )strlen( szName ); + this->szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( this->szName, szName, iNameLen ); + this->szName[ iNameLen ] = TEXT( '\0' ); + + this->iIndex = iIndex; + this->mod = mod; + this->plugin = plugin; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisModule::Start() +{ + if( !mod ) return false; + if( bActive ) return false; + if( plugin->IsActive() ) return false; + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); + if( !active_vis_count ) + { + active_vis_mods = new VisModule * [ 1 ]; + active_vis_mods[ 0 ] = this; + } + else + { + VisModule ** new_active_vis_mods = new VisModule * [ active_vis_count + 1 ]; + memcpy( new_active_vis_mods, active_vis_mods, active_vis_count * sizeof( VisModule * ) ); + new_active_vis_mods[ active_vis_count ] = this; + delete [] active_vis_mods; + active_vis_mods = new_active_vis_mods; + } + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + iArrayIndex = active_vis_count; + + + // Start + _beginthread( PlugThread, 1024 * 1024, ( PVOID )this ); + + bActive = true; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisModule::Stop() +{ + if( !mod ) return false; + if( !bActive ) return false; + if( !plugin->IsActive() ) return false; + +//////////////////////////////////////////////////////////////////////////////// + VisLock.Enter(); + bShouldQuit = true; + VisLock.Leave(); +//////////////////////////////////////////////////////////////////////////////// + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisModule::Config() +{ + if( !mod ) return false; + if( !mod->Config ) return false; + + mod->Config( mod ); + + return true; +} diff --git a/Branches/MusicMod/Player/Src/VisModule.h b/Branches/MusicMod/Player/Src/VisModule.h new file mode 100644 index 0000000000..23e13e7450 --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisModule.h @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_VIS_MODULE_H +#define PA_VIS_MODULE_H + + + +#include "Global.h" +#include "VisPlugin.h" +#include + + + +class VisModule; +class VisPlugin; + +extern VisModule ** active_vis_mods; +extern int active_vis_count; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp visualization module wrapper +//////////////////////////////////////////////////////////////////////////////// +class VisModule +{ +public: + VisModule( char * szName, int iIndex, winampVisModule * mod, VisPlugin * plugin ); + + bool Start(); + bool Config(); + bool Stop(); + + inline bool IsActive() { return bActive; } + + inline TCHAR * GetName() { return szName; } + inline int GetNameLen() { return iNameLen; } + +private: + int iArrayIndex; + bool bActive; + bool bShouldQuit; + bool bAllowRender; + + TCHAR * szName; + int iNameLen; + + int iIndex; + winampVisModule * mod; + VisPlugin * plugin; + + + friend void PlugThread( PVOID pvoid ); + friend void VSAAdd( void * data, int timestamp ); + friend void VSAAddPCMData( void * PCMData, int nch, int bps, int timestamp ); + friend int VSAGetMode( int * specNch, int * waveNch ); +}; + + + +#endif // PA_VIS_MODULE_H diff --git a/Branches/MusicMod/Player/Src/VisPlugin.cpp b/Branches/MusicMod/Player/Src/VisPlugin.cpp new file mode 100644 index 0000000000..af86f41861 --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisPlugin.cpp @@ -0,0 +1,188 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "VisPlugin.h" +#include "Unicode.h" +#include "Console.h" +#include "Main.h" + + + +vector vis_plugins; // extern + +Lock VisLock = Lock( TEXT( "PLAINAMP_VIS_LOCK" ) ); // extern + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +VisPlugin::VisPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) +{ + header = NULL; + + if( !Load() ) + { + return; + } + + if( !bKeepLoaded ) + { + Unload(); + } + + vis_plugins.push_back( this ); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisPlugin::Load() +{ + // (1) Load DLL + hDLL = LoadLibrary( GetFullpath() ); + if( !hDLL ) return false; + + // (2) Find export + WINAMP_VIS_GETTER winampGetVisHeader = + ( WINAMP_VIS_GETTER )GetProcAddress( hDLL, "winampVisGetHeader" ); + if( winampGetVisHeader == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + + // (3) Get header + header = winampGetVisHeader(); + if( header == NULL ) + { + FreeLibrary( hDLL ); + hDLL = NULL; + return false; + } + +//////////////////////////////////////////////////////////////////////////////// + // Forget old modules or we get them twice + if( !modules.empty() ) + { + modules.clear(); + } +//////////////////////////////////////////////////////////////////////////////// + + if( !szName ) + { + // Note: The prefix is not removed to hide their + // origin at Nullsoft! It just reads easier. + if( !strnicmp( header->description, "nullsoft ", 9 ) ) + { + header->description += 9; + } + iNameLen = ( int )strlen( header->description ); + szName = new TCHAR[ iNameLen + 1 ]; + ToTchar( szName, header->description, iNameLen ); + szName[ iNameLen ] = TEXT( '\0' ); + } + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); + Console::Append( szBuffer ); + + // (4) Get modules + winampVisModule * mod; + int iFound = 0; + while( true ) + { + mod = header->getModule( iFound ); + if( !mod ) break; + + // (4a) Modify module + mod->hDllInstance = hDLL; + mod->hwndParent = WindowMain; + mod->sRate = 44100; // TODO + mod->nCh = 2; // TODO + + // (4b) Add module to list + VisModule * vismod = new VisModule( + mod->description, // char * szName + iFound, // UINT uIndex + mod, // winampVisModule * mod + this // VisPlugin * plugin + ); + modules.push_back( vismod ); + + iFound++; + + _stprintf( szBuffer, TEXT( " %s" ), vismod->GetName() ); + Console::Append( szBuffer ); + } + + Console::Append( TEXT( " " ) ); + + if( !iFound ) return false; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisPlugin::Unload() +{ + if( !IsLoaded() ) return true; + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Unloading <%s>" ), GetFilename() ); + Console::Append( szBuffer ); + Console::Append( TEXT( " " ) ); + + header = NULL; + + /* + TODO + VisModule * walk; + vector ::iterator iter = modules.begin(); + while( iter != modules.end() ) + { + walk = *iter; + delete [] walk->szName; + delete walk; + + iter++; + } + */ + + FreeLibrary( hDLL ); + hDLL = NULL; + + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +bool VisPlugin::IsActive() +{ + vector ::iterator iter = modules.begin(); + while( iter != modules.end() ) + { + if( ( *iter )->IsActive() ) return true; + iter++; + } + return false; +} diff --git a/Branches/MusicMod/Player/Src/VisPlugin.h b/Branches/MusicMod/Player/Src/VisPlugin.h new file mode 100644 index 0000000000..92cfdc5a40 --- /dev/null +++ b/Branches/MusicMod/Player/Src/VisPlugin.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_VIS_PLUGIN_H +#define PA_VIS_PLUGIN_H + + + +#include "Global.h" +#include "Plugin.h" +#include "Winamp/Vis.h" +#include "VisModule.h" +#include "Lock.h" +#include + +using namespace std; + + + +typedef winampVisHeader * ( * WINAMP_VIS_GETTER )( void ); + + + +class VisModule; +class VisPlugin; + +extern vector vis_plugins; +extern Lock VisLock; + + + +//////////////////////////////////////////////////////////////////////////////// +/// Winamp visualization plugin wrapper +//////////////////////////////////////////////////////////////////////////////// +class VisPlugin : public Plugin +{ +public: + VisPlugin( TCHAR * szDllpath, bool bKeepLoaded ); + + bool Load(); + bool Unload(); + + TCHAR * GetTypeString() { return TEXT( "Visual" ); } + int GetTypeStringLen() { return 6; } + PluginType GetType() { return PLUGIN_TYPE_VIS; } + + bool IsActive(); + +private: + winampVisHeader * header; + vector modules; + + + friend void ContextMenuVis( VisPlugin * vis, POINT * p ); +}; + + + +#endif // PA_VIS_PLUGIN_H diff --git a/Branches/MusicMod/Player/Src/Winamp.cpp b/Branches/MusicMod/Player/Src/Winamp.cpp new file mode 100644 index 0000000000..a5bc06060f --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp.cpp @@ -0,0 +1,985 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Winamp.h" +#include "Playback.h" +#include "Playlist.h" +#include "Console.h" +#include "Main.h" +#include "Winamp/wa_ipc.h" +#include "Winamp/wa_msgids.h" +#include "AddDirectory.h" +#include "AddFiles.h" +#include "Prefs.h" +#include "PluginManager.h" +#include "Embed.h" +#include "Unicode.h" +#include "zlib/zlib.h" +#include "Rebar.h" + + + +int IPC_GENHOTKEYS_ADD = 0; +int ID_DYNAMICLIBRARY = 0; +int IPC_GETPLAINBARTARGET = 0; + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK WndprocWinamp( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_COMMAND: +/* + { + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "WM_COMMAND <%i> <%i>" ), wp, lp ); + Console::Append( szBuffer ); + } +*/ + switch( LOWORD( wp ) ) + { + case WINAMP_FILE_QUIT: + PostMessage( WindowMain, WM_SYSCOMMAND, SC_CLOSE, 0 ); + break; + + case WINAMP_OPTIONS_PREFS: + Prefs::Show(); + break; +/* + case WINAMP_OPTIONS_AOT: break; + case WINAMP_FILE_REPEAT: break; + case WINAMP_FILE_SHUFFLE: break; + case WINAMP_HIGH_PRIORITY: break; +*/ + case WINAMP_FILE_PLAY: + AddFiles(); + break; +/* + case WINAMP_OPTIONS_EQ: break; + case WINAMP_OPTIONS_ELAPSED: break; + case WINAMP_OPTIONS_REMAINING: break; + case WINAMP_OPTIONS_PLEDIT: break; +*/ + case WINAMP_HELP_ABOUT: + About( hwnd ); + break; + + case WINAMP_MAINMENU: + { + POINT p; + GetCursorPos( &p ); + + CheckMenuItem( + main_context_menu, + PLAINAMP_TOGGLE_CONSOLE, + IsWindowVisible( WindowConsole ) ? MF_CHECKED : MF_UNCHECKED + ); + CheckMenuItem( + main_context_menu, + PLAINAMP_TOGGLE_MANAGER, + IsWindowVisible( WindowManager ) ? MF_CHECKED : MF_UNCHECKED + ); + + TrackPopupMenu( + main_context_menu, + TPM_LEFTALIGN | + TPM_TOPALIGN | + TPM_RIGHTBUTTON, + p.x, + p.y, + 0, + hwnd, + NULL + ); + + break; + } + + case WINAMP_BUTTON1: + Playback::Prev(); + Playback::UpdateSeek(); + break; + + case WINAMP_BUTTON2: + Playback::Play(); + Playback::UpdateSeek(); + break; + + case WINAMP_BUTTON3: + Playback::Pause(); + Playback::UpdateSeek(); + break; + + case WINAMP_BUTTON4: + Playback::Stop(); + Playback::UpdateSeek(); + break; + + case WINAMP_BUTTON5: + Playback::Next(); + Playback::UpdateSeek(); + break; + +/* + case WINAMP_BUTTON1_SHIFT: break; + case WINAMP_BUTTON2_SHIFT: break; + case WINAMP_BUTTON3_SHIFT: break; + case WINAMP_BUTTON4_SHIFT: break; + case WINAMP_BUTTON5_SHIFT: break; + case WINAMP_BUTTON1_CTRL: break; + case WINAMP_BUTTON2_CTRL: break; + case WINAMP_BUTTON3_CTRL: break; + case WINAMP_BUTTON4_CTRL: break; + case WINAMP_BUTTON5_CTRL: break; +*/ + + case WINAMP_VOLUMEUP: + Playback::Volume::Up(); + // TODO Update slider + break; + + case WINAMP_VOLUMEDOWN: + Playback::Volume::Down(); + // TODO Update slider + break; + + case WINAMP_FFWD5S: + Playback::Forward(); + Playback::UpdateSeek(); + break; + + case WINAMP_REW5S: + Playback::Rewind(); + Playback::UpdateSeek(); + break; +/* + case WINAMP_NEXT_WINDOW: break; + case WINAMP_OPTIONS_WINDOWSHADE: break; + case WINAMP_OPTIONS_DSIZE: break; + case IDC_SORT_FILENAME: break; + case IDC_SORT_FILETITLE: break; + case IDC_SORT_ENTIREFILENAME: break; + case IDC_SELECTALL: break; + case IDC_SELECTNONE: break; + case IDC_SELECTINV: break; + case IDM_EQ_LOADPRE: break; + case IDM_EQ_LOADMP3: break; + case IDM_EQ_LOADDEFAULT: break; + case IDM_EQ_SAVEPRE: break; + case IDM_EQ_SAVEMP3: break; + case IDM_EQ_SAVEDEFAULT: break; + case IDM_EQ_DELPRE: break; + case IDM_EQ_DELMP3: break; + case IDC_PLAYLIST_PLAY: break; + case WINAMP_FILE_LOC: break; + case WINAMP_OPTIONS_EASYMOVE: break; +*/ + case WINAMP_FILE_DIR: + AddDirectory(); + break; +/* + case WINAMP_EDIT_ID3: break; + case WINAMP_TOGGLE_AUTOSCROLL: break; + case WINAMP_VISSETUP: break; + case WINAMP_PLGSETUP: break; + case WINAMP_VISPLUGIN: break; + case WINAMP_JUMP: break; + case WINAMP_JUMPFILE: break; + case WINAMP_JUMP10FWD: break; + case WINAMP_JUMP10BACK: break; + case WINAMP_PREVSONG: break; + case WINAMP_OPTIONS_EXTRAHQ: break; +*/ + case ID_PE_NEW: + playlist->RemoveAll(); + break; + + case ID_PE_OPEN: + Playlist::DialogOpen(); + break; +/* + case ID_PE_SAVE: break; +*/ + case ID_PE_SAVEAS: + Playlist::DialogSaveAs(); + break; + + case ID_PE_SELECTALL: + playlist->SelectAll( true ); + break; + + case ID_PE_INVERT: + playlist->SelectInvert(); + break; + + case ID_PE_NONE: + playlist->SelectAll( false ); + break; +/* + case ID_PE_ID3: break; + case ID_PE_S_TITLE: break; + case ID_PE_S_FILENAME: break; + case ID_PE_S_PATH: break; + case ID_PE_S_RANDOM: break; + case ID_PE_S_REV: break; +*/ + case ID_PE_CLEAR: + playlist->RemoveAll(); + break; +/* + case ID_PE_MOVEUP: break; + case ID_PE_MOVEDOWN: break; + case WINAMP_SELSKIN: break; + case WINAMP_VISCONF: break; + case ID_PE_NONEXIST: break; + case ID_PE_DELETEFROMDISK: break; + case ID_PE_CLOSE: break; + case WINAMP_VIS_SETOSC: break; + case WINAMP_VIS_SETANA: break; + case WINAMP_VIS_SETOFF: break; + case WINAMP_VIS_DOTSCOPE: break; + case WINAMP_VIS_LINESCOPE: break; + case WINAMP_VIS_SOLIDSCOPE: break; + case WINAMP_VIS_NORMANA: break; + case WINAMP_VIS_FIREANA: break; + case WINAMP_VIS_LINEANA: break; + case WINAMP_VIS_NORMVU: break; + case WINAMP_VIS_SMOOTHVU: break; + case WINAMP_VIS_FULLREF: break; + case WINAMP_VIS_FULLREF2: break; + case WINAMP_VIS_FULLREF3: break; + case WINAMP_VIS_FULLREF4: break; + case WINAMP_OPTIONS_TOGTIME: break; + case EQ_ENABLE: break; + case EQ_AUTO: break; + case EQ_PRESETS: break; + case WINAMP_VIS_FALLOFF0: break; + case WINAMP_VIS_FALLOFF1: break; + case WINAMP_VIS_FALLOFF2: break; + case WINAMP_VIS_FALLOFF3: break; + case WINAMP_VIS_FALLOFF4: break; + case WINAMP_VIS_PEAKS: break; + case ID_LOAD_EQF: break; + case ID_SAVE_EQF: break; + case ID_PE_ENTRY: break; + case ID_PE_SCROLLUP: break; + case ID_PE_SCROLLDOWN: break; + case WINAMP_MAIN_WINDOW: break; + case WINAMP_VIS_PFALLOFF0: break; + case WINAMP_VIS_PFALLOFF1: break; + case WINAMP_VIS_PFALLOFF2: break; + case WINAMP_VIS_PFALLOFF3: break; + case WINAMP_VIS_PFALLOFF4: break; + case ID_PE_TOP: break; + case ID_PE_BOTTOM: break; + case WINAMP_OPTIONS_WINDOWSHADE_PL: break; + case EQ_INC1: break; + case EQ_INC2: break; + case EQ_INC3: break; + case EQ_INC4: break; + case EQ_INC5: break; + case EQ_INC6: break; + case EQ_INC7: break; + case EQ_INC8: break; + case EQ_INC9: break; + case EQ_INC10: break; + case EQ_INCPRE: break; + case EQ_DECPRE: break; + case EQ_DEC1: break; + case EQ_DEC2: break; + case EQ_DEC3: break; + case EQ_DEC4: break; + case EQ_DEC5: break; + case EQ_DEC6: break; + case EQ_DEC7: break; + case EQ_DEC8: break; + case EQ_DEC9: break; + case EQ_DEC10: break; + case ID_PE_SCUP: break; + case ID_PE_SCDOWN: break; + case WINAMP_REFRESHSKIN: break; + case ID_PE_PRINT: break; + case ID_PE_EXTINFO: break; + case WINAMP_PLAYLIST_ADVANCE: break; + case WINAMP_VIS_LIN: break; + case WINAMP_VIS_BAR: break; + case WINAMP_OPTIONS_MINIBROWSER: break; + case MB_FWD: break; + case MB_BACK: break; + case MB_RELOAD: break; + case MB_OPENMENU: break; + case MB_OPENLOC: break; + case WINAMP_NEW_INSTANCE: break; + case MB_UPDATE: break; + case WINAMP_OPTIONS_WINDOWSHADE_EQ: break; + case EQ_PANLEFT: break; + case EQ_PANRIGHT: break; + case WINAMP_GETMORESKINS: break; + case WINAMP_VIS_OPTIONS: break; + case WINAMP_PE_SEARCH: break; + case ID_PE_BOOKMARK: break; + case WINAMP_EDIT_BOOKMARKS: break; + case WINAMP_MAKECURBOOKMARK: break; + case ID_MAIN_PLAY_BOOKMARK_NONE: break; + case ID_MAIN_PLAY_AUDIOCD: break; + case ID_MAIN_PLAY_AUDIOCD2: break; + case ID_MAIN_PLAY_AUDIOCD3: break; + case ID_MAIN_PLAY_AUDIOCD4: break; + case WINAMP_OPTIONS_VIDEO: break; + case ID_VIDEOWND_ZOOMFULLSCREEN: break; + case ID_VIDEOWND_ZOOM100: break; + case ID_VIDEOWND_ZOOM200: break; + case ID_VIDEOWND_ZOOM50: break; + case ID_VIDEOWND_VIDEOOPTIONS: break; + case WINAMP_MINIMIZE: break; + case ID_PE_FONTBIGGER: break; + case ID_PE_FONTSMALLER: break; + case WINAMP_VIDEO_TOGGLE_FS: break; + case WINAMP_VIDEO_TVBUTTON: break; + case WINAMP_LIGHTNING_CLICK: break; + case ID_FILE_ADDTOLIBRARY: break; + case ID_HELP_HELPTOPICS: break; + case ID_HELP_GETTINGSTARTED: break; + case ID_HELP_WINAMPFORUMS: break; +*/ + case ID_PLAY_VOLUMEUP: + Playback::Volume::Up(); + // TODO Update slider + break; + + case ID_PLAY_VOLUMEDOWN: + Playback::Volume::Down(); + // TODO Update slider + break; +/* + case ID_PEFILE_OPENPLAYLISTFROMLIBRARY_NOPLAYLISTSINLIBRARY: break; + case ID_PEFILE_ADDFROMLIBRARY: break; + case ID_PEFILE_CLOSEPLAYLISTEDITOR: break; + case ID_PEPLAYLIST_PLAYLISTPREFERENCES: break; + case ID_MLFILE_NEWPLAYLIST: break; + case ID_MLFILE_LOADPLAYLIST: break; + case ID_MLFILE_SAVEPLAYLIST: break; + case ID_MLFILE_ADDMEDIATOLIBRARY: break; + case ID_MLFILE_CLOSEMEDIALIBRARY: break; + case ID_MLVIEW_NOWPLAYING: break; + case ID_MLVIEW_LOCALMEDIA_ALLMEDIA: break; + case ID_MLVIEW_LOCALMEDIA_AUDIO: break; + case ID_MLVIEW_LOCALMEDIA_VIDEO: break; + case ID_MLVIEW_PLAYLISTS_NOPLAYLISTINLIBRARY: break; + case ID_MLVIEW_INTERNETRADIO: break; + case ID_MLVIEW_INTERNETTV: break; + case ID_MLVIEW_LIBRARYPREFERENCES: break; + case ID_MLVIEW_DEVICES_NOAVAILABLEDEVICE: break; + case ID_MLFILE_IMPORTCURRENTPLAYLIST: break; + case ID_MLVIEW_MEDIA: break; + case ID_MLVIEW_PLAYLISTS: break; + case ID_MLVIEW_MEDIA_ALLMEDIA: break; + case ID_MLVIEW_DEVICES: break; + case ID_FILE_SHOWLIBRARY: break; + case ID_FILE_CLOSELIBRARY: break; + case ID_POST_PLAY_PLAYLIST: break; + case ID_VIS_NEXT: break; + case ID_VIS_PREV: break; + case ID_VIS_RANDOM: break; + case ID_MANAGEPLAYLISTS: break; + case ID_PREFS_SKIN_SWITCHTOSKIN: break; + case ID_PREFS_SKIN_DELETESKIN: break; + case ID_PREFS_SKIN_RENAMESKIN: break; + case ID_VIS_FS: break; + case ID_VIS_CFG: break; + case ID_VIS_MENU: break; + case ID_VIS_SET_FS_FLAG: break; + case ID_PE_SHOWPLAYING: break; + case ID_HELP_REGISTERWINAMPPRO: break; + case ID_PE_MANUAL_ADVANCE: break; + case WA_SONG_5_STAR_RATING: break; + case WA_SONG_4_STAR_RATING: break; + case WA_SONG_3_STAR_RATING: break; + case WA_SONG_2_STAR_RATING: break; + case WA_SONG_1_STAR_RATING: break; + case WA_SONG_NO_RATING: break; + case PL_SONG_5_STAR_RATING: break; + case PL_SONG_4_STAR_RATING: break; + case PL_SONG_3_STAR_RATING: break; + case PL_SONG_2_STAR_RATING: break; + case PL_SONG_1_STAR_RATING: break; + case PL_SONG_NO_RATING: break; + case AUDIO_TRACK_ONE: break; + case VIDEO_TRACK_ONE: break; + case ID_SWITCH_COLOURTHEME: break; + case ID_GENFF_LIMIT: break; + +*/ + case PLAINAMP_TOGGLE_CONSOLE: + ShowWindow( WindowConsole, IsWindowVisible( WindowConsole ) ? SW_HIDE : SW_SHOW ); + break; + + case PLAINAMP_TOGGLE_MANAGER: + ShowWindow( WindowManager, IsWindowVisible( WindowManager ) ? SW_HIDE : SW_SHOW ); + break; + + case PLAINAMP_PL_REM_SEL: + playlist->RemoveSelected( true ); + break; + + case PLAINAMP_PL_REM_CROP: + playlist->RemoveSelected( false ); + break; + + default: + { + /* + if( wp == ID_DYNAMICLIBRARY ) + { + // Stupid dnylib workaround + PostMessage( hwnd, WM_COMMAND, ID_DYNAMICLIBRARY | ( 1 << 16 ), 0 ); + } + */ + + if( LOWORD( wp ) < 40001 ) break; + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "WM_COMMAND <%i> <%i>" ), wp, lp ); + Console::Append( szBuffer ); + Console::Append( TEXT( "NOT handled" ) ); + Console::Append( " " ); + } + + } + break; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + case WM_WA_IPC: +/* + { + TCHAR szBuffer[ 5000 ]; + if( lp != 2006 ) + { + _stprintf( szBuffer, TEXT( "WM_WA_IPC <%i> <%i>" ), wp, lp ); + } + else + { + // Hotkey sent as strings! + // Idea: make stl map + _stprintf( szBuffer, TEXT( "WM_WA_IPC <%s> <%i>" ), ( char * )wp, lp ); + } + Console::Append( szBuffer ); + } +*/ + switch( lp ) + { + case IPC_GETVERSION: + return 0x5010; // 5.10 +/* + case IPC_GETREGISTEREDVERSION: break; + case IPC_PLAYFILE: break; + case IPC_ENQUEUEFILE: break; +*/ + case IPC_DELETE: + playlist->RemoveAll(); + break; +/* + case IPC_DELETE_INT: break; +*/ + case IPC_STARTPLAY: + Playback::Play(); + Playback::UpdateSeek(); + break; +/* + case IPC_STARTPLAY_INT: break; + case IPC_CHDIR: break; +*/ + case IPC_ISPLAYING: // untested + return ( Playback::IsPlaying() ? ( Playback::IsPaused() ? 3 : 1 ) : 0 ); +/* + case IPC_GETOUTPUTTIME: break; + case IPC_JUMPTOTIME: break; + case IPC_GETMODULENAME: break; + case IPC_EX_ISRIGHTEXE: break; + case IPC_WRITEPLAYLIST: break; +*/ + case IPC_SETPLAYLISTPOS: + playlist->SetCurIndex( ( int )wp ); + break; + + case IPC_SETVOLUME: break; + Playback::Volume::Set( ( int )wp ); + // TODO Update slider + break; + + case IPC_SETPANNING: break; + Playback::Pan::Set( ( int )wp ); + // TODO Update slider + break; + + case IPC_GETLISTLENGTH: + return playlist->GetSize(); + + case IPC_GETLISTPOS: + return playlist->GetCurIndex(); +/* + case IPC_GETINFO: break; + case IPC_GETEQDATA: break; + // TODO + case IPC_SETEQDATA: break; + // TODO + case IPC_ADDBOOKMARK: break; + case IPC_INSTALLPLUGIN: break; + case IPC_RESTARTWINAMP: break; + case IPC_ISFULLSTOP: break; + case IPC_INETAVAILABLE: break; + case IPC_UPDTITLE: break; + case IPC_REFRESHPLCACHE: break; + case IPC_GET_SHUFFLE: break; + case IPC_GET_REPEAT: break; + case IPC_SET_SHUFFLE: break; + case IPC_SET_REPEAT: break; + case IPC_ENABLEDISABLE_ALL_WINDOWS: break; +*/ + case IPC_GETWND: + { + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "IPC_GETWND <%i>" ), wp ); + Console::Append( szBuffer ); + Console::Append( " " ); + } + + switch( wp ) + { + case IPC_GETWND_EQ: break; + case IPC_GETWND_PE: return ( LRESULT )WindowMain; + case IPC_GETWND_MB: break; + case IPC_GETWND_VIDEO: break; + } + + return ( LRESULT )NULL; + + case IPC_ISWNDVISIBLE: + { + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "IPC_ISWNDVISIBLE <%i>" ), wp ); + Console::Append( szBuffer ); + Console::Append( " " ); + } + + switch( wp ) + { + case IPC_GETWND_EQ: break; + case IPC_GETWND_PE: return 1; + case IPC_GETWND_MB: break; + case IPC_GETWND_VIDEO: break; + } + + return 0; +/* + case IPC_SETSKIN: break; + case IPC_GETSKIN: break; + case IPC_EXECPLUG: break; +*/ + case IPC_GETPLAYLISTFILE: + { + static char szAnsiFilename[ 2000 ] = "\0"; + Playlist::GetFilename( ( int )wp, szAnsiFilename, 1999 ); + return ( LRESULT )szAnsiFilename; + } + + case IPC_GETPLAYLISTTITLE: + { + static char szAnsiTitle[ 2000 ] = "\0"; + Playlist::GetTitle( ( int )wp, szAnsiTitle, 1999 ); + return ( LRESULT )szAnsiTitle; + } +/* + case IPC_GETHTTPGETTER: break; + case IPC_MBOPEN: break; + case IPC_CHANGECURRENTFILE: break; + case IPC_GETMBURL: break; + case IPC_MBBLOCK: break; + case IPC_MBOPENREAL: break; + case IPC_ADJUST_OPTIONSMENUPOS: break; +*/ + case IPC_GET_HMENU: + { + switch( wp ) + { + case 0: + return ( LRESULT )main_context_menu; +/* + case 1: break; + case 2: break; + case 3: break; + case 4: break; +*/ + } + return ( LRESULT )NULL; + } + + case IPC_GET_EXTENDED_FILE_INFO: + Console::Append( "IPC_GET_EXTENDED_FILE_INFO" ); + Console::Append( TEXT( "NOT handled" ) ); + Console::Append( " " ); + break; +/* + case IPC_GET_EXTENDED_FILE_INFO_HOOKABLE: break; + case IPC_GET_BASIC_FILE_INFO: break; +*/ + case IPC_GET_EXTLIST: + // TODO + return ( LRESULT )GlobalAlloc( GMEM_ZEROINIT, 2 ); // "\0\0" +/* + case IPC_INFOBOX: break; + case IPC_SET_EXTENDED_FILE_INFO: break; + case IPC_WRITE_EXTENDED_FILE_INFO: break; + case IPC_FORMAT_TITLE: break; +*/ + case IPC_GETUNCOMPRESSINTERFACE: + if( wp == 0x10100000 ) + { + Console::Append( "IPC_GETUNCOMPRESSINTERFACE @ wa_inflate_struct" ); + Console::Append( TEXT( "NOT handled" ) ); + Console::Append( " " ); + } + else + { + Console::Append( "IPC_GETUNCOMPRESSINTERFACE @ zlib" ); + Console::Append( " " ); + return ( LRESULT )uncompress; + } + break; + + case IPC_ADD_PREFS_DLG: + Prefs::AddPage( ( prefsDlgRec * )wp ); + break; +/* + case IPC_REMOVE_PREFS_DLG: break; +*/ + case IPC_OPENPREFSTOPAGE: + Prefs::Show( ( prefsDlgRec * )wp ); + break; + + case IPC_GETINIFILE: + { + static char szWinampInipath[ MAX_PATH ] = ""; + if( *szWinampInipath == '\0' ) + { + GetModuleFileNameA( NULL, szWinampInipath, MAX_PATH - 1 ); + char * szWalk = szWinampInipath + strlen( szWinampInipath ) - 1; + while( ( szWalk > szWinampInipath ) && ( *szWalk != '.' ) ) szWalk--; + szWalk++; + strcpy( szWalk, "ini" ); + } + return ( LRESULT )szWinampInipath; + } + + case IPC_GETINIDIRECTORY: + { + // TODO: trailing slash or not??? + static char szPluginInipath[ MAX_PATH ] = ""; + if( *szPluginInipath == '\0' ) + { + GetModuleFileNameA( NULL, szPluginInipath, MAX_PATH - 1 ); + char * szWalk = szPluginInipath + strlen( szPluginInipath ) - 1; + while( ( szWalk > szPluginInipath ) && ( *szWalk != '\\' ) ) szWalk--; + szWalk++; + strcpy( szWalk, TEXT( "Plugins" ) ); + } + return ( LRESULT )szPluginInipath; + } +/* + case IPC_SPAWNBUTTONPOPUP: break; + case IPC_OPENURLBOX: break; +*/ + case IPC_OPENFILEBOX: + AddFiles(); + break; + + case IPC_OPENDIRBOX: + AddDirectory(); + break; + + case IPC_GET_GENSKINBITMAP: + { + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "IPC_GET_GENSKINBITMAP <%i>" ), wp ); + Console::Append( szBuffer ); + + switch( wp ) + { + case 0: + { + // TODO: make it work + + // Gen.bmp? + static HBITMAP hBitmap = NULL; + static BYTE * image = NULL; + if( !hBitmap ) + { + const int iWidth = 200; // 194; + const int iHeight = 300; // 109; + const int bpp = 24; + int bytes_per_row = iWidth * ( bpp / 8 ); + const int diff = bytes_per_row % 4; + if( diff ) bytes_per_row += ( 4 - diff ); + + const int size_in_bytes = bytes_per_row * iHeight; + image = new BYTE[ size_in_bytes ]; + + hBitmap = CreateBitmap( + iWidth, // int nWidth + iHeight, // int nHeight + 1, // UINT cPlanes + bpp, // UINT cBitsPerPel + image // CONST VOID * lpvBits + ); + + memset( image, 255, size_in_bytes ); + } + + return ( LRESULT )hBitmap; + } + + default: + { + Console::Append( TEXT( "NOT handled" ) ); + } + + } + Console::Append( TEXT( " " ) ); + + break; + } + + case IPC_GET_EMBEDIF: + // TODO + if( !wp ) + { + return ( LRESULT )Embed::Embed; + } + else + { + return ( LRESULT )Embed::Embed( ( embedWindowState * )wp ); + } + break; +/* + case IPC_EMBED_ENUM: break; + case IPC_EMBED_ISVALID: break; + case IPC_CONVERTFILE: break; + case IPC_CONVERTFILE_END: break; + case IPC_CONVERT_CONFIG: break; + case IPC_CONVERT_CONFIG_END: break; + case IPC_GETSADATAFUNC: break; + case IPC_ISMAINWNDVISIBLE: break; + case IPC_SETPLEDITCOLORS: break; + case IPC_SPAWNEQPRESETMENU: break; + case IPC_SPAWNFILEMENU: break; + case IPC_SPAWNOPTIONSMENU: break; + case IPC_SPAWNWINDOWSMENU: break; + case IPC_SPAWNHELPMENU: break; + case IPC_SPAWNPLAYMENU: break; + case IPC_SPAWNPEFILEMENU: break; + case IPC_SPAWNPEPLAYLISTMENU: break; + case IPC_SPAWNPESORTMENU: break; + case IPC_SPAWNPEHELPMENU: break; + case IPC_SPAWNMLFILEMENU: break; + case IPC_SPAWNMLVIEWMENU: break; + case IPC_SPAWNMLHELPMENU: break; + case IPC_SPAWNPELISTOFPLAYLISTS: break; + case WM_WA_SYSTRAY: break; + case IPC_IS_PLAYING_VIDEO: break; + case IPC_GET_IVIDEOOUTPUT: break; +*/ + case IPC_CB_ONSHOWWND: + case IPC_CB_ONHIDEWND: + case IPC_CB_GETTOOLTIP: + case IPC_CB_MISC: + case IPC_CB_CONVERT_STATUS: + case IPC_CB_CONVERT_DONE: + break; +/* + case IPC_ADJUST_FFWINDOWSMENUPOS: break; + case IPC_ISDOUBLESIZE: break; + case IPC_ADJUST_FFOPTIONSMENUPOS: break; +*/ + case IPC_GETTIMEDISPLAYMODE: + return 0; // == elapsed time +/* + case IPC_SETVISWND: break; + case IPC_GETVISWND: break; + case IPC_ISVISRUNNING: break; +*/ + case IPC_CB_VISRANDOM: break; +/* + case IPC_SETIDEALVIDEOSIZE: break; + case IPC_GETSTOPONVIDEOCLOSE: break; + case IPC_SETSTOPONVIDEOCLOSE: break; +*/ + case IPC_TRANSLATEACCELERATOR: + Console::Append( TEXT( "IPC_TRANSLATEACCELERATOR" ) ); + Console::Append( TEXT( "NOT handled" ) ); + Console::Append( TEXT( " " ) ); + break; + + case IPC_CB_ONTOGGLEAOT: break; +/* + case IPC_GETPREFSWND: break; + case IPC_SET_PE_WIDTHHEIGHT: break; + case IPC_GETLANGUAGEPACKINSTANCE: break; +*/ + case IPC_CB_PEINFOTEXT: + case IPC_CB_OUTPUTCHANGED: + break; +/* + case IPC_GETOUTPUTPLUGIN: break; + case IPC_SETDRAWBORDERS: break; + case IPC_DISABLESKINCURSORS: break; +*/ + case IPC_CB_RESETFONT: break; +/* + case IPC_IS_FULLSCREEN: break; + case IPC_SET_VIS_FS_FLAG: break; + case IPC_SHOW_NOTIFICATION: break; + case IPC_GETSKININFO: break; + case IPC_GET_MANUALPLADVANCE: break; + case IPC_SET_MANUALPLADVANCE: break; + case IPC_GET_NEXT_PLITEM: break; + case IPC_GET_PREVIOUS_PLITEM: break; + case IPC_IS_WNDSHADE: break; + case IPC_SETRATING: break; + case IPC_GETRATING: break; + case IPC_GETNUMAUDIOTRACKS: break; + case IPC_GETNUMVIDEOTRACKS: break; + case IPC_GETAUDIOTRACK: break; + case IPC_GETVIDEOTRACK: break; + case IPC_SETAUDIOTRACK: break; + case IPC_SETVIDEOTRACK: break; + case IPC_PUSH_DISABLE_EXIT: break; + case IPC_POP_DISABLE_EXIT: break; + case IPC_IS_EXIT_ENABLED: break; + case IPC_IS_AOT: break; + case IPC_PLCMD: break; + case IPC_MBCMD: break; + case IPC_VIDCMD: break; + case IPC_MBURL: break; + case IPC_MBGETCURURL: break; + case IPC_MBGETDESC: break; + case IPC_MBCHECKLOCFILE: break; + case IPC_MBREFRESH: break; + case IPC_MBGETDEFURL: break; + case IPC_STATS_LIBRARY_ITEMCNT: break; + case IPC_FF_FIRST: break; + case IPC_FF_LAST: break; + case IPC_GETDROPTARGET: break; + case IPC_PLAYLIST_MODIFIED: break; + case IPC_PLAYING_FILE: break; + case IPC_FILE_TAG_MAY_HAVE_UPDATED: break; + case IPC_ALLOW_PLAYTRACKING: break; +*/ + case IPC_HOOK_OKTOQUIT: + return 1; // Okay +/* + case IPC_WRITECONFIG: break; +*/ + case IPC_REGISTER_WINAMP_IPCMESSAGE: + { + // TODO convert to TCHAR???? + UINT res = RegisterWindowMessage( ( LPCTSTR )wp ); + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Message \"%s\" registered as #%i" ), wp, res ); + Console::Append( szBuffer ); + Console::Append( " " ); + + if( !stricmp( ( char * )wp, "GenHotkeysAdd" ) ) + { + IPC_GENHOTKEYS_ADD = res; + } + else if( !stricmp( ( char * )wp, "Dynamic Library" ) ) + { + ID_DYNAMICLIBRARY = res; + } + else if( !stricmp( ( char * )wp, "IPC_GETPLAINBARTARGET" ) ) + { + IPC_GETPLAINBARTARGET = res; + } + + return res; + } + + case 2006: // undocumented, name IPC_CB_HOTKEY or so later and ask to add this to sdk + { + // Hotkey sent as strings! + // Idea: make stl map + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "Hotkey \"%s\" detected" ), wp ); + Console::Append( szBuffer ); + Console::Append( " " ); + + return 1; // Accept??? + } + + default: + { + if( lp == IPC_GENHOTKEYS_ADD ) + { + break; + } + else if( lp == IPC_GETPLAINBARTARGET ) + { + return ( LRESULT )( IsWindowVisible( WindowVis ) ? WindowVis : NULL ); + } + + TCHAR szBuffer[ 5000 ]; + _stprintf( szBuffer, TEXT( "WM_WA_IPC <%i> <%i>" ), wp, lp ); + Console::Append( szBuffer ); + Console::Append( TEXT( "NOT handled" ) ); + Console::Append( " " ); + } + } + break; + + case WM_WA_MPEG_EOF: + Playback::NotifyTrackEnd(); + Playback::Next(); + break; + + case WM_COPYDATA: + { + if( !lp ) return FALSE; + + COPYDATASTRUCT * cds = ( COPYDATASTRUCT * )lp; + switch( cds->dwData ) + { + case IPC_PLAYFILE: + { + const int iLen = cds->cbData; + if( !iLen ) return FALSE; + TCHAR * szKeep = new TCHAR[ iLen + 1 ]; + ToTchar( szKeep, ( char * )cds->lpData, iLen ); + szKeep[ iLen ] = TEXT( '\0' ); + + playlist->PushBack( szKeep ); + return TRUE; + } + } + return FALSE; + } + + } + return DefWindowProc( hwnd, message, wp, lp ); +} diff --git a/Branches/MusicMod/Player/Src/Winamp.h b/Branches/MusicMod/Player/Src/Winamp.h new file mode 100644 index 0000000000..288880174a --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef PA_WINAMP_H +#define PA_WINAMP_H + + + +#include "Global.h" + + + +LRESULT CALLBACK WndprocWinamp( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +#endif // PA_WINAMP_H diff --git a/Branches/MusicMod/Player/Src/Winamp/Dsp.h b/Branches/MusicMod/Player/Src/Winamp/Dsp.h new file mode 100644 index 0000000000..0c62886b8a --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/Dsp.h @@ -0,0 +1,47 @@ +#ifndef WINAMP_DSP_H +#define WINAMP_DSP_H + + +#include + +// DSP plugin interface + +// notes: +// any window that remains in foreground should optimally pass unused +// keystrokes to the parent (winamp's) window, so that the user +// can still control it. As for storing configuration, +// Configuration data should be stored in \plugin.ini +// (look at the vis plugin for configuration code) + +typedef struct winampDSPModule { + char *description; // description + HWND hwndParent; // parent window (filled in by calling app) + HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) + + void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed) + int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed) + + // modify waveform samples: returns number of samples to actually write + // (typically numsamples, but no more than twice numsamples, and no less than half numsamples) + // numsamples should always be at least 128. should, but I'm not sure + int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate); + + void (*Quit)(struct winampDSPModule *this_mod); // called when unloading + + void *userData; // user data, optional +} winampDSPModule; + +typedef struct { + int version; // DSP_HDRVER + char *description; // description of library + winampDSPModule* (*getModule)(int); // module retrieval function +} winampDSPHeader; + +// exported symbols +typedef winampDSPHeader* (*winampDSPGetHeaderType)(); + +// header version: 0x20 == 0.20 == winamp 2.0 +#define DSP_HDRVER 0x20 + + +#endif // WINAMP_DSP_H diff --git a/Branches/MusicMod/Player/Src/Winamp/Gen.h b/Branches/MusicMod/Player/Src/Winamp/Gen.h new file mode 100644 index 0000000000..7e3c5a2368 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/Gen.h @@ -0,0 +1,28 @@ +#ifndef WINAMP_GEN_H +#define WINAMP_GEN_H + + + +#define GPPHDR_VER 0x10 + + + +typedef struct { + int version; + char *description; + int (*init)(); + void (*config)(); + void (*quit)(); + HWND hwndParent; + HINSTANCE hDllInstance; +} winampGeneralPurposePlugin; + +typedef winampGeneralPurposePlugin * ( * winampGeneralPurposePluginGetter )(); + + + +// extern winampGeneralPurposePlugin * gen_plugins[ 256 ]; + + + +#endif // WINAMP_GEN_H diff --git a/Branches/MusicMod/Player/Src/Winamp/In2.h b/Branches/MusicMod/Player/Src/Winamp/In2.h new file mode 100644 index 0000000000..5f990eb2f3 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/In2.h @@ -0,0 +1,119 @@ +#ifndef WINAMP_IN_H +#define WINAMP_IN_H + + +#include +#include "out.h" + +// note: exported symbol is now winampGetInModule2. + +#define IN_VER 0x100 + + +// Changed +// void (*VSASetInfo)(int nch, int srate); +// to +// void (*VSASetInfo)(int srate, int nch); +// since the old one is wrong! +// +// Otherwise in_mp3 is the problem!?... + + +typedef struct +{ + int version; // module type (IN_VER) + char *description; // description of module, with version string + + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp) + + char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0" + // May be altered from Config, so the user can select what they want + + int is_seekable; // is this stream seekable? + int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :) + + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog + + void (*Init)(); // called at program init + void (*Quit)(); // called at program quit + + void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used + int (*InfoBox)(char *file, HWND hwndParent); + + int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc + // playback stuff + int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error + void (*Pause)(); // pause stream + void (*UnPause)(); // unpause stream + int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not + void (*Stop)(); // stop (unload) stream + + // time stuff + int (*GetLength)(); // get length in ms + int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime() + void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush().. + + // volume stuff + void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume + void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan + + // in-window builtin vis stuff + + void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open() + // call after opening audio device with max latency in ms and samplerate + void (*SAVSADeInit)(); // call in Stop() + + + // simple vis supplying mode + void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); + // sets the spec data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) + + // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff. + int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) + // use when calling SAAdd() + void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp + + + // vis stuff (plug-in) + // simple vis supplying mode + void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) + + // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff. + int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd + void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in + + + // call this in Play() to tell the vis plug-ins the current output params. + void (*VSASetInfo)(int srate, int nch); + + + // dsp plug-in processing: + // (filled in by winamp, called by input plug) + + // returns 1 if active (which means that the number of samples returned by dsp_dosamples + // could be greater than went in.. Use it to estimate if you'll have enough room in the + // output buffer + int (*dsp_isactive)(); + + // returns number of samples to output. This can be as much as twice numsamples. + // be sure to allocate enough buffer for samples, then. + int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate); + + + // eq stuff + void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore. + + // info setting (filled in by winamp) + void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :) + + Out_Module *outMod; // filled in by winamp, optionally used :) +} In_Module; + + +#endif // WINAMP_IN_H diff --git a/Branches/MusicMod/Player/Src/Winamp/Out.h b/Branches/MusicMod/Player/Src/Winamp/Out.h new file mode 100644 index 0000000000..7653bcbd96 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/Out.h @@ -0,0 +1,69 @@ +#ifndef WINAMP_OUT_H +#define WINAMP_OUT_H + + +#include + + +// [ids] +// waveout 32 +// disk 33 +// dsound 38 +// xfade 63 +// gapless 64 +// null 65 +// mm2 69 + +#define OUT_VER 0x10 + +typedef struct +{ + int version; // module version (OUT_VER) + char *description; // description of module, with version string + int id; // module id. each input module gets its own. non-nullsoft modules should + // be >= 65536. + + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp) + + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog + + void (*Init)(); // called when loaded + void (*Quit)(); // called when unloaded + + int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); + // returns >=0 on success, <0 on failure + // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins. + // ... so don't expect the max latency returned to be what you asked for. + // returns max latency in ms (0 for diskwriters, etc) + // bufferlenms and prebufferms must be in ms. 0 to use defaults. + // prebufferms must be <= bufferlenms + + void (*Close)(); // close the ol' output device. + + int (*Write)(char *buf, int len); + // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data. + // 1 returns not able to write (yet). Non-blocking, always. + + int (*CanWrite)(); // returns number of bytes possible to write at a given time. + // Never will decrease unless you call Write (or Close, heh) + + int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be + // written (i.e. closing while IsPlaying() returns 1 would truncate the song + + int (*Pause)(int pause); // returns previous pause state + + void (*SetVolume)(int volume); // volume is 0-255 + void (*SetPan)(int pan); // pan is -128 to 128 + + void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms) + // (used for seeking) + + int (*GetOutputTime)(); // returns played time in MS + int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff) + +} Out_Module; + + +#endif // WINAMP_OUT_H diff --git a/Branches/MusicMod/Player/Src/Winamp/Vis.h b/Branches/MusicMod/Player/Src/Winamp/Vis.h new file mode 100644 index 0000000000..280830d7cd --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/Vis.h @@ -0,0 +1,57 @@ +#ifndef WINAMP_VIS_H +#define WINAMP_VIS_H + + +// notes: +// any window that remains in foreground should optimally pass +// keystrokes to the parent (winamp's) window, so that the user +// can still control it. unless escape is hit, or some option +// key specific to the vis is hit. As for storing configuration, +// Configuration data should be stored in \plugin.ini +// Look at the example plugin for a framework. + +// ints are 32 bits, and structure members are aligned on the default 8 byte boundaries +// tested with VC++ 4.2 and 5.0 + + +#include + + +typedef struct winampVisModule { + char *description; // description of module + HWND hwndParent; // parent window (filled in by calling app) + HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) + int sRate; // sample rate (filled in by calling app) + int nCh; // number of channels (filled in...) + int latencyMs; // latency from call of RenderFrame to actual drawing + // (calling app looks at this value when getting data) + int delayMs; // delay between calls in ms + + // the data is filled in according to the respective Nch entry + int spectrumNch; + int waveformNch; + unsigned char spectrumData[2][576]; + unsigned char waveformData[2][576]; + + void (*Config)(struct winampVisModule *this_mod); // configuration dialog + int (*Init)(struct winampVisModule *this_mod); // 0 on success, creates window, etc + int (*Render)(struct winampVisModule *this_mod); // returns 0 if successful, 1 if vis should end + void (*Quit)(struct winampVisModule *this_mod); // call when done + + void *userData; // user data, optional +} winampVisModule; + +typedef struct { + int version; // VID_HDRVER + char *description; // description of library + winampVisModule* (*getModule)(int); +} winampVisHeader; + +// exported symbols +typedef winampVisHeader* (*winampVisGetHeaderType)(); + +// version of current module (0x101 == 1.01) +#define VIS_HDRVER 0x101 + + +#endif // WINAMP_VIS_H diff --git a/Branches/MusicMod/Player/Src/Winamp/wa_ipc.h b/Branches/MusicMod/Player/Src/Winamp/wa_ipc.h new file mode 100644 index 0000000000..75689b9eea --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/wa_ipc.h @@ -0,0 +1,1103 @@ +/* +** Copyright (C) 2003 Nullsoft, Inc. +** +** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held +** liable for any damages arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to +** alter it and redistribute it freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +** +** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +** +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#ifndef _WA_IPC_H_ +#define _WA_IPC_H_ + +/* +** This is the modern replacement for the classic 'frontend.h'. Most of these +** updates are designed for in-process use, i.e. from a plugin. +** +*/ + +/* message used to sent many messages to winamp's main window. +** most all of the IPC_* messages involve sending the message in the form of: +** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*); +*/ +#define WM_WA_IPC WM_USER +/* but some of them use WM_COPYDATA. be afraid. +*/ + +#define IPC_GETVERSION 0 +/* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION); +** +** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0 +** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know. +*/ + +#define IPC_GETREGISTEREDVERSION 770 + + +typedef struct { + char *filename; + char *title; + int length; +} enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA, +// and you get the nice desired result. if title is NULL, it is treated as a "thing", +// otherwise it's assumed to be a file (for speed) + +#define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile +#define IPC_ENQUEUEFILE 100 +/* sent as a WM_COPYDATA, with IPC_PLAYFILE as the dwData, and the string to play +** as the lpData. Just enqueues, does not clear the playlist or change the playback +** state. +*/ + + +#define IPC_DELETE 101 +#define IPC_DELETE_INT 1101 // don't use this, it's used internally by winamp when + // dealing with some lame explorer issues. +/* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE); +** Use IPC_DELETE to clear Winamp's internal playlist. +*/ + + +#define IPC_STARTPLAY 102 // starts playback. almost like hitting play in Winamp. +#define IPC_STARTPLAY_INT 1102 // used internally, don't bother using it (won't be any fun) + + +#define IPC_CHDIR 103 +/* sent as a WM_COPYDATA, with IPC_CHDIR as the dwData, and the directory to change to +** as the lpData. +*/ + + +#define IPC_ISPLAYING 104 +/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING); +** If it returns 1, it is playing. if it returns 3, it is paused, +** if it returns 0, it is not playing. +*/ + + +#define IPC_GETOUTPUTTIME 105 +/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME); +** returns the position in milliseconds of the current track (mode = 0), +** or the track length, in seconds (mode = 1). Returns -1 if not playing or error. +*/ + + +#define IPC_JUMPTOTIME 106 +/* (requires Winamp 1.60+) +** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME); +** IPC_JUMPTOTIME sets the position in milliseconds of the +** current song (approximately). +** Returns -1 if not playing, 1 on eof, or 0 if successful +*/ + +#define IPC_GETMODULENAME 109 +#define IPC_EX_ISRIGHTEXE 666 +/* usually shouldnt bother using these, but here goes: +** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal +** flag gets set, which if you send a normal WM_WA_IPC message with +** IPC_EX_ISRIGHTEXE, it returns whether or not that filename +** matches. lame, I know. +*/ + +#define IPC_WRITEPLAYLIST 120 +/* (requires Winamp 1.666+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST); +** +** IPC_WRITEPLAYLIST writes the current playlist to \\Winamp.m3u, +** and returns the current playlist position. +** Kinda obsoleted by some of the 2.x new stuff, but still good for when +** using a front-end (instead of a plug-in) +*/ + + +#define IPC_SETPLAYLISTPOS 121 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS) +** IPC_SETPLAYLISTPOS sets the playlist position to 'position'. It +** does not change playback or anything, it just sets position, and +** updates the view if necessary +*/ + + +#define IPC_SETVOLUME 122 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME); +** IPC_SETVOLUME sets the volume of Winamp (from 0-255). +*/ + + +#define IPC_SETPANNING 123 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING); +** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)). +*/ + + +#define IPC_GETLISTLENGTH 124 +/* (requires Winamp 2.0+) +** int length = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH); +** IPC_GETLISTLENGTH returns the length of the current playlist, in +** tracks. +*/ + + +#define IPC_GETLISTPOS 125 +/* (requires Winamp 2.05+) +** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS); +** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST +** only faster since it doesn't have to write out the list. Heh, silly me. +*/ + + +#define IPC_GETINFO 126 +/* (requires Winamp 2.05+) +** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO); +** IPC_GETINFO returns info about the current playing song. The value +** it returns depends on the value of 'mode'. +** Mode Meaning +** ------------------ +** 0 Samplerate (i.e. 44100) +** 1 Bitrate (i.e. 128) +** 2 Channels (i.e. 2) +** 3 (5+) Video LOWORD=w HIWORD=h +** 4 (5+) > 65536, string (video description) +*/ + + +#define IPC_GETEQDATA 127 +/* (requires Winamp 2.05+) +** int data=SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); +** IPC_GETEQDATA queries the status of the EQ. +** The value returned depends on what 'pos' is set to: +** Value Meaning +** ------------------ +** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db) +** 10 The preamp value. 0-63 (+20db - -20db) +** 11 Enabled. zero if disabled, nonzero if enabled. +** 12 Autoload. zero if disabled, nonzero if enabled. +*/ + + +#define IPC_SETEQDATA 128 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA); +** IPC_SETEQDATA sets the value of the last position retrieved +** by IPC_GETEQDATA. This is pretty lame, and we should provide +** an extended version that lets you do a MAKELPARAM(pos,value). +** someday... + + new (2.92+): + if the high byte is set to 0xDB, then the third byte specifies + which band, and the bottom word specifies the value. +*/ + +#define IPC_ADDBOOKMARK 129 +/* (requires Winamp 2.4+) +** Sent as a WM_COPYDATA, using IPC_ADDBOOKMARK, adds the specified +** file/url to the Winamp bookmark list. +*/ +/* +In winamp 5+, we use this as a normal WM_WA_IPC and the string: + + "filename\0title\0" + + to notify the library/bookmark editor that a bookmark +was added. Note that using this message in this context does not +actually add the bookmark. +do not use :) +*/ + + +#define IPC_INSTALLPLUGIN 130 +/* not implemented, but if it was you could do a WM_COPYDATA with +** a path to a .wpz, and it would install it. +*/ + + +#define IPC_RESTARTWINAMP 135 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP); +** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :) +*/ + + +#define IPC_ISFULLSTOP 400 +/* (requires winamp 2.7+ I think) +** ret=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP); +** useful for when you're an output plugin, and you want to see +** if the stop/close is a full stop, or just between tracks. +** returns nonzero if it's full, zero if it's just a new track. +*/ + + +#define IPC_INETAVAILABLE 242 +/* (requires Winamp 2.05+) +** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE); +** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp. +*/ + + +#define IPC_UPDTITLE 243 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE); +** IPC_UPDTITLE will ask Winamp to update the informations about the current title. +*/ + + +#define IPC_REFRESHPLCACHE 247 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE); +** IPC_REFRESHPLCACHE will flush the playlist cache buffer. +** (send this if you want it to go refetch titles for tracks) +*/ + + +#define IPC_GET_SHUFFLE 250 +/* (requires Winamp 2.4+) +** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE); +** +** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set) +*/ + + +#define IPC_GET_REPEAT 251 +/* (requires Winamp 2.4+) +** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT); +** +** IPC_GET_REPEAT returns the status of the Repeat option (1 if set) +*/ + + +#define IPC_SET_SHUFFLE 252 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE); +** +** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on) +*/ + + +#define IPC_SET_REPEAT 253 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT); +** +** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on) +*/ + + +#define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable +/* (requires Winamp 2.9+) +** SendMessage(hwnd_winamp,WM_WA_IPC,enable?0:0xdeadbeef,IPC_MBOPENREAL); +** sending with 0xdeadbeef as the param disables all winamp windows, +** any other values will enable all winamp windows. +*/ + + +#define IPC_GETWND 260 +/* (requires Winamp 2.9+) +** HWND h=SendMessage(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND); +** returns the HWND of the window specified. +*/ + #define IPC_GETWND_EQ 0 // use one of these for the param + #define IPC_GETWND_PE 1 + #define IPC_GETWND_MB 2 + #define IPC_GETWND_VIDEO 3 +#define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND + + + + +/************************************************************************ +***************** in-process only (WE LOVE PLUGINS) +************************************************************************/ + + +#define IPC_SETSKIN 200 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN); +** IPC_SETSKIN sets the current skin to "skinname". Note that skinname +** can be the name of a skin, a skin .zip file, with or without path. +** If path isn't specified, the default search path is the winamp skins +** directory. +*/ + + +#define IPC_GETSKIN 201 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN); +** IPC_GETSKIN puts the directory where skin bitmaps can be found +** into skinname_buffer. +** skinname_buffer must be MAX_PATH characters in length. +** When using a .zip'd skin file, it'll return a temporary directory +** where the ZIP was decompressed. +*/ + + +#define IPC_EXECPLUG 202 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG); +** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM. +** the format of this string can be: +** "vis_whatever.dll" +** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir) +** "C:\\dir\\vis_whatever.dll,1" +*/ + + +#define IPC_GETPLAYLISTFILE 211 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE); +** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index]. +** returns a pointer to it. returns NULL on error. +*/ + + +#define IPC_GETPLAYLISTTITLE 212 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE); +** +** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index]. +** returns a pointer to it. returns NULL on error. +*/ + + +#define IPC_GETHTTPGETTER 240 +/* retrieves a function pointer to a HTTP retrieval function. +** if this is unsupported, returns 1 or 0. +** the function should be: +** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle); +** if you call this function, with a parent window, a URL, an output file, and a dialog title, +** it will return 0 on successful download, 1 on error. +*/ + + +#define IPC_MBOPEN 241 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN); +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN); +** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window. +*/ + + + +#define IPC_CHANGECURRENTFILE 245 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE); +** IPC_CHANGECURRENTFILE will set the current playlist item. +*/ + + +#define IPC_GETMBURL 246 +/* (requires Winamp 2.2+) +** char buffer[4096]; // Urls can be VERY long +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL); +** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer. +** buffer must be at least 4096 bytes long. +*/ + + +#define IPC_MBBLOCK 248 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK); +** +** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1 +*/ + +#define IPC_MBOPENREAL 249 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL); +** +** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if +** IPC_MBBLOCK has been set to 1 +*/ + +#define IPC_ADJUST_OPTIONSMENUPOS 280 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS); +** moves where winamp expects the Options menu in the main menu. Useful if you wish to insert a +** menu item above the options/skins/vis menus. +*/ + +#define IPC_GET_HMENU 281 +/* (requires Winamp 2.9+) +** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU); +** values for data: +** 0 : main popup menu +** 1 : main menubar file menu +** 2 : main menubar options menu +** 3 : main menubar windows menu +** 4 : main menubar help menu +** other values will return NULL. +*/ + +#define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam +#define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296 +/* (requires Winamp 2.9+) +** to use, create an extendedFileInfoStruct, point the values filename and metadata to the +** filename and metadata field you wish to query, and ret to a buffer, with retlen to the +** length of that buffer, and then SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO); +** the results should be in the buffer pointed to by ret. +** returns 1 if the decoder supports a getExtendedFileInfo method +*/ +typedef struct { + char *filename; + char *metadata; + char *ret; + int retlen; +} extendedFileInfoStruct; + +#define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam +typedef struct { + char *filename; + + int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used) + + // filled in by winamp + int length; + char *title; + int titlelen; +} basicFileInfoStruct; + +#define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename + +#define IPC_INFOBOX 293 +typedef struct { + HWND parent; + char *filename; +} infoBoxParam; + +#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam +/* (requires Winamp 2.9+) +** to use, create an extendedFileInfoStruct, point the values filename and metadata to the +** filename and metadata field you wish to write in ret. (retlen is not used). and then +** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO); +** returns 1 if the metadata is supported +** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update +*/ + +#define IPC_WRITE_EXTENDED_FILE_INFO 295 +/* (requires Winamp 2.9+) +** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file +** returns 1 if the file has been successfully updated, 0 if error +*/ + +#define IPC_FORMAT_TITLE 297 +typedef struct +{ + char *spec; // NULL=default winamp spec + void *p; + + char *out; + int out_len; + + char * (*TAGFUNC)(char * tag, void * p); //return 0 if not found + void (*TAGFREEFUNC)(char * tag,void * p); +} waFormatTitle; + +#define IPC_GETUNCOMPRESSINTERFACE 331 +/* returns a function pointer to uncompress(). +** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); +** right out of zlib, useful for decompressing zlibbed data. +** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API. +*/ + +typedef struct { + int (*inflateReset)(void *strm); + int (*inflateInit_)(void *strm,const char *version, int stream_size); + int (*inflate)(void *strm, int flush); + int (*inflateEnd)(void *strm); + unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len); +} wa_inflate_struct; + + +#define IPC_ADD_PREFS_DLG 332 +#define IPC_REMOVE_PREFS_DLG 333 +/* (requires Winamp 2.9+) +** to use, allocate a prefsDlgRec structure (either on the heap or some global +** data, but NOT on the stack), initialze the members: +** hInst to the DLL instance where the resource is located +** dlgID to the ID of the dialog, +** proc to the window procedure for the dialog +** name to the name of the prefs page in the prefs. +** where to 0 (eventually we may add more options) +** then, SendMessage(hwnd_winamp,WM_WA_IPC,&prefsRec,IPC_ADD_PREFS_DLG); +** +** you can also IPC_REMOVE_PREFS_DLG with the address of the same prefsRec, +** but you shouldn't really ever have to. +** +*/ +#define IPC_OPENPREFSTOPAGE 380 // pass an id of a builtin page, or a &prefsDlgRec of prefs page to open + +typedef struct _prefsDlgRec { + HINSTANCE hInst; + int dlgID; + void *proc; + + char *name; + int where; // 0 for options, 1 for plugins, 2 for skins, 3 for bookmarks, 4 for prefs + + + int _id; + struct _prefsDlgRec *next; +} prefsDlgRec; + + +#define IPC_GETINIFILE 334 // returns a pointer to winamp.ini +#define IPC_GETINIDIRECTORY 335 // returns a pointer to the directory to put config files in (if you dont want to use winamp.ini) + +#define IPC_SPAWNBUTTONPOPUP 361 // param = +// 0 = eject +// 1 = previous +// 2 = next +// 3 = pause +// 4 = play +// 5 = stop + +#define IPC_OPENURLBOX 360 // pass a HWND to a parent, returns a HGLOBAL that needs to be freed with GlobalFree(), if successful +#define IPC_OPENFILEBOX 362 // pass a HWND to a parent +#define IPC_OPENDIRBOX 363 // pass a HWND to a parent + +// pass an HWND to a parent. call this if you take over the whole UI so that the dialogs are not appearing on the +// bottom right of the screen since the main winamp window is at 3000x3000, call again with NULL to reset +#define IPC_SETDIALOGBOXPARENT 364 + + + +// pass 0 for a copy of the skin HBITMAP +// pass 1 for name of font to use for playlist editor likeness +// pass 2 for font charset +// pass 3 for font size +#define IPC_GET_GENSKINBITMAP 503 + + +#define IPC_GET_EMBEDIF 505 // pass an embedWindowState +// returns an HWND embedWindow(embedWindowState *); if the data is NULL, otherwise returns the HWND directly +typedef struct +{ + HWND me; //hwnd of the window + + int flags; + + RECT r; + + void *user_ptr; // for application use + + int extra_data[64]; // for internal winamp use +} embedWindowState; + +#define EMBED_FLAGS_NORESIZE 1 // set this bit in embedWindowState.flags to keep window from being resizable +#define EMBED_FLAGS_NOTRANSPARENCY 2 // set this bit in embedWindowState.flags to make gen_ff turn transparency off for this wnd + + +#define IPC_EMBED_ENUM 532 +typedef struct embedEnumStruct +{ + int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort + int user_data; // or more :) +} embedEnumStruct; + // pass + +#define IPC_EMBED_ISVALID 533 + +#define IPC_CONVERTFILE 506 +/* (requires Winamp 2.92+) +** Converts a given file to a different format (PCM, MP3, etc...) +** To use, pass a pointer to a waFileConvertStruct struct +** This struct can be either on the heap or some global +** data, but NOT on the stack. At least, until the conversion is done. +** +** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE); +** +** Return value: +** 0: Can't start the conversion. Look at myConvertStruct->error for details. +** 1: Conversion started. Status messages will be sent to the specified callbackhwnd. +** Be sure to call IPC_CONVERTFILE_END when your callback window receives the +** IPC_CB_CONVERT_DONE message. +*/ +typedef struct +{ + char *sourcefile; // "c:\\source.mp3" + char *destfile; // "c:\\dest.pcm" + int destformat[8]; // like 'PCM ',srate,nch,bps + HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages + + //filled in by winamp.exe + char *error; //if IPC_CONVERTFILE returns 0, the reason will be here + + int bytes_done; //you can look at both of these values for speed statistics + int bytes_total; + int bytes_out; + + int killswitch; // don't set it manually, use IPC_CONVERTFILE_END + int extra_data[64]; // for internal winamp use +} convertFileStruct; + +#define IPC_CONVERTFILE_END 507 +/* (requires Winamp 2.92+) +** Stop/ends a convert process started from IPC_CONVERTFILE +** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you +** want to abort a conversion process +** +** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END); +** +** No return value +*/ + +typedef struct { + HWND hwndParent; + int format; + + //filled in by winamp.exe + HWND hwndConfig; + int extra_data[8]; +} convertConfigStruct; +#define IPC_CONVERT_CONFIG 508 +#define IPC_CONVERT_CONFIG_END 509 + +typedef struct +{ + void (*enumProc)(int user_data, const char *desc, int fourcc); + int user_data; +} converterEnumFmtStruct; +#define IPC_CONVERT_CONFIG_ENUMFMTS 510 +/* (requires Winamp 2.92+) +*/ + + +typedef struct +{ + char cdletter; + char *playlist_file; + HWND callback_hwnd; + + //filled in by winamp.exe + char *error; +} burnCDStruct; +#define IPC_BURN_CD 511 +/* (requires Winamp 5.0+) +*/ + +typedef struct +{ + convertFileStruct *cfs; + int priority; +} convertSetPriority; +#define IPC_CONVERT_SET_PRIORITY 512 + +typedef struct +{ + char *filename; + char *title; // 2048 bytes + int length; + int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit +} waHookTitleStruct; +// return TRUE if you hook this +#define IPC_HOOK_TITLES 850 + +#define IPC_GETSADATAFUNC 800 +// 0: returns a char *export_sa_get() that returns 150 bytes of data +// 1: returns a export_sa_setreq(int want); + +#define IPC_ISMAINWNDVISIBLE 900 + + +#define IPC_SETPLEDITCOLORS 920 +typedef struct +{ + int numElems; + int *elems; + HBITMAP bm; // set if you want to override +} waSetPlColorsStruct; + + +// the following IPC use waSpawnMenuParms as parameter +#define IPC_SPAWNEQPRESETMENU 933 +#define IPC_SPAWNFILEMENU 934 //menubar +#define IPC_SPAWNOPTIONSMENU 935 //menubar +#define IPC_SPAWNWINDOWSMENU 936 //menubar +#define IPC_SPAWNHELPMENU 937 //menubar +#define IPC_SPAWNPLAYMENU 938 //menubar +#define IPC_SPAWNPEFILEMENU 939 //menubar +#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar +#define IPC_SPAWNPESORTMENU 941 //menubar +#define IPC_SPAWNPEHELPMENU 942 //menubar +#define IPC_SPAWNMLFILEMENU 943 //menubar +#define IPC_SPAWNMLVIEWMENU 944 //menubar +#define IPC_SPAWNMLHELPMENU 945 //menubar +#define IPC_SPAWNPELISTOFPLAYLISTS 946 + +typedef struct +{ + HWND wnd; + int xpos; // in screen coordinates + int ypos; +} waSpawnMenuParms; + +// waSpawnMenuParms2 is used by the menubar submenus +typedef struct +{ + HWND wnd; + int xpos; // in screen coordinates + int ypos; + int width; + int height; +} waSpawnMenuParms2; + + +// system tray sends this (you might want to simulate it) +#define WM_WA_SYSTRAY WM_USER+1 + +// input plugins send this when they are done playing back +#define WM_WA_MPEG_EOF WM_USER+2 + + + +//// video stuff + +#define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):) +#define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface +#define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24)) +#define VIDUSER_SET_INFOSTRING 0x1000 +#define VIDUSER_GET_VIDEOHWND 0x1001 +#define VIDUSER_SET_VFLIP 0x1002 +#define VIDUSER_SET_TRACKSELINTERFACE 0x1003 // give your ITrackSelector interface as param2 + +#ifndef NO_IVIDEO_DECLARE +#ifdef __cplusplus + +class VideoOutput; +class SubsItem; + +typedef struct { + unsigned char* baseAddr; + long rowBytes; +} YV12_PLANE; + +typedef struct { + YV12_PLANE y; + YV12_PLANE u; + YV12_PLANE v; +} YV12_PLANES; + +class IVideoOutput +{ + public: + virtual ~IVideoOutput() { } + virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0; + virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { } + virtual void close()=0; + virtual void draw(void *frame)=0; + virtual void drawSubtitle(SubsItem *item) { } + virtual void showStatusMsg(const char *text) { } + virtual int get_latency() { return 0; } + virtual void notifyBufferState(int bufferstate) { } /* 0-255*/ + + virtual int extended(int param1, int param2, int param3) { return 0; } // Dispatchable, eat this! +}; + +class ITrackSelector +{ + public: + virtual int getNumAudioTracks()=0; + virtual void enumAudioTrackName(int n, const char *buf, int size)=0; + virtual int getCurAudioTrack()=0; + virtual int getNumVideoTracks()=0; + virtual void enumVideoTrackName(int n, const char *buf, int size)=0; + virtual int getCurVideoTrack()=0; + + virtual void setAudioTrack(int n)=0; + virtual void setVideoTrack(int n)=0; +}; + +#endif //cplusplus +#endif//NO_IVIDEO_DECLARE + +// these messages are callbacks that you can grab by subclassing the winamp window + +// wParam = +#define IPC_CB_WND_EQ 0 // use one of these for the param +#define IPC_CB_WND_PE 1 +#define IPC_CB_WND_MB 2 +#define IPC_CB_WND_VIDEO 3 +#define IPC_CB_WND_MAIN 4 + +#define IPC_CB_ONSHOWWND 600 +#define IPC_CB_ONHIDEWND 601 + +#define IPC_CB_GETTOOLTIP 602 + +#define IPC_CB_MISC 603 + #define IPC_CB_MISC_TITLE 0 + #define IPC_CB_MISC_VOLUME 1 // volume/pan + #define IPC_CB_MISC_STATUS 2 + #define IPC_CB_MISC_EQ 3 + #define IPC_CB_MISC_INFO 4 + #define IPC_CB_MISC_VIDEOINFO 5 + +#define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent) +#define IPC_CB_CONVERT_DONE 605 + +#define IPC_ADJUST_FFWINDOWSMENUPOS 606 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS); +** moves where winamp expects the freeform windows in the menubar windows main menu. Useful if you wish to insert a +** menu item above extra freeform windows. +*/ + +#define IPC_ISDOUBLESIZE 608 + +#define IPC_ADJUST_FFOPTIONSMENUPOS 609 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS); +** moves where winamp expects the freeform preferences item in the menubar windows main menu. Useful if you wish to insert a +** menu item above preferences item. +*/ + +#define IPC_GETTIMEDISPLAYMODE 610 // returns 0 if displaying elapsed time or 1 if displaying remaining time + +#define IPC_SETVISWND 611 // param is hwnd, setting this allows you to receive ID_VIS_NEXT/PREVOUS/RANDOM/FS wm_commands +#define ID_VIS_NEXT 40382 +#define ID_VIS_PREV 40383 +#define ID_VIS_RANDOM 40384 +#define ID_VIS_FS 40389 +#define ID_VIS_CFG 40390 +#define ID_VIS_MENU 40391 + +#define IPC_GETVISWND 612 // returns the vis cmd handler hwnd +#define IPC_ISVISRUNNING 613 +#define IPC_CB_VISRANDOM 628 // param is status of random + +#define IPC_SETIDEALVIDEOSIZE 614 // sent by winamp to winamp, trap it if you need it. width=HIWORD(param), height=LOWORD(param) + +#define IPC_GETSTOPONVIDEOCLOSE 615 +#define IPC_SETSTOPONVIDEOCLOSE 616 + +typedef struct { + HWND hwnd; + int uMsg; + int wParam; + int lParam; +} transAccelStruct; + +#define IPC_TRANSLATEACCELERATOR 617 + +typedef struct { + int cmd; + int x; + int y; + int align; +} windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD + +#define IPC_CB_ONTOGGLEAOT 618 + +#define IPC_GETPREFSWND 619 + +#define IPC_SET_PE_WIDTHHEIGHT 620 // data is a pointer to a POINT structure that holds width & height + +#define IPC_GETLANGUAGEPACKINSTANCE 621 + +#define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02" + +#define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config + +#define IPC_GETOUTPUTPLUGIN 625 + +#define IPC_SETDRAWBORDERS 626 +#define IPC_DISABLESKINCURSORS 627 +#define IPC_CB_RESETFONT 629 + +#define IPC_IS_FULLSCREEN 630 // returns 1 if video or vis is in fullscreen mode +#define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode + +#define IPC_SHOW_NOTIFICATION 632 + +#define IPC_GETSKININFO 633 + +#define IPC_GET_MANUALPLADVANCE 634 +/* (requires Winamp 5.03+) +** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_MANUALPLADVANCE); +** +** IPC_GET_MANUALPLADVANCE returns the status of the Manual Playlist Advance (1 if set) +*/ + +#define IPC_SET_MANUALPLADVANCE 635 +/* (requires Winamp 5.03+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_MANUALPLADVANCE); +** +** IPC_SET_MANUALPLADVANCE sets the status of the Manual Playlist Advance option (1 to turn it on) +*/ + +#define IPC_GET_NEXT_PLITEM 636 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_EOF_GET_NEXT_PLITEM); +** +** Sent to Winamp's main window when an item has just finished playback or the next button has been pressed and +** requesting the new playlist item number to go to. +** Mainly used by gen_jumpex. Subclass this message in your application to return the new item number. +** -1 for normal winamp operation (default) or the new item number in the playlist to play. +*/ + +#define IPC_GET_PREVIOUS_PLITEM 637 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_EOF_GET_PREVIOUS_PLITEM); +** +** Sent to Winamp's main window when the previous button has been pressed and Winamp is requesting the new playlist item number to go to. +** Mainly used by gen_jumpex. Subclass this message in your application to return the new item number. +** -1 for normal winamp operation (default) or the new item number in the playlist to play. +*/ + +#define IPC_IS_WNDSHADE 638 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,wnd,IPC_IS_WNDSHADE); +** +** 'wnd' is window id as defined for IPC_GETWND, or -1 for main window +** Returns 1 if wnd is set to winshade mode, or 0 if it is not +*/ + +#define IPC_SETRATING 639 +/* (requires Winamp 5.04+ with ML) +** SendMessage(hwnd_winamp,WM_WA_IPC,rating,IPC_SETRATING); +** 'rating' is an int value from 0 (no rating) to 5 +*/ + +#define IPC_GETRATING 640 +/* (requires Winamp 5.04+ with ML) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); +** returns the current item's rating +*/ + +#define IPC_GETNUMAUDIOTRACKS 641 +/* (requires Winamp 5.04+) +** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMAUDIOTRACKS); +** returns the number of audio tracks for the currently playing item +*/ + +#define IPC_GETNUMVIDEOTRACKS 642 +/* (requires Winamp 5.04+) +** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMVIDEOTRACKS); +** returns the number of video tracks for the currently playing item +*/ + +#define IPC_GETAUDIOTRACK 643 +/* (requires Winamp 5.04+) +** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETAUDIOTRACK); +** returns the id of the current audio track for the currently playing item +*/ + +#define IPC_GETVIDEOTRACK 644 +/* (requires Winamp 5.04+) +** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVIDEOTRACK); +** returns the id of the current video track for the currently playing item +*/ + +#define IPC_SETAUDIOTRACK 645 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETAUDIOTRACK); +** switch the currently playing item to a new audio track +*/ + +#define IPC_SETVIDEOTRACK 646 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETVIDEOTRACK); +** switch the currently playing item to a new video track +*/ + +#define IPC_PUSH_DISABLE_EXIT 647 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PUSH_DISABLE_EXIT ); +** lets you disable or re-enable the UI exit functions (close button, +** context menu, alt-f4). +** call IPC_POP_DISABLE_EXIT when you are done doing whatever required +** preventing exit +*/ + +#define IPC_POP_DISABLE_EXIT 648 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_POP_DISABLE_EXIT ); +** see IPC_PUSH_DISABLE_EXIT +*/ + +#define IPC_IS_EXIT_ENABLED 649 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_EXIT_ENABLED); +** returns 0 if exit is disabled, 1 otherwise +*/ + +#define IPC_IS_AOT 650 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_AOT); +** returns status of always on top flag. note: this may not match the actual +** TOPMOST window flag while another fullscreen application is focused +*/ + + +// >>>>>>>>>>> Next is 651 + +#define IPC_PLCMD 1000 + +#define PLCMD_ADD 0 +#define PLCMD_REM 1 +#define PLCMD_SEL 2 +#define PLCMD_MISC 3 +#define PLCMD_LIST 4 + +#define IPC_MBCMD 1001 + +#define MBCMD_BACK 0 +#define MBCMD_FORWARD 1 +#define MBCMD_STOP 2 +#define MBCMD_RELOAD 3 +#define MBCMD_MISC 4 + +#define IPC_VIDCMD 1002 + +#define VIDCMD_FULLSCREEN 0 +#define VIDCMD_1X 1 +#define VIDCMD_2X 2 +#define VIDCMD_LIB 3 +#define VIDPOPUP_MISC 4 + +#define IPC_MBURL 1003 //sets the URL +#define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready) +#define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready) +#define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND +#define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library +#define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready) + +#define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status + +// IPC 2000-3000 reserved for freeform messages, see gen_ff/ff_ipc.h +#define IPC_FF_FIRST 2000 +#define IPC_FF_LAST 3000 + +#define IPC_GETDROPTARGET 3001 + +#define IPC_PLAYLIST_MODIFIED 3002 // sent to main wnd whenever the playlist is modified + +#define IPC_PLAYING_FILE 3003 // sent to main wnd with the file as parm whenever a file is played +#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 // sent to main wnd with the file as parm whenever a file tag might be updated + + +#define IPC_ALLOW_PLAYTRACKING 3007 +// send nonzero to allow, zero to disallow + +#define IPC_HOOK_OKTOQUIT 3010 // return 0 to abort a quit, nonzero if quit is OK + +#define IPC_WRITECONFIG 3011 // pass 2 to write all, 1 to write playlist + common, 0 to write common+less common + +// pass a string to be the name to register, and returns a value > 65536, which is a unique value you can use +// for custom WM_WA_IPC messages. +#define IPC_REGISTER_WINAMP_IPCMESSAGE 65536 + + + +#endif //_WA_IPC_H_ diff --git a/Branches/MusicMod/Player/Src/Winamp/wa_msgids.h b/Branches/MusicMod/Player/Src/Winamp/wa_msgids.h new file mode 100644 index 0000000000..ae5ce4fe7b --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winamp/wa_msgids.h @@ -0,0 +1,297 @@ +/* +** wa_msgids.h (created 14/04/2004 12:23:19 PM) +** Created from wa_ipc.h and resource.h from the language sdk +** by Darren Owen aka DrO +** +** This a simple header file which defines the message ids to allow you to control +** Winamp in keeping with the old frontend.h (R.I.P.) +** +** +** Version History: +** +** v1.0 :: intial version with ids for Winamp 5.02+ +** v1.0a :: fixed the file to work on compile +** v1.1 :: added the msg id for 'Manual Playlist Advance' +** v1.2 :: added in song rating menu items +** +** +** How to use: +** +** To send these, use the format: +** +** SendMessage(hwnd_winamp, WM_COMMAND,command_name,0); +** +** For other languages such as Visual Basic, Pascal, etc you will need to use +** the equivalent calling SendMessage(..) calling convention +** +** +** Notes: +** +** IDs 42000 to 45000 are reserved for gen_ff +** IDs from 45000 to 57000 are reserved for library +** +*/ + +#ifndef _WA_MSGIDS_H_ +#define _WA_MSGIDS_H_ + +#define WINAMP_FILE_QUIT 40001 +#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences +#define WINAMP_OPTIONS_AOT 40019 // toggles always on top +#define WINAMP_FILE_REPEAT 40022 +#define WINAMP_FILE_SHUFFLE 40023 +#define WINAMP_HIGH_PRIORITY 40025 +#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box +#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window +#define WINAMP_OPTIONS_ELAPSED 40037 +#define WINAMP_OPTIONS_REMAINING 40038 +#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window +#define WINAMP_HELP_ABOUT 40041 // pops up the about box :) +#define WINAMP_MAINMENU 40043 + + +/* the following are the five main control buttons, with optionally shift +** or control pressed +** (for the exact functions of each, just try it out) +*/ +#define WINAMP_BUTTON1 40044 +#define WINAMP_BUTTON2 40045 +#define WINAMP_BUTTON3 40046 +#define WINAMP_BUTTON4 40047 +#define WINAMP_BUTTON5 40048 +#define WINAMP_BUTTON1_SHIFT 40144 +#define WINAMP_BUTTON2_SHIFT 40145 +#define WINAMP_BUTTON3_SHIFT 40146 +#define WINAMP_BUTTON4_SHIFT 40147 +#define WINAMP_BUTTON5_SHIFT 40148 +#define WINAMP_BUTTON1_CTRL 40154 +#define WINAMP_BUTTON2_CTRL 40155 +#define WINAMP_BUTTON3_CTRL 40156 +#define WINAMP_BUTTON4_CTRL 40157 +#define WINAMP_BUTTON5_CTRL 40158 + +#define WINAMP_VOLUMEUP 40058 // turns the volume up a little +#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little +#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds +#define WINAMP_REW5S 40061 // rewinds 5 seconds +#define WINAMP_NEXT_WINDOW 40063 +#define WINAMP_OPTIONS_WINDOWSHADE 40064 +#define WINAMP_OPTIONS_DSIZE 40165 +#define IDC_SORT_FILENAME 40166 +#define IDC_SORT_FILETITLE 40167 +#define IDC_SORT_ENTIREFILENAME 40168 +#define IDC_SELECTALL 40169 +#define IDC_SELECTNONE 40170 +#define IDC_SELECTINV 40171 +#define IDM_EQ_LOADPRE 40172 +#define IDM_EQ_LOADMP3 40173 +#define IDM_EQ_LOADDEFAULT 40174 +#define IDM_EQ_SAVEPRE 40175 +#define IDM_EQ_SAVEMP3 40176 +#define IDM_EQ_SAVEDEFAULT 40177 +#define IDM_EQ_DELPRE 40178 +#define IDM_EQ_DELMP3 40180 +#define IDC_PLAYLIST_PLAY 40184 +#define WINAMP_FILE_LOC 40185 +#define WINAMP_OPTIONS_EASYMOVE 40186 +#define WINAMP_FILE_DIR 40187 // pops up the load directory box +#define WINAMP_EDIT_ID3 40188 +#define WINAMP_TOGGLE_AUTOSCROLL 40189 +#define WINAMP_VISSETUP 40190 +#define WINAMP_PLGSETUP 40191 +#define WINAMP_VISPLUGIN 40192 +#define WINAMP_JUMP 40193 +#define WINAMP_JUMPFILE 40194 +#define WINAMP_JUMP10FWD 40195 +#define WINAMP_JUMP10BACK 40197 +#define WINAMP_PREVSONG 40198 +#define WINAMP_OPTIONS_EXTRAHQ 40200 +#define ID_PE_NEW 40201 +#define ID_PE_OPEN 40202 +#define ID_PE_SAVE 40203 +#define ID_PE_SAVEAS 40204 +#define ID_PE_SELECTALL 40205 +#define ID_PE_INVERT 40206 +#define ID_PE_NONE 40207 +#define ID_PE_ID3 40208 +#define ID_PE_S_TITLE 40209 +#define ID_PE_S_FILENAME 40210 +#define ID_PE_S_PATH 40211 +#define ID_PE_S_RANDOM 40212 +#define ID_PE_S_REV 40213 +#define ID_PE_CLEAR 40214 +#define ID_PE_MOVEUP 40215 +#define ID_PE_MOVEDOWN 40216 +#define WINAMP_SELSKIN 40219 +#define WINAMP_VISCONF 40221 +#define ID_PE_NONEXIST 40222 +#define ID_PE_DELETEFROMDISK 40223 +#define ID_PE_CLOSE 40224 +#define WINAMP_VIS_SETOSC 40226 +#define WINAMP_VIS_SETANA 40227 +#define WINAMP_VIS_SETOFF 40228 +#define WINAMP_VIS_DOTSCOPE 40229 +#define WINAMP_VIS_LINESCOPE 40230 +#define WINAMP_VIS_SOLIDSCOPE 40231 +#define WINAMP_VIS_NORMANA 40233 +#define WINAMP_VIS_FIREANA 40234 +#define WINAMP_VIS_LINEANA 40235 +#define WINAMP_VIS_NORMVU 40236 +#define WINAMP_VIS_SMOOTHVU 40237 +#define WINAMP_VIS_FULLREF 40238 +#define WINAMP_VIS_FULLREF2 40239 +#define WINAMP_VIS_FULLREF3 40240 +#define WINAMP_VIS_FULLREF4 40241 +#define WINAMP_OPTIONS_TOGTIME 40242 +#define EQ_ENABLE 40244 +#define EQ_AUTO 40245 +#define EQ_PRESETS 40246 +#define WINAMP_VIS_FALLOFF0 40247 +#define WINAMP_VIS_FALLOFF1 40248 +#define WINAMP_VIS_FALLOFF2 40249 +#define WINAMP_VIS_FALLOFF3 40250 +#define WINAMP_VIS_FALLOFF4 40251 +#define WINAMP_VIS_PEAKS 40252 +#define ID_LOAD_EQF 40253 +#define ID_SAVE_EQF 40254 +#define ID_PE_ENTRY 40255 +#define ID_PE_SCROLLUP 40256 +#define ID_PE_SCROLLDOWN 40257 +#define WINAMP_MAIN_WINDOW 40258 +#define WINAMP_VIS_PFALLOFF0 40259 +#define WINAMP_VIS_PFALLOFF1 40260 +#define WINAMP_VIS_PFALLOFF2 40261 +#define WINAMP_VIS_PFALLOFF3 40262 +#define WINAMP_VIS_PFALLOFF4 40263 +#define ID_PE_TOP 40264 +#define ID_PE_BOTTOM 40265 +#define WINAMP_OPTIONS_WINDOWSHADE_PL 40266 +#define EQ_INC1 40267 +#define EQ_INC2 40268 +#define EQ_INC3 40269 +#define EQ_INC4 40270 +#define EQ_INC5 40271 +#define EQ_INC6 40272 +#define EQ_INC7 40273 +#define EQ_INC8 40274 +#define EQ_INC9 40275 +#define EQ_INC10 40276 +#define EQ_INCPRE 40277 +#define EQ_DECPRE 40278 +#define EQ_DEC1 40279 +#define EQ_DEC2 40280 +#define EQ_DEC3 40281 +#define EQ_DEC4 40282 +#define EQ_DEC5 40283 +#define EQ_DEC6 40284 +#define EQ_DEC7 40285 +#define EQ_DEC8 40286 +#define EQ_DEC9 40287 +#define EQ_DEC10 40288 +#define ID_PE_SCUP 40289 +#define ID_PE_SCDOWN 40290 +#define WINAMP_REFRESHSKIN 40291 +#define ID_PE_PRINT 40292 +#define ID_PE_EXTINFO 40293 +#define WINAMP_PLAYLIST_ADVANCE 40294 +#define WINAMP_VIS_LIN 40295 +#define WINAMP_VIS_BAR 40296 +#define WINAMP_OPTIONS_MINIBROWSER 40298 +#define MB_FWD 40299 +#define MB_BACK 40300 +#define MB_RELOAD 40301 +#define MB_OPENMENU 40302 +#define MB_OPENLOC 40303 +#define WINAMP_NEW_INSTANCE 40305 +#define MB_UPDATE 40309 +#define WINAMP_OPTIONS_WINDOWSHADE_EQ 40310 +#define EQ_PANLEFT 40313 +#define EQ_PANRIGHT 40314 +#define WINAMP_GETMORESKINS 40316 +#define WINAMP_VIS_OPTIONS 40317 +#define WINAMP_PE_SEARCH 40318 +#define ID_PE_BOOKMARK 40319 +#define WINAMP_EDIT_BOOKMARKS 40320 +#define WINAMP_MAKECURBOOKMARK 40321 +#define ID_MAIN_PLAY_BOOKMARK_NONE 40322 +#define ID_MAIN_PLAY_AUDIOCD 40323 // starts playing the audio CD in the first CD reader +#define ID_MAIN_PLAY_AUDIOCD2 40324 // plays the 2nd +#define ID_MAIN_PLAY_AUDIOCD3 40325 // plays the 3rd +#define ID_MAIN_PLAY_AUDIOCD4 40326 // plays the 4th +#define WINAMP_OPTIONS_VIDEO 40328 +#define ID_VIDEOWND_ZOOMFULLSCREEN 40329 +#define ID_VIDEOWND_ZOOM100 40330 +#define ID_VIDEOWND_ZOOM200 40331 +#define ID_VIDEOWND_ZOOM50 40332 +#define ID_VIDEOWND_VIDEOOPTIONS 40333 +#define WINAMP_MINIMIZE 40334 +#define ID_PE_FONTBIGGER 40335 +#define ID_PE_FONTSMALLER 40336 +#define WINAMP_VIDEO_TOGGLE_FS 40337 +#define WINAMP_VIDEO_TVBUTTON 40338 +#define WINAMP_LIGHTNING_CLICK 40339 +#define ID_FILE_ADDTOLIBRARY 40344 +#define ID_HELP_HELPTOPICS 40347 +#define ID_HELP_GETTINGSTARTED 40348 +#define ID_HELP_WINAMPFORUMS 40349 +#define ID_PLAY_VOLUMEUP 40351 +#define ID_PLAY_VOLUMEDOWN 40352 +#define ID_PEFILE_OPENPLAYLISTFROMLIBRARY_NOPLAYLISTSINLIBRARY 40355 +#define ID_PEFILE_ADDFROMLIBRARY 40356 +#define ID_PEFILE_CLOSEPLAYLISTEDITOR 40357 +#define ID_PEPLAYLIST_PLAYLISTPREFERENCES 40358 +#define ID_MLFILE_NEWPLAYLIST 40359 +#define ID_MLFILE_LOADPLAYLIST 40360 +#define ID_MLFILE_SAVEPLAYLIST 40361 +#define ID_MLFILE_ADDMEDIATOLIBRARY 40362 +#define ID_MLFILE_CLOSEMEDIALIBRARY 40363 +#define ID_MLVIEW_NOWPLAYING 40364 +#define ID_MLVIEW_LOCALMEDIA_ALLMEDIA 40366 +#define ID_MLVIEW_LOCALMEDIA_AUDIO 40367 +#define ID_MLVIEW_LOCALMEDIA_VIDEO 40368 +#define ID_MLVIEW_PLAYLISTS_NOPLAYLISTINLIBRARY 40369 +#define ID_MLVIEW_INTERNETRADIO 40370 +#define ID_MLVIEW_INTERNETTV 40371 +#define ID_MLVIEW_LIBRARYPREFERENCES 40372 +#define ID_MLVIEW_DEVICES_NOAVAILABLEDEVICE 40373 +#define ID_MLFILE_IMPORTCURRENTPLAYLIST 40374 +#define ID_MLVIEW_MEDIA 40376 +#define ID_MLVIEW_PLAYLISTS 40377 +#define ID_MLVIEW_MEDIA_ALLMEDIA 40377 +#define ID_MLVIEW_DEVICES 40378 +#define ID_FILE_SHOWLIBRARY 40379 +#define ID_FILE_CLOSELIBRARY 40380 +#define ID_POST_PLAY_PLAYLIST 40381 +#define ID_VIS_NEXT 40382 +#define ID_VIS_PREV 40383 +#define ID_VIS_RANDOM 40384 +#define ID_MANAGEPLAYLISTS 40385 +#define ID_PREFS_SKIN_SWITCHTOSKIN 40386 +#define ID_PREFS_SKIN_DELETESKIN 40387 +#define ID_PREFS_SKIN_RENAMESKIN 40388 +#define ID_VIS_FS 40389 +#define ID_VIS_CFG 40390 +#define ID_VIS_MENU 40391 +#define ID_VIS_SET_FS_FLAG 40392 +#define ID_PE_SHOWPLAYING 40393 +#define ID_HELP_REGISTERWINAMPPRO 40394 +#define ID_PE_MANUAL_ADVANCE 40395 +#define WA_SONG_5_STAR_RATING 40396 +#define WA_SONG_4_STAR_RATING 40397 +#define WA_SONG_3_STAR_RATING 40398 +#define WA_SONG_2_STAR_RATING 40399 +#define WA_SONG_1_STAR_RATING 40400 +#define WA_SONG_NO_RATING 40401 +#define PL_SONG_5_STAR_RATING 40402 +#define PL_SONG_4_STAR_RATING 40403 +#define PL_SONG_3_STAR_RATING 40404 +#define PL_SONG_2_STAR_RATING 40405 +#define PL_SONG_1_STAR_RATING 40406 +#define PL_SONG_NO_RATING 40407 +#define AUDIO_TRACK_ONE 40408 +#define VIDEO_TRACK_ONE 40424 + +#define ID_SWITCH_COLOURTHEME 44500 +#define ID_GENFF_LIMIT 45000 + +#endif diff --git a/Branches/MusicMod/Player/Src/Winmain.cpp b/Branches/MusicMod/Player/Src/Winmain.cpp new file mode 100644 index 0000000000..bf9362a991 --- /dev/null +++ b/Branches/MusicMod/Player/Src/Winmain.cpp @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp, Open source Winamp core +// +// Copyright © 2005 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#include "Global.h" +#include "Font.h" +#include "InputPlugin.h" +#include "OutputPlugin.h" +#include "VisPlugin.h" +#include "DspPlugin.h" +#include "GenPlugin.h" +#include "Main.h" +#include "Rebar.h" +#include "Playlist.h" +#include "Status.h" +#include "PluginManager.h" +#include "Prefs.h" +#include "Config.h" + +#include "Emabox/Emabox.h" + + + +#define PLUS_ALT ( FVIRTKEY | FALT ) +#define PLUS_CONTROL ( FVIRTKEY | FCONTROL ) +#define PLUS_CONTROL_ALT ( FVIRTKEY | FCONTROL | FALT ) +#define PLUS_CONTROL_SHIFT ( FVIRTKEY | FCONTROL | FSHIFT ) +#define PLUS_SHIFT ( FVIRTKEY | FSHIFT ) + + + +HINSTANCE g_hInstance = NULL; // extern + +TCHAR * szHomeDir = NULL; // extern +int iHomeDirLen = 0; // extern + +TCHAR * szPluginDir = NULL; // extern +int iPluginDirLen = 0; // extern + + + +TCHAR szCurDir[ MAX_PATH + 1 ] = TEXT( "" ); +ConfCurDir ccdCurDir( szCurDir, TEXT( "CurDir" ) ); + + +bool bWarnPluginsMissing; +ConfBool cbWarnPluginsMissing( &bWarnPluginsMissing, TEXT( "WarnPluginsMissing" ), CONF_MODE_PUBLIC, true ); + + + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow ) +{ + g_hInstance = hInstance; + + + // Load full config + Conf::Init( hInstance ); + + + // Get home dir + szHomeDir = new TCHAR[ MAX_PATH + 1 ]; + iHomeDirLen = GetModuleFileName( NULL, szHomeDir, MAX_PATH ); + if( !iHomeDirLen ) return 1; + + TCHAR * walk = szHomeDir + iHomeDirLen - 1; + while( ( walk > szHomeDir ) && ( *walk != TEXT( '\\' ) ) ) walk--; + walk++; + *walk = TEXT( '\0' ); + iHomeDirLen = walk - szHomeDir; + + + // Get plugins dir + szPluginDir = new TCHAR[ MAX_PATH + 1 ]; + memcpy( szPluginDir, szHomeDir, iHomeDirLen * sizeof( TCHAR ) ); + memcpy( szPluginDir + iHomeDirLen, TEXT( "Plugins" ), 7 * sizeof( TCHAR ) ); + szPluginDir[ iHomeDirLen + 7 ] = TEXT( '\0' ); + + + Font::Create(); + BuildMainWindow(); + Prefs::Create(); + + + // Show window + ShowWindow( WindowMain, SW_SHOW ); + SetForegroundWindow( WindowMain ); + SetFocus( WindowMain ); + + Plugin::FindAll ( szPluginDir, TEXT( "in_*.dll" ), true ); + Plugin::FindAll( szPluginDir, TEXT( "out_*.dll" ), false ); + Plugin::FindAll ( szPluginDir, TEXT( "vis_*.dll" ), false ); + Plugin::FindAll ( szPluginDir, TEXT( "dsp_*.dll" ), false ); + Plugin::FindAll ( szPluginDir, TEXT( "gen_*.dll" ), true ); + + PluginManager::Fill(); + + + // Check plugin presence + // One msgbox maximum + if( bWarnPluginsMissing ) + { + + + if( input_plugins.empty() ) + { + // No input plugins + TCHAR szBuffer[ 5000 ]; + _stprintf( + szBuffer, + TEXT( + "No input plugins were found.\n" + "\n" + "Please install at least one Winamp input plugin to \n" + "%s " + ), + szPluginDir + ); + + int iNeverAgain = bWarnPluginsMissing ? 0 : 1; + EmaBox( 0, szBuffer, TEXT( "Input plugins missing" ), MB_ICONEXCLAMATION | MB_CHECKNEVERAGAIN, &iNeverAgain ); + bWarnPluginsMissing = ( iNeverAgain == 0 ); + } + else if( output_plugins.empty() ) + { + // No output plugins + TCHAR szBuffer[ 5000 ]; + _stprintf( + szBuffer, + TEXT( + "No output plugins were found.\n" + "\n" + "Please install at least one Winamp output plugin to \n" + "%s " + ), + szPluginDir + ); + + int iNeverAgain = bWarnPluginsMissing ? 0 : 1; + EmaBox( 0, szBuffer, TEXT( "Output plugins missing" ), MB_ICONEXCLAMATION | MB_CHECKNEVERAGAIN, &iNeverAgain ); + bWarnPluginsMissing = ( iNeverAgain == 0 ); + } + } + + + // Todo: all the rest... + ACCEL accels[] = { + { PLUS_CONTROL, 'A', ID_PE_SELECTALL }, // [Ctrl] + [A] + { PLUS_CONTROL, 'I', ID_PE_INVERT }, // [Ctrl] + [I] + { PLUS_CONTROL, 'N', ID_PE_NEW }, // [Ctrl] + [N] + { PLUS_CONTROL, 'O', ID_PE_OPEN }, // [Ctrl] + [O] + { PLUS_CONTROL, 'P', WINAMP_OPTIONS_PREFS }, // [Ctrl] + [P] + { PLUS_CONTROL, 'S', ID_PE_SAVEAS }, // [Ctrl] + [S] + { PLUS_CONTROL, VK_F1, WINAMP_HELP_ABOUT }, // [Ctrl] + [F1] + { PLUS_CONTROL_SHIFT, 'A', ID_PE_NONE }, // [Ctrl] + [Shift] + [A] + { PLUS_CONTROL_SHIFT, VK_DELETE, ID_PE_CLEAR }, // [Ctrl] + [Shift] + [Del] + { PLUS_ALT, 'F', WINAMP_MAINMENU }, // [Alt] + [F] + { PLUS_ALT, VK_F4, WINAMP_FILE_QUIT } // [Alt] + [F4] + }; + + + HACCEL hAccel = CreateAcceleratorTable( accels, sizeof( accels ) / sizeof( ACCEL ) ); + if( !hAccel ) + { + MessageBox( 0, TEXT( "Accelerator table error" ), TEXT( "" ), 0 ); + } + + // Message loop + MSG msg; + while( GetMessage( &msg, NULL, 0, 0 ) > 0 ) + { + // Note: Keys without [Alt] or [Ctrl] not everywhere! + if( ( ( msg.hwnd == WindowMain ) || IsChild( WindowMain, msg.hwnd ) ) && + TranslateAccelerator( WindowMain, hAccel, &msg ) ) + { + // MessageBox( 0, TEXT( "Trans" ), TEXT( "" ), 0 ); + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + DestroyAcceleratorTable( hAccel ); + + + // Input + vector ::iterator iter_input = input_plugins.begin(); + while( iter_input != input_plugins.end() ) + { + ( *iter_input )->Unload(); + iter_input++; + } + + // Output + vector ::iterator iter_output = output_plugins.begin(); + while( iter_output != output_plugins.end() ) + { + ( *iter_output )->Unload(); + iter_output++; + } + + // General + vector ::iterator iter_gen = gen_plugins.begin(); + while( iter_gen != gen_plugins.end() ) + { + ( *iter_gen )->Unload(); + iter_gen++; + } + + + // TODO: create main::destroy + // UnregisterClass( PA_CLASSNAME, g_hInstance ); + + Prefs::Destroy(); + + Font::Destroy(); + +/* + delete [] szPluginDir; + delete [] szHomeDir; +*/ + + Conf::Write(); + + return 0; +} diff --git a/Branches/MusicMod/Player/Src/fftw3/fftw3.h b/Branches/MusicMod/Player/Src/fftw3/fftw3.h new file mode 100644 index 0000000000..64e445d30d --- /dev/null +++ b/Branches/MusicMod/Player/Src/fftw3/fftw3.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2003 Matteo Frigo + * Copyright (c) 2003 Massachusetts Institute of Technology + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* header file for fftw3 */ +/* $Id: fftw3.h,v 1.1 2005/10/28 19:01:21 hartwork Exp $ */ + +#ifndef FFTW3_H +#define FFTW3_H + +#if defined(__ICC) || defined(_MSC_VER) +#pragma comment ( lib, "fftw3" ) +#endif + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* If is included, use the C99 complex type. Otherwise + define a type bit-compatible with C99 complex */ +#ifdef _Complex_I +# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C +#else +# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2] +#endif + +#define FFTW_CONCAT(prefix, name) prefix ## name +#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name) +#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name) +#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name) + + +enum fftw_r2r_kind_do_not_use_me { + FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, + FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, + FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 +}; + +struct fftw_iodim_do_not_use_me { + int n; /* dimension size */ + int is; /* input stride */ + int os; /* output stride */ +}; + +/* + huge second-order macro that defines prototypes for all API + functions. We expand this macro for each supported precision + + X: name-mangling macro + R: real data type + C: complex data type +*/ + +#define FFTW_DEFINE_API(X, R, C) \ + \ +FFTW_DEFINE_COMPLEX(R, C); \ + \ +typedef struct X(plan_s) *X(plan); \ + \ +typedef struct fftw_iodim_do_not_use_me X(iodim); \ + \ +typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \ + \ +void X(execute)(const X(plan) p); \ + \ +X(plan) X(plan_dft)(int rank, const int *n, \ + C *in, C *out, int sign, unsigned flags); \ + \ +X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \ + unsigned flags); \ +X(plan) X(plan_dft_2d)(int nx, int ny, \ + C *in, C *out, int sign, unsigned flags); \ +X(plan) X(plan_dft_3d)(int nx, int ny, int nz, \ + C *in, C *out, int sign, unsigned flags); \ + \ +X(plan) X(plan_many_dft)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + int sign, unsigned flags); \ + \ +X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +void X(execute_dft)(const X(plan) p, C *in, C *out); \ +void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, R *ro, R *io); \ + \ +X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +X(plan) X(plan_dft_r2c)(int rank, const int *n, \ + R *in, C *out, unsigned flags); \ + \ +X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \ +X(plan) X(plan_dft_r2c_2d)(int nx, int ny, \ + R *in, C *out, unsigned flags); \ +X(plan) X(plan_dft_r2c_3d)(int nx, int ny, \ + int nz, \ + R *in, C *out, unsigned flags); \ + \ + \ +X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +X(plan) X(plan_dft_c2r)(int rank, const int *n, \ + C *in, R *out, unsigned flags); \ + \ +X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \ +X(plan) X(plan_dft_c2r_2d)(int nx, int ny, \ + C *in, R *out, unsigned flags); \ +X(plan) X(plan_dft_c2r_3d)(int nx, int ny, \ + int nz, \ + C *in, R *out, unsigned flags); \ + \ +X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +X(plan) X(plan_guru_split_dft_r2c)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +X(plan) X(plan_guru_split_dft_c2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \ +void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \ + \ +void X(execute_split_dft_r2c)(const X(plan) p, R *in, R *ro, R *io); \ +void X(execute_split_dft_c2r)(const X(plan) p, R *ri, R *ii, R *out); \ + \ +X(plan) X(plan_many_r2r)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \ + X(r2r_kind) kind, unsigned flags); \ +X(plan) X(plan_r2r_2d)(int nx, int ny, R *in, R *out, \ + X(r2r_kind) kindx, X(r2r_kind) kindy, \ + unsigned flags); \ +X(plan) X(plan_r2r_3d)(int nx, int ny, int nz, \ + R *in, R *out, X(r2r_kind) kindx, \ + X(r2r_kind) kindy, X(r2r_kind) kindz, \ + unsigned flags); \ + \ +X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ +void X(execute_r2r)(const X(plan) p, R *in, R *out); \ + \ +void X(destroy_plan)(X(plan) p); \ +void X(forget_wisdom)(void); \ +void X(cleanup)(void); \ + \ +void X(plan_with_nthreads)(int nthreads); \ +int X(init_threads)(void); \ +void X(cleanup_threads)(void); \ + \ +void X(export_wisdom_to_file)(FILE *output_file); \ +char *X(export_wisdom_to_string)(void); \ +void X(export_wisdom)(void (*write_char)(char c, void *), void *data); \ +int X(import_system_wisdom)(void); \ +int X(import_wisdom_from_file)(FILE *input_file); \ +int X(import_wisdom_from_string)(const char *input_string); \ +int X(import_wisdom)(int (*read_char)(void *), void *data); \ + \ +void X(fprint_plan)(const X(plan) p, FILE *output_file); \ +void X(print_plan)(const X(plan) p); \ + \ +void *X(malloc)(size_t n); \ +void X(free)(void *p); \ + \ +void X(flops)(const X(plan) p, double *add, double *mul, double *fma); \ + \ +extern const char X(version)[]; \ +extern const char X(cc)[]; \ +extern const char X(codelet_optim)[]; + + +/* end of FFTW_DEFINE_API macro */ + +FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex) +FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex) +FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex) + +#define FFTW_FORWARD (-1) +#define FFTW_BACKWARD (+1) + +/* documented flags */ +#define FFTW_MEASURE (0U) +#define FFTW_DESTROY_INPUT (1U << 0) +#define FFTW_UNALIGNED (1U << 1) +#define FFTW_CONSERVE_MEMORY (1U << 2) +#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ +#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ +#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ +#define FFTW_ESTIMATE (1U << 6) + +/* undocumented beyond-guru flags */ +#define FFTW_ESTIMATE_PATIENT (1U << 7) +#define FFTW_BELIEVE_PCOST (1U << 8) +#define FFTW_DFT_R2HC_ICKY (1U << 9) +#define FFTW_NONTHREADED_ICKY (1U << 10) +#define FFTW_NO_BUFFERING (1U << 11) +#define FFTW_NO_INDIRECT_OP (1U << 12) +#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */ +#define FFTW_NO_RANK_SPLITS (1U << 14) +#define FFTW_NO_VRANK_SPLITS (1U << 15) +#define FFTW_NO_VRECURSE (1U << 16) + +#define FFTW_NO_SIMD (1U << 17) + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FFTW3_H */ diff --git a/Branches/MusicMod/Player/Src/vis_plainbar/vis_plainbar.cpp b/Branches/MusicMod/Player/Src/vis_plainbar/vis_plainbar.cpp new file mode 100644 index 0000000000..276065e516 --- /dev/null +++ b/Branches/MusicMod/Player/Src/vis_plainbar/vis_plainbar.cpp @@ -0,0 +1,259 @@ +//////////////////////////////////////////////////////////////////////////////// +// Plainamp Toolbar Vis Plugin +// +// Copyright © 2006 Sebastian Pipping +// +// --> http://www.hartwork.org +// +// This source code is released under the GNU General Public License (GPL). +// See GPL.txt for details. Any non-GPL usage is strictly forbidden. +//////////////////////////////////////////////////////////////////////////////// + + +#define WIN32_LEAN_AND_MEAN +#include + + +#include "../Winamp/vis.h" +#include "../Winamp/wa_ipc.h" + + + +#define PLUGIN_NAME "Plainamp Toolbar Vis Plugin" +#define PLUGIN_VERSION "v0.5" + +#define PLUGIN_DESC PLUGIN_NAME " " PLUGIN_VERSION + + + +static char * szClassName = "PlainbarClass"; + + + +winampVisModule * getModule( int which ); + + +void config( struct winampVisModule * this_mod ); +int init( struct winampVisModule * this_mod ); +int render_spec( struct winampVisModule * this_mod ); +void quit( struct winampVisModule * this_mod ); + + +// Double buffering data +HDC memDC = NULL; // Memory device context +HBITMAP memBM = NULL; // Memory bitmap (for memDC) +HBITMAP oldBM = NULL; // Old bitmap (from memDC) + + +HWND hRender = NULL; +int width = 0; +int height = 0; +bool bRunning = false; +HPEN pen = NULL; + + +WNDPROC WndprocTargetBackup = NULL; +LRESULT CALLBACK WndprocTarget( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ); + + + +winampVisHeader hdr = { + VIS_HDRVER, + PLUGIN_DESC, + getModule +}; + + + +winampVisModule mod_spec = +{ + "Default", + NULL, // hwndParent + NULL, // hDllInstance + 0, // sRate + 0, // nCh + 25, // latencyMS + 25, // delayMS + 2, // spectrumNch + 0, // waveformNch + { 0, }, // spectrumData + { 0, }, // waveformData + config, + init, + render_spec, + quit +}; + + + +#ifdef __cplusplus +extern "C" { +#endif +__declspec( dllexport ) winampVisHeader * winampVisGetHeader() +{ + return &hdr; +} +#ifdef __cplusplus +} +#endif + + + +winampVisModule * getModule( int which ) +{ + return which ? NULL : &mod_spec; +} + + + +void config( struct winampVisModule * this_mod ) +{ + MessageBox( + this_mod->hwndParent, + PLUGIN_DESC "\n" + "\n" + "Copyright © 2006 Sebastian Pipping \n" + "\n" + "\n" + "--> http://www.hartwork.org", + "About", + MB_ICONINFORMATION + ); +} + + + +LRESULT CALLBACK WndprocTarget( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + switch( message ) + { + case WM_SIZE: + width = LOWORD( lp ); + height = HIWORD( lp ); + break; + + case WM_DESTROY: + bRunning = false; + PostQuitMessage( 0 ); + return 0; + + } + + return DefWindowProc( hwnd, message, wp, lp ); +} + + + +int init( struct winampVisModule * this_mod ) +{ + if( !this_mod ) return 1; + + // Register message + const int IPC_GETPLAINBARTARGET = ( int )SendMessage( this_mod->hwndParent, WM_WA_IPC, ( WPARAM )"IPC_GETPLAINBARTARGET", IPC_REGISTER_WINAMP_IPCMESSAGE ); + if( IPC_GETPLAINBARTARGET <= 0 ) return 1; + + // Get render parent + HWND hRenderParent = ( HWND )SendMessage( this_mod->hwndParent, WM_WA_IPC, 0, IPC_GETPLAINBARTARGET ); + if( !IsWindow( hRenderParent ) ) return 1; + + // Plug our child in + WNDCLASS wc; + ZeroMemory( &wc, sizeof( WNDCLASS ) ); + wc.lpfnWndProc = WndprocTarget; + wc.hInstance = this_mod->hDllInstance; + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); + wc.lpszClassName = szClassName; + + if( !RegisterClass( &wc ) ) return 1; + + RECT r; + GetClientRect( hRenderParent, &r ); + width = r.right - r.left; + height = r.bottom - r.top; + + hRender = CreateWindowEx( + 0, + szClassName, + "", + WS_CHILD | WS_VISIBLE, + 0, + 0, + width, + height, + hRenderParent, + NULL, + this_mod->hDllInstance, + 0 + ); + + if( !hRender ) + { + UnregisterClass( szClassName, this_mod->hDllInstance ); + return 1; + } + + // Create doublebuffer + const HDC hdc = GetDC( hRender ); + memDC = CreateCompatibleDC( hdc ); + memBM = CreateCompatibleBitmap( hdc, 576, 256 ); + oldBM = ( HBITMAP )SelectObject( memDC, memBM ); + ReleaseDC( hRender, hdc ); + + pen = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_APPWORKSPACE ) ); + + bRunning = true; + return 0; +} + + + +int render_spec( struct winampVisModule * this_mod ) +{ + // Clear background + RECT rect = { 0, 0, 576, 256 }; + FillRect(memDC, &rect, ( HBRUSH )( COLOR_3DFACE + 1 ) ); + + // Draw analyser + SelectObject( memDC, pen ); + for( int x = 0; x < 576; x++ ) + { + int val = 0; + + for( int y = 0; y < this_mod->nCh; y++ ) + { + if( this_mod->spectrumData[ y ][ x ] > val ) + { + val = this_mod->spectrumData[ y ][ x ]; + } + } + + MoveToEx( memDC, x, 256, NULL ); + LineTo( memDC, x, 256 - val ); + } + + // Copy doublebuffer to window + HDC hdc = GetDC( hRender ); + StretchBlt( hdc, 0, 0, width, height, memDC, 0, 0, 576, 256, SRCCOPY ); + ReleaseDC( hRender, hdc ); + + return bRunning ? 0 : 1; +} + + + +void quit( struct winampVisModule * this_mod ) +{ + if( bRunning ) + { + DestroyWindow( hRender ); + } + + UnregisterClass( szClassName, this_mod->hDllInstance ); + + // Delete doublebuffer + SelectObject( memDC, oldBM ); + DeleteObject( memDC ); + DeleteObject( memBM ); + + DeleteObject( pen ); +} diff --git a/Branches/MusicMod/Player/Src/zlib/zconf.h b/Branches/MusicMod/Player/Src/zlib/zconf.h new file mode 100644 index 0000000000..db9ff5e7e3 --- /dev/null +++ b/Branches/MusicMod/Player/Src/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2005/10/10 21:08:30 hartwork Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/Branches/MusicMod/Player/Src/zlib/zlib.h b/Branches/MusicMod/Player/Src/zlib/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/Branches/MusicMod/Player/Src/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */