1071 lines
27 KiB
C++
1071 lines
27 KiB
C++
#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;
|
|
}
|
|
} |