diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_transcode | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_transcode')
-rw-r--r-- | Src/Plugins/Library/ml_transcode/LinkedQueue.cpp | 139 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/LinkedQueue.h | 41 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/api__ml_transcode.h | 26 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/main.cpp | 1100 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/ml_transcode.rc | 162 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/ml_transcode.sln | 30 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj | 333 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj.filters | 65 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/replaceVars.cpp | 317 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/resource.h | 45 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/reversesync.h | 9 | ||||
-rw-r--r-- | Src/Plugins/Library/ml_transcode/version.rc2 | 39 |
12 files changed, 2306 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_transcode/LinkedQueue.cpp b/Src/Plugins/Library/ml_transcode/LinkedQueue.cpp new file mode 100644 index 00000000..7896c7bb --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/LinkedQueue.cpp @@ -0,0 +1,139 @@ +#include "LinkedQueue.h" + +LinkedQueue::LinkedQueue() +{ + size=0; + head=NULL; + tail=NULL; + bm=NULL; + bmpos=0; + InitializeCriticalSection(&cs); +} + +void LinkedQueue::lock() +{ + EnterCriticalSection(&cs); + //wchar_t buf[100]; wsprintf(buf,L"Lock taken by %x",GetCurrentThreadId()); OutputDebugString(buf); +} +void LinkedQueue::unlock() +{ + LeaveCriticalSection(&cs); + //wchar_t buf[100]; wsprintf(buf,L"Lock released by %x",GetCurrentThreadId()); OutputDebugString(buf); +} + +LinkedQueue::~LinkedQueue() +{ + lock(); + QueueElement * q=head; + while(q) { QueueElement *p=q; q=q->next; delete p; } + unlock(); + DeleteCriticalSection(&cs); +} + +void LinkedQueue::Offer(void * e) +{ + lock(); + if(size==0) { size++; head=tail=new QueueElement(e); unlock(); return; } + tail->next=new QueueElement(e); + tail->next->prev=tail; + tail=tail->next; + size++; + bm=NULL; + unlock(); +} + +void * LinkedQueue::Poll() +{ + lock(); + if(size == 0) { unlock(); return NULL; } + size--; + void * r = head->elem; + QueueElement * q = head; + head=head->next; + if(head!=NULL) head->prev=NULL; + else tail=NULL; + delete q; + bm=NULL; + unlock(); + return r; +} + +void * LinkedQueue::Peek() +{ + lock(); + void * ret=head?head->elem:NULL; + unlock(); + return ret; +} + +QueueElement * LinkedQueue::Find(int x) +{ + if(x>=size || x<0) return NULL; + if(x == 0) return head; + if(x == size-1) return tail; + if(!bm) { bm=head; bmpos=0; } + int diffh = x; + int difft = (size-1) - x; + int diffbm = x - bmpos; + diffbm>0?diffbm:-diffbm; + if(diffh < difft && diffh < diffbm) { bm=head; bmpos=0; } + else if(diffh >= difft && diffbm >= difft) { bm=tail; bmpos=size-1; } + while(bmpos > x && bm) { bm=bm->prev; bmpos--; } + while(bmpos < x && bm) { bm=bm->next; bmpos++; } + return bm; +} + +void * LinkedQueue::Get(int pos) +{ + lock(); + QueueElement * e = Find(pos); + unlock(); + return e?e->elem:NULL; +} + +void LinkedQueue::Set(int pos, void * val) +{ + lock(); + QueueElement * e = Find(pos); + if(e) e->elem=val; + unlock(); +} + +void* LinkedQueue::Del(int pos) +{ + lock(); + QueueElement * e = Find(pos); + if(!e) { unlock(); return NULL; } + else if(size == 1) head=tail=NULL; + else if(e==head) + { + head=head->next; + head->prev=NULL; + } + else if(e==tail) + { + tail=tail->prev; + tail->next=NULL; + } + else + { + e->prev->next = e->next; + e->next->prev = e->prev; + } + size--; + bm=NULL; + unlock(); + void * ret = e->elem; + delete e; + return ret; +} + +int LinkedQueue::GetSize() +{ + return size; + /* + lock(); + int s = size; + unlock(); + return s;*/ +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/LinkedQueue.h b/Src/Plugins/Library/ml_transcode/LinkedQueue.h new file mode 100644 index 00000000..84310efc --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/LinkedQueue.h @@ -0,0 +1,41 @@ +#ifndef _LINKEDQUEUE_H_ +#define _LINKEDQUEUE_H_ + +#include <windows.h> + +class LinkedQueue; +class QueueElement; + +class QueueElement { +public: + QueueElement * next; + QueueElement * prev; + void * elem; + QueueElement(void * e) { next=NULL; prev=NULL; elem=e; } +}; + + +class LinkedQueue { +protected: + QueueElement * head; + QueueElement * tail; + QueueElement * bm; + int bmpos; + int size; + QueueElement * Find(int pos); + CRITICAL_SECTION cs; +public: + LinkedQueue(); + ~LinkedQueue(); + int GetSize(); + void Offer(void * e); + void *Poll(); + void *Peek(); + void *Get(int pos); + void Set(int pos, void * val); + void *Del(int pos); + void lock(); + void unlock(); +}; + +#endif //_LINKEDQUEUE_H_
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/api__ml_transcode.h b/Src/Plugins/Library/ml_transcode/api__ml_transcode.h new file mode 100644 index 00000000..07a944bc --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/api__ml_transcode.h @@ -0,0 +1,26 @@ +#ifndef NULLSOFT_ML_TRANSCODE_API_H +#define NULLSOFT_ML_TRANSCODE_API_H + +#include <api/application/api_application.h> +extern api_application *applicationApi; +#define WASABI_API_APP applicationApi + +#include "../Agave/Metadata/api_metadata.h" +extern api_metadata *metadataApi; +#define AGAVE_API_METADATA metadataApi + +#include "../playlist/api_playlistmanager.h" +extern api_playlistmanager *playlistManager; +#define AGAVE_API_PLAYLISTMANAGER playlistManager + +#include "../Agave/AlbumArt/api_albumart.h" +extern api_albumart *albumArtApi; +#define AGAVE_API_ALBUMART albumArtApi + +#include "../Agave/Language/api_language.h" + +#include "../Winamp/api_stats.h" +extern api_stats *statsApi; +#define AGAVE_API_STATS statsApi + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/main.cpp b/Src/Plugins/Library/ml_transcode/main.cpp new file mode 100644 index 00000000..e0f0c457 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/main.cpp @@ -0,0 +1,1100 @@ +#define PLUGIN_VERSION L"2.79" + +#include <windows.h> +#include <windowsx.h> +#include <stdio.h> +#include <shlwapi.h> +#include <shlobj.h> +#include "..\..\General\gen_ml/ml.h" +#include "../winamp/wa_ipc.h" +#include "../nu/AutoWide.h" +#include "../nu/ns_wc.h" +#include "../nu/AutoChar.h" +#include "..\..\General\gen_ml/itemlist.h" +#include "../playlist/ifc_playlistloadercallback.h" +#include "LinkedQueue.h" +#include "resource.h" +#include <vector> +#include <api/service/waServiceFactory.h> + +#include "api__ml_transcode.h" + +#include <strsafe.h> +#define WM_TRANSCODE_START WM_APP+1 +#define WM_TRANSCODE_ADD WM_APP+10 +#define WM_TRANSCODE_UPDATEUI WM_APP+11 +#define WM_TRANSCODE_ABORT WM_APP+12 + +static int init(); +static void quit(); +static HWND GetDialogBoxParent(); +static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3); + +extern "C" winampMediaLibraryPlugin plugin = +{ + MLHDR_VER, + "nullsoft(ml_transcode.dll)", + init, + quit, + PluginMessageProc, + 0, + 0, + 0, +}; +typedef std::vector<const wchar_t*> PtrListWCharPtr; +LinkedQueue transcodeQueue; + +int transcodeConfig(HWND parent); // returns fourcc + +void transcode(const itemRecordListW *ice, HWND parent); +void transcode(PtrListWCharPtr &filenames, HWND parent); + +void addTrackToTranscodeQueue(itemRecordW *track, unsigned int format, const wchar_t* dest, const wchar_t* folder); +void addTrackToTranscodeQueue(const wchar_t *track, unsigned int format, const wchar_t* dest, const wchar_t* folder); + +void filenameToItemRecord(const wchar_t *file, itemRecordW *ice); +void copyTags(const itemRecordW *in, const wchar_t *out); + +extern void RecursiveCreateDirectory(wchar_t *buf1); +extern wchar_t *FixReplacementVars(wchar_t *str, size_t str_size, itemRecordW *song); +void FixFileLength(wchar_t *str); + +HWND transcoderWnd = NULL; + +wchar_t inifile[MAX_PATH] = {0}; +char inifileA[MAX_PATH] = {0}; + +// wasabi based services for localisation support +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; +api_metadata *AGAVE_API_METADATA=0; +api_application *WASABI_API_APP=0; +api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0; +api_albumart *AGAVE_API_ALBUMART = 0; +api_stats *AGAVE_API_STATS = 0; + +template <class api_T> +void ServiceBuild(api_T *&api_t, GUID factoryGUID_t) +{ + if (plugin.service) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t); + if (factory) + api_t = reinterpret_cast<api_T *>( factory->getInterface() ); + } +} + +template <class api_T> +void ServiceRelease(api_T *api_t, GUID factoryGUID_t) +{ + if (plugin.service && api_t) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t); + if (factory) + factory->releaseInterface(api_t); + } + api_t = NULL; +} + +int init() +{ + ServiceBuild(WASABI_API_APP, applicationApiServiceGuid); + ServiceBuild(WASABI_API_LNG, languageApiGUID); + ServiceBuild(AGAVE_API_METADATA, api_metadataGUID); + ServiceBuild(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID); + ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID); + ServiceBuild(AGAVE_API_STATS, AnonymousStatsGUID); + + const wchar_t *iniDirectory = WASABI_API_APP->path_getUserSettingsPath(); + PathCombine(inifile, iniDirectory, L"Plugins\\ml\\ml_transcode.ini"); + lstrcpynA(inifileA, AutoChar(inifile), MAX_PATH); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(plugin.hDllInstance,MlTranscodeLangGUID); + + static wchar_t szDescription[256]; + StringCchPrintfW( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_NULLSOFT_FORMAT_CONVERTER ), PLUGIN_VERSION ); + + plugin.description = (char*)szDescription; + + return ML_INIT_SUCCESS; +} + +void quit() +{ + if(IsWindow(transcoderWnd)) + SendMessage(transcoderWnd,WM_TRANSCODE_ABORT,0,0); + + ServiceRelease(WASABI_API_APP, applicationApiServiceGuid); + ServiceRelease(WASABI_API_LNG, languageApiGUID); + ServiceRelease(AGAVE_API_METADATA, api_metadataGUID); + ServiceRelease(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID); + ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID); + ServiceRelease(AGAVE_API_STATS, AnonymousStatsGUID); +} + +class TranscodePlaylistLoader : public ifc_playlistloadercallback +{ +public: + TranscodePlaylistLoader(PtrListWCharPtr*_fileList); + void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info); + +protected: + PtrListWCharPtr*fileList; + RECVS_DISPATCH; +}; + +TranscodePlaylistLoader::TranscodePlaylistLoader(PtrListWCharPtr*_fileList) +{ + fileList = _fileList; +} + +void TranscodePlaylistLoader::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info) +{ + fileList->push_back(_wcsdup(filename)); +} + +#define CBCLASS TranscodePlaylistLoader +START_DISPATCH; +VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile) +END_DISPATCH; +#undef CBCLASS + + +INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3) +{ + if (message_type == ML_MSG_ONSENDTOBUILD) + { + if (param1 == ML_TYPE_ITEMRECORDLIST || param1 == ML_TYPE_FILENAMES || + param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_FILENAMESW + || (AGAVE_API_PLAYLISTMANAGER && (param1 == ML_TYPE_PLAYLIST || param1 == ML_TYPE_PLAYLISTS))) + { + mlAddToSendToStructW s; + s.context=param2; + s.desc=WASABI_API_LNGSTRINGW(IDS_FORMAT_CONVERTER); + s.user32=(intptr_t)PluginMessageProc; + SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_ADDTOSENDTOW); + } + } + else if (message_type == ML_MSG_ONSENDTOSELECT) + { + if (param2 && param3 == (INT_PTR)PluginMessageProc) + { + if(param1 == ML_TYPE_FILENAMES) + { + PtrListWCharPtr fileList; + TranscodePlaylistLoader loader(&fileList); + const char * filenames = (const char *)param2; + while(filenames && *filenames) + { + // try to load as playlist first + if (AGAVE_API_PLAYLISTMANAGER->Load(AutoWide(filenames), &loader) != PLAYLISTMANAGER_SUCCESS) + { + // not a playlist.. just add it directly + fileList.push_back(AutoWideDup(filenames)); + } + filenames+=strlen(filenames)+1; + } + transcode(fileList,GetDialogBoxParent()); + + //fileList.freeAll(); + for (auto file : fileList) + { + free((void*)file); + } + fileList.clear(); + + return 1; + } + else if(param1 == ML_TYPE_FILENAMESW) + { + PtrListWCharPtr fileList; + TranscodePlaylistLoader loader(&fileList); + const wchar_t * filenames = (const wchar_t *)param2; + while(filenames && *filenames) + { + // try to load as playlist first + if (AGAVE_API_PLAYLISTMANAGER->Load(filenames, &loader) != PLAYLISTMANAGER_SUCCESS) + { + // not a playlist.. just add it directly + fileList.push_back(filenames); + } + filenames+=wcslen(filenames)+1; + } + transcode(fileList,GetDialogBoxParent()); + return 1; + } + else if(param1 == ML_TYPE_ITEMRECORDLIST) + { + const itemRecordList *ico=(const itemRecordList*)param2; + itemRecordListW list = {0,}; + convertRecordList(&list, ico); + transcode(&list, GetDialogBoxParent()); + freeRecordList(&list); + return 1; + } + else if(param1 == ML_TYPE_ITEMRECORDLISTW) + { + const itemRecordListW *list =(const itemRecordListW*)param2; + transcode(list,GetDialogBoxParent()); + return 1; + } + else if (param1 == ML_TYPE_PLAYLIST) + { + mlPlaylist *playlist = (mlPlaylist *)param2; + PtrListWCharPtr fileList; + fileList.reserve(playlist->numItems); + TranscodePlaylistLoader loader(&fileList); + AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader); + transcode(fileList,GetDialogBoxParent()); + + //fileList.freeAll(); + for (auto file : fileList) + { + free((void*)file); + } + fileList.clear(); + + return 1; + } + else if (param1 == ML_TYPE_PLAYLISTS) + { + mlPlaylist **playlists = (mlPlaylist **)param2; + PtrListWCharPtr fileList; + while (playlists && *playlists) + { + mlPlaylist *playlist = *playlists; + fileList.reserve(fileList.size() + playlist->numItems); + TranscodePlaylistLoader loader(&fileList); + AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader); + playlists++; + } + transcode(fileList,GetDialogBoxParent()); + + //fileList.freeAll(); + for (auto file : fileList) + { + free((void*)file); + } + fileList.clear(); + + return 1; + } + } + } + else if (message_type == ML_MSG_CONFIG) + { + transcodeConfig((HWND)param1); + return 1; + } + return 0; +} + +class TranscodeItem +{ + public: + itemRecordW ice; + unsigned int fourcc; + wchar_t *outfile; + TranscodeItem( unsigned int fourcc, const wchar_t *folder, const wchar_t *outfile, const itemRecordW *i ) : fourcc( fourcc ) + { + ZeroMemory( &ice, sizeof( ice ) ); + copyRecord( &ice, const_cast<itemRecordW *>( i ) ); // TODO: remove for 5.53. this just works around some 5.52 build weirdness + makefn( folder, outfile ); + } + TranscodeItem( unsigned int fourcc, const wchar_t *folder, const wchar_t *outfile, const wchar_t *i ) : fourcc( fourcc ) + { + ZeroMemory( &ice, sizeof( ice ) ); + filenameToItemRecord( i, &ice ); + makefn( folder, outfile ); + } + void makefn( const wchar_t *folder, const wchar_t *outfile ) + { + if ( GetPrivateProfileInt( L"transcoder", L"usefilename", 0, inifile ) ) + { + size_t len = wcslen( ice.filename ) + 10; + this->outfile = (wchar_t *)calloc( len, sizeof( this->outfile[ 0 ] ) ); + StringCchCopyW( this->outfile, len, ice.filename ); + const wchar_t *extn = wcsrchr( outfile, L'.' ); + wchar_t *exto = wcsrchr( this->outfile, L'.' ); + if ( extn && exto && wcslen( extn ) < 10 ) + StringCchCopy( exto, len, extn ); + } + else + { + wchar_t filename[ 2048 ] = { 0 }; + StringCchCopy( filename, 2048, outfile ); + FixReplacementVars( filename, 2048, &ice ); + FixFileLength( filename ); + PathCombine( filename, folder, filename ); + this->outfile = _wcsdup( filename ); + } + } + ~TranscodeItem() + { + free( outfile ); freeRecord( &ice ); + } +}; + +void getViewport( RECT *r, HWND wnd, int full, RECT *sr ) +{ + POINT *p = NULL; + if ( p || sr || wnd ) + { + HMONITOR hm = NULL; + + if ( sr ) + hm = MonitorFromRect( sr, MONITOR_DEFAULTTONEAREST ); + else if ( wnd ) + hm = MonitorFromWindow( wnd, MONITOR_DEFAULTTONEAREST ); + else if ( p ) + hm = MonitorFromPoint( *p, MONITOR_DEFAULTTONEAREST ); + + if ( hm ) + { + MONITORINFOEX mi; + memset( &mi, 0, sizeof( mi ) ); + mi.cbSize = sizeof( mi ); + + if ( GetMonitorInfoW( hm, &mi ) ) + { + if ( !full ) + *r = mi.rcWork; + else + *r = mi.rcMonitor; + + return; + } + } + } + + if ( full ) + { // this might be borked =) + r->top = r->left = 0; + r->right = GetSystemMetrics( SM_CXSCREEN ); + r->bottom = GetSystemMetrics( SM_CYSCREEN ); + } + else + { + SystemParametersInfoW( SPI_GETWORKAREA, 0, r, 0 ); + } +} + +BOOL windowOffScreen( HWND hwnd, POINT pt ) +{ + RECT r = { 0 }, wnd = { 0 }, sr = { 0 }; + + GetWindowRect( hwnd, &wnd ); + sr.left = pt.x; + sr.top = pt.y; + sr.right = sr.left + ( wnd.right - wnd.left ); + sr.bottom = sr.top + ( wnd.bottom - wnd.top ); + + getViewport( &r, hwnd, 0, &sr ); + + return !PtInRect( &r, pt ); +} + +bool transcoding = false; +bool transcoderIdle = false; +int totalItems = 0; +int itemsDone = 0; +int itemsFailed = 0; + +static BOOL CALLBACK transcode_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + static convertFileStructW * cfs; + switch(uMsg) + { + case WM_INITDIALOG: + { + transcoderWnd = hwndDlg; + cfs = (convertFileStructW *)calloc(1, sizeof(convertFileStructW)); + SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETRANGE32,0,100); + SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETRANGE32,0,totalItems*100); + SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,0,0); + SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,0,0); + PostMessage(hwndDlg,WM_TRANSCODE_START,0,0); + + // show edit info window and restore last position as applicable + POINT pt = {GetPrivateProfileInt(L"transcoder", L"convert_x", -1, inifile), + GetPrivateProfileInt(L"transcoder", L"convert_y", -1, inifile)}; + if (!windowOffScreen(hwndDlg, pt)) + SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING); + else + ShowWindow(hwndDlg, SW_SHOWNA); + } + break; + case WM_TRANSCODE_START: + for(;;) + { + TranscodeItem * t = (TranscodeItem *)transcodeQueue.Peek(); + if(!t) + { + SetDlgItemText(hwndDlg,IDC_ABORT,WASABI_API_LNGSTRINGW(IDS_DONE)); + SendMessage(transcoderWnd,WM_TRANSCODE_UPDATEUI,0,0); + transcoderIdle=true; + return 0; + } + transcoderIdle=false; + RecursiveCreateDirectory(t->outfile); + ZeroMemory(cfs,sizeof(*cfs)); + cfs->callbackhwnd = hwndDlg; + cfs->sourcefile = t->ice.filename; + cfs->destfile = t->outfile; + cfs->destformat[0] = t->fourcc; + //cfs->destformat[1] = 44100; + //cfs->destformat[2] = 16; + //cfs->destformat[3] = 2; + cfs->destformat[6] = mmioFOURCC('I','N','I',' '); + cfs->destformat[7] = (intptr_t)inifileA; + cfs->error = L""; + + SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,0,0); + wchar_t buf[1024] = {0}; + StringCchPrintf(buf, 1024, L"%s - %s", t->ice.artist?t->ice.artist:L"", t->ice.title?t->ice.title:L""); + SetDlgItemText(hwndDlg,IDC_CURRENTTRACK,buf); + + if(SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW)) break; + else + { + if (cfs->error && *cfs->error) + { + MessageBox(hwndDlg, cfs->error, WASABI_API_LNGSTRINGW(IDS_TRANSCODING_FAILED), MB_ICONWARNING | MB_OK); + } + delete (TranscodeItem*)transcodeQueue.Poll(); + itemsDone++; itemsFailed++; + } + } + case WM_TRANSCODE_ADD: // update totals, stuff added to queue + SetWindowPos(hwndDlg,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); + if(transcoderIdle) + { + SetDlgItemText(hwndDlg,IDC_ABORT,WASABI_API_LNGSTRINGW(IDS_ABORT)); + SendMessage(hwndDlg,WM_TRANSCODE_START,0,0); + return 0; + } // else update UI + case WM_TRANSCODE_UPDATEUI: + { + SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETRANGE32,0,totalItems*100); + SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,itemsDone*100,0); + wchar_t buf[100] = {0}; + StringCchPrintfW(buf, 100, WASABI_API_LNGSTRINGW(IDS_TRACKS_DONE_REMAINING_FAILED), + itemsDone-itemsFailed, totalItems-itemsDone, itemsFailed); + SetDlgItemText(hwndDlg,IDC_TOTALCAPTION,buf); + } + break; + case WM_WA_IPC: + switch(lParam) + { + case IPC_CB_CONVERT_STATUS: + if(wParam >= 0 && wParam <= 100) + { + SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,(int)wParam + itemsDone*100,0); + SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,(int)wParam,0); + } + break; + case IPC_CB_CONVERT_DONE: + { + SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,100,0); + TranscodeItem * t = (TranscodeItem*)transcodeQueue.Poll(); + itemsDone++; + cfs->callbackhwnd=NULL; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW_END); + copyTags(&t->ice,t->outfile); + if (AGAVE_API_STATS) + { + AGAVE_API_STATS->IncrementStat(api_stats::TRANSCODE_COUNT); + AGAVE_API_STATS->SetStat(api_stats::TRANSCODE_FORMAT, t->fourcc); + } + delete t; + PostMessage(hwndDlg,WM_TRANSCODE_START,0,0); + } + break; + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_ABORT: + transcode_dlgproc(hwndDlg,WM_TRANSCODE_ABORT,0,0); + break; + } + break; + case WM_CLOSE: + case WM_TRANSCODE_ABORT: + { + transcoding = false; + cfs->callbackhwnd = NULL; + if(!transcoderIdle) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW_END); + TranscodeItem * t; + while((t = (TranscodeItem*)transcodeQueue.Poll()) != NULL) + { + // prompt to delete incomplete conversions + if(PathFileExists(t->outfile)) + { + wchar_t title[64] = {0}, prompt[512] = {0}, file[MAX_PATH] = {0}; + lstrcpyn(file, t->outfile, MAX_PATH); + PathStripPath(file); + StringCchPrintf(prompt, 512, WASABI_API_LNGSTRINGW(IDS_REMOVE_PARTIAL_FILE), file); + if(MessageBox(hwndDlg, prompt, + WASABI_API_LNGSTRINGW_BUF(IDS_TRANSCODING_ABORTED, title, 64), MB_YESNO) == IDYES) + { + DeleteFile(t->outfile); + } + } + delete t; + } + + RECT rect = {0}; + GetWindowRect(hwndDlg, &rect); + wchar_t buf[16] = {0}; + StringCchPrintf(buf, 16, L"%d", rect.left); + WritePrivateProfileString(L"transcoder", L"convert_x", buf, inifile); + StringCchPrintf(buf, 16, L"%d", rect.top); + WritePrivateProfileString(L"transcoder", L"convert_y", buf, inifile); + + EndDialog(hwndDlg,0); + itemsDone = 0; + totalItems = 0; + itemsFailed = 0; + transcoderWnd = NULL; + transcoding = false; + transcoderIdle = false; + free(cfs); + } + break; + } + return 0; +} + +void startTranscoding() +{ + if(transcoding) + { + totalItems++; + SendMessage(transcoderWnd,WM_TRANSCODE_ADD,0,0); + } + else + { + transcoding = true; + totalItems=1; + WASABI_API_CREATEDIALOGW(IDD_TRANSCODE, NULL, transcode_dlgproc); + } +} + +void addTrackToTranscodeQueue(const wchar_t * track, unsigned int format, const wchar_t* filepart, const wchar_t* folder) +{ + transcodeQueue.Offer(new TranscodeItem(format, folder, filepart, track)); + startTranscoding(); +} + +void addTrackToTranscodeQueue(itemRecordW * track, unsigned int format, const wchar_t* filepart, const wchar_t* folder) +{ + transcodeQueue.Offer(new TranscodeItem(format, folder, filepart, track)); + startTranscoding(); +} + +static void fourccToString(unsigned int f, wchar_t * str, int str_len) +{ + char s[4] = {(char)(f&0xFF),(char)((f>>8)&0xFF),(char)((f>>16)&0xFF),0}; + StringCchCopy(str, str_len, AutoWide(s)); + CharLower(str); +} + +wchar_t* GetDefaultSaveToFolder(wchar_t* path_to_store) +{ + if(FAILED(SHGetFolderPath(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store))) + { + if(FAILED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store))) + { + // and if that all fails then do a reasonable default + lstrcpyn(path_to_store, L"C:\\My Music", MAX_PATH); + } + // if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music + else + { + PathCombine(path_to_store, path_to_store, L"My Music"); + } + } + return path_to_store; +} + +DWORD GetPrivateProfileStringUTF8(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName) +{ + char utf8_text[2048] = {0}; + GetPrivateProfileStringA(lpAppName,lpKeyName,lpDefault,utf8_text, 2048, lpFileName); + + return MultiByteToWideCharSZ(CP_UTF8, 0, utf8_text, -1, lpReturnedString, nSize); +} + +BOOL WritePrivateProfileStringUTF8(LPCSTR lpAppName, LPCSTR lpKeyName, LPCTSTR lpString, LPCSTR lpFileName) +{ + return WritePrivateProfileStringA(lpAppName, lpKeyName, AutoChar(lpString, CP_UTF8), lpFileName); +} + +class EncodableFormat +{ +public: + unsigned int fourcc; + wchar_t *desc; + EncodableFormat(unsigned int fourcc,wchar_t *desc) : + fourcc(fourcc) {this->desc = _wcsdup(desc);} + ~EncodableFormat() {free(desc);} +}; + +static void enumProc(intptr_t user_data, const char *desc, int fourcc) { + ((C_ItemList*)user_data)->Add(new EncodableFormat((unsigned int)fourcc,AutoWide(desc))); +} + +static void BuildEncodableFormatsList(C_ItemList * list, HWND winampWindow,wchar_t * inifile) { + converterEnumFmtStruct e = {enumProc,(intptr_t)list}; + SendMessage(winampWindow,WM_WA_IPC,(WPARAM)&e,IPC_CONVERT_CONFIG_ENUMFMTS); +} + +unsigned int transcodeGatherSettings(wchar_t *format, wchar_t *folder, int format_len, HWND parent) +{ + if(GetPrivateProfileInt(L"transcoder",L"showconf",1,inifile)) + if(!transcodeConfig(parent)) + return 0; + + wchar_t tmp[MAX_PATH] = {0}; + GetPrivateProfileStringUTF8("transcoder", "fileformat","<Artist> - <Album>\\## - <Title>",format,1024,inifileA); + GetPrivateProfileStringUTF8("transcoder", "fileroot", AutoChar(GetDefaultSaveToFolder(tmp), CP_UTF8), folder, MAX_PATH, inifileA); + + unsigned int fourcc = GetPrivateProfileInt(L"transcoder",L"format",mmioFOURCC('A','A','C','f'),inifile); + + char extA[8]="."; + convertConfigItem c = {fourcc,"extension",&extA[1],7,inifileA}; + if(!SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&c,IPC_CONVERT_CONFIG_GET_ITEM)) + { + // if there was an error, see if it's from an invalid fourcc and try to fallback + C_ItemList * formats = new C_ItemList; + BuildEncodableFormatsList(formats,plugin.hwndWinampParent,inifile); + bool doFail = false; + + for(int i=0; i < formats->GetSize(); i++) { + EncodableFormat * f = (EncodableFormat *)formats->Get(i); + // if it exists then abort and fail as prior behaviour + if(f->fourcc == fourcc) + { + doFail = true; + break; + } + } + if(!doFail) + { + fourcc = mmioFOURCC('A','A','C','f'); + c.format = fourcc; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&c,IPC_CONVERT_CONFIG_GET_ITEM); + } + } + if(extA[1]) StringCchCat(format, format_len, AutoWide(extA)); + else + { + wchar_t ext[8]=L"."; + fourccToString(fourcc,&ext[1], 8); + StringCchCat(format, format_len, ext); + } + return fourcc; +} + +void transcode( PtrListWCharPtr &filenames, HWND parent ) +{ + wchar_t format[ 2048 ] = { 0 }, folder[ MAX_PATH ] = { 0 }; + unsigned int fourcc = transcodeGatherSettings( format, folder, 2048, parent ); + + if ( !fourcc ) + return; + + for ( const wchar_t *l_filename : filenames ) + addTrackToTranscodeQueue( l_filename, fourcc, format, folder ); +} + +void transcode(const itemRecordListW *ice, HWND parent) +{ + wchar_t format[2048] = {0}, folder[MAX_PATH] = {0}; + unsigned int fourcc = transcodeGatherSettings(format, folder, 2048, parent); + if(!fourcc) return; + + for(int i=0; i < ice->Size; i++) { + addTrackToTranscodeQueue(&ice->Items[i],fourcc,format,folder); + } +} + +static void FreeEncodableFormatsList(C_ItemList * list) { + int l = list->GetSize(); + while(--l >= 0) { + delete ((EncodableFormat*)list->Get(l)); + list->Del(l); + } +} + +static void doConfigResizeChild(HWND parent, HWND child) { + if (child) { + RECT r; + GetWindowRect(GetDlgItem(parent, IDC_ENC_CONFIG), &r); + ScreenToClient(parent, (LPPOINT)&r); + SetWindowPos(child, 0, r.left, r.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); + ShowWindow(child, SW_SHOW); + } +} + +BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam) +{ + wchar_t cl[32] = {0}; + GetClassNameW(hwnd, cl, ARRAYSIZE(cl)); + if (!lstrcmpiW(cl, WC_TREEVIEW)) + { + PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd)); + return FALSE; + } + + return TRUE; +} + +int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if(uMsg == BFFM_INITIALIZED) + { + wchar_t buf[4096]=L""; + GetDlgItemText((HWND)lpData,IDC_ROOTDIR,buf,sizeof(buf)/sizeof(wchar_t)); + SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)buf); + SetWindowText(hwnd,WASABI_API_LNGSTRINGW(IDS_SELECT_WHERE_TO_SAVE)); + + // this is not nice but it fixes the selection not working correctly on all OSes + EnumChildWindows(hwnd, browseEnumProc, 0); + } + return 0; +} + +static BOOL CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + static C_ItemList * formats; + static convertConfigStruct * ccs; + switch (uMsg) + { + case WM_INITDIALOG: + { + bool usefn = !!GetPrivateProfileInt(L"transcoder", L"usefilename",0,inifile); + if(GetPrivateProfileInt(L"transcoder", L"showconf", 1, inifile)) CheckDlgButton(hwndDlg,IDC_SHOWEVERY,BST_CHECKED); + if(usefn) CheckDlgButton(hwndDlg,IDC_USE_FILENAME,BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_ROOTDIR),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_NAMING),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_FORMATHELP),!usefn); + + wchar_t buf[4096]=L"", tmp[MAX_PATH]=L""; + GetPrivateProfileStringUTF8("transcoder", "fileformat","<Artist> - <Album>\\## - <Title>",buf,4096,inifileA); + SetDlgItemText(hwndDlg,IDC_NAMING,buf); + + GetPrivateProfileStringUTF8("transcoder", "fileroot", AutoChar(GetDefaultSaveToFolder(tmp), CP_UTF8), buf, 4096, inifileA); + SetDlgItemText(hwndDlg,IDC_ROOTDIR,buf); + formats = new C_ItemList; + BuildEncodableFormatsList(formats,plugin.hwndWinampParent,inifile); + + ccs = (convertConfigStruct *)calloc(sizeof(convertConfigStruct),1); + ccs->extra_data[6] = mmioFOURCC('I','N','I',' '); + ccs->extra_data[7] = (int)inifileA; + ccs->hwndParent = hwndDlg; + ccs->format = GetPrivateProfileInt(L"transcoder",L"format",mmioFOURCC('A','A','C','f'),inifile); + + for(int i=0; i < formats->GetSize(); i++) { + EncodableFormat * f = (EncodableFormat *)formats->Get(i); + int a = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_ADDSTRING, 0, (LPARAM)f->desc); + SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETITEMDATA, (WPARAM)a, (LPARAM)f); + + if(f->fourcc == ccs->format) + SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, (WPARAM)a, 0); + } + + // if there is no selection then force things to the correct default + if(SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, (WPARAM)0, 0) == CB_ERR) { + for(int i=0; i < SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCOUNT, 0, 0); i++) { + EncodableFormat * f = (EncodableFormat *)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, (WPARAM)i, 0); + if(f->fourcc == mmioFOURCC('A','A','C','f')) { + ccs->format = f->fourcc; + SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, (WPARAM)i, 0); + break; + } + } + } + + HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG); + doConfigResizeChild(hwndDlg, h); + + // show config window and restore last position as applicable + POINT pt = {GetPrivateProfileInt(L"transcoder", L"showconf_x", -1, inifile), + GetPrivateProfileInt(L"transcoder", L"showconf_y", -1, inifile)}; + if (!windowOffScreen(hwndDlg, pt)) + SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING); + } + break; + + case WM_DESTROY: + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG_END); + free(ccs); ccs=0; + FreeEncodableFormatsList(formats); + delete formats; formats=0; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_USE_FILENAME: + { + bool usefn = IsDlgButtonChecked(hwndDlg,IDC_USE_FILENAME)!=0; + EnableWindow(GetDlgItem(hwndDlg, IDC_ROOTDIR),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_NAMING),!usefn); + EnableWindow(GetDlgItem(hwndDlg, IDC_FORMATHELP),!usefn); + } + break; + + case IDC_ENCFORMAT: + if (HIWORD(wParam) != CBN_SELCHANGE) return 0; + { + int sel = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG_END); + EncodableFormat * f = (EncodableFormat *)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, sel, 0); + ccs->format = f->fourcc; + HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG); + doConfigResizeChild(hwndDlg, h); + } + } + break; + + case IDC_FORMATHELP: + { + wchar_t titleStr[64] = {0}; + MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_FILENAME_FORMAT_HELP), + WASABI_API_LNGSTRINGW_BUF(IDS_FILENAME_FORMAT_HELP_TITLE,titleStr,64), MB_OK); + break; + } + + case IDC_BROWSE: + { + BROWSEINFO bi = {0}; + LPMALLOC lpm = 0; + wchar_t bffFileName[MAX_PATH] = {0}; + bi.hwndOwner = hwndDlg; + bi.pszDisplayName = bffFileName; + bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_FOLDER); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM)hwndDlg; + LPITEMIDLIST iil = SHBrowseForFolder(&bi); + if(iil) + { + SHGetPathFromIDList(iil,bffFileName); + SHGetMalloc(&lpm); + lpm->Free(iil); + SetDlgItemText(hwndDlg, IDC_ROOTDIR, bffFileName); + } + } + break; + + case IDOK: + case IDCANCEL: + { + DWORD fourcc=0; + if (LOWORD(wParam) == IDOK) + { + wchar_t buf[4096]=L""; + GetDlgItemText(hwndDlg,IDC_NAMING,buf,sizeof(buf)/sizeof(wchar_t)); + WritePrivateProfileStringUTF8("transcoder","fileformat",buf,inifileA); + GetDlgItemText(hwndDlg,IDC_ROOTDIR,buf,sizeof(buf)/sizeof(wchar_t)); + WritePrivateProfileStringUTF8("transcoder","fileroot",buf,inifileA); + WritePrivateProfileString(L"transcoder",L"showconf",IsDlgButtonChecked(hwndDlg,IDC_SHOWEVERY)?L"1":L"0",inifile); + WritePrivateProfileString(L"transcoder",L"usefilename",IsDlgButtonChecked(hwndDlg,IDC_USE_FILENAME)?L"1":L"0",inifile); + + LRESULT esel = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, 0, 0); + if (esel!=CB_ERR) + { + LRESULT data = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, esel, 0); + if (data != CB_ERR) + { + EncodableFormat * f = (EncodableFormat *)data; + StringCchPrintf(buf, 4096, L"%d", f->fourcc); + WritePrivateProfileString(L"transcoder",L"format",buf,inifile); + fourcc=f->fourcc; + } + } + } + + EndDialog(hwndDlg, (LOWORD(wParam) ? fourcc : 0)); + + RECT rect = {0}; + GetWindowRect(hwndDlg, &rect); + wchar_t buf[16] = {0}; + StringCchPrintf(buf, 16, L"%d", rect.left); + WritePrivateProfileString(L"transcoder", L"showconf_x", buf, inifile); + StringCchPrintf(buf, 16, L"%d", rect.top); + WritePrivateProfileString(L"transcoder", L"showconf_y", buf, inifile); + } + break; + } + break; + } + return 0; +} + +int transcodeConfig(HWND parent) { // returns fourcc + return WASABI_API_DIALOGBOXW(IDD_TRANSCODE_CONFIG, parent, config_dlgproc); +} +// metadata shit + +extern wchar_t *guessTitles(const wchar_t *filename, int *tracknum,wchar_t **artist, wchar_t **album,wchar_t **title); + +#define atoi_NULLOK(s) ((s)?_wtoi(s):0) + +void filenameToItemRecord(const wchar_t *file, itemRecordW * ice) +{ + int gtrack=0; + wchar_t *gartist=NULL,*galbum=NULL,*gtitle=NULL; + wchar_t *guessbuf = guessTitles(file,>rack,&gartist,&galbum,>itle); + if(!gartist) gartist=L""; + if(!galbum) galbum=L""; + if(!gtitle) gtitle=L""; + + wchar_t buf[512] = {0}; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"title", buf, 512); + if(buf[0]) { ice->title=_wcsdup(buf); gartist=L""; galbum=L""; gtrack=-1;} + else ice->title=_wcsdup(gtitle); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"album", buf, 512); + if(buf[0]) ice->album=_wcsdup(buf); + else ice->album=_wcsdup(galbum); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"artist", buf, 512); + if(buf[0]) ice->artist=_wcsdup(buf); + else ice->artist=_wcsdup(gartist); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"albumartist", buf, 512); + if(buf[0]) ice->albumartist=_wcsdup(buf); + else ice->albumartist=_wcsdup(ice->artist); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"track", buf, 512); + if(buf[0]) ice->track=atoi_NULLOK(buf); + else ice->track=gtrack; + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"genre", buf, 512); + ice->genre=_wcsdup(buf); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"comment", buf, 512); + ice->comment=_wcsdup(buf); + + buf[0]=0; + AGAVE_API_METADATA->GetExtendedFileInfo(file, L"year", buf, 512); + ice->year=atoi_NULLOK(buf); + + basicFileInfoStructW b={0}; + b.filename=const_cast<wchar_t *>(file); //benski> changed extendedFileInfoStruct but not basicFileInfoStruct, i'll have to do that later so we can get rid of this cast + b.quickCheck=0; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&b,IPC_GET_BASIC_FILE_INFOW); + ice->length=b.length; + + ice->filename = _wcsdup(file); + free(guessbuf); +} + +void copyTags(const itemRecordW *in, const wchar_t *out) +{ + // check if the old file still exists - if it does, we will let Winamp copy metadata for us + if (wcscmp(in->filename, out) && PathFileExists(in->filename)) + { + copyFileInfoStructW copy; + copy.dest = out; + copy.source = in->filename; + if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)©, IPC_COPY_EXTENDED_FILE_INFOW) == 0) // 0 indicates success here + { + AGAVE_API_ALBUMART->CopyAlbumArt(in->filename, out); + return; + } + } + + wchar_t buf[32] = {0}, file[MAX_PATH] = {0}; + StringCchCopy(file, MAX_PATH, out); + extendedFileInfoStructW e = {0}; + e.filename=file; + + e.metadata=L"album"; + e.ret=in->album; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"artist"; + e.ret=in->artist; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"albumartist"; + e.ret=in->albumartist; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"title"; + e.ret=in->title; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"track"; + StringCchPrintf(buf, 32, L"%d", in->track); + e.ret=buf; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"genre"; + e.ret=in->genre; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + e.metadata=L"comment"; + e.ret=in->comment; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + + if(in->year > 0) + { + e.metadata=L"year"; + StringCchPrintf(buf, 32, L"%d", in->year); + e.ret=buf; + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW); + } + + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_WRITE_EXTENDED_FILE_INFO); +} + +extern "C" { + __declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin() { + return &plugin; + } + + __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) { + // prompt to remove our settings with default as no (just incase) + wchar_t title[256] = {0}; + StringCchPrintf(title, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_FORMAT_CONVERTER), PLUGIN_VERSION); + if(MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS), + title,MB_YESNO|MB_DEFBUTTON2) == IDYES) + { + DeleteFile(inifile); + } + // if not transcoding then can remove on the fly (5.37+) + if(!IsWindow(transcoderWnd)){ + return ML_PLUGIN_UNINSTALL_NOW; + } + // otherwise allow for any prompting/full restart removal (default) + return ML_PLUGIN_UNINSTALL_REBOOT; + } +}; + +static HWND GetDialogBoxParent() +{ + HWND parent = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT); + if (!parent || parent == (HWND)1) + return plugin.hwndWinampParent; + return parent; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/ml_transcode.rc b/Src/Plugins/Library/ml_transcode/ml_transcode.rc new file mode 100644 index 00000000..f18bd888 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/ml_transcode.rc @@ -0,0 +1,162 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_TRANSCODE DIALOGEX 0, 0, 186, 90 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | DS_CENTERMOUSE | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Converting..." +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "",IDC_CURRENTTRACK,7,7,172,8 + CONTROL "",IDC_TRACKPROGRESS,"msctls_progress32",WS_BORDER,7,18,172,14 + LTEXT "",IDC_TOTALCAPTION,7,38,172,8 + CONTROL "",IDC_TOTALPROGRESS,"msctls_progress32",WS_BORDER,7,49,172,14 + PUSHBUTTON "Abort",IDC_ABORT,67,70,50,13 +END + +IDD_TRANSCODE_CONFIG DIALOGEX 0, 0, 271, 319 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Format Converter Configuration" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Output File Naming Scheme",IDC_STATIC,7,4,256,80 + LTEXT "Specify the destination folder to store your converted music:",IDC_STATIC,13,15,231,8,0,WS_EX_TRANSPARENT + EDITTEXT IDC_ROOTDIR,14,26,192,13,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,207,26,50,13 + LTEXT "Specify the naming scheme:",IDC_STATIC,13,42,198,8,0,WS_EX_TRANSPARENT + EDITTEXT IDC_NAMING,14,52,192,13,ES_AUTOHSCROLL + PUSHBUTTON "Format Help",IDC_FORMATHELP,207,52,50,13 + CONTROL "Use old file name and path (just change the extension)",IDC_USE_FILENAME, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,70,219,10 + GROUPBOX "Encoding Format",IDC_STATIC,7,87,256,40 + LTEXT "Select the format you wish to convert to:",IDC_STATIC,13,97,135,8 + COMBOBOX IDC_ENCFORMAT,14,108,243,116,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "",IDC_ENC_CONFIG,7,129,256,169,NOT WS_VISIBLE + CONTROL "Show this before each convert",IDC_SHOWEVERY,"Button",BS_AUTOCHECKBOX | BS_VCENTER | WS_TABSTOP,7,304,140,9 + DEFPUSHBUTTON "Ok",IDOK,159,302,50,13 + PUSHBUTTON "Cancel",IDCANCEL,213,302,50,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_TRANSCODE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 83 + END + + IDD_TRANSCODE_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 4 + BOTTOMMARGIN, 315 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_NULLSOFT_FORMAT_CONVERTER "Nullsoft Format Converter v%s" + 65535 "{699B8BA5-B292-4aba-8047-D46B0DF4E1D6}" +END + +STRINGTABLE +BEGIN + IDS_FORMAT_CONVERTER "Format Converter" + IDS_DONE "Done" + IDS_TRANSCODING_FAILED "Transcoding Failed" + IDS_ABORT "Abort" + IDS_TRACKS_DONE_REMAINING_FAILED + "%d tracks done, %d tracks remaining, %d failed" + IDS_FILENAME_FORMAT_HELP + "You may enter a filename format string for your copied files.\nIt can contain \\ or / to delimit a path, and the following keywords:\n\n<Artist> - inserts the artist with the default capitalization\n<ARTIST> - inserts the artist in all uppercase\n<artist> - inserts the artist in all lowercase\n<Albumartist>/<ALBUMARTIST>/<albumartist> - inserts the album artist\n<Album>/<ALBUM>/<album> - inserts the album\n<year> - inserts the album year\n<Genre>/<GENRE>/<genre> - inserts the album genre\n<Title>/<TITLE>/<title> - inserts the track title\n#, ##, ### - inserts the track number, with leading 0s if ## or ###\n<filename> - uses the old filename of the file (not the full path)\n<disc> - inserts the disc number\n<discs> - inserts the total discs number (e.g. CD<disc> of <discs>)" + IDS_FILENAME_FORMAT_HELP_TITLE "Filename format help" + IDS_CHOOSE_FOLDER "Choose a folder or create a new one" + IDS_SELECT_WHERE_TO_SAVE "Choose where to save converted files" + IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS + "Do you also want to remove the saved settings file for this plug-in?" + IDS_TRANSCODING_ABORTED "Transcoding Aborted" + IDS_REMOVE_PARTIAL_FILE "Do you want to remove the partially transcoded file\n '%s' or keep it?\n\n(Note: it is likely to be invalid and not play correctly)" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Plugins/Library/ml_transcode/ml_transcode.sln b/Src/Plugins/Library/ml_transcode/ml_transcode.sln new file mode 100644 index 00000000..6559eb11 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/ml_transcode.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ml_transcode", "ml_transcode.vcxproj", "{B9933E53-426C-4603-BE06-672059143A27}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B9933E53-426C-4603-BE06-672059143A27}.Debug|Win32.ActiveCfg = Debug|Win32 + {B9933E53-426C-4603-BE06-672059143A27}.Debug|Win32.Build.0 = Debug|Win32 + {B9933E53-426C-4603-BE06-672059143A27}.Debug|x64.ActiveCfg = Debug|x64 + {B9933E53-426C-4603-BE06-672059143A27}.Debug|x64.Build.0 = Debug|x64 + {B9933E53-426C-4603-BE06-672059143A27}.Release|Win32.ActiveCfg = Release|Win32 + {B9933E53-426C-4603-BE06-672059143A27}.Release|Win32.Build.0 = Release|Win32 + {B9933E53-426C-4603-BE06-672059143A27}.Release|x64.ActiveCfg = Release|x64 + {B9933E53-426C-4603-BE06-672059143A27}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B5FE8422-686F-47D5-A186-D3E42F8236F4} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj b/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj new file mode 100644 index 00000000..e41d528d --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj @@ -0,0 +1,333 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{B9933E53-426C-4603-BE06-672059143A27}</ProjectGuid> + <RootNamespace>ml_transcode</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>false</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <GenerateMapFile>false</GenerateMapFile> + <MapExports>false</MapExports> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + <MapFileName>$(IntDir)$(TargetName).map</MapFileName> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4244;4302;4311;4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <GenerateMapFile>false</GenerateMapFile> + <MapExports>false</MapExports> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + <MapFileName>$(IntDir)$(TargetName).map</MapFileName> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <MapFileName>$(IntDir)$(TargetName).map</MapFileName> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4244;4302;4311;4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <MapFileName>$(IntDir)$(TargetName).map</MapFileName> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ModuleDefinitionFile> + </ModuleDefinitionFile> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\..\General\gen_ml\itemlist.h" /> + <ClInclude Include="..\..\General\gen_ml\ml.h" /> + <ClInclude Include="..\..\..\nu\AutoChar.h" /> + <ClInclude Include="..\..\..\nu\AutoWide.h" /> + <ClInclude Include="..\..\..\Winamp\wa_ipc.h" /> + <ClInclude Include="api__ml_transcode.h" /> + <ClInclude Include="LinkedQueue.h" /> + <ClInclude Include="resource.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\General\gen_ml\itemlist.cpp" /> + <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" /> + <ClCompile Include="..\ml_local\guess.cpp" /> + <ClCompile Include="LinkedQueue.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="replaceVars.cpp" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="ml_transcode.rc" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj.filters b/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj.filters new file mode 100644 index 00000000..a8481226 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj.filters @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="..\ml_local\guess.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="LinkedQueue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="replaceVars.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\itemlist.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__ml_transcode.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="LinkedQueue.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nu\AutoChar.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nu\AutoWide.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\General\gen_ml\itemlist.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\General\gen_ml\ml.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\Winamp\wa_ipc.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{dad8753a-63ad-4940-b004-ee080d154ba8}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{9eded93f-4358-4590-b654-608fc1d13764}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{56b6e7a2-f5f3-4b8d-a042-b3bf2cd8b7dd}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="ml_transcode.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/replaceVars.cpp b/Src/Plugins/Library/ml_transcode/replaceVars.cpp new file mode 100644 index 00000000..6a6ce53b --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/replaceVars.cpp @@ -0,0 +1,317 @@ +#include <windows.h> +#include <ctype.h> +#include <string.h> +#include "..\..\General\gen_ml/ml.h" + +#include <shlwapi.h> +#include <strsafe.h> + +static void removebadchars(wchar_t *s, wchar_t *&end, size_t &str_size) +{ + const wchar_t *start = s; + while (s && *s) + { + if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|') + *s = L'_'; + s = CharNextW(s); + } + + // cut off trailing periods + if (s != start) + { + do + { + s--; + if (*s == '.') + { + *s = '_'; + end--; + str_size++; + } + else + break; + } + while (s != start); + } +} + +void RecursiveCreateDirectory(wchar_t *str) +{ + wchar_t *p = str; + if ((p[0] ==L'\\' || p[0] ==L'/') && (p[1] ==L'\\' || p[1] ==L'/')) + { + p += 2; + while (p &&*p && *p !=L'\\' && *p !=L'/') p++; + if (!p || !*p) return ; + p++; + while (p && *p && *p !=L'\\' && *p !=L'/') p++; + } + else + { + while (p && *p && *p !=L'\\' && *p !=L'/') p++; + } + + while (p && *p) + { + while (p && *p && *p !=L'\\' && *p !=L'/') p = CharNextW(p); + if (p && *p) + { + wchar_t lp = *p; + *p = 0; + CreateDirectoryW(str, NULL); + *p++ = lp; + } + } +} + +void FixFileLength(wchar_t *str) +{ + size_t len = wcslen(str); + if (len >= MAX_PATH) // no good + { + size_t extensionPosition=len; + while (extensionPosition--) + { + if (str[extensionPosition]=='.' || str[extensionPosition] == '/' || str[extensionPosition] == '\\') + break; + } + if (str[extensionPosition]=='.') // found an extension? good, let's relocate it + { + ptrdiff_t diff = len - extensionPosition; + diff++; + while (diff) + { + str[MAX_PATH-diff]=str[len-diff+1]; + diff--; + } + } + str[MAX_PATH-1]=0; + } +} + +static void ADD_STR(const wchar_t *x, wchar_t *&outp, size_t &str_size) +{ + wchar_t *end = outp; + StringCchCopyExW(outp, str_size, (x) ? (x) : L"", &end, &str_size, 0); + removebadchars(outp, end, str_size); + outp = end; +} + +static void ADD_STR_U(const wchar_t *x, wchar_t *&outp, size_t &str_size) +{ + wchar_t *end = outp; + StringCchCopyExW(outp, str_size, (x) ? (x) : L"", &end, &str_size, 0); + removebadchars(outp, end, str_size); + CharUpperW(outp); + outp = end; +} + +static void ADD_STR_L(const wchar_t *x, wchar_t *&outp, size_t &str_size) +{ + wchar_t *end = outp; + StringCchCopyExW(outp, str_size, (x)?(x):L"", &end, &str_size,0); + removebadchars(outp, end, str_size); + CharLowerW(outp); + outp=end; +} + +// FixReplacementVars: replaces <Artist>, <Title>, <Album>, and #, ##, ##, with appropriate data +wchar_t *FixReplacementVars(wchar_t *str, size_t str_size, itemRecordW * song) +{ + wchar_t tmpsrc[4096] = {0}; + lstrcpyn(tmpsrc,str,sizeof(tmpsrc)/sizeof(wchar_t)); //lstrcpyn is nice enough to make sure it's null terminated. + + wchar_t *inp = tmpsrc; + wchar_t *outp = str; + + while (inp && *inp && str_size) + { + if (*inp == L'<') + { + if (!wcsncmp(inp,L"<TITLE>",7)) + { + ADD_STR_U(song->title, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<title>",7)) + { + ADD_STR_L(song->title, outp, str_size); + inp+=7; + } + else if (!_wcsnicmp(inp,L"<Title>",7)) + { + ADD_STR(song->title, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<ALBUM>",7)) + { + ADD_STR_U(song->album, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<album>",7)) + { + ADD_STR_L(song->album, outp, str_size); + inp+=7; + } + else if (!_wcsnicmp(inp,L"<Album>",7)) + { + ADD_STR(song->album, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<GENRE>",7)) + { + ADD_STR_U(song->genre, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<genre>",7)) + { + ADD_STR_L(song->genre, outp, str_size); + inp+=7; + } + else if (!_wcsnicmp(inp,L"<Genre>",7)) + { + ADD_STR(song->genre, outp, str_size); + inp+=7; + } + else if (!wcsncmp(inp,L"<ARTIST>",8)) + { + ADD_STR_U(song->artist, outp, str_size); + inp+=8; + } + else if (!wcsncmp(inp,L"<artist>",8)) + { + ADD_STR_L(song->artist, outp, str_size); + inp+=8; + } + else if (!_wcsnicmp(inp,L"<Artist>",8)) + { + ADD_STR(song->artist, outp, str_size); + inp+=8; + } + else if (!wcsncmp(inp,L"<ALBUMARTIST>",13)) + { + if (song->albumartist && song->albumartist[0]) + ADD_STR_U(song->albumartist, outp, str_size); + else + ADD_STR_U(song->artist, outp, str_size); + inp+=13; + } + else if (!wcsncmp(inp,L"<albumartist>",13)) + { + if (song->albumartist && song->albumartist[0]) + ADD_STR_L(song->albumartist, outp, str_size); + else + ADD_STR_L(song->artist, outp, str_size); + inp+=13; + } + else if (!_wcsnicmp(inp,L"<Albumartist>",13)) + { + if (song->albumartist && song->albumartist[0]) + ADD_STR(song->albumartist, outp, str_size); + else + ADD_STR(song->artist, outp, str_size); + inp+=13; + } + else if (!_wcsnicmp(inp,L"<year>",6)) + { + wchar_t year[64] = {0}; + if(song->year==0) year[0]=0; + else StringCchPrintf(year, 64, L"%d", song->year); + ADD_STR(year, outp, str_size); + inp+=6; + } + else if (!_wcsnicmp(inp,L"<disc>",6)) + { + wchar_t disc[16] = {0}; + if(song->disc==0) disc[0]=0; + else StringCchPrintf(disc, 16, L"%d", song->disc); + ADD_STR(disc, outp, str_size); + inp+=6; + } + else if (!_wcsnicmp(inp,L"<discs>",7)) + { + wchar_t discs[32] = {0}; + if(song->disc==0) discs[0]=0; + else StringCchPrintf(discs, 32, L"%d", song->discs); + ADD_STR(discs, outp, str_size); + inp+=7; + } + else if(!_wcsnicmp(inp,L"<filename>",10)) + { + wchar_t *fn = _wcsdup(PathFindFileName(song->filename)); + const wchar_t *insert; + + if (NULL != fn && + FALSE != PathIsFileSpec(fn)) + { + PathRemoveExtension(fn); + insert = fn; + } + else + insert = NULL; + + if (NULL == insert || L'\0' == *insert) + insert = L"<filename>"; + + ADD_STR(insert, outp, str_size); + + free(fn); + inp+=10; + } + else *outp++=*inp++; + } + else if (*inp == '#') + { + int nd = 0; + wchar_t tmp[64] = {0}; + while (inp && *inp =='#') nd++,inp++; + + if (!song->track) + { + tmp[0] = 0; + while (inp && *inp == ' ') inp++; + if (inp && (*inp == '-' || *inp == '.' || *inp == '_')) // separator + { + inp++; + while (inp && *inp == ' ') inp++; + } + } + else + { + if (nd > 1) + { + wchar_t tmp2[32] = {0}; + if (nd > 5) nd=5; + StringCchPrintf(tmp2, 32, L"%%%02dd",nd); + StringCchPrintf(tmp, 64, tmp2,song->track); + } + else StringCchPrintf(tmp, 64, L"%d", song->track); + } + ADD_STR(tmp, outp, str_size); + } + else *outp++ = *inp++; + } + if (outp) *outp = 0; + + inp = str; + outp = str; + wchar_t lastc=0; + while (inp && *inp) + { + wchar_t c=*inp++; + if (c == '\t') c=' '; + + if (c == ' ' && (lastc == ' ' || lastc == '\\' || lastc == '/')) continue; // ignore space after slash, or another space + + if ((c == '\\' || c == '/') && lastc == ' ') outp--; // if we have a space then slash, back up to write the slash where the space was + *outp++ = c; + lastc = c; + } + if (outp) *outp=0; + + #undef ADD_STR + #undef ADD_STR_L + #undef ADD_STR_U + + return(str); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/resource.h b/Src/Plugins/Library/ml_transcode/resource.h new file mode 100644 index 00000000..1fac1dd8 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/resource.h @@ -0,0 +1,45 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ml_transcode.rc +// +#define IDS_FORMAT_CONVERTER 0 +#define IDS_DONE 1 +#define IDS_TRANSCODING_FAILED 2 +#define IDS_ABORT 3 +#define IDCANCEL2 4 +#define IDS_TRACKS_DONE_REMAINING_FAILED 4 +#define IDS_FILENAME_FORMAT_HELP 5 +#define IDS_FILENAME_FORMAT_HELP_TITLE 6 +#define IDS_CHOOSE_FOLDER 7 +#define IDS_SELECT_WHERE_TO_SAVE 9 +#define IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS 10 +#define IDS_TRANSCODING_ABORTED 11 +#define IDS_STRING12 12 +#define IDS_REMOVE_PARTIAL_FILE 12 +#define IDD_TRANSCODE 101 +#define IDD_TRANSCODE_CONFIG 102 +#define IDC_TRACKPROGRESS 1001 +#define IDC_CURRENTTRACK 1002 +#define IDC_TOTALPROGRESS 1003 +#define IDC_TOTALCAPTION 1004 +#define IDC_ABORT 1005 +#define IDC_USE_FILENAME 1011 +#define IDC_ROOTDIR 1014 +#define IDC_BROWSE 1015 +#define IDC_NAMING 1016 +#define IDC_FORMATHELP 1017 +#define IDC_ENC_CONFIG 1018 +#define IDC_SHOWEVERY 1019 +#define IDC_ENCFORMAT 1020 +#define IDS_NULLSOFT_FORMAT_CONVERTER 65534 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Library/ml_transcode/reversesync.h b/Src/Plugins/Library/ml_transcode/reversesync.h new file mode 100644 index 00000000..b1363658 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/reversesync.h @@ -0,0 +1,9 @@ +#ifndef _REVERSESYNC_H +#define _REVERSESYNC_H + +WIN32_FIND_DATA *File_Exists(char *buf); +char *Skip_Root(char *path); +BOOL RecursiveCreateDirectory(char* buf1); +char *FixReplacementVars(char *str, int str_size, itemRecord * song); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_transcode/version.rc2 b/Src/Plugins/Library/ml_transcode/version.rc2 new file mode 100644 index 00000000..e0d322b9 --- /dev/null +++ b/Src/Plugins/Library/ml_transcode/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,79,0,0 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp Media Library Plug-in" + VALUE "FileVersion", "2,79,0,0" + VALUE "InternalName", "Nullsoft Format Convertor" + VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "ml_transcode.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END |