aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_transcode
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_transcode
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_transcode')
-rw-r--r--Src/Plugins/Library/ml_transcode/LinkedQueue.cpp139
-rw-r--r--Src/Plugins/Library/ml_transcode/LinkedQueue.h41
-rw-r--r--Src/Plugins/Library/ml_transcode/api__ml_transcode.h26
-rw-r--r--Src/Plugins/Library/ml_transcode/main.cpp1100
-rw-r--r--Src/Plugins/Library/ml_transcode/ml_transcode.rc162
-rw-r--r--Src/Plugins/Library/ml_transcode/ml_transcode.sln30
-rw-r--r--Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj333
-rw-r--r--Src/Plugins/Library/ml_transcode/ml_transcode.vcxproj.filters65
-rw-r--r--Src/Plugins/Library/ml_transcode/replaceVars.cpp317
-rw-r--r--Src/Plugins/Library/ml_transcode/resource.h45
-rw-r--r--Src/Plugins/Library/ml_transcode/reversesync.h9
-rw-r--r--Src/Plugins/Library/ml_transcode/version.rc239
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,&gtrack,&gartist,&galbum,&gtitle);
+ 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)&copy, 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