diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_disc/cdrip.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_disc/cdrip.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_disc/cdrip.cpp | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_disc/cdrip.cpp b/Src/Plugins/Library/ml_disc/cdrip.cpp new file mode 100644 index 00000000..58192596 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/cdrip.cpp @@ -0,0 +1,1061 @@ +#include "main.h" +#include <windowsx.h> +#include "resource.h" + +#include "..\nu\listview.h" +#include "../nu/DialogSkinner.h" +#include "../nu/ChildSizer.h" + +#include "config.h" +#include "../winamp/wa_ipc.h" + +#include "..\..\General\gen_ml/gaystring.h" + +#include <stdio.h> +#include <shlobj.h> +#include <time.h> +#include "../nu/AutoChar.h" +#include "../nu/AutoCharFn.h" +#include "../nu/AutoWide.h" + +#include "ReplayGain.h" + +#include "M3UWriter.h" +#include "PLSWriter.h" +#include "./settings.h" +#include <shlwapi.h> +#include <windows.h> +#include <strsafe.h> + +extern unsigned int FileTimeToUnixTime(FILETIME *ft); + +static UINT uMsgRipperNotify = 0; + + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HWND CreateCDRipWindow(HWND hwndParent, CHAR cLetter) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_CDROM_EX2, hwndParent, DlgProc, (LPARAM)cLetter); +} +//physically update metadata in a given file +int updateFileInfo(char *filename, char *metadata, char *data) +{ + extendedFileInfoStruct efis = { + filename, + metadata, + data ? data : "", + data ? strlen(data) : 0, + }; + return (INT)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_SET_EXTENDED_FILE_INFO); +} + +//physically update metadata in a given file +int updateFileInfoW(wchar_t *filename, const wchar_t *metadata, const wchar_t *data) +{ + extendedFileInfoStructW efis = { + filename, + metadata, + data ? data : L"", + data ? lstrlenW(data) : 0, + }; + return (INT)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_SET_EXTENDED_FILE_INFOW); +} + + +static int m_extract_curtrack, m_extract_nb, m_extract_nb_total; +static int m_db_has_upd; +static convertFileStructW m_fcs; +static wchar_t m_extract_src[64]; +static DWORD m_extract_time; +static int m_extracting; +static cdrip_params *m_rip_params; +HWND m_extract_wnd = 0; +static wchar_t m_last_total_status[512]; +static wchar_t m_last_item_status[512]; +static int m_cur_rg = 0; +static int done = 0; + +bool RegisteredEncoder(DWORD fourcc) +{ + if (fourcc == mmioFOURCC('M', 'P', '3', 'l') + || fourcc == mmioFOURCC('A', 'A', 'C', 'H') + || fourcc == mmioFOURCC('M', '4', 'A', 'H')) + return true; + else + return false; +} + +static void createDirForFile(char *str) +{ + char *p = str; + if ((p[0] == '\\' || p[0] == '/') && (p[1] == '\\' || p[1] == '/')) + { + p += 2; + while (p && *p && *p != '\\' && *p != '/') p++; + if (!p || !*p) return ; + p++; + while (p && *p && *p != '\\' && *p != '/') p++; + } + else + { + while (p && *p && *p != '\\' && *p != '/') p++; + } + + while (p && *p) + { + while (p && *p != '\\' && *p != '/' && *p) p = CharNextA(p); + if (p && *p) + { + char lp = *p; + *p = 0; + CreateDirectoryA(str, NULL); + *p++ = lp; + } + } +} + +static void createDirForFileW(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 !=L'\\' && *p !=L'/' && *p) p = CharNextW(p); + if (p && *p) + { + wchar_t lp = *p; + *p = 0; + CreateDirectoryW(str, NULL); + *p++ = lp; + } + } +} + +static void LockCD(char cLetter, BOOL bLock) +{ + wchar_t info[32] = {0}; + wchar_t name[] = L"cda://X"; + name[6] = cLetter; + getFileInfoW(name, (bLock) ? L"cdlock" : L"cdunlock", info, sizeof(info)/sizeof(wchar_t)); +} + +static int m_pstat_bytesdone; +static int m_pstat_bytesout; +static int m_pstat_timedone; + +static int m_rip_done; + +static HWND m_hwndstatus; +static W_ListView m_statuslist; + +static void NotifyInfoWindow(HWND hwnd, BOOL bForceRefresh) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + if (hwndParent) SendMessageW(hwndParent, WM_SHOWFILEINFO, + (WPARAM) WISF_MESSAGE | ((bForceRefresh) ? WISF_FORCE : WISF_NORMAL), + (LPARAM)WASABI_API_LNGSTRINGW(IDS_INFO_RIPPING)); +} + +static void ListView_OnItemChanged(HWND hwndDlg, NMLISTVIEW *pnmv) +{ + if (LVIF_STATE & pnmv->uChanged) + { + if ((LVIS_FOCUSED & pnmv->uOldState) != (LVIS_FOCUSED & pnmv->uNewState)) + { + NotifyInfoWindow(hwndDlg, TRUE); + } + } +} + +static void Window_OnQueryInfo(HWND hwnd) +{ + NotifyInfoWindow(hwnd, FALSE); +} + +static INT_PTR Window_OnNotify(HWND hwndDlg, INT ctrlId, LPNMHDR phdr) +{ + switch(phdr->idFrom) + { + case IDC_LIST2: + switch(phdr->code) + { + case LVN_ITEMCHANGED: ListView_OnItemChanged(hwndDlg, (NMLISTVIEW*)phdr); break; + } + break; + } + return 0; +} + +INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static ChildWndResizeItem ripwnd_rlist[] = { + {IDC_LIST2, 0x0011}, + {IDC_CDINFO, 0x0000}, + {IDC_RIPOPTS, 0x0101}, + {IDC_CANCEL_RIP, 0x0101}, + {IDC_BTN_SHOWINFO, 0x1111}, + }; + + INT_PTR a = (INT_PTR)dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam); if (a) return a; + switch (uMsg) + { + case WM_SIZE: + if (wParam != SIZE_MINIMIZED) + { + childSizer.Resize(hwndDlg, ripwnd_rlist, sizeof(ripwnd_rlist) / sizeof(ripwnd_rlist[0])); + } + break; + case WM_PAINT: + { + int tab[] = { IDC_LIST2 | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwndDlg, tab, 1); + } + return 0; + case WM_INITDIALOG: + + m_hwndstatus = hwndDlg; + + SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwndDlg, IDC_BTN_SHOWINFO)); + + m_statuslist.setwnd(GetDlgItem(hwndDlg, IDC_LIST2)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TRACK_NUMBER), g_view_metaconf->ReadInt(L"col_track", 60)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), g_view_metaconf->ReadInt(L"col_title", 200)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_LENGTH), g_view_metaconf->ReadInt(L"col_len", 80)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_STATUS), g_view_metaconf->ReadInt(L"col_status", 200)); + + SetDlgItemText(hwndDlg, IDC_CDINFO, m_last_total_status); + { + int l = m_rip_params->ntracks; + int x = 0; + for (int i = 0;i < l;i++) if (m_rip_params->tracks[i]) + { + wchar_t buf[1024] = {0}; + StringCchPrintf(buf, 1024, L"%d", i + 1); + m_statuslist.InsertItem(x, buf, 0); + m_statuslist.SetItemText(x, 1, m_rip_params->tracks[i]); + + StringCchPrintf(buf, 512, L"%d:%02d", m_rip_params->lengths[i] / 60, m_rip_params->lengths[i] % 60); + m_statuslist.SetItemText(x, 2, buf); + + if (i < m_extract_curtrack || m_rip_done) + m_statuslist.SetItemText(x, 3, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + else if (i > m_extract_curtrack) + m_statuslist.SetItemText(x, 3, WASABI_API_LNGSTRINGW(IDS_QUEUED)); + else + { + m_statuslist.SetItemText(x, 3, m_last_item_status[0] ? m_last_item_status : WASABI_API_LNGSTRINGW(IDS_RIPPING)); + } + x++; + } + } + + if (!m_extract_wnd || m_rip_done) + { + SetDlgItemText(hwndDlg, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + } + + if (g_config->ReadInt(L"cdripautoeject", 0)) CheckDlgButton(hwndDlg, IDC_CHECK2, BST_CHECKED); + if (g_config->ReadInt(L"cdripautoplay", 0)) CheckDlgButton(hwndDlg, IDC_CHECK3, BST_CHECKED); + if (g_config->ReadInt(L"cdripautoclose", 1)) CheckDlgButton(hwndDlg, IDC_CHECK1, BST_CHECKED); + + childSizer.Init(hwndDlg, ripwnd_rlist, sizeof(ripwnd_rlist) / sizeof(ripwnd_rlist[0])); + + ListView_SetTextColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMFG)); + ListView_SetBkColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMBG)); + ListView_SetTextBkColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMBG)); + + if(m_statuslist.getwnd()) + { + MLSKINWINDOW sw; + sw.hwndToSkin = m_statuslist.getwnd(); + sw.skinType = SKINNEDWND_TYPE_LISTVIEW; + sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS; + MLSkinWindow(plugin.hwndLibraryParent, &sw); + } + NotifyInfoWindow(hwndDlg, TRUE); + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_RIPOPTS: + { + RECT r; + HMENU menu = GetSubMenu(g_context_menus, 5); + GetWindowRect((HWND)lParam, &r); + CheckMenuItem(menu, ID_RIPOPTIONS_RIPPINGSTATUSWINDOW, g_config->ReadInt(L"cdripstatuswnd", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_EJECTCDWHENCOMPLETED, g_config->ReadInt(L"cdripautoeject", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PLAYTRACKSWHENCOMPLETED, g_config->ReadInt(L"cdripautoplay", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE, g_config->ReadInt(L"cdripautoclose", 0) ? MF_CHECKED : MF_UNCHECKED); + + int prio = g_config->ReadInt(L"extractprio", THREAD_PRIORITY_NORMAL); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_IDLE, prio == THREAD_PRIORITY_IDLE ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_LOWEST, prio == THREAD_PRIORITY_LOWEST ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_BELOWNORMAL, prio == THREAD_PRIORITY_BELOW_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_NORMAL, prio == THREAD_PRIORITY_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_ABOVENORMAL, prio == THREAD_PRIORITY_ABOVE_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_HIGH, prio == THREAD_PRIORITY_HIGHEST ? MF_CHECKED : MF_UNCHECKED); + + int x = Menu_TrackPopup(plugin.hwndLibraryParent, menu, + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | + TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + r.left, r.top, hwndDlg, NULL); + switch (x) + { + case ID_RIPOPTIONS_RIPPINGSTATUSWINDOW: + { + int x = g_config->ReadInt(L"cdripstatuswnd", 0); + g_config->WriteInt(L"cdripstatuswnd", !x); + ShowWindow(m_extract_wnd, x ? SW_HIDE : SW_SHOW); + } + break; + case ID_RIPOPTIONS_EJECTCDWHENCOMPLETED: + g_config->WriteInt(L"cdripautoeject", !g_config->ReadInt(L"cdripautoeject", 0)); + break; + case ID_RIPOPTIONS_PLAYTRACKSWHENCOMPLETED: + g_config->WriteInt(L"cdripautoplay", !g_config->ReadInt(L"cdripautoplay", 0)); + break; + case ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE: + g_config->WriteInt(L"cdripautoclose", !g_config->ReadInt(L"cdripautoclose", 0)); + break; + case ID_RIPOPTIONS_PRIORITY_IDLE: + case ID_RIPOPTIONS_PRIORITY_LOWEST: + case ID_RIPOPTIONS_PRIORITY_BELOWNORMAL: + case ID_RIPOPTIONS_PRIORITY_NORMAL: + case ID_RIPOPTIONS_PRIORITY_ABOVENORMAL: + case ID_RIPOPTIONS_PRIORITY_HIGH: + { + int prio = THREAD_PRIORITY_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_IDLE) prio = THREAD_PRIORITY_IDLE; + if (x == ID_RIPOPTIONS_PRIORITY_LOWEST) prio = THREAD_PRIORITY_LOWEST; + if (x == ID_RIPOPTIONS_PRIORITY_BELOWNORMAL) prio = THREAD_PRIORITY_BELOW_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_ABOVENORMAL) prio = THREAD_PRIORITY_ABOVE_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_HIGH) prio = THREAD_PRIORITY_HIGHEST; + g_config->WriteInt(L"extractprio", prio); + convertSetPriorityW csp = { + &m_fcs, + prio, + }; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&csp, IPC_CONVERT_SET_PRIORITYW); + } + break; + } + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + } + return 0; + case IDC_CANCEL_RIP: + { + wchar_t title[64] = {0}; + if (!m_extract_wnd || + m_rip_done || + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_CANCEL_RIP), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP_QUESTION,title,64), + MB_YESNO | MB_ICONQUESTION) == IDYES) + { + if (m_rip_params) LockCD(m_rip_params->drive_letter, FALSE); + if (m_extract_wnd) DestroyWindow(m_extract_wnd); + DestroyWindow(hwndDlg); + } + return 0; + } + case IDC_BTN_SHOWINFO: + switch(HIWORD(wParam)) + { + case BN_CLICKED: + SendMessageW(GetParent(hwndDlg), WM_COMMAND, wParam, lParam); + NotifyInfoWindow(hwndDlg, TRUE); + break; + } + break; + } + break; + case WM_DESTROY: + if (m_statuslist.getwnd()) + { + g_view_metaconf->WriteInt(L"col_track", m_statuslist.GetColumnWidth(0)); + g_view_metaconf->WriteInt(L"col_title", m_statuslist.GetColumnWidth(1)); + g_view_metaconf->WriteInt(L"col_len", m_statuslist.GetColumnWidth(2)); + g_view_metaconf->WriteInt(L"col_status", m_statuslist.GetColumnWidth(3)); + } + + m_hwndstatus = 0; + return 0; + + case WM_ERASEBKGND: return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwndDlg); break; + case WM_NOTIFY: return Window_OnNotify(hwndDlg, (INT)wParam, (LPNMHDR) lParam); + + + } + return 0; +} + +static BOOL CALLBACK extract_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + m_extract_wnd = hwndDlg; + m_rip_done = 0; + SetDlgItemText(hwndDlg, IDC_STATUS, WASABI_API_LNGSTRINGW(IDS_INITIALIZING)); + m_pstat_bytesdone = 0; + m_pstat_bytesout = 0; + m_pstat_timedone = 0; + m_extract_nb = 0; + m_extract_curtrack = -1; + m_cur_rg = 0; + { + m_extract_nb_total = 0; + int l = m_rip_params->ntracks; + for (int i = 0;i < l;i++) if (m_rip_params->tracks[i]) m_extract_nb_total++; + } + + LockCD(m_rip_params->drive_letter, TRUE); + + SetPropW(hwndDlg, L"WARIPPER", (HANDLE)hwndDlg); + SetPropW(hwndDlg, L"DRIVE", (HANDLE)(INT_PTR)(0xFF & m_rip_params->drive_letter)); + + if (!uMsgRipperNotify) uMsgRipperNotify = RegisterWindowMessageA("WARIPPER_BROADCAST_MSG"); + if (uMsgRipperNotify) SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, (WPARAM)m_rip_params->drive_letter, (LPARAM)TRUE); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + PostMessage(hwndDlg, WM_APP + 1, 0, 0); + if (g_config->ReadInt(L"cdripstatuswnd", 0)) ShowWindow(hwndDlg, SW_SHOW); + + INT bVal; + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CALCULATERG, &bVal) && bVal) + { + CreateGain(); + QueueUserAPC(StartGain, rgThread, + (ULONG_PTR)((m_rip_params->ntracks == m_extract_nb_total) ? RG_ALBUM : RG_INDIVIDUAL_TRACKS)); + } + break; + case WM_APP + 2: // track is starting to be RG scanned + m_statuslist.SetItemText(m_cur_rg, 3, WASABI_API_LNGSTRINGW(IDS_CALCULATING_REPLAY_GAIN)); + break; + case WM_APP + 3: // track is starting to be RG scanned + m_statuslist.SetItemText(m_cur_rg, 3, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + m_cur_rg++; + break; + case WM_APP + 1: + { + INT trackOffset, cchDest; + TCHAR szDestination[MAX_PATH] = {0}, szFormat[MAX_PATH] = {0}; + int l = m_rip_params->ntracks; + done = 1; + + Settings_GetInt(C_EXTRACT, EF_TRACKOFFSET, &trackOffset); + Settings_ReadString(C_EXTRACT, EF_TITLEFMT, szFormat, ARRAYSIZE(szFormat)); + Settings_ReadString(C_EXTRACT, EF_PATH, szDestination, ARRAYSIZE(szDestination)); + CleanupDirectoryString(szDestination); + + cchDest = lstrlen(szDestination); + + for (int i = m_extract_curtrack + 1;i < l;i++) + { + if (m_rip_params->tracks[i]) + { + StringCchPrintfW(m_extract_src, 64, L"cda://%c,%d.cda", m_rip_params->drive_letter, i + 1); + szDestination[cchDest] = TEXT('\0'); + if (cchDest) PathAddBackslash(szDestination); + + wchar_t tmp1[32] = {0}, tmp2[32] = {0}, tmp3[32] = {0}, tmp4[32] = {0}, tmp5[32] = {0}; + FormatFileName(szDestination, + ARRAYSIZE(szDestination)-11, // ensure we're leaving enough room for the extension + szFormat, + i + trackOffset, + (m_rip_params->artist && *(m_rip_params->artist)) ? (m_rip_params->artist) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ARTIST,tmp1,32), + (m_rip_params->album && *(m_rip_params->album)) ? (m_rip_params->album) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ALBUM,tmp2,32), + (m_rip_params->tracks[i] && *(m_rip_params->tracks[i])) ? (m_rip_params->tracks[i]) : L"0", + (m_rip_params->genre && *(m_rip_params->genre)) ? (m_rip_params->genre) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp3,32), + (m_rip_params->year && *(m_rip_params->year)) ? (m_rip_params->year) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp4,32), + (m_rip_params->trackArtists[i] && m_rip_params->trackArtists[i][0])?m_rip_params->trackArtists[i] : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp5,32), + NULL, (m_rip_params->disc && *(m_rip_params->disc)) ? (m_rip_params->disc) : L""); + memset(&m_fcs, 0, sizeof(m_fcs)); + m_fcs.sourcefile = m_extract_src; + INT fourcc; + Settings_GetInt(C_EXTRACT, EF_FOURCC, &fourcc); + m_fcs.destformat[0]=fourcc; + if (m_fcs.destformat[0] == OLD_AAC_CODEC) Settings_GetDefault(C_EXTRACT, EF_FOURCC, &m_fcs.destformat[0]); + + // now determine the extension + wchar_t fmt[10] = {0}; + GetExtensionString(fmt, ARRAYSIZE(fmt), (DWORD)m_fcs.destformat[0]); + BOOL upperCase; + if (SUCCEEDED(Settings_GetBool(C_EXTRACT, EF_UPPEREXTENSION, &upperCase)) && FALSE != upperCase) + CharUpper(fmt); + else + CharLower(fmt); + + StringCchCat(szDestination, ARRAYSIZE(szDestination), TEXT(".")); + StringCchCat(szDestination, ARRAYSIZE(szDestination), fmt); + + if (m_rip_params->filenames[i]) free(m_rip_params->filenames[i]); + m_rip_params->filenames[i] = _wcsdup(szDestination); + + wchar_t tempFile[MAX_PATH] = {0}; + wchar_t tmppath[MAX_PATH] = {0}; + GetTempPath(MAX_PATH,tmppath); + GetTempFileName(tmppath,L"rip",0,tempFile); + + m_rip_params->tempFilenames[i] = _wcsdup(tempFile); + createDirForFileW(m_rip_params->filenames[i]); + m_fcs.destfile = _wcsdup(tempFile); + createDirForFileW(m_fcs.destfile); + m_fcs.callbackhwnd = hwndDlg; + m_fcs.error = L""; + m_extract_time = 0; + m_extract_curtrack = i; + + wchar_t *ptr = m_rip_params->filenames[i]; + if (cchDest && cchDest < (int)lstrlenW(ptr)) ptr += (cchDest + 1); + SetDlgItemText(hwndDlg, IDC_CURTRACK, ptr); + + if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW) != 1) + { + wchar_t tmp[512] = {0}; + StringCchPrintf(tmp, 512, WASABI_API_LNGSTRINGW(IDS_ERROR_RIPPING_TRACK), i + 1, m_fcs.error ? m_fcs.error : L""); + MessageBox(hwndDlg, tmp, WASABI_API_LNGSTRINGW(IDS_ERROR), MB_OK); + done = -1; + break; + } + convertSetPriorityW csp = { + &m_fcs, + g_config->ReadInt(L"extractprio", THREAD_PRIORITY_NORMAL), + }; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&csp, IPC_CONVERT_SET_PRIORITYW); + m_extracting = 1; + done = 0; + PostMessage(hwndDlg, WM_WA_IPC , 0, IPC_CB_CONVERT_STATUS); + break; + } + } + if (done && m_rip_params) + { + LockCD(m_rip_params->drive_letter, FALSE); + + if (g_config->ReadInt(L"cdripautoeject", 0) && done > 0) + { + char buf[64] = {0}; + StringCchPrintfA(buf, 64, "cda://%c.cda", m_rip_params->drive_letter); + char buf2[32] = {0}; + getFileInfo(buf, "<eject>", buf2, sizeof(buf2)); + } + + if (g_config->ReadInt(L"cdripautoplay", 0) && done > 0) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i]) + { + COPYDATASTRUCT cds; + cds.dwData = IPC_PLAYFILEW; + cds.lpData = (void *) m_rip_params->filenames[i]; + cds.cbData = sizeof(wchar_t) * (lstrlenW(m_rip_params->filenames[i]) + 1); // include space for null char + SendMessage(plugin.hwndWinampParent, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds); + } + } + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY); + } + + + if (m_rip_params->ntracks == m_extract_nb_total && done > 0) + { + INT bVal; + if ((S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEM3U, &bVal) && bVal) || + (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEPLS, &bVal) && bVal)) + { + + wchar_t str[MAX_PATH] = {0}, fmt[MAX_PATH] = {0}; + Settings_ReadString(C_EXTRACT, EF_PLAYLISTFMT, fmt, ARRAYSIZE(fmt)); + Settings_ReadString(C_EXTRACT, EF_PATH, str, ARRAYSIZE(str)); + + int l = lstrlenW(str); + if (l) + PathAddBackslash(str); + + FormatFileName(str, ARRAYSIZE(str)-5, // ensure we're leaving enough room for the extension + fmt, 0xdeadbeef, + m_rip_params->artist ? m_rip_params->artist : L"", + m_rip_params->album ? m_rip_params->album : L"", + NULL, + m_rip_params->genre ? m_rip_params->genre : L"", + m_rip_params->year ? m_rip_params->year : L"", + NULL, + NULL, + m_rip_params->disc ? m_rip_params->disc : L""); + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEM3U, &bVal) && bVal) + { + wchar_t str2[MAX_PATH] = {0}; + lstrcpynW(str2, str, MAX_PATH); + StringCchCatW(str2, MAX_PATH, L".m3u"); + createDirForFileW(str2); + M3UWriter w; + FILE *fp=_wfopen(str2, L"wt"); + w.Open(fp, AutoCharFn(str2), TRUE); + BOOL ext; + Settings_GetBool(C_EXTRACT, EF_USEM3UEXT, &ext); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i] && m_rip_params->filenames[i]) + { + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->tracks[i])); + if (ext) + w.SetExtended(AutoCharFn(m_rip_params->filenames[i]), str.Get(), m_rip_params->lengths[i]); + else + w.SetFilename(AutoCharFn(m_rip_params->filenames[i])); + + } + } + w.Close(); + } + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEPLS, &bVal) && bVal) + { + char str2[MAX_PATH] = {0}; + lstrcpynA(str2, AutoChar(str), MAX_PATH); + StringCchCatA(str2, MAX_PATH, ".pls"); + createDirForFile(str2); + // TODO: check for bad unicode conversion + PLSWriter w; + w.Open(str2); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i] && m_rip_params->filenames[i]) + { + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->tracks[i])); + w.SetFilename(AutoCharFn(m_rip_params->filenames[i])); + w.SetTitle(str.Get()); + w.SetLength(m_rip_params->lengths[i]); + w.Next(); + } + } + w.Close(); + } + } + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEMLPL, &bVal) && bVal) + { + itemRecordListW irl = {0, }; + allocRecordList(&irl, m_rip_params->ntracks, 0); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i]) + { + int n = irl.Size; + memset(&irl.Items[n], 0, sizeof(itemRecordW)); + irl.Items[n].filename = _wcsdup(m_rip_params->filenames[i]); + irl.Items[n].album = _wcsdup(m_rip_params->album); + irl.Items[n].artist = _wcsdup(m_rip_params->artist); + irl.Items[n].title = _wcsdup(m_rip_params->tracks[i]); + irl.Items[n].genre = _wcsdup(m_rip_params->genre); + irl.Items[n].year = _wtoi(m_rip_params->year); + irl.Items[n].length = m_rip_params->lengths[i]; + irl.Size++; + } + } + + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->album)); + AutoWide name(str.Get()); + mlMakePlaylist pl = {sizeof(mlMakePlaylist), (const wchar_t*)name, ML_TYPE_ITEMRECORDLISTW, (void *) & irl, 0x01}; + SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&pl, ML_IPC_PLAYLIST_MAKE); + freeRecordList(&irl); + } + } // playlist creation + + if (rgThread) + QueueUserAPC(WriteGain, rgThread, 0); + else + PostMessage(m_extract_wnd, WM_APP + 4, 0, 0); + } + } + break; + case WM_APP + 4: + if (m_db_has_upd) + { + // TODO: benski> does mldb read metadata from this call or the 'add' call - because it won't have replaygain tags until now + PostMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB); + } + + m_rip_done = 1; + if (g_config->ReadInt(L"cdripautoclose", 1)) + { + DestroyWindow(hwndDlg); + } + else + { + SetWindowText(hwndDlg, WASABI_API_LNGSTRINGW(done > 0 ? IDS_RIP_COMPLETE : IDS_RIP_FAILED)); + SetDlgItemText(hwndDlg, IDC_BUTTON1, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + if (m_hwndstatus) + { + SetDlgItemText(m_hwndstatus, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + } + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETPOS, 100, 0); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETPOS, 100, 0); + + + int now = m_pstat_timedone; + + int bytesout = m_pstat_bytesout; + + double extracted_time = (double) m_pstat_bytesdone * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + + int br = (int) (((double)bytesout * 8.0 / extracted_time) / 1000.0 + 0.5); + + if (done > 0) + { + wchar_t sstr[16] = {0}; + StringCchPrintf(m_last_total_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_TRACKS_RIPPED_IN_X), + m_extract_nb_total, + WASABI_API_LNGSTRINGW_BUF(m_extract_nb_total == 1 ? IDS_TRACK : IDS_TRACKS,sstr,16), + now / 1000 / 60, (now / 1000) % 60, + extracted_time / (now / 1000.0), + br, (double)bytesout * (1.0 / (1024.0*1024.0)) + ); + } + else + { + WASABI_API_LNGSTRINGW_BUF(IDS_RIP_FAILED,m_last_total_status,512); + } + + SetDlgItemText(hwndDlg, IDC_STATUS2, m_last_total_status); + SetDlgItemText(hwndDlg, IDC_CURTRACK, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + SetDlgItemText(hwndDlg, IDC_STATUS, L""); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + SetDlgItemText(m_hwndstatus, IDC_CDINFO, m_last_total_status); + SetDlgItemText(m_hwndstatus, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_DONE)); + } + } + break; + case WM_WA_IPC: + switch (lParam) + { + case IPC_CB_CONVERT_STATUS: + { + if (!m_extract_time) + { + m_extract_time = GetTickCount(); + break; + } + DWORD now = GetTickCount() - m_extract_time; + if (!now) now = 1000; //safety + wchar_t tmp[512 + 128] = {0}; + + { + int total_t = 0; + if (wParam) total_t = MulDiv(100, now, (int)wParam); + int rem_t = total_t - now; + + double extracted_time = (double) m_fcs.bytes_done * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + int br = (int) (((double)m_fcs.bytes_out * 8.0 / extracted_time) / 1000.0 + 0.5); + + int estsize = 0; + if (m_fcs.bytes_total > 0) estsize = MulDiv(m_fcs.bytes_out, m_fcs.bytes_total, m_fcs.bytes_done); + + if (rem_t < 0) rem_t = 0; + if (total_t < 0) total_t = 0; + + StringCchPrintf(tmp, 640, + WASABI_API_LNGSTRINGW(IDS_ELAPSED_X_REMAINING_X_TOTAL_X), + now / 1000 / 60, (now / 1000) % 60, + rem_t / 1000 / 60, (rem_t / 1000) % 60, + total_t / 1000 / 60, (total_t / 1000) % 60, + extracted_time / ((double)now / 1000.0), + br, (double)estsize * (1.0 / (1024.0*1024.0)) + ); + SetDlgItemText(hwndDlg, IDC_STATUS, tmp); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + StringCchPrintf(m_last_item_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_KBPS_AT_X_REALTIME), + wParam, + br, + extracted_time / ((double)now / 1000.0) + ); + m_statuslist.SetItemText(m_extract_nb, 3, m_last_item_status); + } + } + + { + int total_in_bytes_calc = m_rip_params->total_length_bytes; + + now += m_pstat_timedone; + + int total_t = 0; + int bytesdone = m_fcs.bytes_done + m_pstat_bytesdone; + int bytesout = m_fcs.bytes_out + m_pstat_bytesout; + if (bytesdone) total_t = MulDiv(total_in_bytes_calc, now, bytesdone); + + int rem_t = total_t - now; + + double extracted_time = (double) bytesdone * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + int br = (int) (((double)bytesout * 8.0 / extracted_time) / 1000.0 + 0.5); + + int estsize = 0; + if (total_in_bytes_calc > 0) estsize = MulDiv(bytesout, total_in_bytes_calc, bytesdone); + + if (rem_t < 0) rem_t = 0; + if (total_t < 0) total_t = 0; + + StringCchPrintf(m_last_total_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_OF_X_ELAPSED_X_REMAINING_X), + m_extract_nb + 1, m_extract_nb_total, + now / 1000 / 60, (now / 1000) % 60, + rem_t / 1000 / 60, (rem_t / 1000) % 60, + total_t / 1000 / 60, (total_t / 1000) % 60, + extracted_time / ((double)now / 1000.0), + br, (double)estsize * (1.0 / (1024.0*1024.0)) + ); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + SetDlgItemText(m_hwndstatus, IDC_CDINFO, m_last_total_status); + } + SetDlgItemText(hwndDlg, IDC_STATUS2, m_last_total_status); + + int a = 0; + if (total_in_bytes_calc) a = MulDiv(bytesdone, 100, total_in_bytes_calc); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETPOS, a, 0); + + StringCchPrintf(tmp, 640, WASABI_API_LNGSTRINGW(IDS_X_PERCENT_RIPPING_FROM_CD), a); + SetWindowText(hwndDlg, tmp); + } + + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETPOS, wParam, 0); + } + break; + case IPC_CB_CONVERT_DONE: + + SendMessage(plugin.hwndWinampParent , WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW_END); + free(m_fcs.destfile); + m_pstat_bytesdone += m_fcs.bytes_done; + m_pstat_bytesout += m_fcs.bytes_out; + if (m_extract_time) m_pstat_timedone += GetTickCount() - m_extract_time; + + CopyFileW(m_rip_params->tempFilenames[m_extract_curtrack], m_rip_params->filenames[m_extract_curtrack], FALSE); + DeleteFileW(m_rip_params->tempFilenames[m_extract_curtrack]); + if (AGAVE_API_STATS) + { + AGAVE_API_STATS->IncrementStat(api_stats::RIP_COUNT); + AGAVE_API_STATS->SetStat(api_stats::RIP_FORMAT, m_fcs.destformat[0]); + } + wchar_t *lastfn = m_rip_params->filenames[m_extract_curtrack]; + + if (g_config->ReadInt(L"extracttag", 1)) + { + // add metadata to this file + if (updateFileInfoW(lastfn, L"title", m_rip_params->tracks[m_extract_curtrack])) + { + updateFileInfoW(lastfn, L"conductor", m_rip_params->conductors[m_extract_curtrack]); + updateFileInfoW(lastfn, L"composer", m_rip_params->composers[m_extract_curtrack]); + updateFileInfoW(lastfn, L"GracenoteFileID", m_rip_params->gracenoteFileIDs[m_extract_curtrack]); + updateFileInfoW(lastfn, L"GracenoteExtData", m_rip_params->gracenoteExtData[m_extract_curtrack]); + updateFileInfoW(lastfn, L"artist", m_rip_params->trackArtists[m_extract_curtrack]); + //if (lstrcmpiW(m_rip_params->trackArtists[m_extract_curtrack], m_rip_params->artist)) // only write albumartist if they're different + updateFileInfoW(lastfn, L"albumartist", m_rip_params->artist); + updateFileInfoW(lastfn, L"album", m_rip_params->album); + updateFileInfoW(lastfn, L"genre", m_rip_params->genre); + updateFileInfoW(lastfn, L"year", m_rip_params->year); + updateFileInfoW(lastfn, L"disc", m_rip_params->disc); + updateFileInfoW(lastfn, L"publisher", m_rip_params->publisher); + if (m_rip_params->comment && m_rip_params->comment[0]) + updateFileInfoW(lastfn, L"comment", m_rip_params->comment); + else + { + TCHAR szComment[8192] = {0}; + Settings_ReadString(C_EXTRACT, EF_COMMENTTEXT, szComment, ARRAYSIZE(szComment)); + updateFileInfoW(lastfn, L"comment", szComment); + } + + wchar_t buf[32] = {0}; + if (m_extract_curtrack >= 0) + { + if (g_config->ReadInt(L"total_tracks", 0)) + StringCchPrintfW(buf, 32, L"%d/%d", m_extract_curtrack + g_config->ReadInt(L"trackoffs", 1), m_rip_params->ntracks); + else + StringCchPrintfW(buf, 32, L"%d", m_extract_curtrack + g_config->ReadInt(L"trackoffs", 1)); + } + else buf[0] = 0; + updateFileInfoW(lastfn, L"track", buf); + + if (WASABI_API_APP) + updateFileInfoW(lastfn, L"tool", WASABI_API_APP->main_getVersionString()); + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITE_EXTENDED_FILE_INFO); + } + } + + if (g_config->ReadInt(L"extractaddml", 1)) + { + LMDB_FILE_ADD_INFOW fi = {lastfn, -1, -1}; + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi); + m_db_has_upd = 1; + } + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + m_statuslist.SetItemText(m_extract_nb, 3, WASABI_API_LNGSTRING(IDS_WAITING)); + } + + if (rgThread) + QueueUserAPC(CalculateGain, rgThread, (ULONG_PTR)_wcsdup(lastfn)); + else + PostMessage(m_extract_wnd, WM_APP + 3, 0, 0); + + + m_extract_nb++; + m_extracting = 0; + PostMessage(hwndDlg, WM_APP + 1, 0, 0); + break; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_BUTTON1: + { + wchar_t title[64] = {0}; + if (m_rip_done || + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_CANCEL_RIP), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP_QUESTION,title,64), + MB_YESNO | MB_ICONQUESTION) == IDYES) + { + LockCD(m_rip_params->drive_letter, FALSE); + DestroyWindow(hwndDlg); + } + return 0; + } + case IDCANCEL: + g_config->WriteInt(L"cdripstatuswnd", 0); + ShowWindow(hwndDlg, SW_HIDE); + break; + } + break; + case WM_CLOSE: + return 0; + case WM_DESTROY: + if (m_extracting) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW_END); + // make sure we clean up on cancel! + m_extracting = 0; + DeleteFileW(m_rip_params->tempFilenames[m_extract_curtrack]); + } + if (uMsgRipperNotify) SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, (WPARAM)(m_rip_params) ? m_rip_params->drive_letter : 0, (LPARAM)FALSE); + if (m_rip_params) + { + int i; + for (i = 0; i < m_rip_params->ntracks; i++) + { + free(m_rip_params->tracks[i]); + free(m_rip_params->trackArtists[i]); + free(m_rip_params->composers[i]); + free(m_rip_params->gracenoteFileIDs[i]); + free(m_rip_params->gracenoteExtData[i]); + free(m_rip_params->conductors[i]); + free(m_rip_params->filenames[i]); + free(m_rip_params->tempFilenames[i]); + } + free(m_rip_params->gracenoteFileIDs); + free(m_rip_params->gracenoteExtData); + free(m_rip_params->composers); + free(m_rip_params->conductors); + free(m_rip_params->tracks); + free(m_rip_params->trackArtists); + free(m_rip_params->filenames); + free(m_rip_params->tempFilenames); + free(m_rip_params->lengths); + + free(m_rip_params->album); + free(m_rip_params->artist); + free(m_rip_params->genre); + free(m_rip_params->year); + free(m_rip_params->publisher); + free(m_rip_params->comment); + free(m_rip_params->disc); + + free(m_rip_params); + m_rip_params = 0; + } + m_extract_wnd = 0; + + if (rgThread) + QueueUserAPC(CloseGain, rgThread, 0); + + break; + } + return 0; +} + +void cdrip_stop_all_extracts() +{ + if (m_rip_params) LockCD(m_rip_params->drive_letter, FALSE); + if (m_extract_wnd) DestroyWindow(m_extract_wnd); + if (m_hwndstatus) DestroyWindow(m_hwndstatus); +} + +int cdrip_isextracting(char drive) +{ + if (!m_rip_params) return 0; + if (drive == -1 && m_rip_done) + { + if (m_extract_wnd && IsWindow(m_extract_wnd)) DestroyWindow(m_extract_wnd); + if (m_hwndstatus && IsWindow(m_hwndstatus)) DestroyWindow(m_hwndstatus); + return 0; + } + if (drive == 0 || drive == -1) return toupper(m_rip_params->drive_letter); + return toupper(m_rip_params->drive_letter) == toupper(drive); +} + +HWND cdrip_FindBurningHWND(char cLetter) +{ + HWND h = 0; + while (NULL != (h = FindWindowExW(NULL, h, L"#32770", NULL))) + { + if (!GetPropW(h, L"WARIPPER")) continue; + if (((char)(INT_PTR)GetPropW(h, L"DRIVE")) == cLetter) return h; + } + return NULL; +} + +void cdrip_extractFiles(cdrip_params *parms) +{ + WASABI_API_LNGSTRINGW_BUF(IDS_INITIALIZING,m_last_total_status,512); + m_last_item_status[0] = 0; + m_rip_params = parms; + WASABI_API_CREATEDIALOGW(IDD_VIEW_CDROM_EXTRACT, plugin.hwndWinampParent, extract_dialogProc); +}
\ No newline at end of file |