aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_mp3/id3dlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Input/in_mp3/id3dlg.cpp')
-rw-r--r--Src/Plugins/Input/in_mp3/id3dlg.cpp1071
1 files changed, 1071 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_mp3/id3dlg.cpp b/Src/Plugins/Input/in_mp3/id3dlg.cpp
new file mode 100644
index 00000000..85de0393
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/id3dlg.cpp
@@ -0,0 +1,1071 @@
+#include "main.h"
+#include "Metadata.h"
+#include "../Winamp/wa_ipc.h"
+// ID3v2 stuff
+#include "../id3v2/id3_tag.h"
+#include "FactoryHelper.h"
+#include "id3.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "AACFrame.h"
+#include "LAMEinfo.h"
+#include <shlwapi.h>
+#include "../nu/ns_wc.h"
+#include "../nu/ListView.h"
+#include "resource.h"
+#include "Stopper.h"
+#include "config.h"
+#include <strsafe.h>
+
+
+// TODO: benski> CUT!!!
+char g_stream_title[256] = {0};
+
+int fixAACCBRbitrate(int br)
+{
+ static short brs[] =
+ {
+ 8, 12, 16, 20, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0
+ };
+ int x;
+ for (x = 0; x < sizeof(brs) / sizeof(brs[0]); x ++)
+ {
+ int delta = (brs[x] * 8) / 128;
+ if (delta < 2) delta = 2;
+ if (br < brs[x] - delta) break;
+ if (br < brs[x] + delta) return brs[x];
+ }
+ return br;
+}
+
+void ConvertTryUTF8(const char *in, wchar_t *out, size_t outlen)
+{
+ out[0]=0;
+ int x = MultiByteToWideCharSZ(CP_UTF8, MB_ERR_INVALID_CHARS, in, -1, out, (int)outlen);
+ if (!x)
+ {
+ if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
+ MultiByteToWideCharSZ(CP_ACP, 0, in, -1, out, (int)outlen);
+ else
+ MultiByteToWideCharSZ(CP_UTF8, 0, in, -1, out, (int)outlen);
+ }
+}
+
+void getfileinfo(const wchar_t *filename, wchar_t *title, int *length_in_ms)
+{
+ const wchar_t *fn;
+ if (length_in_ms) *length_in_ms = -1000;
+ if (filename && filename[0])
+ fn = filename;
+ else
+ fn = lastfn;
+ if (!_wcsnicmp(fn, L"file://", 7)) fn += 7;
+ if (PathIsURL(fn))
+ {
+ if (title)
+ {
+ if (fn != filename || !_wcsicmp(fn, lastfn))
+ {
+ EnterCriticalSection(&g_lfnscs);
+ if (lastfn_status[0])
+ {
+ char buf[4096] = {0};
+ StringCchPrintfA(buf, 4096, "[%s] %s", lastfn_status, lastfn_data_ready ? g_stream_title : (char *)AutoChar(fn));
+ ConvertTryUTF8(buf, title, 256);
+ }
+ else
+ {
+ if (!lastfn_data_ready)
+ lstrcpynW(title, fn, 256);
+ else
+ {
+ ConvertTryUTF8(g_stream_title, title, 256);
+ }
+ }
+ LeaveCriticalSection(&g_lfnscs);
+ if (length_in_ms) *length_in_ms = getlength();
+ }
+ else
+ {
+ lstrcpynW(title, fn, 256);
+ }
+ }
+ return ;
+ }
+ else
+ {
+ Metadata info;
+ if (info.Open(fn) == METADATA_SUCCESS)
+ {
+ if (title)
+ {
+ wchar_t mp3artist[256] = L"", mp3title[256] = L"";
+ info.GetExtendedData("artist", mp3artist, 256);
+ info.GetExtendedData("title", mp3title, 256);
+ if (mp3artist[0] && mp3title[0])
+ StringCchPrintfW(title, 256, L"%s - %s", mp3artist, mp3title);
+ else if (mp3title[0])
+ lstrcpynW(title, mp3title, 256);
+ else
+ {
+ lstrcpynW(title, fn, MAX_PATH);
+ PathStripPathW(title);
+ PathRemoveExtensionW(title);
+ }
+ }
+
+ if (fn == filename)
+ {
+ wchar_t ln[128]=L"";
+ info.GetExtendedData("length", ln, 128);
+ *length_in_ms = _wtoi(ln);
+ }
+ else
+ *length_in_ms = getlength();
+ }
+ else if (fn != filename)
+ *length_in_ms = getlength();
+ }
+}
+
+int id3Dlg(const wchar_t *fn, HWND hwnd)
+{
+ return 1;
+}
+
+extern const wchar_t *id3v1_genres[];
+extern size_t numGenres;
+
+static int our_change=0;
+
+#define GetMeta(hwnd) (Metadata *)GetPropW(GetParent(hwnd),L"mp3info")
+#define SetMeta(hwnd,meta) SetPropW(GetParent(hwnd),L"mp3info",(HANDLE)meta)
+
+static INT_PTR CALLBACK id3v1_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int my_change_v1=0;
+ static const int ctrls[] =
+ {
+ IDC_ID3V11_TRACK,
+ IDC_ID3_TITLE,
+ IDC_ID3_ARTIST,
+ IDC_ID3_ALBUM,
+ IDC_ID3_YEAR,
+ IDC_ID3_COMMENT,
+ IDC_ID3_GENRE,
+ };
+ static const int strs_lim[] =
+ {
+ 3,
+ 30,
+ 30,
+ 30,
+ 4,
+ 28,
+ 1,
+ };
+ static const char * strs[] =
+ {
+ "track",
+ "title",
+ "artist",
+ "album",
+ "year",
+ "comment",
+ "genre",
+ };
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ meta->AddRef();
+ else
+ {
+ meta = new Metadata();
+ meta->Open((wchar_t*)lParam);
+ SetMeta(hwndDlg,meta);
+ }
+
+ wchar_t genre_buf[32] = {0};
+ meta->id3v1.GetString("genre",genre_buf,32);
+
+ our_change=1;
+
+ SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_RESETCONTENT, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_SETCURSEL, -1, 0);
+ for (size_t x = 0; x != numGenres; x ++)
+ {
+ int y = (int)SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_ADDSTRING, 0, (LPARAM)id3v1_genres[x]);
+ SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_SETITEMDATA, y, x);
+
+ if (_wcsicmp(genre_buf,id3v1_genres[x])==0)
+ SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_SETCURSEL, y, 0);
+ }
+
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ // make sure the edit boxes are limited to id3v1 spec sizes (trickier on number type fields)
+ wchar_t buf[32] = {0};
+ SendDlgItemMessage(hwndDlg,ctrls[i],EM_SETLIMITTEXT,strs_lim[i],0);
+ meta->id3v1.GetString(strs[i],buf,32);
+ SetDlgItemTextW(hwndDlg,ctrls[i],buf);
+ }
+
+ if (meta->id3v1.HasData())
+ {
+ CheckDlgButton(hwndDlg,IDC_ID3V1,TRUE);
+ if (!config_write_id3v1)
+ { // if we have id3v1 writing turned off, disable controls
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),FALSE);
+ }
+ }
+ else
+ { // no id3v1 tag present
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),FALSE);
+
+ if (!config_create_id3v1)
+ { // don't allow one to be created if the settings disallow
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ID3V1),FALSE);
+ }
+ }
+
+ our_change=0;
+ }
+ break;
+ case WM_USER:
+ if (wParam && lParam && !our_change && !my_change_v1)
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+
+ if (!config_write_id3v1)
+ break;
+
+ if (!config_create_id3v1 && !meta->id3v1.HasData())
+ break;
+
+ wchar_t *key = (wchar_t*)wParam;
+ wchar_t *value = (wchar_t*)lParam;
+ AutoChar keyA(key);
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ if (_stricmp(keyA,strs[i])==0)
+ {
+ // benski> i don't think this is what we want? meta->SetExtendedData(strs[i],value);
+ meta->id3v1.SetString(strs[i], value);
+ wchar_t buf[2048]=L"";
+ meta->id3v1.GetString(strs[i],buf,2048);
+
+ if (!IsDlgButtonChecked(hwndDlg,IDC_ID3V1))
+ {
+ // re-enable stuff
+ CheckDlgButton(hwndDlg,IDC_ID3V1,TRUE);
+ for (int j=0; j<sizeof(ctrls)/sizeof(int); j++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[j]),TRUE);
+ my_change_v1++;
+ SetDlgItemTextW(hwndDlg,ctrls[j],L"");
+ my_change_v1--;
+ }
+ }
+ my_change_v1++;
+ if (ctrls[i] == IDC_ID3_GENRE)
+ {
+ int n = (int)SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
+ SendDlgItemMessage(hwndDlg, IDC_ID3_GENRE, CB_SETCURSEL, n, 0);
+ }
+ else
+ SetDlgItemTextW(hwndDlg,ctrls[i],buf);
+ my_change_v1--;
+ break;
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ // this should be done by one pane ONLY. Doesn't matter which one.
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+
+ Stopper stopper;
+ if (!_wcsicmp(lastfn, meta->filename))
+ stopper.Stop();
+ int ret = meta->Save();
+ stopper.Play();
+
+ wchar_t boxtitle[256] = {0};
+ switch(ret)
+ {
+ case SAVE_SUCCESS:
+ {
+ // cheap way to trigger a metadata reset in a thread-safe manner
+ wchar_t d[10] = {0};
+ extendedFileInfoStructW reset_info = {0};
+ reset_info.filename=L".mp3";
+ reset_info.metadata=L"artist";
+ reset_info.ret = d;
+ reset_info.retlen=10;
+ SendMessage(mod.hMainWindow, WM_WA_IPC, (WPARAM)&reset_info, IPC_GET_EXTENDED_FILE_INFOW);
+ }
+ break;
+ case SAVE_ERROR_READONLY:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_READONLY),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ case SAVE_ERROR_OPENING_FILE:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_OPENING_FILE),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ case SAVE_APEV2_WRITE_ERROR:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_APEV2),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ case SAVE_LYRICS3_WRITE_ERROR:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_LYRICS3),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ case SAVE_ID3V1_WRITE_ERROR:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_ID3V1),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ case SAVE_ID3V2_WRITE_ERROR:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_ID3V2),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ default:
+ MessageBox(hwndDlg,
+ WASABI_API_LNGSTRINGW(IDS_METADATA_ERROR_UNSPECIFIED),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SAVING_METADATA, boxtitle, 256),
+ MB_OK);
+ break;
+ }
+ }
+ break;
+ case IDC_ID3V1_TO_V2:
+ {
+ my_change_v1=1;
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ {
+ wchar_t buf[2048]=L"";
+ GetDlgItemTextW(hwndDlg,ctrls[i],buf,2048);
+ meta->id3v2.SetString(strs[i],buf);
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ my_change_v1=0;
+ }
+ break;
+ case IDC_ID3V1:
+ {
+ our_change=1;
+ BOOL checked = IsDlgButtonChecked(hwndDlg,IDC_ID3V1);
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ if (!checked)
+ meta->id3v1.Clear();
+
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),checked);
+
+ wchar_t buf[2048]=L"";
+ if (checked)
+ {
+ GetDlgItemText(hwndDlg,ctrls[i],buf,2048);
+ if (buf[0])
+ meta->id3v1.SetString(strs[i],buf);
+ }
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ our_change=0;
+ }
+ break;
+ default:
+ if (!our_change && !my_change_v1 && (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == CBN_SELCHANGE))
+ {
+ our_change=1;
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ if (LOWORD(wParam) == ctrls[i])
+ {
+ wchar_t buf[2048]=L"";
+ if (HIWORD(wParam) == EN_CHANGE)
+ GetDlgItemTextW(hwndDlg,ctrls[i],buf,2048);
+ else
+ {
+ LRESULT n = SendDlgItemMessage(hwndDlg, ctrls[i], CB_GETCURSEL, 0, 0);
+ n = SendDlgItemMessage(hwndDlg, ctrls[i], CB_GETITEMDATA, n, 0);
+ if (n>=0 && n<(LRESULT)numGenres)
+ lstrcpyn(buf,id3v1_genres[n],2048);
+ }
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ meta->id3v1.SetString(strs[i],buf);
+ if (!meta->id3v2.HasData())
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ }
+ our_change=0;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta) meta->Release();
+ }
+ break;
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK id3v2_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int my_change_v2=0;
+ static const int ctrls[] =
+ {
+ IDC_ID3V2_TRACK,
+ IDC_ID3V2_TITLE,
+ IDC_ID3V2_ARTIST,
+ IDC_ID3V2_ALBUM,
+ IDC_ID3V2_YEAR,
+ IDC_ID3V2_COMMENT,
+ IDC_ID3V2_GENRE,
+ IDC_ID3V2_COMPOSER,
+ IDC_ID3V2_PUBLISHER,
+ IDC_ID3V2_MARTIST,
+ IDC_ID3V2_RECORD,
+ IDC_ID3V2_URL,
+ IDC_ID3V2_ENCODER,
+ IDC_ID3V2_ALBUM_ARTIST,
+ IDC_ID3V2_DISC,
+ IDC_TRACK_GAIN,
+ IDC_ALBUM_GAIN,
+ IDC_ID3V2_BPM,
+ };
+ static const char * strs[] =
+ {
+ "track",
+ "title",
+ "artist",
+ "album",
+ "year",
+ "comment",
+ "genre",
+ "composer",
+ "publisher",
+ "originalartist",
+ "copyright",
+ "url",
+ "tool",
+ "albumartist",
+ "disc",
+ "replaygain_track_gain", // 15
+ "replaygain_album_gain", // 16
+ "bpm",
+ };
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ our_change=1;
+ SendDlgItemMessage(hwndDlg, IDC_ID3V2_GENRE, CB_RESETCONTENT, 0, 0);
+ for (size_t x = 0; x != numGenres; x ++)
+ {
+ int y = (int)SendDlgItemMessage(hwndDlg, IDC_ID3V2_GENRE, CB_ADDSTRING, 0, (LPARAM)id3v1_genres[x]);
+ SendDlgItemMessage(hwndDlg, IDC_ID3V2_GENRE, CB_SETITEMDATA, y, x);
+ }
+
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ meta->AddRef();
+ else
+ {
+ meta = new Metadata();
+ meta->Open((wchar_t*)lParam);
+ SetMeta(hwndDlg,meta);
+ }
+
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ wchar_t buf[32768] = {0};
+ meta->id3v2.GetString(strs[i],buf,32768);
+ if((i == 15 || i == 16) && buf[0])
+ {
+ SetDlgItemTextW(hwndDlg,ctrls[i],L"buf");
+ // this isn't nice but it localises the RG values
+ // for display as they're saved in the "C" locale
+ double value = _wtof_l(buf,WASABI_API_LNG->Get_C_NumericLocale());
+ StringCchPrintfW(buf,64,L"%-+.2f dB", value);
+ }
+ SetDlgItemTextW(hwndDlg,ctrls[i],buf);
+ }
+
+ if (meta->id3v2.HasData())
+ CheckDlgButton(hwndDlg,IDC_ID3V2,TRUE);
+ else
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),FALSE);
+
+ our_change=0;
+ }
+ break;
+ case WM_USER:
+ if (wParam && lParam && !our_change && !my_change_v2)
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ wchar_t *key = (wchar_t*)wParam;
+ wchar_t *value = (wchar_t*)lParam;
+ AutoChar keyA(key);
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ if (_stricmp(keyA,strs[i])==0)
+ {
+ // benski> cut? i don't think this is what we want: meta->SetExtendedData(strs[i],value);
+ meta->id3v2.SetString(strs[i], value);
+ wchar_t buf[32768]=L"";
+ meta->id3v2.GetString(strs[i],buf,32768);
+
+ if (!IsDlgButtonChecked(hwndDlg,IDC_ID3V2))
+ {
+ // re-enable items
+ CheckDlgButton(hwndDlg,IDC_ID3V2,TRUE);
+ for (int j=0; j<sizeof(ctrls)/sizeof(int); j++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[j]),TRUE);
+ my_change_v2++;
+ SetDlgItemTextW(hwndDlg,ctrls[j],L"");
+ my_change_v2--;
+ }
+ }
+ my_change_v2++;
+ SetDlgItemTextW(hwndDlg,ctrls[i],buf);
+ my_change_v2--;
+ break;
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ID3V2_TO_V1:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ my_change_v2=1;
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ {
+ wchar_t buf[32768]=L"";
+ GetDlgItemTextW(hwndDlg,ctrls[i],buf,32768);
+ meta->id3v1.SetString(strs[i],buf);
+ meta->GetExtendedData(strs[i], buf, 32768);
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ my_change_v2=0;
+ }
+ break;
+ case IDC_ID3V2:
+ {
+ our_change=1;
+ BOOL checked = IsDlgButtonChecked(hwndDlg,IDC_ID3V2);
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ if (!checked)
+ meta->id3v2.Clear();
+
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),checked);
+
+ wchar_t buf[32768]=L"";
+ if (checked)
+ {
+ GetDlgItemText(hwndDlg,ctrls[i],buf,32768);
+ if (buf[0])
+ meta->id3v2.SetString(strs[i],buf);
+ }
+ meta->GetExtendedData(strs[i],buf,32768);
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ our_change=0;
+ }
+ break;
+ case IDOK:
+ {
+ extern Metadata *m_ext_get_mp3info;
+ if (m_ext_get_mp3info)
+ m_ext_get_mp3info->Release();
+ m_ext_get_mp3info=0;
+ }
+ break;
+ default:
+ if (!our_change && !my_change_v2 && (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_EDITUPDATE))
+ {
+ our_change=1;
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ if (LOWORD(wParam) == ctrls[i])
+ {
+ wchar_t buf[32768] = {0};
+ if (HIWORD(wParam) == EN_CHANGE)
+ GetDlgItemTextW(hwndDlg,ctrls[i],buf,32768);
+ else
+ {
+ LRESULT n = SendMessage(GetDlgItem(hwndDlg, ctrls[i]), CB_GETCURSEL, 0, 0);
+ n = SendMessage(GetDlgItem(hwndDlg, ctrls[i]), CB_GETITEMDATA, n, 0);
+ if (n>=0 && n<(LRESULT)numGenres)
+ lstrcpyn(buf,id3v1_genres[n],32768);
+ else{
+ GetDlgItemTextW(hwndDlg,ctrls[i],buf,32768);
+ }
+ }
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ meta->id3v2.SetString(strs[i],buf);
+ meta->GetExtendedData(strs[i],buf,32768);
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ }
+ }
+ our_change=0;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ meta->Release();
+ }
+ break;
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK lyrics3_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static const int ctrls[] =
+ {
+ IDC_LYRICS3_TITLE,
+ IDC_LYRICS3_ARTIST,
+ IDC_LYRICS3_ALBUM,
+ };
+ static const char * strs[] =
+ {
+ "title",
+ "artist",
+ "album",
+ };
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ meta->AddRef();
+ else
+ {
+ meta = new Metadata();
+ meta->Open((wchar_t*)lParam);
+ SetMeta(hwndDlg,meta);
+ }
+
+ for (int i=0; i<sizeof(strs)/sizeof(char*); i++)
+ {
+ wchar_t buf[2048] = {0};
+ SendDlgItemMessage(hwndDlg,ctrls[i],EM_SETLIMITTEXT,250,0);
+ meta->lyrics3.GetString(strs[i],buf,250);
+ SetDlgItemTextW(hwndDlg,ctrls[i],buf);
+ }
+
+ if (meta->lyrics3.HasData())
+ CheckDlgButton(hwndDlg,IDC_LYRICS3,TRUE);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_LYRICS3:
+ {
+ BOOL checked = IsDlgButtonChecked(hwndDlg,IDC_LYRICS3);
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ if (!checked)
+ meta->lyrics3.Clear();
+ else // clear the dirty state if re-enabled so we don't lose the lyrics3 tag
+ meta->lyrics3.ResetDirty();
+
+ for (int i=0; i<sizeof(ctrls)/sizeof(int); i++)
+ {
+ EnableWindow(GetDlgItem(hwndDlg,ctrls[i]),checked);
+
+ wchar_t buf[2048]=L"";
+ if (checked)
+ {
+ GetDlgItemText(hwndDlg,ctrls[i],buf,2048);
+ if (buf[0])
+ meta->lyrics3.SetString(strs[i],buf);
+ }
+ meta->GetExtendedData(strs[i],buf,2048);
+ // if we don't flag this then we can lose info in the id3v1 and v2 tags which is definitely bad
+ our_change++;
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)(wchar_t*)AutoWide(strs[i]),(LPARAM)buf);
+ our_change--;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta) meta->Release();
+ }
+ break;
+ }
+ return 0;
+}
+/* ================
+APEv2 Editor Tab
+================ */
+
+
+
+static INT_PTR CALLBACK apev2_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static W_ListView listview;
+ static int my_change_ape=0;
+ switch (uMsg)
+ {
+ case WM_NOTIFYFORMAT:
+ return NFR_UNICODE;
+
+ case WM_INITDIALOG:
+ {
+ our_change++;
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ {
+ meta->AddRef();
+ }
+ else
+ {
+ meta = new Metadata();
+ meta->Open((wchar_t*)lParam);
+ SetMeta(hwndDlg,meta);
+ }
+
+ if (meta->apev2.HasData())
+ CheckDlgButton(hwndDlg,IDC_APEV2,TRUE);
+
+ listview.setwnd(GetDlgItem(hwndDlg, IDC_APE_LIST));
+ listview.SetDoubleBuffered(true);
+ listview.AddCol(WASABI_API_LNGSTRINGW(IDS_NAME), 82);
+ listview.AddCol(WASABI_API_LNGSTRINGW(IDS_VALUE), 160);
+
+ listview.SetVirtualCount((int)meta->apev2.GetNumItems());
+ listview.AutoSizeColumn(0);
+ listview.AutoSizeColumn(1);
+
+ SetDlgItemTextW(hwndDlg,IDC_APE_KEY,L"");
+ SetDlgItemTextW(hwndDlg,IDC_APE_VALUE,L"");
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_KEY),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_VALUE),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_DELETE),FALSE);
+ our_change--;
+ return 1;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_APE_KEY:
+ case IDC_APE_VALUE:
+ if(HIWORD(wParam) == EN_CHANGE)
+ {
+ int selected = listview.GetNextSelected();
+ if (selected != LB_ERR)
+ {
+ listview.RefreshItem(selected);
+ }
+ }
+ else if(HIWORD(wParam) == EN_KILLFOCUS)
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+
+ my_change_ape++;
+
+ char key[1024] = {0};
+ wchar_t value[32768] = {0};
+ GetDlgItemTextA(hwndDlg, IDC_APE_KEY, key, 1024);
+ GetDlgItemText(hwndDlg, IDC_APE_VALUE, value, 32768);
+ int selected = listview.GetNextSelected();
+ if (selected != LB_ERR)
+ {
+ meta->apev2.SetKeyValueByIndex(selected, key, value);
+ }
+
+ const wchar_t *winamp_key = APE::MapApeKeyToWinampKeyW(key);
+ if (winamp_key)
+ {
+ our_change++;
+ SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)winamp_key,(WPARAM)value);
+ our_change--;
+ }
+ my_change_ape--;
+ }
+ break;
+
+ case IDC_APEV2:
+ {
+ BOOL checked = IsDlgButtonChecked(hwndDlg,IDC_APEV2);
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ if (!checked)
+ meta->apev2.MarkClear();
+ else // clear the dirty state if re-enabled so we don't lose the apev2 tag
+ meta->apev2.ResetDirty();
+ }
+ break;
+
+ case IDC_DELETE_ALL:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ my_change_ape++;
+ listview.UnselectAll();
+ meta->apev2.Clear();
+ listview.SetVirtualCount((int)meta->apev2.GetNumItems());
+ my_change_ape--;
+ }
+ break;
+
+ case IDC_APE_ADD:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ int index = listview.GetCount();
+ if (meta->apev2.AddItem() == APEv2::APEV2_SUCCESS)
+ {
+ listview.SetVirtualCount((int)meta->apev2.GetNumItems());
+ listview.SetSelected(index);
+ listview.ScrollTo(index);
+ SetFocus(GetDlgItem(hwndDlg, IDC_APE_KEY));
+ }
+ }
+ break;
+
+ case IDC_APE_DELETE:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (!meta) break;
+ int selected = listview.GetNextSelected();
+ if (selected != LB_ERR)
+ {
+ listview.UnselectAll();
+ meta->apev2.RemoveItem(selected);
+ listview.SetVirtualCount((int)meta->apev2.GetNumItems());
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR l=(LPNMHDR)lParam;
+ if (l->idFrom==IDC_APE_LIST) switch (l->code)
+ {
+ case LVN_GETDISPINFO:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ {
+ NMLVDISPINFO *lpdi = (NMLVDISPINFO*) l;
+ if (lpdi->item.mask & LVIF_TEXT)
+ {
+ int selected = listview.GetNextSelected();
+ switch (lpdi->item.iSubItem)
+ {
+ case 0:
+ {
+ if (lpdi->item.iItem == selected)
+ {
+ GetDlgItemText(hwndDlg, IDC_APE_KEY, lpdi->item.pszText, lpdi->item.cchTextMax);
+ }
+ else
+ {
+ const char *key=0;
+ meta->apev2.EnumValue(lpdi->item.iItem, &key, 0, 0);
+ MultiByteToWideCharSZ(CP_ACP, 0, key?key:"", -1, lpdi->item.pszText, lpdi->item.cchTextMax);
+ }
+ }
+ return 0;
+
+ case 1:
+ {
+ if (lpdi->item.iItem == selected)
+ {
+ GetDlgItemText(hwndDlg, IDC_APE_VALUE, lpdi->item.pszText, lpdi->item.cchTextMax);
+ }
+ else
+ {
+ const char *key=0;
+ meta->apev2.EnumValue(lpdi->item.iItem, &key, lpdi->item.pszText, lpdi->item.cchTextMax);
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case LVN_KEYDOWN:
+ break;
+
+ case LVN_ITEMCHANGED:
+ {
+ my_change_ape++;
+ LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam;
+ if (lv->uNewState & LVIS_SELECTED)
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ {
+ const char *key=0;
+ wchar_t value[32768] = {0};
+ meta->apev2.EnumValue(lv->iItem, &key, value, 32768);
+ SetDlgItemTextA(hwndDlg,IDC_APE_KEY,key);
+ SetDlgItemText(hwndDlg,IDC_APE_VALUE,value);
+ BOOL editable = meta->apev2.IsItemReadOnly(lv->iItem)?FALSE:TRUE;
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_KEY),editable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_VALUE),editable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_DELETE),TRUE);
+ listview.RefreshItem(lv->iItem);
+ }
+ }
+ if (lv->uOldState & LVIS_SELECTED)
+ {
+ SetDlgItemTextW(hwndDlg,IDC_APE_KEY,L"");
+ SetDlgItemTextW(hwndDlg,IDC_APE_VALUE,L"");
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_KEY),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_VALUE),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_APE_DELETE),FALSE);
+ }
+ my_change_ape--;
+ }
+ }
+ }
+ break;
+
+ case WM_USER:
+ if (wParam && lParam && !our_change && !my_change_ape)
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta)
+ {
+ const wchar_t *keyW = (const wchar_t *)wParam;
+ const wchar_t *value = (const wchar_t *)lParam;
+ AutoChar key(keyW);
+ my_change_ape++;
+ meta->apev2.SetString(key, value);
+ listview.UnselectAll();
+ listview.SetVirtualCount((int)meta->apev2.GetNumItems());
+ listview.RefreshAll();
+ my_change_ape--;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ Metadata *meta = GetMeta(hwndDlg);
+ if (meta) meta->Release();
+ }
+ break;
+ }
+ return 0;
+}
+
+extern "C"
+{
+ // return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
+ // if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")!
+ __declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn)
+ {
+ if (!_wcsnicmp(fn, L"file://", 7)) fn += 7;
+ if (PathIsURLW(fn)) return 2;
+ return 1;
+ }
+
+ // should return a child window of 513x271 pixels (341x164 in msvc dlg units), or return NULL for no tab.
+ // Fill in name (a buffer of namelen characters), this is the title of the tab (defaults to "Advanced").
+ // filename will be valid for the life of your window. n is the tab number. This function will first be
+ // called with n == 0, then n == 1 and so on until you return NULL (so you can add as many tabs as you like).
+ // The window you return will recieve WM_COMMAND, IDOK/IDCANCEL messages when the user clicks OK or Cancel.
+ // when the user edits a field which is duplicated in another pane, do a SendMessage(GetParent(hwnd),WM_USER,(WPARAM)L"fieldname",(LPARAM)L"newvalue");
+ // this will be broadcast to all panes (including yours) as a WM_USER.
+ __declspec(dllexport) HWND winampAddUnifiedFileInfoPane(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen)
+ {
+ if (n == 0)
+ {
+ SetPropW(parent,L"INBUILT_NOWRITEINFO", (HANDLE)1);
+ lstrcpyn(name,L"ID3v1", (int)namelen);
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO_ID3V1, parent, id3v1_dlgproc, (LPARAM)filename);
+ }
+ if (n == 1)
+ {
+ lstrcpyn(name,L"ID3v2", (int)namelen);
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO_ID3V2, parent, id3v2_dlgproc, (LPARAM)filename);
+ }
+ if (n == 2)
+ {
+ Metadata *meta = (Metadata *)GetPropW(parent, L"mp3info");
+ if (meta->lyrics3.HasData())
+ {
+ lstrcpyn(name,L"Lyrics3", (int)namelen);
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO_LYRICS3, parent, lyrics3_dlgproc, (LPARAM)filename);
+ }
+ else if (meta->apev2.HasData())
+ {
+ lstrcpyn(name,L"APEv2", (int)namelen);
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO_APEV2, parent, apev2_dlgproc, (LPARAM)filename);
+ }
+ }
+ if (n == 3)
+ {
+ Metadata *meta = (Metadata *)GetPropW(parent, L"mp3info");
+ if (meta->lyrics3.HasData() && meta->apev2.HasData())
+ {
+ lstrcpyn(name,L"APEv2", (int)namelen);
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO_APEV2, parent, apev2_dlgproc, (LPARAM)filename);
+ }
+ }
+ return NULL;
+ }
+} \ No newline at end of file