diff options
Diffstat (limited to 'Src/Plugins/Input/in_cdda')
60 files changed, 17913 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_cdda/AUDIO.Cpp b/Src/Plugins/Input/in_cdda/AUDIO.Cpp new file mode 100644 index 00000000..6d378ecd --- /dev/null +++ b/Src/Plugins/Input/in_cdda/AUDIO.Cpp @@ -0,0 +1,112 @@ +#include <windows.h> +#include "Audio.h" +#include "main.h" +#include "api__in_cdda.h" + +static int start_clock,paused; +static HWAVEIN hWaveIn; +static short data_latest[576*2]; +static short data_buffers[2][576*2]; +static WAVEHDR wave_hdrs[2]; +static HANDLE hThread; +static DWORD WINAPI Thread(LPVOID _a); +int a_v = -666, a_p = 0, initted = 0; + +int audioInit(/*int sample*/) +{ + WAVEFORMATEX wft = {0}; + DWORD threadid; + start_clock=GetTickCount(); + paused=0; +// if (!sample) return initted=0; + wft.wFormatTag = WAVE_FORMAT_PCM; + wft.nChannels = 2; + wft.nSamplesPerSec = 44100; + wft.nBlockAlign = 2*2; + wft.nAvgBytesPerSec = wft.nSamplesPerSec*wft.nBlockAlign; + wft.wBitsPerSample = 16; + wft.cbSize = 0; + if (waveInOpen(&hWaveIn,WAVE_MAPPER,&wft,0,0,0) != MMSYSERR_NOERROR) + { + return 1; + } + for (int x = 0; x < 2; x ++) + { + memset(&wave_hdrs[x],0,sizeof(wave_hdrs[x])); + wave_hdrs[x].lpData = (char *) data_buffers[x]; + wave_hdrs[x].dwBufferLength = 576*2*sizeof(short); + waveInPrepareHeader(hWaveIn,&wave_hdrs[x],sizeof(wave_hdrs[0])); + waveInAddBuffer(hWaveIn,&wave_hdrs[x],sizeof(wave_hdrs[0])); + } + initted=1; + done=0; + waveInStart(hWaveIn); + hThread = CreateThread(NULL,0,Thread,(LPVOID)&done,0,&threadid); + SetThreadPriority(hThread, (int)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST)); + return 0; +} + +void audioPause(int s) +{ + if (s) + { + if (!paused) + { + paused=1; + if (initted) waveInStop(hWaveIn); + start_clock = GetTickCount()-start_clock; + } + } + else + { + if (paused) + { + if (initted) waveInStart(hWaveIn); + start_clock=GetTickCount()-start_clock; + paused=0; + } + } +} + +void audioQuit() +{ + if (!initted) return; + done=1; + WaitForSingleObject(hThread,INFINITE); + waveInStop(hWaveIn); + waveInReset(hWaveIn); + while (waveInClose(hWaveIn) == WAVERR_STILLPLAYING) Sleep(10); + CloseHandle(hThread); +} + +int audioGetPos() +{ + if (paused) return start_clock; + return GetTickCount()-start_clock; +} + + +void audioSetPos(int ms) +{ + start_clock = GetTickCount()-ms; +} + +static DWORD WINAPI Thread(LPVOID _a) +{ + volatile int *a = (volatile int *)_a; + int w; + while (!*a) + { + Sleep(576000/44100); + if (wave_hdrs[0].dwFlags & WHDR_DONE) w=0; + else if (wave_hdrs[1].dwFlags & WHDR_DONE) w=1; + else continue; + memcpy(data_latest,wave_hdrs[w].lpData,576*2*sizeof(short)); + wave_hdrs[w].dwFlags=WHDR_PREPARED; + waveInAddBuffer(hWaveIn,&wave_hdrs[w],sizeof(wave_hdrs[0])); +// memset(data_latest,0,576*2*sizeof(short)); + line.VSAAddPCMData(data_latest,2,16,0); + line.SAAddPCMData(data_latest,2,16,0); + } + return 0; +} diff --git a/Src/Plugins/Input/in_cdda/AUDIO.H b/Src/Plugins/Input/in_cdda/AUDIO.H new file mode 100644 index 00000000..9d2c65db --- /dev/null +++ b/Src/Plugins/Input/in_cdda/AUDIO.H @@ -0,0 +1,6 @@ +int audioInit(/*int*/); +int audioGetPos(); +void audioSetPos(int ms); +void audioGetWaveform(unsigned short data[576*2]); +void audioQuit(); +void audioPause(int s); diff --git a/Src/Plugins/Input/in_cdda/CDDB.Cpp b/Src/Plugins/Input/in_cdda/CDDB.Cpp new file mode 100644 index 00000000..626cc329 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDDB.Cpp @@ -0,0 +1,1709 @@ +#include "main.h" +#include "api__in_cdda.h" + +#include "cddbinterface.h" +#include "cddb.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoChar.h" +#include "../winamp/wa_ipc.h" +#include "../nu/ns_wc.h" +#include ".\cddbevnt.h" +#include ".\cddbui.h" +#include ".\grabwnd.h" +#include <api/application/api_application.h> +#include <atlbase.h> +#include "../nde/ndestring.h" +#include "../Winamp/buildtype.h" +#include <commctrl.h> +#include <strsafe.h> + +// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C} +static const GUID internetConfigGroupGUID = + { 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } }; + +TRACKINFO::~TRACKINFO() +{ + Reset(); +} + +void TRACKINFO::Reset() +{ +ndestring_release(artist); + artist=0; + ndestring_release(title); + title=0; + ndestring_release(tagID); + tagID=0; + ndestring_release(composer); + composer=0; + ndestring_release(conductor); + conductor=0; + ndestring_release(extData); + extData=0; + ndestring_release(remixing); + remixing=0; + ndestring_release(isrc); + isrc=0; +} + +TRACKINFO::TRACKINFO(const TRACKINFO ©) +{ + operator =(copy); +} + +TRACKINFO &TRACKINFO::operator =(const TRACKINFO ©) +{ + ndestring_retain(artist=copy.artist); + ndestring_retain(title=copy.title); + ndestring_retain(tagID=copy.tagID); + ndestring_retain(composer=copy.composer); + ndestring_retain(conductor=copy.conductor); + ndestring_retain(extData=copy.extData); + ndestring_retain(remixing=copy.remixing); + ndestring_retain(isrc=copy.isrc); + return *this; +} + +void DINFO::Reset() +{ + ndestring_release(title); + title=0; + ndestring_release(artist); + artist=0; + ndestring_release(tuid); + tuid=0; + ndestring_release(year); + year=0; + ndestring_release(genre); + genre=0; + ndestring_release(label); + label=0; + ndestring_release(notes); + notes=0; + ndestring_release(conductor); + conductor=0; + ndestring_release(composer); + composer=0; + ndestring_release(remixing); + remixing=0; + discnum=0; + numdiscs=0; +} + +DINFO::~DINFO() +{ + Reset(); +} + +DINFO::DINFO(const DINFO ©) +{ + operator =(copy); +} + +DINFO &DINFO::operator =(const DINFO ©) +{ + ndestring_retain(title=copy.title); + ndestring_retain(artist=copy.artist); + ndestring_retain(tuid=copy.tuid); + ndestring_retain(year=copy.year); + ndestring_retain(genre=copy.genre); + ndestring_retain(label=copy.label); + ndestring_retain(notes=copy.notes); + compilation=copy.compilation; + discnum=copy.discnum; + numdiscs=copy.numdiscs; + ntracks=copy.ntracks; + ndestring_retain(conductor=copy.conductor); + ndestring_retain(composer=copy.composer); + ndestring_retain(remixing=copy.remixing); + for (int i=0;i<sizeof(tracks)/sizeof(*tracks);i++) + tracks[i]=copy.tracks[i]; + + CDDBID=copy.CDDBID; + memcpy(pnFrames, copy.pnFrames, sizeof(pnFrames)); + nDiscLength=copy.nDiscLength; + + populated=copy.populated; + return *this; +} + + +#define TM_INVOKERESULTS (WM_APP + 222) +#define TM_UNINITTHREAD (WM_APP + 2) + +#define CENTER_PARENT (-32000) +#define CENTER_LEFT 0x0001 +#define CENTER_TOP 0x0002 + +#define WASABI_WND_CLASSW L"BaseWindow_RootWnd" + +#define INVARIANT_LCID MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +typedef struct _MEDIALOOKUP +{ + HRESULT result; + HWND hwndInfo; + CDDB_CB callback; + ULONG_PTR user; + UINT flags; + BSTR bstrTOC; + DWORD threadId; +} MEDIALOOKUP; + +typedef struct _THREADDATA +{ + LONG ref; + HHOOK hhook; + BOOL uninitCom; +} THREADDATA; + +CRITICAL_SECTION lockThread; + +typedef struct _INVOKEDATA +{ + MEDIALOOKUP lookup; + ICddbDisc *pDisc; + HANDLE evntDone; + DWORD *pdwAutoCloseDelay; +} INVOKEDATA; + +static DWORD tlsSlot = TLS_OUT_OF_INDEXES; +#ifndef IGNORE_API_GRACENOTE +ICDDBControl *pCDDBControl=0; +static CDBBEventManager eventMngr; +#endif +static MEDIALOOKUP g_lookup = {0, 0, }; +static HANDLE evntBusy = NULL; +static LONG evntBusyRef = 0; +static HWND hwndProgressListener = NULL; +static ICddbDisc *pSubmitDisc = NULL; +static POINT g_lastcddbpos = { CENTER_PARENT, CENTER_PARENT}; // center + + +static HRESULT SetupCDDB(BOOL resetError); +static void CALLBACK Cddb_OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData, UINT_PTR user); +static void CALLBACK Cddb_OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal, UINT_PTR user); +#ifndef IGNORE_API_GRACENOTE +static void Cddb_OnMediaLookupCompleted(HRESULT hr, CDDBMatchCode matchCode, MEDIALOOKUP *pLookup); +static void Cddb_OnGetFullDiscInfoCompleted(HRESULT hr, ICddbDisc *pDisc, MEDIALOOKUP *pLookup); +static void Cddb_OnSubmitDiscCompleted(HRESULT result, MEDIALOOKUP *pLookup); + +static HRESULT Cddb_DoFuzzyMatchDlg(HWND hwndCaller, UINT flags, ICddbDiscs *pDiscs, LONG *plVal); +static HRESULT Cddb_DoSubmitNewDlg(HWND hwndCaller, LPCWSTR pszTOC, UINT flags, ICddbDisc **ppDisc); + +#define CLEARLOOKUP() SecureZeroMemory(&g_lookup, sizeof(MEDIALOOKUP)) +#define IS_BUSY(__timeout) (evntBusy && (WAIT_OBJECT_0 == WaitForSingleObject(evntBusy, (__timeout)))) +#define SET_BUSY(__enable) ((__enable) ? (SetEvent(evntBusy)) : ResetEvent(evntBusy)) + +void ShutDownCDDB() +{ + if (pCDDBControl) + { + eventMngr.Unadvise(pCDDBControl); + pCDDBControl->Release(); + pCDDBControl=0; + } +} +#endif + +static HWND GetAdaptedParent(HWND hwndParent) +{ + if (!hwndParent || !IsWindow(hwndParent)) hwndParent = line.hMainWindow; + if (!hwndParent || !IsWindow(hwndParent)) hwndParent = GetDesktopWindow(); + if (hwndParent == line.hMainWindow) + { + hwndParent = (HWND)SendMessageW(line.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT); + if (!IsWindow(hwndParent)) hwndParent = line.hMainWindow; + } + return hwndParent; +} + +static BOOL CalculatePopUpPos(RECT *prcParent, RECT *prcPopUp, UINT flags) +{ + LONG x, y; + MONITORINFO mi; + if (!prcPopUp) return FALSE; + + if (prcParent) + { + x = prcParent->left; + y = prcParent->top; + + OffsetRect(prcPopUp, -prcPopUp->left, -prcPopUp->top); + OffsetRect(prcParent, -prcParent->left, -prcParent->top); + if (CENTER_LEFT & flags) x += (prcParent->right - prcPopUp->right)/2; + if (CENTER_TOP & flags) y += (prcParent->bottom - prcPopUp->bottom )/2; + + SetRect(prcPopUp, x, y, x + prcPopUp->right, y + prcPopUp->bottom); + } + mi.cbSize = sizeof(MONITORINFO); + HMONITOR hMonitor = MonitorFromRect(prcPopUp, MONITOR_DEFAULTTONULL); + if (!hMonitor) + { + OffsetRect(prcPopUp, -prcPopUp->left, -prcPopUp->top); + hMonitor = MonitorFromRect(prcPopUp, MONITOR_DEFAULTTONEAREST); + + if(GetMonitorInfo(hMonitor, &mi)) + { + x = mi.rcWork.left + ((mi.rcWork.right - mi.rcWork.left) - prcPopUp->right)/2; + if(x < mi.rcWork.left) x = mi.rcWork.left; + y = mi.rcWork.top + ((mi.rcWork.bottom - mi.rcWork.top) - prcPopUp->bottom)/2; + if(y < mi.rcWork.top) y = mi.rcWork.top; + SetRect(prcPopUp, x, y, x + prcPopUp->right, y + prcPopUp->bottom); + } + } + else + { + if(GetMonitorInfo(hMonitor, &mi)) + { + if (prcPopUp->right > mi.rcWork.right) + { + OffsetRect(prcPopUp, mi.rcWork.right - prcPopUp->right, 0); + } + } + } + return TRUE; +} + +static BOOL SetPopUpPos(HWND hwnd, UINT flags) +{ + RECT rc, rw; + + if (!hwnd) return FALSE; + + HWND hwndParent = GetParent(hwnd); + hwndParent = GetAdaptedParent(hwndParent); + + if (GetClientRect(hwndParent, &rc) && GetWindowRect(hwnd, &rw)) + { + HWND hwndFound; + wchar_t szClass[2048] = {0}; + UINT flags = CENTER_LEFT; + + MapWindowPoints(hwndParent, HWND_DESKTOP, (POINT*)&rc, 2); + + if (hwndParent == line.hMainWindow || + (GetClassNameW(hwndParent, szClass, sizeof(szClass)/sizeof(wchar_t)) && + CSTR_EQUAL == CompareStringW(INVARIANT_LCID, 0, szClass, -1, WASABI_WND_CLASSW, -1) && + NULL != (hwndFound = FindWindowEx(NULL, hwndParent, WASABI_WND_CLASSW, NULL))) + && IsWindowVisible(hwndFound)) + { + OffsetRect(&rc, (rc.right - rc.left + 4), 0); + flags &= ~ CENTER_LEFT; + } + if (CalculatePopUpPos(&rc, &rw, flags)) + { + SetWindowPos(hwnd, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE); + } + } + return TRUE; +} + +static void Cddb_ProcessResult(MEDIALOOKUP *pLookup, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay) +{ + if (pLookup && pLookup->callback) pLookup->callback(pLookup->result, pDisc, pdwAutoCloseDelay, pLookup->user); +} + +static void CALLBACK Execute_ProcessResult(INVOKEDATA *pData) +{ + #ifndef IGNORE_API_GRACENOTE + INVOKEDATA data; + + if (!pData) return; + + CopyMemory(&data, &pData->lookup, sizeof(INVOKEDATA)); + if (data.pDisc) + data.pDisc->AddRef(); + + Cddb_ProcessResult(&data.lookup, data.pDisc, data.pdwAutoCloseDelay); + if (data.pDisc) + data.pDisc->Release(); + if (data.evntDone) + SetEvent(data.evntDone); + #endif +} + +static LRESULT CALLBACK HookMessageProc(int code, WPARAM wParam, LPARAM lParam) +{ + THREADDATA *pData; + + if (TLS_OUT_OF_INDEXES == tlsSlot) return 0; + pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (!pData) return 0; + + if (code < 0) return CallNextHookEx(pData->hhook, code, wParam, lParam); + + if (NULL == ((MSG*)lParam)->hwnd) // thread message + { + switch(((MSG*)lParam)->message) + { + case TM_INVOKERESULTS: + Execute_ProcessResult((INVOKEDATA*)((MSG*)lParam)->lParam); + return TRUE; + case TM_UNINITTHREAD: + Cddb_UninitializeThread(); + return TRUE; + } + } + + return CallNextHookEx(pData->hhook, code, wParam, lParam); +} + +void Cddb_Initialize(void) +{ + InitializeCriticalSection(&lockThread); +} + +void Cddb_Uninitialize(void) +{ + DeleteCriticalSection(&lockThread); +} + +static HRESULT Cddb_IsThreadInitialized(void) +{ + THREADDATA *pData; + if (TLS_OUT_OF_INDEXES == tlsSlot) return E_OUTOFMEMORY; + pData = (THREADDATA*)TlsGetValue(tlsSlot); + return (pData) ? S_OK : S_FALSE; +} + +static HANDLE GetMainThreadHandle(void) +{ + HANDLE hThread = NULL; + api_application *pApp = NULL; + waServiceFactory *sf = NULL; + + if (!line.service) return NULL; + if (NULL == (sf = line.service->service_getServiceByGuid(applicationApiServiceGuid))) return NULL; + if (NULL == (pApp = (api_application*)sf->getInterface())) { return NULL; } + + hThread = pApp->main_getMainThreadHandle(); + sf->releaseInterface(pApp); + + return hThread; +} + +static HRESULT Cddb_InvokeProcessResult(MEDIALOOKUP *pLookup, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay) +{ + HRESULT hr = E_FAIL; + #ifndef IGNORE_API_GRACENOTE + INVOKEDATA data; + if (!pLookup) return E_INVALIDARG; + CopyMemory(&data.lookup, pLookup, sizeof(MEDIALOOKUP)); + data.pDisc = pDisc; + data.pdwAutoCloseDelay = pdwAutoCloseDelay; + if (NULL != pDisc) + pDisc->AddRef(); + + if (!data.lookup.threadId) data.lookup.threadId = GetWindowThreadProcessId(line.hMainWindow, NULL); + if (data.lookup.threadId != GetCurrentThreadId()) + { + data.evntDone = CreateEvent(NULL, FALSE, FALSE, NULL); + if (data.evntDone) + { + if (PostThreadMessage(data.lookup.threadId, TM_INVOKERESULTS, 0, (LPARAM)&data)) + { + MSG msg; + msg.message = NULL; + + for(;;) + { + DWORD status = MsgWaitForMultipleObjectsEx(1, &data.evntDone, + INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + + if (status == WAIT_OBJECT_0+1) + { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (WM_QUIT == msg.message) + { + break; + } + if (0 == CallMsgFilter(&msg, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + else if (status == WAIT_OBJECT_0) + { + break; + } + } + + if (WM_QUIT == msg.message) + PostQuitMessage((int)msg.wParam); + hr = S_OK; + } + CloseHandle(data.evntDone); + } + } + else + { + Cddb_ProcessResult(pLookup, pDisc, pdwAutoCloseDelay); + hr = S_OK; + } + + if (NULL != pDisc) + pDisc->Release(); + #endif + return hr; +} + +#ifndef IGNORE_API_GRACENOTE +bool GetRole(ICddbTrack *track, BSTR roleId, BSTR *str) +{ + if (!roleId || !*roleId) + return false; + + if (!track) + return false; + + ICddbCreditsPtr credits; + track->get_Credits(&credits); + if (credits) + { + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCreditPtr credit; + credits->GetCredit(c + 1, &credit); + if (credit) + { + BSTR thisRole; + credit->get_Id(&thisRole); + if (!wcscmp(thisRole, roleId)) + { + credit->get_Name(str); + return true; + } + } + } + } + return false; +} + +bool GetRole(ICddbDisc *track, BSTR roleId, BSTR *str) +{ + if (!roleId || !*roleId) + return false; + + if (!track) + return false; + + ICddbCreditsPtr credits; + track->get_Credits(&credits); + if (credits) + { + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCreditPtr credit; + credits->GetCredit(c + 1, &credit); + if (credit) + { + BSTR thisRole; + credit->get_Id(&thisRole); + if (!wcscmp(thisRole, roleId)) + { + credit->get_Name(str); + return true; + } + } + } + } + return false; +} +#endif + +HRESULT Cddb_InitializeThread(void) +{ + HRESULT hr = S_OK; + EnterCriticalSection(&lockThread); + + if (!evntBusy) + { + evntBusyRef = 0; + evntBusy = CreateEvent(NULL, TRUE, FALSE, NULL); + if (NULL == evntBusy) + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + evntBusyRef++; + + if (TLS_OUT_OF_INDEXES == tlsSlot && + TLS_OUT_OF_INDEXES == (tlsSlot = TlsAlloc())) + hr = E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + THREADDATA *pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (pData) + { + pData->ref++; + } + else + { + pData = (THREADDATA*)calloc(1, sizeof(THREADDATA)); + if (!pData) + { + hr = E_OUTOFMEMORY; + } + if (SUCCEEDED(hr)) + { + pData->hhook = SetWindowsHookExW(WH_MSGFILTER, HookMessageProc, NULL, GetCurrentThreadId()); + if (!pData->hhook || !TlsSetValue(tlsSlot, pData)) + { + if (pData->hhook) UnhookWindowsHookEx(pData->hhook); + free(pData); + pData = NULL; + hr = E_FAIL; + } + else + { + pData->ref = 1; + pData->uninitCom = (S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + hr = S_OK; + } + } + } + } + } + LeaveCriticalSection(&lockThread); + return hr; +} + +HRESULT Cddb_UninitializeThread(void) +{ + EnterCriticalSection(&lockThread); + + if (TLS_OUT_OF_INDEXES != tlsSlot) + { + THREADDATA *pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (NULL != pData && + pData->ref && 0 == --pData->ref) + { + TlsSetValue(tlsSlot, NULL); + if (pData->hhook) + UnhookWindowsHookEx(pData->hhook); + + if (pData->uninitCom) + CoUninitialize(); + + free(pData); + } + } + + if (evntBusyRef && 0 == --evntBusyRef) + { + CloseHandle(evntBusy); + evntBusy = NULL; + } + + LeaveCriticalSection(&lockThread); + return S_OK; +} + +LPCWSTR Cddb_CalculateTOC(DINFO *pDisc, LPWSTR pszTOC, size_t cchTOC) +{ + LPWSTR p; + if (!pszTOC || !pDisc || !cchTOC) return NULL; + pszTOC[0] = 0x00; + p = pszTOC; + for (int x = 0; x < pDisc->ntracks + 1; x++) + { + if (S_OK != StringCchPrintfExW(p, cchTOC, &p, &cchTOC, + STRSAFE_NULL_ON_FAILURE, L"%lu ", pDisc->pnFrames[x])) return NULL; + } + if (p != pszTOC) *(p - 1) = 0x00; + return pszTOC; +} + +// 2 author (???) +// 3 composer +// 6 lyricist +// 7 publisher (how is this different from label?) +// 9 songwriter (music & lyrics) +// 10 conductor/arranger +// 11 Arranger +// 12 Conductor +// 13 Director +// 72 Engineer +// 74 Mastering +// 75 Mastering Location +// 76 Mixing +// 77 Mixing Location +// 78 Producer +// 79 Programming (???) +// 80 Recording Location +// 147 remixer +#ifndef IGNORE_API_GRACENOTE +void GetDiscInfo(ICddbDiscPtr pDisc, DINFO *ps) +{ + CComBSTR str, disc_artist, disc_composer, disc_conductor, disc_remixing; + BSTR composerRole=L"3", conductorRole=L"12", remixingRole=L"147"; + + /* + for (int i=0;i<100;i++) + { + wchar_t id[256] = {0}; + _itow(i, id, 10); + ICddbRolePtr role; + pCDDBControl->GetRoleInfo(id, &role); + if (role) + { + BSTR name, description; + role->get_Name(&name); + role->get_Description(&description); + wchar_t str[4096] = {0}; + wsprintf(str, L"ID: %s\r\nName: %s\r\nDescription: %s\r\n", id, name, description); + MessageBoxW(NULL, str, L"CDDB Role", MB_OK); + } + } + */ + + ps->Reset(); + if (pDisc == NULL) // yikes! + return; + ICddbDisc2Ptr pDisc2; + pDisc->QueryInterface(&pDisc2); + + ICddbDisc2_5Ptr pDisc2_5; + pDisc->QueryInterface(&pDisc2_5); + + if (GetRole(pDisc, conductorRole, &disc_conductor) && disc_conductor && disc_conductor.m_str[0]) + ps->conductor = ndestring_wcsdup(disc_conductor.m_str); + + if (GetRole(pDisc, composerRole, &disc_composer) && disc_composer && disc_composer.m_str[0]) + ps->composer = ndestring_wcsdup(disc_composer.m_str); + + if (GetRole(pDisc, remixingRole, &disc_remixing) && disc_remixing && disc_remixing.m_str[0]) + ps->remixing = ndestring_wcsdup(disc_remixing.m_str); + + if (SUCCEEDED(pDisc->get_Artist(&disc_artist)) && disc_artist && disc_artist.m_str[0]) + ps->artist = ndestring_wcsdup(disc_artist.m_str); + + if (SUCCEEDED(pDisc->get_Year(&str)) && str && str.m_str[0]) + ps->year = ndestring_wcsdup(str.m_str); + + if (pDisc2_5 == NULL + || (FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(3, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(2, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(1, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimary(&str))) + ) + { + pDisc->get_GenreId(&str); + ICddbGenre *poop = 0; + if (SUCCEEDED(pCDDBControl->GetGenreInfo(str, &poop)) && poop) + { + poop->get_Name(&str); + poop->Release(); + } + else + str.Empty(); + } + if (str && str.m_str[0]) + ps->genre = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Title(&str)) && str && str.m_str[0]) + ps->title = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_TitleUId(&str)) && str && str.m_str[0]) + ps->tuid = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Label(&str)) && str && str.m_str[0]) + ps->label = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Notes(&str)) && str && str.m_str[0]) + ps->notes = ndestring_wcsdup(str.m_str); + + long val; + if (SUCCEEDED(pDisc->get_Compilation(&val))) + ps->compilation = !!val; + + if (SUCCEEDED(pDisc->get_TotalInSet(&str)) && str && str.m_str[0]) + ps->numdiscs = _wtoi(str.m_str); + + if (SUCCEEDED(pDisc->get_NumberInSet(&str)) && str && str.m_str[0]) + ps->discnum = _wtoi(str.m_str); + + for (int x = 0; x < ps->ntracks; x ++) + { + TRACKINFO &trackInfo = ps->tracks[x]; + ICddbTrack *t; + ICddbTrack2_5Ptr track2_5; + pDisc->GetTrack(x + 1, &t); + if (!t) break; + + t->QueryInterface(&track2_5); + + if (SUCCEEDED(t->get_Artist(&str)) && str && str.m_str[0] && (!disc_artist || !disc_artist.m_str[0] || wcscmp(str.m_str, disc_artist.m_str))) + trackInfo.artist = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(t->get_Title(&str)) && str && str.m_str[0]) + trackInfo.title = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(t->get_ISRC(&str)) && str && str.m_str[0]) + trackInfo.isrc = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pCDDBControl->GetDiscTagId(pDisc, x + 1, &str)) && str && str.m_str[0]) + trackInfo.tagID = ndestring_wcsdup(str.m_str); + + if (GetRole(t, conductorRole, &str) && str && str.m_str[0] && (!disc_conductor || !disc_conductor.m_str[0] || wcscmp(str.m_str, disc_conductor.m_str))) + trackInfo.conductor = ndestring_wcsdup(str.m_str); + + if (GetRole(t, composerRole, &str) && str && str.m_str[0] && (!disc_composer || !disc_composer.m_str[0] || wcscmp(str.m_str, disc_composer.m_str))) + trackInfo.composer = ndestring_wcsdup(str.m_str); + + if (GetRole(t, remixingRole, &str) && str && str.m_str[0] && (!disc_remixing || !disc_remixing.m_str[0] || wcscmp(str.m_str, disc_remixing.m_str))) + trackInfo.remixing = ndestring_wcsdup(str.m_str); + + if (track2_5 != NULL && (SUCCEEDED(track2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0]) // try track first + || (pDisc2_5 != NULL && SUCCEEDED(pDisc2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0])) // then disc + trackInfo.extData = ndestring_wcsdup(str.m_str); + + t->Release(); + } + + ps->populated = true; +} +#endif + +HRESULT Cddb_GetIUIOptions(void **ppUIOptions) +{ + HRESULT hr; + + if (!ppUIOptions) return E_INVALIDARG; + *ppUIOptions = NULL; + + hr = SetupCDDB(FALSE); + if (SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + hr = CoCreateInstance(CLSID_CddbUIOptions, NULL, + CLSCTX_INPROC_SERVER, IID_ICddbUIOptions, ppUIOptions); + #endif + } + return hr; +} + +HRESULT Cddb_GetIControl(void **ppControl) +{ + HRESULT hr; + + if (!ppControl) return E_INVALIDARG; + *ppControl = NULL; + + hr = SetupCDDB(FALSE); + if(SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + pCDDBControl->AddRef(); + *ppControl = pCDDBControl; + #endif + } + return hr; +} + +HRESULT Cddb_GetICacheManger(void **ppCache) +{ + HRESULT hr; + + if (!ppCache) return E_INVALIDARG; + *ppCache = NULL; + + hr = SetupCDDB(FALSE); + if (SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + hr = CoCreateInstance(CLSID_CddbCacheManager, NULL, + CLSCTX_INPROC_SERVER, IID_ICddbCacheManager, ppCache); + #endif + } + return hr; +} + +static HRESULT SetupCDDB(BOOL resetError) +{ + static HRESULT result(S_FALSE); + + #ifndef IGNORE_API_GRACENOTE + if (S_FALSE == result || (FAILED(result) && resetError)) + { + if (AGAVE_API_GRACENOTE) + pCDDBControl = AGAVE_API_GRACENOTE->GetCDDB(); + result = (NULL == pCDDBControl) ? CDDBCTLNotInitialized : S_OK; + if (SUCCEEDED(result)) + { + HRESULT hr; + ICddbOptionsPtr pOptions; + hr = pCDDBControl->GetOptions(&pOptions); + if (SUCCEEDED(hr)) + { + LONG lVal; + BOOL bUpdate(FALSE); + hr = pOptions->get_AsyncCompletion(&lVal); + if (SUCCEEDED(hr) && !lVal) { pOptions->put_AsyncCompletion(1); bUpdate = TRUE; } + hr = pOptions->get_ProgressEvents(&lVal); + if (SUCCEEDED(hr) && !lVal) { pOptions->put_ProgressEvents(1); bUpdate = TRUE; } + +#if defined(BETA) || defined(INTERNAL) || defined(NIGHT) + pOptions->put_TestSubmitMode(TRUE); // BETA +#endif + + if (bUpdate) pCDDBControl->SetOptions(pOptions); + } + if (SUCCEEDED(eventMngr.Advise(pCDDBControl))) + { + eventMngr.RegisterCallback(CDDB_CB_CMDCOMPLETED, Cddb_OnCommandCompleted); + eventMngr.RegisterCallback(CDDB_CB_CMDPROGRESS, Cddb_OnCommandProgress); + } + + } + } + #endif + return result; +} + +#ifndef IGNORE_API_GRACENOTE +HRESULT Cddb_GetDiscFromCache(BSTR bstrTOC, ICddbDisc **ppDisc) +{ + HRESULT hr; + ICddbCacheManager *pCache; + + if (!ppDisc) return E_INVALIDARG; + *ppDisc = NULL; + + if (!bstrTOC) return CDDB_E_BADTOC; + + hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + hr = pCache->FetchDiscByToc(bstrTOC, ppDisc); + pCache->Release(); + } + + return hr; +} +#endif + +static LRESULT CALLBACK DisplayDiscInfoWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + HWND hwndListener; + WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"WNDPROC"); + switch(uMsg) + { + case WM_INITDIALOG: + result = (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam); + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if (hwndListener) CddbProgressDlg_SetStatus(hwndListener, MAKEINTRESOURCEW(IDS_OPENING), -1); + return result; + case WM_DESTROY: + { + RemovePropW(hwnd, L"WNDPROC"); + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if (hwndListener) + { + RECT rc, rw; + if (GetWindowRect(hwndListener, &rc) && GetWindowRect(hwnd, &rw)) + { + CalculatePopUpPos(&rw, &rc, CENTER_LEFT); + SetWindowPos(hwndListener, NULL, rc.left, rc.top, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + } + } + HWND *list = (HWND*)GetPropW(hwnd, L"WNDLIST"); + RemovePropW(hwnd, L"WNDLIST"); + if (list) + { + for (HWND *p = list; *p != NULL; p++) ShowWindowAsync(*p, SW_SHOWNA); + free(list); + } + RemovePropW(hwnd, L"LISTENER"); + + if (fnOldProc) SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc); + } + break; + case WM_SHOWWINDOW: + if (wParam) + { + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if(hwndListener) + { + HWND *list = (HWND*)calloc(24, sizeof(HWND)); + if (!FindAllOwnedWindows(hwndListener, list, 24, 0) || !SetPropW(hwnd, L"WNDLIST", list)) free(list); + else for (HWND *p = list; *p != NULL; p++) ShowWindowAsync(*p, SW_HIDE); + ShowWindowAsync(hwndListener, SW_HIDE); + } + } + break; + } + + if (!fnOldProc) + { + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + return (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam); +} + +static void CALLBACK OnGrabbed_DisplayDiscInfo(HWND hwnd, CREATESTRUCT *lpcs, HWND *phwndInsertAfter, ULONG_PTR user) +{ + WNDPROC oldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)DisplayDiscInfoWndProc); + if (oldProc) + { + SetPropW(hwnd, L"WNDPROC", oldProc); + SetPropW(hwnd, L"LISTENER", (HANDLE)user); + } + if(user) + { + RECT rc, rw; + if (GetClientRect((HWND)user, &rc)) + { + MapWindowPoints((HWND)user, HWND_DESKTOP, (POINT*)&rc, 2); + SetRect(&rw, lpcs->x, lpcs->y, lpcs->x + lpcs->cx, lpcs->y + lpcs->cy); + CalculatePopUpPos(&rc, &rw, CENTER_LEFT); + lpcs->x = rw.left; + lpcs->y = rw.top; + } + } + else ShowWindow((HWND)user, SW_HIDE); +} + +void Cddb_GetResultText(HRESULT hr, LPWSTR pszResult, INT cchResult, LPWSTR pszReason, INT cchReason) +{ + INT nResult, nReason; + + nResult = (S_OK == hr) ? IDS_SUCCESS : IDS_NOT_FOUND; + nReason = 0; + + if (FAILED(hr)) + { + switch(hr) + { + #ifndef IGNORE_API_GRACENOTE + case CDDBCTLNotInitialized: nReason = IDS_CDDB_NOT_INSTALLED; break; + case CDDBCTLBusy: nReason = IDS_CDDB_E_BUSY; break; + case CDDB_E_BADTOC: nReason = IDS_CDDB_E_BADTOC; break; + case E_ABORT: + case CDDBTRNCancelled: + nReason = IDS_CDDB_E_ABORT; break; + #endif + default: nReason = IDS_CDDB_E_FAIL; break; + } + } + + if (pszReason && cchReason) + { + if(nReason) + { INT len; + WASABI_API_LNGSTRINGW_BUF(IDS_REASON, pszReason, cchReason); + len = lstrlenW(pszReason); + cchReason -= len; + WASABI_API_LNGSTRINGW_BUF(nReason, pszReason + len, cchReason); + } + else pszReason[0] = 0x00; + } + + if (pszResult && cchResult) + { + WASABI_API_LNGSTRINGW_BUF(nResult, pszResult, cchResult); + } +} + +static HRESULT Cddb_FinishLookup(MEDIALOOKUP *pLookup, ICddbDisc *pDisc) +{ + HRESULT hr = E_FAIL; + #ifndef IGNORE_API_GRACENOTE + MEDIALOOKUP lookup_cpy; + DWORD delay = AUTOCLOSE_NOW; + + if (!pLookup) hr = E_INVALIDARG; + if (!evntBusy) hr = E_FAIL; + else hr = S_OK; + + if (NULL != pDisc) + pDisc->AddRef(); + + if (NULL != pLookup) + { + CopyMemory(&lookup_cpy, pLookup, sizeof(MEDIALOOKUP)); + SecureZeroMemory(pLookup, sizeof(MEDIALOOKUP)); + } + else + SecureZeroMemory(&lookup_cpy, sizeof(MEDIALOOKUP)); + + if (SUCCEEDED(hr)) + { + HRESULT hrInvoke; + + if(S_OK != lookup_cpy.result) + { + if (NULL != pDisc) + pDisc->Release(); + + pDisc = NULL; + } + + if (lookup_cpy.hwndInfo) + { + CddbProgressDlg_SetExtendedMode(lookup_cpy.hwndInfo, FALSE); + CddbProgressDlg_EnableAbortButton(lookup_cpy.hwndInfo, FALSE); + CddbProgressDlg_SetStatus(lookup_cpy.hwndInfo, MAKEINTRESOURCEW(IDS_PROCESSING), -1); + } + + if (FAILED(lookup_cpy.result)) + delay = 5000; + + hrInvoke = Cddb_InvokeProcessResult(&lookup_cpy, pDisc, &delay); + if (FAILED(hrInvoke) && S_OK == lookup_cpy.result) + lookup_cpy.result = hrInvoke; + } + + SET_BUSY(FALSE); + + if (SUCCEEDED(hr)) + { + if (lookup_cpy.hwndInfo) + { + RECT rc; + if (GetWindowRect(lookup_cpy.hwndInfo, &rc)) + { + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + } + + lookup_cpy.result = Cddb_DisplayResultDlg(lookup_cpy.hwndInfo, lookup_cpy.result, delay, + CDDB_UI_USE_PARENT | lookup_cpy.flags); + if (delay > 10 && 0 == (CDDB_UI_RESULT_MODAL & lookup_cpy.flags) || FAILED(lookup_cpy.result)) + { + CddbProgressDlg_ExitModal(lookup_cpy.hwndInfo, lookup_cpy.result, FALSE); + } + } + hr = lookup_cpy.result; + } + + if (NULL != lookup_cpy.bstrTOC) + SysFreeString(lookup_cpy.bstrTOC); + + if (lookup_cpy.threadId == GetCurrentThreadId()) + Cddb_UninitializeThread(); + else + { + if (PostThreadMessage(lookup_cpy.threadId, TM_UNINITTHREAD, 0, 0L)) + { + /* MSG msg; + DWORD status; + msg.message = NULL; + for(;;) + { + status = MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (status == WAIT_OBJECT_0+1) + { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (WM_QUIT == msg.message) break; + if (!CallMsgFilter(&msg, 0)) DispatchMessage(&msg); + } + } + else if (status == WAIT_OBJECT_0) + { + break; + } + } + if (WM_QUIT == msg.message) PostQuitMessage((int)msg.wParam);*/ + } + } + + if (NULL != pDisc) + pDisc->Release(); + #endif + return hr; +} + +static void CALLBACK CddbProgressDlg_OnAbort(HWND hwndDlg, BSTR bstrUser) +{ + #ifndef IGNORE_API_GRACENOTE + ICDDBControl *pControl; + HRESULT hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + LONG lVal; + pControl->Cancel(&lVal); + CddbProgressDlg_EnableAbortButton(hwndDlg, FALSE); + pControl->Release(); + } + + //CddbProgressDlg_Completed(hwndDlg, L"Aborted !!!", 4600); + #endif +} + +typedef struct _MODALDATA +{ + ICddbDisc *pDisc; + UINT flags; + BSTR bstrTOC; + +} MODALDATA; + +#ifndef IGNORE_API_GRACENOTE +HRESULT Cddb_DisplayDiscInfo(ICddbDisc *pDisc, CDDBUIFlags *pUIFlags, HWND hwndParent) +{ + HRESULT hr; + ICDDBControl *pControl; + BOOL bManual = FALSE; + hr = Cddb_GetIControl((void**)&pControl); + if (FAILED(hr)) return hr; + + if (hwndParent) + { + if (!BeginGrabCreateWindow(L"#32770", NULL, NULL, OnGrabbed_DisplayDiscInfo, (ULONG_PTR)hwndParent)) + { + ShowWindow(hwndParent, SW_HIDE); + bManual = TRUE; + } + } + + hr = pControl->DisplayDiscInfo(pDisc, *pUIFlags, pUIFlags); + if (hwndParent) + { + EndGrabCreateWindow(); + if (bManual) ShowWindow(hwndParent, SW_SHOW); + } + + return hr; +} + +static void CALLBACK CddbProgressDlg_OnSubmitNew(HWND hwndDlg, BSTR bstrUser) +{ + HRESULT hr; + ICDDBControl *pControl; + CDDBUIFlags uiflags; + MODALDATA *pData; + wchar_t szText[256] = {0}; + + pData = (MODALDATA*)CddbProgressDlg_GetUserData(hwndDlg); + if (!pData) + { + CddbProgressDlg_ExitModal(hwndDlg, E_INVALIDARG, TRUE); + return; + } + + CddbProgressDlg_ShowButton1(hwndDlg, NULL, NULL, NULL); + + SetWindowText(hwndDlg, WASABI_API_LNGSTRINGW_BUF(IDS_SUBMITDISC_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndDlg, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(hwndDlg, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + hr = pControl->GetSubmitDisc(pData->bstrTOC, NULL, NULL, &pData->pDisc); + pControl->Release(); + } + + if (!pData->pDisc) + { + CddbProgressDlg_ExitModal(hwndDlg, hr, TRUE); + return; + } + + uiflags = (CDDBUIFlags)(UI_SUBMITNEW | UI_EDITMODE); + hr = Cddb_DisplayDiscInfo(pData->pDisc, &uiflags, hwndDlg); + + if (SUCCEEDED(hr) && (0 == ((uiflags & (UI_OK | UI_DATA_CHANGED)) == (UI_OK | UI_DATA_CHANGED)))) + hr = S_FALSE; + + if (S_OK != hr) + { + pData->pDisc->Release(); + pData->pDisc = NULL; + } + CddbProgressDlg_ExitModal(hwndDlg, hr, TRUE); + return; +} + +static void CALLBACK CddbProgressDlg_OnAcceptMatch(HWND hwndDlg, BSTR bstrUser) +{ + MODALDATA *pData; + pData = (MODALDATA*)CddbProgressDlg_GetUserData(hwndDlg); + if (!pData) + { + CddbProgressDlg_ExitModal(hwndDlg, E_INVALIDARG, TRUE); + return; + } + + pData->pDisc = (ICddbDisc*)(LONG_PTR)(LONG)(CddbProgressDlg_GetSelRecordIndex(hwndDlg) + 1); + CddbProgressDlg_ExitModal(hwndDlg, S_OK, TRUE); + return; +} +#endif + +HRESULT Cddb_DoLookup(LPCWSTR pszTOC, HWND hwndParent, CDDB_CB callback, UINT flags, ULONG_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + HRESULT hr; + + ICDDBControl *pControl; + CDDBMatchCode matchCode; + + if (!callback) return E_INVALIDARG; + + if (IS_BUSY(0)) + { + return (CSTR_EQUAL == CompareStringW(INVARIANT_LCID, 0, g_lookup.bstrTOC, -1, pszTOC, -1)) ? E_PENDING : CDDBCTLBusy; + } + + hr = Cddb_InitializeThread(); + if (FAILED(hr)) return hr; + + SET_BUSY(TRUE); + CLEARLOOKUP(); + + g_lookup.callback = callback; + g_lookup.user = user; + g_lookup.flags = flags; + g_lookup.threadId = GetCurrentThreadId(); + g_lookup.bstrTOC = SysAllocString(pszTOC); + eventMngr.SetUserParam((ULONG_PTR)&g_lookup); + + if (0 == (CDDB_NOCACHE & flags)) + { + ICddbDisc *pDisc; + g_lookup.result = Cddb_GetDiscFromCache(g_lookup.bstrTOC, &pDisc); + if (CDDBTRNDataStoreNotCached != g_lookup.result) + { + Cddb_FinishLookup(&g_lookup, pDisc); + if (pDisc) pDisc->Release(); + return S_OK; + } + } + + if (CDDB_NOINET == (CDDB_NOINET & flags)) + { + g_lookup.result = S_FALSE; + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + hwndParent = GetAdaptedParent(hwndParent); + + g_lookup.hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + hwndProgressListener = g_lookup.hwndInfo; + + CddbProgressDlg_Initialize(g_lookup.hwndInfo, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(g_lookup.hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + if (g_lookup.hwndInfo) + { + SetPopUpPos(g_lookup.hwndInfo, CENTER_LEFT); + ShowWindow(g_lookup.hwndInfo, SW_SHOWNA); + } + + g_lookup.result = Cddb_GetIControl((void**)&pControl); + if (FAILED(g_lookup.result)) + { + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + g_lookup.result = pControl->LookupMediaByToc(g_lookup.bstrTOC, TRUE, &matchCode); + + pControl->Release(); + if (FAILED(g_lookup.result)) + { + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + if (CDDB_UI_MODAL & flags) + { + RECT rc; + + hr = CddbProgressDlg_DoModal(g_lookup.hwndInfo, &rc); + if (SUCCEEDED(hr)) + { + SET_BUSY(FALSE); + CLEARLOOKUP(); + + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + } + } + return S_OK; + #else + return E_FAIL; + #endif +} + +static HRESULT Cddb_DoSubmitNewDlg(HWND hwndCaller, BSTR bstrTOC, UINT flags, ICddbDisc **ppDisc) +{ + RECT rw; + HRESULT hr; + HWND hwndInfo, hwndOldListener, hwndParent; + MODALDATA data; + wchar_t szText[256] = {0}; + + if (!ppDisc) return E_INVALIDARG; + + data.pDisc = NULL; + data.bstrTOC = bstrTOC; + data.flags = flags; + + hwndParent = (hwndCaller) ? GetParent(hwndCaller) : NULL; + if (!hwndParent) hwndParent = line.hMainWindow; + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + + if (!hwndInfo || !CddbProgressDlg_SetUserData(hwndInfo, &data)) + { + if (hwndInfo) + DestroyWindow(hwndInfo); + + if (NULL != data.bstrTOC) + SysFreeString(data.bstrTOC); + return E_FAIL; + } + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, MAKEINTRESOURCEW(IDS_NOT_FOUND), NULL, NULL); + CddbProgressDlg_Completed(hwndInfo, MAKEINTRESOURCEW(IDS_SUBMIT_OFFER), NULL, AUTOCLOSE_NEVER, S_OK); + #ifndef IGNORE_API_GRACENOTE + CddbProgressDlg_ShowButton1(hwndInfo, MAKEINTRESOURCEW(IDS_SUBMITNEW), CddbProgressDlg_OnSubmitNew, NULL); + #endif + + hwndOldListener = hwndProgressListener; + if (hwndCaller) + { + GetWindowRect(hwndCaller, &rw); + SetWindowPos(hwndInfo, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); + ShowWindowAsync(hwndCaller, SW_HIDE); + } + else ShowWindow(hwndInfo, SW_SHOW); + + RECT rc; + hr = CddbProgressDlg_DoModal(hwndInfo, &rc); + + *ppDisc = data.pDisc; + + if (hwndCaller) + { + SetWindowPos(hwndCaller, HWND_TOP, rc.left, rc.top, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW); + } + + hwndProgressListener = hwndOldListener; + return hr; +} + +#ifndef IGNORE_API_GRACENOTE +static HRESULT Cddb_DoFuzzyMatchDlg(HWND hwndCaller, UINT flags, ICddbDiscs *pDiscs, LONG *plVal) +{ + HRESULT hr; + LONG count; + ICddbDisc *pDisc(NULL); + BSTR bstrArtist, bstrTitle; + RECT rw; + HWND hwndInfo, hwndOldListener, hwndParent; + MODALDATA data; + wchar_t szText[256] = {0}; + + data.pDisc = NULL; + data.flags = flags; + + if (!plVal || !pDiscs) return E_INVALIDARG; + *plVal = 0L; + + hwndParent = (hwndCaller) ? GetParent(hwndCaller) : NULL; + if (!hwndParent) hwndParent = line.hMainWindow; + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + + if (!hwndInfo || !CddbProgressDlg_SetUserData(hwndInfo, &data)) + { + if (hwndInfo) DestroyWindow(hwndInfo); + return E_FAIL; + } + + hwndOldListener = hwndProgressListener; + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, MAKEINTRESOURCEW(IDS_FUZZYDISC_TITLE), NULL, NULL); + CddbProgressDlg_SetStatus(hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + if (hwndCaller) + { + GetWindowRect(hwndCaller, &rw); + SetWindowPos(hwndInfo, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOSIZE); + ShowWindowAsync(hwndCaller, SW_HIDE); + } + ShowWindow(hwndInfo, SW_SHOWNA); + + if (FAILED(pDiscs->get_Count(&count))) count = 0; + for(long i = 1; i <= count; i++) + { + if (SUCCEEDED(pDiscs->GetDisc(i, &pDisc))) + { + if (FAILED(pDisc->get_Artist(&bstrArtist))) bstrArtist = NULL; + if (FAILED(pDisc->get_Title(&bstrTitle))) bstrTitle = NULL; + CddbProgressDlg_AddRecord(hwndInfo, bstrArtist, bstrTitle, NULL); + if (bstrArtist) SysFreeString(bstrArtist); + if (bstrTitle) SysFreeString(bstrTitle); + pDisc->Release(); + } + } + + CddbProgressDlg_ShowButton1(hwndInfo, MAKEINTRESOURCEW(IDS_ACCEPT), CddbProgressDlg_OnAcceptMatch, NULL); + CddbProgressDlg_SetExtendedMode(hwndInfo, TRUE); + CddbProgressDlg_Completed(hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_MULTIPLE), NULL, AUTOCLOSE_NEVER, S_OK); + + UpdateWindow(hwndInfo); + SetForegroundWindow(hwndInfo); + + RECT rc; + hr = CddbProgressDlg_DoModal(hwndInfo, &rc); + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + *plVal = ((LONG)(LONG_PTR)data.pDisc); + + if (hwndCaller) + { + SetWindowPos(hwndCaller, HWND_TOP, rc.left, rc.top, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW); + } + hwndProgressListener = hwndOldListener; + return hr; +} +#endif + +static void CALLBACK Cddb_OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData, UINT_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + switch(lCommandCode) + { + case CMD_LookupMediaByToc: Cddb_OnMediaLookupCompleted(hCommandResult, (CDDBMatchCode)pCommandData->lVal, (MEDIALOOKUP*)user); break; + case CMD_GetFullDiscInfo: Cddb_OnGetFullDiscInfoCompleted(hCommandResult, (ICddbDisc*)pCommandData->byref, (MEDIALOOKUP*)user); break; + case CMD_SubmitDisc: Cddb_OnSubmitDiscCompleted(hCommandResult, (MEDIALOOKUP*)user); break; + } + #endif +} + +static void CALLBACK Cddb_OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal, UINT_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + if (hwndProgressListener) + { + INT ids(0), nComplete(-1); + switch(lProgressCode) + { + case CMD_CONNECTING: ids = IDS_CDDB_PROGRESS_CONNECTING; break; + case CMD_SENDING: ids = IDS_CDDB_PROGRESS_SENDING; nComplete = lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_RECEIVING: ids = IDS_CDDB_PROGRESS_RECEIVING; nComplete = lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_CANCELLED: ids = IDS_CDDB_PROGRESS_CANCELLED; break; + case CMD_WAITING: ids = IDS_CDDB_PROGRESS_WAITING; lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_COMPLETED: ids = IDS_CDDB_PROGRESS_COMPLETED; break; + } + if (ids) CddbProgressDlg_SetStatus(hwndProgressListener, MAKEINTRESOURCEW(ids), nComplete); + } + #endif +} + +#ifndef IGNORE_API_GRACENOTE +static void Cddb_OnMediaLookupCompleted(HRESULT result, CDDBMatchCode matchCode, MEDIALOOKUP *pLookup) +{ + ICDDBControl *pControl; + ICddbDisc *pDisc(NULL), *pfuzzyDisc(NULL); + ICddbDiscs *pDiscs(NULL); + LONG lVal; + wchar_t szText[256] = {0}; + if (!pLookup) return; + + SetWindowText(pLookup->hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + pLookup->result = result; + if (FAILED(pLookup->result)) + { + switch(pLookup->result) + { + case CDDBSVCServiceError: pLookup->result = CDDB_E_BADTOC; break;// + } + Cddb_FinishLookup(pLookup, NULL); + return; + } + + pLookup->result = Cddb_GetIControl((void**)&pControl); + if (FAILED(pLookup->result)) + { + Cddb_FinishLookup(pLookup, NULL); + return; + } + + switch(matchCode) + { + case MATCH_EXACT: + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_EXACT), -1); + pLookup->result = pControl->GetMatchedDiscInfo((IUnknown**)&pDisc); + break; + case MATCH_MULTIPLE: + pLookup->result = S_MULTIPLE; + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_MULTIPLE), -1); + if (0 != ((CDDB_UI_MULTIPLE | CDDB_RESOLVE_MULTIPLE) & pLookup->flags)) + { + lVal = 0; + pLookup->result = pControl->GetMatchedDiscInfo((IUnknown**)&pDiscs); + if (SUCCEEDED(pLookup->result)) + { + if (0 != (CDDB_UI_MULTIPLE & pLookup->flags)) + { + pLookup->result = Cddb_DoFuzzyMatchDlg(pLookup->hwndInfo, 0, pDiscs, &lVal); + if (S_OK != pLookup->result) lVal = 0; + } + if (0 == lVal && 0 != (CDDB_RESOLVE_MULTIPLE & pLookup->flags)) lVal = 1; + if (lVal) + { + CddbProgressDlg_Initialize(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + pLookup->result = pDiscs->GetDisc(lVal, &pfuzzyDisc); + if (SUCCEEDED(pLookup->result)) + { + if (!pfuzzyDisc) pLookup->result = S_FALSE; + else + { + pLookup->result = pfuzzyDisc->IsSubmit(&lVal); + if (FAILED(pLookup->result) || !lVal) + { + pLookup->result = pControl->GetFullDiscInfo(pfuzzyDisc, TRUE, &pDisc); + pfuzzyDisc->Release(); + if (SUCCEEDED(pLookup->result)) + { + pDiscs->Release(); + pControl->Release(); + return; + } + } + else pDisc = pfuzzyDisc; + } + } + } + pDiscs->Release(); + } + } + break; + case MATCH_NONE: + pLookup->result = S_FALSE; + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_NOT_FOUND), -1); + if (CDDB_UI_NOMATCH & pLookup->flags) + { + pLookup->result = Cddb_DoSubmitNewDlg(pLookup->hwndInfo, pLookup->bstrTOC, 0, &pDisc); + if (S_OK == pLookup->result) + { + LONG lVal; + CddbProgressDlg_Initialize(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_SUBMITTING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + pSubmitDisc = pDisc; + pLookup->result = pControl->SubmitDisc(pSubmitDisc, TRUE, &lVal); + if (SUCCEEDED(pLookup->result)) + { + pControl->Release(); + return; + } + + } + } + break; + } + pControl->Release(); + + Cddb_FinishLookup(pLookup, pDisc); + if (pDisc) pDisc->Release(); +} +#endif + +static void Cddb_OnGetFullDiscInfoCompleted(HRESULT result, ICddbDisc *pDisc, MEDIALOOKUP *pLookup) +{ + if (!pLookup) return; + pLookup->result = result; + Cddb_FinishLookup(pLookup, pDisc); +} + +static void Cddb_OnSubmitDiscCompleted(HRESULT result, MEDIALOOKUP *pLookup) +{ + #ifndef IGNORE_API_GRACENOTE + if (!pLookup) return; + pLookup->result = result; + if (FAILED(result)) + { + if (pSubmitDisc) pSubmitDisc->Release(); + pSubmitDisc = NULL; + } + Cddb_FinishLookup(pLookup, pSubmitDisc); + if (pSubmitDisc) + { + pSubmitDisc->Release(); + pSubmitDisc = NULL; + } + #endif +} + +HWND Cddb_GetInfoWindow(void) +{ + #ifndef IGNORE_API_GRACENOTE + return (IS_BUSY(0)) ? g_lookup.hwndInfo : NULL; + #else + return NULL; + #endif +} + +void Cdbb_DisplayInfo(LPCWSTR pszTitle, LPCWSTR pszCaption, LPCWSTR pszStatus, INT percentCompleted) +{ + HWND hwndInfo; + hwndInfo = Cddb_GetInfoWindow(); + if (!hwndInfo) return; + BOOL CddbProgressDlg_SetStatus(HWND hwnd, LPCWSTR pszStatus, INT nPercentCompleted); +} + +HRESULT Cddb_DisplayResultDlg(HWND hwndParent, HRESULT result, DWORD dwAutoCloseDelay, UINT flags) +{ + #ifndef IGNORE_API_GRACENOTE + HWND hwndInfo; + wchar_t szReason[256] = {0}, szResult[256] = {0}; + + if (CDDB_UI_USE_PARENT & flags) hwndInfo = hwndParent; + else + { + wchar_t szText[256] = {0}; + hwndParent = GetAdaptedParent(hwndParent); + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + SetPopUpPos(hwndInfo, CENTER_LEFT); + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, NULL, NULL, NULL); + CddbProgressDlg_Completed(hwndInfo, NULL, NULL, AUTOCLOSE_NEVER, S_OK); + } + if (!hwndInfo || !IsWindow(hwndInfo)) return E_FAIL; + + if (AUTOCLOSE_NOW == dwAutoCloseDelay && GetWindowThreadProcessId(hwndInfo, NULL) != GetCurrentThreadId()) + { + dwAutoCloseDelay = 1; // DestroyWindow is not working on other thread + ShowWindowAsync(hwndInfo, SW_HIDE); // in case we in modal loop on other + } + + if (dwAutoCloseDelay > 10) + { + Cddb_GetResultText(result, szResult, sizeof(szResult)/sizeof(wchar_t), + szReason, sizeof(szReason)/sizeof(wchar_t)); + ShowWindow(hwndInfo, SW_SHOW); + } + + CddbProgressDlg_Completed(hwndInfo, szResult, szReason, dwAutoCloseDelay, result); + + if (dwAutoCloseDelay > 10 && CDDB_UI_RESULT_MODAL == ((CDDB_UI_MODAL | CDDB_UI_RESULT_MODAL) & flags)) + { + CddbProgressDlg_DoModal(hwndInfo, NULL); + } + #endif + + return S_OK; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/CDDB.H b/Src/Plugins/Input/in_cdda/CDDB.H new file mode 100644 index 00000000..8685078d --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDDB.H @@ -0,0 +1,184 @@ +#ifndef NULLSOFT_IN_CDDA_CDDB_H +#define NULLSOFT_IN_CDDA_CDDB_H + +#define S_MULTIPLE MATCH_MULTIPLE + +#ifdef IGNORE_API_GRACENOTE +struct TRACKINFO +{ + TRACKINFO() + { + artist=0; + title=0; + genre=0; + tagID=0; + composer=0; + conductor=0; + extData=0; + remixing=0; + isrc=0; + } + TRACKINFO(const TRACKINFO ©); + TRACKINFO &operator =(const TRACKINFO ©); + ~TRACKINFO(); + + void Reset(); + + wchar_t *artist; + wchar_t *title; + wchar_t *genre; + wchar_t *tagID; + wchar_t *composer; + wchar_t *conductor; + wchar_t *extData; + wchar_t *remixing; + wchar_t *isrc; +}; +#endif + + struct DINFO +{ + DINFO() + { + label=0; + notes=0; + genre=0; + artist=0; + year=0; + tuid=0; + title=0; + composer=0; + conductor=0; + remixing=0; + compilation=false; + discnum=0; + numdiscs=0; + ntracks=0; + CDDBID=0; + nDiscLength=0; + populated=false; + memset(pnFrames, 0, sizeof(pnFrames)); + } + DINFO(const DINFO ©); + DINFO &operator =(const DINFO ©); + ~DINFO(); + void Reset(); + + wchar_t *title; + wchar_t *artist; + wchar_t *tuid; + wchar_t *year; + wchar_t *genre; + wchar_t *label; + wchar_t *notes; + bool compilation; + int discnum; + int numdiscs; + int ntracks; + wchar_t *conductor; + wchar_t *composer; + wchar_t *remixing; + #ifdef IGNORE_API_GRACENOTE + TRACKINFO tracks[100]; + #endif + + unsigned int CDDBID; + unsigned int pnFrames[100]; + unsigned int nDiscLength; + + bool populated; +}; + +extern char config_use_cddb; + + +#define CDDB_E_BADTOC 0x82FD0001 + +#define CDDB_NONE 0x0000 // +#define CDDB_NOCACHE 0x1000 // +#define CDDB_NOINET 0x2000 // + +#define CDDB_RESOLVE_MULTIPLE 0x0001 // selects first + + + +#define CDDB_UI_MODAL 0x0010 // +#define CDDB_UI_RESULT_MODAL 0x0020 // result window will stay modal +#define CDDB_UI_USE_PARENT 0x0040 // instead of creating child window from hwndParent - just reuse hwndParent + +#define CDDB_UI_NOMATCH 0x0100 // displays submit new dialog +#define CDDB_UI_MULTIPLE 0x0200 // displays multiple choices dialog + +#define AUTOCLOSE_NOW 0x00000000 +#define AUTOCLOSE_NEVER 0xFFFFFFFF + +int GetDiscID(MCIDEVICEID wDeviceID, DINFO* psDI); +int GetCDDBInfo(DINFO *ps, wchar_t device); + +#include "CDDBInterface.h" +#ifdef IGNORE_API_GRACENOTE +class ICddbDisc; +#endif +typedef HRESULT (CALLBACK *CDDB_CB)(HRESULT /*result*/, ICddbDisc* /*pDisc*/, DWORD* /*pdwAutoCloseDelay*/, ULONG_PTR /*user*/); + +#ifndef IGNORE_API_GRACENOTE +HRESULT DoCDDBDlg(DINFO *ps, HWND hwnd, int editopt); +void GetDiscInfo(ICddbDiscPtr pDisc, DINFO *ps); +bool GetRole(ICddbTrack *track, BSTR roleId, BSTR *str); +bool GetRole(ICddbDisc *track, BSTR roleId, BSTR *str); +extern ICDDBControl *pCDDBControl; + +void InitializeCddbCache(void); +void UninitializeCddbCache(void); +#endif + +HRESULT CddbCache_SetDisc(DINFO *pDiscInfo, HRESULT lookupResult); + +void Cddb_Initialize(void); +void Cddb_Uninitialize(void); + +HRESULT Cddb_InitializeThread(void); +HRESULT Cddb_UninitializeThread(void); + +LPCWSTR Cddb_CalculateTOC(DINFO *pDisc, LPWSTR pszTOC, size_t cchTOC); +HRESULT Cddb_DoLookup(LPCWSTR pszTOC, HWND hwndParent, CDDB_CB callback, UINT flags, ULONG_PTR user); + +#ifndef IGNORE_API_GRACENOTE +void DefaultValues(DINFO *ps); +#endif + +bool DoCDText(DINFO *ps, wchar_t device); + +HRESULT Cddb_GetIUIOptions(void** ppUIOptions); +#ifndef IGNORE_API_GRACENOTE +void ShutDownCDDB(); +HRESULT Cddb_GetDiscFromCache(BSTR bstrTOC, ICddbDisc **ppDisc); +bool CDEdit(CHAR cDevice, DINFO *ps, HWND hwnd); + +HRESULT Cddb_GetIControl(void **ppControl); +HRESULT Cddb_GetICacheManger(void **ppCache); + +HRESULT Cddb_DisplayDiscInfo(ICddbDisc *pDisc, CDDBUIFlags *pUIFlags, HWND hwndParent); + +void Cddb_GetResultText(HRESULT hr, LPWSTR pszResult, INT cchResult, LPWSTR pszReason, INT cchReason); +#endif + +HRESULT Cddb_DisplayResultDlg(HWND hwndParent, HRESULT result, DWORD dwAutoCloseDelay, UINT flags); // flags can be CDDB_MODAL | CDDB_DISPLAY_IN_PARENT + +#ifndef IGNORE_API_GRACENOTE + +// info calls work only in callback +HWND Cddb_GetInfoWindow(void); +void Cdbb_DisplayInfo(LPCWSTR pszTitle, LPCWSTR pszCaption, LPCWSTR pszStatus, INT percentCompleted); + +void StoreDisc(unsigned int cddb_id, ICddbDiscPtr pDisc); +#endif + +bool StoreCDText(unsigned int cddb_id, wchar_t device); +void StoreCDNoInfo(unsigned int cddb_id); + +bool QueryDINFO(unsigned int cddb_id, DINFO *info); +//#ifndef IGNORE_API_GRACENOTE +bool StoreDINFO(unsigned cddb_id, DINFO *info); +//#endif +#endif diff --git a/Src/Plugins/Input/in_cdda/CDDBInterface.h b/Src/Plugins/Input/in_cdda/CDDBInterface.h new file mode 100644 index 00000000..cf357baf --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDDBInterface.h @@ -0,0 +1,10 @@ +#ifndef CDDBInterface_h +#define CDDBInterface_h + +//#import "CDDBControl.tlb" no_namespace, named_guids, raw_interfaces_only +//#import "../gracenote/CDDBControlWinamp.dll" no_namespace, named_guids, raw_interfaces_only +#ifndef IGNORE_API_GRACENOTE +#include "../gracenote/cddbcontrolwinamp.tlh" +#endif + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/CDPlay.cpp b/Src/Plugins/Input/in_cdda/CDPlay.cpp new file mode 100644 index 00000000..da2bbadf --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDPlay.cpp @@ -0,0 +1 @@ +#include "CDPlay.h"
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/CDPlay.h b/Src/Plugins/Input/in_cdda/CDPlay.h new file mode 100644 index 00000000..49de6601 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDPlay.h @@ -0,0 +1,34 @@ +#ifndef NULLSOFT_CDPLAYH +#define NULLSOFT_CDPLAYH + +class C_CDPlay +{ +public: + virtual ~C_CDPlay() { } + + virtual int play(wchar_t drive, int track)=0; + virtual void stop()=0; + virtual void pause()=0; + virtual void unpause()=0; + virtual int getlength()=0; + virtual int getoutputtime()=0; + virtual void setoutputtime(int time_in_ms)=0; + virtual void setvolume(int _a_v, int _a_p)=0; + + //called by winampGetExtendedRead_* + virtual int open(wchar_t drive, int track) { return 1; } + virtual int read(char *dest, int len, int *killswitch) { return 0; } + + // queries if this is the currently playing drive & track, passing track == 0 just means check drive + bool IsPlaying(wchar_t drive, int track=0) + { + if (drive == g_drive && (!track)) + return true; + + return false; + } + + wchar_t g_drive; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/CDText.cpp b/Src/Plugins/Input/in_cdda/CDText.cpp new file mode 100644 index 00000000..21518a80 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDText.cpp @@ -0,0 +1,265 @@ +#include "main.h" +#include "cddb.h" +#include "api__in_cdda.h" +#ifndef IGNORE_API_GRACENOTE +#include "../primo/obj_primo.h" +#endif +//#include "CDPlay.h" +#include "DAEPlay.h" +#include "../nu/ns_wc.h" +#include "../nde/ndestring.h" + +#ifndef IGNORE_API_GRACENOTE +const char *ReadLine(const char *input, char *output, size_t size, int codepage) +{ + size--; // leave room for null terminator + while (input && *input && *input != '\r' && size) + { + char *next = CharNextExA(codepage, input, 0); + while (input != next) + { + if (size) + { + *output = *input; + output++; + *output = 0; // safe because we left room for the null terminator + size--; + } + input++; + } + } + + + if (*input == '\r') + input++; + if (*input == '\n') + input++; + + return input; +} + + +static bool CDText_Process(DINFO *ps, const char *title, const char *performers, const char *composers, int codepage) +{ + char thisTitle[1024] = {0}; + + const char *titles = title; + // first, get disc title + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(ps->title); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + ps->title = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, ps->title, count); + } + + // now get track titles + int trackNum = 0; + while (titles && *titles) + { + if (trackNum == ps->ntracks) + break; + TRACKINFO &trackInfo = ps->tracks[trackNum]; + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(trackInfo.title); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + trackInfo.title = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, trackInfo.title, count); + } + + trackNum++; + } + + titles = performers; + // now get disc artist + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(ps->artist); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + ps->artist = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, ps->artist, count); + } + + // now get track artists + trackNum = 0; + while (titles && *titles) + { + if (trackNum == ps->ntracks) + break; + TRACKINFO &trackInfo = ps->tracks[trackNum]; + + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(trackInfo.artist); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + trackInfo.artist = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, trackInfo.artist, count); + } + + trackNum++; + } + + titles = composers; + // now get disc composer + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(ps->composer); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + ps->composer = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, ps->composer, count); + } + + // now get track composers + trackNum = 0; + while (titles && *titles) + { + if (trackNum == ps->ntracks) + break; + TRACKINFO &trackInfo = ps->tracks[trackNum]; + + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + if (thisTitle[0]) + { + ndestring_release(trackInfo.composer); + int count = MultiByteToWideChar(codepage, 0, thisTitle, -1, 0, 0); + trackInfo.composer = ndestring_malloc(count*sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, thisTitle, -1, trackInfo.composer, count); + } + + trackNum++; + } + + ps->populated = true; + return true; +} + +bool DoCDText(DINFO *ps, char device) +{ + if (!device) + return false; + + if (config_use_veritas) + { + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + + if (!primo) + return false; + + DWORD unit = device; + DWORD tracks; + if (primo->DiscInfoEx(&unit, 0, NULL, NULL, NULL, &tracks, NULL, NULL) != PRIMOSDK_OK) // CDTextInfoEJ suggest that this needs to be called first + { + sf->releaseInterface(primo); + return false; + } + if (ps->ntracks == 0) // go ahead and set if it's not set yet + ps->ntracks = tracks; + char titleE[8192] = "", performerE[8192] = "", composerE[8192] = "", titleJ[2000] = "", performerJ[2000] = "", composerJ[2000] = ""; + if (primo->CDTextInfoEJ(&unit, (PBYTE)titleE, (PBYTE)performerE, (PBYTE)composerE, (PBYTE)titleJ, (PBYTE)performerJ, (PBYTE)composerJ) == PRIMOSDK_OK) + { + sf->releaseInterface(primo); + // read titles + if (titleE[0]) + return CDText_Process(ps, titleE, performerE, composerE, 28591); + else + return CDText_Process(ps, titleJ, performerJ, composerJ, 932); + } + } + + return false; +} +#else +bool DoCDText(DINFO *ps, wchar_t device) +{ + if (!device) + return false; + + DAEPlay *dae = (g_cdplay && g_cdplay == daePlayer && g_cdplay->g_drive == device ? daePlayer : new DAEPlay); + if (dae) + { + if (dae != daePlayer) + { + if (dae->open(device, 1)) + { + delete(dae); + return false; + } + } + + DAEPlay::CDTextArray* cd_text = dae->getCDText(); + if ((int)cd_text > 0) + { + if (ps) + { + ps->ntracks = cd_text->size() - 1; + + ndestring_release(ps->title); + ps->title = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_TITLE][0]); + + ndestring_release(ps->artist); + ps->artist = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_PERFORMER][0]); + + // TODO match this to the supported list of genres... + /*ndestring_release(ps->genre); + ps->genre = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_GENRE][0]);*/ + + ndestring_release(ps->composer); + ps->composer = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_COMPOSER][0]); + + for (size_t i = 1; i < cd_text->size(); i++) + { + if (i == ps->ntracks + 1) + break; + + TRACKINFO &trackInfo = ps->tracks[i-1]; + + // TODO improve error handling + ndestring_release(trackInfo.artist); + trackInfo.artist = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_PERFORMER][i]); + //free(cd_text[DAEPlay::CD_TEXT_PERFORMER][i]); + + ndestring_release(trackInfo.title); + trackInfo.title = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_TITLE][i]); + //free(cd_text[DAEPlay::CD_TEXT_TITLE][i]); + + ndestring_release(trackInfo.genre); + trackInfo.genre = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_GENRE][i]); + //free(cd_text[DAEPlay::CD_TEXT_GENRE][i]); + + ndestring_release(trackInfo.composer); + trackInfo.composer = ndestring_wcsdup(cd_text[DAEPlay::CD_TEXT_COMPOSER][i]); + //free(cd_text[DAEPlay::CD_TEXT_COMPOSER][i]); + } + + ps->populated = true; + } + + if (dae != daePlayer) delete(dae); + return true; + } + if (dae != daePlayer) delete(dae); + } + + return false; +} +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/CONFIG.Cpp b/Src/Plugins/Input/in_cdda/CONFIG.Cpp new file mode 100644 index 00000000..14a813fd --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CONFIG.Cpp @@ -0,0 +1,261 @@ +#include "main.h" +#ifndef IGNORE_API_GRACENOTE +#include "cddb.h" +#else +extern char config_use_cddb; +//char config_use_cddb = 0; +#endif +#include "api__in_cdda.h" +#include "../winamp/wa_ipc.h" + +//int config_sample=1; +//int config_use_veritas=1; +//int config_rip_veritas=1; +//int config_maxextractspeed=4; +//int config_offset=0; +//int config_read_leadin=0; + +//int config_rip_buffersize=24; +//int config_rip_buffers=256; + +//int config_play_buffersize=1; +//int config_play_buffers=256; + +char *INI_FILE = 0; +char app_name[] = "CDDA/Line Input Driver"; + +static int _r_i(char *name, int def) +{ + name += 7; + return GetPrivateProfileIntA(app_name, name, def, INI_FILE); +} + +#define RI(x) (( x ) = _r_i(#x,( x ))) + +static void _w_i(char *name, int d) +{ + char str[120] = {0}; + wsprintfA(str, "%d", d); + name += 7; + WritePrivateProfileStringA(app_name, name, str, INI_FILE); +} +#define WI(x) _w_i(#x,( x )) + +void config_read() +{ + INI_FILE = (char*)SendMessage(line.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE); + //RI(config_sample); + RI(config_use_cddb); + /*RI(config_use_veritas); + config_rip_veritas=config_use_veritas; + RI(config_rip_veritas);*/ + //RI(config_maxextractspeed); + + //RI(config_offset); + + //RI(config_rip_buffersize); + //RI(config_rip_buffers); + + //RI(config_play_buffersize); + //RI(config_play_buffers); + //RI(config_read_leadin); +} + +void config_write() +{ + //WI(config_sample); + WI(config_use_cddb); + //WI(config_use_veritas); + //WI(config_rip_veritas); + //WI(config_maxextractspeed); +} + +// TODO need to review all of this!!! +#if 0 +BOOL CALLBACK ripConfigProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + //if (config_rip_veritas) CheckDlgButton(hwndDlg,IDC_VERITAS,BST_CHECKED); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"0.5x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"1x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"2x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"4x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"8x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)L"16x"); + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_UNLIMITED)); + + if (config_maxextractspeed<0)config_maxextractspeed=0; + if (config_maxextractspeed>6)config_maxextractspeed=6; + //if (config_maxextractspeed > 4 && getRegVer() < 1) config_maxextractspeed=4; + + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_SETCURSEL,config_maxextractspeed,0); + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + /*case IDC_VERITAS: + config_rip_veritas = IsDlgButtonChecked(hwndDlg,IDC_VERITAS)?1:0; + break;*/ + case IDC_COMBO1: + { + int x=(INT)SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_GETCURSEL,0,0); + if (x != CB_ERR) + { + if (x<0)x=0; + if (x>6)x=6; + /*if (x > 4 && getRegVer() < 1) + { + SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_SETCURSEL,4,0); + x=4; + config_maxextractspeed=x; + wchar_t title[64] = {0}; + if (MessageBoxW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_PURCHASE_WINAMP_PRO_PROMPT), + WASABI_API_LNGSTRINGW_BUF(IDS_WINAMP_PRO_FEATURE,title,64),MB_YESNO) == IDYES) + { + SendMessage(line.hMainWindow,WM_WA_IPC,0,IPC_GETREGISTEREDVERSION); + } + } + else*/ config_maxextractspeed=x; + } + } + break; + } + return FALSE; + case WM_DESTROY: + config_write(); + return FALSE; + } + return 0; +} +#endif + +static long cddbResourceID=202; +static long cddbMaxFrames=46; +static long cddbHeight=80, cddbWidth=80; +static HMODULE cddbUI = 0; + + +static bool GetUI() +{ + #ifndef IGNORE_API_GRACENOTE + ICddbUIOptions *pUIOptions; + if (SUCCEEDED(Cddb_GetIUIOptions((void**)&pUIOptions))) + { + if (SUCCEEDED(pUIOptions->GetCurrent(UI_DISP_PROGRESS))) // not sure what this does, but it seems to be required + { + pUIOptions->get_ProgressResourceID(&cddbResourceID); + pUIOptions->get_Frames(&cddbMaxFrames); + pUIOptions->get_Bottom(&cddbHeight); + pUIOptions->get_Right(&cddbWidth); + pUIOptions->get_ResourceHINSTANCE((long *)&cddbUI); + } + pUIOptions->Release(); + return true; + } + #endif + return false; +} + +static HANDLE cddbImage =0; +static int cddbFrame = 0; + +BOOL CALLBACK ConfigProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DRAWITEM: + if (wParam == IDC_CDDBICON) + { + DRAWITEMSTRUCT *drawItem = (DRAWITEMSTRUCT *) lParam; + if (cddbImage) + { + HDC hdcbm = CreateCompatibleDC(drawItem->hDC); + HGDIOBJ old = SelectObject(hdcbm, cddbImage); + BitBlt(drawItem->hDC, 0, 0, cddbWidth, cddbHeight, hdcbm, (cddbFrame * cddbWidth), 0, SRCCOPY); + SelectObject(hdcbm, old); + DeleteDC(hdcbm); + } + else + { + RECT r={0,0,cddbWidth,cddbHeight}; + FillRect(drawItem->hDC, &r, (HBRUSH)GetStockObject(GRAY_BRUSH)); + } + return TRUE; + } + break; + + case WM_DESTROY: + cddbImage=0; + break; + + case WM_INITDIALOG: + cddbFrame=0; + cddbImage=0; + { + IUnknown *pUnknown = NULL; + #ifndef IGNORE_API_GRACENOTE + Cddb_GetIControl((void**)&pUnknown); + #endif + if (!pUnknown) + { + ShowWindow(GetDlgItem(hwndDlg,IDC_CDDBNOTE),SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg,IDC_CDDB),SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CDDBICON),SW_HIDE); + } + else pUnknown->Release(); + } + + //if (config_sample) CheckDlgButton(hwndDlg,IDC_SAMPLE,BST_CHECKED); + if (config_use_cddb&1) CheckDlgButton(hwndDlg,IDC_CDDB,BST_CHECKED); + //if (config_use_veritas) CheckDlgButton(hwndDlg,IDC_VERITAS,BST_CHECKED); + + if ((config_use_cddb&1) && GetUI()) + { + cddbImage = LoadImage(cddbUI, MAKEINTRESOURCE(cddbResourceID), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE); + SetTimer(hwndDlg, 2, 65, NULL); + } + SetWindowPos(GetDlgItem(hwndDlg, IDC_CDDBICON), 0, 0, 0, cddbWidth, cddbHeight, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); + return TRUE; + + case WM_TIMER: + switch (wParam) + { + case 2: + if (cddbFrame < cddbMaxFrames-1) + { + cddbFrame++; + InvalidateRect(GetDlgItem(hwndDlg, IDC_CDDBICON), 0, TRUE); + } + else + KillTimer(hwndDlg, 2); + + break; + } + return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CDDBICON: + if (HIWORD(wParam) == STN_CLICKED) SendMessage(line.hMainWindow, WM_WA_IPC, (WPARAM)L"http://www.cddb.com/", IPC_OPEN_URL); + return 0; + case IDOK: + //config_sample = IsDlgButtonChecked(hwndDlg,IDC_SAMPLE)?1:0; + config_use_cddb = IsDlgButtonChecked(hwndDlg,IDC_CDDB)?1:0; + //config_use_veritas = IsDlgButtonChecked(hwndDlg,IDC_VERITAS)?1:0; + config_write(); + case IDCANCEL: + EndDialog(hwndDlg,1); + return FALSE; + } + return FALSE; + } + return 0; +} + +void config(HWND hwndParent) +{ + WASABI_API_DIALOGBOXW(IDD_DIALOG1,hwndParent,ConfigProc); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/DAEPlay.cpp b/Src/Plugins/Input/in_cdda/DAEPlay.cpp new file mode 100644 index 00000000..30495ab9 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/DAEPlay.cpp @@ -0,0 +1,423 @@ +#include "DAEPlay.h" +#include "api__in_cdda.h" +#include "../nu/AutoWide.h" +#include <strsafe.h> + +int DAEPlay::getTrackInfo() +{ + CDROM_TOC tableOfContents = {0}; + DWORD tocSize = sizeof(tableOfContents); + + if (!DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &tableOfContents, tocSize, &tocSize, 0)) + { + return 1; + } + + for (int i = tableOfContents.FirstTrack - 1 ; i < tableOfContents.LastTrack ; i += 1) + { + if (i == g_track) + { + track_length = MSFToBlocks(tableOfContents.TrackData[i+1].Address) - (start_address = MSFToBlocks(tableOfContents.TrackData[i].Address)); + return 0; + } + } + + return 1; +} + +DAEPlay::CDTextArray* DAEPlay::getCDText() +{ + // if we've already cached it, return asap + if (cd_text != 0) + { + return cd_text; + } + + CDROM_TOC tableOfContents = {0}; + DWORD tocSize = sizeof(tableOfContents), returned = 0; + + if (!DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &tableOfContents, tocSize, &tocSize, 0)) + { + // issue accessing drive + return (cd_text = (CDTextArray *)-1); + } + + // MMC-3 Draft Revision 10g: Table 222 Q Sub-channel control field + tableOfContents.TrackData[0].Control &= 5; + if (!(tableOfContents.TrackData[0].Control == 0/* || tableOfContents.TrackData[0 - 1].Control == 1*/)) + { + // invalid format + return (cd_text = (CDTextArray *)-1); + } + + CDROM_READ_TOC_EX tableOfContentsEx = {0}; + tableOfContentsEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT; + WORD tocSizeEx = 0; + // Read the contents to get the size of the actual data + if (!DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC_EX, &tableOfContentsEx, sizeof(tableOfContentsEx), &tocSizeEx, sizeof(tocSizeEx), &returned, 0)) + { + // issue accessing drive + return (cd_text = (CDTextArray *)-1); + } + + // The bytes are swapped so we need to switch them around + tocSizeEx = ((tocSizeEx>>8) | (tocSizeEx<<8)) + sizeof(tocSizeEx); + + // Allocate a buffer for reading the actual CD Text data block + char *pCDTextData = new char[tocSizeEx]; + if (!pCDTextData) + { + return (cd_text = (CDTextArray *)-1); + } + + memset(pCDTextData, 0, tocSizeEx); + + // Now read the data + if(!DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC_EX, &tableOfContentsEx, sizeof(tableOfContentsEx), pCDTextData, tocSizeEx, &returned, 0)) + { + delete []pCDTextData; + return (cd_text = (CDTextArray *)-1); + } + + tocSizeEx = (WORD)(returned - sizeof(CDROM_TOC_CD_TEXT_DATA)); + + if(!tocSizeEx) + { + delete []pCDTextData; + return (cd_text = (CDTextArray *)-1); + } + + // This is the stuff we really need. It's an array of packs with the data (mostly text) + CDROM_TOC_CD_TEXT_DATA_BLOCK* pCDTextBlock = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors; + + // As we go through the packets we'll store the strings in this array. The strings are often in different packets and need to be concatenated together. + cd_text = new CDTextArray[CD_TEXT_NUM_PACKS]; + UINT m_nGenreCode = -1; + + // Loop through all the packets extracting the data we need. Each packet starts with a packet type, the track number, language code, + // character offset, and character size. The packets end with a 2 byte CRC. We don't need most of this stuff to display the info. We can get + // the packets for any track and they'll have all the data for each track (it's duplicated). + for( ;tocSizeEx >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); tocSizeEx -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pCDTextBlock++) + { + if (pCDTextBlock->TrackNumber > tableOfContents.LastTrack) // Track is beyond what is on the disc + continue; + + // Only looking for CD Text item packets + if ((pCDTextBlock->PackType -= 0x80) >= 0x10) + continue; + + // Genre is encoded with the code and the supplemental text in the same packet + if (m_nGenreCode == -1 && pCDTextBlock->PackType == CD_TEXT_GENRE) + { + // TODO + m_nGenreCode = pCDTextBlock->Text[0]*16 + pCDTextBlock->Text[1]; + /*CString Text = !pCDTextBlock->Unicode + ? CString(CStringA((CHAR*)pCDTextBlock->Text+2, CD_TEXT_FIELD_LENGTH-2)) + : CString(CStringW((WCHAR*)pCDTextBlock->WText+2, CD_TEXT_FIELD_LENGTH-2)); + cd_text[pCDTextBlock->PackType][0] = Text;*/ + } + else + { + // Parse the text. There could be more than one item in the text block separated by null bytes so we need to check the whole thing + // The text is in a block of up to 12 characters. We'll just keep adding to our buffers until we go through all of the packets. + int nLengthRemaining = CD_TEXT_FIELD_LENGTH; + UINT nTrack = pCDTextBlock->TrackNumber; + UINT nOffset = 0; + // We're at the end of text when: + // Used up 12 chars + // Got to a null + // On the last track + while (nTrack <= tableOfContents.LastTrack && nLengthRemaining > 0 && nOffset < CD_TEXT_FIELD_LENGTH) + { + wchar_t *text = (wchar_t*)calloc(nLengthRemaining + 1, sizeof(wchar_t)); + if (!text) continue; + + lstrcpyn(text, (pCDTextBlock->Unicode ? pCDTextBlock->WText + nOffset : AutoWide((char *)pCDTextBlock->Text + nOffset)), nLengthRemaining + 1); + + if (!cd_text[pCDTextBlock->PackType][nTrack]) + cd_text[pCDTextBlock->PackType][nTrack] = (wchar_t*)calloc(lstrlen(text) + 1, sizeof(wchar_t)); + else // TODO error handling + cd_text[pCDTextBlock->PackType][nTrack] = (wchar_t*)realloc(cd_text[pCDTextBlock->PackType][nTrack], (lstrlen(cd_text[pCDTextBlock->PackType][nTrack]) + lstrlen(text) + 1) * sizeof(wchar_t)); + + if (text[0]) + lstrcat(cd_text[pCDTextBlock->PackType][nTrack], text); + + nOffset += lstrlen(text) + 1; + nLengthRemaining = nLengthRemaining - lstrlen(text) - 1; + ++nTrack; + free(text); + } + } + } while (0); + + delete []pCDTextData; + return cd_text; +} + +int DAEPlay::threadProc2() +{ + while (1) + { + if (need_seek != -1) + { + current_sector = ((need_seek * CD_BLOCKS_PER_SECOND) / 1000) / DEF_SECTORS_PER_READ; + bytes_in_sbuf = 0; + line.outMod->Flush(need_seek); + need_seek = -1; + } + + if (fillBuffer(killswitch)) + { + PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + return 0; + } + + if (!bytes_in_sbuf && !killswitch) + { + //wait for output to be finished + line.outMod->Write(NULL, 0); + while (!killswitch && line.outMod->IsPlaying()) Sleep(10); + if (!killswitch) + { + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + } + return 0; + } + + if (killswitch) + { + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + return 0; + } + + char sample_buffer[576*4*2] = {0}; + int bytes = sizeof(sample_buffer) / 2; // enough room for dsp bullcrap + bytes = min((int)bytes_in_sbuf, (int)bytes); + memcpy(sample_buffer, sbuf, bytes); + if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes); + bytes_in_sbuf -= bytes; + + line.VSAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime()); + line.SAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime()); + + if (line.dsp_isactive()) + bytes = line.dsp_dosamples((short *)sample_buffer, bytes / g_nch / 2, 16, g_nch, 44100) * (g_nch * 2); + + while (line.outMod->CanWrite() < bytes && !killswitch) Sleep(66); + if (killswitch) + { + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + return 0; + } + + line.outMod->Write(sample_buffer, bytes); + } + + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + return 0; +} + +void DAEPlay::stop() +{ + if (hThread) + { + killswitch = 1; + WaitForSingleObject(hThread, INFINITE); + } + + line.outMod->Close(); +} + +int DAEPlay::open(wchar_t drive, int track) //called by winampGetExtendedRead +{ + g_track = track-1; + if (g_track < 0) + return 1; + + g_drive = drive; + + wchar_t CDDevice[8]=L"\\\\.\\x:"; + CDDevice[4] = drive; + + if (hDrive != INVALID_HANDLE_VALUE) + CloseHandle(hDrive); + + hDrive = CreateFile(CDDevice, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hDrive == INVALID_HANDLE_VALUE) + return 1; + + // TODO only store the request track! + if (getTrackInfo()) + return 1; + + g_playlength = (track_length / CD_BLOCKS_PER_SECOND) * 1000; + + bytes_in_sbuf = 0; + + if (!sbuf) + sbuf = (unsigned char *)malloc(2352 * buf_size); + if (!sbuf) + return 1; + + data = new BYTE[DEF_SECTORS_PER_READ * CDROM_RAW_BYTES_PER_SECTOR]; + if (!data) + return 1; + + return 0; +} + +int DAEPlay::play(wchar_t drive, int track) //called by winamp2's normal(old) play() interface +{ + int old_drive = g_drive; + + if (open(drive, track)) return 1; + + // do this here as it helps to prevent an audio glitch on first playback and volume is set low + setvolume(a_v, a_p); + + int maxlat = line.outMod->Open(44100, g_nch, 16, -1, -1); + if (maxlat < 0) + { + g_drive = 0; + return 1; + } + + // to prevent re-spinning as we're not going to get cd-text later + // if it's not able to be obtained when first opening the device. + if (old_drive != drive) + { + if ((int)cd_text > 0) + delete []cd_text; + cd_text = NULL; + getCDText(); + } + + line.SetInfo(1411, 44, g_nch, 1); + line.SAVSAInit(maxlat, 44100); + line.VSASetInfo(g_nch, 44100); + line.is_seekable = 1; + + bytes_in_sbuf = 0; + current_sector = 0; + killswitch = 0; + DWORD thread_id = 0; + hThread = CreateThread(NULL, NULL, &threadProc, (LPVOID)this, NULL, &thread_id); + SetThreadPriority(hThread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST)); + + //open the device thru MCI (for getfileinfo to work properly) + g_playtrack = track; + + return 0; +} + +int DAEPlay::fillBuffer(int kill) +{ + if (!kill && bytes_in_sbuf <= 0) + { + if (current_sector < (track_length / DEF_SECTORS_PER_READ)) + { + // Contains an offset into the CD-ROM disc where data will be read. You can calculate this offset by multiplying the starting sector number for the request times 2048. + RAW_READ_INFO _RawReadInfo = {0}; + _RawReadInfo.DiskOffset.QuadPart = ((current_sector * DEF_SECTORS_PER_READ) + start_address) * CDROM_COOKED_BYTES_PER_SECTOR; + _RawReadInfo.TrackMode = CDDA; + _RawReadInfo.SectorCount = DEF_SECTORS_PER_READ; + + DWORD data_length = DEF_SECTORS_PER_READ * CDROM_RAW_BYTES_PER_SECTOR; + if (!DeviceIoControl(hDrive, IOCTL_CDROM_RAW_READ, &_RawReadInfo, sizeof(_RawReadInfo), + data, data_length, &data_length, 0)) + { + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + return 1; + } + + // TODO make sure the buffer size is enough for our needs + memcpy(sbuf, data, DEF_SECTORS_PER_READ * CDROM_RAW_BYTES_PER_SECTOR); + bytes_in_sbuf += DEF_SECTORS_PER_READ * CDROM_RAW_BYTES_PER_SECTOR; + } + current_sector++; + } + return 0; +} + +int DAEPlay::read(char *dest, int len, int *killswitch) //called by winampGetExtendedRead_getData +{ + int l = 0; + + // TODO make sure this will handle a CD ejection... + while (l < len && !*killswitch) + { + if (fillBuffer(*killswitch)) + { + return -1; + } + + if (!bytes_in_sbuf) break; + + int bytes = min(bytes_in_sbuf, len - l); + memcpy(dest + l, sbuf, bytes); + + if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes); + bytes_in_sbuf -= bytes; + + l += bytes; + } + + return l; +} + +DAEPlay::DAEPlay() +{ + sbuf = NULL; + data = NULL; + cd_text = NULL; + bytes_in_sbuf = 0; + buf_size = 64; //make it configitem + g_track = -1; + + // fix these three as that's normal + g_nch = 2; + g_srate = 44100; + g_bps = 16; + + killswitch = 0; + hDrive = INVALID_HANDLE_VALUE; + hThread = NULL; + need_seek = -1; + current_sector = 0; + start_address = 0; + track_length = 0; +} + +DAEPlay::~DAEPlay() +{ + if (hDrive != INVALID_HANDLE_VALUE) + { + CloseHandle(hDrive); + hDrive = INVALID_HANDLE_VALUE; + } + + if (sbuf) + { + free(sbuf); + sbuf = NULL; + } + + if (data) + { + delete []data; + data = NULL; + } + + if ((int)cd_text > 0) + { + delete []cd_text; + } + cd_text = NULL; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/DAEPlay.h b/Src/Plugins/Input/in_cdda/DAEPlay.h new file mode 100644 index 00000000..940dd508 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/DAEPlay.h @@ -0,0 +1,112 @@ +#ifndef NULLSOFT_DAEPLAYH +#define NULLSOFT_DAEPLAYH + +#include "Main.h" +#include "CDPlay.h" +#include "../nu/AutoLock.h" +#include <map> +#include <winioctl.h> +#include "Ntddcdrm.h" + +#define CD_BLOCKS_PER_SECOND 75 +#define DEF_SECTORS_PER_READ 8 +#define CDROM_RAW_BYTES_PER_SECTOR 2352 +#define CDROM_COOKED_BYTES_PER_SECTOR 2048 + +using namespace Nullsoft::Utility; +class DAEPlay : public C_CDPlay +{ +public: + DAEPlay(); + ~DAEPlay(); + int open(wchar_t drive, int track); + int play(wchar_t drive, int track); + + static DWORD WINAPI threadProc(LPVOID lpParameter) + { + DAEPlay *wp = (DAEPlay *)lpParameter; + return wp->threadProc2(); + } + + int read(char *dest, int len, int *killswitch); + int threadProc2(); + void stop(); + + void pause() + { + line.outMod->Pause(1); + } + + void unpause() + { + line.outMod->Pause(0); + } + + int getlength() + { + return g_playlength; + } + + int getoutputtime() + { + return line.outMod->GetOutputTime(); + } + + void setoutputtime(int time_in_ms) + { + need_seek = time_in_ms; + } + + void setvolume(int _a_v, int _a_p) + { + line.outMod->SetVolume(_a_v); + line.outMod->SetPan(_a_p); + } + + typedef std::map<int, wchar_t*> CDTextArray; + CDTextArray* getCDText(); + + enum PacketTypes { + CD_TEXT_TITLE, + CD_TEXT_PERFORMER, + CD_TEXT_SONGWRITER, + CD_TEXT_COMPOSER, + CD_TEXT_ARRANGER, + CD_TEXT_MESSAGES, + CD_TEXT_DISC_ID, + CD_TEXT_GENRE, + CD_TEXT_TOC_INFO, + CD_TEXT_TOC_INFO2, + CD_TEXT_RESERVED_1, + CD_TEXT_RESERVED_2, + CD_TEXT_RESERVED_3, + CD_TEXT_RESERVED_4, + CD_TEXT_CODE, + CD_TEXT_SIZE, + CD_TEXT_NUM_PACKS + }; + +private: + + BYTE * data; + CDTextArray* cd_text; + unsigned char *sbuf; + long bytes_in_sbuf; + int buf_size; + int g_track, g_nch, g_srate, g_bps; + int killswitch; + HANDLE hDrive, hThread; + int need_seek; + + DWORD start_address, track_length, current_sector; + + int getTrackInfo(); + int fillBuffer(int kill); + + DWORD MSFToBlocks(UCHAR msf[4]) + { + return (((msf[1] * (CD_BLOCKS_PER_SECOND * 60)) + (msf[2] * CD_BLOCKS_PER_SECOND) + msf[3]) - 150); + } +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/DB.Cpp b/Src/Plugins/Input/in_cdda/DB.Cpp new file mode 100644 index 00000000..71bfdd99 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/DB.Cpp @@ -0,0 +1,306 @@ +#include "main.h" +#include "cddb.h" +#include "../Winamp/wa_ipc.h" +#include "../nu/AutoChar.h" +#include "../nu/AutoWide.h" +#include "api__in_cdda.h" + +#include <api/service/waservicefactory.h> +#include <shlwapi.h> +#include <atlbase.h> +#include "resource.h" +#include <commctrl.h> +#include <strsafe.h> + +char config_use_cddb = 1; + +#define MAX_CACHE_SIZE 8 + + +typedef struct _CBDATA +{ + DINFO *ps; + CHAR cLetter; + DWORD cddbid; +} CBDATA; + +typedef struct _CACHEREC +{ + DINFO discInfo; + HRESULT result; +} CACHEREC; + +static CACHEREC cddb_cache[MAX_CACHE_SIZE]; +static int cddb_cache_cursor = 0; + +void DefaultValues(DINFO *ps) +{ + ps->Reset(); + ps->compilation = false; + ps->discnum = 0; + ps->numdiscs = 0; + + ps->populated = true; +} + +static bool IsInternetAvailable() +{ + return !!SendMessage(line.hMainWindow, WM_WA_IPC, 0, IPC_INETAVAILABLE); +} + +static DWORD failid[26] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +#define WRITEINFO(obj, field, name) { obj->get_ ## field(&str); fwprintf(fp, name L": %s\r\n", str.m_str); } +#define WRITEINFO_LONG(obj, field, name) { long val; obj->get_ ## field(&val); fwprintf(fp, name L": %d\r\n", val); } + +#ifndef IGNORE_API_GRACENOTE +static void DumpInfoFile(ICddbDiscPtr disc) +{ +#if 0 // keep this code, but we'll wait until a later version to implement more data + long numTracks; + FILE *fp = fopen("c:\\cdinfo.txt", "wt"); + // wchar_t BOM[] = {0xFEFF, 0}; + // fwrite(BOM, 2, 1, fp); + CComBSTR str; + + WRITEINFO(disc, Toc, L"Disc TOC"); + WRITEINFO(disc, Artist, L"Disc Artist"); + WRITEINFO(disc, Title, L"Disc Title"); + WRITEINFO(disc, Label, L"Disc Label"); + WRITEINFO(disc, Year, L"Disc Year"); + WRITEINFO(disc, MediaId, L"Disc MediaId"); + WRITEINFO(disc, Notes, L"Disc Notes"); + WRITEINFO(disc, GenreId, L"Disc GenreId"); + WRITEINFO(disc, SecondaryGenreId, L"Disc Secondary GenreId"); + WRITEINFO(disc, RegionId, L"Disc RegionId"); + WRITEINFO(disc, Revision, L"Disc Revision"); + WRITEINFO(disc, TotalInSet, L"Disc Discs"); + WRITEINFO(disc, NumberInSet, L"Disc Disc #"); + WRITEINFO(disc, LanguageId, L"Disc Language Id"); + WRITEINFO(disc, RevisionTag, L"Disc Revision Tag"); + WRITEINFO_LONG(disc, Compilation, L"Disc Compilation"); + + ICddbDisc2 *disc2; + disc->QueryInterface(&disc2); + WRITEINFO(disc2, ReleaseDate, L"Disc Release Date"); + WRITEINFO(disc2, RecordingDate, L"Disc Recording Date"); + WRITEINFO(disc2, ProductCode, L"Disc Product Code"); + WRITEINFO(disc2, YearComposed, L"Disc Year Composed"); + disc2->Release(); + + ICddbCredits *credits; + disc->get_Credits(&credits); + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCredit *credit; + credits->GetCredit(c + 1, &credit); + WRITEINFO(credit, Id, L"Credit ID"); + WRITEINFO(credit, Name, L"Credit Name"); + WRITEINFO(credit, Notes, L"Credit Notes"); + credit->Release(); + } + credits->Release(); + + ICddbTracks *tracks; + disc->get_Tracks(&tracks); + tracks->get_Count(&numTracks); + for (int i = 0;i < numTracks;i++) + { + ICddbTrack *track; + tracks->GetTrack(i + 1, &track); + fputws(L"-----------------\r\n", fp); + WRITEINFO(track, Title, L"Track Title"); + WRITEINFO(track, Artist, L"Track Artist"); + WRITEINFO(track, Year, L"Track Year"); + WRITEINFO(track, Label, L"Track Label"); + WRITEINFO(track, Notes, L"Track Notes"); + WRITEINFO(track, GenreId, L"Track GenreId"); + WRITEINFO(track, SecondaryGenreId, L"Track SecondaryGenreId"); + WRITEINFO(track, Lyrics, L"Track Lyrics"); + WRITEINFO(track, BeatsPerMinute, L"Track BPM"); + WRITEINFO(track, ISRC, L"Track ISRC"); + + ICddbTrack2 *track2; + track->QueryInterface(&track2); + WRITEINFO(track2, ReleaseDate, L"Release Date"); + WRITEINFO(track2, RecordingDate, L"Recording Date"); + WRITEINFO(track2, YearComposed, L"Year Composed"); + track2->Release(); + + ICddbCredits *credits; + track->get_Credits(&credits); + if (credits) + { + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCredit *credit; + credits->GetCredit(c + 1, &credit); + WRITEINFO(credit, Id, L"Credit ID"); + WRITEINFO(credit, Name, L"Credit Name"); + WRITEINFO(credit, Notes, L"Credit Notes"); + credit->Release(); + } + credits->Release(); + } + track->Release(); + } + + tracks->Release(); + fclose(fp); +#endif +} +#endif + +#ifdef IGNORE_API_GRACENOTE +static HRESULT CALLBACK Cddb_ResultCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user) +{ + int index; + CACHEREC *pRec; + CBDATA *pData = (CBDATA*)user; + if (!pData) return E_POINTER; + DINFO *pDI = NULL; + + for (index = 0, pRec = &cddb_cache[0]; index < MAX_CACHE_SIZE && 0 != pRec->discInfo.CDDBID; pRec++, index++) + { + if (pRec->discInfo.CDDBID == pData->cddbid) + { + pDI = &pRec->discInfo; + + break; + } + } + if (!pDI) return S_OK; + + if (S_OK == result) + { + #ifndef IGNORE_API_GRACENOTE + if (pDisc) + { + DumpInfoFile(pDisc); + GetDiscInfo(pDisc, pDI); + StoreDisc(pDI->CDDBID, pDisc); + ICddbCacheManager* pCache; + HRESULT hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + CComBSTR toc; + pDisc->get_Toc(&toc); + pCache->StoreDiscByToc(toc, pDisc); + pCache->Release(); + } + pDI->populated = true; + } + #endif + } + else + { + #ifndef IGNORE_API_GRACENOTE + if (DoCDText(pDI, pData->cLetter)) + { + StoreCDText(pDI->CDDBID, pData->cLetter); + result = S_OK; + } + #endif + } + + CddbCache_SetDisc(pDI, result); + + if (pData->ps->CDDBID == pDI->CDDBID) + { + *pData->ps = *pDI; + } + return S_OK; +} +#endif + +void InitializeCddbCache(void) +{ + ZeroMemory(cddb_cache, sizeof(CACHEREC)*MAX_CACHE_SIZE); + cddb_cache_cursor = 0; +} + +void UninitializeCddbCache(void) +{ + ZeroMemory(cddb_cache, sizeof(CACHEREC)*MAX_CACHE_SIZE); + cddb_cache_cursor = 0; +} + +HRESULT CddbCache_SetDisc(DINFO *pDiscInfo, HRESULT lookupResult) +{ + int index; + CACHEREC *pRec; + if (!pDiscInfo || 0 == pDiscInfo->CDDBID) return E_FAIL; + + for (index = 0, pRec = &cddb_cache[0]; index < MAX_CACHE_SIZE && 0 != pRec->discInfo.CDDBID; pRec++, index++) + { + if (pRec->discInfo.CDDBID == pDiscInfo->CDDBID) break; + } + if (0 == pRec->discInfo.CDDBID || MAX_CACHE_SIZE == index) + { + pRec = &cddb_cache[cddb_cache_cursor]; + cddb_cache_cursor++; + if (cddb_cache_cursor >= MAX_CACHE_SIZE) cddb_cache_cursor = 0; + } + + if (pRec) + { + pRec->result = lookupResult; + pRec->discInfo = *pDiscInfo; + } + + return S_OK; +} + +int GetCDDBInfo(DINFO *ps, wchar_t device) +{ + int index; + CACHEREC *pRec; + //HRESULT hr; + + //wchar_t szTOC[2048] = {0}; + + if (ps->populated) return 0; + + /* first, look in our memory cache */ + for (index = 0, pRec = &cddb_cache[0]; index < MAX_CACHE_SIZE && 0 != pRec->discInfo.CDDBID; pRec++, index++) + { + if (pRec->discInfo.CDDBID == ps->CDDBID) + { + if (S_OK == pRec->result) + *ps = pRec->discInfo; + else + DefaultValues(ps); + return 0; // no need to notify about changes + + } + } + + /* look it up in the local database */ + if (QueryDINFO(ps->CDDBID, ps)) + { + CddbCache_SetDisc(ps, S_OK); + return 0; + } + + /* check CDDB & CD-Text */ + /*CddbCache_SetDisc(ps, E_PENDING); + if (Cddb_CalculateTOC(ps, szTOC, sizeof(szTOC)/sizeof(wchar_t))) + { + ULONG flags; + CBDATA data; + data.ps = ps; + data.cLetter = device; + data.cddbid = ps->CDDBID; + flags = CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_NOMATCH; + if (!config_use_cddb || !IsInternetAvailable()) flags |= CDDB_NOINET; + hr = Cddb_DoLookup(szTOC, line.hMainWindow, Cddb_ResultCallback, flags, (ULONG_PTR)&data); + if (FAILED(hr)) Cddb_DisplayResultDlg(line.hMainWindow, hr, AUTOCLOSE_NEVER, flags); + } + else hr = CDDB_E_BADTOC; + if (FAILED(hr)) CddbCache_SetDisc(ps, hr);*/ + return 1;//SUCCEEDED(hr); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/EditCDInfo.cpp b/Src/Plugins/Input/in_cdda/EditCDInfo.cpp new file mode 100644 index 00000000..07cd3769 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/EditCDInfo.cpp @@ -0,0 +1,447 @@ +#include "main.h" +#include "cddb.h" +#include "../nu/ListView.h" +#include "cddbinterface.h" +#include "../Agave/Language/api_language.h" +#include "../Winamp/wa_ipc.h" +#include <atlbase.h> +#include <strsafe.h> + +int _g_disable_cddb; + +#if 0 +static DINFO *p; +static char dialogDevice; +W_ListView trackList; + +static void Populate(HWND hDlg) +{ + int x; + trackList.Clear(); + SetDlgItemTextW(hDlg, IDC_TITLE, p->title); + SetDlgItemTextW(hDlg, IDC_PUBLISHER, p->label); + SetDlgItemTextW(hDlg, IDC_ARTIST, p->artist); + SetDlgItemTextW(hDlg, IDC_GENRE, p->genre); + SetDlgItemTextW(hDlg, IDC_YEAR, p->year); + CheckDlgButton(hDlg, IDC_COMPILATION, p->compilation?BST_CHECKED:BST_UNCHECKED); + for (x = 0; x < p->ntracks; x ++) + { + trackList.InsertItem(x, p->tracks[x].artist, 0); + trackList.SetItemText(x, 1, p->tracks[x].title); + } +} + +static HRESULT CALLBACK Cddb_ResultCallback(DWORD cddbId, HRESULT result, ICddbDisc *pDisc, ULONG_PTR user) +{ + CBDATA *pData = (CBDATA*)user; + DefaultValues(pData->p); + + if(S_OK == result) + { + + } + else if (S_FALSE == result) + { + + } + else if (S_MULTIPLE == result) + { + + } + Populate(pData->hwnd); + return S_OK; +} + +static LRESULT CALLBACK EditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_NOTIFYFORMAT: + return NFR_UNICODE; + + case WM_INITDIALOG: + trackList.setwnd(GetDlgItem(hDlg, IDC_TRACKS)); + + RECT rect1, rect2; + GetWindowRect(GetDlgItem(hDlg, IDC_EDITARTIST), &rect1); + GetWindowRect(GetDlgItem(hDlg, IDC_EDITTEXT), &rect2); + + trackList.AddCol(WASABI_API_LNGSTRINGW(plugin.hDllInstance,IDS_ARTIST), rect2.left-rect1.left-3); + trackList.AddCol(WASABI_API_LNGSTRINGW(plugin.hDllInstance,IDS_TITLE), (rect2.right-rect2.left)-18); + + if (_g_disable_cddb) EnableWindow(GetDlgItem(hDlg, IDC_GETCDDB), 0); + SendDlgItemMessage(hDlg, IDC_TITLE, EM_LIMITTEXT, 512, 0); + SendDlgItemMessage(hDlg, IDC_PUBLISHER, EM_LIMITTEXT, 512, 0); + SendDlgItemMessage(hDlg, IDC_ARTIST, EM_LIMITTEXT, 512, 0); + SendDlgItemMessage(hDlg, IDC_YEAR, EM_LIMITTEXT, 8, 0); + SendDlgItemMessage(hDlg, IDC_GENRE, EM_LIMITTEXT, 64, 0); + SendDlgItemMessage(hDlg, IDC_EDITTEXT, EM_LIMITTEXT, 512, 0); + SendDlgItemMessage(hDlg, IDC_EDITARTIST, EM_LIMITTEXT, 512, 0); + + if (GetCDDBInfo(p, dialogDevice)) + { + int x; + SetDlgItemText(hDlg, IDC_TITLE, WASABI_API_LNGSTRINGW(line.hDllInstance,IDS_TITLE)); + SetDlgItemText(hDlg, IDC_ARTIST, WASABI_API_LNGSTRINGW(line.hDllInstance,IDS_ALBUM_ARTIST)); + for (x = 0; x < p->ntracks; x ++) + { + wchar_t buf[128] = {0}; + StringCchPrintfW(buf, 128, L"Track %d", x + 1); + trackList.InsertItem(x, "Artist", 0); + trackList.SetItemText(x, 1, buf); + } + } + else + { + Populate(hDlg); + } + + return 1; + case WM_NOTIFY: + { + LPNMHDR l = (LPNMHDR)lParam; + switch (l->code) + { + case LVN_ITEMCHANGED: + { + LPNMLISTVIEW lvNotif = (LPNMLISTVIEW)l; + if (lvNotif->uNewState & LVIS_SELECTED) + { + wchar_t buf[512] = {0}; + trackList.GetText(trackList.GetNextSelected(-1), 0, buf, 512); + SetDlgItemTextW(hDlg, IDC_EDITARTIST, buf); + trackList.GetText(trackList.GetNextSelected(-1), 1, buf, 512); + SetDlgItemTextW(hDlg, IDC_EDITTEXT, buf); + } + } + break; + } + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_GETCDDB: + { + wchar_t szTOC[2048] = {0}; + if (Cddb_CalculateTOC(p, szTOC, sizeof(szTOC)/sizeof(wchar_t))) + { + CBDATA data = { p, hDlg }; + HRESULT hr = Cddb_DoLookup(p->CDDBID, szTOC, hDlg, Cddb_ResultCallback, + CDDB_NOCACHE | CDDB_MODAL | CDDB_UI_MULTIPLE, (ULONG_PTR)&data); + } + else hr = CDDB_E_BADTOC; + } + break; + case IDC_CDTEXT: + if (DoCDText(p, dialogDevice)) + { + Populate(hDlg); + } + break; + case IDCANCEL: EndDialog(hDlg, 1); break; + case IDOK: + { + int x; + GetDlgItemTextW(hDlg, IDC_TITLE, p->title, TITLE_SIZE); + GetDlgItemTextW(hDlg, IDC_PUBLISHER, p->label, 511); p->label[511] = 0; + GetDlgItemTextW(hDlg, IDC_ARTIST, p->artist, ARTIST_SIZE); + GetDlgItemTextW(hDlg, IDC_GENRE, p->genre, 63); p->genre[63] = 0; + GetDlgItemTextW(hDlg, IDC_YEAR, p->year, 8); + p->compilation = !!IsDlgButtonChecked(hDlg, IDC_COMPILATION); + for (x = 0; x < p->ntracks; x ++) + { + trackList.GetText(x, 0, p->tracks[x].artist, ARTIST_SIZE); + trackList.GetText(x, 1, p->tracks[x].title, TITLE_SIZE); + } + AddToDatabase(p); + } + + EndDialog(hDlg, 0); + break; + case IDC_REMOVE: + RemoveFromDatabase(p); + EndDialog(hDlg, 1); break; + + case IDC_EDITTEXT: + if (HIWORD(wParam) == EN_CHANGE) + { + wchar_t buf[512] = {0}; + int p = trackList.GetNextSelected(-1); + if (p != LB_ERR) + { + GetDlgItemTextW(hDlg, IDC_EDITTEXT, buf, 512); + trackList.SetItemText(p, 1, buf); + } + } + break; + + case IDC_EDITARTIST: + if (HIWORD(wParam) == EN_CHANGE) + { + wchar_t buf[512] = {0}; + int p = trackList.GetNextSelected(-1); + if (p != LB_ERR) + { + GetDlgItemTextW(hDlg, IDC_EDITARTIST, buf, 512); + trackList.SetItemText(p, 0, buf); + + if (!IsDlgButtonChecked(hDlg, IDC_COMPILATION)) + { + wchar_t buf2[512] = {0}; + GetDlgItemTextW(hDlg, IDC_ARTIST, buf2, 512); + if (lstrcmp(buf, buf2)) + CheckDlgButton(hDlg, IDC_COMPILATION, BST_CHECKED); + } + } + } + break; + case IDC_ARTIST: + if (HIWORD(wParam) == EN_CHANGE && !IsDlgButtonChecked(hDlg, IDC_COMPILATION)) + { + wchar_t buf[512] = {0}; + GetDlgItemTextW(hDlg, IDC_ARTIST, buf, 512); + + for (int x = 0; x < p->ntracks; x ++) + { + trackList.SetItemText(x, 0, buf); + } + if (trackList.GetNextSelected(-1) != LB_ERR) + { + SetDlgItemTextW(hDlg, IDC_EDITARTIST, buf); + + } + } + break; + + } + return 0; + } + return 0; +} + +void DBEdit(DINFO *ps, HWND hwnd, int l, char device) +{ + static int i = 0; + if (i) return ; + i = 1; + p = ps; + dialogDevice = device; + _g_disable_cddb = l; + if (!WASABI_API_DIALOGBOX(IDD_EDIT, hwnd, (DLGPROC)EditProc)) + { + PostMessage(line.hMainWindow, WM_USER, (WPARAM)L"cda://", 247 /*IPC_REFRESHPLCACHE*/); + } + i = 0; +} + +#endif +#if 0 + +typedef struct _EDITDATA +{ + DINFO *p; + INT modified; + CHAR cDevice; + +} EDITDATA; + +#define GET_DATA(__hwnd) (EDITDATA*)(LONG_PTR)GetWindowLongPtrW((__hwnd), GWLP_USERDATA); + + +#define SET_IF(hwndDlg, id, data) if (data) SetDlgItemText(hwndDlg, id, data); else SetDlgItemText(hwndDlg, id, L""); +static void Fill(HWND hwndDlg, const DINFO *info) +{ + SET_IF(hwndDlg, IDC_TITLE, info->title); + SET_IF(hwndDlg, IDC_ARTIST, info->artist); + + if (info->discnum) + SetDlgItemInt(hwndDlg, IDC_DISC, info->discnum, FALSE); + else + SetDlgItemText(hwndDlg, IDC_DISCS, L""); + + if (info->numdiscs) + SetDlgItemInt(hwndDlg, IDC_DISCS, info->numdiscs, FALSE); + else + SetDlgItemText(hwndDlg, IDC_DISCS, L""); + + SET_IF(hwndDlg, IDC_YEAR, info->year); + SET_IF(hwndDlg, IDC_LABEL, info->label); + SET_IF(hwndDlg, IDC_NOTES, info->notes); + SET_IF(hwndDlg, IDC_GENRE, info->genre); + + CheckDlgButton(hwndDlg, IDC_COMPILATION, (info->compilation)?BST_CHECKED:BST_UNCHECKED); + SendDlgItemMessage(hwndDlg, IDC_TRACKLIST, LB_RESETCONTENT, 0, 0); + + for (int x = 0; x < info->ntracks; x ++) + { + wchar_t buf[1100] = {0}; + if (!info->tracks[x].title) + StringCchPrintfW(buf, 1100, L"%d.", x+1); + else if (info->tracks[x].artist && info->tracks[x].artist[0] && wcscmp(info->tracks[x].artist, info->artist)) + StringCchPrintfW(buf, 1100, L"%d. %s - %s", x+1, info->tracks[x].artist, info->tracks[x].title); + else + StringCchPrintfW(buf, 1100, L"%d. %s", x+1, info->tracks[x].title); + SendDlgItemMessageW(hwndDlg, IDC_TRACKLIST, LB_ADDSTRING, 0, (LPARAM)buf); + + } +} + +static HRESULT CALLBACK Cddb_LookupCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user) +{ + HWND hwnd = (HWND)user; + EDITDATA *pData = GET_DATA(hwnd); + if (!pData) return E_INVALIDARG; + + if(S_OK == result) + { + pData->modified = 1; + DefaultValues(pData->p); + GetDiscInfo(pDisc, pData->p); + StoreDisc(pData->p->CDDBID, pDisc); + ICddbCacheManager* pCache; + HRESULT hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + CComBSTR toc; + pDisc->get_Toc(&toc); + hr = pCache->StoreDiscByToc(toc, pDisc); + pCache->Release(); + } + Fill(hwnd, pData->p); + } + else + { + *pdwAutoCloseDelay = AUTOCLOSE_NEVER; + } + CddbCache_SetDisc(pData->p, result); + return S_OK; +} + +static HRESULT CALLBACK Cddb_EditCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user) +{ + HWND hwnd = (HWND)user; + EDITDATA *pData = GET_DATA(hwnd); + if (!pData) return E_INVALIDARG; + + if (FAILED(result)) + { + *pdwAutoCloseDelay = AUTOCLOSE_NEVER; + return S_OK; + } + + if (SUCCEEDED(result)) + { + HRESULT hr(S_OK); + wchar_t szTOC[2048] = {0}; + ICDDBControl *pControl; + CDDBUIFlags uiFlags = UI_EDITMODE; + + if (!Cddb_CalculateTOC(pData->p, szTOC, sizeof(szTOC)/sizeof(wchar_t))) hr = CDDB_E_BADTOC; + if (SUCCEEDED(hr)) hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + if (!pDisc) + { + uiFlags = UI_SUBMITNEW; + hr = pControl->GetSubmitDisc(szTOC, 0, 0, &pDisc); + if (FAILED(hr)) pDisc = NULL; + } + else pDisc->AddRef(); + + if (pDisc) + { + Cddb_DisplayDiscInfo(pDisc, &uiFlags, hwnd); + if (uiFlags & UI_DATA_CHANGED) + { + ICddbCacheManager* pCache; + hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + hr = pCache->StoreDiscByToc(szTOC, pDisc); + pCache->Release(); + } + + pData->modified = 1; + DefaultValues(pData->p); + GetDiscInfo(pDisc, pData->p); + StoreDisc(pData->p->CDDBID, pDisc); + Fill(hwnd, pData->p); + CddbCache_SetDisc(pData->p, S_OK); + } + pDisc->Release(); + } + pControl->Release(); + } + + } + return S_OK; +} + +static LRESULT CALLBACK EditProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + EDITDATA *pData; + + switch (message) + { + case WM_INITDIALOG: + { + pData = (EDITDATA*)lParam; + if (!pData) { EndDialog(hwndDlg, 0); return 0; } + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); + pData->modified = 0; + Fill(hwndDlg, pData->p); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CDDB: + { + wchar_t szTOC[2048] = {0}; + pData = GET_DATA(hwndDlg); + + if (pData && Cddb_CalculateTOC(pData->p, szTOC, sizeof(szTOC)/sizeof(wchar_t))) + { + UINT flags = CDDB_NOCACHE | CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL; + HRESULT hr = Cddb_DoLookup(szTOC, hwndDlg, Cddb_LookupCallback, flags, (ULONG_PTR)hwndDlg); + if (FAILED(hr)) Cddb_DisplayResultDlg(hwndDlg, hr, AUTOCLOSE_NEVER, flags); + } + } + break; + case IDC_EDIT: + { + wchar_t szTOC[2048] = {0}; + pData = GET_DATA(hwndDlg); + + if (pData && Cddb_CalculateTOC(pData->p, szTOC, sizeof(szTOC)/sizeof(wchar_t))) + { + UINT flags = CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL; + HRESULT hr = Cddb_DoLookup(szTOC, hwndDlg, Cddb_EditCallback, flags, (ULONG_PTR)hwndDlg); + if (FAILED(hr)) Cddb_DisplayResultDlg(hwndDlg, hr, AUTOCLOSE_NEVER, flags); + } + } + break; + case IDCANCEL: + pData = (EDITDATA*)(LONG_PTR)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + EndDialog(hwndDlg, (pData) ? pData->modified : 0); + break; + } + break; + } + return 0; +} +bool CDEdit(CHAR cDevice, DINFO *ps, HWND hwnd) +{ + EDITDATA data; + ZeroMemory(&data, sizeof(EDITDATA)); + data.cDevice = cDevice; + data.p = ps; + + if (WASABI_API_DIALOGBOXPARAM(IDD_EDIT, hwnd, (DLGPROC)EditProc, (LPARAM)&data)) + { + PostMessageW(line.hMainWindow, WM_USER, (WPARAM)L"cda://", IPC_REFRESHPLCACHE); + } + return ( 0 != data.modified); +} +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/ExtendedFileInfo.cpp b/Src/Plugins/Input/in_cdda/ExtendedFileInfo.cpp new file mode 100644 index 00000000..2b620294 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/ExtendedFileInfo.cpp @@ -0,0 +1,1241 @@ +#define SKIP_OVER +#include "main.h" +#include "api__in_cdda.h" + +#include "CDPlay.h" +#include "DAEPlay.h" +#include "MCIPlay.h" +#include "WindacPlay.h" + +#include "cddb.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoChar.h" +#include "../nde/ndestring.h" +#include "../nu/ListView.h" +#ifndef IGNORE_API_GRACENOTE +#include "../primo/obj_primo.h" +#endif +#include "../Winamp/wa_ipc.h" +#include <api/service/waservicefactory.h> +#include <shlwapi.h> +#include <atlbase.h> +#include <strsafe.h> + +#if 0 +BOOL CALLBACK ripConfigProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +#endif + +static int cachedev_used; +static MCIDEVICEID cachedev; +static wchar_t last_fn[8]; +extern "C" __declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, int destlen) +{ + s_last_error = NULL; + if (!_stricmp(data, "type")) + { + lstrcpynW(dest, L"0", destlen); //audio + return 1; + } + else if (!_stricmp(data, "family")) + { + LPCWSTR e, p(NULL); + DWORD lcid; + e = PathFindExtensionW(fn); + if (L'.' != *e) return 0; + e++; + lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, e, -1, L"CDA", -1)) p = WASABI_API_LNGSTRINGW(IDS_FAMILY_STRING); + if (p && S_OK == StringCchCopyW(dest, destlen, p)) return 1; + return 0; + } + else if (!_stricmp(data, "ext_cdda")) + { + lstrcpynW(dest, L"1", destlen); //audio + return 1; + } + + // TODO determine if we even keep any of this... + /* + else if (!_stricmp(data, "cdda_config_text")) + { + WASABI_API_LNGSTRINGW_BUF(IDS_RIPPING,dest,destlen); + return 1; + } + else if (!_strnicmp(data, "cdda_cf_", 8)) + { + HWND parent = (HWND)atoi(data + 8); + dest[0] = 0; + if (parent && IsWindow(parent)) + { + parent = WASABI_API_CREATEDIALOGW(IDD_PREFS_CDRIP, parent, ripConfigProc); + _itow((int)parent, dest, 10); + } + return 1; + } + */ + + if (!lstrcmpiW(PathFindExtensionW(fn), L".cda") && !_wcsnicmp(fn + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX + { + static wchar_t fakebuf[128]; + StringCchPrintf(fakebuf, 128, L"cda://%c,%d", fn[0], _wtoi(PathFindFileNameW(fn) + 5)); + fn = fakebuf; + } + + if (!_wcsnicmp(fn, L"cda://", 6)) // determine length of cd track via MCI + { + int track = lstrlenW(fn) > 8 ? _wtoi(fn + 8) : 0; + int device = fn[6]; + if (device >= 'a' && device <= 'z') device += 'A' -'a'; + MCIDEVICEID dev2 = 0; + + if (cachedev_used) dev2 = cachedev; + + if (!_stricmp(data, "discid") || !_stricmp(data, "cddbid")) + { + dest[0] = 0; +#ifdef DISCID + DiscId *disc = discid_new(); + wchar_t drive[4] = {device, L':'}; + + if (!discid_read_sparse(disc, drive, 0)) { + discid_free(disc); + return 0; + } + + if (!_stricmp(data, "cddbid")) + lstrcpynW(dest, AutoWide(discid_get_freedb_id(disc)), destlen); + else + lstrcpynW(dest, AutoWide(discid_get_id(disc)), destlen); + + discid_free(disc); +#endif + } + else if (!_stricmp(data, "cdengine")) + { + dest[0] = 0; + if (g_cdplay && device && g_cdplay->IsPlaying(device)) + { + if (g_cdplay == daePlayer) + lstrcpynW(dest, L"DAE", destlen); + else if (g_cdplay == windacPlayer) + { + if (hDLL) + lstrcpynW(dest, L"ASPI", destlen); + else + lstrcpynW(dest, L"SPTI", destlen); + } + else if (g_cdplay == mciPlayer) + lstrcpynW(dest, L"MCI", destlen); + } + return 1; + } + else if (!_stricmp(data, "<begin>")) + { + if (!CDOpen(&cachedev, device, L"cache")) + cachedev = 0; + + if (NULL != dest && destlen > 1) + { + dest[0] = (NULL != cachedev) ? L'1' : L'0'; + dest[1] = L'\0'; + } + + cachedev_used = 1; + //OutputDebugString("begin device caching\n"); + } + else if (!_stricmp(data, "<end>")) + { + if (cachedev_used && cachedev) + CDClose(&cachedev); + //OutputDebugString("end device caching\n"); + cachedev_used = 0; + cachedev = 0; + } + else if (!_stricmp(data, "<eject>")) + { + if (!cachedev_used) + { + if (!CDOpen(&dev2, device, L"eject")) + dev2 = 0; + } + if (dev2) + { + CDEject(dev2); + if (dev2 != cachedev) + CDClose(&dev2); + } + } + else if (!_stricmp(data, "ntracks")) + { + if (!cachedev_used) + { + if (!CDOpen(&dev2, device, L"ntracks")) dev2 = 0; + } + if (dev2) + { + _itow(CDGetTracks(dev2), dest, 10); + if (dev2 != cachedev) CDClose(&dev2); + } + else + { + if (NULL != dest && destlen > 1) + { + dest[0] = L'0'; + dest[1] = L'\0'; + } + } + } + else if (!_stricmp(data, "tracktype")) + { + if (!cachedev_used) + { + if (!CDOpen(&dev2, device, L"tracktype")) dev2 = 0; + } + if (dev2) + { + MCI_STATUS_PARMS sMCIStatus; + sMCIStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + sMCIStatus.dwTrack = track; + if (mciSendCommand(dev2, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR) &sMCIStatus)) + WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,dest,destlen); + else lstrcpynW(dest, (sMCIStatus.dwReturn != MCI_CDA_TRACK_AUDIO ? L"data" : L"audio"), destlen); + + if (dev2 != cachedev) CDClose(&dev2); + } + } + else if (!_stricmp(data, "length")) + { + if (!cachedev_used) + { + if (!CDOpen(&dev2, device, L"length")) dev2 = 0; + } + if (dev2) + { + MCI_SET_PARMS sMCISet; + sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS; + MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + _itow(CDGetTrackLength(dev2, track), dest, 10); + sMCISet.dwTimeFormat = MCI_FORMAT_TMSF; + MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + + if (dev2 != cachedev) + CDClose(&dev2); + } + } + else if (!_stricmp(data, "album") || !_stricmp(data, "artist") || + !_stricmp(data, "year") || !_stricmp(data, "genre") || + !_stricmp(data, "title") || !_stricmp(data, "comment") || + !_stricmp(data, "tuid") || !_stricmp(data, "albumartist") || + !_stricmp(data, "publisher") || !_stricmp(data, "disc") || + !_stricmp(data, "conductor") || !_stricmp(data, "composer") || + !_stricmp(data, "remixing") || !_stricmp(data, "isrc") || + !_stricmp(data, "GracenoteFileID") || !_stricmp(data, "GracenoteExtData") + ) + { + int cached = 0; + //cache our myps + static DINFO myps; + /*static unsigned int last_time; + unsigned int now = GetTickCount();*/ + cached = !_wcsnicmp(fn, last_fn, 7); + // TODO disabled as this is causing more access issues than it seems to help... + /*if (cached) + { + if (now > last_time + 1000) cached = 0; + if (now < last_time - 1000) cached = 0; // counter wrapped + }*/ + + if (!cached) + { + lstrcpynW(last_fn, fn, 8); + + memset(&myps, 0, sizeof(myps)); + if (!cachedev_used) + { + if (CDOpen(&dev2, device, L"extinfo")) + { + GetDiscID(dev2, &myps); + CDClose(&dev2); + } + } + else GetDiscID(dev2, &myps); + } + + if (myps.CDDBID) + { + // try to get CDDB information and then revert to CD-Text if CDDB is not available + if (GetCDDBInfo(&myps, device)) + { + wchar_t cache[] = {L"cda://x"}; + cache[6] = device; + PostMessage(line.hMainWindow, WM_WA_IPC, (WPARAM)cache, IPC_REFRESHPLCACHE); + } + else if (!cached && !myps.populated) + { + if (DoCDText(&myps, device)) + { + wchar_t cache[] = {L"cda://x"}; + cache[6] = device; + PostMessage(line.hMainWindow, WM_WA_IPC, (WPARAM)cache, IPC_REFRESHPLCACHE); + } + } + + if (!_stricmp(data, "album")) + { + if (myps.title) + lstrcpynW(dest, myps.title, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "artist") && track>0 && track<100) + { + if (myps.tracks[track-1].artist) + lstrcpynW(dest, myps.tracks[track-1].artist, destlen); + else if (myps.artist) + lstrcpynW(dest, myps.artist, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "albumartist")) + { + if (myps.artist) + lstrcpynW(dest, myps.artist, destlen); + else if (track == 0) + WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ARTIST,dest,destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "title") && track>0 && track<100) + { + if (myps.tracks[track-1].title) + lstrcpynW(dest, myps.tracks[track-1].title, destlen); + else + StringCchPrintfW(dest, destlen, WASABI_API_LNGSTRINGW(IDS_TRACK_X), track); + } + else if (!_stricmp(data, "year")) + { + if (myps.year) + lstrcpynW(dest, myps.year, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "genre")) + { + if (myps.genre) + lstrcpynW(dest, myps.genre, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "comment")) + { + if (myps.notes) + lstrcpynW(dest, myps.notes, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "publisher")) + { + if (myps.label) + lstrcpynW(dest, myps.label, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "composer")) + { + if (track>0 && myps.tracks[track-1].composer) + lstrcpynW(dest, myps.tracks[track-1].composer, destlen); + else if (myps.composer) + lstrcpynW(dest, myps.composer, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "remixing")) + { + if (track>0 && myps.tracks[track-1].remixing) + lstrcpynW(dest, myps.tracks[track-1].remixing, destlen); + else if (myps.composer) + lstrcpynW(dest, myps.remixing, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "conductor")) + { + if (track>0 && myps.tracks[track-1].conductor) + lstrcpynW(dest, myps.tracks[track-1].conductor, destlen); + else if (myps.conductor) + lstrcpynW(dest, myps.conductor, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "isrc") && track>0 && track<100) + { + if (myps.tracks[track-1].isrc) + lstrcpynW(dest, myps.tracks[track-1].isrc, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "GracenoteFileID") && track>0 && track<100) + { + if (myps.tracks[track-1].tagID) + lstrcpynW(dest, myps.tracks[track-1].tagID, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "GracenoteExtData") && track>0 && track<100) + { + if (myps.tracks[track-1].extData) + lstrcpynW(dest, myps.tracks[track-1].extData, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "tuid")) + { + if (myps.tuid) + lstrcpynW(dest, myps.tuid, destlen); + else + dest[0]=0; + } + else if (!_stricmp(data, "disc")) + { + if (myps.numdiscs > 0) + StringCchPrintf(dest, destlen, L"%u/%u", myps.discnum, myps.numdiscs); + else if (myps.discnum) + StringCchPrintf(dest, destlen, L"%u", myps.discnum); + else + dest[0] = 0; + } + else + { +// last_time = GetTickCount(); + return 0;// some error condition (such as track == 0) got us here + } + } + else + { + if (!_stricmp(data, "title") && track>0 && track<100) + { + StringCchPrintfW(dest, destlen, WASABI_API_LNGSTRINGW(IDS_TRACK_X), track); + } + last_fn[0] = 0x00; + } +// last_time = GetTickCount(); + } + else if (!_stricmp(data, "cdtype")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + DWORD retCode = PRIMOSDK_OK + 1; + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = (DWORD)fn[6]; + DWORD mediumtype; + DWORD mediumformat; + DWORD erasable; + DWORD tracks, used, free; + retCode = primo->DiscInfo(&unit, &mediumtype, &mediumformat, &erasable, &tracks, &used, &free); + if (retCode == PRIMOSDK_OK) + { + if (mediumformat > 0xf0 && mediumformat < 0xff) lstrcpynW(dest, L"DVD", destlen); + else lstrcpynW(dest, L"CD", destlen); + if (mediumtype == PRIMOSDK_BLANK || mediumtype == PRIMOSDK_COMPLIANTGOLD) StringCchCatW(dest, destlen, L"R"); + if (erasable) StringCchCatW(dest, destlen, L"W"); + } + sf->releaseInterface(primo); + } + return (retCode == PRIMOSDK_OK); + #else + return 0; + #endif + } + else if (!_stricmp(data, "cdtype2")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + DWORD retCode = PRIMOSDK_OK + 1; + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = (DWORD)fn[6]; + DWORD mediumType; + DWORD mediumFormat; + DWORD erasable; + DWORD tracks, used, free; + DWORD medium = -1, protectedDVD = -1, mediumEx = -1; + DWORD rfu; + retCode = primo->DiscInfoEx(&unit, 1, &mediumType, &mediumFormat, &erasable, &tracks, &used, &free); + if (retCode == PRIMOSDK_OK) + { + primo->DiscInfo2(&unit, &medium, &protectedDVD, NULL, &mediumEx, &rfu); + //format: mediumType;mediumFormat;mediumEx;protectedDVD;erasable;tracks;used;free + StringCchPrintfW(dest, destlen, L"%d;%d;%d;%d;%d;%d;%d;%d", mediumType, mediumFormat, mediumEx, protectedDVD, erasable, tracks, used, free); + } + sf->releaseInterface(primo); + } + return (retCode == PRIMOSDK_OK); + #else + return 0; + #endif + } + else if (!_stricmp(data, "cdlengths")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = (DWORD)fn[6]; + DWORD mediumtype; + DWORD mediumformat; + DWORD erasable; + DWORD tracks, used, free; + if (primo->DiscInfo(&unit, &mediumtype, &mediumformat, &erasable, &tracks, &used, &free) == PRIMOSDK_OK) + { + StringCchPrintfW(dest, destlen, L"%d,%d", free, used); + } + sf->releaseInterface(primo); + } + #endif + } + else if (!_stricmp(data, "cdspeeds")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + DWORD retCode = PRIMOSDK_OK + 1; + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = (DWORD)fn[6]; + DWORD cdspeeds[32]; + DWORD dvdspeeds[32]; + DWORD capabilities; + retCode = primo->UnitSpeeds(&unit, (unsigned long *) & cdspeeds, (unsigned long *) & dvdspeeds, &capabilities); + if (retCode == PRIMOSDK_OK) + { + wchar_t *p = dest; + //reading speeds + int i; + for (i = 0;cdspeeds[i] != 0xFFFFFFFF;i++); + i++; + //CD-R speeds + for (;cdspeeds[i] != 0xFFFFFFFF;i++) + { + StringCchPrintfW(p, destlen, L"%d", cdspeeds[i]); + StringCchCatW(p, destlen, L"/"); + p += lstrlenW(p); + } + *p = ';'; + p++; + i++; + //CD-RW speeds + for (;cdspeeds[i] != 0xFFFFFFFF;i++) + { + StringCchPrintfW(p, destlen, L"%d", cdspeeds[i]); + StringCchCatW(p, destlen, L"/"); + p += lstrlenW(p); + } + } + sf->releaseInterface(primo); + } + return (retCode == PRIMOSDK_OK); + #else + return 0; + #endif + } + else if (!_stricmp(data, "cdinfo")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + DWORD retCode = PRIMOSDK_OK + 1; + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = (DWORD)fn[6]; + DWORD type; + BYTE szUnitDescr[64 + 1] = {0,}; // Unit Vendor, Model and FW. version + + retCode = primo->UnitInfo(&unit, &type, szUnitDescr, NULL); + if (retCode == PRIMOSDK_OK) + { + StringCchPrintfW(dest, destlen, L"%d;%s", type, (wchar_t *)AutoWide((char *)szUnitDescr)); + } + sf->releaseInterface(primo); + } + return (retCode == PRIMOSDK_OK); + #else + return 0; + #endif + } + else if (!_stricmp(data, "cdlock")) + { + dest[0] = 0; + #ifndef IGNORE_API_GRACENOTE + if (!m_veritas_handle) + { + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) m_veritas_handle = reinterpret_cast<obj_primo *>(sf->getInterface()); + } + + if (!m_veritas_handle) + return 0; + + m_nblock++; + DWORD unit = (DWORD)fn[6]; + m_veritas_handle->UnitLock(&unit, PRIMOSDK_LOCK); + lstrcpynW(dest, L"locked", destlen); + return 1; + #else + return 0; + #endif + } + else if (!_stricmp(data, "cdunlock")) + { + if (!m_nblock) return 0; + + #ifndef IGNORE_API_GRACENOTE + if (!m_veritas_handle) + { + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) m_veritas_handle = reinterpret_cast<obj_primo *>(sf->getInterface()); + } + + if (!m_veritas_handle) + return 0; + + DWORD unit = (DWORD)fn[6]; + m_veritas_handle->UnitLock(&unit, PRIMOSDK_UNLOCK); + m_nblock--; + lstrcpynW(dest, L"unlocked", destlen); + return 1; + #else + return 0; + #endif + } + else if (!_stricmp(data, "track") && track) + { + StringCchPrintfW(dest, destlen, L"%d", track); + return 1; + } + else if (!_stricmp(data, "bitrate") && track) + { + StringCchPrintfW(dest, destlen, L"%d", 1411/*200*/); + return 1; + } + else + return 0; + + return 1; + } + return 0; +} + +static wchar_t m_eiw_lastdrive; +//#ifndef IGNORE_API_GRACENOTE +static DINFO setInfo; +//#endif + +void ParseIntSlashInt(const wchar_t *string, int *part, int *parts); + +extern "C" __declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *val) +{ +//#ifndef IGNORE_API_GRACENOTE + s_last_error = NULL; + if (!lstrcmpiW(PathFindExtensionW(fn), L".cda") && !_wcsnicmp(fn + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX + { + static wchar_t fakebuf[128]; + StringCchPrintf(fakebuf, 128, L"cda://%c,%d", fn[0], _wtoi(PathFindFileNameW(fn) + 5)); + fn = fakebuf; + } + + wchar_t drive = 0; + int tracknum = -1; + if (!ParseName(fn, drive, tracknum)) + return 0; + + if (drive < 'A' || drive > 'Z') return 0; + + if (drive != m_eiw_lastdrive) + { + setInfo.Reset(); + setInfo.populated=false; + m_eiw_lastdrive = 0; + MCIDEVICEID dev2 = 0; + if (!CDOpen(&dev2, drive, L"setinfo")) dev2 = 0; + + if (dev2) + { + int ret = GetDiscID(dev2, &setInfo); + CDClose(&dev2); + if (!ret) + { + GetCDDBInfo(&setInfo, drive); + m_eiw_lastdrive = drive; + } + } + } + + if (!m_eiw_lastdrive) + return 0; + + #define DO_TRACK(comparetag, field) if (tracknum > 0 && tracknum < 100 && !_stricmp(data, comparetag)) {\ + ndestring_release(setInfo.tracks[tracknum-1]. ## field);\ + setInfo.tracks[tracknum-1]. ## field=0;\ + if (val && *val) setInfo.tracks[tracknum-1]. ## field=ndestring_wcsdup(val);\ + } + + #define DO_DISC(comparetag, field) if (!_stricmp(data, comparetag)) {\ + ndestring_release(setInfo. ## field);\ + setInfo. ## field=0;\ + if (val && *val) setInfo. ## field=ndestring_wcsdup(val);\ + } + + if (tracknum > 0 && tracknum < 100 && !_stricmp(data, "artist")) + { + if (val && setInfo.tracks[tracknum-1].artist == 0 && setInfo.artist && !_wcsicmp(setInfo.artist, val)) + val=0; + + ndestring_release(setInfo.tracks[tracknum-1].artist); + setInfo.tracks[tracknum-1].artist=0; + if (val && *val) setInfo.tracks[tracknum-1].artist=ndestring_wcsdup(val); + } + else DO_TRACK("title", title) + else DO_TRACK("composer", composer) + else DO_TRACK("conductor", conductor) + else DO_TRACK("GracenoteFileID", tagID) + else DO_TRACK("GracenoteExtData", extData) + else DO_DISC("album", title) + else DO_DISC("albumartist", artist) + else DO_DISC("genre", genre) + else DO_DISC("year", year) + else DO_DISC("comment", notes) + else DO_DISC("publisher", label) + else DO_DISC("tuid", tuid) + else DO_DISC("composer", composer) + else DO_DISC("conductor", conductor) + else if (!_stricmp(data, "disc")) + ParseIntSlashInt(val , &setInfo.discnum, &setInfo.numdiscs); + else +//#endif + return 0; + return 1; +} + +extern "C" __declspec(dllexport) int winampWriteExtendedFileInfo() +{ + s_last_error = NULL; + // write it out + if (m_eiw_lastdrive) + { + //#ifndef IGNORE_API_GRACENOTE + CddbCache_SetDisc(&setInfo, S_OK); + StoreDINFO(setInfo.CDDBID, &setInfo); + m_eiw_lastdrive = 0; + last_fn[0]=0; + if (cachedev_used) + { + CDClose(&cachedev); + cachedev_used=0; + } + return 1; + //#endif + } + return 0; +} + +// 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")! +extern "C" __declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn) +{ + return 1; +} + +#define SET_IF(hwndDlg, id, data) if (data) SetDlgItemText(hwndDlg, id, data); else SetDlgItemText(hwndDlg, id, L""); +static void Fill(HWND hwndDlg, const DINFO *info) +{ + SET_IF(hwndDlg, IDC_TITLE, info->title); + SET_IF(hwndDlg, IDC_ARTIST, info->artist); + + if (info->discnum) + SetDlgItemInt(hwndDlg, IDC_DISC, info->discnum, FALSE); + else + SetDlgItemText(hwndDlg, IDC_DISCS, L""); + + if (info->numdiscs) + SetDlgItemInt(hwndDlg, IDC_DISCS, info->numdiscs, FALSE); + else + SetDlgItemText(hwndDlg, IDC_DISCS, L""); + + SET_IF(hwndDlg, IDC_YEAR, info->year); + SET_IF(hwndDlg, IDC_LABEL, info->label); + SET_IF(hwndDlg, IDC_NOTES, info->notes); + SET_IF(hwndDlg, IDC_GENRE, info->genre); + + SendDlgItemMessage(hwndDlg, IDC_TRACKLIST, LB_RESETCONTENT, 0, 0); + + #ifndef IGNORE_API_GRACENOTE + for (int x = 0; x < info->ntracks; x ++) + { + wchar_t buf[1100] = {0}; + if (!info->tracks[x].title) + StringCchPrintfW(buf, 1100, L"%d.", x+1); + else if (info->tracks[x].artist && info->tracks[x].artist[0] && wcscmp(info->tracks[x].artist, info->artist)) + StringCchPrintfW(buf, 1100, L"%d. %s - %s", x+1, info->tracks[x].artist, info->tracks[x].title); + else + StringCchPrintfW(buf, 1100, L"%d. %s", x+1, info->tracks[x].title); + SendDlgItemMessageW(hwndDlg, IDC_TRACKLIST, LB_ADDSTRING, 0, (LPARAM)buf); + } + #endif +} + +#ifndef IGNORE_API_GRACENOTE +struct LookupData +{ + LookupData(HWND hwndDlg) + { + hwnd=hwndDlg; + dlgItem=0; + device=0; + tracknum=0; + use=false; + disc=0; + memset(szTOC, 0, sizeof(szTOC)); + } + ~LookupData() + { + if (disc) + disc->Release(); + } + HWND hwnd; + int dlgItem; + wchar_t szTOC[2048]; + char device; + int tracknum; + bool use; + ICddbDisc *disc; + DINFO info; +}; + +static HRESULT CALLBACK Cddb_LookupCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user) +{ + LookupData *data = (LookupData *)user; + + if (S_OK == result) + { + data->info.Reset(); + data->info.populated=false; + if (data->disc) + data->disc->Release(); + data->disc=pDisc; + data->disc->AddRef(); + GetDiscInfo(pDisc, &data->info); + Fill(data->hwnd, &data->info); + + ICddbCacheManager* pCache; + HRESULT hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + pCache->StoreDiscByToc(data->szTOC, data->disc); + pCache->Release(); + } + } + else + { + *pdwAutoCloseDelay = AUTOCLOSE_NEVER; + } + + return S_OK; +} + +static HRESULT CALLBACK Cddb_EditCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user) +{ + LookupData *data = (LookupData *)user; + + if (FAILED(result)) + { + *pdwAutoCloseDelay = AUTOCLOSE_NEVER; + return S_OK; + } + + if (SUCCEEDED(result)) + { + HRESULT hr(S_OK); + ICDDBControl *pControl; + CDDBUIFlags uiFlags = UI_EDITMODE; + + if (SUCCEEDED(hr)) hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + if (!pDisc) + { + uiFlags = UI_SUBMITNEW; + hr = pControl->GetSubmitDisc(data->szTOC, 0, 0, &pDisc); + if (FAILED(hr)) pDisc = NULL; + } + else + pDisc->AddRef(); + + if (pDisc) + { + HWND parent = GetParent(data->hwnd); + Cddb_DisplayDiscInfo(pDisc, &uiFlags, parent); + if (uiFlags & UI_DATA_CHANGED) + { + ICddbCacheManager* pCache; + hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + pCache->StoreDiscByToc(data->szTOC, pDisc); + pCache->Release(); + } + + data->info.Reset(); + data->info.populated=false; + if (data->disc) + data->disc->Release(); + data->disc=pDisc; + data->disc->AddRef(); + GetDiscInfo(pDisc, &data->info); + Fill(data->hwnd, &data->info); + } + pDisc->Release(); + } + pControl->Release(); + } + } + return S_OK; +} + +bool SubmitEdit(ICddbDisc *pDisc) +{ + //CDDBUIFlags uiFlags = UI_EDITMODE; + ICDDBControl *pControl; + + HRESULT hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + + long val; + pControl->SubmitDisc(pDisc, 0, &val); + pControl->Release(); + if (val == 0) + return true; + } + return false; +} +#endif + +#define SEND_DISC(field, val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)(val?val:L"")); +#define SEND_DISC_OR_TRACK(field, disc_val, track_val) { if (track_val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)track_val); else if (disc_val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)disc_val); else SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)L"");} +#define SEND_TRACK(field, val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)(val?val:L"")); + +#ifndef IGNORE_API_GRACENOTE +static void NotifyParent_MusicID(HWND hwndParent, const LookupData *data) +{ + DINFO disc = data->info; + TRACKINFO dummy; + TRACKINFO &track = data->tracknum?disc.tracks[data->tracknum-1]:dummy; + + SEND_DISC(L"album", disc.title); + SEND_DISC(L"albumartist", disc.artist); + SEND_DISC_OR_TRACK(L"artist", disc.artist, track.artist); + SEND_DISC(L"tuid", disc.tuid); + SEND_DISC(L"year", disc.year); + SEND_DISC(L"genre", disc.genre); + SEND_DISC(L"publisher", disc.label); + SEND_DISC(L"comment", disc.notes); + SEND_DISC_OR_TRACK(L"conductor", disc.conductor, track.conductor); + SEND_DISC_OR_TRACK(L"composer", disc.composer, track.composer); + + wchar_t disc_temp[64] = {0}; + if (disc.numdiscs) + StringCchPrintfW(disc_temp, 64, L"%d/%d", disc.discnum, disc.numdiscs); + else if (disc.discnum) + StringCchPrintfW(disc_temp, 64, L"%d", disc.discnum); + else + disc_temp[0]=0; + SEND_DISC(L"disc", disc_temp); + + SEND_TRACK(L"title", track.title); + SEND_TRACK(L"GracenoteFileID", track.tagID); + SEND_TRACK(L"GracenoteExtData", track.extData); +} + +static INT_PTR CALLBACK MusicID_Proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + LookupData *data = new LookupData(hwndDlg); + wchar_t *filename = (wchar_t *)lParam; + if (ParseName(AutoChar(filename), data->device, data->tracknum)) // TODO: remove AutoChar here, I'm just being lazy + { + MCIDEVICEID d = 0; + if (CDOpen(&d, data->device, L"MusicID_Dlg")) + { + GetDiscID(d, &data->info); + CDClose(&d); + + if (Cddb_CalculateTOC(&data->info, data->szTOC, sizeof(data->szTOC)/sizeof(wchar_t))) + { + ICddbCacheManager *pCache; + if (SUCCEEDED(Cddb_GetICacheManger((void**)&pCache))) + { + if (SUCCEEDED(pCache->FetchDiscByToc(data->szTOC, &data->disc))) + { + GetDiscInfo(data->disc, &data->info); + Fill(hwndDlg, &data->info); + } + pCache->Release(); + } + } + } + } + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)data); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data->use && data->disc) + { + StoreDisc(data->info.CDDBID, data->disc); + CddbCache_SetDisc(&data->info, S_OK); + } + } + break; + case IDC_LOOKUP: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data) + { + data->dlgItem = LOWORD(wParam); + HWND parent = GetParent(hwndDlg); + UINT flags = CDDB_NOCACHE | CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL; + HRESULT hr = Cddb_DoLookup(data->szTOC, parent, Cddb_LookupCallback, flags, (ULONG_PTR)data); + if (FAILED(hr)) Cddb_DisplayResultDlg(parent, hr, AUTOCLOSE_NEVER, flags); + } + } + break; + case IDC_USE: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + data->use=true; + NotifyParent_MusicID(GetParent(hwndDlg), data); + } + break; + case IDC_EDIT_GRACENOTE: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + data->dlgItem = LOWORD(wParam); + HWND parent = GetParent(hwndDlg); + UINT flags = CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL; + HRESULT hr = Cddb_DoLookup(data->szTOC, parent, Cddb_EditCallback, flags, (ULONG_PTR)data); + if (FAILED(hr)) Cddb_DisplayResultDlg(parent, hr, AUTOCLOSE_NEVER, flags); + } + break; + case IDC_SUBMIT: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data && data->disc) + SubmitEdit(data->disc); + } + break; + } + break; + case WM_DESTROY: + { + LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + delete data; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)0); + } + break; + } + return 0; +} +#endif + +struct CDTextData +{ +public: + CDTextData() + { + device=0; + tracknum=0; + use=false; + } + DINFO info; + wchar_t device; + int tracknum; + bool use; +}; + +static void Send_CDText(HWND hwndParent, const CDTextData *data) +{ + DINFO disc = data->info; + TRACKINFO dummy; + TRACKINFO &track = data->tracknum ? disc.tracks[data->tracknum-1] : dummy; + SEND_DISC(L"album", disc.title); + SEND_DISC(L"albumartist", disc.artist); + SEND_DISC_OR_TRACK(L"artist", disc.artist, track.artist); + SEND_DISC_OR_TRACK(L"composer", disc.composer, track.composer); + SEND_TRACK(L"title", track.title); + SEND_DISC_OR_TRACK(L"genre", disc.genre, track.genre); +} + +static void FillDialog_CDText(HWND hwndDlg, const DINFO &info) +{ + SET_IF(hwndDlg, IDC_ARTIST, info.artist); + SET_IF(hwndDlg, IDC_ALBUM, info.title); + SET_IF(hwndDlg, IDC_COMPOSER, info.composer); + + W_ListView listview(GetDlgItem(hwndDlg, IDC_TRACKS)); + + listview.Clear(); + + for (int i=0;i<info.ntracks;i++) + { + const TRACKINFO &track = info.tracks[i]; + wchar_t num[64] = {0}; + StringCchPrintfW(num, 64, L"%d", i+1); + int index = listview.AppendItem(num, 0); + if (track.artist) + listview.SetItemText(index, 1, track.artist); + if (track.title) + listview.SetItemText(index, 2, track.title); + if (track.genre) + listview.SetItemText(index, 3, track.genre); + if (track.composer) + listview.SetItemText(index, 4, track.composer); + } +} + +static INT_PTR CALLBACK CDText_Proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + W_ListView listview; + listview.setwnd(GetDlgItem(hwndDlg, IDC_TRACKS)); + + listview.AddCol(WASABI_API_LNGSTRINGW(IDS_TRACK), 50); + listview.AddCol(WASABI_API_LNGSTRINGW(IDS_ARTIST), 150); + listview.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), 150); + // TODO + listview.AddCol(L"Genre"/*WASABI_API_LNGSTRINGW(IDS_GENRE)*/, 150); + listview.AddCol(WASABI_API_LNGSTRINGW(IDS_COMPOSER), 150); + + CDTextData *data = new CDTextData; + wchar_t *filename = (wchar_t *)lParam; + if (ParseName(filename, data->device, data->tracknum)) + { + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)data); + } + else + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + + // this is slow if there's no CD Text + PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_LOOKUP, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, IDC_LOOKUP)); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data && data->use) + StoreCDText(data->info.CDDBID, data->device); + } + break; + case IDC_LOOKUP: + { + CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data && DoCDText(&data->info, data->device)) + { + FillDialog_CDText(hwndDlg, data->info); + } + } + break; + case IDC_USE: + { + CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (data) + { + data->use=true; + Send_CDText(GetParent(hwndDlg), data); + } + } + break; + } + break; + case WM_DESTROY: + { + CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + delete data; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)0); + } + break; + } + return 0; +} + +// 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. +extern "C" __declspec(dllexport) HWND winampAddUnifiedFileInfoPane(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen) +{ + if (!lstrcmpiW(PathFindExtensionW(filename), L".cda") && !_wcsnicmp(filename + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX + { + static wchar_t fakebuf[128]; + StringCchPrintf(fakebuf, 128, L"cda://%c,%d", filename[0], _wtoi(PathFindFileNameW(filename) + 5)); + filename = fakebuf; + } + + #ifndef IGNORE_API_GRACENOTE + switch (n) + { + case 0: // MusicID + StringCchCopyW(name, namelen, L"MusicID"); // benski> this is purposefully not translatable + return WASABI_API_CREATEDIALOGPARAMW(IDD_MUSICID,parent,MusicID_Proc,(LPARAM)_wcsdup(filename)); + case 1: // CD Text + WASABI_API_LNGSTRINGW_BUF(IDS_CDTEXT,name, namelen); + return WASABI_API_CREATEDIALOGPARAMW(IDD_CDTEXT,parent,CDText_Proc,(LPARAM)_wcsdup(filename)); + default: + return 0; + } + #else + switch (n) + { + case 0: // CD Text + { + //if (DoCDText(0, filename[6])) // this is slow if there's no CD Text + { + WASABI_API_LNGSTRINGW_BUF(IDS_CDTEXT,name, namelen); + return WASABI_API_CREATEDIALOGPARAMW(IDD_CDTEXT,parent,CDText_Proc,(LPARAM)_wcsdup(filename)); + } + return 0; + } + default: + return 0; + } + #endif +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/ExtendedRead.cpp b/Src/Plugins/Input/in_cdda/ExtendedRead.cpp new file mode 100644 index 00000000..007b6a65 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/ExtendedRead.cpp @@ -0,0 +1,145 @@ +#include "main.h" + +#include "CDPlay.h" +#include "DAEPlay.h" +#include "MCIPlay.h" +#include "WindacPlay.h" + +#include "api__in_cdda.h" +#include "workorder.h" +#include "CDDB.h" + +//returns handle!=0 if successful, 0 if error +//size will return the final nb of bytes written to the output, -1 if unknown +//TODO> add output format stuff (srate, nch, bps) +extern "C" __declspec(dllexport) intptr_t winampGetExtendedRead_openW(const wchar_t *fn, int *size, int *bps, int *nch, int *srate) +{ + s_last_error = NULL; + C_CDPlay *wp = NULL; + int ret = 1; + + wchar_t device = 0; + int track = -1; + if (!ParseName(fn, device, track)) + return 0; + + if (playStatus[device].IsRipping() || (g_cdplay && g_cdplay->IsPlaying(device))) + { + wchar_t title[32] = {0}; + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_CD_CURRENTLY_IN_USE), + WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_IN_USE,title,32), + MB_ICONWARNING | MB_OK); + return -1; + } + + // Get a ICddbDisc object for MusicID + #ifndef IGNORE_API_GRACENOTE + ICddbDiscPtr pDisc = NULL; + OpenMusicIDWorkOrder(); + if (workorder) + { + MCIDEVICEID submitDev = 0; + if (!CDOpen(&submitDev, device, L"MusicID")) submitDev = 0; + if (submitDev) + { + DINFO info; + ret = GetDiscID(submitDev, &info); + CDClose(&submitDev); + if (ret == 0) + { + wchar_t szTOC[2048] = {0}; + if (Cddb_CalculateTOC(&info, szTOC, sizeof(szTOC)/sizeof(wchar_t))) + Cddb_GetDiscFromCache(szTOC, &pDisc); + } + } + } + + if (config_rip_veritas) + { + VeritasPlay *vp = new VeritasPlay(true); + wp = vp; + ret = wp->open(device, track); + if (ret) + { + delete(wp); + wp = NULL; + } + else if (workorder && pDisc != 0) // see if MusicID is interested + { + void *handle = 0; + workorder->GetSigHandle(&handle, pDisc, track); + vp->submitHandle = handle; + } + } + #endif + + if (ret) + { + DAEPlay *dae = new DAEPlay; + if (dae) + { + wp = dae; + ret = wp->open(device, track); + if (ret) + { + delete(wp); + wp = NULL; + } + } + else + { + wp = NULL; + } + } + + if (ret) + { + wp = new WindacPlay; + if (wp->open(device, track)) + { + delete(wp); + return 0; + } + } + + if (size && wp) + { + double s = (double)wp->getlength() / 1000; + s *= (44100 * 4); + *size = (int)s; + } + if (srate) *srate = 44100; + if (nch) *nch = 2; + if (bps) *bps = 16; + playStatus[device].RippingStarted(); + return (intptr_t)wp; +} + +//returns nb of bytes read. -1 if read error (like CD ejected). if (ret<len), EOF is assumed +extern "C" __declspec(dllexport) int winampGetExtendedRead_getData(intptr_t handle, char *dest, int len, int *killswitch) +{ + s_last_error = NULL; + C_CDPlay *wp = (C_CDPlay*)handle; + return (wp ? wp->read(dest, len, killswitch) : -1); +} + +extern "C" __declspec(dllexport) void winampGetExtendedRead_close(intptr_t handle) +{ + s_last_error = NULL; + C_CDPlay *wp = (C_CDPlay*)handle; + if (wp) + { + playStatus[wp->g_drive].RippingStopped(); + delete wp; + wp = 0; + } +} + +// extended info writing (used by gen_ml to update the local CDDB database after a burn) + +extern "C" __declspec(dllexport) char * winampGetExtendedRead_lasterror() +{ + char * retval = s_last_error; + s_last_error = NULL; + return retval; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/FuncTypedefs.h b/Src/Plugins/Input/in_cdda/FuncTypedefs.h new file mode 100644 index 00000000..e465bc07 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/FuncTypedefs.h @@ -0,0 +1,94 @@ +#ifndef NULLSOFT_FUNCTYPEDEFSH +#define NULLSOFT_FUNCTYPEDEFSH + + +typedef unsigned char * PBYTE; +// typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT); + +// we Need all these as a minimum: +// 1 arg +// typedef DWORD (CALLBACK * LPFNDLLFUNC1)(DWORD); +typedef DWORD (CALLBACK * NoArgCallback)(); +// DWORD WINAPI PrimoSDK_End(VOID); + + +typedef DWORD (CALLBACK * OneArgCallback)(DWORD); +/* +DWORD PrimoSDK_Trace(DWORD dwTrace); +DWORD PrimoSDK_CloseImage(DWORD dwHandle); +DWORD PrimoSDK_ReleaseHandle(DWORD dwHandle); +*/ +// typedef DWORD (CALLBACK1a * )(PDWORD); +typedef DWORD (CALLBACK * OneArgCallback2)(PDWORD); +/* +DWORD PrimoSDK_Init(PDWORD pdwRelease); +DWORD PrimoSDK_GetHandle(PDWORD pdwHandle); +*/ +// 2 +typedef DWORD (CALLBACK * TwoArgCallback)(DWORD, PBYTE); +// DWORD PrimoSDK_AddFolder (DWORD dwHandle, PBYTE szFolder); +// typedef DWORD (CALLBACK2a)(DWORD, DWORD); +typedef DWORD (CALLBACK * TwoArgCallback2)(DWORD, DWORD); +// DWORD PrimoSDK_VerifyImage(DWORD dwHandle, DWORD dwSpeed); +typedef DWORD (CALLBACK * TwoArgCallback3)(DWORD, PDWORD); +// 3 +// typedef DWORD (CALLBACK3 ) +typedef DWORD (CALLBACK * ThreeArgCallback)(DWORD, PDWORD, DWORD); + +// DWORD WINAPI PrimoSDK_UnitLock(DWORD dwHandle, PDWORD pdwUnit, DWORD dwFlags); +/* +DWORD PrimoSDK_EraseMedium(DWORD dwHandle, PDWORD pdwUnit, DWORD dwFlags); +DWORD PrimoSDK_UnitAIN(DWORD dwHandle, PDWORD pdwUnit, DWORD dwFlags); +DWORD PrimoSDK_MoveMedium(DWORD dwHandle, PDWORD pdwUnit, DWORD dwFlags); +*/ +// typedef DWORD (CALLBACK3b )(DWORD, PBYTE, PBYTE); +typedef DWORD (CALLBACK * ThreeArgCallback2 )(DWORD, PBYTE, PBYTE); +// DWORD PrimoSDK_AddFile(DWORD dwHandle, PBYTE szFileOnCD, PBYTE szSourceFile); + +typedef DWORD (CALLBACK * ThreeArgCallback3 )(DWORD, DWORD, DWORD); + +// 4 +typedef DWORD (CALLBACK * FourArgCallback)(DWORD, PDWORD, DWORD, PBYTE); +// DWORD PrimoSDK_UnitVxBlock(DWORD dwHandle, PDWORD pdwUnit, DWORD dwFlags, PBYTE szAppName); +typedef DWORD (CALLBACK * FourArgCallback2 )( DWORD, DWORD, DWORD, PDWORD); +// DWORD PrimoSDK_WriteImage(DWORD dwHandle, DWORD dwFlags, DWORD dwSpeed, PDWORD pdwSize); +// 5 +typedef DWORD (CALLBACK * FourArgCallback3 )( DWORD, DWORD, PDWORD, PDWORD); +// DWORD WINAPI PrimoSDK_RunningStatus(DWORD dwHandle, DWORD dwFlags,PDWORD pdwCurSector, PDWORD pdwTotSector); + +typedef DWORD (CALLBACK *FourArgCallback4)( DWORD, PBYTE, DWORD, PDWORD); + +// typedef DWORD (CALLBACK5 )( DWORD, PDWORD, PDWORD, PBYTE, PDWORD); +typedef DWORD (CALLBACK * FiveArgCallback)( DWORD, PDWORD, PDWORD, PBYTE, PDWORD); +// DWORD PrimoSDK_UnitInfo(DWORD dwHandle, PDWORD pdwUnit, PDWORD pdwType, PBYTE szDescr, PDWORD pdwReady); + +//typedef DWORD (CALLBACK5b )( DWORD, PDWORD, PDWORD, PDWORD, PDWORD); +typedef DWORD (CALLBACK * FiveArgCallback2)( DWORD, PDWORD, PDWORD, PDWORD, PDWORD); +// DWORD PrimoSDK_UnitSpeeds(DWORD dwHandle, PDWORD pdwUnit, PDWORD pdwCDSpeeds, PDWORD pdwDVDSpeeds, PDWORD pdwCapabilities); +typedef DWORD (CALLBACK * FiveArgCallback3 )( DWORD, PBYTE, DWORD, PDWORD, PDWORD); +// DWORD WINAPI PrimoSDK_NextExtractAudioBuffer(DWORD, PBYTE, DWORD, PDWORD, PDWORD); +// 6 +//typedef DWORD (CALLBACK6 ) (DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +typedef DWORD (CALLBACK * SixArgCallback) (DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +// DWORD PrimoSDK_UnitInfo2(DWORD dwHandle, PDWORD pdwUnit, PDWORD pdwTypes, PDWORD pdwClass, PDWORD pdwBusType, PDWORD pdwRFU); +// 7 +// typedef DWORD (CALLBACK7 )( DWORD, PDWORD, PBYTE, DWORD, DWORD, DWORD, PBYTE); +typedef DWORD (CALLBACK * SevenArgCallback)( DWORD, PDWORD, PBYTE, DWORD, DWORD, DWORD, PBYTE); +// DWORD PrimoSDK_NewImage(DWORD dwHandle, PDWORD pdwUnits, PBYTE szVolumeName, DWORD dwTrackToLoad, DWORD dwFlags, DWORD dwSwapThreshold, PBYTE szTemp); +typedef DWORD (CALLBACK * SevenArgCallback2)( DWORD, DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +// DWORD WINAPI PrimoSDK_TrackInfo(DWORD, DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +typedef DWORD (CALLBACK * SevenArgCallback3)( DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +// DWORD WINAPI PrimoSDK_DiscInfo2(DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); + +// 8 +//typedef DWORD (CALLBACK8 )( DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +typedef DWORD (CALLBACK * EightArgCallback )( DWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD); +// DWORD PrimoSDK_DiscInfo(DWORD dwHandle, PDWORD pdwUnit, PDWORD pdwMediumType, PDWORD pdwMediumFormat, PDWORD pdwErasable, PDWORD pdwTracks, PDWORD pdwUsed, PDWORD pdwFree); + +typedef DWORD (CALLBACK * EightArgCallback2 )(DWORD, PDWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); +// DWORD WINAPI PrimoSDK_ExtractAudioToBuffer(DWORD, PDWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); + +typedef DWORD (CALLBACK * EightArgCallback3)(DWORD, PDWORD, PBYTE, PBYTE, PBYTE, PBYTE, PBYTE, PBYTE); + +typedef DWORD (CALLBACK * NineArgCallback)(DWORD,PDWORD,DWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD); +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/MAIN.H b/Src/Plugins/Input/in_cdda/MAIN.H new file mode 100644 index 00000000..0d5dd767 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/MAIN.H @@ -0,0 +1,81 @@ +#ifndef NULLSOFT_MAINH +#define NULLSOFT_MAINH +#include <windows.h> +#include <stdio.h> +#include "../Winamp/in2.h" +#include "audio.h" +#include "resource.h" +#include "PlayStatus.h" +#include "../nu/AutoLock.h" +#include <mmsystem.h> + +#define WM_WA_MPEG_EOF WM_USER+2 + +extern In_Module line; + +extern volatile int done; +extern int paused; +extern int g_lastpos; +extern int m_nblock; + +extern DWORD MainThreadId; + +void config(HWND hwndParent); +void config_read(); +//extern int config_sample; + +//extern int config_rip_buffersize; // number of sectors to read at once when ripping +//extern int config_rip_buffers; // number of buffers to use when ripping +//extern int config_play_buffersize; // number of sectors to read at once when playing +//extern int config_play_buffers; // number of buffers to use when playing + +//extern int config_maxextractspeed; + +// TODO review this for the DAE mode... +//extern int config_offset; // number of samples of offset when ripping (like EAC) +//extern int config_read_leadin; + +extern int g_playlength; +extern int g_playtrack; + +void WaitForEvent(HANDLE hEvent, DWORD msMaxWaitTime); +MCIERROR MCISendCommand(MCIDEVICEID IDDevice, UINT uMsg, DWORD fdwCommand, DWORD_PTR dwParam); +int isMediaPresent(MCIDEVICEID wDeviceID); +void CDClose(MCIDEVICEID* lpDeviceID); +BOOL CDOpen(MCIDEVICEID* lpDeviceID, int device, const wchar_t *alias = 0); +BOOL CDID(MCIDEVICEID wDeviceID, wchar_t *id, size_t len); +void CDClose(MCIDEVICEID* lpDeviceID); +unsigned int CDGetTracks(MCIDEVICEID wDeviceID); +unsigned int CDGetCurrTrack(MCIDEVICEID wDeviceID); +int CDPlay(MCIDEVICEID wDeviceID, unsigned int nTrack, BOOL bResume, unsigned int nMin, unsigned int nSec, unsigned int endms); +void CDStop(MCIDEVICEID wDeviceID); +void CDEject(MCIDEVICEID wDeviceID); +void CDPause(MCIDEVICEID wDeviceID); +unsigned int CDGetTrackLength(MCIDEVICEID wDeviceID, + unsigned int nTrack); + +int getSCSIIDFromDrive(char driveletter, int *host, int *id, int *lun); +extern char * s_last_error; +void CloseTables(); + +const char *ReadLine(const char *input, char *output, size_t size, int codepage); + +bool ParseName(const wchar_t *fn, wchar_t &device, int &trackNum); + +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = + { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } }; + +class C_CDPlay; +class WindacPlay; +class DAEPlay; +class MciPlay; + +extern C_CDPlay *g_cdplay; +extern WindacPlay *windacPlayer; +extern DAEPlay *daePlayer; +extern MciPlay *mciPlayer; + +extern int a_v, a_p; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/MCI.Cpp b/Src/Plugins/Input/in_cdda/MCI.Cpp new file mode 100644 index 00000000..26132b12 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/MCI.Cpp @@ -0,0 +1,152 @@ +#include "main.h" + +MCIERROR MCISendCommand(MCIDEVICEID IDDevice, UINT uMsg, DWORD fdwCommand, DWORD_PTR dwParam) +{ + MCIERROR nErr = mciSendCommand(IDDevice, uMsg, fdwCommand, dwParam); +#if 0 + if (nErr) + { + wchar_t szError[256] = {0}; + mciGetErrorString(nErr, szError, 256); + MessageBox(NULL,szError,L"MCI CD Error",MB_OK); + } +#endif + return nErr; +} + +int isMediaPresent(MCIDEVICEID wDeviceID) +{ + MCI_STATUS_PARMS p; + p.dwItem=MCI_STATUS_MEDIA_PRESENT; + if (MCISendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD_PTR)&p)) return 1; + return p.dwReturn?1:0; +} + +BOOL CDOpen(MCIDEVICEID* lpDeviceID, int device, const wchar_t *alias) +{ + //OutputDebugString("Calling cdopen()\n"); + MCI_OPEN_PARMS sMCIOpen; + MCI_SET_PARMS sMCISet; + wchar_t zDevice[3]={(wchar_t)device,':',0}; + DWORD nErr; + + sMCIOpen.dwCallback = 0; + sMCIOpen.wDeviceID = 0; + sMCIOpen.lpstrAlias = alias; + sMCIOpen.lpstrDeviceType = (LPCTSTR) MCI_DEVTYPE_CD_AUDIO; + sMCIOpen.lpstrElementName = zDevice; + nErr = MCISendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | + MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT | + (alias ? MCI_OPEN_ALIAS : 0), (DWORD_PTR) &sMCIOpen); + if (nErr) + { + nErr = MCISendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | + MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT | + (alias ? MCI_OPEN_ALIAS : 0), (DWORD_PTR) &sMCIOpen); + if (nErr) + { + return FALSE; + } + } + + sMCISet.dwTimeFormat = MCI_FORMAT_TMSF; + MCISendCommand (sMCIOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR) &sMCISet); + + *lpDeviceID = sMCIOpen.wDeviceID; + + return TRUE; +} + +void CDClose(MCIDEVICEID* lpDeviceID) +{ + MCI_GENERIC_PARMS sMCIGeneric; + + sMCIGeneric.dwCallback = (DWORD_PTR) line.hMainWindow; + MCISendCommand(*lpDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR) &sMCIGeneric); + + *lpDeviceID = 0; +} + +void CDEject(MCIDEVICEID wDeviceID) +{ + MCI_SET_PARMS mciset; + MCISendCommand (wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN,(DWORD_PTR) &mciset); +} + +unsigned int CDGetTracks(MCIDEVICEID wDeviceID) +{ + MCI_STATUS_PARMS sMCIStatus; + sMCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + if (MCISendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT,(DWORD_PTR) &sMCIStatus)) return -1; + return sMCIStatus.dwReturn; +} + +unsigned int CDGetCurrTrack(MCIDEVICEID wDeviceID) +{ + MCI_STATUS_PARMS sMCIStatus; + + sMCIStatus.dwItem = MCI_STATUS_POSITION; + MCISendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT,(DWORD_PTR) &sMCIStatus); + + return ((int) MCI_TMSF_TRACK (sMCIStatus.dwReturn)); +} + +int CDPlay(MCIDEVICEID wDeviceID, unsigned int nTrack, BOOL bResume, unsigned int nMin, unsigned int nSec, unsigned int endms) +{ + MCI_PLAY_PARMS sMCIPlay; + unsigned int nActualTrack = nTrack; + + sMCIPlay.dwFrom = MCI_MAKE_TMSF (nActualTrack, nMin, nSec, 0); + sMCIPlay.dwTo = MCI_MAKE_TMSF (nActualTrack, endms/60000, (endms/1000)%60,0); + if (!bResume) + { + return MCISendCommand (wDeviceID, MCI_PLAY, MCI_FROM | MCI_TO ,(DWORD_PTR) &sMCIPlay); + } + else + { + return MCISendCommand (wDeviceID, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD_PTR) (LPVOID) &sMCIPlay); + } +} + +void CDStop(MCIDEVICEID wDeviceID) +{ + MCISendCommand(wDeviceID, MCI_STOP, 0, 0); +} + +void CDPause(MCIDEVICEID wDeviceID) +{ + MCISendCommand(wDeviceID, MCI_PAUSE, 0,0); +} + +unsigned int CDGetTrackLength(MCIDEVICEID wDeviceID, unsigned int nTrack) +{ + MCI_STATUS_PARMS sMCIStatus; + int r; + + sMCIStatus.dwItem = MCI_STATUS_POSITION ; + sMCIStatus.dwTrack = nTrack+1; + if (MCISendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT,(DWORD_PTR) &sMCIStatus)) // if error than last track + { + sMCIStatus.dwItem = MCI_STATUS_LENGTH; + sMCIStatus.dwTrack = nTrack; + if (MCISendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT,(DWORD_PTR) &sMCIStatus)) return -1000; + return sMCIStatus.dwReturn; + } + + r=sMCIStatus.dwReturn; + sMCIStatus.dwItem = MCI_STATUS_POSITION ; + sMCIStatus.dwTrack = nTrack; + if (MCISendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT,(DWORD_PTR) &sMCIStatus)) return -1000; + return r-sMCIStatus.dwReturn; +} + +BOOL CDID(MCIDEVICEID wDeviceID, wchar_t *id, size_t len) +{ + MCI_INFO_PARMS sMCIInfo; + sMCIInfo.dwCallback=0; + sMCIInfo.dwRetSize=len; + sMCIInfo.lpstrReturn=id; + DWORD nErr= MCISendCommand(wDeviceID, MCI_INFO, MCI_INFO_MEDIA_IDENTITY, (DWORD_PTR)&sMCIInfo); + + return !nErr; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/MCIPlay.h b/Src/Plugins/Input/in_cdda/MCIPlay.h new file mode 100644 index 00000000..fe8e43ad --- /dev/null +++ b/Src/Plugins/Input/in_cdda/MCIPlay.h @@ -0,0 +1,182 @@ +#ifndef NULLSOFT_MCIPLAYH +#define NULLSOFT_MCIPLAYH + +#include "CDPlay.h" +#include "main.h" + +class MciPlay : public C_CDPlay { +public: + MciPlay() + { + posinms=0; + } + + int play(wchar_t drive, int track) + { + g_drive = drive; + + { + MCI_SET_PARMS sMCISet; + g_playtrack = track; + + if (!CDOpen(&playdev, drive, L"mci")) + { + playdev=0; + g_drive = 0; + return 1; + } + sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS; + MCISendCommand (playdev, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR) (LPVOID) &sMCISet); + g_playlength=CDGetTrackLength(playdev,g_playtrack); + sMCISet.dwTimeFormat = MCI_FORMAT_TMSF; + MCISendCommand (playdev, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR) (LPVOID) &sMCISet); + if (CDPlay(playdev,g_playtrack,FALSE,0,0,g_playlength)) + { + CDClose(&playdev); + playdev=0; + g_drive = 0; + return 1; + } + line.is_seekable=1; + } + line.SetInfo(1411,44,2,1); + line.SAVSAInit(0,44100); + line.VSASetInfo(2,44100); + setvolume(a_v, a_p); + { + short dta[576*2] = {0}; + line.VSAAddPCMData(dta,2,16,0); + line.SAAddPCMData(dta,2,16,0); + } + if (audioInit(/*config_sample*/)) + { + } + return 0; + } + + void stop() + { + //CDStop(playdev); + if (!done) CDPause(playdev); + CDClose(&playdev); + audioQuit(); + } + + void pause() + { + posinms=audioGetPos(); + CDPause(playdev); + audioPause(1); + } + + void unpause() + { + int pos=audioGetPos(); + CDPlay(playdev, g_playtrack, TRUE,pos/60000,(pos/1000)%60,g_playlength); + audioPause(0); + } + + int getlength() + { + return g_playlength; + } + + int getoutputtime() + { + int p; + if (paused) + { + return posinms; + } + p=audioGetPos(); + if (GetCurrentThreadId()==MainThreadId) + { + if ((p > g_playlength || (p-g_lastpos > 2000 && !isMediaPresent(playdev))) && !done) + { + done=1; + PostMessage(line.hMainWindow,WM_WA_MPEG_EOF,0,0); + } + if (g_lastpos > p+2000) + g_lastpos=p; + } + return p; + } + + void setoutputtime(int time_in_ms) + { + CDPlay(playdev,g_playtrack,FALSE,time_in_ms/60000,(time_in_ms/1000)%60,g_playlength); + if (paused) + { + audioPause(0); + } + audioSetPos(time_in_ms); + g_lastpos=time_in_ms; + if (paused) + { + audioPause(1); + CDPause(playdev); + } + done=0; + } + + void setvolume(int _a_v, int _a_p) { + HMIXER hmix; + int vol1, vol2; + if (_a_v < 0) _a_v = 0; + if (_a_v > 255) _a_v = 255; + if (_a_p < -127) _a_p = -127; + if (_a_p > 127) _a_p = 127; + vol1 = vol2 = (_a_v*2048) / 255; + if (_a_p > 0) + { + vol1 *= (127-_a_p); + vol1 /= 127; + } + else if (_a_p < 0) + { + vol2 *= (_a_p+127); + vol2 /= 127; + } + + if (mixerOpen(&hmix,0,0,0,0) == MMSYSERR_NOERROR) + { + MIXERLINE ml={sizeof(ml),0}; + ml.dwComponentType=MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC; + if (mixerGetLineInfo((HMIXEROBJ)hmix,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR) + { + MIXERLINECONTROLS mlc = {sizeof(mlc),ml.dwLineID,}; + MIXERCONTROL mc={sizeof(mc),}; + mlc.cControls=1; + mlc.cbmxctrl=sizeof(mc); + mlc.pamxctrl=&mc; + mlc.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME; + if (mixerGetLineControls((HMIXEROBJ)hmix,&mlc,MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR) + { + MIXERCONTROLDETAILS mcd = {sizeof(mcd),mc.dwControlID,ml.cChannels,}; + MIXERCONTROLDETAILS_UNSIGNED v[2]; + mcd.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mcd.paDetails=v; + + v[0].dwValue=mc.Bounds.dwMinimum + (vol1*(mc.Bounds.dwMaximum-mc.Bounds.dwMinimum))/2048; + v[1].dwValue=mc.Bounds.dwMinimum + (vol2*(mc.Bounds.dwMaximum-mc.Bounds.dwMinimum))/2048; + + if (mixerSetControlDetails((HMIXEROBJ)hmix,&mcd,0) == MMSYSERR_NOERROR) + { + // yay we're done! + } + // else MessageBox(NULL,"mixerSetLineControlDetails()","Error",MB_OK); + } + //else MessageBox(NULL,"mixerGetLineControls()","Error",MB_OK); + } +// else MessageBox(NULL,"mixerGetLineInfo()","Error",MB_OK); + mixerClose(hmix); + } + //else MessageBox(NULL,"MixerOpen()","Error",MB_OK); + } + +private: + int posinms; + MCIDEVICEID playdev; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/Main.cpp b/Src/Plugins/Input/in_cdda/Main.cpp new file mode 100644 index 00000000..c867a660 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/Main.cpp @@ -0,0 +1,598 @@ +//#define PLUGIN_NAME "Nullsoft CD Plug-in" +#define PLUGIN_VERSION L"4.7" + +#include "main.h" +#include "cddb.h" + +#include "CDPlay.h" +#include "DAEPlay.h" +#include "MCIPlay.h" +#include "WindacPlay.h" + +#include "PlayStatus.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoChar.h" +#include "../Winamp/strutil.h" +#include "../winamp/wa_ipc.h" +#include <shlwapi.h> +#include "api__in_cdda.h" +#include "workorder.h" +#include <strsafe.h> +using namespace Nullsoft::Utility; +Nullsoft::Utility::LockGuard *playDeviceGuard = 0; +char * s_last_error = NULL; + +static wchar_t playDriveLetter; +//extern int config_maxextractspeed; +api_config *AGAVE_API_CONFIG=0; + +#ifndef _DEBUG +BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + DisableThreadLibraryCalls(hInst); + return TRUE; +} +#endif + +#ifdef IGNORE_API_GRACENOTE +static DINFO g_ps; +#endif +int g_ps_inuse = 0; +int g_playtrack, g_playlength; +wchar_t lastfn[1024] = {0}; +int paused; +void _setvolume(); +DWORD MainThreadId; + +extern char INI_FILE[]; +extern char app_name[]; + +int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message) +{ + MSGBOXPARAMS msgbx = {sizeof(MSGBOXPARAMS),0}; + msgbx.lpszText = message; + msgbx.lpszCaption = title; + msgbx.lpszIcon = MAKEINTRESOURCE(102); + msgbx.hInstance = GetModuleHandle(0); + msgbx.dwStyle = MB_USERICON; + msgbx.hwndOwner = parent; + return MessageBoxIndirect(&msgbx); +} + +void about(HWND hwndParent) +{ + wchar_t message[1024] = {0}, text[1024] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_CD_PLUGIN_OLD,text,1024); + StringCchPrintf(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT), + line.description, TEXT(__DATE__)); + DoAboutMessageBox(hwndParent,text,message); +} + +void quit(); +int init(); + +int isourfile(const in_char *fn) +{ + if (!_wcsnicmp(fn, L"cda://", 6)) return 1; + return 0; +} + +volatile int done = 0; + +int g_lastpos = 0; +C_CDPlay *g_cdplay = 0; + +const wchar_t *filename(const wchar_t *fn) +{ + const wchar_t *s = scanstr_backcW(fn, L"\\/", 0); + if (!s) return fn; + return (s + 1); +} + +bool ParseName(const wchar_t *fn, wchar_t &device, int &trackNum) +{ + wchar_t track[16] = L"1"; + if (!_wcsnicmp(fn, L"cda://", 6)) + { + fn += 6; + wchar_t d[16] = {0}; + wchar_t *p = d; + while (fn && *fn && *fn != L',' && (p - d < 15)) *p++ = *fn++; + if (p) *p = 0; + device = toupper(d[0]); + if (*fn == L',') fn++; + lstrcpyn(track, fn, ARRAYSIZE(track)); + trackNum = _wtoi(track); + return true; + } + else if (!_wcsicmp(extensionW(fn), L"cda")) + { + const wchar_t *f = filename(fn); + if (!_wcsnicmp(f, L"track", 5)) f += 5; + wchar_t t[16] = {0}; + wchar_t *p = t; + while (f && *f && *f != L'.' && (p - t < 15)) *p++ = *f++; + lstrcpyn(track, t, ARRAYSIZE(track)); + device = toupper(fn[0]); + trackNum = _wtoi(track); + return true; + } + return false; +} + +WindacPlay *windacPlayer = 0; +DAEPlay *daePlayer = 0; +MciPlay *mciPlayer = 0; + +int play(const in_char *fn) +{ + done = 0; + lstrcpyn(lastfn, fn, 1024); + line.is_seekable = 0; + g_lastpos = 0; + + int track = -1; + if (!ParseName(fn, playDriveLetter, track)) + return 1; + + if (playStatus[playDriveLetter].IsRipping() || (g_cdplay && g_cdplay->IsPlaying(playDriveLetter))) + { + wchar_t title[32] = {0}; + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_CD_CURRENTLY_IN_USE), + WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_IN_USE,title,32), MB_OK); + return 1; + } + + if (g_cdplay) delete g_cdplay; g_cdplay = NULL; + + //first, try DAE + if (!daePlayer) daePlayer = new DAEPlay; + g_cdplay = daePlayer; + + int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0); + if (ret != 0) + { + if (g_cdplay) delete g_cdplay; g_cdplay = daePlayer = NULL; + + //second, try Windac + if (!windacPlayer) windacPlayer = new WindacPlay; + g_cdplay = windacPlayer; + ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0); + if (ret != 0) + { + if (g_cdplay) delete g_cdplay; g_cdplay = windacPlayer = NULL; + + //try MCI + if (!mciPlayer) mciPlayer = new MciPlay; + g_cdplay = mciPlayer; + int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 1); + if (ret != 0) + { + //no luck + if (g_cdplay) delete g_cdplay; g_cdplay = mciPlayer = NULL; + return ret; + } + } + } + paused = 0; + return 0; +} + + +void pause() +{ + if (g_cdplay) g_cdplay->pause(); + paused = 1; +} +void unpause() +{ + if (g_cdplay) g_cdplay->unpause(); + paused = 0; +} +int ispaused() +{ + return paused; +} + +void stop() +{ + if (g_cdplay) + { + g_cdplay->stop(); + g_cdplay = NULL; + } + + done = 0; + line.SAVSADeInit(); +} + +int getlength() +{ + if (g_cdplay) return g_cdplay->getlength(); + return -1000; +} + +int getoutputtime() +{ + if (g_cdplay) return g_cdplay->getoutputtime(); + return 0; + //return audioGetPos(); +} +void setoutputtime(int time_in_ms) +{ + if (g_cdplay) g_cdplay->setoutputtime(time_in_ms); +} + +void setvolume(int volume) +{ + if (volume != -666) + { + a_v = volume; + } + if (g_cdplay) g_cdplay->setvolume(a_v, a_p); +} + +void setpan(int pan) +{ + a_p = pan; + if (g_cdplay) g_cdplay->setvolume(a_v, a_p); +} + +int infoDlg(const in_char *fn, HWND hwnd) +{ + return 0; +#if 0 // switched to unified file info dialog in 5.53 + if (!_stricmp(extension(fn), "cda") || !_strnicmp(fn, "cda://", 6)) + { + if (!g_ps_inuse) + { + char device; + int res=1; + MCIDEVICEID d = 0; + g_ps_inuse = 1; + device = fn[_strnicmp(fn, "cda://", 6) ? 0 : 6]; + if (device >= 'a' && device <= 'z') device += 'A' -'a'; + + CDOpen(&d, device, L"infoDlg"); + memset(&g_ps, 0, sizeof(g_ps)); + res = GetDiscID(d, &g_ps); + CDClose(&d); + if (!res) + res = GetCDDBInfo(&g_ps, device); + + //if (!res) DBEdit(&g_ps, hwnd, 0, device); + //if (!res) + { + if (CDEdit(device, &g_ps, hwnd)) + { + g_ps_inuse = 0; + return INFOBOX_EDITED; + } + } + g_ps_inuse = 0; + } + } + return INFOBOX_UNCHANGED; +#endif +} + + +void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms) +{ +#if 0 + int track; + char device; + MCIDEVICEID dev2 = 0; + if (length_in_ms) *length_in_ms = -1000; + + if (!filename || !*filename) // currently playing + { + if (!_stricmp(extension(lastfn), "cda") || !_strnicmp(lastfn, "cda://", 6)) + { + #ifdef IGNORE_API_GRACENOTE + if (title) + { + lstrcpynA(title, "CD Track", GETFILEINFO_TITLE_LENGTH); + if (!g_ps_inuse) + { + g_ps_inuse = 1; + memset(&g_ps, 0, sizeof(g_ps)); + + if (CDOpen(&dev2, playDriveLetter, L"getfileinfo")) + { + wchar_t wtitle[256] = {0}; + int ret = GetDiscID(dev2, &g_ps); + CDClose(&dev2); + if (!ret && GetCDDBInfo(&g_ps, 0)) // TODO: get device letter + PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247/*IPC_REFRESHPLCACHE*/); + if (wtitle[0]) + lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH); + + } + g_ps_inuse = 0; + } + } + if (length_in_ms) *length_in_ms = g_playlength; + #endif + } + + return ; + } + + if (title) + { + const char *p = filename + strlen(filename); + while (p >= filename && *p != '\\') p--; + lstrcpynA(title, ++p, GETFILEINFO_TITLE_LENGTH); + } + track = 0; + + if (!_strnicmp(filename, "cda://", 6)) // determine length of cd track via MCI + { + track = atoi(filename + 8); + device = filename[6]; + if (device >= 'a' && device <= 'z') device += 'A' -'a'; + + if (length_in_ms) + { + if (CDOpen(&dev2, device, L"getfileinfo")) + { + MCI_SET_PARMS sMCISet; + sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS; + MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + *length_in_ms = CDGetTrackLength(dev2, track); + sMCISet.dwTimeFormat = MCI_FORMAT_TMSF; + MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + } + } + } + else // determine from RIFF structure of .CDA + { + HMMIO hmmio; + hmmio = mmioOpenA((char *)filename, NULL, MMIO_READ | MMIO_ALLOCBUF); + device = filename[0]; + if (device >= 'a' && device <= 'z') device += 'A' -'a'; + if (hmmio) + { + MMCKINFO mmckinfoParent; // parent chunk information + mmckinfoParent.fccType = mmioFOURCC('C', 'D', 'D', 'A'); + if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF) == MMSYSERR_NOERROR) + { + MMCKINFO mmckinfoSubchunk; // subchunk information structure + mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' '); + if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) == MMSYSERR_NOERROR) + { + char *format; + DWORD dwFmtSize; // size of "FMT" chunk + dwFmtSize = mmckinfoSubchunk.cksize; + format = (char *) GlobalAlloc(GPTR, dwFmtSize); + if (mmioRead(hmmio, (HPSTR) format, dwFmtSize) == (int)dwFmtSize) + { + mmioAscend(hmmio, &mmckinfoSubchunk, 0); + track = *((short int *)format + 1); + if (length_in_ms) + { + int length = *((int *)format + 3); + int l = length % 75; + length /= 75; + length *= 1000; + length += (l * 1000) / 75; + *length_in_ms = length; + } + } + GlobalFree(format); + } + } + mmioClose(hmmio, 0); + } + } + + #ifdef IGNORE_API_GRACENOTE + if (title && track) + { + if (0 && !g_ps_inuse) + { + g_ps_inuse = 1; + memset(&g_ps, 0, sizeof(g_ps)); + if (!dev2) + { + CDOpen(&dev2, device, L"getfileinfo"); + } + if (dev2) + { + StringCchPrintfA(title, GETFILEINFO_TITLE_LENGTH, "CD Track %d", track); + wchar_t wtitle[256] = L""; + int ret = GetDiscID(dev2, &g_ps); + CDClose(&dev2); + dev2=0; + if (!ret && GetCDDBInfo(&g_ps, device)) + PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247 /*IPC_REFRESHPLCACHE*/); + if (wtitle[0]) + lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH); + } + g_ps_inuse = 0; + } + } + #endif + if (dev2) CDClose(&dev2); +#endif +} + +void eq_set(int on, char data[10], int preamp) +{} + +In_Module line = +{ + IN_VER_RET, + "nullsoft(in_cdda.dll)", + 0, // hMainWindow + 0, // hDllInstance + 0, + 0, // is_seekable + 1, // uses output plugins + about,//config, + about, + init, + quit, + getfileinfo, + infoDlg, + isourfile, + play, + pause, + unpause, + ispaused, + stop, + getlength, + getoutputtime, + setoutputtime, + setvolume, + setpan, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, // dsp shit + eq_set, + NULL, // setinfo + NULL // out_mod +}; + +int m_nblock = 0; + +extern "C" +{ + __declspec(dllexport) In_Module * winampGetInModule2() + { + s_last_error = NULL; + return &line; + } + + + + +#if 0 // TODO? + + __declspec(dllexport) int winampWriteExtendedFileInfo() + { + s_last_error = NULL; + // write it out + if (m_eiw_lastdrive) + { + AddToDatabase(&setInfo); + m_eiw_lastdrive = 0; + return 1; + } + return 0; + } +#endif +}; + +// wasabi based services for localisation support +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; +#ifndef IGNORE_API_GRACENOTE +api_gracenote *AGAVE_API_GRACENOTE = 0; +#endif +api_application *WASABI_API_APP = 0; + +void SetFileExtensions(void) +{ + static char fileExtensionsString[1200] = {0}; // "CDA\0CDDA Audio Tracks (*.CDA)\0" + char* end = 0; + StringCchCopyExA(fileExtensionsString, 1200, "CDA", &end, 0, 0); + StringCchCopyExA(end+1, 1200, WASABI_API_LNGSTRING(IDS_CDDA_AUDIO_TRACKS), 0, 0, 0); + line.FileExtensions = fileExtensionsString; +} + +int init() +{ + if (!IsWindow(line.hMainWindow)) + return IN_INIT_FAILURE; + + //CoInitialize(0); + + #ifndef IGNORE_API_GRACENOTE + Cddb_Initialize(); + InitializeCddbCache(); + #endif + + // loader so that we can get the localisation service api for use + waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface()); + + sf = line.service->service_getServiceByGuid(AgaveConfigGUID); + if (sf) AGAVE_API_CONFIG = reinterpret_cast<api_config*>(sf->getInterface()); + + #ifndef IGNORE_API_GRACENOTE + sf = line.service->service_getServiceByGuid(gracenoteApiGUID); + if (sf) AGAVE_API_GRACENOTE = reinterpret_cast<api_gracenote*>(sf->getInterface()); + #endif + + sf = line.service->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(line.hDllInstance,InCDDALangGUID); + + static wchar_t szDescription[256]; + StringCchPrintfW(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_CD_PLUGIN),PLUGIN_VERSION); + line.description = (char*)szDescription; + + SetFileExtensions(); + + playDeviceGuard = new Nullsoft::Utility::LockGuard; + playStatusGuard = new Nullsoft::Utility::LockGuard; + + MainThreadId = GetCurrentThreadId(); + config_read(); + return IN_INIT_SUCCESS; +} + +void quit() +{ + #ifndef IGNORE_API_GRACENOTE + ShutdownMusicIDWorkOrder(); + #endif + + if (playStatusGuard) + { + delete playStatusGuard; + playStatusGuard = 0; + } + + if (windacPlayer) + { + delete windacPlayer; + windacPlayer = NULL; + } + + if (daePlayer) + { + delete daePlayer; + daePlayer = NULL; + } + + if (mciPlayer) + { + delete mciPlayer; + mciPlayer = NULL; + } + + #ifndef IGNORE_API_GRACENOTE + ShutDownCDDB(); + #endif + + waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID); + if (sf) sf->releaseInterface(WASABI_API_LNG); + + sf = line.service->service_getServiceByGuid(AgaveConfigGUID); + if (sf) sf->releaseInterface(AGAVE_API_CONFIG); + + #ifndef IGNORE_API_GRACENOTE + sf = line.service->service_getServiceByGuid(gracenoteApiGUID); + if (sf) sf->releaseInterface(AGAVE_API_GRACENOTE); + + Cddb_Uninitialize(); + UninitializeCddbCache(); + #endif + + CloseTables(); + //CoUninitialize(); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/PlayStatus.cpp b/Src/Plugins/Input/in_cdda/PlayStatus.cpp new file mode 100644 index 00000000..533292f4 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/PlayStatus.cpp @@ -0,0 +1,23 @@ +#include "PlayStatus.h" + +//std::map<char, DriveStatus> playStatus; +PlayStatus playStatus; +Nullsoft::Utility::LockGuard *playStatusGuard = 0; + +DriveStatus::DriveStatus() : ripping(false) +{} + +void DriveStatus::RippingStarted() +{ + ripping = true; +} + +void DriveStatus::RippingStopped() +{ + ripping = false; +} + +bool DriveStatus::IsRipping() const +{ + return ripping; +} diff --git a/Src/Plugins/Input/in_cdda/PlayStatus.h b/Src/Plugins/Input/in_cdda/PlayStatus.h new file mode 100644 index 00000000..9e6ed1de --- /dev/null +++ b/Src/Plugins/Input/in_cdda/PlayStatus.h @@ -0,0 +1,28 @@ +#ifndef NULLSOFT_PLAYSTATUSH +#define NULLSOFT_PLAYSTATUSH +#pragma warning(disable:4786) +//#include <map> +#include "../nu/AutoLock.h" + +class DriveStatus +{ +public: + DriveStatus(); + + void RippingStarted(), RippingStopped(); + + bool IsRipping() const; +private: + bool ripping; +}; + +class PlayStatus +{ +public: + DriveStatus &operator [](int index) { return driveStatus[index-'A']; } + DriveStatus driveStatus[26]; +}; +extern PlayStatus playStatus; +//extern std::map<char, DriveStatus> playStatus; +extern Nullsoft::Utility::LockGuard *playStatusGuard; +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/VeritasPlay.cpp b/Src/Plugins/Input/in_cdda/VeritasPlay.cpp new file mode 100644 index 00000000..efb10d9a --- /dev/null +++ b/Src/Plugins/Input/in_cdda/VeritasPlay.cpp @@ -0,0 +1,636 @@ +#include "Main.h" +#include <windows.h> +#include "VeritasPlay.h" +#include "CDDB.h" +#include "workorder.h" +#include "api.h" + +VeritasPlay::VeritasPlay(bool _ripping) +: opened(false), ripping(_ripping), +primo(0), padStart(false), padEnd(false) +{ + submitHandle=0; + hThread = NULL; + overflowBuffer = NULL; + overflow = 0; + buffers = NULL; + currentBuffer = 0; +} + +VeritasPlay::~VeritasPlay() +{ + if (opened) + Abort(); + + Close(); + + DestroyBuffers(); + + + if (primo) + { + waServiceFactory *sf = (line.service ? line.service->service_getServiceByGuid(obj_primo::getServiceGuid()) : NULL); + if (sf) sf->releaseInterface(primo); + } + + primo = 0; + + if (submitHandle) + { + int x = workorder->CloseSig(submitHandle); + submitHandle=0; + } +} + +void VeritasPlay::CreateBuffers() +{ + if (buffers) + return; + + if (ripping) + { + buf_size = config_rip_buffersize; + nb_veritas_buf = config_rip_buffers; + } + else + { + buf_size = config_play_buffersize; + nb_veritas_buf = config_play_buffers; + } + + overflowBuffer = new BYTE[2352 * buf_size]; + overflow = 0; + + buffers = new VeritasBuffer[nb_veritas_buf]; + for (int i = 0;i < nb_veritas_buf;i++) + { + buffers[i].Create(buf_size); + } +} + +void VeritasPlay::DestroyBuffers() +{ + if (buffers) + { + for (int i = 0;i < nb_veritas_buf;i++) + { + buffers[i].Destroy(); + } + delete [] buffers; + } + + buffers = 0; + + delete overflowBuffer; + overflowBuffer = 0; +} + +void VeritasPlay::setvolume(int a_v, int a_p) +{ + line.outMod->SetVolume(a_v); + line.outMod->SetPan(a_p); +} + +void VeritasPlay::setoutputtime(int time_in_ms) +{ + need_seek = time_in_ms; +} + +void VeritasPlay::stop() +{ + killswitch = 1; + + Close(); + + if (hThread) + { + WaitForEvent(hThread, INFINITE); + hThread=0; + } + + line.outMod->Close(); +} + +void VeritasPlay::SeekAndFlush() +{ + int destsector = start_sector + ((need_seek * 75) / 1000); + Abort(); + openVeritasTrack(destsector, end_sector - destsector); + decode_pos_ms = need_seek; + // wait for a buffer before we flush + DWORD cursec = 0, totsec = 0; + while (true) + { + if (primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec) != PRIMOSDK_RUNNING + && primo->UnitStatus(&unit, NULL, NULL, NULL, NULL) == PRIMOSDK_UNITERROR) + return; + + // check how far we've gone + if (cursec < buffers[currentBuffer].sector) + Sleep(1); + else + break; + } + + overflow = 0; + lastseek = destsector; + line.outMod->Flush(need_seek); + need_seek = -1; +} + + +void VeritasPlay::Seek() +{ + int destsector = start_sector + ((need_seek * 75) / 1000); + Abort(); + openVeritasTrack(destsector, end_sector - destsector); + + overflow = 0; + decode_pos_ms = need_seek; + need_seek = -1; + + lastseek = destsector; +} + +void VeritasPlay::Abort() +{ + AbortAsync(); + WaitForAbort(66); +} + +void VeritasPlay::AbortAsync() +{ + primo->RunningStatus(PRIMOSDK_ABORT, NULL, NULL); +} + +void VeritasPlay::WaitForAbort(int time) +{ + while (primo->RunningStatus(PRIMOSDK_GETSTATUS, NULL, NULL) == PRIMOSDK_RUNNING) + Sleep(time); + opened=false; +} + +int VeritasPlay::openVeritasTrack(DWORD start, DWORD length) +{ + int speedChoice = config_maxextractspeed; + DWORD speed; + if (ripping) + { + switch (speedChoice) + { + case 0: // 0.5x + case 1: // 1x + speed = 1; // can't do 0.5x in the SDK + break; + case 2: // 2x + speed = 2; + break; + case 3: // 4x + speed = 4; + break; + case 4: // 8x + speed = 8; + break; + case 5: // 16x + if (getRegVer() <= 0) + speed = 8; + else + speed = 16; + break; + default: + if (speedChoice < 0) + speed = PRIMOSDK_MIN; + else + { + if (getRegVer() <= 0) + speed = 8; + else + speed = PRIMOSDK_MAX; + } + break; + } + } + else + speed = 4;//PRIMOSDK_MAX; + + if (primo->ExtractAudioToBuffer(&unit, start, length, speed, 0, 0, 0) != PRIMOSDK_OK) + return 0; + + for (int i = 0;i < nb_veritas_buf;i++) + { + buffers[i].internal = buffers[i].buffer; + if (i==0 && padStart) + { + buffers[i].offset = buf_size*2352 + config_offset*4; + buffers[i].readSize = buf_size*2352; + memset((char *)(buffers[i].internal)+buffers[i].offset, 0, buffers[i].readSize); + buffers[i].sector=0; + continue; + } + if (i==0 && ripping) + buffers[i].offset = ((2352 + config_offset*4) % 2352); + if (primo->NextExtractAudioBuffer(buffers[i].buffer, buf_size*2352, &buffers[i].readSize, &buffers[i].sector) != PRIMOSDK_OK) + return 0; + } + + currentBuffer = 0; + opened = true; + return 1; +} + +int VeritasPlay::CopyOverflow(char *sample_buffer, int len) +{ + if (overflow) + { + len = min(len, overflow); + memset(sample_buffer, 0, len); + memcpy(sample_buffer, overflowBuffer, len); + overflow -= len; + return len; + } + return 0; +} + +void VeritasPlay::OutputOverflow() +{ + while (overflow) + { + char sample_buffer[576*4*2] = {0}; + int bytes = 576 * 4; + int len = min(bytes, overflow); + memset(sample_buffer, 0, bytes); + memcpy(sample_buffer, overflowBuffer, len); + Output(sample_buffer, bytes); + overflow -= len; + } +} +#include <assert.h> +void VeritasPlay::OutputBuffer(VeritasBuffer &buffer) +{ + char sample_buffer[576*4*2] = {0}; + size_t bytes = 576 * 4; + char *bufferPosition = sample_buffer; + if (overflow) + { + assert(overflow < (long)bytes); + memcpy(bufferPosition, overflowBuffer, overflow); + bytes -= overflow; + bufferPosition += overflow; + overflow = 0; + } + BYTE *bufferInput = buffer.buffer; + while (buffer.readSize) + { + if (buffer.readSize < bytes) // if we don't have enough left, save it to overflow + { + // if there was overflow last time, and the passed buffer didn't fill us up + // then we'll have to save both + BYTE *temp = overflowBuffer; + int samplesLeft = 576 * 4 - bytes; + if (samplesLeft) + { + memcpy(temp, sample_buffer, samplesLeft); + temp += samplesLeft; + overflow += samplesLeft; + } + + // copy any leftovers of the passed buffer + memcpy(temp, bufferInput, buffer.readSize); + bufferInput += buffer.readSize; + overflow += buffer.readSize; + buffer.readSize = 0; + return ; + } + else + { + memcpy(bufferPosition, bufferInput, bytes); + bufferPosition = sample_buffer; + bufferInput += bytes; + buffer.readSize -= bytes; + bytes = 576 * 4; + Output(sample_buffer, 576*4); + } + } +} + +size_t VeritasPlay::CopyBuffer(VeritasBuffer &buffer, char *&sample_buffer, int &bytes) +{ + // since a buffer is only copied once, this is safe + buffer.readSize -= buffer.offset; + buffer.internal += buffer.offset; + buffer.offset=0; + size_t len = min((size_t)bytes, buffer.readSize); + + memcpy(sample_buffer, buffer.internal, len); + buffer.internal += len; + buffer.readSize -= len; + sample_buffer += len; + bytes -= len; + return len; +} + +void VeritasPlay::Output(char *buffer, int len) +{ + line.VSAAddPCMData(buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/); + line.SAAddPCMData(buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/); + + int bytes = len; + if (line.dsp_isactive()) + bytes = line.dsp_dosamples((short *)buffer, len / g_nch / 2, 16, g_nch, 44100) * (g_nch * 2); + + while (line.outMod->CanWrite() < bytes && !killswitch) Sleep(10); + + line.outMod->Write(buffer, bytes); + + decode_pos_ms += ((len / g_nch / 2) * 1000) / 44100; +} + +int VeritasPlay::read(char *dest, int len, int *killswitch) //called by winampGetExtendedRead_getData +{ + bool noAbort=false; + int bytesCopied = 0; + + speedLimiter.Limit(killswitch); + while (!*killswitch) + { + DWORD cursec = 0, totsec = 0; + int r = primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec); + + switch(r) + { + case PRIMOSDK_RUNNING: + break; + case PRIMOSDK_OK: + noAbort=true; + break; + default: + goto readabort; // benski> Mr. Faulkner's high school BASIC class prepared me for the real world! + } + + int a = primo->UnitStatus(&unit, NULL, NULL, NULL, NULL); + switch(a) + { + case PRIMOSDK_OK: + break; + default: // todo is everything else really an error? maybe message box for testing purposes + goto readabort; + } + + // check how far we've gone + if (cursec >= buffers[currentBuffer].sector) + { + char *olddest=dest; + int bytes = CopyBuffer(buffers[currentBuffer], dest, len); + if (submitHandle && bytes) + { + int res = workorder->WriteSigData(submitHandle, olddest, bytes); + switch(res) + { + case S_OK: + break; + case SG_SignatureAcquired: + default: + workorder->CloseSig(submitHandle); + submitHandle=0; + break; + } + } + speedLimiter.MoreBytesRead(bytes); + bytesCopied += bytes; + + if (!len || end == 1) + { + return bytesCopied; + } + + if ((buffers[currentBuffer].sector + lastseek) == end_sector) // are we done? + { + bytesCopied -= ((2352 - config_offset*4) % 2352); + end = 1; + return bytesCopied; + } + + buffers[currentBuffer].internal = buffers[currentBuffer].buffer; + buffers[currentBuffer].offset = 0; + if (!noAbort) + if (primo) primo->NextExtractAudioBuffer(buffers[currentBuffer].buffer, buf_size*2352, &buffers[currentBuffer].readSize, &buffers[currentBuffer].sector); + currentBuffer = (currentBuffer + 1) % nb_veritas_buf; + + } + else if (bytesCopied != 0) + return bytesCopied; + else + Sleep(13*buf_size); + } + // TODO: we can only get here if killswitch got set or if there was an error +readabort: + if (submitHandle) + { + workorder->AbortSig(submitHandle); + submitHandle=0; + } + AbortAsync(); + return -1; +} + +int VeritasPlay::threadProc2() +{ + bool noAbort=false; + while (!killswitch) + { + if (need_seek != -1) + SeekAndFlush(); + + DWORD cursec = 0, totsec = 0; + int r = primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec); + + switch(r) + { + case PRIMOSDK_RUNNING: + break; + case PRIMOSDK_OK: + noAbort=true; + break; + default: + Abort(); + if (!killswitch) Sleep(200); + if (!killswitch) PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + return 0; + } + + int a = primo->UnitStatus(&unit, NULL, NULL, NULL, NULL); + switch(a) + { + case PRIMOSDK_OK: + break; + default: // todo is everything else really an error? maybe message box for testing purposes + Abort(); + if (!killswitch) Sleep(200); + if (!killswitch) PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + return 0; + } + + // check how far we've gone + if (cursec >= buffers[currentBuffer].sector) + { + OutputBuffer(buffers[currentBuffer]); + + if ((buffers[currentBuffer].sector+lastseek)==end_sector) // are we done? + break; + + buffers[currentBuffer].internal = buffers[currentBuffer].buffer; + if (!noAbort) + primo->NextExtractAudioBuffer(buffers[currentBuffer].buffer, buf_size*2352, &buffers[currentBuffer].readSize, &buffers[currentBuffer].sector); + + currentBuffer = (currentBuffer + 1) % nb_veritas_buf; + } + else + Sleep(13*buf_size); + } + + if (killswitch) + { + Abort(); + return 0; + } + + if (!noAbort) + AbortAsync(); + + OutputOverflow(); + //wait for output to be finished + line.outMod->Write(NULL, 0); + if (!noAbort) + WaitForAbort(10); + while (!killswitch && line.outMod->IsPlaying()) Sleep(10); + if (!killswitch) + PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + + + return 0; +} + +#define VERITASPLAY_OPEN_FAIL 1 +#define VERITASPLAY_OPEN_NOPRIMO 2 + +int VeritasPlay::open(char drive, int track) //called by winampGetExtendedRead +{ + if ((ripping && !config_rip_veritas)) + return VERITASPLAY_OPEN_FAIL; + + need_seek = -1; + + driveLetter = drive; + unit = drive; + + hThread = NULL; + + if (!primo) + { + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + } + + if (!primo) + return VERITASPLAY_OPEN_NOPRIMO; + + end = 0; + + speedLimiter.Reset(); + if (getRegVer() <= 0) + speedLimiter.SetLimit(5); + else + speedLimiter.NoLimit(); + + if (primo->DiscInfoEx(&unit,0, NULL, NULL, NULL, NULL, NULL, NULL) == PRIMOSDK_OK) + { + DWORD sesnum, tracktype, pregap; + if (primo->TrackInfo(track, &sesnum, &tracktype, &pregap, &start_sector, &sec_length) == PRIMOSDK_OK) + { + if (ripping) + { + if (config_offset != 0) + sec_length++; // TODO: some sort of logic for the last track + if (config_offset<0) + { + if (track != 1 || config_read_leadin) + start_sector--; + else + { + sec_length--; + padStart=true; + } + } + + } + end_sector = start_sector + sec_length; +#if 0 // TODO: add a config option to skip pregap (maybe separate config for burning and playback) + start_sector+=pregap; + sec_length-=pregap; +#endif + CreateBuffers(); + + if (openVeritasTrack(start_sector, sec_length)) + { + g_nch = 2; // TODO: maybe we should handle red book 4 channel audio? + g_playlength = (sec_length / 75) * 1000; + + decode_pos_ms = 0; + lastseek = start_sector; + need_seek = -1; + return 0; + } + } + } + Close(); + return VERITASPLAY_OPEN_FAIL; +} + +int VeritasPlay::play(char drive, int track) //called by winamp2 +{ + if (!config_use_dae2 || !config_use_veritas) + return 1; + + hThread=NULL; + { + g_playtrack = track; + } + + switch(open(drive, track)) + { + case VERITASPLAY_OPEN_FAIL: + Sleep(200); + // fall through + case VERITASPLAY_OPEN_NOPRIMO: + Close(); + return 1; + } + + DWORD thread_id; + hThread = CreateThread(NULL, NULL, &threadProc, (LPVOID)this, CREATE_SUSPENDED, &thread_id); + SetThreadPriority(hThread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST)); + + int maxlat = line.outMod->Open(44100, g_nch, 16, -1, -1); + if (maxlat < 0) + { + Sleep(200); + Close(); + CloseHandle(hThread); + return 1; + } + + killswitch = 0; + + line.SetInfo(1411, 44, g_nch, 1); + line.SAVSAInit(maxlat, 44100); + line.VSASetInfo(g_nch, 44100); + line.is_seekable = 1; + ResumeThread(hThread); + + return 0; +} + +void VeritasPlay::Close() +{ + driveLetter=0; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/VeritasPlay.h b/Src/Plugins/Input/in_cdda/VeritasPlay.h new file mode 100644 index 00000000..30b16f38 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/VeritasPlay.h @@ -0,0 +1,122 @@ +#ifndef NULLSOFT_VERITASPLAYH +#define NULLSOFT_VERITASPLAYH + +#include "CDPlay.h" +#include <windows.h> +#include "SpeedLimiter.h" +#include "main.h" + +using namespace Nullsoft::Utility; +class VeritasBuffer +{ +public: + VeritasBuffer() : buffer(0), readSize(0), sector(0), offset(0) + { + } + ~VeritasBuffer() + { + Destroy(); + } + void Create(int numBuffers) + { + buffer = new BYTE[numBuffers * 2352]; + Clear(); + } + void Destroy() + { + if (buffer) + delete buffer; + buffer = 0; + Clear(); + } + void Clear() + { + readSize = 0; + sector = 0; + } + BYTE *buffer; + BYTE *internal; + DWORD readSize; + DWORD sector; + int offset; +}; + +class VeritasPlay : public C_CDPlay +{ +public: + VeritasPlay(bool _ripping = false); + ~VeritasPlay(); + //void Delete() {if (primo) delete primo; primo = 0; } + void CreateBuffers(); + void DestroyBuffers(); + int open(char drive, int track); //called by winampGetExtendedRead + int play(char drive, int track); //called by winamp2 + int openVeritasTrack(DWORD start, DWORD length); + + static DWORD WINAPI threadProc(LPVOID lpParameter) + { + VeritasPlay *wp = (VeritasPlay *)lpParameter; + return wp->threadProc2(); + } + + void OutputBuffer(VeritasBuffer &buffer); + int read(char *dest, int len, int *killswitch); + void Abort(); + void Seek(); + void SeekAndFlush(); + void Output(char *buffer, int len); + void OutputOverflow(); + int CopyOverflow(char *sample_buffer, int len); + + size_t CopyBuffer(VeritasBuffer &buffer, char *&sample_buffer, int &bytes); + int threadProc2(); + void stop(); + void pause() + { + line.outMod->Pause(1); + } + void unpause() + { + line.outMod->Pause(0); + } + int getlength() + { + return g_playlength; + } + int getoutputtime() + { + return line.outMod->GetOutputTime(); + } + void setoutputtime(int time_in_ms); + void setvolume(int a_v, int a_p); + + void *submitHandle; +private: + void Close(); + void AbortAsync(); + + void WaitForAbort(int time); + int killswitch; + HANDLE hThread; + int decode_pos_ms; + int need_seek; + + DWORD unit, start_sector, end_sector, lastseek, sec_length; + int end; + int total_extract_len; + DWORD extract_start_time; + BYTE *overflowBuffer; + long overflow; + VeritasBuffer *buffers; + int buf_size, currentBuffer, nb_veritas_buf; + int g_nch; + bool ripping, opened; + SpeedLimiter speedLimiter; + bool padStart, padEnd; + + #ifndef IGNORE_PRIMO + obj_primo *primo; + #endif +}; + +#endif diff --git a/Src/Plugins/Input/in_cdda/WindacPlay.cpp b/Src/Plugins/Input/in_cdda/WindacPlay.cpp new file mode 100644 index 00000000..69c7a78b --- /dev/null +++ b/Src/Plugins/Input/in_cdda/WindacPlay.cpp @@ -0,0 +1,321 @@ +#include "WindacPlay.h" +#include "api__in_cdda.h" + +int WindacPlay::threadProc2() +{ + while (1) + { + if (need_seek != -1) + { + current_sector = start_sector; + current_sector += ((need_seek * 75) / 1000); + bytes_in_sbuf = 0; + line.outMod->Flush(need_seek); + decode_pos_ms = need_seek; + need_seek = -1; + } + if (!killswitch && bytes_in_sbuf <= 0 && current_sector.GetHSG() < end_sector.GetHSG()) + { + if (!scsi->Get_DriveStatus().CDPresent) + { + //infos->error("No CD present!"); + PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + return 0; + } + unsigned char *s = sbuf; + while ((bytes_in_sbuf < buf_size*2352) && (current_sector.GetHSG() < end_sector.GetHSG()) && !killswitch) + { + int n = min((int)16, (int)(end_sector.GetHSG() - current_sector.GetHSG())); + memset(s, 0, n*2352); + scsi->ReadCDDA(current_sector, n, s); + while (!scsi->WaitCDDA() && !killswitch) Sleep(66); + bytes_in_sbuf += n * 2352; + s += n * 2352; + current_sector += n; + } + } + + if (!bytes_in_sbuf && !killswitch) + { + //wait for output to be finished + line.outMod->Write(NULL, 0); + while (!killswitch && line.outMod->IsPlaying()) Sleep(10); + if (!killswitch) + PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + return 0; + } + + if (killswitch) return 0; + + char sample_buffer[576*4*2] = {0}; + int bytes = sizeof(sample_buffer) / 2; // enough room for dsp bullcrap + bytes = min((int)bytes_in_sbuf, (int)bytes); + memcpy(sample_buffer, sbuf, bytes); + if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes); + bytes_in_sbuf -= bytes; + + int obytes = bytes; + + line.VSAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/); + line.SAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/); + + if (line.dsp_isactive()) + bytes = line.dsp_dosamples((short *)sample_buffer, bytes / g_nch / 2, 16, g_nch, 44100) * (g_nch * 2); + + while (line.outMod->CanWrite() < bytes && !killswitch) Sleep(66); + if (killswitch) return 0; + + line.outMod->Write(sample_buffer, bytes); + + decode_pos_ms += ((obytes / g_nch / 2) * 1000) / 44100; + } + return 0; +} + +void WindacPlay::stop() +{ + if (hThread) + { + killswitch = 1; + WaitForSingleObject(hThread, INFINITE); + } + if (needsToClose) + { + needsToClose = false; + } + line.outMod->Close(); +} + +int WindacPlay::open(wchar_t drive, int track) //called by winampGetExtendedRead +{ + g_drive = drive; + if (!inited && !LoadASPI()) + { + g_drive = 0; + return 1; + } + + inited = 1; + + int drivenum = 0; + getTrackInfos(&drivenum, (char)drive); + + m_pMapDrive = new CMapDrive(TRUE); + int nbdrives = m_pMapDrive->GetMaxDrives(); + if (!nbdrives) return 0; + + int host = -1, id = -1, lun = -1; + if (getSCSIIDFromDrive((char)drive, &host, &id, &lun)) + { + int found = 0; + for (int i = 0;i < nbdrives;i++) + { + drive_info = m_pMapDrive->GetInfo(i); + if (drive_info.HostAdapterNumber == host && drive_info.ID == id && drive_info.LUN == lun) + { + found = 1; + break; + } + } + if (!found) + { + s_last_error = "Drive not found"; + return 1; + } + } + else + { + // can't figure out the SCSI ID, oh well, try the gay method + TDriveInfo *tdi = &m_pMapDrive->GetInfo(drivenum); + if (!tdi) + { + s_last_error = "Drive not found"; + return 1; + } + + drive_info = *tdi; + } + + scsi = new CSCSICD((char)drive, drive_info); + + TDriveStatus status = scsi->Get_DriveStatus(); + + if (!status.CDPresent) + { + s_last_error = "CD not present"; + //infos->warning("No CD present!"); + g_drive=0; + return 1; + } + + TTrackList track_info = {0}; + track_info.TrackNummer = track; + scsi->ReadTrackInfo(track_info); + + if (track_info.Flags.DataTrack) + { + s_last_error = "Cannot play track"; + //infos->warning("Can't play data tracks"); + g_drive=0; + return 1; + } + + start_sector = track_info.StartSektor; + current_sector = start_sector; + end_sector = start_sector; + slength = track_info.Laenge; + end_sector += slength; + + g_playlength = (slength / 75) * 1000; + + g_nch = track_info.Flags.AudioChannels; + g_srate = 44100; + g_bps = 16; + + scsi->PrepareCDDA(); + + if (!sbuf) + sbuf = (unsigned char *)malloc(2352 * buf_size); + bytes_in_sbuf = 0; + + last_eject_scan = 0; + + return 0; +} + +int WindacPlay::play(wchar_t drive, int track) //called by winamp2's normal(old) play() interface +{ + if (open(drive, track)) return 1; + + // do this here as it helps to prevent an audio glitch on first playback and volume is set low + setvolume(a_v, a_p); + + int maxlat = line.outMod->Open(44100, g_nch, 16, -1, -1); + if (maxlat < 0) + { + g_drive=0; + return 1; + } + + line.SetInfo(1411, 44, g_nch, 1); + line.SAVSAInit(maxlat, 44100); + line.VSASetInfo(g_nch, 44100); + line.is_seekable = 1; + + killswitch = 0; + DWORD thread_id; + hThread = CreateThread(NULL, NULL, &threadProc, (LPVOID)this, NULL, &thread_id); + SetThreadPriority(hThread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST)); + + //open the device thru MCI (for getfileinfo to work properly) + g_playtrack = track; + needsToClose = true; + + return 0; +} + +int WindacPlay::read(char *dest, int len, int *killswitch) //called by winampGetExtendedRead_getData +{ + int l = 0; + + while (l < len && !*killswitch) + { + if (!*killswitch && bytes_in_sbuf <= 0 && current_sector.GetHSG() < end_sector.GetHSG()) + { + //scan for ejected CD only every 2 seconds + if (last_eject_scan + 5000 < GetTickCount()) + { + int cnt = 5; + while (!scsi->Get_DriveStatus().CDPresent && cnt--) + { + Sleep(100); + } + if (cnt < 0 && !scsi->Get_DriveStatus().CDPresent) + { + //infos->error("No CD present!"); + return -1; + } + last_eject_scan = GetTickCount(); + } + + unsigned char *s = sbuf; + while ((bytes_in_sbuf < buf_size*2352) && (current_sector.GetHSG() < end_sector.GetHSG())) + { + int n = min((int)16, (int)(end_sector.GetHSG() - current_sector.GetHSG())); + memset(s, 0, n*2352); + scsi->ReadCDDA(current_sector, n, s); + while (!scsi->WaitCDDA() && !*killswitch) Sleep(66); + if (*killswitch) break; + bytes_in_sbuf += n * 2352; + s += n * 2352; + current_sector += n; + } + } + + if (!bytes_in_sbuf) break; + + int bytes = min(bytes_in_sbuf, len - l); + memcpy(dest + l, sbuf, bytes); + + if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes); + bytes_in_sbuf -= bytes; + + l += bytes; + } + return l; +} + +void WindacPlay::getTrackInfos(int *drivenum, char driveletter) +{ + //finds first cdrom drive letter + char firstcd = 'D'; + { + DWORD drives = GetLogicalDrives(); + int nb = 0; + for (int drivemask = 0; (drivemask < 32) && (nb < 4); drivemask++) + { + if (drives&(1 << drivemask)) + { + wchar_t tmp[16] = {0}; + wsprintf(tmp, L"%c:\\", L'A' + drivemask); + if (GetDriveType(tmp) == DRIVE_CDROM) + { + firstcd = 'A' + drivemask; + break; + } + } + } + } + + *drivenum = driveletter - (unsigned char)firstcd; +} + +WindacPlay::WindacPlay() +{ + scsi = NULL; + sbuf = NULL; + m_pMapDrive = NULL; + buf_size = 64; //make it configitem + hThread = NULL; + decode_pos_ms = 0; + inited = 0; + need_seek = -1; + needsToClose = false; +} + +WindacPlay::~WindacPlay() +{ + if (scsi) + { + scsi->FinishCDDA(); + delete(scsi); + } + delete(m_pMapDrive); + free(sbuf); + if (inited) FreeASPI(); + + if (needsToClose) + { + needsToClose = false; + } +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/WindacPlay.h b/Src/Plugins/Input/in_cdda/WindacPlay.h new file mode 100644 index 00000000..da06308b --- /dev/null +++ b/Src/Plugins/Input/in_cdda/WindacPlay.h @@ -0,0 +1,77 @@ +#ifndef NULLSOFT_WINDACPLAYH +#define NULLSOFT_WINDACPLAYH + +#include "Main.h" +#include "CDPlay.h" +#include "windac/Dac32.h" +#include "../nu/AutoLock.h" + +using namespace Nullsoft::Utility; +class WindacPlay : public C_CDPlay +{ +public: + WindacPlay(); + ~WindacPlay(); + int open(wchar_t drive, int track); + int play(wchar_t drive, int track); + static DWORD WINAPI threadProc(LPVOID lpParameter) + { + WindacPlay *wp = (WindacPlay *)lpParameter; + return wp->threadProc2(); + } + + int read(char *dest, int len, int *killswitch); + int threadProc2(); + void stop(); + void pause() + { + line.outMod->Pause(1); + } + void unpause() + { + line.outMod->Pause(0); + } + int getlength() + { + return g_playlength; + } + int getoutputtime() + { + return line.outMod->GetOutputTime(); + } + void setoutputtime(int time_in_ms) + { + need_seek = time_in_ms; + } + void setvolume(int _a_v, int _a_p) + { + line.outMod->SetVolume(_a_v); + line.outMod->SetPan(_a_p); + } + +private: + void getTrackInfos(int *drivenum, char driveletter); + unsigned char *sbuf; + long bytes_in_sbuf; + int buf_size; + int start, end; + int g_nch, g_srate, g_bps; + int killswitch; + HANDLE hThread; + int decode_pos_ms; + int need_seek; + + BOOL inited; + + CMapDrive *m_pMapDrive; + CSCSICD *scsi; + TDriveInfo drive_info; + CCDAdress start_sector, current_sector, end_sector; + int slength; + + DWORD last_eject_scan; + + bool needsToClose; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/api__in_cdda.h b/Src/Plugins/Input/in_cdda/api__in_cdda.h new file mode 100644 index 00000000..a2dc222c --- /dev/null +++ b/Src/Plugins/Input/in_cdda/api__in_cdda.h @@ -0,0 +1,22 @@ +#ifndef NULLSOFT_APIH +#define NULLSOFT_APIH + +#include <api/application/api_application.h> +extern api_application *applicationApi; +#define WASABI_API_APP applicationApi + +#include "../Agave/Config/api_config.h" +extern api_config *agaveConfigApi; +#define AGAVE_API_CONFIG agaveConfigApi + +#include "../Agave/Language/api_language.h" + +#ifndef IGNORE_API_GRACENOTE +#include "../gracenote/api_gracenote.h" +extern api_gracenote *gracenoteApi; +#define AGAVE_API_GRACENOTE gracenoteApi +#endif + +#include <api/service/waServiceFactory.h> + +#endif NULLSOFT_APIH
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/cddbevnt.cpp b/Src/Plugins/Input/in_cdda/cddbevnt.cpp new file mode 100644 index 00000000..4a86a2a7 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/cddbevnt.cpp @@ -0,0 +1,178 @@ +#include "./cddbevnt.h" +#include "cddbinterface.h" +#include <strsafe.h> +#include <ocidl.h> + +#include "cddbcontrolwinamp.tlh" + +CDBBEventManager::CDBBEventManager(void) : ref(1), cookie(0), user(0), + fnCmdCompleted(NULL), fnCmdProgress(NULL), + fnLogMessage(NULL), fnServerMessage(NULL) +{ +} + +CDBBEventManager::~CDBBEventManager(void) +{ +} + +HRESULT CDBBEventManager::Advise(IUnknown *pCDDBCtrl) +{ + HRESULT hr; + IConnectionPoint *pcp; + IConnectionPointContainer *pcpc; + + if (cookie) return E_FAIL; + if (!pCDDBCtrl) return E_INVALIDARG; + + hr = pCDDBCtrl->QueryInterface(IID_IConnectionPointContainer, (PVOID*)&pcpc); + if (SUCCEEDED (hr)) + { + hr = pcpc->FindConnectionPoint(DIID_DCDDBEvents, &pcp); + if (SUCCEEDED(hr)) + { + hr = pcp->Advise(static_cast<IDispatch*>(this), &cookie); + if (FAILED(hr)) cookie = 0; + pcp->Release(); + } + pcpc->Release(); + } + return hr; +} + +HRESULT CDBBEventManager::Unadvise(IUnknown *pCDDBCtrl) +{ + HRESULT hr; + IConnectionPoint *pcp = nullptr; + IConnectionPointContainer *pcpc = nullptr; + + if (!cookie) return S_OK; + if (!pCDDBCtrl) return E_INVALIDARG; + + hr = pCDDBCtrl->QueryInterface(IID_IConnectionPointContainer, (PVOID*)&pcpc); + if (SUCCEEDED (hr)) + { + hr = pcpc->FindConnectionPoint(DIID_DCDDBEvents, &pcp); + if (SUCCEEDED(hr)) + { + hr = pcp->Unadvise(cookie); + pcp->Release(); + } + pcpc->Release(); + } + return hr; +} + +HRESULT CDBBEventManager::RegisterCallback(UINT nType, void *fnCallback) +{ + switch(nType) + { + case CDDB_CB_CMDCOMPLETED: fnCmdCompleted = (CDDB_CMDCOMPLETED)fnCallback; break; + case CDDB_CB_CMDPROGRESS: fnCmdProgress = (CDDB_CMDPROGRESS)fnCallback; break; + case CDDB_CB_LOGMSG: fnLogMessage = (CDDB_LOGMSG)fnCallback; break; + case CDDB_CB_SRVMSG: fnServerMessage = (CDDB_SRVMSG)fnCallback; break; + default: return E_INVALIDARG; + } + return S_OK; +} + +ULONG_PTR CDBBEventManager::SetUserParam(ULONG_PTR userParam) +{ + ULONG_PTR tmp = user; + user = userParam; + return tmp; +} + +STDMETHODIMP CDBBEventManager::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) return E_POINTER; + + if (IsEqualIID(riid, DIID_DCDDBEvents)) + *ppvObject = dynamic_cast<CDBBEventManager*>(this); + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = dynamic_cast<IDispatch*>(this); + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = dynamic_cast<IUnknown*>(this); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG CDBBEventManager::AddRef(void) +{ + return InterlockedIncrement(&ref); +} + +ULONG CDBBEventManager::Release(void) +{ + if (ref && 0 == InterlockedDecrement(&ref)) + { + delete this; + return 0; + } + return ref; +} + +STDMETHODIMP CDBBEventManager::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + return DISP_E_UNKNOWNNAME; +} + +STDMETHODIMP CDBBEventManager::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CDBBEventManager::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CDBBEventManager::Invoke(DISPID dispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pDispParams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + switch(dispId) + { + case EVENT_COMMAND_COMPLETED: + if (3 != pDispParams->cArgs) return DISP_E_BADPARAMCOUNT; + OnCommandCompleted(pDispParams->rgvarg[2].lVal, pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].pvarVal); + return S_OK; + case EVENT_LOG_MESSAGE: + if (1 != pDispParams->cArgs) return DISP_E_BADPARAMCOUNT; + OnLogMessage(pDispParams->rgvarg[0].bstrVal); + return S_OK; + case EVENT_SERVER_MESSAGE: + if (3 != pDispParams->cArgs) return DISP_E_BADPARAMCOUNT; + OnServerMessage(pDispParams->rgvarg[2].lVal, pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].bstrVal); + return S_OK; + case EVENT_COMMAND_PROGRESS: + if (4 != pDispParams->cArgs) return DISP_E_BADPARAMCOUNT; + OnCommandProgress(pDispParams->rgvarg[3].lVal, pDispParams->rgvarg[2].lVal, pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal); + return S_OK; + } + return DISP_E_MEMBERNOTFOUND; +} + +void CDBBEventManager::OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData) +{ + if(fnCmdCompleted) fnCmdCompleted(lCommandCode, hCommandResult, pCommandData, user); +} + +void CDBBEventManager::OnLogMessage(BSTR bstrMessage) +{ + if(fnLogMessage) fnLogMessage(bstrMessage, user); +} + +void CDBBEventManager::OnServerMessage(LONG lMessageCode, LONG lMessageAction, BSTR bstrMessageData) +{ + if(fnServerMessage) fnServerMessage(lMessageCode, lMessageAction,bstrMessageData, user); +} + +void CDBBEventManager::OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal) +{ + if(fnCmdProgress) fnCmdProgress(lCommandCode, lProgressCode, lBytesDone, lBytesTotal, user); + +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/cddbevnt.h b/Src/Plugins/Input/in_cdda/cddbevnt.h new file mode 100644 index 00000000..21104cde --- /dev/null +++ b/Src/Plugins/Input/in_cdda/cddbevnt.h @@ -0,0 +1,63 @@ +#ifndef NULLSOFT_CDDB_EVENT_MANAGER_HEADER +#define NULLSOFT_CDDB_EVENT_MANAGER_HEADER + + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +// callbacks +typedef void (CALLBACK *CDDB_CMDCOMPLETED)(LONG /*lCommandCode*/, HRESULT /*hCommandResult*/, VARIANT* /*pCommandData*/, ULONG_PTR /*user*/); +typedef void (CALLBACK *CDDB_LOGMSG)(BSTR /*bstrMessage*/, ULONG_PTR /*user*/); +typedef void (CALLBACK *CDDB_SRVMSG)(LONG /*lMessageCode*/, LONG /*lMessageAction*/, BSTR /*bstrMessageData*/, ULONG_PTR /*user*/); +typedef void (CALLBACK *CDDB_CMDPROGRESS)(LONG /*lCommandCode*/, LONG /*lProgressCode*/, LONG /*lBytesDone*/, LONG /*lBytesTotal*/, ULONG_PTR /*user*/); +// callback types +#define CDDB_CB_CMDCOMPLETED 0 +#define CDDB_CB_CMDPROGRESS 1 +#define CDDB_CB_LOGMSG 2 +#define CDDB_CB_SRVMSG 3 + +class CDBBEventManager : public IDispatch +{ +public: + CDBBEventManager(void); + virtual ~CDBBEventManager(void); + +public: + // *** IUnknown Methods *** + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + // *** IDispatch Methods *** + STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid); + STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); + STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo); + STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr); + +protected: + void OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData); + void OnLogMessage(BSTR bstrMessage); + void OnServerMessage(LONG lMessageCode, LONG lMessageAction, BSTR bstrMessageData); + void OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal); + +public: + HRESULT Advise(IUnknown *pCDDBCtrl); + HRESULT Unadvise(IUnknown *pCDDBCtrl); + HRESULT RegisterCallback(UINT nType, void *fnCallback); + ULONG_PTR SetUserParam(ULONG_PTR userParam); +protected: + LONG ref; + DWORD cookie; + ULONG_PTR user; + CDDB_CMDCOMPLETED fnCmdCompleted; + CDDB_CMDPROGRESS fnCmdProgress; + CDDB_LOGMSG fnLogMessage; + CDDB_SRVMSG fnServerMessage; + +}; + +#endif //NULLSOFT_CDDB_EVENT_MANAGER_HEADER + diff --git a/Src/Plugins/Input/in_cdda/cddbui.cpp b/Src/Plugins/Input/in_cdda/cddbui.cpp new file mode 100644 index 00000000..adb51e71 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/cddbui.cpp @@ -0,0 +1,997 @@ +#include "main.h" +#include ".\cddbui.h" +#include ".\cddb.h" +#include "api__in_cdda.h" +#include ".\resource.h" +#include "..\winamp\wa_ipc.h" + +#include <api/application/api_application.h> + +#include <shobjidl.h> +#include <commctrl.h> +#include <strsafe.h> + +#include "cddbcontrolwinamp.tlh" + +#define PROP_PRGDLG L"PRGDLG" + + +#define TIMER_PROGRESS_DESTROY_ID 1978 +#define TIMER_PROGRESS_DESTROY_ELAPSE 250 +#define TIMER_PROGRESS_ANIMATE_ID 1980 +#define TIMER_PROGRESS_ANIMATE_ELAPSE 65 + +#define MODAL_EXIT 0 +#define MODAL_ACTIVE 1 +#define MODAL_DESTROY 2 + +#define ICON_OFFSET_X 12 +#define ICON_OFFSET_Y 12 + +#define DIALOG_HEIGHT_NORMAL 66 +#define DIALOG_HEIGHT_EXTENDED 160 + +#ifndef IDC_HAND +#define IDC_HAND MAKEINTRESOURCE(32649) +#endif //IDC_HAND + + + +typedef struct _PROGRESSICON +{ + HINSTANCE hInstance; + LONG resId; + RECT rc; + LONG frames; + LONG step; + HBITMAP hbmp; +} PROGRESSICON; + +typedef struct _PROGRESSDLG +{ + PROGRESSICON icon; + UINT uState; + DWORD dwAutoClose; + CDDBDLG_ONBTNCLICK OnAbort; + CDDBDLG_ONBTNCLICK OnButton1; + BSTR Btn1Data; + BSTR AbortData; + WORD Modal; + HRESULT rCode; + HANDLE user; +} PROGRESSDLG; + +static HFONT hFont = NULL; +static LONG fontRef = 0; + +static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void CALLBACK ProgressDlg_OnTimer(HWND hwnd, UINT uMsg, UINT_PTR evntId, DWORD dwTime); +static void InvalidateLogo(HWND hwnd, PROGRESSICON *pIcon); +static BOOL EndProgressDialog(HWND hwnd); + +#define GET_DATA(__hwnd) ((PROGRESSDLG*)GetPropW((__hwnd), PROP_PRGDLG)) + +static wchar_t szText1[256]; +static wchar_t szText2[256]; + +#define GET_SAFE_LANGSTRING(__str, __buff, __cch) ((__str) ? (IS_INTRESOURCE(__str) ? WASABI_API_LNGSTRINGW_BUF((UINT)(UINT_PTR)(__str), (__buff), (__cch)) : (__str)) : L"") +#define GET_SAFE_LANGSTRING1(__str) GET_SAFE_LANGSTRING((__str), (szText1), (sizeof(szText1)/sizeof(wchar_t))) +#define GET_SAFE_LANGSTRING2(__str) GET_SAFE_LANGSTRING((__str), (szText2), (sizeof(szText2)/sizeof(wchar_t))) + + +typedef struct _ENUMWND_DATAPACK +{ + HWND host; + HWND *list; + INT index; + INT count; + UINT flags; + BOOL found; +} ENUMWND_DATAPACK; + +HWND CddbProgressDlg_Create(HWND hwndParent, INT nCmdShow) +{ + HWND hdlg = WASABI_API_CREATEDIALOGPARAMW(IDD_CDDB_PROGRESS, NULL, DialogProc, 0L); + if (hdlg && SW_HIDE != nCmdShow) ShowWindow(hdlg, SW_HIDE); + return hdlg; +} + +BOOL CddbProgressDlg_Initialize(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnAbort, BSTR bstrAbortUser) +{ + HWND hwndCtrl; + PROGRESSDLG *pDlg; + + if(!hwnd || !IsWindow(hwnd)) return FALSE; + + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + + KillTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID); + pDlg->OnAbort = (fnOnAbort) ? fnOnAbort : NULL; + if (pDlg->AbortData) SysFreeString(pDlg->AbortData); + pDlg->AbortData = (bstrAbortUser) ? SysAllocString(bstrAbortUser) : NULL; + + SetDlgItemTextW(hwnd, IDC_LBL_CAPTION, GET_SAFE_LANGSTRING1(pszCaption)); + SetDlgItemTextW(hwnd, IDC_LBL_STATUS, L""); + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LBL_REASON))) + { + ShowWindow(hwndCtrl, SW_HIDE); + SetWindowTextW(hwndCtrl, L""); + } + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS))) + { + ShowWindow(hwndCtrl, SW_HIDE); + SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)0, (LPARAM)0L); + + } + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL))) + { + SetWindowTextW(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW((fnOnAbort) ? IDS_ABORT : IDS_CLOSE))); + EnableWindow(hwndCtrl, (NULL != fnOnAbort)); + } + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT))) + { + SendMessageW(hwndCtrl, LVM_DELETEALLITEMS, 0, 0L); + } + + + pDlg->icon.step = 0; + InvalidateLogo(hwnd, &pDlg->icon); + SetTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID, TIMER_PROGRESS_ANIMATE_ELAPSE, ProgressDlg_OnTimer); + + pDlg->uState = STATE_ACTIVE; + return TRUE; +} + +BOOL CddbProgressDlg_Completed(HWND hwnd, LPCWSTR pszResult, LPCWSTR pszReason, DWORD nAutoCloseDelay, HRESULT rCode) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + + KillTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID); + + pDlg->uState = STATE_COMPLETED; + pDlg->rCode = rCode; + + if (AUTOCLOSE_NOW == nAutoCloseDelay) + { + EndProgressDialog(hwnd); + } + else + { + + HWND hwndCtrl; + SetDlgItemTextW(hwnd, IDC_LBL_STATUS, GET_SAFE_LANGSTRING1(pszResult)); + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS))) + { + ShowWindow(hwndCtrl, SW_HIDE); + SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)0, (LPARAM)0L); + } + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LBL_REASON))) + { + SetWindowTextW(hwndCtrl, GET_SAFE_LANGSTRING1(pszReason)); + ShowWindow(hwndCtrl, SW_SHOWNORMAL); + } + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL))) + { + + if (AUTOCLOSE_NEVER != nAutoCloseDelay) + { + INT time = nAutoCloseDelay/1000 + (((nAutoCloseDelay%1000)>500) ? 1 : 0); + if (time) + { + wchar_t szText[128] = {0}; + StringCchPrintfW(szText, sizeof(szText)/sizeof(wchar_t), L"%s (%d)", GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)),time); + SetDlgItemTextW(hwnd, IDCANCEL, szText); + } + else SetWindowText(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE))); + } + else SetWindowText(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE))); + EnableWindow(hwndCtrl, TRUE); + } + + + pDlg->icon.step = pDlg->icon.frames - 1; + InvalidateLogo(hwnd, &pDlg->icon); + + if (AUTOCLOSE_NEVER != nAutoCloseDelay) + { + pDlg->dwAutoClose = GetTickCount() + nAutoCloseDelay; + return (0 != SetTimer(hwnd, TIMER_PROGRESS_DESTROY_ID, TIMER_PROGRESS_DESTROY_ELAPSE, ProgressDlg_OnTimer)); + } + } + return TRUE; +} + +BOOL CddbProgressDlg_SetStatus(HWND hwnd, LPCWSTR pszStatus, INT nPercentCompleted) +{ + BOOL br(TRUE); + HWND hwndCtrl; + if (!hwnd || !IsWindow(hwnd)) return FALSE; + if (pszStatus && !SetDlgItemTextW(hwnd, IDC_LBL_STATUS, GET_SAFE_LANGSTRING1(pszStatus))) br = FALSE; + hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS); + if (hwndCtrl) + { + if (nPercentCompleted > 100) nPercentCompleted = 100; + if (nPercentCompleted < 0) ShowWindow(hwndCtrl, SW_HIDE); + else + { + SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)nPercentCompleted, (LPARAM)0L); + ShowWindow(hwndCtrl, SW_SHOWNA); + } + } + return br; +} + +UINT CddbProgressDlg_GetState(HWND hwnd) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return STATE_INACTIVE; + pDlg = GET_DATA(hwnd); + return (pDlg) ? pDlg->uState : STATE_INACTIVE; +} + +BOOL CddbProgressDlg_EnableAbortButton(HWND hwnd, BOOL bEnable) +{ + HWND hwndBtn; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + if (NULL == (hwndBtn = GetDlgItem(hwnd, IDCANCEL))) return FALSE; + return EnableWindow(hwndBtn, bEnable); +} + +BOOL CddbProgressDlg_ShowButton1(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnButton1, BSTR bstrUser) +{ + PROGRESSDLG *pDlg; + HWND hwndBtn; + + if(!hwnd || !IsWindow(hwnd)) return FALSE; + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + + if (NULL == (hwndBtn = GetDlgItem(hwnd, IDC_BUTTON1))) return FALSE; + + if (pDlg->Btn1Data) SysFreeString(pDlg->Btn1Data); + + if(pszCaption && fnOnButton1) + { + SetWindowTextW(hwndBtn, GET_SAFE_LANGSTRING1(pszCaption)); + ShowWindow(hwndBtn, SW_SHOWNORMAL); + pDlg->OnButton1 = fnOnButton1; + pDlg->Btn1Data = (bstrUser) ? SysAllocString(bstrUser) : NULL; + SendMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)TRUE, (LPARAM)hwndBtn); + } + else + { + ShowWindow(hwndBtn, SW_HIDE); + pDlg->OnButton1 = NULL; + pDlg->Btn1Data = NULL; + + } + return TRUE; +} + +BOOL CddbProgressDlg_ShowInTaskbar(HWND hwnd, BOOL bShow) +{ + HRESULT hr; + ITaskbarList *pTaskbar; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + hr = CoCreateInstance(CLSID_TaskbarList,0, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (void**)&pTaskbar); + if(SUCCEEDED(hr)) + { + hr = pTaskbar->HrInit(); + if (SUCCEEDED(hr)) + { + if (bShow) + { + hr = pTaskbar->AddTab(hwnd); + pTaskbar->ActivateTab(hwnd); + + } + else pTaskbar->DeleteTab(hwnd); + } + pTaskbar->Release(); + } + return (S_OK == hr); +} +BOOL CddbProgressDlg_SetExtendedMode(HWND hwnd, BOOL bEnable) +{ + RECT rc; + HWND hwndCtrl; + INT height; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + GetWindowRect(hwnd, &rc); + + RECT rw; + GetClientRect(hwnd, &rw); + height = (rc.bottom - rc.top) - (rw.bottom - rw.top); + SetRect(&rw, 0, 0, 1, (bEnable) ? DIALOG_HEIGHT_EXTENDED : DIALOG_HEIGHT_NORMAL); + MapDialogRect(hwnd, &rw); + height += rw.bottom; + + if (height == rc.bottom - rc.top) return TRUE; + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_BUTTON1))) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, rw.left, rw.top + (height - (rc.bottom - rc.top)), 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + } + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL))) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, rw.left, rw.top + (height - (rc.bottom - rc.top)), 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + } + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT))) + { + PROGRESSDLG *pDlg; + INT listBottom; + GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 1); + listBottom = rw.top - MulDiv(4, HIWORD(GetDialogBaseUnits()), 8); + + pDlg = GET_DATA(hwnd); + if (pDlg) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + INT listTop = ICON_OFFSET_Y * 2 + (pDlg->icon.rc.bottom - pDlg->icon.rc.top); + SetWindowPos(hwndCtrl, NULL, ICON_OFFSET_X, listTop, rc.right - rc.left - ICON_OFFSET_X*2, listBottom - listTop, SWP_NOACTIVATE | SWP_NOZORDER); + ShowWindow(hwndCtrl, (bEnable) ? SW_SHOW : SW_HIDE); + } + } + + SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); + + + return TRUE; +} +BOOL CddbProgressDlg_AddRecord(HWND hwnd, LPCWSTR pszArtist, LPCWSTR pszTitle, LPCWSTR pszLanguage) +{ + HWND hwndList; + LVITEMW item; + INT index; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + + hwndList = GetDlgItem(hwnd, IDC_LV_EXT); + if (!hwndList) return FALSE; + + item.mask = LVIF_TEXT; + item.iItem = 0xFFFF; + item.iSubItem = 0; + item.pszText = GET_SAFE_LANGSTRING1(pszArtist); + index = (INT)SendMessageW(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&item); + if (-1 == index) return FALSE; + + if (0 == index) + { + item.state = LVIS_FOCUSED | LVIS_SELECTED; + item.stateMask = item.state; + SendMessageW(hwndList, LVM_SETITEMSTATE, (WPARAM)index, (LPARAM)&item); + } + item.iItem = index; + item.mask = LVIF_TEXT; + item.iSubItem = 1; + item.pszText = GET_SAFE_LANGSTRING1(pszTitle);; + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&item); + + item.iItem = index; + item.mask = LVIF_TEXT; + item.iSubItem = 2; + item.pszText = GET_SAFE_LANGSTRING1(pszLanguage);; + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&item); + + return TRUE; +} + + +#define HOOK_MAX_DATA 12 +typedef struct _HOOKDATA +{ + HHOOK handle; + int ref; + HWND modalList[HOOK_MAX_DATA]; +} HOOKDATA; + +static HOOKDATA g_hook = { NULL, 0}; + +static LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam) +{ + MOUSEHOOKSTRUCT *pMouse = (MOUSEHOOKSTRUCT*)lParam; + switch(wParam) + { + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONDBLCLK: + if (FALSE == IsWindowEnabled(pMouse->hwnd)) + { + + for(int i = g_hook.ref - 1; i > -1 ; i--) + { + HWND hwndOwner = GetWindow(g_hook.modalList[i], GW_OWNER); + if (hwndOwner == pMouse->hwnd || hwndOwner == GetWindow(pMouse->hwnd, GW_OWNER)) + { + DWORD style = GetWindowLongPtrW(g_hook.modalList[i], GWL_STYLE); + if (0 != (WS_VISIBLE & style) && 0 == (WS_DISABLED & style)) + { + HWND hwndTest = GetForegroundWindow(); + if (hwndTest == g_hook.modalList[i]) + { + FLASHWINFO flash; + flash.hwnd = g_hook.modalList[i]; + flash.cbSize = sizeof(FLASHWINFO); + flash.dwFlags = FLASHW_CAPTION; + flash.uCount = 2; + flash.dwTimeout = 100; + FlashWindowEx(&flash); + MessageBeep(MB_OK); + } + else SetForegroundWindow(g_hook.modalList[i]); + return CallNextHookEx(g_hook.handle, code, wParam, lParam); + } + } + } + } + break; + } + return CallNextHookEx(g_hook.handle, code, wParam, lParam); +} +static void AddModalHook(HWND hdlg) +{ + if (!hdlg) return; + if (!g_hook.handle) + { + ZeroMemory(&g_hook, sizeof(HOOKDATA)); + g_hook.handle = SetWindowsHookEx(WH_MOUSE, HookProc, line.hDllInstance, NULL); + if (!g_hook.handle) return; + } + if (HOOK_MAX_DATA == (g_hook.ref - 1)) return; + g_hook.modalList[g_hook.ref] = hdlg; + g_hook.ref++; + return; +} + +static void ReleaseModalHook(HWND hdlg) +{ + if (!hdlg) return; + for (int i = 0; i < g_hook.ref; i++) + { + if (g_hook.modalList[i] == hdlg) + { + if (i != g_hook.ref -1) MoveMemory(&g_hook.modalList[i], &g_hook.modalList[i + 1], (g_hook.ref - i -1)*sizeof(HWND)); + + g_hook.ref--; + if (!g_hook.ref) + { + UnhookWindowsHookEx(g_hook.handle); + ZeroMemory(&g_hook, sizeof(HOOKDATA)); + } + return; + } + } + return ; +} + +HRESULT CddbProgressDlg_DoModal(HWND hwnd, RECT *prc) +{ + MSG msg; + HWND hwndOwner; + + PROGRESSDLG *pDlg; + HRESULT rCode; + HWND disabledList[32] = {0}; + + if(!hwnd || !IsWindow(hwnd)) return E_INVALIDARG; + pDlg = GET_DATA(hwnd); + if (!pDlg || MODAL_ACTIVE == pDlg->Modal) return E_POINTER; + + pDlg->Modal = MODAL_ACTIVE; + hwndOwner = GetParent(hwnd); + if (hwndOwner == GetDesktopWindow()) hwndOwner = NULL; + if (hwndOwner != line.hMainWindow && + hwndOwner == (HWND)SendMessageW(line.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT)) + { + hwndOwner = line.hMainWindow; + } + + DWORD mineTID, parentTID; + mineTID = GetWindowThreadProcessId(hwnd, NULL); + parentTID = (hwndOwner) ? GetWindowThreadProcessId(hwndOwner, NULL) : mineTID; + if (hwndOwner) + { + HWND *p; + if (mineTID != parentTID) AttachThreadInput(parentTID, mineTID, TRUE); + p = disabledList; + if (IsWindowEnabled(hwndOwner)) + { + *p = hwndOwner; + p++; + } + FindAllOwnedWindows(hwndOwner, p, sizeof(disabledList)/sizeof(HWND) - (INT)(p - disabledList), FINDWND_ONLY_ENABLED); + for (p = disabledList; *p != NULL; p++) { if (hwnd != *p) EnableWindow(*p, FALSE); } + } + + AddModalHook(hwnd); + + msg.message = WM_NULL; + while(MODAL_ACTIVE == pDlg->Modal) + { + if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) break; + else if (!CallMsgFilter(&msg, MSGF_DIALOGBOX) && + !IsDialogMessage(hwnd, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + else if (MODAL_ACTIVE == pDlg->Modal) WaitMessage(); + } + + ReleaseModalHook(hwnd); + + rCode = pDlg->rCode; + + if (msg.message == WM_QUIT) PostQuitMessage((int)msg.wParam); + if (hwndOwner) + { + if (mineTID != parentTID) AttachThreadInput(parentTID, mineTID, FALSE); + for (HWND *p = disabledList; *p != NULL; p++) { if (hwnd != *p) EnableWindow(*p, TRUE); } + SetActiveWindow(hwndOwner); + } + + if (prc && !GetWindowRect(hwnd, prc)) SetRect(prc, 0, 0, 0,0); + + if(MODAL_EXIT != pDlg->Modal) DestroyWindow(hwnd); + return rCode; +} + +BOOL CddbProgressDlg_ExitModal(HWND hwnd, HRESULT rCode, BOOL bDesroy) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + if (MODAL_ACTIVE == pDlg->Modal) + { + pDlg->Modal = (bDesroy) ? MODAL_DESTROY : MODAL_EXIT; + pDlg->rCode = rCode; + PostMessageW(hwnd, WM_NULL, 0, 0); + } + return TRUE; +} + +BOOL CddbProgressDlg_IsModal(HWND hwnd) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + pDlg = GET_DATA(hwnd); + return (pDlg && (MODAL_ACTIVE == pDlg->Modal)); +} + +INT CddbProgressDlg_GetSelRecordIndex(HWND hwnd) +{ + HWND hwndList; + if(!hwnd || !IsWindow(hwnd)) return -1; + hwndList = GetDlgItem(hwnd, IDC_LV_EXT); + if (!hwndList) return -1; + return (INT)(INT_PTR)SendMessageW(hwndList, LVM_GETNEXTITEM, -1, (LPARAM)(LVNI_SELECTED | LVNI_FOCUSED)); +} + +BOOL CddbProgressDlg_SetUserData(HWND hwnd, HANDLE user) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return FALSE; + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + pDlg->user = user; + return TRUE; +} + +HANDLE CddbProgressDlg_GetUserData(HWND hwnd) +{ + PROGRESSDLG *pDlg; + if(!hwnd || !IsWindow(hwnd)) return NULL; + pDlg = GET_DATA(hwnd); + return (pDlg) ? pDlg->user : NULL; +} + +static void InvalidateLogo(HWND hwnd, PROGRESSICON *pIcon) +{ + RECT rc; + SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y, + ICON_OFFSET_X + (pIcon->rc.right - pIcon->rc.left), + ICON_OFFSET_Y + (pIcon->rc.bottom - pIcon->rc.top)); + InvalidateRect(hwnd, &rc, TRUE); +} + +static BOOL EnableWindowTheme(HWND hwnd, BOOL bEnable) +{ + static HMODULE hModule = NULL; + static BOOL firstTime = TRUE; + static HRESULT (WINAPI *__setwintheme)(HWND, LPCWSTR, LPCWSTR) = NULL; + + if (!hModule) + { + if (!firstTime) return FALSE; + firstTime = FALSE; + hModule = LoadLibraryW(L"UxTheme.dll"); + if (!hModule) return FALSE; + __setwintheme = (HRESULT (WINAPI *)(HWND, LPCWSTR, LPCWSTR))GetProcAddress(hModule, "SetWindowTheme"); + if (!__setwintheme) + { + FreeLibrary(hModule); + hModule = NULL; + return FALSE; + } + } + return (S_OK == __setwintheme(hwnd, NULL, ((bEnable) ? NULL : L""))); +} + +static HRESULT InitializeProgressIcon(PROGRESSICON *pIcon) +{ + HRESULT hr; + LONG/*_PTR*/ lVal; // benski> windows 64 isn't supported by gracenote + + ICddbUIOptions *pUIOptions; + + if (!pIcon) return E_INVALIDARG; + ZeroMemory(pIcon, sizeof(PROGRESSICON)); + + hr = Cddb_GetIUIOptions((void**)&pUIOptions); + if (FAILED(hr)) return hr; + + hr = pUIOptions->GetCurrent(UI_DISP_PROGRESS); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(pUIOptions->get_ResourceHINSTANCE(&lVal))) pIcon->hInstance = (HINSTANCE)lVal; + if (SUCCEEDED(pUIOptions->get_Left(&lVal))) pIcon->rc.left = (LONG)lVal; + if (SUCCEEDED(pUIOptions->get_Top(&lVal))) pIcon->rc.top = (LONG)lVal; + if (SUCCEEDED(pUIOptions->get_Right(&lVal))) pIcon->rc.right = (LONG)lVal; + if (SUCCEEDED(pUIOptions->get_Bottom(&lVal))) pIcon->rc.bottom = (LONG)lVal; + pUIOptions->get_ProgressResourceID(&pIcon->resId); + pUIOptions->get_Frames(&pIcon->frames); + } + pUIOptions->Release(); + return hr; +} + +static BOOL AnimateProgressIcon(HDC hdc, INT x, INT y, PROGRESSICON *pIcon) +{ + INT w, h; + HDC hdcDst; + HBITMAP bmpOld; + + if (!hdc || !pIcon) return FALSE; + + if (!pIcon->hbmp) + { + if (pIcon->hInstance && pIcon->resId) + { + pIcon->hbmp = (HBITMAP)LoadImageW(pIcon->hInstance, MAKEINTRESOURCEW(pIcon->resId), + IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE); + } + if (!pIcon->hbmp) return FALSE; + } + + hdcDst = CreateCompatibleDC(hdc); + bmpOld = (HBITMAP)SelectObject(hdcDst, pIcon->hbmp); + + w = pIcon->rc.right - pIcon->rc.left; + h = pIcon->rc.bottom - pIcon->rc.top; + + BitBlt(hdc, x, y, w, h, hdcDst, pIcon->rc.left + (pIcon->step * w), pIcon->rc.top, SRCCOPY); + SelectObject(hdcDst, bmpOld); + DeleteDC(hdcDst); + return TRUE; +} + +static void CALLBACK ProgressDlg_OnTimer(HWND hwnd, UINT uMsg, UINT_PTR evntId, DWORD dwTime) +{ + PROGRESSDLG *pDlg; + pDlg = GET_DATA(hwnd); + if (!pDlg) return; + + DWORD tclose; + switch(evntId) + { + case TIMER_PROGRESS_ANIMATE_ID: + InvalidateLogo(hwnd, &pDlg->icon); + if (++pDlg->icon.step >= pDlg->icon.frames) + { + KillTimer(hwnd, evntId); + pDlg->icon.step = pDlg->icon.frames - 1; + } + break; + case TIMER_PROGRESS_DESTROY_ID: + tclose = pDlg->dwAutoClose; + if (dwTime >= tclose) + { + KillTimer(hwnd, evntId); + EndProgressDialog(hwnd); + } + else + { + wchar_t szText[128] = {0}; + tclose = (tclose - dwTime)/1000 + ((((tclose - dwTime)%1000) > 500) ? 1 : 0); + StringCchPrintfW(szText, sizeof(szText)/sizeof(wchar_t), L"%s (%d)", GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)), tclose); + SetDlgItemTextW(hwnd, IDCANCEL, szText); + } + break; + } +} + +static BOOL EndProgressDialog(HWND hwnd) +{ + PROGRESSDLG *pDlg; + pDlg = GET_DATA(hwnd); + if (!pDlg) return FALSE; + + if (MODAL_ACTIVE == pDlg->Modal) + { + pDlg->Modal = MODAL_DESTROY; + PostMessageW(hwnd, WM_NULL, 0, 0); + } + else + { + DestroyWindow(hwnd); + } + return TRUE; +} + +static INT_PTR ProgressDlg_OnDialogInit(HWND hwnd, HWND hwndFocus, LPARAM lParam) +{ + HWND hwndCtrl; + PROGRESSDLG *pDlg(NULL); + + pDlg = (PROGRESSDLG*)calloc(1, sizeof(PROGRESSDLG)); + if (pDlg) + { + pDlg->uState = STATE_INACTIVE; + if ((FAILED(InitializeProgressIcon(&pDlg->icon)) || !SetPropW(hwnd, PROP_PRGDLG, pDlg))) + { + free(pDlg); + pDlg = NULL; + DestroyWindow(hwnd); + return TRUE; + } + } + hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS); + if (hwndCtrl) + { + RECT rc; + EnableWindowTheme(hwndCtrl, FALSE); + SetWindowLongPtrW(hwndCtrl, GWL_EXSTYLE, GetWindowLongPtrW(hwndCtrl, GWL_EXSTYLE) & ~WS_EX_STATICEDGE); + GetWindowRect(hwndCtrl, &rc); + SetWindowPos(hwndCtrl, NULL, 0, 0, rc.right - rc.left, 3, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + SendMessageW(hwndCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessageW(hwndCtrl, PBM_SETPOS, 0, 0L); + SendMessageW(hwndCtrl, PBM_SETSTEP, 1, 0L); + SendMessageW(hwndCtrl, PBM_SETBARCOLOR, 0, (LPARAM)GetSysColor(COLOR_WINDOW)); + SendMessageW(hwndCtrl, PBM_SETBKCOLOR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); + } + hwndCtrl = GetDlgItem(hwnd, IDC_LBL_STATUS); + if(hwndCtrl) + { + if (!hFont) + { + HFONT hf; + LOGFONT lf; + + hf = (HFONT)SendMessageW(hwndCtrl, WM_GETFONT, 0, 0L); + if (hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + if (hf && GetObject(hf, sizeof(LOGFONT), &lf)) + { + HDC hdc = GetDC(hwndCtrl); + lf.lfHeight = (hdc) ? -MulDiv(7, GetDeviceCaps(hdc, LOGPIXELSY), 72) : -9; + lf.lfWeight = FW_THIN; + lf.lfQuality = PROOF_QUALITY; + StringCchCopy(lf.lfFaceName, sizeof(lf.lfFaceName)/sizeof(*lf.lfFaceName), L"Arial"); + hFont = CreateFontIndirect(&lf); + if (hdc) ReleaseDC(hwnd, hdc); + } + } + if (hFont) + { + SendMessageW(hwndCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE); + SendDlgItemMessageW(hwnd, IDC_LBL_REASON, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE); + fontRef++; + } + } + + if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT))) + { + DWORD exstyle = LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP; + SendMessageW(hwndCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, exstyle, exstyle); + LVCOLUMNW column; + column.mask = LVCF_WIDTH | LVCF_TEXT; + column.cx = 120; + column.pszText = L"Artist"; + SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column); + column.cx = 160; + column.pszText = L"Album"; + SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column); + column.cx = 40; + column.pszText = L"Language"; + SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column); + } + + return TRUE; +} + +static void ProgressDlg_OnDestroy(HWND hwnd) +{ + PROGRESSDLG *pDlg; + pDlg = GET_DATA(hwnd); + if (pDlg) + { + RemovePropW(hwnd, PROP_PRGDLG); + if (pDlg->icon.hbmp) DeleteObject(pDlg->icon.hbmp); + if (pDlg->Btn1Data) SysFreeString(pDlg->Btn1Data); + if (pDlg->AbortData) SysFreeString(pDlg->AbortData); + + free(pDlg); + pDlg = NULL; + } + + if (fontRef && 0 == --fontRef) + { + DeleteObject(hFont); + hFont = NULL; + } +} + +static void ProgressDlg_OnCommand(HWND hwnd, WORD ctrlId, WORD evntId, HWND hwndCtrl) +{ + PROGRESSDLG *pDlg; + + pDlg = GET_DATA(hwnd); + if (!pDlg) return; + + switch(ctrlId) + { + case IDCANCEL: + pDlg->rCode = S_FALSE; + switch(pDlg->uState) + { + case STATE_ACTIVE: + if (!pDlg->OnAbort) return; + SetWindowTextW(hwndCtrl, WASABI_API_LNGSTRINGW(IDS_ABORTING)); + EnableWindow(hwndCtrl, FALSE); + pDlg->uState = STATE_ABORTING; + pDlg->OnAbort(hwnd, pDlg->AbortData); + return; + case STATE_ABORTING: return; // don't do anything + } + ; + EndProgressDialog(hwnd); + break; + case IDC_BUTTON1: + if (BN_CLICKED == evntId) + { + if (pDlg->OnButton1) pDlg->OnButton1(hwnd, pDlg->Btn1Data); + } + break; + } +} + +static void ProgressDlg_OnErase(HWND hwnd, HDC hdc) +{ + PROGRESSDLG *pDlg; + + if (NULL != (pDlg = GET_DATA(hwnd))) + { + RECT rc; + SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y, + ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left), + ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top)); + if (RectVisible(hdc, &rc)) + { + if (AnimateProgressIcon(hdc, ICON_OFFSET_X, ICON_OFFSET_Y, &pDlg->icon)) + ExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); + } + } +} + +static void ProgressDlg_OnLButtonDown(HWND hwnd, DWORD wKey, POINTS pts) +{ + PROGRESSDLG *pDlg = GET_DATA(hwnd); + if (pDlg) + { + POINT pt; + RECT rc; + POINTSTOPOINT(pt, pts); + SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y, + ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left), + ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top)); + + if (PtInRect(&rc, pt)) SendMessageW(line.hMainWindow, WM_WA_IPC, (WPARAM)L"http://www.cddb.com/", IPC_OPEN_URL); + } +} + +static INT_PTR ProgressDlg_OnSetCursor(HWND hwnd, HWND hwndCursor, WORD htCode, WORD msgId) +{ + PROGRESSDLG *pDlg = GET_DATA(hwnd); + if (pDlg) + { + RECT rc; + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1); + SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y, + ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left), + ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top)); + if (PtInRect(&rc, pt)) return (NULL != SetCursor(LoadCursor(NULL, IDC_HAND))); + } + return FALSE; +} + +static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: return ProgressDlg_OnDialogInit(hwndDlg, (HWND)wParam, lParam); + case WM_DESTROY: ProgressDlg_OnDestroy(hwndDlg); break; + case WM_COMMAND: ProgressDlg_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + case WM_ERASEBKGND: ProgressDlg_OnErase(hwndDlg, (HDC)wParam); break; + case WM_LBUTTONDOWN: ProgressDlg_OnLButtonDown(hwndDlg, (DWORD)wParam, MAKEPOINTS(lParam)); break; + case WM_SETCURSOR: return ProgressDlg_OnSetCursor(hwndDlg, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)); + } + return 0; +} + +static BOOL CALLBACK EnumWnd_OnNextWindow(HWND hwnd, LPARAM lParam) +{ + ENUMWND_DATAPACK *pData = (ENUMWND_DATAPACK*)lParam; + if (!pData) return FALSE; + + if (!pData->found) + { + if (pData->host == hwnd) pData->found = TRUE; + // return TRUE; + } + ULONG_PTR style = GetWindowLongPtrW(hwnd, GWL_STYLE); + if (0 == (WS_CHILD & style) && + (0 == (FINDWND_ONLY_VISIBLE & pData->flags) || (WS_VISIBLE & style)) && + (0 == (FINDWND_ONLY_ENABLED & pData->flags) || 0 == (WS_DISABLED & style))) + { + HWND hwndOwner = GetWindow(hwnd, GW_OWNER); + if (pData->host == hwndOwner) + { + if (pData->index == pData->count) return FALSE; /// + pData->list[pData->index] = hwnd; + pData->index++; + } + } + return TRUE; +} + +BOOL FindAllOwnedWindows(HWND hwndHost, HWND *hwndList, INT cList, UINT flags) +{ + BOOL br; + ENUMWND_DATAPACK data; + + ZeroMemory(&data, sizeof(ENUMWND_DATAPACK)); + if (!hwndHost || !hwndList) return FALSE; + + data.host = hwndHost; + data.list = hwndList; + data.count = cList; + data.flags = flags; + data.list[0] = NULL; + br = EnumWindows(EnumWnd_OnNextWindow, (LPARAM)&data); + data.list[data.index] = NULL; + return br; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/cddbui.h b/Src/Plugins/Input/in_cdda/cddbui.h new file mode 100644 index 00000000..d4e0a60d --- /dev/null +++ b/Src/Plugins/Input/in_cdda/cddbui.h @@ -0,0 +1,46 @@ +#ifndef NULLSOFT_CDDB_UI_HEADER +#define NULLSOFT_CDDB_UI_HEADER + + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +#define AUTOCLOSE_NOW 0x00000000 +#define AUTOCLOSE_NEVER 0xFFFFFFFF + + +#define STATE_INACTIVE ((UINT)0) +#define STATE_ACTIVE ((UINT)1) +#define STATE_COMPLETED ((UINT)2) +#define STATE_ABORTING ((UINT)3) + +typedef void (CALLBACK *CDDBDLG_ONBTNCLICK)(HWND /*hwndDlg*/, BSTR /*bstrUser*/); // return TRUE to close dialog or FALSE to stay in STATE_ABORTING + +// all functions can accept String IDS and will resolve it using WASABI_API_LNGSTRINGW +HWND CddbProgressDlg_Create(HWND hwndParent, INT nCmdShow); +BOOL CddbProgressDlg_Initialize(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnAbort, BSTR bstrAbortUser); // +BOOL CddbProgressDlg_Completed(HWND hwnd, LPCWSTR pszResult, LPCWSTR pszReason, DWORD nAutoCloseDelay, HRESULT rCode); +BOOL CddbProgressDlg_SetStatus(HWND hwnd, LPCWSTR pszStatus, INT nPercentCompleted); +BOOL CddbProgressDlg_EnableAbortButton(HWND hwnd, BOOL bEnable); +BOOL CddbProgressDlg_ShowButton1(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnButton1, BSTR bstrUser); // set pszCaption = NULL and/or fnOnButton1 = NULL to hide it +UINT CddbProgressDlg_GetState(HWND hwnd); +BOOL CddbProgressDlg_SetUserData(HWND hwnd, HANDLE user); +HANDLE CddbProgressDlg_GetUserData(HWND hwnd); +BOOL CddbProgressDlg_ShowInTaskbar(HWND hwnd, BOOL bShow); +BOOL CddbProgressDlg_SetExtendedMode(HWND hwnd, BOOL bEnable); +BOOL CddbProgressDlg_AddRecord(HWND hwnd, LPCWSTR pszArtist, LPCWSTR pszTitle, LPCWSTR pszLanguage); +INT CddbProgressDlg_GetSelRecordIndex(HWND hwnd); +HRESULT CddbProgressDlg_DoModal(HWND hwnd, RECT *prc); // if prc != NULL will contain window rect before it closed +BOOL CddbProgressDlg_ExitModal(HWND hwnd, HRESULT rCode, BOOL bDestroy); /// exits modal loop without destroying window +BOOL CddbProgressDlg_IsModal(HWND hwnd); + + +#define FINDWND_ONLY_VISIBLE 0x01 +#define FINDWND_ONLY_ENABLED 0x02 + +BOOL FindAllOwnedWindows(HWND hwndHost, HWND *hwndList, INT cList, UINT flags); + +#endif //NULLSOFT_CDDB_UI_HEADER diff --git a/Src/Plugins/Input/in_cdda/discid.cpp b/Src/Plugins/Input/in_cdda/discid.cpp new file mode 100644 index 00000000..0ffbc06e --- /dev/null +++ b/Src/Plugins/Input/in_cdda/discid.cpp @@ -0,0 +1,168 @@ +#include "main.h" +#include "cddb.h" +#include <strsafe.h> + +/* +* cddb_sum +* Convert an integer to its text string representation, and +* compute its checksum. Used by cddb_discid to derive the +* disc ID. +* +* Args: +* n - The integer value. +* +* Return: +* The integer checksum. +*/ +int cddb_sum(int n) +{ + char buf[12], + *p; + int ret = 0; + + /* For backward compatibility this algorithm must not change */ + StringCchPrintfA(buf, 12, "%lu", n); + for (p = buf; *p != '\0'; p++) + ret += (*p - '0'); + + return (ret); +} + +/* +* cddb_discid +* Compute a magic disc ID based on the number of tracks, +* the length of each track, and a checksum of the string +* that represents the offset of each track. +* +* Return: +* The integer disc ID. +*/ + +unsigned long cddb_discid(unsigned char nTracks, unsigned int* pnMin, unsigned int* pnSec) +{ + int i, + t = 0, + n = 0; + + /* For backward compatibility this algorithm must not change */ + for (i = 0; i < (int) nTracks; i++) + { + n += cddb_sum((pnMin[i] * 60) + pnSec[i]); + + t += ((pnMin[i + 1] * 60) + pnSec[i + 1]) - ((pnMin[i] * 60) + pnSec[i]); + } + + return ((n % 0xff) << 24 | t << 8 | nTracks); +} + +// Functions used to generate the CDDB id + +void CDGetEndFrame(MCIDEVICEID wDeviceID, + DINFO* psDI, + unsigned int nOffset, + unsigned int* pnFrame, + unsigned int* pnMin, + unsigned int* pnSec) +{ + MCI_STATUS_PARMS sMCIStatus; + + sMCIStatus.dwItem = MCI_STATUS_LENGTH; + MCISendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, + (DWORD_PTR)(LPVOID) &sMCIStatus); +#ifdef _WIN64 + *pnFrame = (unsigned int)((double)sMCIStatus.dwReturn * (75.0 / 1000.0)); +#else + { + int nFrame; + static double tmp = 75.0 / 1000.0; + unsigned long a = sMCIStatus.dwReturn; + __asm + { + fld qword ptr tmp + fild dword ptr a + fmul + fistp dword ptr nFrame + } + *pnFrame = nFrame; + } +#endif + pnFrame[0] += 1 + nOffset; // Due to bug in MCI according to CDDB docs! + + psDI->nDiscLength = (pnFrame[0] / 75); + + *pnMin = pnFrame[0] / 75 / 60; + *pnSec = (pnFrame[0] / 75) % 60; +} + + +void CDGetAbsoluteTrackPos(MCIDEVICEID wDeviceID, + unsigned int nTrack, + unsigned int* pnFrame, + unsigned int* pnMin, + unsigned int* pnSec) +{ + MCI_STATUS_PARMS sMCIStatus; + + sMCIStatus.dwItem = MCI_STATUS_POSITION; + sMCIStatus.dwTrack = nTrack; + MCISendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, + (DWORD_PTR)(LPVOID) &sMCIStatus); +#ifdef _WIN64 + *pnFrame = (int)((double)sMCIStatus.dwReturn * (75.0 / 1000.0)); +#else + { + static double tmp = 75.0 / 1000.0; + unsigned long a = sMCIStatus.dwReturn; + __asm + { + fld qword ptr tmp + fild dword ptr a + fmul + fistp dword ptr a + } + *pnFrame = a; + } +#endif + + + *pnMin = *pnFrame / 75 / 60; + *pnSec = (*pnFrame / 75) % 60; +} + +int GetDiscID(MCIDEVICEID wDeviceID, DINFO* psDI) +{ + MCI_SET_PARMS sMCISet; + unsigned int nLoop; + unsigned int nMCITracks = CDGetTracks(wDeviceID); + unsigned int* pnMin = NULL; + unsigned int* pnSec = NULL; + + if (nMCITracks > 65535) return 1; + + if (nMCITracks > 128) nMCITracks = 128; + psDI->ntracks = nMCITracks; + + pnMin = (unsigned int*)GlobalAlloc(GPTR, (nMCITracks + 1) * 2 * sizeof(unsigned int)); + if (!pnMin) return 1; + + pnSec = pnMin + (nMCITracks + 1); + + sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS; + MCISendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + + for (nLoop = 0 ; nLoop < nMCITracks; nLoop ++) + CDGetAbsoluteTrackPos(wDeviceID, nLoop + 1, &psDI->pnFrames[nLoop], &pnMin[nLoop], &pnSec[nLoop]); + + CDGetEndFrame(wDeviceID, psDI, psDI->pnFrames[0], &psDI->pnFrames[nLoop], &pnMin[nLoop], &pnSec[nLoop]); + + psDI->CDDBID = cddb_discid((unsigned char)nMCITracks, pnMin, pnSec); + + sMCISet.dwTimeFormat = MCI_FORMAT_TMSF; + MCISendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet); + + if (pnMin) + { + GlobalFree(pnMin); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/grabwnd.cpp b/Src/Plugins/Input/in_cdda/grabwnd.cpp new file mode 100644 index 00000000..71341fcd --- /dev/null +++ b/Src/Plugins/Input/in_cdda/grabwnd.cpp @@ -0,0 +1,74 @@ +#include ".\grabwnd.h" +#include <strsafe.h> + + +#define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) +typedef struct _GRABDATA +{ + HHOOK hook; + HWND hwndParent; + WCHAR szClassName[256]; + WCHAR szTitle[256]; + GRABCB callback; + ULONG_PTR user; +} GRABDATA; + +static GRABDATA g_grab = {0, 0, }; + +static BOOL IsTargetClass(HWND hwnd, LPCWSTR plzClassName) +{ + wchar_t szName[256] = {0}; + return (0x00 == plzClassName[0] || + (GetClassNameW(hwnd, szName, sizeof(szName)/sizeof(wchar_t)) && + CSTR_EQUAL == CompareStringW(LCID_INVARIANT, NORM_IGNORECASE, szName, -1, plzClassName, -1))); +} + +static BOOL IsTargetTitle(HWND hwnd, LPCWSTR pszTitle) +{ + wchar_t szName[256] = {0}; + return (0x00 == pszTitle[0] || + (GetWindowTextW(hwnd, szName, sizeof(szName)/sizeof(wchar_t)) && + CSTR_EQUAL == CompareStringW(LCID_INVARIANT, NORM_IGNORECASE, szName, -1, pszTitle, -1))); +} +static LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam) +{ + if (HCBT_CREATEWND == code && IsTargetClass((HWND)wParam, g_grab.szClassName) && + IsTargetTitle((HWND)wParam, g_grab.szTitle) && + (!g_grab.hwndParent || ((CBT_CREATEWND*)lParam)->lpcs->hwndParent == g_grab.hwndParent)) + { + LRESULT result; + if (g_grab.callback) + { + g_grab.callback((HWND)wParam, ((CBT_CREATEWND*)lParam)->lpcs, &((CBT_CREATEWND*)lParam)->hwndInsertAfter, g_grab.user); + } + result = CallNextHookEx(g_grab.hook, code, wParam, lParam); + UnhookWindowsHookEx(g_grab.hook); + + + ZeroMemory(&g_grab, sizeof(GRABDATA)); + return result; + } + return CallNextHookEx(g_grab.hook, code, wParam, lParam); +} + +BOOL BeginGrabCreateWindow(LPCWSTR pszClassName, LPCWSTR pszTitle, HWND hwndParent, GRABCB callback, ULONG_PTR user) +{ + if (g_grab.hook || !callback) return FALSE; + if (pszClassName) StringCchCopyW(g_grab.szClassName, sizeof(g_grab.szClassName)/sizeof(wchar_t), pszClassName); + else g_grab.szClassName[0] = 0x00; + if (pszTitle) StringCchCopyW(g_grab.szTitle, sizeof(g_grab.szTitle)/sizeof(wchar_t), pszTitle); + else g_grab.szTitle[0] = 0x00; + g_grab.hwndParent = hwndParent; + g_grab.callback = callback; + g_grab.user = user; + + g_grab.hook = SetWindowsHookEx(WH_CBT, HookProc, NULL, GetCurrentThreadId()); + if (!g_grab.hook) ZeroMemory(&g_grab, sizeof(GRABDATA)); + + return (NULL != g_grab.hook); +} +void EndGrabCreateWindow(void) +{ + if (g_grab.hook) UnhookWindowsHookEx(g_grab.hook); + ZeroMemory(&g_grab, sizeof(GRABDATA)); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/grabwnd.h b/Src/Plugins/Input/in_cdda/grabwnd.h new file mode 100644 index 00000000..290f0b66 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/grabwnd.h @@ -0,0 +1,18 @@ +#ifndef NULLSOFT_GRAB_WINDOW_HEADER +#define NULLSOFT_GRAB_WINDOW_HEADER + + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +typedef void (CALLBACK *GRABCB)(HWND /*hwnd*/, CREATESTRUCT* /*lpcs*/, HWND* /*phwndInsertAfter*/, ULONG_PTR /*user*/); + +BOOL BeginGrabCreateWindow(LPCWSTR pszClassName, LPCWSTR pszTitle, HWND hwndParent, GRABCB callback, ULONG_PTR user); // you can skip fields that you don't need +void EndGrabCreateWindow(void); //always call it when you done to gurantee proper shutdown + + + +#endif //NULLSOFT_GRAB_WINDOW_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/in_cdda.rc b/Src/Plugins/Input/in_cdda/in_cdda.rc new file mode 100644 index 00000000..9965aae9 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/in_cdda.rc @@ -0,0 +1,366 @@ +// 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 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#if defined(APSTUDIO_INVOKED) || defined(ORIGINAL) +#if defined(APSTUDIO_INVOKED) +IDD_DIALOG1$(ORIGINAL) DIALOGEX 0, 0, 173, 146 +#else +IDD_DIALOG1 DIALOGEX 0, 0, 173, 146 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CD playback settings" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Digital Audio Extraction",IDC_STATIC,4,4,164,50 + CONTROL "Enable digital audio extraction if possible",IDC_DIGITAL, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,17,153,14 + CONTROL "Use Sonic engine when possible",IDC_VERITAS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,33,142,14 + GROUPBOX "Sampling (when not in DAE mode)",IDC_STATIC,4,57,164,67 + CONTROL "&Sample input from soundcard (for vis)\n(requires 44khz 16bit stereo capability)",IDC_SAMPLE, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,67,153,24 + LTEXT "(Note: be sure to set up your soundcard sampling input to the correct input source in order to have visualizations working)",IDC_STATIC,17,92,138,28 + GROUPBOX "MusicID",IDC_STATIC,233,12,82,84,NOT WS_VISIBLE + CONTROL "Use MusicID",IDC_CDDB,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,241,23,57,10 + LTEXT "The MusicID components are not installed. Please get Winamp Full or Pro to enable MusicID support.",IDC_CDDBNOTE,241,36,65,50,NOT WS_VISIBLE + CONTROL "",IDC_CDDBICON,"Static",SS_OWNERDRAW | SS_NOTIFY | SS_REALSIZEIMAGE | NOT WS_VISIBLE,247,39,15,13 + DEFPUSHBUTTON "OK",IDOK,64,129,50,13 + PUSHBUTTON "Cancel",IDCANCEL,118,129,50,13 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(IGNORE_API_GRACENOTE) +#if defined(APSTUDIO_INVOKED) +IDD_DIALOG2$(IGNORE_API_GRACENOTE) DIALOGEX 0, 0, 247, 68 +#else +IDD_DIALOG2 DIALOGEX 0, 0, 247, 68 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Retrieving CD information..." +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_CDDBICON,"Static",SS_OWNERDRAW | SS_NOTIFY,7,7,16,14 + LTEXT "MusicID brought to you by Gracenote",IDC_STATIC,67,8,167,9 + LTEXT "",IDC_STATUS,67,20,173,18,SS_SUNKEN + PUSHBUTTON "Abort",ID_ABORTBABY,67,41,50,14 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(DISABLED) +#if defined(APSTUDIO_INVOKED) +IDD_PREFS_CDRIP$(DISABLED) DIALOGEX 0, 0, 260, 226 +#else +IDD_PREFS_CDRIP DIALOGEX 0, 0, 260, 226 +#endif +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Ripping Speed",IDC_STATIC,4,3,256,70 + LTEXT "As Winamp rips your CDs to files, it must read the audio data from the CD. The unit of speed used is 1x, which means that the audio is extracted at the ",IDC_STATIC,11,14,244,16 + LTEXT "same rate as if you were listening to it. Choose what speed you would like to rip your CDs at (higher speeds require less time to rip):",IDC_STATIC,12,30,243,17 + LTEXT "Maximum speed at which Winamp should rip CDs:",IDC_STATIC,12,55,158,8 + COMBOBOX IDC_COMBO1,171,53,59,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Advanced Ripping Settings",IDC_STATIC,4,77,256,52 + CONTROL "Read audio data from CDs using bundled Sonic extraction engine",IDC_VERITAS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,90,221,10 + LTEXT "Disabling this option will instruct Winamp to attempt to rip via a third party ASPI driver or, if not available, using the native NT SCSI API.",IDC_STATIC,24,104,229,19 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(IGNORE_API_GRACENOTE) +#if defined(APSTUDIO_INVOKED) +IDD_CDDB_PROGRESS$(IGNORE_API_GRACENOTE) DIALOGEX 0, 0, 250, 66 +#else +IDD_CDDB_PROGRESS DIALOGEX 0, 0, 250, 66 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_NOIDLEMSG | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT +CAPTION "Retrieving CD information..." +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_LBL_CAPTION,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | SS_WORDELLIPSIS | WS_GROUP,70,8,172,10 + PUSHBUTTON "&Abort",IDCANCEL,182,43,60,15 + CONTROL "",IDC_LBL_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,70,17,172,8 + CONTROL "",IDC_PRG_STATUS,"msctls_progress32",PBS_SMOOTH | NOT WS_VISIBLE,70,25,111,6 + LTEXT "",IDC_LBL_REASON,70,25,111,8,NOT WS_VISIBLE + PUSHBUTTON "Button1",IDC_BUTTON1,113,43,60,15,NOT WS_VISIBLE + CONTROL "",IDC_LV_EXT,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,8,58,234,7 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(IGNORE_API_GRACENOTE) +#if defined(APSTUDIO_INVOKED) +IDD_MUSICID$(IGNORE_API_GRACENOTE) DIALOGEX 0, 0, 341, 164 +#else +IDD_MUSICID DIALOGEX 0, 0, 341, 164 +#endif +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Lookup",IDC_LOOKUP,231,146,50,14 + PUSHBUTTON "Submit",IDC_SUBMIT,175,146,50,14 + PUSHBUTTON "Edit",IDC_EDIT_GRACENOTE,119,146,50,14 + PUSHBUTTON "Use",IDC_USE,287,146,50,14 + LTEXT "Title",IDC_STATIC,7,9,40,14,SS_CENTERIMAGE,WS_EX_RIGHT + LTEXT "Album Artist",IDC_STATIC,7,27,40,14,SS_CENTERIMAGE,WS_EX_RIGHT + LTEXT "Disc",IDC_STATIC,7,44,40,14,SS_CENTERIMAGE,WS_EX_RIGHT + LTEXT "Year",IDC_STATIC,7,61,40,14,SS_CENTERIMAGE,WS_EX_RIGHT + LTEXT "Label",IDC_STATIC,7,78,40,14,SS_CENTERIMAGE,WS_EX_RIGHT + LTEXT "of",IDC_STATIC,83,44,8,14,SS_CENTERIMAGE + LTEXT "Primary Genre",IDC_STATIC,172,27,48,14,SS_CENTERIMAGE,WS_EX_RIGHT + GROUPBOX "Notes",IDC_STATIC,6,94,177,50 + GROUPBOX "Track List",IDC_STATIC,186,42,152,102 + LISTBOX IDC_TRACKLIST,191,52,142,87,LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_TITLE,55,9,281,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_ARTIST,55,27,110,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_DISC,55,44,24,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_DISCS,96,44,24,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_YEAR,55,61,65,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_LABEL,55,78,105,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_GENRE,227,27,109,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_NOTES,13,103,164,36,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "MusicID",IDC_STATIC,0,0,341,164 +END +#endif + +IDD_CDTEXT DIALOGEX 0, 0, 341, 164 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "CD Text",IDC_STATIC,0,0,341,164 + LTEXT "Artist:",IDC_STATIC,3,9,21,8 + EDITTEXT IDC_ARTIST,3,19,109,14,ES_AUTOHSCROLL + LTEXT "Album:",IDC_STATIC,116,9,23,8 + EDITTEXT IDC_ALBUM,116,19,109,14,ES_AUTOHSCROLL + LTEXT "Composer:",IDC_STATIC,228,9,36,8 + EDITTEXT IDC_COMPOSER,228,19,109,14,ES_AUTOHSCROLL + CONTROL "",IDC_TRACKS,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,4,36,333,106 + PUSHBUTTON "Lookup",IDC_LOOKUP,233,146,50,14 + PUSHBUTTON "Use",IDC_USE,287,146,50,14 +END + +#if defined(APSTUDIO_INVOKED) || defined(IGNORE_API_GRACENOTE) +#if defined(APSTUDIO_INVOKED) +IDD_DIALOG1$(IGNORE_API_GRACENOTE) DIALOGEX 0, 0, 173, 216 +#else +IDD_DIALOG1 DIALOGEX 0, 0, 173, 216 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CD playback settings" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Digital Audio Extraction",IDC_STATIC,4,4,164,50 + CONTROL "Enable digital audio extraction if possible",IDC_DIGITAL, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,17,153,14 + CONTROL "Use Sonic engine when possible",IDC_VERITAS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,33,142,14 + GROUPBOX "Sampling (when not in DAE mode)",IDC_STATIC,4,57,164,67 + CONTROL "&Sample input from soundcard (for vis)\n(requires 44khz 16bit stereo capability)",IDC_SAMPLE, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,11,67,153,24 + LTEXT "(Note: be sure to set up your soundcard sampling input to the correct input source in order to have visualizations working)",IDC_STATIC,17,92,138,28 + GROUPBOX "MusicID",IDC_STATIC,4,127,82,84 + CONTROL "Use MusicID",IDC_CDDB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,138,57,10 + LTEXT "The MusicID components are not installed. Please get Winamp Full or Pro to enable MusicID support.",IDC_CDDBNOTE,12,151,65,50,NOT WS_VISIBLE + CONTROL "",IDC_CDDBICON,"Static",SS_OWNERDRAW | SS_NOTIFY | SS_REALSIZEIMAGE,17,153,15,13 + DEFPUSHBUTTON "OK",IDOK,117,178,50,13 + PUSHBUTTON "Cancel",IDCANCEL,117,197,50,13 +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + "IDD_DIALOG1$(ORIGINAL)", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 159 + TOPMARGIN, 4 + BOTTOMMARGIN, 124 + END + + "IDD_DIALOG2$(IGNORE_API_GRACENOTE)", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 240 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + "IDD_CDDB_PROGRESS$(IGNORE_API_GRACENOTE)", DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 242 + VERTGUIDE, 70 + VERTGUIDE, 181 + TOPMARGIN, 8 + BOTTOMMARGIN, 58 + END + + "IDD_DIALOG1$(IGNORE_API_GRACENOTE)", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 159 + TOPMARGIN, 4 + BOTTOMMARGIN, 194 + END +END +#endif // APSTUDIO_INVOKED + + +#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""\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_NULLSOFT_CD_PLUGIN "Nullsoft CD Plug-in v%s" + 65535 "{87DCEEC2-1EC3-4c59-BED4-E8F42232C7D8}" +END + +STRINGTABLE +BEGIN + IDS_NULLSOFT_CD_PLUGIN_OLD "Nullsoft CD Plug-in" + IDS_QUERYING "Accessing Gracenote CDDB®..." + IDS_NOT_FOUND "No matches found" + IDS_PROCESSING "Processing..." + IDS_CDDB_NOT_INSTALLED "MusicID not installed" + IDS_SUCCESS "Success" + IDS_CLOSE "&Close" + IDS_INITIALIZING "initializing..." + IDS_ABORTING "Aborting..." + IDS_UNLIMITED "Unlimited" + IDS_PURCHASE_WINAMP_PRO_PROMPT + "In order to use more than 8x extraction, you must purchase Winamp Pro.\nWould you like information on purchasing Winamp Pro?" + IDS_WINAMP_PRO_FEATURE "Winamp Pro Feature" + IDS_ARTIST "Artist" + IDS_TITLE "Title" + IDS_ALBUM_ARTIST "Album Artist" +END + +STRINGTABLE +BEGIN + IDS_NULLSOFT_CD_PLUGIN2 "Nullsoft CD Plug-in" + IDS_CD_CURRENTLY_IN_USE "CD Drive currently in use" + IDS_DRIVE_IN_USE "Drive in use" + IDS_DRIVE_NOT_FOUND "Drive not found" + IDS_CD_NOT_PRESENT "CD not present" + IDS_CANNOT_PLAY_TRACK "Cannot play track" + IDS_CDDA_AUDIO_TRACKS "CDDA Audio Tracks (*.CDA)" + IDS_RIPPING "Ripping" + IDS_TRACK_X "Track %i" + IDS_UNKNOWN "unknown" + IDS_UNKNOWN_ARTIST "Unknown Artist" + IDS_FAMILY_STRING "CD Audio Track shortcut" + IDS_ABOUT_TEXT "%s\nCopyright © 1997-2023 Winamp SA\n\nBuild date: %s\n\nHow to use:\n For CD audio, open cda://<cd drive letter>\n (or use the command in winamp)\n\n You can also play individual CD tracks using\n cda://<letter>,<number>\n\n" +END + +STRINGTABLE +BEGIN + IDS_ABORT "&Abort" + IDS_CDDB_PROGRESS_CONNECTING "connecting..." + IDS_CDDB_PROGRESS_SENDING "sending..." +END + +STRINGTABLE +BEGIN + IDS_CDDB_PROGRESS_RECEIVING "receiving..." + IDS_CDDB_PROGRESS_WAITING "waiting..." + IDS_CDDB_PROGRESS_CANCELLED "cancelled" + IDS_CDDB_PROGRESS_COMPLETED "completed" + IDS_CDDB_E_BUSY "Service busy" + IDS_CDDB_E_FAIL "Unknown error" + IDS_CDDB_E_BADTOC "Bad disc data" + IDS_REASON "Reason: " + IDS_FOUND_MULTIPLE "Multiple matches were found online for this CD." + IDS_RESOLVING "resolving" + IDS_SUBMITTINGDISC "Submitting disc info..." + IDS_FOUND_EXACT "Exact match found" + IDS_SUBMITNEW "Submit &New" + IDS_SUBMITDISC_TITLE "Submitting Disc Information" + IDS_SUBMITTING "Submitting Disc Information to Gracenote CDDB®..." + IDS_OPENING "opening dialog..." +END + +STRINGTABLE +BEGIN + IDS_FUZZYDISC_TITLE "Multiple Match Results" + IDS_ACCEPT "&Accept" + IDS_LOOKUPRESULT_TITLE "CD Lookup Results" + IDS_SUBMIT_OFFER "Do you want to submit new?" + IDS_CDDB_E_ABORT "Aborted by user" + IDS_CDTEXT "CD Text" + IDS_TRACK "Track" + IDS_COMPOSER "Composer" +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/Input/in_cdda/in_cdda.sln b/Src/Plugins/Input/in_cdda/in_cdda.sln new file mode 100644 index 00000000..9b43b7b0 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/in_cdda.sln @@ -0,0 +1,86 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29613.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_cdda", "in_cdda.vcxproj", "{F514A693-F5AA-4A7F-B091-81A0901C2EF6}" + ProjectSection(ProjectDependencies) = postProject + {57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27} + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} + {E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D} + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "..\nde\nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}" +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 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Debug|Win32.ActiveCfg = Debug|Win32 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Debug|Win32.Build.0 = Debug|Win32 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Debug|x64.ActiveCfg = Debug|x64 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Debug|x64.Build.0 = Debug|x64 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Release|Win32.ActiveCfg = Release|Win32 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Release|Win32.Build.0 = Release|Win32 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Release|x64.ActiveCfg = Release|x64 + {F514A693-F5AA-4A7F-B091-81A0901C2EF6}.Release|x64.Build.0 = Release|x64 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64 + {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64 + {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64 + {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64 + {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64 + {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {41AF61AB-53FC-4AC8-A9FB-234866A1F3AE} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Input/in_cdda/in_cdda.vcxproj b/Src/Plugins/Input/in_cdda/in_cdda.vcxproj new file mode 100644 index 00000000..88e44deb --- /dev/null +++ b/Src/Plugins/Input/in_cdda/in_cdda.vcxproj @@ -0,0 +1,393 @@ +<?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>{F514A693-F5AA-4A7F-B091-81A0901C2EF6}</ProjectGuid> + <RootNamespace>in_cdda</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> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </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;..\..\..\replicant;..;..\..\..\;..\..\..\external_dependencies\libdiscid-0.6.2\include;..\..\..\gracenote;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;IN_CDDA2_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x601;IGNORE_API_GRACENOTE;IGNORE_PRIMO;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4005;4065;4099;4133;4273;4700;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <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\ +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> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\external_dependencies\libdiscid-0.6.2\include;..\..\..\gracenote;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;IN_CDDA2_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x601;IGNORE_API_GRACENOTE;IGNORE_PRIMO;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4005;4065;4099;4267;4244;4273;4302;4311;4700;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </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> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;..\..\..\libdiscid\include;..\..\..\gracenote;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_CDDA2_EXPORTS;UNICODE_INPUT_PLUGIN;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;IGNORE_API_GRACENOTE;IGNORE_PRIMO;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4005;4065;4099;4700;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>winmm.dll;nde.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <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> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;..\..\..\libdiscid\include;..\..\..\gracenote;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;IN_CDDA2_EXPORTS;UNICODE_INPUT_PLUGIN;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;IGNORE_API_GRACENOTE;IGNORE_PRIMO;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4005;4065;4099;4267;4244;4273;4302;4311;4700;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>odbc32.lib;odbccp32.lib;winmm.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>winmm.dll;nde.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <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> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\nde\nde.vcxproj"> + <Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project> + <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies> + <ReferenceOutputAssembly>true</ReferenceOutputAssembly> + </ProjectReference> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <CustomBuild Include="..\..\..\libdiscid\include\discid\discid.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\include\discid\discid_private.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\base64.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\ntddcdrm.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\sha1.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <ClInclude Include="..\..\..\Winamp\strutil.h" /> + <ClInclude Include="api__in_cdda.h" /> + <ClInclude Include="AUDIO.H" /> + <ClInclude Include="CDDB.H" /> + <CustomBuild Include="cddbevnt.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <ClInclude Include="CDDBInterface.h" /> + <CustomBuild Include="cddbui.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + <ClInclude Include="CDPlay.h" /> + <ClInclude Include="DAEPlay.h" /> + <ClInclude Include="FuncTypedefs.h" /> + <ClInclude Include="grabwnd.h" /> + <ClInclude Include="MAIN.H" /> + <ClInclude Include="MCIPlay.h" /> + <ClInclude Include="PlayStatus.h" /> + <ClInclude Include="resource.h" /> + <CustomBuild Include="WindacPlay.h" /> + <CustomBuild Include="windac\Aspifunc.h" /> + <CustomBuild Include="windac\Dac32.h" /> + <CustomBuild Include="workorder.h"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </CustomBuild> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\base64.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\disc.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\disc_win32.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\sha1.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\toc.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\..\..\nu\listview.cpp" /> + <ClCompile Include="..\..\..\Winamp\strutil.cpp" /> + <ClCompile Include="AUDIO.Cpp" /> + <ClCompile Include="CDDB.Cpp" /> + <ClCompile Include="cddbevnt.cpp" /> + <ClCompile Include="cddbui.cpp" /> + <ClCompile Include="CDText.cpp" /> + <ClCompile Include="CONFIG.Cpp" /> + <ClCompile Include="DAEPlay.cpp" /> + <ClCompile Include="DB.Cpp" /> + <ClCompile Include="discid.cpp" /> + <ClCompile Include="EditCDInfo.cpp" /> + <ClCompile Include="ExtendedFileInfo.cpp" /> + <ClCompile Include="ExtendedRead.cpp" /> + <ClCompile Include="grabwnd.cpp" /> + <ClCompile Include="Main.cpp" /> + <ClCompile Include="MCI.Cpp" /> + <ClCompile Include="nde_cd.cpp" /> + <ClCompile Include="PlayStatus.cpp" /> + <ClCompile Include="scsi_id.cpp" /> + <ClCompile Include="util.cpp" /> + <ClCompile Include="WindacPlay.cpp" /> + <ClCompile Include="windac\Aspifunc.cpp" /> + <ClCompile Include="windac\Dac32.cpp" /> + <ClCompile Include="windac\NTScsi.cpp" /> + <ClCompile Include="workorder.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_cdda.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/in_cdda.vcxproj.filters b/Src/Plugins/Input/in_cdda/in_cdda.vcxproj.filters new file mode 100644 index 00000000..fcfa3b74 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/in_cdda.vcxproj.filters @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="AUDIO.Cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="windac\Aspifunc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CDDB.Cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="cddbevnt.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="cddbui.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CDText.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CONFIG.Cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="windac\Dac32.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DAEPlay.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DB.Cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="discid.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="EditCDInfo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ExtendedFileInfo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ExtendedRead.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="grabwnd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MCI.Cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nde_cd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="windac\NTScsi.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PlayStatus.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="scsi_id.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="WindacPlay.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="workorder.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\base64.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\disc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\disc_win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\listview.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\sha1.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\Winamp\strutil.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\external_dependencies\libdiscid-0.6.2\src\toc.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__in_cdda.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="AUDIO.H"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CDDB.H"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CDDBInterface.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CDPlay.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="DAEPlay.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="FuncTypedefs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="grabwnd.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="MAIN.H"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="MCIPlay.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="PlayStatus.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\Winamp\strutil.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <CustomBuild Include="windac\Aspifunc.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="cddbevnt.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="cddbui.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="windac\Dac32.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="WindacPlay.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="workorder.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\base64.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\include\discid\discid.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\include\discid\discid_private.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\ntddcdrm.h"> + <Filter>Header Files</Filter> + </CustomBuild> + <CustomBuild Include="..\..\..\libdiscid\src\sha1.h"> + <Filter>Header Files</Filter> + </CustomBuild> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{8d59d863-b543-4d13-b6a7-55382eadffe0}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{ab3794f1-f2e8-465d-abc5-6fcf5bef0413}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{388bf86e-3bd7-4945-8833-ebecc85f04f8}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_cdda.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/inst.nsi b/Src/Plugins/Input/in_cdda/inst.nsi new file mode 100644 index 00000000..4354a247 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/inst.nsi @@ -0,0 +1,78 @@ +Name "CDDB2 test, beta 1" + +; The file to write +OutFile "cddb2.exe" + +InstallDir $PROGRAMFILES\Winamp +InstallDirRegKey HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\Winamp" \ + "UninstallString" + +; The text to prompt the user to enter a directory +DirText "Please select your Winamp path below (you will be able to proceed when Winamp is detected):" +DirShow hide + +; automatically close the installer when done. +AutoCloseWindow true +; hide the "show details" box +ShowInstDetails nevershow + +BGGradient 000000 308030 FFFFFF +InstallColors FF8080 000000 +InstProgressFlags smooth colored + +Function .onInit + MessageBox MB_YESNO|MB_ICONQUESTION "Install CDDB2 update test?" IDYES update + MessageBox MB_OK|MB_ICONINFORMATION "Install aborted." + Abort + update: +FunctionEnd + +Function .onVerifyInstDir + IfFileExists $INSTDIR\Winamp.exe Good + Abort + Good: +FunctionEnd + +Function CloseWinamp + Push $0 + loop: + FindWindow $0 "Winamp v1.x" + IntCmp $0 0 done + SendMessage $0 16 0 0 + StrCpy $9 "yes" + Sleep 100 + Goto loop + done: + Pop $0 +FunctionEnd + + +Section "ThisNameIsIgnoredSoWhyBother?" + StrCpy $9 "no" + Call CloseWinamp + SetOutPath $INSTDIR + File "C:\program files\winamp\winamp.exe" + SetOutPath $INSTDIR\Plugins + + UnRegDll $OUTDIR\cddbcontrolwinamp.dll + UnRegDll $OUTDIR\cddbuiwinamp.dll + File "C:\program files\winamp\plugins\in_cdda.dll" + File "C:\program files\winamp\plugins\in_mp3.dll" + File "cddbcontrolwinamp.dll" + File "cddbuiwinamp.dll" + RegDll $OUTDIR\cddbcontrolwinamp.dll + RegDll $OUTDIR\cddbuiwinamp.dll + + DetailPrint Completed. +SectionEnd + + +Function .onInstSuccess + MessageBox MB_OK|MB_ICONINFORMATION "Update installed." + StrCmp $9 "no" nope + Exec '"$INSTDIR\Winamp.exe"' + nope: +FunctionEnd + +; eof diff --git a/Src/Plugins/Input/in_cdda/nde_cd.cpp b/Src/Plugins/Input/in_cdda/nde_cd.cpp new file mode 100644 index 00000000..2b20e36f --- /dev/null +++ b/Src/Plugins/Input/in_cdda/nde_cd.cpp @@ -0,0 +1,720 @@ +#include "../nde/nde_c.h" +#include "main.h" +#include <shlwapi.h> +#include "../nu/AutoLock.h" +#include "../nu/AutoWide.h" +#include "cddbinterface.h" +#include "cddb.h" + +#include "api__in_cdda.h" +#include <api/service/waservicefactory.h> +#include <atlbase.h> +#include <strsafe.h> + +using namespace Nullsoft::Utility; +static nde_database_t discDB=0; +static nde_table_t discTable=0, trackTable=0; +static Nullsoft::Utility::LockGuard dbcs; +static int g_dirty; + +enum +{ + NDE_CD_SUCCESS=0, + NDE_CD_FAILURE=1, +}; + +enum +{ + DISCTABLE_ID_DISCID = 0, + DISCTABLE_ID_ALBUM=1, + DISCTABLE_ID_ARTIST=2, + DISCTABLE_ID_TUID=3, + DISCTABLE_ID_YEAR=4, + DISCTABLE_ID_GENRE=5, + DISCTABLE_ID_COMMENT=6, + DISCTABLE_ID_DISC=7, + DISCTABLE_ID_COMPOSER=8, + DISCTABLE_ID_PUBLISHER=9, + DISCTABLE_ID_CONDUCTOR=10, + DISCTABLE_ID_REMIXING=10, +}; + +enum +{ + TRACKTABLE_ID_DISCID = 0, + TRACKTABLE_ID_TRACK = 1, + TRACKTABLE_ID_ARTIST=2, + TRACKTABLE_ID_TITLE=3, + TRACKTABLE_ID_TAGID=4, + TRACKTABLE_ID_COMPOSER=5, + TRACKTABLE_ID_CONDUCTOR=6, + TRACKTABLE_ID_EXTENDED_DATA=7, + TRACKTABLE_ID_REMIXING=8, + TRACKTABLE_ID_ISRC=9, +}; + +static void CreateDiscFields(nde_table_t table) +{ + // create defaults + NDE_Table_NewColumnW(table, DISCTABLE_ID_DISCID, L"discid", FIELD_INTEGER); + NDE_Table_NewColumnW(table, DISCTABLE_ID_ALBUM, L"title", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_ARTIST, L"artist", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_TUID, L"tuid", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_YEAR, L"year", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_GENRE, L"genre", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_COMMENT, L"comment", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_DISC, L"disc", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_COMPOSER, L"composer", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_PUBLISHER, L"publisher", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_CONDUCTOR, L"conductor", FIELD_STRING); + NDE_Table_NewColumnW(table, DISCTABLE_ID_REMIXING, L"remixing", FIELD_STRING); + + NDE_Table_PostColumns(table); + NDE_Table_AddIndexByIDW(table, DISCTABLE_ID_DISCID, L"discid"); +} + +static void CreateTrackFields(nde_table_t table) +{ + // create defaults + NDE_Table_NewColumnW(table, TRACKTABLE_ID_DISCID, L"discid", FIELD_INTEGER); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_TRACK, L"track", FIELD_INTEGER); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_ARTIST, L"artist", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_TITLE, L"title", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_TAGID, L"tagid", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_COMPOSER, L"composer", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_CONDUCTOR, L"conductor", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_EXTENDED_DATA, L"extendeddata", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_REMIXING, L"remixing", FIELD_STRING); + NDE_Table_NewColumnW(table, TRACKTABLE_ID_ISRC, L"ISRC", FIELD_STRING); + + NDE_Table_PostColumns(table); + NDE_Table_AddIndexByIDW(table, TRACKTABLE_ID_DISCID, L"discid"); + NDE_Table_AddIndexByIDW(table, TRACKTABLE_ID_TRACK, L"track"); +} + +static int OpenDiscDatabase() +{ + AutoLock lock(dbcs); + if (!discDB) + { + discDB = NDE_CreateDatabase(); + } + return NDE_CD_SUCCESS; +} + +static int OpenDiscTable() +{ + AutoLock lock(dbcs); + int ret = OpenDiscDatabase(); + if (ret != NDE_CD_SUCCESS) + { + return ret; + } + + if (!discTable) + { + const wchar_t *inidir = WASABI_API_APP->path_getUserSettingsPath(); + wchar_t discTablePath[MAX_PATH] = {0}, discIndexPath[MAX_PATH] = {0}; + PathCombineW(discTablePath, inidir, L"plugins"); + PathAppendW(discTablePath, L"cddiscs.dat"); + PathCombineW(discIndexPath, inidir, L"plugins"); + PathAppendW(discIndexPath, L"cddiscs.idx"); + discTable = NDE_Database_OpenTable(discDB, discTablePath, discIndexPath, NDE_OPEN_ALWAYS, NDE_CACHE); + if (discTable) + { + CreateDiscFields(discTable); + } + } + return (discTable ? NDE_CD_SUCCESS : NDE_CD_FAILURE); +} + +static int OpenTrackTable() +{ + AutoLock lock(dbcs); + int ret = OpenDiscDatabase(); + if (ret != NDE_CD_SUCCESS) + { + return ret; + } + + if (!trackTable) + { + const wchar_t *inidir = WASABI_API_APP->path_getUserSettingsPath(); + wchar_t trackTablePath[MAX_PATH] = {0}, trackIndexPath[MAX_PATH] = {0}; + PathCombineW(trackTablePath, inidir, L"plugins"); + PathAppendW(trackTablePath, L"cdtracks.dat"); + PathCombineW(trackIndexPath, inidir, L"plugins"); + PathAppendW(trackIndexPath, L"cdtracks.idx"); + trackTable = NDE_Database_OpenTable(discDB, trackTablePath, trackIndexPath, NDE_OPEN_ALWAYS, NDE_CACHE); + if (trackTable) + { + CreateTrackFields(trackTable); + } + } + return (trackTable ? NDE_CD_SUCCESS : NDE_CD_FAILURE); +} + +void CloseTables() +{ + if (discTable) + { + if (g_dirty & 1) NDE_Table_Sync(discTable); + NDE_Database_CloseTable(discDB, discTable); + discTable = 0; + } + + if (trackTable) + { + if (g_dirty & 2) NDE_Table_Sync(trackTable); + NDE_Database_CloseTable(discDB, trackTable); + trackTable = 0; + } + + if (discDB) + { + NDE_DestroyDatabase(discDB); + discDB = 0; + } + g_dirty = 0; +} + +static void db_setFieldInt(nde_scanner_t s, unsigned char id, int data) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (!f) f = NDE_Scanner_NewFieldByID(s, id); + NDE_IntegerField_SetValue(f, data); +} + +static void db_setFieldString(nde_scanner_t s, unsigned char id, const wchar_t *data) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (!f) f = NDE_Scanner_NewFieldByID(s, id); + NDE_StringField_SetString(f, data); +} + +static void db_removeField(nde_scanner_t s, unsigned char id) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (f) + { + NDE_Scanner_DeleteField(s, f); + } +} + +static int db_getFieldInt(nde_scanner_t s, unsigned char id, int defaultVal) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (f) + return NDE_IntegerField_GetValue(f); + else + return defaultVal; +} + +static wchar_t *db_getFieldString(nde_scanner_t s, unsigned char id) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (f) + return NDE_StringField_GetString(f); + else + return 0; +} + +static void SeekToDisc(nde_scanner_t s, unsigned int cddb_id) +{ + if (!NDE_Scanner_LocateInteger(s, DISCTABLE_ID_DISCID, FIRST_RECORD, cddb_id)) + { + NDE_Scanner_New(s); + db_setFieldInt(s,DISCTABLE_ID_DISCID,cddb_id); + } +} + +static void SeekToTrack(nde_scanner_t s, unsigned int cddb_id, int track) +{ + nde_field_t f_id = NDE_IntegerField_Create(cddb_id); + NDE_Scanner_AddFilterByID(s, TRACKTABLE_ID_DISCID, f_id, FILTER_EQUALS); + if (!NDE_Scanner_LocateInteger(s, TRACKTABLE_ID_TRACK, FIRST_RECORD, track)) + { + NDE_Scanner_New(s); + db_setFieldInt(s,TRACKTABLE_ID_DISCID,cddb_id); + db_setFieldInt(s,TRACKTABLE_ID_TRACK,track); + } + NDE_Scanner_RemoveFilters(s); +} + +#ifndef IGNORE_API_GRACENOTE +void StoreDisc(unsigned int cddb_id, ICddbDiscPtr pDisc) +{ + AutoLock lock(dbcs); + CComBSTR str, disc_artist, disc_composer, disc_conductor, disc_remixing; + BSTR composerRole=L"3", conductorRole=L"12", remixingRole=L"147"; + + /* + for (int i=100;i<300;i++) + { + wchar_t id[256] = {0}; + _itow(i, id, 10); + ICddbRolePtr role; + pCDDBControl->GetRoleInfo(id, &role); + if (role) + { + BSTR name, description; + role->get_Name(&name); + role->get_Description(&description); + wchar_t str[4096] = {0}; + wsprintf(str, L"ID: %s\r\nName: %s\r\nDescription: %s\r\n", id, name, description); + MessageBoxW(NULL, str, L"CDDB Role", MB_OK); + } + } + */ + OpenDiscTable(); + nde_scanner_t s = NDE_Table_CreateScanner(discTable); + SeekToDisc(s, cddb_id); + + ICddbDisc2Ptr pDisc2; + pDisc->QueryInterface(&pDisc2); + + ICddbDisc2_5Ptr pDisc2_5; + pDisc->QueryInterface(&pDisc2_5); + + if (GetRole(pDisc, conductorRole, &disc_conductor) && disc_conductor && disc_conductor.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_CONDUCTOR, disc_conductor); + else + db_removeField(s, DISCTABLE_ID_CONDUCTOR); + + if (GetRole(pDisc, composerRole, &disc_composer) && disc_composer && disc_composer.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_COMPOSER, disc_composer); + else + db_removeField(s, DISCTABLE_ID_COMPOSER); + + if (GetRole(pDisc, remixingRole, &disc_remixing) && disc_remixing && disc_remixing.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_REMIXING, disc_remixing); + else + db_removeField(s, DISCTABLE_ID_REMIXING); + + if (SUCCEEDED(pDisc->get_Artist(&disc_artist)) && disc_artist && disc_artist.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_ARTIST, disc_artist); + else + db_removeField(s, DISCTABLE_ID_ARTIST); + + if (SUCCEEDED(pDisc->get_Year(&str)) && str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_YEAR, str); + else + db_removeField(s, DISCTABLE_ID_YEAR); + + if (pDisc2_5 == NULL + || (FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(3, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(2, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(1, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimary(&str))) + ) + { + pDisc->get_GenreId(&str); + ICddbGenre *poop = 0; + if (SUCCEEDED(pCDDBControl->GetGenreInfo(str, &poop)) && poop) + { + poop->get_Name(&str); + poop->Release(); + } + else + str.Empty(); + } + + if (str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_GENRE, str); + else + db_removeField(s, DISCTABLE_ID_GENRE); + + if (SUCCEEDED(pDisc->get_Title(&str)) && str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_ALBUM, str); + else + db_removeField(s, DISCTABLE_ID_ALBUM); + + if (SUCCEEDED(pDisc->get_TitleUId(&str)) && str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_TUID, str); + else + db_removeField(s, DISCTABLE_ID_TUID); + + if (SUCCEEDED(pDisc->get_Label(&str)) && str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_PUBLISHER, str); + else + db_removeField(s, DISCTABLE_ID_PUBLISHER); + + if (SUCCEEDED(pDisc->get_Notes(&str)) && str && str.m_str[0]) + db_setFieldString(s, DISCTABLE_ID_COMMENT, str); + else + db_removeField(s, DISCTABLE_ID_COMMENT); + + /* + long val; + pDisc->get_Compilation(&val); + ps->compilation = !!val; + */ + int numdiscs = 0; + if (SUCCEEDED(pDisc->get_TotalInSet(&str)) && str && str.m_str[0]) + numdiscs = _wtoi(str.m_str); + int discnum =0; + if (SUCCEEDED(pDisc->get_NumberInSet(&str)) && str && str.m_str[0]) + discnum = _wtoi(str.m_str); + + if (discnum) + { + wchar_t disc_temp[64] = {0}; + if (numdiscs) + StringCchPrintfW(disc_temp, 64, L"%d/%d", discnum, numdiscs); + else + StringCchPrintfW(disc_temp, 64, L"%d", discnum); + db_setFieldString(s, DISCTABLE_ID_DISC, disc_temp); + } + else + db_removeField(s, DISCTABLE_ID_DISC); + + long tracks=0; + if (FAILED(pDisc->get_NumTracks(&tracks))) + tracks=0; + + NDE_Scanner_Post(s); + NDE_Table_DestroyScanner(discTable, s); + OpenTrackTable(); + s = NDE_Table_CreateScanner(trackTable); + for (int x = 0; x < tracks; x ++) + { + ICddbTrack *t=0; + ICddbTrack2_5Ptr track2_5; + if (FAILED(pDisc->GetTrack(x + 1, &t)) || !t) + break; + + SeekToTrack(s, cddb_id, x+1); + + // don't store if it's the same as the disc artist + if (SUCCEEDED(t->get_Artist(&str)) && str && str.m_str[0] && (!disc_artist || !disc_artist.m_str[0] || wcscmp(str.m_str, disc_artist.m_str))) + db_setFieldString(s, TRACKTABLE_ID_ARTIST, str); + else + db_removeField(s, TRACKTABLE_ID_ARTIST); + + if (SUCCEEDED(t->get_Title(&str)) && str && str.m_str[0]) + db_setFieldString(s, TRACKTABLE_ID_TITLE, str); + else + db_removeField(s, TRACKTABLE_ID_TITLE); + + if (SUCCEEDED(t->get_ISRC(&str)) && str && str.m_str[0]) + db_setFieldString(s, TRACKTABLE_ID_ISRC, str); + else + db_removeField(s, TRACKTABLE_ID_ISRC); + + if (SUCCEEDED(pCDDBControl->GetDiscTagId(pDisc, x + 1, &str)) && str && str.m_str[0]) + db_setFieldString(s, TRACKTABLE_ID_TAGID, str); + else + db_removeField(s, TRACKTABLE_ID_TAGID); + + // don't store if it's the same as the disc conductor + if (GetRole(t, conductorRole, &str) && str && str.m_str[0] && (!disc_conductor || !disc_conductor.m_str[0] || wcscmp(str.m_str, disc_conductor.m_str))) + db_setFieldString(s, TRACKTABLE_ID_CONDUCTOR, str); + else + db_removeField(s, TRACKTABLE_ID_CONDUCTOR); + + // don't store if it's the same as the disc composer + if (GetRole(t, composerRole, &str) && str && str.m_str[0] && (!disc_composer || !disc_composer.m_str[0] || wcscmp(str.m_str, disc_composer.m_str))) + db_setFieldString(s, TRACKTABLE_ID_COMPOSER, str); + else + db_removeField(s, TRACKTABLE_ID_COMPOSER); + + // don't store if it's the same as the disc remixer + if (GetRole(t, remixingRole, &str) && str && str.m_str[0] && (!disc_remixing || !disc_remixing.m_str[0] || wcscmp(str.m_str, disc_remixing.m_str))) + db_setFieldString(s, TRACKTABLE_ID_REMIXING, str); + else + db_removeField(s, TRACKTABLE_ID_REMIXING); + + t->QueryInterface(&track2_5); + + if (track2_5 != NULL && (SUCCEEDED(track2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0]) // try track first + || (pDisc2_5 != NULL && SUCCEEDED(pDisc2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0])) // then disc + db_setFieldString(s, TRACKTABLE_ID_EXTENDED_DATA, str); + else + db_removeField(s, TRACKTABLE_ID_EXTENDED_DATA); + + NDE_Scanner_Post(s); + t->Release(); + } + + NDE_Table_DestroyScanner(trackTable, s); + NDE_Table_Sync(trackTable); + NDE_Table_Sync(discTable); +} +#endif + +static void CDText_Process(unsigned int cddb_id, const char *title, const char *performers, const char *composers, int codepage) +{ + AutoLock lock(dbcs); + OpenDiscTable(); + nde_scanner_t s = NDE_Table_CreateScanner(discTable); + SeekToDisc(s, cddb_id); + + char thisTitle[1024] = {0}; + + const char *titles = title; + // first, get disc title + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + + db_setFieldString(s, DISCTABLE_ID_ALBUM, AutoWide(thisTitle, codepage)); + + // now get track titles + OpenTrackTable(); + nde_scanner_t tableScanner = NDE_Table_CreateScanner(trackTable); + int trackNum = 1; + while (titles && *titles) + { + SeekToTrack(tableScanner, cddb_id, trackNum++); + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + db_setFieldString(tableScanner, TRACKTABLE_ID_TITLE, AutoWide(thisTitle, codepage)); + NDE_Scanner_Post(tableScanner); + } + + titles = performers; + // now get disc artist + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + db_setFieldString(s, DISCTABLE_ID_ARTIST, AutoWide(thisTitle, codepage)); + + // now get track artists + trackNum = 1; + while (titles && *titles) + { + SeekToTrack(tableScanner, cddb_id, trackNum++); + + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + db_setFieldString(tableScanner, TRACKTABLE_ID_ARTIST, AutoWide(thisTitle, codepage)); + NDE_Scanner_Post(tableScanner); + } + + titles = composers; + // now get disc composer + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + db_setFieldString(s, DISCTABLE_ID_COMPOSER, AutoWide(thisTitle, codepage)); + + // now get track composers + trackNum = 1; + while (titles && *titles) + { + SeekToTrack(tableScanner, cddb_id, trackNum++); + + thisTitle[0] = 0; + titles = ReadLine(titles, thisTitle, 1024, codepage); + db_setFieldString(tableScanner, TRACKTABLE_ID_COMPOSER, AutoWide(thisTitle, codepage)); + NDE_Scanner_Post(tableScanner); + } + + NDE_Table_DestroyScanner(trackTable, tableScanner); + NDE_Scanner_Post(s); + NDE_Table_DestroyScanner(discTable, s); +} + +/* returns true if there was CD text */ +bool StoreCDText(unsigned int cddb_id, wchar_t device) +{ + if (!device) + return false; + + #ifndef IGNORE_API_GRACENOTE + if (config_use_veritas) + { + obj_primo *primo=0; + waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (primo) + { + DWORD unit = device; + if (primo->DiscInfoEx(&unit, 0, NULL, NULL, NULL, NULL, NULL, NULL) != PRIMOSDK_OK) // CDTextInfoEJ suggest that this needs to be called first + { + sf->releaseInterface(primo); + return false; + } + char titleE[8192] = "", performerE[8192] = "", composerE[8192] = "", titleJ[2000] = "", performerJ[2000] = "", composerJ[2000] = ""; + if (primo->CDTextInfoEJ(&unit, (PBYTE)titleE, (PBYTE)performerE, (PBYTE)composerE, (PBYTE)titleJ, (PBYTE)performerJ, (PBYTE)composerJ) == PRIMOSDK_OK) + { + sf->releaseInterface(primo); + // read titles + if (titleE[0]) + { + CDText_Process(cddb_id, titleE, performerE, composerE, 28591 /* Latin1 */); + return true; + } + else if (titleJ[0]) + { + CDText_Process(cddb_id, titleJ, performerJ, composerJ, 932 /* SHIFT-JIS */); + return true; + } + } + } + } + #endif + + return false; +} + +void StoreCDNoInfo(unsigned int cddb_id) +{ + AutoLock lock(dbcs); + OpenDiscTable(); + nde_scanner_t s = NDE_Table_CreateScanner(discTable); + SeekToDisc(s, cddb_id); + NDE_Scanner_Post(s); + NDE_Table_DestroyScanner(discTable, s); + g_dirty |= 1; +} + +// sets part and parts to 0 on fail/missing +void ParseIntSlashInt(const wchar_t *string, int *part, int *parts) +{ + *part = 0; + *parts = 0; + + if (string && string[0]) + { + *part = _wtoi(string); + while (string && *string && *string != '/') + { + string++; + } + if (string && *string == '/') + { + string++; + *parts = _wtoi(string); + } + } +} + +bool QueryDINFO(unsigned int cddb_id, DINFO *info) +{ + info->Reset(); + AutoLock lock(dbcs); + if (OpenDiscTable() != NDE_CD_SUCCESS) + return false; + + nde_scanner_t s = NDE_Table_CreateScanner(discTable); + if (NDE_Scanner_LocateInteger(s, DISCTABLE_ID_DISCID, FIRST_RECORD, cddb_id)) + { + ndestring_retain(info->title = db_getFieldString(s, DISCTABLE_ID_ALBUM)); + ndestring_retain(info->artist = db_getFieldString(s, DISCTABLE_ID_ARTIST)); + ndestring_retain(info->tuid = db_getFieldString(s, DISCTABLE_ID_TUID)); + ndestring_retain(info->year = db_getFieldString(s, DISCTABLE_ID_YEAR)); + ndestring_retain(info->genre = db_getFieldString(s, DISCTABLE_ID_GENRE)); + ndestring_retain(info->notes = db_getFieldString(s, DISCTABLE_ID_COMMENT)); + const wchar_t *disc_str = db_getFieldString(s, DISCTABLE_ID_DISC); + ParseIntSlashInt(disc_str , &info->discnum, &info->numdiscs); + ndestring_retain(info->composer = db_getFieldString(s, DISCTABLE_ID_COMPOSER)); + ndestring_retain(info->label = db_getFieldString(s, DISCTABLE_ID_PUBLISHER)); + ndestring_retain(info->conductor = db_getFieldString(s, DISCTABLE_ID_CONDUCTOR)); + + /* Read tracks */ + OpenTrackTable(); + nde_scanner_t trackScanner = NDE_Table_CreateScanner(trackTable); + + nde_field_t f_id = NDE_IntegerField_Create(cddb_id); + NDE_Scanner_AddFilterByID(trackScanner, TRACKTABLE_ID_DISCID, f_id, FILTER_EQUALS); + + int trackNum=1; + while (trackNum < 100) + { + TRACKINFO &trackInfo = info->tracks[trackNum-1]; + if (!NDE_Scanner_LocateInteger(trackScanner, TRACKTABLE_ID_TRACK, FIRST_RECORD, trackNum)) + break; + trackNum++; + ndestring_retain(trackInfo.artist = db_getFieldString(trackScanner, TRACKTABLE_ID_ARTIST)); + ndestring_retain(trackInfo.title = db_getFieldString(trackScanner, TRACKTABLE_ID_TITLE)); + ndestring_retain(trackInfo.tagID = db_getFieldString(trackScanner, TRACKTABLE_ID_TAGID)); + ndestring_retain(trackInfo.composer = db_getFieldString(trackScanner, TRACKTABLE_ID_COMPOSER)); + ndestring_retain(trackInfo.conductor = db_getFieldString(trackScanner, TRACKTABLE_ID_CONDUCTOR)); + ndestring_retain(trackInfo.extData = db_getFieldString(trackScanner, TRACKTABLE_ID_EXTENDED_DATA)); + } + NDE_Table_DestroyScanner(trackTable, trackScanner); + NDE_Table_DestroyScanner(discTable, s); + info->populated = true; + return true; + } + NDE_Table_DestroyScanner(discTable, s); + return false; +} + +static void db_add_or_set(nde_scanner_t s, unsigned char id, wchar_t *data) +{ + nde_field_t f = NDE_Scanner_GetFieldByID(s, id); + if (data) + { + if (!f) f = NDE_Scanner_NewFieldByID(s, id); + NDE_StringField_SetNDEString(f, data); + } + else if (f) + { + NDE_Scanner_DeleteField(s, f); + } +} + +static void db_compare_add_or_set(nde_scanner_t s, unsigned char id, const wchar_t *disc_data, wchar_t *data) +{ + if (disc_data && data && !wcscmp(disc_data, data)) + db_removeField(s, id); + else + db_add_or_set(s, id, data); +} + +//#ifndef IGNORE_API_GRACENOTE +bool StoreDINFO(unsigned cddb_id, DINFO *info) +{ + AutoLock lock(dbcs); + if (OpenDiscTable() != NDE_CD_SUCCESS) + return false; + + nde_scanner_t s = NDE_Table_CreateScanner(discTable); + SeekToDisc(s, cddb_id); + + db_add_or_set(s, DISCTABLE_ID_ALBUM, info->title); + db_add_or_set(s, DISCTABLE_ID_ARTIST, info->artist); + db_add_or_set(s, DISCTABLE_ID_TUID, info->tuid); + db_add_or_set(s, DISCTABLE_ID_YEAR, info->year); + db_add_or_set(s, DISCTABLE_ID_GENRE, info->genre); + db_add_or_set(s, DISCTABLE_ID_PUBLISHER, info->label); + db_add_or_set(s, DISCTABLE_ID_COMMENT, info->notes); + + if (info->discnum) + { + wchar_t disc_temp[64] = {0}; + if (info->numdiscs) + StringCchPrintfW(disc_temp, 64, L"%d/%d", info->discnum, info->numdiscs); + else + StringCchPrintfW(disc_temp, 64, L"%d", info->discnum); + db_setFieldString(s, DISCTABLE_ID_DISC, disc_temp); + } + else + db_removeField(s, DISCTABLE_ID_DISC); + + db_add_or_set(s, DISCTABLE_ID_CONDUCTOR, info->conductor); + db_add_or_set(s, DISCTABLE_ID_COMPOSER, info->composer); + + NDE_Scanner_Post(s); + NDE_Table_DestroyScanner(discTable, s); + + OpenTrackTable(); + s = NDE_Table_CreateScanner(trackTable); + for (int x=0;x<info->ntracks;x++) + { + SeekToTrack(s, cddb_id, x+1); + TRACKINFO &trackInfo = info->tracks[x]; + db_compare_add_or_set(s, TRACKTABLE_ID_ARTIST, info->artist, trackInfo.artist); + db_add_or_set(s, TRACKTABLE_ID_TITLE, trackInfo.title); + db_add_or_set(s, TRACKTABLE_ID_TAGID, trackInfo.tagID); + db_compare_add_or_set(s, TRACKTABLE_ID_COMPOSER, info->composer, trackInfo.composer); + db_compare_add_or_set(s, TRACKTABLE_ID_CONDUCTOR, info->conductor, trackInfo.conductor); + db_add_or_set(s, TRACKTABLE_ID_EXTENDED_DATA, trackInfo.extData); + NDE_Scanner_Post(s); + } + NDE_Table_DestroyScanner(trackTable, s); + NDE_Table_Sync(trackTable); + NDE_Table_Sync(discTable); + g_dirty = 0; + return true; +} +//#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/ntddcdrm.h b/Src/Plugins/Input/in_cdda/ntddcdrm.h new file mode 100644 index 00000000..f9904978 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/ntddcdrm.h @@ -0,0 +1,549 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddcdrm.h + +Abstract: + + This module contains structures and definitions + associated with CDROM IOCTls. + +Author: + + Mike Glass + +Revision History: + +--*/ + +// begin_winioctl + +#ifndef _NTDDCDRM_ +#define _NTDDCDRM_ + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +// +// remove some level 4 warnings for this header file: +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int + +#ifdef __cplusplus +extern "C" { +#endif + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM + +#define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// CDROM Audio Device Control Functions +// + +#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0014, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_CONFIGURATION CTL_CODE(IOCTL_CDROM_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS) + +// end_winioctl + +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future with the IOCTL_STORAGE +// codes included below +// + +#define IOCTL_CDROM_CHECK_VERIFY CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_LOAD_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESERVE CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RELEASE CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_FIND_NEW_DEVICES CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// The following file contains the IOCTL_STORAGE class ioctl definitions +// + +//#include "ntddstor.h" + +// begin_winioctl + +// +// The following device control code is for the SIMBAD simulated bad +// sector facility. See SIMBAD.H in this directory for related structures. +// + +#define IOCTL_CDROM_SIMBAD CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// Maximum CD Rom size +// + +#define MAXIMUM_NUMBER_TRACKS 100 +#define MAXIMUM_CDROM_SIZE 804 +#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 // two bytes min transferred + +// +// READ_TOC_EX structure +// +typedef struct _CDROM_READ_TOC_EX { + UCHAR Format : 4; + UCHAR Reserved1 : 3; // future expansion + UCHAR Msf : 1; + UCHAR SessionTrack; + UCHAR Reserved2; // future expansion + UCHAR Reserved3; // future expansion +} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; + +#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 +#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 +#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 +#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 +#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 +#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 + +// +// CD ROM Table OF Contents (TOC) +// Format 0 - Get table of contents +// + +typedef struct _TRACK_DATA { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +typedef struct _CDROM_TOC { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstTrack; + UCHAR LastTrack; + + // + // Track data + // + + TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; +} CDROM_TOC, *PCDROM_TOC; + +#define CDROM_TOC_SIZE sizeof(CDROM_TOC) + +// +// CD ROM Table OF Contents +// Format 1 - Session Information +// + +typedef struct _CDROM_TOC_SESSION_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // One track, representing the first track + // of the last finished session + // + + TRACK_DATA TrackData[1]; + +} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; + + +// +// CD ROM Table OF Contents +// Format 2 - Full TOC +// + +typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { + UCHAR SessionNumber; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR Reserved1; + UCHAR Point; + UCHAR MsfExtra[3]; + UCHAR Zero; + UCHAR Msf[3]; +} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; + +typedef struct _CDROM_TOC_FULL_TOC_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // one to N descriptors included + // + + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; + +} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; + +// +// CD ROM Table OF Contents +// Format 3 - Program Memory Area +// +typedef struct _CDROM_TOC_PMA_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // one to N descriptors included + // + + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; + +} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA; + +// +// CD ROM Table OF Contents +// Format 4 - Absolute Time In Pregroove +// + +typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { + + UCHAR CdrwReferenceSpeed : 3; + UCHAR Reserved3 : 1; + UCHAR WritePower : 3; + UCHAR True1 : 1; + UCHAR Reserved4 : 6; + UCHAR UnrestrictedUse : 1; + UCHAR Reserved5 : 1; + UCHAR A3Valid : 1; + UCHAR A2Valid : 1; + UCHAR A1Valid : 1; + UCHAR DiscSubType : 3; + UCHAR IsCdrw : 1; + UCHAR True2 : 1; + UCHAR Reserved7; + + UCHAR LeadInMsf[3]; + UCHAR Reserved8; + + UCHAR LeadOutMsf[3]; + UCHAR Reserved9; + + UCHAR A1Values[3]; + UCHAR Reserved10; + + UCHAR A2Values[3]; + UCHAR Reserved11; + + UCHAR A3Values[3]; + UCHAR Reserved12; + +} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; + +typedef struct _CDROM_TOC_ATIP_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // zero? to N descriptors included. + // + + CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0]; + +} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA; + +// +// CD ROM Table OF Contents +// Format 5 - CD Text Info +// +#define CD_TEXT_FIELD_LENGTH 12 +typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { + UCHAR PackType; + UCHAR TrackNumber : 7; + UCHAR ExtensionFlag : 1; // should be zero! + UCHAR SequenceNumber; + UCHAR CharacterPosition : 4; + UCHAR BlockNumber : 3; + UCHAR Unicode : 1; + union { + UCHAR Text[12]; + WCHAR WText[6]; + }; + UCHAR CRC[2]; +} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; + +typedef struct _CDROM_TOC_CD_TEXT_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // the text info comes in discrete blocks of + // a heavily-overloaded structure + // + + CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0]; + +} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA; + +// +// These are the types used for PackType field in CDROM_TOC_CD_TEXT_DATA_BLOCK +// and also for requesting specific info from IOCTL_CDROM_READ_CD_TEXT +// +#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 +#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 +#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 +#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 +#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 +#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 +#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 +#define CDROM_CD_TEXT_PACK_GENRE 0x87 +#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 +#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 +// 0x8a - 0x8d are reserved.... +#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e +#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f + +// +// Play audio starting at MSF and ending at MSF +// + +typedef struct _CDROM_PLAY_AUDIO_MSF { + UCHAR StartingM; + UCHAR StartingS; + UCHAR StartingF; + UCHAR EndingM; + UCHAR EndingS; + UCHAR EndingF; +} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; + +// +// Seek to MSF +// + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + + +// +// Flags for the disk type +// + +typedef struct _CDROM_DISK_DATA { + + ULONG DiskData; + +} CDROM_DISK_DATA, *PCDROM_DISK_DATA; + +#define CDROM_DISK_AUDIO_TRACK (0x00000001) +#define CDROM_DISK_DATA_TRACK (0x00000002) + +// +// CD ROM Data Mode Codes, used with IOCTL_CDROM_READ_Q_CHANNEL +// + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + + +// +// CD ROM Sub-Q Channel Data Format +// + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval : 1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + +// +// Audio Status Codes +// + +#define AUDIO_STATUS_NOT_SUPPORTED 0x00 +#define AUDIO_STATUS_IN_PROGRESS 0x11 +#define AUDIO_STATUS_PAUSED 0x12 +#define AUDIO_STATUS_PLAY_COMPLETE 0x13 +#define AUDIO_STATUS_PLAY_ERROR 0x14 +#define AUDIO_STATUS_NO_STATUS 0x15 + +// +// ADR Sub-channel Q Field +// + +#define ADR_NO_MODE_INFORMATION 0x0 +#define ADR_ENCODES_CURRENT_POSITION 0x1 +#define ADR_ENCODES_MEDIA_CATALOG 0x2 +#define ADR_ENCODES_ISRC 0x3 + +// +// Sub-channel Q Control Bits +// + +#define AUDIO_WITH_PREEMPHASIS 0x1 +#define DIGITAL_COPY_PERMITTED 0x2 +#define AUDIO_DATA_TRACK 0x4 +#define TWO_FOUR_CHANNEL_AUDIO 0x8 + +// +// Get Audio control parameters +// + +typedef struct _CDROM_AUDIO_CONTROL { + UCHAR LbaFormat; + USHORT LogicalBlocksPerSecond; +} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; + +// +// Volume control - Volume takes a value between 1 and 0xFF. +// SCSI-II CDROM audio suppports up to 4 audio ports with +// Independent volume control. +// + +typedef struct _VOLUME_CONTROL { + UCHAR PortVolume[4]; +} VOLUME_CONTROL, *PVOLUME_CONTROL; + +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +// +// Passed to cdrom to describe the raw read, ie. Mode 2, Form 2, CDDA... +// + +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +#ifdef __cplusplus +} +#endif + + +#if _MSC_VER >= 1200 +#pragma warning(pop) // un-sets any local warning changes +#else +#pragma warning(default:4200) // array[0] is not a warning for this file +#pragma warning(default:4201) // nameless struct/unions +#pragma warning(default:4214) // bit fields other than int +#endif + + +#endif // _NTDDCDRM_ + +// end_winioctl + + diff --git a/Src/Plugins/Input/in_cdda/resource.h b/Src/Plugins/Input/in_cdda/resource.h new file mode 100644 index 00000000..3d60abbb --- /dev/null +++ b/Src/Plugins/Input/in_cdda/resource.h @@ -0,0 +1,136 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by in_cdda.rc +// +#define IDS_NULLSOFT_CD_PLUGIN_OLD 1 +#define IDS_QUERYING 2 +#define IDC_REMOVE 3 +#define IDS_NOT_FOUND 3 +#define IDC_GETCDDB 4 +#define IDS_PROCESSING 4 +#define IDS_CDDB_NOT_INSTALLED 5 +#define IDS_SUCCESS 6 +#define IDS_CLOSE 7 +#define IDS_INITIALIZING 8 +#define IDS_ABORTING 9 +#define IDS_UNLIMITED 10 +#define IDS_PURCHASE_WINAMP_PRO_PROMPT 11 +#define IDS_WINAMP_PRO_FEATURE 12 +#define IDS_ARTIST 13 +#define IDS_TITLE 14 +#define IDS_ALBUM_ARTIST 15 +#define IDS_NULLSOFT_CD_PLUGIN2 16 +#define IDS_ABOUT 17 +#define IDS_CD_CURRENTLY_IN_USE 18 +#define IDS_DRIVE_IN_USE 19 +#define IDS_DRIVE_NOT_FOUND 20 +#define IDS_CD_NOT_PRESENT 21 +#define IDS_CANNOT_PLAY_TRACK 22 +#define IDS_STRING0 23 +#define IDS_CDDA_AUDIO_TRACKS 23 +#define IDS_RIPPNG 24 +#define IDS_RIPPING 24 +#define IDS_TRACK_X 25 +#define IDS_UNKNOWN 26 +#define IDS_UNKNOWN_ARTIST 27 +#define IDS_FAMILY_STRING 28 +#define IDS_ABOUT_TEXT 29 +#define IDD_DIALOG1 101 +#define IDD_DIALOG2 102 +#define IDD_MULSEL 103 +#define IDD_SERVSEL 104 +#define IDS_ABORT 109 +#define IDS_CDDB_PROGRESS_CONNECTING 110 +#define IDS_CDDB_PROGRESS_SENDING 111 +#define IDS_CDDB_PROGRESS_RECEIVING 112 +#define IDS_CDDB_PROGRESS_WAITING 113 +#define IDS_CDDB_PROGRESS_CANCELLED 114 +#define IDS_CDDB_PROGRESS_COMPLETED 115 +#define IDS_CDDB_E_BUSY 116 +#define IDS_CDDB_E_FAIL 117 +#define IDS_CDDB_E_BADTOC 118 +#define IDS_REASON 119 +#define IDS_FOUND_MULTIPLE 120 +#define IDS_RESOLVING 121 +#define IDS_SUBMITTINGDISC 122 +#define IDS_FOUND_EXACT 123 +#define IDS_SUBMITNEW 124 +#define IDS_SUBMITDISC_TITLE 125 +#define IDS_SUBMITTING 126 +#define IDS_OPENING 127 +#define IDS_FUZZYDISC_TITLE 128 +#define IDS_ACCEPT 129 +#define IDS_LOOKUPRESULT_TITLE 130 +#define IDS_SUBMIT_OFFER 131 +#define IDS_CDDB_E_ABORT 132 +#define IDS_CDTEXT 133 +#define IDD_DIALOG3 134 +#define IDD_MUSICID 134 +#define IDS_TRACK 135 +#define IDS_COMPOSER 136 +#define IDD_PREFS_CDRIP 232 +#define IDD_CDDB_PROGRESS 233 +#define IDD_CDTEXT 234 +#define IDC_SAMPLE 1000 +#define IDC_STATUS 1001 +#define ID_ABORTBABY 1002 +#define IDC_SERV 1003 +#define IDC_EMAIL 1004 +#define IDC_CDDB 1005 +#define IDC_EMAIL2 1006 +#define IDC_LIST1 1006 +#define IDC_RAS 1006 +#define IDC_TRACKLIST 1006 +#define IDC_LV_EXT 1006 +#define IDC_BUTTON1 1007 +#define IDC_CDTEXT 1007 +#define IDC_CDDBICON 1008 +#define IDC_CDDBICON2 1009 +#define IDC_TITLE 1010 +#define IDC_ARTIST 1011 +#define IDC_TRACKS 1012 +#define IDC_EDITTEXT 1013 +#define IDC_CDDBNOTE 1014 +#define IDC_PUBLISHER 1014 +#define IDC_DIGITAL 1015 +#define IDC_GENRE 1015 +#define IDC_YEAR 1016 +#define IDC_VERITAS 1016 +#define IDC_COMBO1 1019 +#define IDC_PROGRESS 1020 +#define IDC_STATUS_TEXT 1021 +#define IDC_EDITARTIST 1022 +#define IDC_CHECK1 1024 +#define IDC_COMPILATION 1024 +#define IDC_BUTTON2 1025 +#define IDC_EDIT 1025 +#define IDC_SUBMIT 1025 +#define IDC_CLOSE 1027 +#define IDC_DISC 1030 +#define IDC_DISCS 1031 +#define IDC_NOTES 1032 +#define IDC_LABEL 1033 +#define IDC_EDIT1 1034 +#define IDC_LBL_CAPTION 1035 +#define IDC_EDIT2 1035 +#define IDC_COMPOSER 1035 +#define IDC_ALBUM 1036 +#define IDC_LBL_STATUS 1039 +#define IDC_PRG_STATUS 1040 +#define IDC_LBL_REASON 1041 +#define IDC_EDIT_GRACENOTE 1042 +#define IDC_LOOKUP 1043 +#define IDC_BUTTON4 1044 +#define IDC_USE 1044 +#define IDS_NULLSOFT_CD_PLUGIN 65534 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 136 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1045 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Input/in_cdda/scsi_id.cpp b/Src/Plugins/Input/in_cdda/scsi_id.cpp new file mode 100644 index 00000000..78410457 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/scsi_id.cpp @@ -0,0 +1,124 @@ +#include <windows.h> +#include <winioctl.h> + +//functions to get the SCSI ID from a drive letter +//thanks to Microsoft for making this a nightmare... + +// begin ntddscsi.h definitions + +#define IOCTL_SCSI_BASE \ + FILE_DEVICE_CONTROLLER + +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE \ + ( \ + IOCTL_SCSI_BASE, \ + 0x0406, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS \ + ) + +#define IOCTL_SCSI_GET_INQUIRY_DATA \ + CTL_CODE( \ + IOCTL_SCSI_BASE, \ + 0x0403, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS \ + ) + +typedef struct _SCSI_ADDRESS { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +}SCSI_ADDRESS, *PSCSI_ADDRESS; + +// +// Define SCSI information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_BUS_DATA { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +}SCSI_BUS_DATA, *PSCSI_BUS_DATA; + +// +// Define SCSI adapter bus information structure.. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_ADAPTER_BUS_INFO { + UCHAR NumberOfBuses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + +// +// Define SCSI adapter bus information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_INQUIRY_DATA { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +}SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + +// end ntddscsi.h definitions + +int getSCSIIDFromDrive(char driveletter, int *host, int *id, int *lun) +{ + //FUCKO: only works on NT :( + + SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + wchar_t tmp[128] = {0}; + wsprintf(tmp,L"\\\\.\\%c:",driveletter); + HANDLE device = CreateFile( + tmp, + 0, // no particular access necessary + // for the IO control we're using + FILE_SHARE_READ + | FILE_SHARE_WRITE + | FILE_SHARE_DELETE, + 0, // no security attrs - ignored anyway + OPEN_EXISTING, + 0, // no attributes or flags + 0 // no template + ); + + if( device == INVALID_HANDLE_VALUE ) return 0; + + SCSI_ADDRESS sa; + ULONG bytes; + + BOOL status = DeviceIoControl( + device, + IOCTL_SCSI_GET_ADDRESS, + 0, 0, // no input buffer + &sa, sizeof(sa), // output args + &bytes, // bytes returned + 0 // ignored + ); + + if (!status && 50 == GetLastError()) + { + *host = ((driveletter > 'a') ? (driveletter - 'a') : (driveletter - 'A')); + *id = 0; + *lun = 0; + CloseHandle(device); + return 1; + } + CloseHandle(device); + + if( !status ) return 0; + + *host=sa.PortNumber; + *id=sa.TargetId; + *lun=sa.Lun; + return 1; +} diff --git a/Src/Plugins/Input/in_cdda/util.cpp b/Src/Plugins/Input/in_cdda/util.cpp new file mode 100644 index 00000000..8fb2d243 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/util.cpp @@ -0,0 +1,23 @@ +#include "Main.h" + +void WaitForEvent(HANDLE hEvent, DWORD msMaxWaitTime) +{ + // DWORD i; + MSG msg; + const unsigned long eachWait = 10; + unsigned long totalWait = 0; + + while (WaitForSingleObject(hEvent, eachWait) == WAIT_TIMEOUT) + { + while (PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE)) + { + //TranslateMessage(&msg); + DispatchMessage(&msg); + } + + totalWait += eachWait; + if (totalWait >= msMaxWaitTime) + break; + + } +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/version.rc2 b/Src/Plugins/Input/in_cdda/version.rc2 new file mode 100644 index 00000000..56aab11f --- /dev/null +++ b/Src/Plugins/Input/in_cdda/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 4,7,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 Input Plug-in" + VALUE "FileVersion", "4,7,0,0" + VALUE "InternalName", "Nullsoft CD Plug-in" + VALUE "LegalCopyright", "Copyright © 1997-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "in_cdda.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Plugins/Input/in_cdda/windac/Aspi.h b/Src/Plugins/Input/in_cdda/windac/Aspi.h new file mode 100644 index 00000000..cc55c36e --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Aspi.h @@ -0,0 +1,410 @@ +#ifndef ASPI_INCLUDED +#define ASPI_INCLUDED + +#include <Windows.h> +#include <Stdio.h> +#include <Stdlib.h> + +// Handle to the ASPI libaray +extern HINSTANCE hAspiLib; +void GetAspiError(int nErrorCode,LPSTR lpszError); + +// 1 byte alignment or SCSI structures +#pragma pack(push,1) + +#define MAX_SCSIDEVICES 16 + + +#define TIMEOUT 10000 + + +typedef void (*POSTPROCFUNC)(); + +typedef struct TOC_TAG +{ + BYTE _reserved1; + BYTE bFlags; + BYTE bTrack; + BYTE _reserved2; + DWORD dwStartSector; +} TOC; + + +// The SRB_Flags are defined below. These flags may be OR'd together to form +// the final value for SRB_Flags in the SRB. Note that SRB_POSTING and +// SRB_EVENT_NOTIFY are mutually exclusive, as are SRB_DIR_IN and SRB_DIR_OUT. In +// addition, the directioin bits (SRB_DIR_IN and SRB_DIR_OUT) MUST be set +// correctly on commands which transfer data. Using SRB_DIR_SCSI is no longer +// an option as in ASPI for DOS and ASPI for Win16. + +#define SRB_POSTING 0x01 // Enable ASPI command completion posting. See section on posting below. +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 // Enables reporting of residual byte count.This flag is only significant if the host adapter reports support for residual byte count in the SC_HA_INQUIRY command. When data underrun occurs, the SRB_BufLen field is updated to reflect the remaining bytes to transfer. +#define SRB_DIR_IN 0x08 // Data transfer from SCSI target to host. +#define SRB_DIR_OUT 0x10 // Data transfer from host to SCSI target. +#define SRB_EVENT_NOTIFY 0x40 // Enable ASPI command event notification. See section on event notification below. + + +// Inquiry DeviceTypeCodes +#define DTC_DISK 0x00 // Direct-access device +#define DTC_TAPE 0x01 // Sequential-access device +#define DTC_PRINTER 0x02 // Printer device +#define DTC_PROCESSOR 0x03 // Processor device +#define DTC_WORM 0x04 // Write-once device +#define DTC_CDROM 0x05 // CD-ROM device +#define DTC_SCANNER 0x06 // Scanner device +#define DTC_OPTICAL 0x07 // Optical memory device +#define DTC_JUKEBOX 0x08 // Medium changer device +#define DTC_COMM 0x09 // Communications device +#define DTC_PREPRESS1 0x0A // Pre-press device 1 +#define DTC_PREPRESS2 0x0B // Pre-press device 2 +#define DTC_UNKNOWN 0x1F // Unknown or no device type + + +/*************************************************************************** + ** SRB Status + ***************************************************************************/ +#define SS_PENDING 0x00 /* SRB being processed */ +#define SS_COMP 0x01 /* SRB completed without error */ +#define SS_ABORTED 0x02 /* SRB aborted */ +#define SS_ABORT_FAIL 0x03 /* Unable to abort SRB */ +#define SS_ERR 0x04 /* SRB completed with error */ +#define SS_INVALID_CMD 0x80 /* Invalid ASPI command */ +#define SS_INVALID_HA 0x81 /* Invalid host adapter number */ +#define SS_NO_DEVICE 0x82 /* SCSI device not installed */ +#define SS_INVALID_SRB 0xE0 /* Invalid parameter set in SRB */ +#define SS_OLD_MANAGER 0xE1 /* ASPI manager doesn't support */ + /* windows */ +#define SS_BUFFER_ALIGN 0xE1 /* Buffer not aligned (replaces */ + /* SS_OLD_MANAGER in Win32) */ +#define SS_ILLEGAL_MODE 0xE2 /* Unsupported Windows mode */ +#define SS_NO_ASPI 0xE3 /* No ASPI managers */ +#define SS_FAILED_INIT 0xE4 /* ASPI for windows failed init */ +#define SS_ASPI_IS_BUSY 0xE5 /* No resources available to */ + /* execute command */ +#define SS_BUFFER_TO_BIG 0xE6 /* Buffer size too big to handle */ +#define SS_BUFFER_TOO_BIG 0xE6 /* Correct spelling of 'too' */ +#define SS_MISMATCHED_COMPONENTS 0xE7 /* The DLLs/EXEs of ASPI don't */ + /* version check */ +#define SS_NO_ADAPTERS 0xE8 /* No host adapters to manager */ +#define SS_INSUFFICIENT_RESOURCES 0xE9 /* Couldn't allocate resources */ + /* needed to init */ +#define SS_ASPI_IS_SHUTDOWN 0xEA /* Call came to ASPI after */ + /* PROCESS_DETACH */ +#define SS_BAD_INSTALL 0xEB /* The DLL or other components */ + /* are installed wrong */ + + +// SRB defines +#define SC_HA_INQUIRY 0x00 // Get information about installed host adapters,including the number of installed adapters. +#define SC_GET_DEV_TYPE 0x01 // Get information about installed SCSI devices. +#define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI I/O. +#define SC_ABORT_SRB 0x03 // Abort an outstanding I/O request. +#define SC_RESET_DEV 0x04 // Reset an individual SCSI target. +#define SC_GET_DISK_INFO 0x06 // Get information on disk type SCSI devices (not available under Windows NT). +#define SC_GETSET_TIMEOUTS 0x08 + +// MISC defines +#define CDSAMPLEFREQ 44100 +#define TRACKSPERSEC 75 + +#define CB_CDDASECTOR 2352 +#define CB_QSUBCHANNEL 0 +#define CB_CDROMSECTOR 2048 +#define CB_AUDIO (CB_CDDASECTOR-CB_QSUBCHANNEL) + + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 +} SRB_HEADER, *LPSRB; + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_HA_INQUIRY + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 + BYTE HA_Count; // Number of host adapters present + BYTE HA_SCSI_ID; // SCSI ID of host adapter + BYTE HA_ManagerId[16]; // String describing the manager + BYTE HA_Identifier[16]; // String describing the host adapter + BYTE HA_Unique[16]; // Host Adapter Unique parameters + WORD HA_Rsvd1; +} SRB_HAINQUIRY, *LPSRB_HAINQUIRY; + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_GET_DEV_TYPE + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // Reserved + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + BYTE SRB_DeviceType; // Target's peripheral device type + BYTE SRB_Rsvd1; // Reserved for alignment +} SRB_GDEVBLOCK, *LPSRB_GDEVBLOCK; + + +#define SENSE_LEN 14 // Maximum sense length + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_EXEC_SCSI_CMD + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + WORD SRB_Rsvd1; // Reserved for Alignment + DWORD SRB_BufLen; // Data Allocation Length + BYTE *SRB_BufPointer; // Data Buffer Point + BYTE SRB_SenseLen; // Sense Allocation Length + BYTE SRB_CDBLen; // CDB Length + BYTE SRB_HaStat; // Host Adapter Status + BYTE SRB_TargStat; // Target Status + void (*SRB_PostProc)(); // Post routine + void *SRB_Rsvd2; // Reserved + BYTE SRB_Rsvd3[16]; // Reserved for expansion + BYTE CDBByte[16]; // SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // Request Sense buffer +} SRB_EXECSCSICMD, *LPSRB_EXECSCSICMD; + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_EXEC_SCSI_CMD + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // Reserved + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + BYTE SRB_DriveFlags; // Driver flags + BYTE SRB_Int13HDriveInfo;// Host Adapter Status + BYTE SRB_Heads; // Preferred number of heads translation + BYTE SRB_Sectors; // Preferred number of sectors translation + BYTE SRB_Rsvd1[10]; // Reserved +} SRB_GETDISKINFO, *LPSRB_GETDISKINFO; + + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_RESET_DEV + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // Reserved + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + BYTE SRB_Rsvd1[12]; // Reserved for Alignment + BYTE SRB_HaStat; // Host Adapter Status + BYTE SRB_TargStat; // Target Status + void *SRB_PostProc; // Post routine + void *SRB_Rsvd2; // Reserved + BYTE SRB_Rsvd3[32]; // Reserved +} SRB_BUSDEVICERESET, *LPSRB_BUSDEVICERESET; + + +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_ABORT_SRB */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaID; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + void *SRB_ToAbort; /* 08/008 Pointer to SRB to abort */ +} SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort; + + +typedef unsigned char Ucbit; +typedef unsigned char u_char; + +#define MP_P_CODE \ + Ucbit p_code : 6; \ + Ucbit p_res : 1; \ + Ucbit parsave : 1 + + +// CD Cap / mech status +typedef struct SCSICDMODEPAGE2A_TAG +{ + MP_P_CODE; // parsave & pagecode (0) + u_char p_len; // 0x14 = 20 Bytes (1) + + Ucbit cd_r_read : 1; // Reads CD-R media (2) + Ucbit cd_rw_read : 1; // Reads CD-RW media + Ucbit method2 : 1; // Reads fixed packet method2 media + Ucbit dvd_rom_read: 1; // Reads DVD ROM media + Ucbit dvd_r_read : 1; // Reads DVD-R media + Ucbit dvd_ram_read: 1; // Reads DVD-RAM media + Ucbit res_2_67 : 2; // Reserved + + Ucbit cd_r_write : 1; // Supports writing CD-R media (3) + Ucbit cd_rw_write : 1; // Supports writing CD-RW media + Ucbit test_write : 1; // Supports emulation write + Ucbit res_3_3 : 1; // Reserved + Ucbit dvd_r_write : 1; // Supports writing DVD-R media + Ucbit dvd_ram_write: 1; // Supports writing DVD-RAM media + Ucbit res_3_67 : 2; // Reserved + + Ucbit audio_play : 1; // Supports Audio play operation (4) + Ucbit composite : 1; // Deliveres composite A/V stream + Ucbit digital_port_2: 1; // Supports digital output on port 2 + Ucbit digital_port_1: 1; // Supports digital output on port 1 + Ucbit mode_2_form_1: 1; // Reads Mode-2 form 1 media (XA) + Ucbit mode_2_form_2: 1; // Reads Mode-2 form 2 media + Ucbit multi_session: 1; // Reads multi-session media + Ucbit res_4 : 1; // Reserved + + Ucbit cd_da_supported: 1; // Reads audio data with READ CD cmd + Ucbit cd_da_accurate: 1; // READ CD data stream is accurate + Ucbit rw_supported: 1; // Reads R-W sub channel information + Ucbit rw_deint_cor: 1; // Reads de-interleved R-W sub chan + Ucbit c2_pointers : 1; // Supports C2 error pointers + Ucbit ISRC : 1; // Reads ISRC information + Ucbit UPC : 1; // Reads media catalog number (UPC) + Ucbit read_bar_code: 1; // Supports reading bar codes + + Ucbit lock : 1; // PREVENT/ALLOW may lock media (5) + Ucbit lock_state : 1; // Lock state 0=unlocked 1=locked + Ucbit prevent_jumper: 1; // State of prev/allow jumper 0=pres + Ucbit eject : 1; // Ejects disc/cartr with STOP LoEj + Ucbit res_6_4 : 1; // Reserved + Ucbit loading_type: 3; // Loading mechanism type + + Ucbit sep_chan_vol: 1; // Vol controls each channel separat (6) + Ucbit sep_chan_mute: 1; // Mute controls each channel separat + Ucbit disk_present_rep:1; // Changer supports disk present rep + Ucbit sw_slot_sel:1; // Load empty slot in changer + Ucbit res_7 : 4; // Reserved + + BYTE ReadSpeedH; // Max. read speed in KB/s (7) + BYTE ReadSpeedL; // Max. read speed in KB/s (7) + + u_char num_vol_levels[2]; // # of supported volume levels (9) + + u_char buffer_size[2]; // Buffer size for the data in KB (11) + u_char cur_read_speed[2]; // Current read speed in KB/s (13) + u_char res_16; // Reserved (14) + + Ucbit res_17_0: 1; // Reserved (15) + Ucbit BCK : 1; // Data valid on falling edge of BCK + Ucbit RCK : 1; // Set: HIGH high LRCK=left channel + Ucbit LSBF : 1; // Set: LSB first Clear: MSB first + Ucbit length : 2; // 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c + Ucbit res_17 : 2; // Reserved + + u_char max_write_speed[2]; // Max. write speed supported in KB/s (17) + + u_char cur_write_speed[2]; // Current write speed in KB/s (19) + +} SCSICDMODEPAGE2A; + +char *fillbytes(void *tov, int cnt, char val); + + +typedef struct SCISMODEHEADER_TAG { + Ucbit sense_data_len : 8; + u_char medium_type; + Ucbit res2 : 4; + Ucbit cache : 1; + Ucbit res : 2; + Ucbit write_prot : 1; + BYTE nBlockLen; +} SCISMODEHEADER; + +typedef struct SCSIMODEHDR_6_TAG { + BYTE btModeDataLen; // 0 + BYTE btMediumType; // 1 + BYTE btDevSpecificParam; // 2 + BYTE btBlkDescrLen; // 3 +} SCSIMODEHDR_6; + + +typedef struct SCSIMODEHDR_10_TAG { + BYTE btModeDataLenH; // 0 + BYTE btModeDataLenL; // 1 + BYTE btMediumType; // 2 + BYTE btDevSpecificParam; // 3 + BYTE btReserved1; // 4 + BYTE btReserved2; // 5 + BYTE btBlkDescrLenH; // 6 + BYTE btBlkDescrLenL; // 7 +} SCSIMODEHDR_10; + +typedef struct SCSIBLOCKDESCRIPTOR_TAG { + BYTE btDensity; // 0 + BYTE btNumberOfBlocksH; // 1 + BYTE btNumberOfBlocksM; // 2 + BYTE btNumberOfBlocksL; // 3 + BYTE btReserved; // 4 + BYTE btBlockLenH; // 5 + BYTE btBlockLenM; // 6 + BYTE btBlockLenL; // 7 +} SCSIBLOCKDESCRIPTOR; + + + + +// Error recovery Parameters +typedef struct SCSICDMODEPAGE1A_TAG{ + MP_P_CODE; // 0 parsave & pagecode + u_char p_len; // 1 0x0A = 12 Bytes + Ucbit disa_correction : 1; // 2 Byte 2 + Ucbit term_on_rec_err : 1; + Ucbit report_rec_err : 1; + Ucbit en_early_corr : 1; + Ucbit read_continuous : 1; + Ucbit tranfer_block : 1; + Ucbit en_auto_reall_r : 1; + Ucbit en_auto_reall_w : 1; + u_char rd_retry_count; // 3 Byte 3 + u_char correction_span; // 4 + char head_offset_count; // 5 + char data_strobe_offset; // 6 + u_char res; // 7 + u_char wr_retry_count; // 8 + u_char res_tape[2]; // 9 + u_char recov_timelim[2]; // 11 +} SCSICDMODEPAGE1A; + + + + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_GETSET_TIMEOUTS + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + DWORD SRB_Timeout; // Timeout in half seconds +} +SRB_GetSetTimeouts, *PSRB_GetSetTimeouts; + +typedef struct +{ + LPBYTE AB_BufPointer; // Pointer to the ASPI allocated buffer + DWORD AB_BufLen; // Length in bytes of the buffer + DWORD AB_ZeroFill; // Flag set to 1 if buffer should be zeroed + DWORD AB_Reserved; // Reserved, MUST = 0 +} +ASPI32BUFF, *PASPI32BUFF; + +#pragma pack(pop) + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Aspifunc.cpp b/Src/Plugins/Input/in_cdda/windac/Aspifunc.cpp new file mode 100644 index 00000000..ee8f3544 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Aspifunc.cpp @@ -0,0 +1,378 @@ +// ---------------------------------------------- +// - ASPIFUNC implementation file - +// - Written 1996-1998 by Christoph Schmelnik - +// ---------------------------------------------- + +// Version 1.40 : 24.02.1998 +// Changes: +// Set correct direction flags, to work with NT device IO interface and ATAPI drives +// Added Immediate paremeter for WaitSCSIRequest to allow detection of buffer underruns + +#include <stddef.h> +#include "aspifunc.h" + +HMODULE hDLL=0; +VOIDPROC GetASPI32SupportInfo; +SRBPROC SendASPI32Command; +int ASPIInstalled; +int RunningNT; +int NumberOfHostAdapters; + +//Implementation of base ASPI Functions +BOOL HAInquiry(int HostAdapterNumber,char *ManagerID, char *HAID,THAUnique &HAUnique) +{ + SRB_HAInquiry MySRB; + DWORD ASPI_Status; + memset(&MySRB,0,sizeof(SRB_HAInquiry)); + MySRB.SRB_Cmd = SC_HA_INQUIRY; + MySRB.SRB_HaId = HostAdapterNumber; + MySRB.SRB_Flags = 0; + MySRB.SRB_Hdr_Rsvd = 0; + ASPI_Status = SendASPI32Command ( (LPSRB) &MySRB ); + if (ASPI_Status!=SS_COMP) + return FALSE; + HAUnique=MySRB.HA_Unique; + for (int i=0; i<16; i++) + { + ManagerID[i]=MySRB.HA_ManagerId[i]; + HAID[i]=MySRB.HA_Identifier[i]; + } + ManagerID[16]=0; + HAID[16]=0; + return TRUE; +} + +int GetDeviceType(int HostAdapterNumber,int TargetId,int LUN) +{ + SRB_GDEVBlock MySRB; + DWORD ASPI_Status; + memset(&MySRB,0,sizeof(SRB_GDEVBlock)); + MySRB.SRB_Cmd = SC_GET_DEV_TYPE; + MySRB.SRB_HaId = HostAdapterNumber; + MySRB.SRB_Flags = 0; + MySRB.SRB_Hdr_Rsvd = 0; + MySRB.SRB_Target = TargetId; + MySRB.SRB_Lun = LUN; + ASPI_Status = SendASPI32Command ((LPSRB)&MySRB); + /***************************************************/ + /* If ASPI_Status == SS_COMP, MySRB.SRB_DeviceType */ + /* will contain the peripheral device type. */ + /***************************************************/ + if (ASPI_Status==SS_COMP) + return MySRB.SRB_DeviceType; + return DTYPE_UNKNOWN; +} + +BOOL ExecuteSCSIRequest(int HostAdapterNumber,int TargetId,int LUN,int RequestFlags, + TOpcode OpC, BYTE OpCLen,void *DataPtr, int DataLen, HANDLE hDriveEvent) +{ + if ((HostAdapterNumber>=NumberOfHostAdapters) && + RunningNT) + { + DWORD il, ol; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; + ZeroMemory(&sb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)); + sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + sb.sptd.CdbLength = OpCLen; + sb.sptd.DataIn = ((SRB_DIR_IN & RequestFlags) ? 1/*SCSI_IOCTL_DATA_IN*/ : 0/*SCSI_IOCTL_DATA_OUT*/); + sb.sptd.SenseInfoLength = 32; + sb.sptd.DataTransferLength = DataLen; + sb.sptd.TimeOutValue = 2; + sb.sptd.DataBuffer = (unsigned char*) DataPtr; + sb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + for (int i=0; i<OpCLen; i++) sb.sptd.Cdb[i]=OpC[i]; + il = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); + if (DeviceIoControl(hDriveEvent, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sb, il, &sb, il, &ol, FALSE)) + { + if (sb.sptd.ScsiStatus==0) + return TRUE; + } + return FALSE; + } + + + SRB_ExecSCSICmd MySRB; + DWORD ASPI_Status; + DWORD ASPIEventStatus; + memset(&MySRB,0,sizeof(SRB_ExecSCSICmd)); + MySRB.SRB_Cmd = SC_EXEC_SCSI_CMD; + MySRB.SRB_HaId = HostAdapterNumber; + MySRB.SRB_Flags = RequestFlags|SRB_EVENT_NOTIFY; + MySRB.SRB_Hdr_Rsvd = 0; + MySRB.SRB_Target = TargetId; + MySRB.SRB_Lun = LUN; + MySRB.SRB_BufPointer = (unsigned char*) DataPtr; + MySRB.SRB_BufLen = DataLen; + MySRB.SRB_CDBLen = OpCLen; + MySRB.SRB_SenseLen = SENSE_LEN; + MySRB.SRB_PostProc = (void(__cdecl *)(void))hDriveEvent; + for (int i=0; i<OpCLen; i++) MySRB.CDBByte[i]=OpC[i]; + + ResetEvent(hDriveEvent); + ASPI_Status = SendASPI32Command ((LPSRB)&MySRB); + + /**************************************************/ + /* Block on event till signaled */ + /**************************************************/ + + if ( MySRB.SRB_Status == SS_PENDING ) + { + ASPIEventStatus = WaitForSingleObject(hDriveEvent, TIMEOUT); + + /**************************************************/ + /* Reset event to non-signaled state. */ + /**************************************************/ + if (ASPIEventStatus == WAIT_OBJECT_0) + ResetEvent(hDriveEvent); + else + { + OutputDebugString(L"Execute Timed out\n"); + AbortSCSIRequest(MySRB); + } + } + + if (MySRB.SRB_Status==SS_COMP) + return TRUE; + + return FALSE; +} + +void FillSCSIRequest(int HostAdapterNumber,int TargetId,int LUN,int RequestFlags, + TOpcode OpC, BYTE OpCLen,void *DataPtr, int DataLen,SRB_ExecSCSICmd &MySRB, HANDLE hDriveEvent) +{ + memset(&MySRB,0,sizeof(SRB_ExecSCSICmd)); + MySRB.SRB_Cmd = SC_EXEC_SCSI_CMD; + MySRB.SRB_HaId = HostAdapterNumber; + if ((HostAdapterNumber>=NumberOfHostAdapters) && + RunningNT) + { + MySRB.SRB_Flags = RequestFlags; + } + else + { + MySRB.SRB_Flags = RequestFlags|SRB_EVENT_NOTIFY; + MySRB.SRB_Hdr_Rsvd = 0; + MySRB.SRB_PostProc = (void(__cdecl *)(void))hDriveEvent; + } + MySRB.SRB_Target = TargetId; + MySRB.SRB_Lun = LUN; + MySRB.SRB_BufPointer = (unsigned char*) DataPtr; + MySRB.SRB_BufLen = DataLen; + MySRB.SRB_CDBLen = OpCLen; + MySRB.SRB_SenseLen = SENSE_LEN; + for (int i=0; i<OpCLen; i++) MySRB.CDBByte[i]=OpC[i]; +} + +void ExecuteSCSIRequest(SRB_ExecSCSICmd &MySRB,HANDLE hDriveEvent) +{ + if ((MySRB.SRB_HaId>=NumberOfHostAdapters) && + RunningNT) + { + DWORD il, ol; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; + ZeroMemory(&sb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)); + sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + sb.sptd.PathId = 0; + sb.sptd.TargetId = 1; + sb.sptd.Lun = 0; + sb.sptd.CdbLength = MySRB.SRB_CDBLen; + sb.sptd.DataIn = MySRB.SRB_Flags; + sb.sptd.SenseInfoLength = 32; + sb.sptd.DataTransferLength = MySRB.SRB_BufLen; + sb.sptd.TimeOutValue = TIMEOUT; + sb.sptd.DataBuffer = MySRB.SRB_BufPointer; + sb.sptd.SenseInfoOffset = + offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + for (int i=0; i<MySRB.SRB_CDBLen; i++) sb.sptd.Cdb[i]=MySRB.CDBByte[i]; + il = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); + if (DeviceIoControl(hDriveEvent, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sb, il, &sb, il, &ol, NULL)) + if (sb.sptd.ScsiStatus==0) + { + MySRB.SRB_Status=SS_COMP; + return; + } + MySRB.SRB_Status=SS_ERR; + return; + } + DWORD ASPI_Status; + ResetEvent(hDriveEvent); + ASPI_Status = SendASPI32Command ((LPSRB)&MySRB); +} + +BYTE WaitSCSIRequest(SRB_ExecSCSICmd &MySRB,HANDLE hDriveEvent,BOOL bImmediate) +{ + if ((MySRB.SRB_HaId>=NumberOfHostAdapters) && + RunningNT) + return MySRB.SRB_Status; + if ((MySRB.SRB_Status == SS_PENDING) && + !bImmediate) + { + DWORD ASPIEventStatus = WaitForSingleObject(hDriveEvent, 100); + + if (ASPIEventStatus == WAIT_OBJECT_0) + { + ResetEvent(hDriveEvent); + } + } + + return MySRB.SRB_Status; +} + +BOOL AbortSCSIRequest(SRB_ExecSCSICmd &StuckSRB) +{ + SRB_Abort AbortSRB; + DWORD ASPIStatus; + AbortSRB.SRB_Cmd = SC_ABORT_SRB; + AbortSRB.SRB_HaId = StuckSRB.SRB_HaId; + AbortSRB.SRB_Flags = 0; + AbortSRB.SRB_Hdr_Rsvd = 0; + AbortSRB.SRB_ToAbort = (LPSRB)&StuckSRB; + ASPIStatus = SendASPI32Command ( (LPSRB)&AbortSRB ); + return (ASPIStatus==SS_COMP); +} + + +int GetDeviceInfo(int HostAdapterNumber,int TargetId,int LUN,BYTE &SCSIType,char *VendorID, + char *ProductID,char *ProductRevision,HANDLE hDriveEvent) +{ + struct InquireFormat + { + BYTE ConfigPara[8]; + char VendorID[8]; + char ProductID[16]; + char ProductRevision[4]; + } DeviceInfo; + TOpcode OpC; + OpC[0]=0x12; + OpC[1]=0; + OpC[2]=0; + OpC[3]=0; + OpC[4]=sizeof(DeviceInfo); + OpC[5]=0; + memset(&DeviceInfo,0,sizeof(DeviceInfo)); + BOOL r=ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_IN,OpC,6,(void*)&DeviceInfo,sizeof(DeviceInfo),hDriveEvent); + if (r) + { + for (int i=0; i<16; i++) + { + if (i<8) VendorID[i]=DeviceInfo.VendorID[i]; + ProductID[i]=DeviceInfo.ProductID[i]; + if (i<4) ProductRevision[i]=DeviceInfo.ProductRevision[i]; + } + VendorID[8]=0; + ProductID[16]=0; + ProductRevision[4]=0; + SCSIType=DeviceInfo.ConfigPara[2] & 0x0f; + return DeviceInfo.ConfigPara[0]; + } + return DTYPE_UNKNOWN; +} + +BOOL TestUnitReady(int HostAdapterNumber,int TargetId,int LUN,HANDLE hDriveEvent) +{ + TOpcode OpC; + OpC[0]=0; + OpC[1]=0; + OpC[2]=0; + OpC[3]=0; + OpC[4]=0; + OpC[5]=0; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_IN,OpC,6,NULL,0,hDriveEvent); +} + +BOOL ModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,int PageCode,HANDLE hDriveEvent) +{ +// while (!TestUnitReady(HostAdapterNumber,TargetId,LUN)); + TOpcode OpC; + OpC[0]=0x1a; + OpC[1]=0x00; + OpC[2]=PageCode; + OpC[3]=0x00; + OpC[4]=Size; + OpC[5]=0x00; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_IN,OpC,6,(void *)&ModeData,Size,hDriveEvent); +} + +BOOL ATAPIModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,int PageCode,HANDLE hDriveEvent) +{ +// while (!TestUnitReady(HostAdapterNumber,TargetId,LUN)); + TOpcode OpC; + OpC[0]=0x5a; + OpC[1]=0x00; + OpC[2]=PageCode; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=Size; + OpC[9]=0x00; + OpC[10]=0x00; + OpC[11]=0x00; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_IN,OpC,12,(void *)&ModeData,Size,hDriveEvent); +} + +BOOL addModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent) +{ +// while (!TestUnitReady(HostAdapterNumber,TargetId,LUN)); + TOpcode OpC; + OpC[0]=0xca; + OpC[1]=0x08; + OpC[2]=0x0f; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=Size; + OpC[9]=0x00; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_IN,OpC,10,(void *)&ModeData,Size,hDriveEvent); +} + +BOOL ModeSelect(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent) +{ +// while (!TestUnitReady(HostAdapterNumber,TargetId,LUN)); + TOpcode OpC; + OpC[0]=0x15; + if (Size==12) + OpC[1]=0x00; + else + OpC[1]=0x10; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=Size; + OpC[5]=0x00; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_OUT,OpC,6,(void *)&ModeData,Size,hDriveEvent); +} + +BOOL addModeSelect(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent) +{ +// while (!TestUnitReady(HostAdapterNumber,TargetId,LUN)); + TOpcode OpC; + OpC[0]=0xc5; + OpC[1]=0x10; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=Size; + OpC[9]=0x00; + return ExecuteSCSIRequest(HostAdapterNumber,TargetId,LUN,SRB_DIR_OUT,OpC,10,(void *)&ModeData,Size,hDriveEvent); +} + +BOOL SCSIMaxBlocks(HANDLE fh, int *mb) +{ + DWORD ol; + IO_SCSI_CAPABILITIES ca; + + if (DeviceIoControl(fh,IOCTL_SCSI_GET_CAPABILITIES,NULL,0, + &ca,sizeof(IO_SCSI_CAPABILITIES),&ol,NULL)) + { + *mb=(int)ca.MaximumTransferLength; + return TRUE; + } + return FALSE; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Aspifunc.h b/Src/Plugins/Input/in_cdda/windac/Aspifunc.h new file mode 100644 index 00000000..c63c2f81 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Aspifunc.h @@ -0,0 +1,101 @@ +// ---------------------------------------------- +// - ASPIFUNC header file - +// - Written 1996-1998 by Christoph Schmelnik - +// ---------------------------------------------- + +// Version 1.40 : 24.02.1998 +// Changes: +// function prototype for WaitSCSIRequest extended by immediate parameter + +#ifndef _ASPIFUNC_H +#define _ASPIFUNC_H + +#ifndef STRICT +#define STRICT // Enable strict tape checking +#define WIN32_LEAN_AND_MEAN // Include only needed header files +#endif +#include <windows.h> +#include <stdio.h> +#include <winioctl.h> + +#include "winaspi.h" +#include "scsidefs.h" + +/*#ifdef DLL +#define DACDLL __declspec(dllexport) +#else +#define DACDLL __declspec(dllimport) +#endif*/ +#define DACDLL + +typedef DWORD (__cdecl *VOIDPROC)(); +typedef DWORD (__cdecl *SRBPROC)(LPSRB); +typedef BYTE TOpcode[30]; + +// NT DeviceIO Structures +#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef struct _IO_SCSI_CAPABILITIES { + ULONG Length; + ULONG MaximumTransferLength; + ULONG MaximumPhysicalPages; + ULONG SupportedAsynchronousEvents; + ULONG AlignmentMask; + BOOLEAN TaggedQueuing; + BOOLEAN AdapterScansDown; + BOOLEAN AdapterUsesPio; +} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES; + +typedef struct _SCSI_PASS_THROUGH_DIRECT { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + +typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER { + SCSI_PASS_THROUGH_DIRECT sptd; + ULONG Filler; // realign buffer to double word boundary + UCHAR ucSenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + + +extern HMODULE hDLL; +extern VOIDPROC GetASPI32SupportInfo; +extern SRBPROC SendASPI32Command; +extern int ASPIInstalled; +extern int RunningNT; +extern int NumberOfHostAdapters; + +// base ASPI functions +int DACDLL GetDeviceType(int HostAdapterNumber,int TargetId,int LUN); +BOOL ExecuteSCSIRequest(int HostAdapterNumber,int TargetId,int LUN,int RequestFlags, + TOpcode OpC, BYTE OpCLen,void *DataPtr, int DataLen,HANDLE hDriveEvent); +void ExecuteSCSIRequest(SRB_ExecSCSICmd &MySRB,HANDLE hDriveEvent); +void FillSCSIRequest(int HostAdapterNumber,int TargetId,int LUN,int RequestFlags, + TOpcode OpC, BYTE OpCLen,void *DataPtr, int DataLen,SRB_ExecSCSICmd &MySRB,HANDLE hDriveEvent); +BYTE WaitSCSIRequest(SRB_ExecSCSICmd &MySRB,HANDLE hDriveEvent,BOOL bImmediate=FALSE); +BOOL AbortSCSIRequest(SRB_ExecSCSICmd &StuckSRB); +int GetDeviceInfo(int HostAdapterNumber,int TargetId,int LUN,BYTE &SCSIType,char *VendorID, + char *ProductID,char *ProductRevision,HANDLE hDriveEvent); +BOOL HAInquiry(int HostAdapterNumber,char *ManagerID, char *HAID,THAUnique &HAUnique); +BOOL TestUnitReady(int HostAdapterNumber,int TargetId,int LUN,HANDLE hDriveEvent); +BOOL ModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,int PageCode,HANDLE hDriveEvent); +BOOL ATAPIModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,int PageCode,HANDLE hDriveEvent); +BOOL addModeSense(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent); +BOOL ModeSelect(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent); +BOOL addModeSelect(int HostAdapterNumber,int TargetId,int LUN,TDriveMode &ModeData,int Size,HANDLE hDriveEvent); +BOOL SCSIMaxBlocks(HANDLE fh, int *mb); + +#endif //_ASPIFUNC_H
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Dac32.cpp b/Src/Plugins/Input/in_cdda/windac/Dac32.cpp new file mode 100644 index 00000000..9172a1dd --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Dac32.cpp @@ -0,0 +1,2667 @@ +// ---------------------------------------------- +// - DAC32.DLL Implementations Datei - +// - Written 1996-1998 by Christoph Schmelnik - +// ---------------------------------------------- + +// Version 1.33 : 18.01.1998 +// Changes: +// Added speed selection support for all current Plextor drives +// +// Version 1.40 : 24.02.1998 +// Changes: +// Set correct direction flags, to work with NT device IO interface and ATAPI drives +// Changed main CD detection to TestUnitReady +// Removed CD detection from Audio Status Info +// Added hopefully correct read command for Matsushita/Panasonic drives +// Added Parameters to CDAC class to allow the disabling of the audio test and to spin up the drive for a specified time +// in seconds to avoid spin up problems on some drives. Both parameters have default values so it behaves like the old version +// without the additional parameters +// Added Parameter to the constructor of CWaveSave to disable writing any Headers. Also this parameter has a default to work like +// before. +// Added virtual function in CDAC to report buffer underruns in Burst Copy Mode +// For the last feature an immediate parameter in WaitCDDA is added +// GetLastSense function added to return the sense information for the last read audio command +// Configuration in CMapDrive extended by new features +// Added function to CD Class to read Media Cataloge Number +// +// Version 1.41 : 02.05.1998 +// Changes: +// New GetInfoEx() function in CMapDrive, to allow a better result checking. +// Bugfixed error handling in CWaveSave and CDAC regarding write errors +// +// Version 1.42 : 02.08.1998 +// Changes: +// Added GetLastReadableAddress function to get the last readable Sektor of a session. +// Added a flag in the drive properties for the function. +// Added this function to the CDAC object. +// +// Version 1.43 : 23.12.1998 +// Changes: +// Added Wave and DAC classes are now available in a MT version, the old versions will not longer be updated. +// +// Version 1.44 : 10.03.1999 +// Changes: +// Added Support for current Plextor CDROM drives and CD-Writers. +// Added Support for Jukeboxes +// Changed Handling of the Ringbuffer +// +// Version 1.45 : 15.08.1999 +// Changes: +// Added Enhanced error detection for Plextor drives. +// Several Bugfixes (initialising under NT and Ringbuffer specific) +// +// Version 1.45-Build 11 : 11.11.1999 +// Changes: +// Added a check for the MaxSektor parameter in CBaseWaveMT to avoid Program failures even if the applications provides an invalid value. +// Changed source to comile with Borland compiler +// Added MMC-2 Type which will be default for Sony CD-Writers 140 and 928 +// Skip Virtual CD devices in Bus scan +// Fixed Array out of bound bug in drive detection. + +//limit the read to 64k, because of a bug in the Adaptec drivers +#define Bug64 + +//limit the number of retries at error to 5 +#define MAXTRIES 5 +#include "dac32.h" +#include <stdlib.h> +#include <assert.h> +#include <process.h> + +#ifdef __BORLANDC__ // pgo (to make it compatible with Bormand compiler) +#define _stricmp _stricmp +#define _strlwr strlwr +#endif + +// ---------------------------------------------------------------------------------------- +// - Implementation of the private copy operators - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Check the syntax of program - +// ---------------------------------------------------------------------------------------- + +CBaseCD& CBaseCD::operator = (const CBaseCD &other) +{ + assert(!&other); + return (*this); +} + +CSCSICD& CSCSICD::operator = (const CSCSICD &other) +{ + assert(!&other); + return (*this); +} + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CCDAdress - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Eliminate the errors at compile time - +// ---------------------------------------------------------------------------------------- +void CCDAdress::SetRedbook(long Value) +{ + Adresse=Value >> 24; + Adresse+=((Value >> 16) & 255)*75; + Adresse+=((Value >> 8) & 255)*4500; +}; + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CMapInfo - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Implement the information of the TypeMappings - +// ---------------------------------------------------------------------------------------- +CMapInfo::CMapInfo() +{ + strncpy(TypNamen[0],"TOSHIBA ", 9); + strncpy(TypNamen[1],"SONY ", 9); + strncpy(TypNamen[2],"NEC ", 9); + strncpy(TypNamen[3],"HITACHI ", 9); + strncpy(TypNamen[4],"YAMAHA ", 9); + strncpy(TypNamen[5],"PIONEER ", 9); + strncpy(TypNamen[6],"IBM ", 9); + strncpy(TypNamen[7],"PLEXTOR ", 9); + strncpy(TypNamen[8],"PHILIPS ", 9); + strncpy(TypNamen[9],"GRUNDIG ", 9); + strncpy(TypNamen[10],"HP ", 9); + strncpy(TypNamen[11],"IMS ", 9); + strncpy(TypNamen[12],"MITSUMI ", 9); + strncpy(TypNamen[13],"ATAPI ", 9); + strncpy(TypNamen[14],"TOSHNEW ", 9); + strncpy(TypNamen[15],"RICOH ", 9); + strncpy(TypNamen[16],"MATSHITA", 9); + strncpy(TypNamen[17],"PLASMON ", 9); + strncpy(TypNamen[18],"KODAK ", 9); + strncpy(TypNamen[19],"TEAC ", 9); + strncpy(TypNamen[20],"CyberDrv", 9); + strncpy(TypNamen[21],"MMC-2 ", 9); // pgo + int const t[]={CDTYPE_TOSHIBA,CDTYPE_SONY,CDTYPE_NEC,CDTYPE_SONY,CDTYPE_SONY,CDTYPE_SONY, + CDTYPE_SONY,CDTYPE_PLEXTOR,CDTYPE_PHILIPS,CDTYPE_PHILIPS,CDTYPE_PHILIPS,CDTYPE_PHILIPS, + CDTYPE_PHILIPS,CDTYPE_ATAPI,CDTYPE_TOSHNEW,CDTYPE_RICOH,CDTYPE_MATSHITA,CDTYPE_PHILIPS, + CDTYPE_PHILIPS,CDTYPE_SONY,CDTYPE_CYBERDRV, + CDTYPE_CYBERDRV}; // pgo + for (int i=0; i<MaxMappings; i++) + TypMapping[i]=t[i]; +} + +char *CMapInfo::GetTypName(int Index) +{ + return TypNamen[Index]; +}; + +int CMapInfo::GetTypMapping(int Index) +{ + return TypMapping[Index]; +}; + +int CMapInfo::GetTypMappingRev(int CDType) +{ + int Index=0; + while ((Index<MaxMappings) && + (TypMapping[Index]!=CDType)) + Index++; + return Index; +}; + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CMapDrive - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Administration of the drive configuration - +// ---------------------------------------------------------------------------------------- +CMapDrive::CMapDrive(BOOL bDoReset) +{ + First=0; + + m_hDriveEvent=INVALID_HANDLE_VALUE; + wchar_t szEventName[32] = {0}; + wsprintf(szEventName,L"%X",this); + m_hDriveEvent=CreateEvent(NULL,TRUE,FALSE,szEventName); + if (bDoReset) + Reset(); +}; + +CMapDrive::~CMapDrive() +{ + DeleteAll(); + if (m_hDriveEvent!=INVALID_HANDLE_VALUE) + CloseHandle(m_hDriveEvent); +}; + +void CMapDrive::DeleteAll() +{ + TDriveInfoMem *Akt; + Akt=First; + while (First) + { + Akt=First; + First=Akt->Next; + delete Akt; + } +}; + +void CMapDrive::Reset() +{ + TDriveInfoMem *Akt,*Last; + DeleteAll(); + BYTE SCSIType; + TDriveInfo Info = {0}; + int DType = DTYPE_UNKNOWN; + char Revision[5] = {0}; + char ManagerID[17] = {0}; + char HAID[17] = {0}; + + THAUnique HAUnique; + MEMORYSTATUS MemStat; + MemStat.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus((LPMEMORYSTATUS)&MemStat); + CMapInfo MapInfo; + int HostNum; + for (HostNum=0; HostNum<NumberOfHostAdapters; HostNum++) + { + memset(Revision,0,sizeof(Revision)); + memset(ManagerID,0,sizeof(ManagerID)); + memset(HAID,0,sizeof(HAID)); + memset(&HAUnique,0,sizeof(HAUnique)); + if (HAInquiry(HostNum,ManagerID,HAID,HAUnique)) + { + if (_stricmp(HAID, "fastcdmp") == 0) //pgo: Skip Virtual CD Adapter in Bus Scan + continue; + HostAdapterMemory[HostNum]=HAUnique.MaximumTransferLen; + for (int IDNum=0; IDNum<8; IDNum++) + for (int LUNNum=0; LUNNum<=MAXLUN; LUNNum++) + { + DType=GetDeviceInfo(HostNum,IDNum,LUNNum,SCSIType,Info.VendorID,Info.ProductID,Revision,m_hDriveEvent); + if ((DType==DTYPE_CROM)|| + (DType==DTYPE_WORM)) + { + if (SCSIType) + { + int i; + for (i=0; (i<MaxMappings) && _stricmp(Info.VendorID,MapInfo.GetTypName(i)); i++); + if (i>=MaxMappings) i=1; //pgo: avoid array out of bound + Info.Type=i; + } + else + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_ATAPI); + + if (MapInfo.GetTypMapping(Info.Type)==CDTYPE_TOSHIBA) + { + char szNumbers[17] = {0}; + for (size_t i=0; i<strlen(Info.ProductID); i++) + if (isdigit(Info.ProductID[i])) + strncat(szNumbers,&Info.ProductID[i],1); + int nProductID=atoi(szNumbers); + if (((nProductID>3800) && + (nProductID<4000)) || + ((nProductID>5700) && + (nProductID<10000))) + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_TOSHNEW); + } + // pgo + else if (MapInfo.GetTypMapping(Info.Type)==CDTYPE_SONY) + { + if (SCSIType) + { + char szNumbers[17] = {0}; + for (size_t i=0; i<strlen(Info.ProductID); i++) + if (isdigit(Info.ProductID[i])) + strncat(szNumbers,&Info.ProductID[i],1); + int nProductID=atoi(szNumbers); + if ((nProductID == 140) || (nProductID == 928)) + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_CYBERDRV); + } + } + Info.ID=IDNum; + Info.LUN=LUNNum; + Info.HostAdapterNumber=HostNum; + Info.Mode=ModeBurst; + Info.MaxSektors=MemStat.dwTotalPhys/16/2352; + if (Info.MaxSektors>(HostAdapterMemory[HostNum]/2352)) + Info.MaxSektors=HostAdapterMemory[HostNum]/2352; +#ifdef Bug64 + if (Info.MaxSektors>27) Info.MaxSektors=27; +#else + if (Info.MaxSektors>446) Info.MaxSektors=446; +#endif + if (!Info.MaxSektors) Info.MaxSektors=26; + + Info.SynchSektors=3; + Info.Speed=0; + Info.PerformDATest=DATEST_FIRSTTRACK; + Info.SpinUpMode=SPINUP_NEVER; + Info.dwSpinUpTime=5; + Info.bUseLastReadableAddress=FALSE; + Info.bUseC2ErrorInfo=FALSE; + Info.bSpinDown=FALSE; + Akt=new TDriveInfoMem; + Akt->Info=Info; + Akt->Next=0; + if (!First) First=Akt; + else Last->Next=Akt; + //Last must be set to Akt + Last=Akt; + } + } + } + } + if (RunningNT) + { + //check all drives for direct access + int Index, Length; + wchar_t DriveList[128] = {0}, *pDrives = 0; + + Length=GetLogicalDriveStrings(128,DriveList); + if (Length) + { + pDrives=DriveList; + Index=0; + while (pDrives && *pDrives && (Index<Length)) + { + if (GetDriveType(pDrives)==DRIVE_CDROM) + { + wchar_t CDDevice[10]=L"\\\\.\\x:"; + HANDLE hDrive; + CharLower(pDrives); + //_strlwr(pDrives); + CDDevice[4]=pDrives[0]; + int IDNum=pDrives[0]-'a'; + + //For Windows NT 5 use other file flags + OSVERSIONINFO osver; + memset( &osver, 0x00, sizeof(osver) ); + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx( &osver ); + + DWORD dwOpenFlags = GENERIC_READ; + if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osver.dwMajorVersion > 4) ) dwOpenFlags |= GENERIC_WRITE; + + hDrive=CreateFile(CDDevice,dwOpenFlags,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); + if (hDrive!=INVALID_HANDLE_VALUE) + { + //CT> added correct host/id/lun guessing + extern int getSCSIIDFromDrive(char driveletter, int *host, int *id, int *lun); + int m_lun; + getSCSIIDFromDrive((char)pDrives[0],&HostNum,&IDNum,&m_lun); + + DType=GetDeviceInfo(HostNum,IDNum,m_lun,SCSIType,Info.VendorID,Info.ProductID,Revision,hDrive); + if ((DType==DTYPE_CROM)|| + (DType==DTYPE_WORM)) + { + SCSIMaxBlocks(hDrive,&HostAdapterMemory[HostNum]); + if (SCSIType) + { + int i; + for (i=0; (i<MaxMappings) && _stricmp(Info.VendorID,MapInfo.GetTypName(i)); i++); + if (i>=MaxMappings) i=1; //pgo: avoid array out of bound + Info.Type=i; + } + else + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_ATAPI); + if (MapInfo.GetTypMapping(Info.Type)==CDTYPE_TOSHIBA) + { + char szNumbers[17]; + szNumbers[0]=0; + for (size_t i=0; i<strlen(Info.ProductID); i++) + if (isdigit(Info.ProductID[i])) + strncat(szNumbers,&Info.ProductID[i],1); + int nProductID=atoi(szNumbers); + if (((nProductID>3800) && + (nProductID<4000)) || + ((nProductID>5700) && + (nProductID<10000))) + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_TOSHNEW); + } + // pgo + else if (MapInfo.GetTypMapping(Info.Type)==CDTYPE_SONY) + { + if (SCSIType) + { + char szNumbers[17] = {0}; + for (size_t i=0; i<strlen(Info.ProductID); i++) + if (isdigit(Info.ProductID[i])) + strncat(szNumbers,&Info.ProductID[i],1); + int nProductID=atoi(szNumbers); + if ((nProductID == 140) || (nProductID == 928)) + Info.Type=MapInfo.GetTypMappingRev(CDTYPE_CYBERDRV); + } + } + Info.ID=IDNum; + Info.LUN=0; + Info.HostAdapterNumber=HostNum; + Info.Mode=ModeNormal; + Info.MaxSektors=MemStat.dwTotalPhys/16/2352; + if (Info.MaxSektors>(HostAdapterMemory[HostNum]/2352)) + Info.MaxSektors=HostAdapterMemory[HostNum]/2352; +#ifdef Bug64 + if (Info.MaxSektors>27) Info.MaxSektors=27; +#else + if (Info.MaxSektors>446) Info.MaxSektors=446; +#endif + if (!Info.MaxSektors || + (MapInfo.GetTypMapping(Info.Type)==CDTYPE_ATAPI)) + Info.MaxSektors=26; + Info.SynchSektors=3; + Info.Speed=0; + Info.PerformDATest=DATEST_FIRSTTRACK; + Info.SpinUpMode=SPINUP_NEVER; + Info.dwSpinUpTime=5; + Info.bUseLastReadableAddress=FALSE; + Info.bUseC2ErrorInfo=FALSE; + Info.bSpinDown=FALSE; + Akt=new TDriveInfoMem; + Akt->Info=Info; + Akt->Next=0; + if (!First) First=Akt; + else Last->Next=Akt; + //Last must be set to Akt + Last=Akt; + HostNum++; + } + CloseHandle(hDrive); + } + } + pDrives+=4; + Index+=4; + } + } + } +}; + +int CMapDrive::GetMaxDrives() +{ + int i=0; + TDriveInfoMem *Akt; + Akt=First; + while (Akt) + { + i++; + Akt=Akt->Next; + } + return i; +}; + +TDriveInfo &CMapDrive::GetInfo(int index) +{ + int i=0; + TDriveInfoMem *Akt; + Akt=First; + while ((Akt) && (i<index)) + { + i++; + Akt=Akt->Next; + } + return Akt->Info; +}; + +BOOL CMapDrive::GetInfoEx(int index, TDriveInfo *&pInfo) +{ + int i=0; + TDriveInfoMem *Akt; + Akt=First; + while ((Akt) && (i<index)) + { + i++; + Akt=Akt->Next; + } + if (!Akt) + return FALSE; + pInfo=&Akt->Info; + return TRUE; +}; + +void CMapDrive::DeleteInfo(int index) +{ + int i=0; + TDriveInfoMem *Akt,*Prev; + Akt=First; + Prev=0; + while ((Akt) && (i<index)) + { + i++; + Prev=Akt; + Akt=Akt->Next; + } + if (!Akt) return; + if (Prev) Prev->Next=Akt->Next; + else First=Akt->Next; + delete Akt; +}; + +int CMapDrive::GetMaxHostAdapters() +{ + return NumberOfHostAdapters; +}; + +int CMapDrive::GetSupportedHostAdapterMemory(int index) +{ + if ((index<NumberOfHostAdapters) && + (index>=0)) + return HostAdapterMemory[index]; + else + return -1; +}; + +void CMapDrive::SetSupportedHostAdapterMemory(int index,int Memory) +{ + if ((index<NumberOfHostAdapters) && + (index>=0)) + HostAdapterMemory[index]=Memory; +} + +int CMapDrive::GetMaxSektors(int HostAdapterNumber) +{ +#ifdef Bug64 + int Result=HostAdapterMemory[HostAdapterNumber]/2352; + if (Result>27) + Result=27; + return Result; +#else + return HostAdapterMemory[HostAdapterNumber]/2352; +#endif +}; + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CMapInfoJuke - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Implement the information of the TypeMappings - +// ---------------------------------------------------------------------------------------- +CMapInfoJuke::CMapInfoJuke() +{ + strncpy(TypNamen[0],"SONY ", 9); + strncpy(TypNamen[1],"PIONEER ", 9); + int const t[]={JUKETYPE_SONY,JUKETYPE_PIONEER}; + for (int i=0; i<MaxMappingsJuke; i++) + TypMapping[i]=t[i]; +} + +char *CMapInfoJuke::GetTypName(int Index) +{ + return TypNamen[Index]; +}; + +int CMapInfoJuke::GetTypMapping(int Index) +{ + return TypMapping[Index]; +}; + +int CMapInfoJuke::GetTypMappingRev(int JukeType) +{ + int Index=0; + while ((Index<MaxMappingsJuke) && + (TypMapping[Index]!=JukeType)) + Index++; + return Index; +}; + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CMapJuke - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Administration of the jukebox configuration - +// ---------------------------------------------------------------------------------------- +CMapJuke::CMapJuke(BOOL bDoReset) +{ + First=0; + + m_hJukeEvent=INVALID_HANDLE_VALUE; + wchar_t szEventName[32] = {0}; + wsprintf(szEventName,L"%X",this); + m_hJukeEvent=CreateEvent(NULL,TRUE,FALSE,szEventName); + if (bDoReset) + Reset(); +}; + +CMapJuke::~CMapJuke() +{ + DeleteAll(); + if (m_hJukeEvent!=INVALID_HANDLE_VALUE) + CloseHandle(m_hJukeEvent); +}; + +void CMapJuke::DeleteAll() +{ + TJukeInfoMem *Akt; + Akt=First; + while (First) + { + Akt=First; + First=Akt->Next; + if (Akt->Info.pConnectedDrives) + delete Akt->Info.pConnectedDrives; + delete Akt; + } +}; + +void CMapJuke::Reset() +{ + TJukeInfoMem *Akt,*Last; + DeleteAll(); + BYTE SCSIType = 0; + TJukeInfo Info = {0}; + int DType = DTYPE_UNKNOWN; + char Revision[5] = {0}; + char ManagerID[17] = {0}; + char HAID[17] = {0}; + + THAUnique HAUnique; + CMapInfoJuke MapInfo; + for (int HostNum=0; HostNum<NumberOfHostAdapters; HostNum++) + { + memset(Revision,0,sizeof(Revision)); + memset(ManagerID,0,sizeof(ManagerID)); + memset(HAID,0,sizeof(HAID)); + memset(&HAUnique,0,sizeof(HAUnique)); + if (HAInquiry(HostNum,ManagerID,HAID,HAUnique)) + { + for (int IDNum=0; IDNum<8; IDNum++) + { + for (int LUNNum=0; LUNNum<=MAXLUN; LUNNum++) + { + memset(&Info,0,sizeof(Info)); + DType=GetDeviceInfo(HostNum,IDNum,LUNNum,SCSIType,Info.VendorID,Info.ProductID,Revision,m_hJukeEvent); + if (DType==DTYPE_JUKE) + { + int i; + for (i=0; (i<MaxMappingsJuke) && _stricmp(Info.VendorID,MapInfo.GetTypName(i)); i++); + if (_stricmp(Info.VendorID,MapInfo.GetTypName(i))) i=JUKETYPE_SONY; + Info.Type=i; + switch (Info.Type) + { + case JUKETYPE_PIONEER : + Info.MaxDrives=4; //currently only data for the 500x changer implemeneted + Info.MaxDiscs=500; + break; + case JUKETYPE_SONY : + default: + Info.MaxDrives=2; + Info.MaxDiscs=100; + break; + } + Info.pConnectedDrives=new int[Info.MaxDrives]; + for (int nDriveNum=0; nDriveNum<Info.MaxDrives; nDriveNum++) + Info.pConnectedDrives[nDriveNum]=-1; + Info.ID=IDNum; + Info.LUN=LUNNum; + Info.HostAdapterNumber=HostNum; + + Akt=new TJukeInfoMem; + Akt->Info=Info; + Akt->bIsWorking=FALSE; + Akt->Next=0; + if (!First) First=Akt; + else Last->Next=Akt; + //Last must be set to Akt + Last=Akt; + } + } + } + } + } +}; + +int CMapJuke::GetMaxJukes() +{ + int i=0; + TJukeInfoMem *Akt; + Akt=First; + while (Akt) + { + i++; + Akt=Akt->Next; + } + return i; +}; + +TJukeInfo &CMapJuke::GetInfo(int index) +{ + int i=0; + TJukeInfoMem *Akt; + Akt=First; + while ((Akt) && (i<index)) + { + i++; + Akt=Akt->Next; + } + return Akt->Info; +}; + +BOOL CMapJuke::IsWorking(int index) +{ + int i=0; + TJukeInfoMem *Akt; + Akt=First; + while ((Akt) && (i<index)) + { + i++; + Akt=Akt->Next; + } + return Akt->bIsWorking; +}; + +void CMapJuke::SetWorking(int index,BOOL bIsWorking) +{ + int i=0; + TJukeInfoMem *Akt; + Akt=First; + while ((Akt) && (i<index)) + { + i++; + Akt=Akt->Next; + } + Akt->bIsWorking=bIsWorking; +}; + +void CMapJuke::DeleteInfo(int index) +{ + int i=0; + TJukeInfoMem *Akt,*Prev; + Akt=First; + Prev=0; + while ((Akt) && (i<index)) + { + i++; + Prev=Akt; + Akt=Akt->Next; + } + if (!Akt) return; + if (Prev) Prev->Next=Akt->Next; + else First=Akt->Next; + if (Akt->Info.pConnectedDrives) + delete Akt->Info.pConnectedDrives; + delete Akt; +}; + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CJukeBox - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Control the basic JukeBox functions over ASPI - +// ---------------------------------------------------------------------------------------- +CJukeBox::CJukeBox (TJukeInfo &xInfo):Config(xInfo) +{ + m_hJukeEvent=INVALID_HANDLE_VALUE; + wchar_t szEventName[32] = {0}; + wsprintf(szEventName,L"%X",this); + m_hJukeEvent=CreateEvent(NULL,TRUE,FALSE,szEventName); + assert(m_hJukeEvent); +} + +CJukeBox::~CJukeBox() +{ + if (m_hJukeEvent!=INVALID_HANDLE_VALUE) + CloseHandle(m_hJukeEvent); +} + +BOOL CJukeBox::MoveMedium(int Source,int Destination) +{ + switch (MapInfo.GetTypMapping(Config.Type)) + { + case JUKETYPE_PIONEER : + if ((Source<1) || (Source>Config.MaxDiscs)) + if ((Source<0x4000) || (Source>=(0x4000+Config.MaxDrives))) + return FALSE; + if ((Destination<1) || (Destination>Config.MaxDiscs)) + if ((Destination<0x4000) || (Destination>=(0x4000+Config.MaxDrives))) + return FALSE; + break; + case JUKETYPE_SONY : + default: + if ((Source<1) || (Source>Config.MaxDiscs)) + { + if ((Source<0x4000) || (Source>=(0x4000+Config.MaxDrives))) + return FALSE; + else + Source-=0x3fff; + } + else + Source+=10; + if ((Destination<1) || (Destination>Config.MaxDiscs)) + { + if ((Destination<0x4000) || (Destination>=(0x4000+Config.MaxDrives))) + return FALSE; + else + Destination-=0x3fff; + } + else + Destination+=10; + break; + } + + while (!TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hJukeEvent)); + TOpcode OpC; + OpC[0]=0xa5; + OpC[1]=Config.LUN>>5; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=Source/256; + OpC[5]=Source%256; + OpC[6]=Destination/256; + OpC[7]=Destination%256; + OpC[8]=0x00; + OpC[9]=0x00; + OpC[10]=0x00; + OpC[11]=0x00; + return ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,12,NULL,0,m_hJukeEvent); +} + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CBaseCD - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: The drive independent functions to access the CD-ROM drives - +// ---------------------------------------------------------------------------------------- +int CBaseCD::Lasterror() +{ + int h; + h=Error; + Error=CDOK; + return h; +} + +int CBaseCD::ReadFirstTrackInfo(TTrackList &Infos) +{ + if (!FirstTrack) return 0; + AktTrack=FirstTrack; + Infos=AktTrack->Info; + return 1; +} + +int CBaseCD::ReadNextTrackInfo(TTrackList &Infos) +{ + if ((!FirstTrack) || + (!AktTrack->Next)) return 0; + AktTrack=AktTrack->Next; + Infos=AktTrack->Info; + return 1; +} + +int CBaseCD::ReadPrevTrackInfo(TTrackList &Infos) +{ + if ((!FirstTrack) || + (!AktTrack->Prev)) return 0; + AktTrack=AktTrack->Prev; + Infos=AktTrack->Info; + return 1; +} + +int CBaseCD::ReadTrackInfo(TTrackList &Infos) +{ + if ((!FirstTrack) || + (Infos.TrackNummer<1)) return 0; + if (!AktTrack) + AktTrack=FirstTrack; + if (AktTrack->Info.TrackNummer==Infos.TrackNummer) + { + Infos=AktTrack->Info; + return 1; + } + while ((AktTrack->Info.TrackNummer>Infos.TrackNummer) && + (AktTrack->Prev)) + AktTrack=AktTrack->Prev; + while ((AktTrack->Info.TrackNummer<Infos.TrackNummer) && + (AktTrack->Next)) + AktTrack=AktTrack->Next; + if (AktTrack->Info.TrackNummer!=Infos.TrackNummer) return 0; + Infos=AktTrack->Info; + return 1; +} + +int CBaseCD::ReadMaxTracks() +{ + TTrackListeMem *Laeufer; + if (!FirstTrack) return 0; + Laeufer=AktTrack; + while (Laeufer->Next) + Laeufer=Laeufer->Next; + return Laeufer->Info.TrackNummer; +} + +void CBaseCD::DeleteTrackList() +{ + while (FirstTrack) + { + AktTrack=FirstTrack->Next; + delete FirstTrack; + FirstTrack=AktTrack; + } +} + + +// ---------------------------------------------------------------------------------------- +// - Implementation of the class members of CSCSICD - +// - - +// - Author: Christoph Schmelnik - +// - Purpose: Control the basic CDROM functions over ASPI - +// ---------------------------------------------------------------------------------------- +CSCSICD::CSCSICD (char drive, TDriveInfo &xInfo):Config(xInfo) +{ + m_bSpeedTableInitialized=FALSE; + FirstTrack=0; + NECRotationSpeed = 0; // pgo + Changed=FALSE; + CDPresentLast=TRUE; + Error=CDOK; + m_hDriveEvent=INVALID_HANDLE_VALUE; + memset(&m_SenseInfo,0,sizeof(TSenseInfo)); + if ((Config.HostAdapterNumber>=NumberOfHostAdapters) && + RunningNT) + { + DWORD dwFlags; + OSVERSIONINFO osver; + wchar_t CDDevice[10]=L"\\\\.\\x:"; + CDDevice[4]=(wchar_t)drive;//(Config.HostAdapterNumber + 'A'/* + 1*/); + //For Windows NT 5 use other file flags + memset( &osver, 0x00, sizeof(osver) ); + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx( &osver ); + + // if Win2K or greater, add GENERIC_WRITE + dwFlags = GENERIC_READ; + if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osver.dwMajorVersion > 4) ) dwFlags |= GENERIC_WRITE; + + m_hDriveEvent = CreateFile( CDDevice, dwFlags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + } + else + { + wchar_t szEventName[32] = {0}; + wsprintf(szEventName,L"%X",this); + m_hDriveEvent=CreateEvent(NULL,TRUE,FALSE,szEventName); + assert(m_hDriveEvent); + } + TDriveStatus DInfo=Get_DriveStatus(); + if (DInfo.CDPresent) ReRead(); +} + +CSCSICD::~CSCSICD() +{ + DeleteTrackList(); + if (m_hDriveEvent!=INVALID_HANDLE_VALUE) + CloseHandle(m_hDriveEvent); +} + +void CSCSICD::PrepareCDDA() +{ + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + { + memset(&ModeData,0,sizeof(ModeData)); + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,0,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + ModeData[0]=0; + TDriveMode ModeSelectData; + ModeSelectData[0]=0x00; + ModeSelectData[1]=0x00; + ModeSelectData[2]=0x00; + ModeSelectData[3]=0x08; + ModeSelectData[4]=0x82; + ModeSelectData[5]=0x00; + ModeSelectData[6]=0x00; + ModeSelectData[7]=0x00; + ModeSelectData[8]=0x00; + ModeSelectData[9]=0x00; + ModeSelectData[10]=0x09; + ModeSelectData[11]=0x30; + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSelectData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_TOSHNEW : + { + memset(&ModeData,0,sizeof(ModeData)); + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,15,0x20,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + ModeData[0]=0; + TDriveMode ModeSelectData; + ModeSelectData[0]=0x00; + ModeSelectData[1]=0x00; + ModeSelectData[2]=0x00; + ModeSelectData[3]=0x08; + ModeSelectData[4]=0x82; + ModeSelectData[5]=0x00; + ModeSelectData[6]=0x00; + ModeSelectData[7]=0x00; + ModeSelectData[8]=0x00; + ModeSelectData[9]=0x00; + ModeSelectData[10]=0x09; + ModeSelectData[11]=0x30; + + ModeSelectData[12]=0x20; + ModeSelectData[13]=0x01; + ModeSelectData[14]=(ModeData[14] & 0xcf)|0x10; + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSelectData,15,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_NEC : + { + memset(&ModeData,0,sizeof(ModeData)); + if (!addModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + NECRotationSpeed=ModeData[6] & 0x20; + ModeData[6]=ModeData[6]|0x20; + if (!addModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_PHILIPS : + case CDTYPE_MATSHITA : + { + memset(&ModeData,0,sizeof(ModeData)); + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,0,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + ModeData[0]=0; + TDriveMode ModeSelectData; + ModeSelectData[0]=0x00; + ModeSelectData[1]=0x00; + ModeSelectData[2]=0x00; + ModeSelectData[3]=0x08; + ModeSelectData[4]=0x00; + ModeSelectData[5]=0x00; + ModeSelectData[6]=0x00; + ModeSelectData[7]=0x00; + ModeSelectData[8]=0x00; + ModeSelectData[9]=0x00; + ModeSelectData[10]=0x09; + ModeSelectData[11]=0x30; + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSelectData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + } +} + +void CSCSICD::ReadCDDA(CCDAdress StartSektor,long Sektoranzahl,void *Buffer,BOOL bUseC2ErrorInfo) +{ + TOpcode OpC; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=LOBYTE(HIWORD(StartSektor.GetHSG())); + OpC[4]=HIBYTE(LOWORD(StartSektor.GetHSG())); + OpC[5]=LOBYTE(LOWORD(StartSektor.GetHSG())); + OpC[6]=0x00; + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + case CDTYPE_TOSHNEW : + { + OpC[0]=0x28; + OpC[7]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[8]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[9]=0x00; + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,Buffer,Sektoranzahl*2352,ReadSRB,m_hDriveEvent); + break; + } + case CDTYPE_SONY : + case CDTYPE_RICOH : + case CDTYPE_PLEXTOR : + { + OpC[0]=0xD8; + OpC[7]=0x00; + OpC[8]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[9]=LOBYTE(LOWORD(Sektoranzahl)); + // benski + if (bUseC2ErrorInfo) + OpC[10]=0x04; + else + OpC[10]=0x00; + OpC[11]=0x00; + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,12,Buffer,(bUseC2ErrorInfo)?(Sektoranzahl*2646):(Sektoranzahl*2352),ReadSRB,m_hDriveEvent); + break; + } + case CDTYPE_NEC : + { + OpC[0]=0xD4; + OpC[7]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[8]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[9]=0x00; + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,Buffer,Sektoranzahl*2352,ReadSRB,m_hDriveEvent); + break; + } + case CDTYPE_MATSHITA : + { + OpC[0]=0xD4; + OpC[7]=0x00; + OpC[8]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[9]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[10]=0x00; + OpC[11]=0x00; + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,12,Buffer,Sektoranzahl*2352,ReadSRB,m_hDriveEvent); + break; + } + case CDTYPE_PHILIPS : + { + OpC[0]=0x28; + OpC[7]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[8]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[9]=0x00; + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,Buffer,Sektoranzahl*2352,ReadSRB,m_hDriveEvent); + break; + } + case CDTYPE_ATAPI : + case CDTYPE_CYBERDRV : + { + OpC[0]=0xBE; + OpC[1]=0x04; + OpC[7]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[8]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[9]=0xF0; + // benski + if (bUseC2ErrorInfo) + OpC[9]|=2; // flag 2 is supposed to mean check for C2 error info + OpC[10]=0x00; + OpC[11]=0x00; + // with C2 error info, our sector size is now 2646 bytes + FillSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,12,Buffer,bUseC2ErrorInfo?(Sektoranzahl*2646):(Sektoranzahl*2352),ReadSRB,m_hDriveEvent); + break; + } + } + ExecuteSCSIRequest(ReadSRB,m_hDriveEvent); + StartReadTime=GetTickCount(); +} + +BOOL CSCSICD::WaitCDDA(BOOL bImmediate) +{ + BYTE Status=WaitSCSIRequest(ReadSRB,m_hDriveEvent,bImmediate); + if ((Status!=SS_PENDING) && + (Status!=SS_COMP)) + { + memcpy(&m_SenseInfo,&ReadSRB.SenseArea,SENSE_LEN); + Error=CDASPIError; + } + if ((Status==SS_PENDING) && + !bImmediate) + { + DWORD AktReadTime=GetTickCount(); + if (abs((long long)AktReadTime-StartReadTime)>12000) + { + AbortSCSIRequest(ReadSRB); + Error=CDTimeOut; + Status=SS_COMP; + } + } + return (Status!=SS_PENDING); +} + +void CSCSICD::FinishCDDA() +{ + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + { + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_TOSHNEW : + { + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,15,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_NEC : + { + ModeData[6]=ModeData[6]|NECRotationSpeed; + if (!addModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + case CDTYPE_PHILIPS : + case CDTYPE_MATSHITA : + { + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + break; + } + } +} + +void CSCSICD::SortWaveData(DWORD *Data,int Samples) +{ + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_PHILIPS : +// RICOH Drives doesn't seem to swap the bytes +// This has been evaluated with the CD-RW drives +// So they are even just handled like SONY drives, but i don't remove this type +// case CDTYPE_RICOH : + { + for (int i=0; i<Samples; i++) + Data[i]=((Data[i]&0xff00ff00)>>8)| + ((Data[i]&0x00ff00ff)<<8); + break; + } + } +} + +CCDAdress CSCSICD::GetErrorAdress() +{ + CCDAdress h; + h.SetHSG(0); + if ((Error!=CDOK)&& + (ReadSRB.SRB_TargStat==STATUS_CHKCOND)) + h.SetHSG((ReadSRB.SenseArea[3]<<24)+ + (ReadSRB.SenseArea[4]<<16)+ + (ReadSRB.SenseArea[5]<<8)+ + ReadSRB.SenseArea[6]); + return h; +} + +void CSCSICD::Play_Audio(CCDAdress StartSektor,long Sektoranzahl) +{ + while (!TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hDriveEvent)); + TOpcode OpC; + OpC[0]=0x45; + OpC[1]=0x00; + OpC[2]=HIBYTE(HIWORD(StartSektor.GetHSG())); + OpC[3]=LOBYTE(HIWORD(StartSektor.GetHSG())); + OpC[4]=HIBYTE(LOWORD(StartSektor.GetHSG())); + OpC[5]=LOBYTE(LOWORD(StartSektor.GetHSG())); + OpC[6]=0x00; + OpC[7]=HIBYTE(LOWORD(Sektoranzahl)); + OpC[8]=LOBYTE(LOWORD(Sektoranzahl)); + OpC[9]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,10,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +void CSCSICD::Stop_Audio() +{ + while (!TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hDriveEvent)); + TOpcode OpC; +/* OpC[0]=0x1b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; +*/ + OpC[0]=0x2b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x00; + OpC[9]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,10,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +void CSCSICD::Pause_Audio() +{ + while (!TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hDriveEvent)); + TOpcode OpC; + OpC[0]=0x4b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x00; + OpC[9]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,10,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +void CSCSICD::Resume_Audio() +{ + while (!TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hDriveEvent)); + TOpcode OpC; + OpC[0]=0x4b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x01; + OpC[9]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,10,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +TDriveStatus CSCSICD::Get_DriveStatus() +{ + TDriveStatus h = {0}; +/* TOpcode OpC; + TQChannelInfo ChannelInfo; + BOOL b; + memset(&ChannelInfo,0,sizeof(ChannelInfo)); + OpC[0]=0x42; + OpC[1]=0x02; + OpC[2]=0x40; + OpC[3]=0x01; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=sizeof(ChannelInfo); + OpC[9]=0x00; + if (MapInfo.GetTypMapping(Config.Type)==CDTYPE_ATAPI) + { + OpC[10]=0; + OpC[11]=0; + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,12,(void *)&ChannelInfo,sizeof(ChannelInfo),m_hDriveEvent); + } + else + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,10,(void *)&ChannelInfo,sizeof(ChannelInfo),m_hDriveEvent); + if (b && ChannelInfo.DataLen) +*/ + if (TestUnitReady(Config.HostAdapterNumber,Config.ID,Config.LUN,m_hDriveEvent)) + h.CDPresent=TRUE; + else + h.CDPresent=FALSE; + if (h.CDPresent!=CDPresentLast) Changed=TRUE; + CDPresentLast=h.CDPresent; + return h; +} + +BOOL CSCSICD::MediaChanged() +{ + BOOL h; + h=Changed; + //if (CDPresentLast) + Changed=FALSE; + return h; +} + +TAudioStatus CSCSICD::Get_AudioStatus_Info() +{ + TAudioStatus h; + TOpcode OpC; + TQChannelInfo ChannelInfo; + BOOL b; + memset(&ChannelInfo,0,sizeof(ChannelInfo)); + OpC[0]=0x42; + OpC[1]=0x02; + OpC[2]=0x40; + OpC[3]=0x01; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x10; + OpC[9]=0x00; + h.Pause=FALSE; + h.IsPlaying=FALSE; + h.IsDone=FALSE; + h.PlayError=FALSE; + if (MapInfo.GetTypMapping(Config.Type)==CDTYPE_ATAPI) + { + OpC[10]=0; + OpC[11]=0; + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,12,(void *)&ChannelInfo,16,m_hDriveEvent); + } + else + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,(void *)&ChannelInfo,16,m_hDriveEvent); + if (b && ChannelInfo.DataLen) + { +// if (!CDPresentLast) Changed=TRUE; +// CDPresentLast=TRUE; + switch (ChannelInfo.AudioStatus) + { + case 0x11 : h.IsPlaying=TRUE; break; + case 0x12 : h.Pause=TRUE; break; + case 0x13 : h.IsDone=TRUE; break; + case 0x14 : h.PlayError=TRUE; break; + } + h.AbsSektor.SetRedbook(ChannelInfo.AbsCDAdress); + h.RelSektor.SetRedbook(ChannelInfo.RelTrackAdress); + h.TrackNummer=ChannelInfo.TrackNumber; + } + else + { +// if (CDPresentLast) Changed=TRUE; +// CDPresentLast=FALSE; + h.PlayError=TRUE; + Error=CDNoCD; + } + return h; +} + +void CSCSICD::Get_MediaCatalogNumber(char szUPC[16]) +{ + TOpcode OpC; + BYTE Info[24] = {0}; + BOOL b; + szUPC[0]=0; + OpC[0]=0x42; + OpC[1]=0x02; + OpC[2]=0x40; + OpC[3]=0x02; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=sizeof(Info); + OpC[9]=0x00; + if (MapInfo.GetTypMapping(Config.Type)==CDTYPE_ATAPI) + { + OpC[10]=0; + OpC[11]=0; + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,12,(void *)&Info,sizeof(Info),m_hDriveEvent); + } + else + b=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,(void *)&Info,sizeof(Info),m_hDriveEvent); + if (b && (Info[8]&0x80)) + { + BOOL bIsEmpty=TRUE; + for (int i=0; i<15; i++) + { + BYTE Value=Info[i+9]; + if (Value) + bIsEmpty=FALSE; + if (Value<10) + Value+=0x30; + szUPC[i]=Value; + } + szUPC[15]=0; + if (bIsEmpty) + szUPC[0]=0; + } +} + +void CSCSICD::EjectDisk() +{ + TOpcode OpC; + OpC[0]=0x1b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x02; + OpC[5]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,6,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +void CSCSICD::LockDoor(int Lock) +{ + TOpcode OpC; + OpC[0]=0x1e; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=((BYTE) Lock) & 1; + OpC[5]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,6,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +void CSCSICD::CloseTray() +{ + TOpcode OpC; + OpC[0]=0x1b; + OpC[1]=0x00; + OpC[2]=0x00; + OpC[3]=0x00; + OpC[4]=0x03; + OpC[5]=0x00; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,0,OpC,6,NULL,0,m_hDriveEvent)) + Error=CDDriveNotReady; +} + +int Swap(int value) +{ + int result=(value & 0xff000000)>>24; + result|=(value & 0x00ff0000)>>8; + result|=(value & 0x0000ff00)<<8; + result|=(value & 0x000000ff)<<24; + return result; +} + +void CSCSICD::ReRead() +{ + DeleteTrackList(); + m_bSpeedTableInitialized=FALSE; + TTOCHeader TOCHeader; + memset(&TOCHeader,0,sizeof(TOCHeader)); + TOpcode OpC; + OpC[0]=0x43; + OpC[1]=0; + OpC[2]=0; + OpC[3]=0; + OpC[4]=0; + OpC[5]=0; + OpC[6]=0; + OpC[7]=HIBYTE(sizeof(TTOCHeader)); + OpC[8]=LOBYTE(sizeof(TTOCHeader)); + OpC[9]=0; + + BOOL r=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,(void*)&TOCHeader,sizeof(TOCHeader),m_hDriveEvent); + if (r && TOCHeader.FirstTrack && TOCHeader.LastTrack) + { + TTrackListeMem *Last; + CCDAdress Ende; + Last=FirstTrack; + for (int i=TOCHeader.FirstTrack; i<=TOCHeader.LastTrack; i++) + { + AktTrack=new TTrackListeMem; + //AbsCDAdress + //AdrCtrl + AktTrack->Info.TrackNummer=TOCHeader.Info[i-1].TrackNummer; + AktTrack->Info.StartSektor.SetHSG(Swap(TOCHeader.Info[i-1].AbsCDAdress)+150); + Ende.SetHSG(Swap(TOCHeader.Info[i].AbsCDAdress)+150); + AktTrack->Info.Laenge=Ende.GetHSG()-AktTrack->Info.StartSektor.GetHSG(); + AktTrack->Info.StartSektor.SetHSG(AktTrack->Info.StartSektor.GetHSG()-150); + if (TOCHeader.Info[i-1].AdrCtrl & 8) + AktTrack->Info.Flags.AudioChannels=4; + else + AktTrack->Info.Flags.AudioChannels=2; + AktTrack->Info.Flags.PreEmphasis=(TOCHeader.Info[i-1].AdrCtrl & 1); + AktTrack->Info.Flags.DataTrack=(TOCHeader.Info[i-1].AdrCtrl & 4); + AktTrack->Info.Flags.CopyProhibeted=!(TOCHeader.Info[i-1].AdrCtrl & 2); + AktTrack->Prev=Last; + AktTrack->Next=0; + if (FirstTrack) + Last->Next=AktTrack; + else + FirstTrack=AktTrack; + Last=AktTrack; + } + // check for CD-Extra + if (AktTrack) + { + if (AktTrack->Info.Flags.DataTrack) + { + Last=AktTrack->Prev; + if (Last && !Last->Info.Flags.DataTrack) + { + if (Last->Info.Laenge>11400) + Last->Info.Laenge-=11400; + } + } + } + } + else + { + if (CDPresentLast) Changed=TRUE; + CDPresentLast=FALSE; + Error=CDDriveNotReady; + } +} + +CCDAdress CSCSICD::GetLastReadableAddress(CCDAdress StartSektor) +{ + CCDAdress LastSektor; + BYTE RetVal[8] = {0}; + TOpcode OpC; + OpC[0]=0x25; + OpC[1]=0; + OpC[2]=HIBYTE(HIWORD(StartSektor.GetHSG())); + OpC[3]=LOBYTE(HIWORD(StartSektor.GetHSG())); + OpC[4]=HIBYTE(LOWORD(StartSektor.GetHSG())); + OpC[5]=LOBYTE(LOWORD(StartSektor.GetHSG())); + OpC[6]=0; + OpC[7]=0; + OpC[8]=1; //Set PMI Bit + OpC[9]=0; + + BOOL r=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,10,(void*)&RetVal,sizeof(RetVal),m_hDriveEvent); + if (!r) + return StartSektor; + LastSektor.SetHSG((RetVal[0]<<24)+(RetVal[1]<<16)+(RetVal[2]<<8)+RetVal[3]); + return LastSektor; +} + +int CSCSICD::GetMaxSektors() +{ + return Config.MaxSektors; +}; + +int CSCSICD::GetSynchSektors() +{ + return Config.SynchSektors; +}; + +int CSCSICD::GetMode() +{ + return Config.Mode; +}; + +int CSCSICD::GetSpeed() +{ + return Config.Speed; +}; + +TSenseInfo CSCSICD::GetSense() +{ + TSenseInfo SenseInfo; + memset(&SenseInfo,0,sizeof(SenseInfo)); + TOpcode OpC; + OpC[0]=0x03; + OpC[1]=0; + OpC[2]=0; + OpC[3]=0; + OpC[4]=sizeof(SenseInfo); + OpC[5]=0; + + BOOL r=ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_IN,OpC,6,(void*)&SenseInfo,sizeof(SenseInfo),m_hDriveEvent); + if (!r) + memset(&SenseInfo,0,sizeof(SenseInfo)); + return SenseInfo; +} + +TSenseInfo CSCSICD::GetLastSenseInfo() +{ + TSenseInfo Info=m_SenseInfo; + memset(&m_SenseInfo,0,sizeof(TSenseInfo)); + return Info; +} + +void CSCSICD::InitSpeedTable() +{ + if (m_bSpeedTableInitialized) + return; + SupportedSpeeds=0; + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + break; + case CDTYPE_TOSHNEW : + { + SpeedTable[0]=2352*75; + SpeedTable[1]=2352*75*4; + SpeedTable[2]=2352*75*4; + SpeedTable[3]=-2; + SupportedSpeeds=4; + break; + } + case CDTYPE_SONY : + case CDTYPE_RICOH : + case CDTYPE_ATAPI : + case CDTYPE_CYBERDRV : + { + int LastSpeed=GetCurrentSpeed(); + int Speed=65532000; + BOOL bFound=FALSE; + while (!bFound && (Speed>0)) + { + SetCurrentSpeed(Speed); + if (Lasterror()==CDOK) + { + int ResultingSpeed=GetCurrentSpeed(); + if (Lasterror()==CDOK) + { + bFound=FALSE; + for (int i=0; i<SupportedSpeeds; i++) + { + if (SpeedTable[i]==ResultingSpeed) + bFound=TRUE; + } + if (!bFound) + { + SpeedTable[SupportedSpeeds]=ResultingSpeed; + SupportedSpeeds++; + Speed=ResultingSpeed-2352*75; + } + else + { + Speed-=(2352*75); + bFound=FALSE; + } + } + } + else + Speed=0; + } + if (SupportedSpeeds>1) + { + //Swap entries + for (int i=0; i<(SupportedSpeeds/2); i++) + { + int Help=SpeedTable[i]; + SpeedTable[i]=SpeedTable[SupportedSpeeds-1-i]; + SpeedTable[SupportedSpeeds-1-i]=Help; + } + } + SetCurrentSpeed(LastSpeed); + break; + } + case CDTYPE_PLEXTOR : + { + int LastSpeed=GetCurrentSpeed(); + for (int index=1; index<=20; index++) + { + SetCurrentSpeed(index*2352*75); + if (Lasterror()==CDOK) + { + int Speed=GetCurrentSpeed(); + if (Lasterror()==CDOK) + { + BOOL found=FALSE; + for (int i=0; i<SupportedSpeeds; i++) + { + if (SpeedTable[i]==Speed) + found=TRUE; + } + if (!found) + { + SpeedTable[SupportedSpeeds]=Speed; + SupportedSpeeds++; + } + } + } + } + SetCurrentSpeed(LastSpeed); + break; + } + case CDTYPE_NEC : + { + break; + } + case CDTYPE_PHILIPS : + case CDTYPE_MATSHITA : + { + int LastSpeed=GetCurrentSpeed(); + SpeedTable[0]=-1; + SupportedSpeeds++; + for (int index=1; index<8; index++) + { + SetCurrentSpeed(2352*75*index); + if (Lasterror()==CDOK) + { + int Speed=GetCurrentSpeed(); + if ((Lasterror()==CDOK) && + (Speed==2352*75*index)) + { + SpeedTable[SupportedSpeeds]=2352*75*index; + SupportedSpeeds++; + } + } + } + SetCurrentSpeed(LastSpeed); + break; + } + } + m_bSpeedTableInitialized=TRUE; +} + +BYTE CSCSICD::GetSupportedSpeeds() +{ + return SupportedSpeeds; +} + +BOOL IsOldPhilips(TDriveInfo *pConfig) +{ + BOOL bResult=FALSE; + if (strstr(pConfig->ProductID,"2000")) + bResult=TRUE; + if (strstr(pConfig->ProductID,"4020")) + bResult=TRUE; + return bResult; +} + +//return the identifictaion number for the plextor models +//defined values: +#define PX4X 0 +#define PX6X 1 +#define PX8X 2 +#define PX12X 3 +#define PX20X 4 +#define PX32X 5 +#define PXR412 6 +#define PX40X 7 + +DWORD GetPlextorModel(TDriveInfo *pConfig) +{ + DWORD dwResult=PX40X; + char szId[7] = {0}; + strncpy(szId,&pConfig->ProductID[10],6); + szId[6]=0; + if (!_stricmp(szId,"W4220T")) + { + dwResult=PXR412; + } + else + { + if (!_stricmp(szId,"W8220T")) + { + dwResult=PXR412; + } + else + { + szId[5]=0; + if (!_stricmp(szId,"R412C")) + { + dwResult=PXR412; + } + else + { + if (!_stricmp(szId,"R820T")) + { + dwResult=PXR412; + } + else + { + szId[2]=0; + if (!strcmp(szId,"40")) + dwResult=PX40X; + else + { + if (!strcmp(szId,"32")) + dwResult=PX32X; + else + { + if (!strcmp(szId,"20")) + dwResult=PX20X; + else + { + if (!strcmp(szId,"12")) + dwResult=PX12X; + else + { + if (!isdigit(szId[1])) + szId[1]=0; + if (!strcmp(szId,"8")) + dwResult=PX8X; + else + { + if (!strcmp(szId,"6")) + dwResult=PX6X; + else + { + if (!strcmp(szId,"4")) + dwResult=PX4X; + } + } + } + } + } + } + } + } + } + } + return dwResult; +} + +int CSCSICD::GetCurrentSpeed() +{ + TDriveMode ModeSenseData; + int Speed=0; + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + { + Speed=0; + break; + } + case CDTYPE_TOSHNEW : + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,15,0x20,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + int Index=(ModeSenseData[14] & 0x30)>>4; + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*4; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=-2; + break; + } + break; + } + case CDTYPE_SONY : + case CDTYPE_RICOH : + case CDTYPE_CYBERDRV : + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,34,0x2A,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + Speed=(ModeSenseData[26]*256+ModeSenseData[27])*1000; + break; + } + case CDTYPE_ATAPI : + { + if (!ATAPIModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,34,0x2A,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + if ((ModeSenseData[8]&0x3F)==0x2A) + Speed=(ModeSenseData[22]*256+ModeSenseData[23])*1000; + else if ((ModeSenseData[4]&0x3F)==0x2A) + Speed=(ModeSenseData[18]*256+ModeSenseData[19])*1000; + else Speed=-1; + break; + } + case CDTYPE_PLEXTOR : + { + DWORD dwModel=GetPlextorModel(&Config); + if (dwModel!=PXR412) + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,16,0x31,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + int Index=ModeSenseData[14]; + switch (dwModel) + { + case PX4X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + default : + Speed=-1; + break; + } + break; + } + case PX6X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*4; + break; + case 2 : + Speed=2352*75*6; + break; + default : + Speed=-1; + break; + } + break; + } + case PX8X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=2352*75*8; + break; + default : + Speed=-1; + break; + } + break; + } + case PX12X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=2352*75*8; + break; + case 4 : + Speed=2352*75*8; + break; + case 5 : + Speed=2352*75*12; + break; + default : + Speed=-1; + break; + } + break; + } + case PX20X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=2352*75*8; + break; + case 4 : + Speed=2352*75*8; + break; + case 5 : + Speed=-2; + break; + case 6 : + Speed=2352*75*12; + break; + default : + Speed=-1; + break; + } + break; + } + case PX32X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=2352*75*8; + break; + case 4 : + Speed=2352*75*8; + break; + case 5 : + Speed=2352*75*8; + break; + case 6 : + Speed=2352*75*14; + break; + default : + Speed=-1; + break; + } + break; + } + case PX40X : + { + switch (Index) + { + case 0 : + Speed=2352*75; + break; + case 1 : + Speed=2352*75*2; + break; + case 2 : + Speed=2352*75*4; + break; + case 3 : + Speed=2352*75*8; + break; + case 4 : + Speed=2352*75*8; + break; + case 5 : + Speed=2352*75*10; + break; + case 6 : + Speed=2352*75*17; + break; + default : + Speed=-1; + break; + } + break; + } + } + } + else + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,32,0x2A,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + Speed=(ModeSenseData[26]*256+ModeSenseData[27])*1000; + } + break; + } + case CDTYPE_NEC : + { + if (!addModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } +// Speed=ModeSenseData[6] & 0x20; + break; + } + case CDTYPE_PHILIPS : + case CDTYPE_MATSHITA : + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,20,0x23,m_hDriveEvent)) + { + Error=CDASPIError; + return 0; + } + int Index; + if (IsOldPhilips(&Config)) + Index=ModeSenseData[14]; + else + Index=ModeSenseData[16]; + switch (Index) + { + case 0 : + Speed=-1; + break; + case 1 : + Speed=2352*75; + break; + case 2 : + Speed=2352*75*2; + break; + case 4 : + Speed=2352*75*4; + break; + case 6 : + Speed=2352*75*6; + break; + case 8 : + Speed=2352*75*8; + break; + default : + Speed=-2; + } + break; + } + default : + Speed=0; + } + return Speed; +} + +void CSCSICD::SetCurrentSpeed(int Speed) +{ + TDriveMode ModeSenseData; + if (Speed==0) + return; + switch (MapInfo.GetTypMapping(Config.Type)) + { + case CDTYPE_TOSHIBA : + break; + case CDTYPE_TOSHNEW : + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,15,0x20,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + ModeSenseData[0]=0; + int Index; + switch (Speed) + { + case -2 : + Index=3; + break; + case 2352*75 : + Index=0; + break; + case 2352*75*4 : + Index=1; + break; + default : + Index=2; + } + ModeSenseData[14]=(ModeSenseData[14] & 0xcf)|(Index<<4); + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,15,m_hDriveEvent)) + Error=CDASPIError; + break; + } + case CDTYPE_SONY : + case CDTYPE_RICOH : + case CDTYPE_CYBERDRV : + case CDTYPE_ATAPI : + { + TOpcode OpC; + OpC[0]=0xbb; + OpC[1]=0x00; + OpC[4]=0x00; + OpC[5]=0x00; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x00; + OpC[9]=0x00; + OpC[10]=0x00; + OpC[11]=0x00; + int NewSpeed=Speed/1000; + int ModSpeed=NewSpeed*1000; + int Direction=0; + int AktSpeed=0; + int Counter=0; + do + { + Error=CDOK; + Counter++; + NewSpeed+=Direction; + OpC[2]=NewSpeed/256; + OpC[3]=NewSpeed%256; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_OUT,OpC,12,NULL,0,m_hDriveEvent)) + Error=CDASPIError; + // Is the speed really the one we have selected? + AktSpeed=GetCurrentSpeed(); + if (!Direction) + { + if (AktSpeed<Speed) + Direction=1; + else if (AktSpeed>Speed) + Direction=-1; + } + } + while ((AktSpeed!=ModSpeed) && NewSpeed && (Counter<3)); + break; + } + case CDTYPE_PLEXTOR : + { + DWORD dwModel=GetPlextorModel(&Config); + if (dwModel!=PXR412) + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,16,0x31,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + int Index; + switch (dwModel) + { + case PX4X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case -1 : + case 2352*75*4 : + Index=2; + break; + default : + Index=-1; + break; + } + break; + } + case PX6X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*4 : + Index=1; + break; + case -1 : + case 2352*75*6 : + Index=2; + break; + default : + Index=-1; + break; + } + break; + } + case PX8X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case 2352*75*4 : + Index=2; + break; + case -1 : + case 2352*75*8 : + Index=3; + break; + default : + Index=-1; + break; + } + break; + } + case PX12X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case 2352*75*4 : + Index=2; + break; + case 2352*75*8 : + Index=3; + break; + case -1 : + case 2352*75*12 : + Index=5; + break; + default : + Index=-1; + break; + } + break; + } + case PX20X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case 2352*75*4 : + Index=2; + break; + case 2352*75*8 : + Index=3; + break; + case -1 : + case 2352*75*12 : + Index=6; + break; + default : + Index=-1; + break; + } + break; + } + case PX32X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case 2352*75*4 : + Index=2; + break; + case 2352*75*8 : + Index=3; + break; + case -1 : + case 2352*75*14 : + Index=6; + break; + default : + Index=-1; + break; + } + break; + } + case PX40X : + { + switch (Speed) + { + case 2352*75 : + Index=0; + break; + case 2352*75*2 : + Index=1; + break; + case 2352*75*4 : + Index=2; + break; + case 2352*75*8 : + Index=3; + break; + case 2352*75*10 : + Index=5; + break; + case -1 : + case 2352*75*17 : + Index=6; + break; + default : + Index=-1; + break; + } + break; + } + } + if (Index>=0) + { + ModeSenseData[14]=Index; + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,16,m_hDriveEvent)) + Error=CDASPIError; + } + else + Error=CDASPIError; + } + else + { + TOpcode OpC; + OpC[0]=0xbb; + OpC[1]=0x00; + OpC[4]=0xff; + OpC[5]=0xff; + OpC[6]=0x00; + OpC[7]=0x00; + OpC[8]=0x00; + OpC[9]=0x00; + OpC[10]=0x00; + OpC[11]=0x00; + int NewSpeed=Speed/1000; + int ModSpeed=NewSpeed*1000; + int Direction=0; + int AktSpeed=0; + int Counter=0; + do + { + Error=CDOK; + Counter++; + NewSpeed+=Direction; + OpC[2]=NewSpeed/256; + OpC[3]=NewSpeed%256; + if (!ExecuteSCSIRequest(Config.HostAdapterNumber,Config.ID,Config.LUN,SRB_DIR_OUT,OpC,12,NULL,0,m_hDriveEvent)) + Error=CDASPIError; + // Is the speed really the one we have selected? + AktSpeed=GetCurrentSpeed(); + if (!Direction) + { + if (AktSpeed<Speed) + Direction=1; + else if (AktSpeed>Speed) + Direction=-1; + } + } + while ((AktSpeed!=ModSpeed) && NewSpeed && (Counter<3)); + } + break; + } + case CDTYPE_NEC : + { + if (!addModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,12,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } +// Speed=ModeSenseData[6] & 0x20; + if (!addModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,12,m_hDriveEvent)) + Error=CDASPIError; + break; + } + case CDTYPE_PHILIPS : + case CDTYPE_MATSHITA : + { + if (!ModeSense(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,20,0x23,m_hDriveEvent)) + { + Error=CDASPIError; + return; + } + ModeSenseData[0]=0; + int Index; + switch (Speed) + { + case -2 : + case -1 : + Index=0; + break; + case 2352*75 : + Index=1; + break; + case 2352*75*2 : + Index=2; + break; + case 2352*75*4 : + Index=4; + break; + case 2352*75*6 : + Index=6; + break; + case 2352*75*8 : + Index=8; + break; + default : + Index=0; + } + if (IsOldPhilips(&Config)) + ModeSenseData[14]=Index; + else + ModeSenseData[16]=Index; + if (!ModeSelect(Config.HostAdapterNumber,Config.ID,Config.LUN,ModeSenseData,20,m_hDriveEvent)) + Error=CDASPIError; + break; + } + } +} + +int CSCSICD::GetSpeed(BYTE Index) +{ + if (Index<SupportedSpeeds) + return SpeedTable[Index]; + return 0; +} + + +// ---------------------------------------------------------------------------------------- +// - Implementation of general functions - +// - - +// - Author: Christoph Schmelnik - +// - Purposee: variour initialisations - +// ---------------------------------------------------------------------------------------- + +extern "C" DWORD NtScsiSendASPI32Command( LPSRB lpsrb ); +int LoadASPI2() +{ + OSVERSIONINFO VersionInfo; + VersionInfo.dwOSVersionInfoSize=sizeof(VersionInfo); + GetVersionEx(&VersionInfo); + if (VersionInfo.dwPlatformId==VER_PLATFORM_WIN32_NT) + RunningNT=TRUE; + else + RunningNT=FALSE; + ASPIInstalled=TRUE; + + hDLL=LoadLibrary(L"WNASPI32.DLL"); // load DLL + + if (hDLL==0) + { + if(RunningNT) { + // ok, let's try to see if we can use NT's internal SCSI manager + extern int NtScsiInit( void ); + int nb; + if(nb=NtScsiInit()) { + NumberOfHostAdapters=nb; + SendASPI32Command=(SRBPROC)&NtScsiSendASPI32Command; + return TRUE; + } + } + ASPIInstalled=FALSE; + return FALSE; + } + GetASPI32SupportInfo=(VOIDPROC)GetProcAddress(hDLL,"GetASPI32SupportInfo"); // get Address + SendASPI32Command=(SRBPROC)GetProcAddress(hDLL,"SendASPI32Command"); // get Address + if (GetASPI32SupportInfo==NULL) + { + ASPIInstalled=FALSE; + return FALSE; + } + if (SendASPI32Command==NULL) + { + ASPIInstalled=FALSE; + return FALSE; + } + int r=GetASPI32SupportInfo(); + if (HIBYTE(r)!=SS_COMP) + { + ASPIInstalled=FALSE; + return FALSE; + } + NumberOfHostAdapters=LOBYTE(r); + return TRUE; +} + +int LoadASPI() { + int ret=0; + __try { + ret=LoadASPI2(); + } __except(EXCEPTION_EXECUTE_HANDLER) + { + ret=0; + } + return ret; +} + + +int FreeASPI() +{ + extern int NtScsiDeInit( void ); + NtScsiDeInit(); + if (hDLL) FreeLibrary(hDLL); + hDLL=NULL; + return TRUE; +} + + +int CheckASPI() +{ + return ASPIInstalled; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Dac32.dsp b/Src/Plugins/Input/in_cdda/windac/Dac32.dsp new file mode 100644 index 00000000..714b0166 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Dac32.dsp @@ -0,0 +1,127 @@ +# Microsoft Developer Studio Project File - Name="Dac32" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Dac32 - Win32 Release +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "Dac32.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "Dac32.mak" CFG="Dac32 - Win32 Release" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "Dac32 - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Dac32 - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Win32/Digital Audio Copy/DAC32 DLL", FAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Dac32 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\WinRel" +# PROP BASE Intermediate_Dir ".\WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "DLL" /Fr /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /map /nodefaultlib + +!ELSEIF "$(CFG)" == "Dac32 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\WinDebug" +# PROP BASE Intermediate_Dir ".\WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# ADD BASE CPP /nologo /MT /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "DLL" /Fr /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "Dac32 - Win32 Release" +# Name "Dac32 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\aspifunc.cpp +# End Source File +# Begin Source File + +SOURCE=.\dac32.cpp +# End Source File +# Begin Source File + +SOURCE=.\dac32.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\Aspifunc.h +# End Source File +# Begin Source File + +SOURCE=.\Dac32.h +# End Source File +# Begin Source File + +SOURCE=.\Scsidefs.h +# End Source File +# Begin Source File + +SOURCE=.\Winaspi.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Src/Plugins/Input/in_cdda/windac/Dac32.h b/Src/Plugins/Input/in_cdda/windac/Dac32.h new file mode 100644 index 00000000..4e4ab624 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Dac32.h @@ -0,0 +1,775 @@ +// ---------------------------------------------- +// - DAC32.DLL Header Datei - +// - Written 1996-1998 by Christoph Schmelnik - +// ---------------------------------------------- + +// Changes +// =========== +// Version 1.2 : +// -CMapDrive supports now up to 34 Host Adapters, because now it could access the drives under +// NT with the DeviceControl Interface +// The required information for this is coded as: +// Drives accessed over the new Interface have a HostAdapterNumber above or equal to the +// NumberOfHostAdapters (global Information). +// The ID consists of the good old drive number, like in DOS. +// The LUN is not used for the configuration, but it is used to hold the open handle to the device +// The Burstmodus couldn't be used with the new access mode, so the default setting for those +// drives is the Normal-mode. (For those drives is no difference between Burst- and Normal-mode) +// -LoadASPI checks now the Windows Version and hold this result global in the DLL +// -The Constructor of CSCSCD opens the handles to the new devices +// -The destructor closes those handles +// Interface changes are not required but some values must be handled differnt to avoid +// misconfiguring, e.g. it is not allowed to configure the new drives ID, LUN, and HostAdapterNumber +// -A bug in CWaveSave regarding conversion to mixed mono has been fixed. +// +// Version 1.33 : 18.01.1998 +// Changes: +// Added speed selection support for all current Plextor drives +// +// Version 1.40 : 24.02.1998 +// Changes: +// Set correct direction flags, to work with NT device IO interface and ATAPI drives +// Changed main CD detection to TestUnitReady +// Removed CD detection from Audio Status Info +// Added hopefully correct read command for Matsushita/Panasonic drives +// Added Parameters to CDAC class to allow the disabling of the audio test and to spin up the drive for a specified time +// in seconds to avoid spin up problems on some drives. Both parameters have default values so it behaves like the old version +// without the additional parameters +// Added Parameter to the constructor of CWaveSave to disable writing any Headers. Also this parameter has a default to work like +// before. +// Added virtual function in CDAC to report buffer underruns in Burst Copy Mode +// For the last feature an immediate parameter in WaitCDDA is added +// GetLastSense function added to return the sense information for the last read audio command +// Configuration in CMapDrive extended by new features +// Fixed GetRedBook operator in CCDAdress +// Added function to CD Class to read Media Cataloge Number +// +// Version 1.41 : 28.04.1998 +// Changes: +// New GetInfoEx() function in CMapDrive, to allow a better result checking. +// +// Version 1.42 : 02.08.1998 +// Changes: +// Added GetLastReadableAddress function to get the last readable Sektor of a session. +// Added a flag in the drive properties for the function. +// Added this function to the CDAC object. +// +// Version 1.43 : 23.12.1998 +// Changes: +// Added Wave and DAC classes are now available in a MT version, the old versions will not longer be updated. +// +// Version 1.44 : 10.03.1999 +// Changes: +// Added Support for current Plextor CDROM drives and CD-Writers. +// Added Support for Jukeboxes +// Changed Handling of the Ringbuffer +// +// Version 1.45 : 15.08.1999 +// Changes: +// Added Enhanced error detection for Plextor drives. +// Several Bugfixes (initialising under NT and Ringbuffer specific) +// +// Version 1.45-Build 11 : 11.11.1999 +// Changes: +// Added a check for the MaxSektor parameter in CBaseWaveMT to avoid Program failures even if the applications provides an invalid value. +// Changed source to comile with Borland compiler +// Added MMC-2 Type which will be default for Sony CD-Writers 140 and 928 +// Skip Virtual CD devices in Bus scan +// Fixed Array out of bound bug in drive detection. + + +#ifndef _DAC32_H +#define _DAC32_H + +#ifndef STRICT +#define STRICT // Use strct typechecking +#define WIN32_LEAN_AND_MEAN // compile only important Headerfiles +#endif + +#include <windows.h> +#include <stdio.h> +#include "aspifunc.h" + +/*#ifdef DLL +#define DACDLL __declspec(dllexport) +#else +#define DACDLL __declspec(dllimport) +#endif*/ +#define DACDLL + +#ifdef _DEBUG +#define DBGOUT(sz) OutputDebugString(sz) +#else +#define DBGOUT(sz) +#endif + +//The Errormessages for the CD and DAC Classes +#define CDOK 0x000 +#define CDUnknownDrive 0x001 +#define CDDriveNotReady 0x002 +#define CDUnknownCommand 0x003 +#define CDSeekError 0x006 +#define CDSectorNotFound 0x008 +#define CDReadError 0x00B +#define CDGeneralError 0x00C +#define CDNoCD 0x00E +#define CDIllegalCDChange 0x00F +#define CDDriveNotFound 0x100 +#define CDNoMemory 0x101 +#define CDDACUnable 0x102 +#define CDASPIError 0x103 +#define CDUserBreak 0x104 +#define CDTimeOut 0x105 + +//The Errormessage for the wave classes +#define WAVEFileOpenError 0x200 +#define WAVEFileWriteError 0x201 +#define WAVEChannelError 0x202 +#define WAVEBitsError 0x203 +#define WAVEFreqError 0x204 +#define WAVENameError 0x205 +#define WAVEMemoryError 0x206 + +//The supported base drive types +#define CDTYPE_TOSHIBA 0 +#define CDTYPE_SONY 1 +#define CDTYPE_NEC 2 +#define CDTYPE_PHILIPS 3 +#define CDTYPE_ATAPI 4 +#define CDTYPE_TOSHNEW 5 +#define CDTYPE_RICOH 6 +#define CDTYPE_MATSHITA 7 +#define CDTYPE_PLEXTOR 8 +#define CDTYPE_CYBERDRV 9 + +#define JUKETYPE_SONY 0 +#define JUKETYPE_PIONEER 1 + +//Amount of predefined drive mappings (relationship between real drives and base drive types) +#define MaxMappings 22 // pgo + +//Amount of predefined jukebox mappings (relationship between real jukeboxes and base jukebox types) +#define MaxMappingsJuke 2 + +//The possible Copy modes +#define ModeNormal 0 +#define ModeSynch 1 +#define ModeBurst 2 + +//The possible Values for the DA Test +#define DATEST_ALLWAYS 0 +#define DATEST_FIRSTTRACK 1 +#define DATEST_NEVER 2 + +//The possible SpinUp modes +#define SPINUP_ALLWAYS 0 +#define SPINUP_FIRSTTRACK 1 +#define SPINUP_NEVER 2 + +// Amount of DWORD for the synchronisation +#define SynLen 512 + +// The Class for the Addressformats +class DACDLL CCDAdress +{ +public: + void SetRedbook(long Value); + void SetHSG(long Value) + { + Adresse=Value; + }; + long GetHSG() + { + return Adresse; + }; + long GetRedbook() + { + long t; + t=(Adresse % 75)<<24; + t+=((Adresse / 75) % 60)<<16; + t+=((Adresse / 75) / 60)<<8; + return t; + }; + CCDAdress &operator = (const CCDAdress &other) + { + Adresse=other.Adresse; + return (*this); + }; + CCDAdress &operator + (const long Value) + { + Adresse+=Value; + return (*this); + }; + CCDAdress &operator - (const long Value) + { + Adresse-=Value; + return (*this); + }; + CCDAdress &operator += (const long Value) + { + Adresse+=Value; + return (*this); + }; + CCDAdress &operator -= (const long Value) + { + Adresse-=Value; + return (*this); + }; +private: + long Adresse; +}; + +// Typendeclarations +struct TDriveStatus +{ + int DoorOpen; //Door open/closed + int DoorLocked; //Door locked/unlocked + int Cooked_RAW; //supports Cooked and RAW or Cooked + int Read_Write; //supports read and write + int Data_Audio_Video; //supports Data/Audio/Video or only Data + int Interleave; //supports Interleave regarding ISO + int CommandPrefetch; //supports Command Prefetching + int AudioChannelManipulation; //supports Audio-Channel Manipulation + int HSG_Redbook; //supports HSG and Redbook Addressing or only HSG + int CDPresent; //CD inserted or not + int RWSupport; //supports R-W-Sub Channels +}; + +struct TAudioStatus +{ + BOOL Pause; //Play is paused + BOOL IsPlaying; //CD is playing + BOOL IsDone; //Play is stopped + BOOL PlayError; //Play completed with error + int TrackNummer; //Number of actual track + CCDAdress AbsSektor,RelSektor; //Startsector and Endsector of last/next Play +}; + +struct TTrackFlag +{ + BYTE AudioChannels; //Amount of Audio Channels (2/4) + BOOL PreEmphasis; //Audio Channel with or without... + BOOL DataTrack; //Data track or Audio track + BOOL CopyProhibeted; //Digital copy prohibited +}; + +struct TTrackList +{ + BYTE TrackNummer; //Number of Track + CCDAdress StartSektor; //First sector in HSG Format + long Laenge; //Amount of Sectors + TTrackFlag Flags; +}; + +struct TTrackListeMem +{ + TTrackList Info; + TTrackListeMem *Prev,*Next; +}; + +struct TDriveInfo +{ + int ID; + int LUN; + int HostAdapterNumber; + int Type; + int MaxSektors; + int SynchSektors; + int Mode; + char VendorID[9]; + char ProductID[17]; + int Speed; + int PerformDATest; + int SpinUpMode; + DWORD dwSpinUpTime; + BOOL bUseLastReadableAddress; + BOOL bUseC2ErrorInfo; + BOOL bSpinDown; +}; + +struct TJukeInfo +{ + int ID; + int LUN; + int HostAdapterNumber; + int Type; + int MaxDrives; + int *pConnectedDrives; + int MaxDiscs; + char VendorID[9]; + char ProductID[17]; +}; + +// The class with the infos for the type mapping +class DACDLL CMapInfo +{ +public: + CMapInfo(); + char *GetTypName(int Index); + int GetTypMapping(int Index); + int GetTypMappingRev(int CDType); +private: + char TypNamen[MaxMappings][9]; + int TypMapping[MaxMappings]; +}; + +// The class with the infos for the type mapping +class DACDLL CMapInfoJuke +{ +public: + CMapInfoJuke(); + char *GetTypName(int Index); + int GetTypMapping(int Index); + int GetTypMappingRev(int JukeType); +private: + char TypNamen[MaxMappingsJuke][9]; + int TypMapping[MaxMappingsJuke]; +}; + +// The base class (pure virtual) for the CD access +class DACDLL CBaseCD +{ +public: + int Lasterror(); + virtual void PrepareCDDA()=0; + virtual void ReadCDDA(CCDAdress StartSektor,long Sektoranzahl,void *Buffer,BOOL bUseC2ErrorInfo=FALSE)=0; + virtual BOOL WaitCDDA(BOOL bImmediate=FALSE)=0; + virtual void FinishCDDA()=0; + virtual void SortWaveData(DWORD *Data,int Samples)=0; + virtual CCDAdress GetErrorAdress()=0; + virtual void Play_Audio(CCDAdress StartSektor,long Sektoranzahl)=0; + virtual void Stop_Audio()=0; + virtual void Pause_Audio()=0; + virtual void Resume_Audio()=0; + virtual TDriveStatus Get_DriveStatus()=0; + virtual BOOL MediaChanged()=0; + virtual void Get_MediaCatalogNumber(char szUPC[16])=0; + virtual void EjectDisk()=0; + virtual void LockDoor(int Lock)=0; + virtual void CloseTray()=0; + virtual void ReRead()=0; + virtual CCDAdress GetLastReadableAddress(CCDAdress StartSektor)=0; + virtual int GetMaxSektors()=0; + virtual int GetSynchSektors()=0; + virtual int GetMode()=0; + virtual int GetSpeed()=0; + virtual void InitSpeedTable()=0; + virtual BYTE GetSupportedSpeeds()=0; + virtual int GetCurrentSpeed()=0; + virtual void SetCurrentSpeed(int Speed)=0; + virtual int GetSpeed(BYTE Index)=0; + int ReadFirstTrackInfo(TTrackList &Infos); + int ReadNextTrackInfo(TTrackList &Infos); + int ReadPrevTrackInfo(TTrackList &Infos); + int ReadTrackInfo(TTrackList &Infos); + int ReadMaxTracks(); +protected: + int Error,BusyFlag,DoneFlag; + TTrackListeMem *FirstTrack,*AktTrack; + void DeleteTrackList(); +private: + CBaseCD& operator = (const CBaseCD &other); +}; + +// The class for the access to SCSI drives +class DACDLL CSCSICD:public CBaseCD +{ +public: + CSCSICD (char drive, TDriveInfo &xInfo); + ~CSCSICD(); + virtual void PrepareCDDA(); + virtual void ReadCDDA(CCDAdress StartSektor,long Sektoranzahl,void *Buffer,BOOL bUseC2ErrorInfo=FALSE); + virtual BOOL WaitCDDA(BOOL bImmediate=FALSE); + virtual void FinishCDDA(); + virtual void SortWaveData(DWORD *Data,int Samples); + virtual CCDAdress GetErrorAdress(); + virtual void Play_Audio(CCDAdress StartSektor,long Sektoranzahl); + virtual void Stop_Audio(); + virtual void Pause_Audio(); + virtual void Resume_Audio(); + virtual TDriveStatus Get_DriveStatus(); + virtual BOOL MediaChanged(); + virtual TAudioStatus Get_AudioStatus_Info(); + virtual void Get_MediaCatalogNumber(char szUPC[16]); + virtual void EjectDisk(); + virtual void LockDoor(int Lock); + virtual void CloseTray(); + virtual void ReRead(); + virtual CCDAdress GetLastReadableAddress(CCDAdress StartSektor); + virtual int GetMaxSektors(); + virtual int GetSynchSektors(); + virtual int GetMode(); + virtual int GetSpeed(); + virtual void InitSpeedTable(); + virtual BYTE GetSupportedSpeeds(); + virtual int GetCurrentSpeed(); + virtual void SetCurrentSpeed(int Speed); + virtual int GetSpeed(BYTE Index); + TDriveInfo &GetInfo() + { + return Config; + }; + TSenseInfo GetSense(); + TSenseInfo GetLastSenseInfo(); + +private: + CSCSICD& operator = (const CSCSICD &other); + + TDriveInfo &Config; // Drive Configuration + BOOL CDPresentLast,Changed; // Helpvariables for the MediaChanged function + SRB_ExecSCSICmd ReadSRB; // SCSI Commando Block + TDriveMode ModeData; + BYTE NECRotationSpeed; + CMapInfo MapInfo; + DWORD StartReadTime; + int SpeedTable[256]; + BYTE SupportedSpeeds; + HANDLE m_hDriveEvent; + TSenseInfo m_SenseInfo; + BOOL m_bSpeedTableInitialized; +}; + +// The base class for saving/converting the audio data +class DACDLL CBaseWave +{ +public: + int Lasterror(); + virtual void WritePuffer(long Samples,DWORD *Buffer)=0; +protected: + int Error; //last occured error +private: + CBaseWave& operator = (const CBaseWave &other); +}; + +typedef struct +{ + BOOL bIsUsed; //Is Buffer used? + BOOL bReady; //Is Nuffer ready to write? + int nSamples; //Number of Samples in Buffer. + int nZeroSamples; //Number of Silence Samples to insert before the buffer + DWORD *dwBuffer; //Buffer for Audio Data +} WAVEBUFFER, *PWAVEBUFFER; + +typedef struct _WAVEBUFFERLIST +{ + PWAVEBUFFER pWaveBuffer; + _WAVEBUFFERLIST *pNext; +} WAVEBUFFERLIST, *PWAVEBUFFERLIST; + + +typedef struct +{ + HANDLE hEvent; + LPVOID pData; +} TWAVEMTSTRUCT; + +// The base class for saving/converting the audio data as its own thread +class DACDLL CBaseWaveMT +{ +public: + CBaseWaveMT(DWORD dwBufferSize,BOOL bUseHighPriority=FALSE,int MaxSektors=27,DWORD dwExtraBytes=0); + ~CBaseWaveMT(); + + void SetFadeInOut(int dwTotalSamples,int dwFadeSamples); + + PWAVEBUFFER GetBuffer(); //returns NULL if no Buffer is available + void SignalBuffer(); //signal if a buffer is filled; + int Lasterror(); + double GetBufferFullRatio(); + DWORD GetBytesInBuffer(); + + virtual void WritePuffer(long Samples,DWORD *Buffer)=0; + + friend unsigned _stdcall WaveThreadProc(LPVOID pUserData); + +protected: + int Error; //last occured error + + void StartThread(); //call this from your own initialisation function + BOOL WriteData(); + void StopThread(BOOL bImmediate=FALSE); //call this from your own cleanup function + +private: + CBaseWaveMT& operator = (const CBaseWaveMT &other); + + DWORD m_Nullen[256]; + PWAVEBUFFERLIST m_pFirstBuffer, m_pReadBuffer, m_pWriteBuffer; + TWAVEMTSTRUCT m_WaveInfo; + BOOL m_bStopThread,m_bAbortThread,m_bIsWorking; + HANDLE m_hWaveThread; + BOOL m_bUseHighPriority; + int m_dwTotalSamples,m_dwFadeSamples,m_dwCurrentSample; + int m_nBufferNum,m_nReadBufferNum,m_nWriteBufferNum; + int m_nMaxSektors; +}; + +// The class for saving audio data in a wave file +class DACDLL CWaveSave:public CBaseWave +{ +public: + CWaveSave(const char *DateiName,BYTE Freq,BYTE Channels,BYTE Bits,BOOL bWriteHeaders=TRUE); + ~CWaveSave(); + virtual void WritePuffer(long Samples,DWORD *Buffer); +private: + void WMono8(long Samples,DWORD *Buffer); + void WStereo8(long Samples,DWORD *Buffer); + void WMono16(long Samples,DWORD *Buffer); + void WStereo16(long Samples,DWORD *Buffer); + void WLR8(long Samples,int Mode,DWORD *Buffer); + void WLR16(long Samples,int Mode,DWORD *Buffer); + + CWaveSave& operator = (const CWaveSave &other); + + BYTE ConvertType; //CodeNumber of the conversion type + FILE *Datei; //file variable to access the wave file + WORD *DPM16; //Pointer to the file data buffer + BYTE *DPM8; //Pointer to the file data buffer + DWORD *DPS16; //Pointer to the file data buffer + BYTE *DPS8; //Pointer to the file data buffer + int DatenCount; //Counter of data in buffer + long WaveBytes; //Counts all written bytes + BYTE SAdd; //Value to increment the source counter + BOOL m_bWriteHeaders; //Write Headers of Wave file +}; + +// The class for saving audio data in a wave file in its own thread +class DACDLL CWaveSaveMT:public CBaseWaveMT +{ +public: + CWaveSaveMT(DWORD dwBufferSize,BOOL bUseHighPriority=FALSE,int MaxSektors=27,DWORD dwExtraBytes=0):CBaseWaveMT(dwBufferSize,bUseHighPriority,MaxSektors,dwExtraBytes) + { + }; + void Init(const char *DateiName,BYTE Freq,BYTE Channels,BYTE Bits,BOOL bWriteHeaders=TRUE); + void Done(BOOL bImmediate=FALSE); + virtual void WritePuffer(long Samples,DWORD *Buffer); +private: + void WMono8(long Samples,DWORD *Buffer); + void WStereo8(long Samples,DWORD *Buffer); + void WMono16(long Samples,DWORD *Buffer); + void WStereo16(long Samples,DWORD *Buffer); + void WLR8(long Samples,int Mode,DWORD *Buffer); + void WLR16(long Samples,int Mode,DWORD *Buffer); + + CWaveSave& operator = (const CWaveSave &other); + + BYTE ConvertType; //CodeNumber of the conversion type + FILE *Datei; //file variable to access the wave file + WORD *DPM16; //Pointer to the file data buffer + BYTE *DPM8; //Pointer to the file data buffer + DWORD *DPS16; //Pointer to the file data buffer + BYTE *DPS8; //Pointer to the file data buffer + int DatenCount; //Counter of data in buffer + long WaveBytes; //Counts all written bytes + BYTE SAdd; //Value to increment the source counter + BOOL m_bWriteHeaders; //Write Headers of Wave file +}; + +// The class for copying the audio data from CD. +class DACDLL CDAC +{ +public: + CDAC(CBaseCD *pDrive,CBaseWave *pWave, + CCDAdress Start,long Laenge,BOOL xKillZeros,BOOL bPerformDATest=TRUE,DWORD dwSpinUpTime=0,BOOL bUseLastReadableAddress=FALSE); + ~CDAC(); + int Lasterror(); + void Copy(); + int Errors(); + void StopCopy(); + + // The following member functions are declared as virtual. They could be used to display + // information to the user. They do nothing by default. + virtual void WriteInit(); + virtual void WritePercent(float Percent); + virtual void WriteReading(); + virtual void WriteReadingEnd(); + virtual void WriteSynch(); + virtual void WriteSynchEnd(); + virtual void WriteFlushing(); + virtual void WriteFlushingEnd(); + virtual void WriteSynchError(); + virtual void WriteBufferUnderrun(CCDAdress Start); + virtual void WriteReRead(CCDAdress Start,long Laenge); + virtual void WriteSektorsSkipped(CCDAdress Start,long Laenge); + virtual void WriteDone(); + virtual void OnIdle(); + +protected: + CCDAdress StartSektor,StartOld; + int SynchErrors,Error; + long Anzahl,AnzahlOld,Remain; + +private: + CBaseCD *m_pCD; + BOOL RunCopy,KillFirst,KillLast,KillZero,Found; + DWORD m_dwSpinUpTime; + CBaseWave *m_pWaveSave; + long SektorAnzahl,Retries,SynchDiff,ZeroCount; + DWORD *MemBlocks[2]; + int BlockCount,S_Offset; + int SpeedSave; + DWORD m_Nullen[256]; + + void ReadCDDA(CCDAdress Start,long Sektoranzahl,void *Buffer); + void FlushWave(); + void FlushSynch(int Samples,DWORD *Data); + void MakeTable(DWORD *Werte,DWORD *Table); + int SynchSearch(DWORD *String1,DWORD *String2,DWORD *Table); + void SynchWave(); + + CDAC& operator = (const CDAC &other); +}; + +// The class for copying the audio data from CD. +class DACDLL CDACMT +{ +public: + CDACMT(CBaseCD *pDrive,CBaseWaveMT *pWave, + CCDAdress Start,long Laenge,BOOL xKillZeros,BOOL bPerformDATest=TRUE,DWORD dwSpinUpTime=0,BOOL bUseHighPriority=FALSE,BOOL bUseC2ErrorInfo=FALSE,BOOL bSpinDown=FALSE,BOOL bUseLastReadableAddress=FALSE); + ~CDACMT(); + int Lasterror(); + void Copy(); + int Errors(); + void StopCopy(); + + // The following member functions are declared as virtual. They could be used to display + // information to the user. They do nothing by default. + virtual void WriteInit(); + virtual void WritePercent(float Percent); + virtual void WriteReading(); + virtual void WriteReadingEnd(); + virtual void WriteSynch(); + virtual void WriteSynchEnd(); + virtual void WriteFlushing(); + virtual void WriteFlushingEnd(); + virtual void WriteSynchError(); + virtual void WriteBufferUnderrun(CCDAdress Start); + virtual void WriteReRead(CCDAdress Start,long Laenge); + virtual void WriteSektorsSkipped(CCDAdress Start,long Laenge); + virtual void WriteDone(); + virtual void OnIdle(BOOL bReturnFast=TRUE); + + friend unsigned _stdcall DACThreadProc(LPVOID pUserData); +protected: + CCDAdress StartSektor,StartOld; + int SynchErrors,Error; + long Anzahl,AnzahlOld,Remain; + + void CopyMT(); +private: + CBaseCD *m_pCD; + BOOL RunCopy,KillFirst,KillLast,KillZero,Found; + DWORD m_dwSpinUpTime; + CBaseWaveMT *m_pWaveSave; + BOOL m_bUseC2ErrorInfo; + BOOL m_bSpinDown; + long SektorAnzahl,Retries,SynchDiff,ZeroCount; + PWAVEBUFFER MemBlocks[2]; + int BlockCount,S_Offset; + int SpeedSave; + int m_MaxSektors; + int m_SynchSektors; + + void ReadCDDA(CCDAdress Start,long Sektoranzahl,void *Buffer); + void FlushWave(int nMax=2); + void FlushSynch(int Samples,PWAVEBUFFER Data); + void MakeTable(DWORD *Werte,DWORD *Table); + int SynchSearch(DWORD *String1,DWORD *String2,DWORD *Table); + void SynchWave(); + + CDACMT& operator = (const CDACMT &other); + + HANDLE m_hDACThread; + BOOL m_bUseHighPriority; +}; + +// The class for configuring the SCSI CDROM drives +class DACDLL CMapDrive +{ +public: + CMapDrive(BOOL bDoReset=TRUE); + ~CMapDrive(); + void Reset(); + int GetMaxDrives(); + TDriveInfo &GetInfo(int index); + BOOL GetInfoEx(int index, TDriveInfo *&pInfo); + void DeleteInfo(int index); + int GetMaxHostAdapters(); + int GetSupportedHostAdapterMemory(int index); + void SetSupportedHostAdapterMemory(int index,int Memory); + int GetMaxSektors(int HostAdapterNumber); +protected: + void DeleteAll(); + +private: + struct TDriveInfoMem + { + TDriveInfo Info; + TDriveInfoMem *Next; + }; + TDriveInfoMem *First; + int HostAdapterMemory[34]; + HANDLE m_hDriveEvent; +}; + + +// The class for configuring the SCSI Jukeboxes +class DACDLL CMapJuke +{ +public: + CMapJuke(BOOL bDoReset=TRUE); + ~CMapJuke(); + void Reset(); + int GetMaxJukes(); + TJukeInfo &GetInfo(int index); + BOOL IsWorking(int index); + void SetWorking(int index,BOOL bIsWorking); + void DeleteInfo(int index); +protected: + void DeleteAll(); + +private: + struct TJukeInfoMem + { + TJukeInfo Info; + BOOL bIsWorking; + TJukeInfoMem *Next; + }; + TJukeInfoMem *First; + HANDLE m_hJukeEvent; +}; + +//The class to access Jukeboxes +class DACDLL CJukeBox +{ +public: + CJukeBox (TJukeInfo &xInfo); + ~CJukeBox(); + //use following defines to address an item in the jukebox: + //drive0..x : 0x4000...0x400x + //storage1..xxx : 0x0001...0x0xxx + BOOL MoveMedium(int Source,int Destination); + TJukeInfo &GetInfo() + { + return Config; + }; + +private: + TJukeInfo &Config; // Drive Configuration + CMapInfoJuke MapInfo; + HANDLE m_hJukeEvent; +}; + + +// ---------------------- +// function declarations +// ---------------------- + +// initialize and deinatialize the WNASPI32.DLL and some internal flags +int DACDLL LoadASPI(); +int DACDLL FreeASPI(); + +int DACDLL CheckASPI(); + + + +#endif //_DAC32_H
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Dac32.mak b/Src/Plugins/Input/in_cdda/windac/Dac32.mak new file mode 100644 index 00000000..46b175f7 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Dac32.mak @@ -0,0 +1,285 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +!IF "$(CFG)" == "" +CFG=Dac32 - Win32 Debug +!MESSAGE No configuration specified. Defaulting to Dac32 - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Dac32 - Win32 Release" && "$(CFG)" != "Dac32 - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Dac32.mak" CFG="Dac32 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Dac32 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Dac32 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Dac32 - Win32 Debug" +CPP=cl.exe +RSC=rc.exe +MTL=mktyplib.exe + +!IF "$(CFG)" == "Dac32 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\Dac32.dll" "$(OUTDIR)\Dac32.bsc" + +CLEAN : + -@erase "$(INTDIR)\aspifunc.obj" + -@erase "$(INTDIR)\aspifunc.sbr" + -@erase "$(INTDIR)\dac32.obj" + -@erase "$(INTDIR)\dac32.res" + -@erase "$(INTDIR)\dac32.sbr" + -@erase "$(OUTDIR)\Dac32.bsc" + -@erase "$(OUTDIR)\Dac32.dll" + -@erase "$(OUTDIR)\Dac32.exp" + -@erase "$(OUTDIR)\Dac32.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "DLL" /Fr /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "DLL"\ + /Fr"$(INTDIR)/" /Fp"$(INTDIR)/Dac32.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\Release/ +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +RSC_PROJ=/l 0x407 /fo"$(INTDIR)/dac32.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/Dac32.bsc" +BSC32_SBRS= \ + "$(INTDIR)\aspifunc.sbr" \ + "$(INTDIR)\dac32.sbr" + +"$(OUTDIR)\Dac32.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /map /nodefaultlib +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\ + /pdb:"$(OUTDIR)/Dac32.pdb" /machine:I386 /out:"$(OUTDIR)/Dac32.dll"\ + /implib:"$(OUTDIR)/Dac32.lib" +LINK32_OBJS= \ + "$(INTDIR)\aspifunc.obj" \ + "$(INTDIR)\dac32.obj" \ + "$(INTDIR)\dac32.res" + +"$(OUTDIR)\Dac32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Dac32 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\Dac32.dll" "$(OUTDIR)\Dac32.bsc" + +CLEAN : + -@erase "$(INTDIR)\aspifunc.obj" + -@erase "$(INTDIR)\aspifunc.sbr" + -@erase "$(INTDIR)\dac32.obj" + -@erase "$(INTDIR)\dac32.res" + -@erase "$(INTDIR)\dac32.sbr" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\Dac32.bsc" + -@erase "$(OUTDIR)\Dac32.dll" + -@erase "$(OUTDIR)\Dac32.exp" + -@erase "$(OUTDIR)\Dac32.ilk" + -@erase "$(OUTDIR)\Dac32.lib" + -@erase "$(OUTDIR)\Dac32.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /MT /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "DLL" /Fr /YX /c +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\ + /D "DLL" /Fr"$(INTDIR)/" /Fp"$(INTDIR)/Dac32.pch" /YX /Fo"$(INTDIR)/"\ + /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\Debug/ +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /win32 +MTL_PROJ=/nologo /D "_DEBUG" /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +RSC_PROJ=/l 0x407 /fo"$(INTDIR)/dac32.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/Dac32.bsc" +BSC32_SBRS= \ + "$(INTDIR)\aspifunc.sbr" \ + "$(INTDIR)\dac32.sbr" + +"$(OUTDIR)\Dac32.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# SUBTRACT LINK32 /nodefaultlib +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes\ + /pdb:"$(OUTDIR)/Dac32.pdb" /debug /machine:I386 /out:"$(OUTDIR)/Dac32.dll"\ + /implib:"$(OUTDIR)/Dac32.lib" +LINK32_OBJS= \ + "$(INTDIR)\aspifunc.obj" \ + "$(INTDIR)\dac32.obj" \ + "$(INTDIR)\dac32.res" + +"$(OUTDIR)\Dac32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "Dac32 - Win32 Release" +# Name "Dac32 - Win32 Debug" + +!IF "$(CFG)" == "Dac32 - Win32 Release" + +!ELSEIF "$(CFG)" == "Dac32 - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\dac32.cpp + +!IF "$(CFG)" == "Dac32 - Win32 Release" + +DEP_CPP_DAC32=\ + ".\Aspifunc.h"\ + ".\Dac32.h"\ + ".\Scsidefs.h"\ + ".\Winaspi.h"\ + + +"$(INTDIR)\dac32.obj" : $(SOURCE) $(DEP_CPP_DAC32) "$(INTDIR)" + +"$(INTDIR)\dac32.sbr" : $(SOURCE) $(DEP_CPP_DAC32) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "Dac32 - Win32 Debug" + +DEP_CPP_DAC32=\ + ".\Aspifunc.h"\ + ".\Dac32.h"\ + ".\Scsidefs.h"\ + ".\Winaspi.h"\ + + +"$(INTDIR)\dac32.obj" : $(SOURCE) $(DEP_CPP_DAC32) "$(INTDIR)" + +"$(INTDIR)\dac32.sbr" : $(SOURCE) $(DEP_CPP_DAC32) "$(INTDIR)" + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\aspifunc.cpp +DEP_CPP_ASPIF=\ + ".\Aspifunc.h"\ + ".\Scsidefs.h"\ + ".\Winaspi.h"\ + + +"$(INTDIR)\aspifunc.obj" : $(SOURCE) $(DEP_CPP_ASPIF) "$(INTDIR)" + +"$(INTDIR)\aspifunc.sbr" : $(SOURCE) $(DEP_CPP_ASPIF) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\dac32.rc + +"$(INTDIR)\dac32.res" : $(SOURCE) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/Src/Plugins/Input/in_cdda/windac/Dac32.rc b/Src/Plugins/Input/in_cdda/windac/Dac32.rc new file mode 100644 index 00000000..1e81aeee --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Dac32.rc @@ -0,0 +1,121 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,4,5,11 + PRODUCTVERSION 1,4,5,11 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "CASH\0" + VALUE "FileDescription", "Christoph Schmelnik's Digital Audio Copy 32 Bit Copy Engine\0" + VALUE "FileVersion", "1, 4, 5, 11\0" + VALUE "InternalName", "DAC32 DLL\0" + VALUE "LegalCopyright", "Copyright © 1996-1999 by Christoph Schmelnik\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "Dac32.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Christoph Schmelnik's Digital Audio Copy for Win32\0" + VALUE "ProductVersion", "Version 1.45\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (Deutschland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Deutsch (Deutschland) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Plugins/Input/in_cdda/windac/NTScsi.cpp b/Src/Plugins/Input/in_cdda/windac/NTScsi.cpp new file mode 100644 index 00000000..8112b100 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/NTScsi.cpp @@ -0,0 +1,501 @@ +#include <stdio.h> +#include <stddef.h> +#include "NTScsi.h" + +typedef struct { + BYTE ha; + BYTE tgt; + BYTE lun; + BYTE driveLetter; + BOOL bUsed; + HANDLE hDevice; + BYTE inqData[36]; +} NTSCSIDRIVE; + +typedef struct +{ + BYTE numAdapters; + NTSCSIDRIVE drive[26]; +} NTSCSIDRIVES; + +void GetDriveInformation( BYTE i, NTSCSIDRIVE *pDrive ); + +static HANDLE GetFileHandle( BYTE i ); + +static BOOL bNtScsiAvailable = FALSE; +static NTSCSIDRIVES NtScsiDrives; +static BOOL bUseNtScsi = FALSE; + +/* + * Initialization of SCSI Pass Through Interface code. Responsible for + * setting up the array of SCSI devices. This code will be a little + * different from the normal code -- it will query each drive letter from + * C: through Z: to see if it is a CD. When we identify a CD, we then + * send CDB with the INQUIRY command to it -- NT will automagically fill in + * the PathId, TargetId, and Lun for us. + */ + +int NtScsiInit( void ) +{ + BYTE i; + wchar_t buf[4] = {0}; + UINT uDriveType; + int retVal = 0; + + if ( bNtScsiAvailable ) + { + for( i = 2; i < 26; i++ ) if ( NtScsiDrives.drive[i].bUsed ) retVal++; + bUseNtScsi = (retVal > 0 ); + return retVal; + } + + memset( &NtScsiDrives, 0x00, sizeof(NtScsiDrives) ); + + for( i = 0; i < 26; i++ ) + { + NtScsiDrives.drive[i].hDevice = INVALID_HANDLE_VALUE; + } + + for( i = 2; i < 26; i++ ) + { + wsprintf( buf, L"%c:\\", (wchar_t)('A'+i) ); + uDriveType = GetDriveType( buf ); + + /* check if this is a CDROM drive */ + if ( uDriveType == DRIVE_CDROM ) + { + GetDriveInformation( i, &NtScsiDrives.drive[i] ); + + if ( NtScsiDrives.drive[i].bUsed ) + retVal++; + } + } + + NtScsiDrives.numAdapters = NtScsiGetNumAdapters( ); + + bNtScsiAvailable = TRUE; + + if ( retVal > 0 ) + { + bUseNtScsi = TRUE; + } + + return retVal; +} + + +int NtScsiDeInit( void ) +{ + BYTE i; + + if ( !bNtScsiAvailable ) + return 0; + + for( i = 2; i < 26; i++ ) + { + if ( NtScsiDrives.drive[i].bUsed ) + { + CloseHandle( NtScsiDrives.drive[i].hDevice ); + } + } + + NtScsiDrives.numAdapters = NtScsiGetNumAdapters( ); + + ZeroMemory( &NtScsiDrives, sizeof(NtScsiDrives) ); + bNtScsiAvailable = FALSE; + return -1; +} + + +/* + * Returns the number of "adapters" present. + */ +BYTE NtScsiGetNumAdapters( void ) +{ + BYTE buf[256] = {0}; + WORD i; + BYTE numAdapters = 0; + + // PortNumber 0 should exist, so pre-mark it. This avoids problems + // when the primary IDE drives are on PortNumber 0, but can't be opened + // because of insufficient privelege (ie. non-admin). + buf[0] = 1; + + for( i = 0; i < 26; i++ ) + { + if ( NtScsiDrives.drive[i].bUsed ) + buf[NtScsiDrives.drive[i].ha] = 1; + } + + for( i = 0; i <= 255; i++ ) + { + if ( buf[i] ) + numAdapters++; + } + + return numAdapters; +} + + +/* + * Replacement for GetASPI32SupportInfo from wnaspi32.dll + */ +DWORD NtScsiGetASPI32SupportInfo( void ) +{ + DWORD retVal; + + + if ( !NtScsiDrives.numAdapters ) + retVal = (DWORD)(MAKEWORD(0,SS_NO_ADAPTERS)); + else + retVal = (DWORD)(MAKEWORD(NtScsiDrives.numAdapters,SS_COMP)); + + return retVal; +} + +/* + * Needs to call the appropriate function for the lpsrb->SRB_Cmd specified. + * Valid types are SC_HA_INQUIRY, SC_GET_DEV_TYPE, SC_EXEC_SCSI_CMD, + * and SC_RESET_DEV. + */ +DWORD NtScsiSendASPI32Command( LPSRB lpsrb ) +{ + if ( !lpsrb ) + return SS_ERR; + + switch( lpsrb->SRB_Cmd ) + { + case SC_HA_INQUIRY: + return NtScsiHandleHaInquiry( (LPSRB_HAINQUIRY)lpsrb ); + break; + + case SC_GET_DEV_TYPE: + return NtScsiGetDeviceType( (LPSRB_GDEVBLOCK)lpsrb ); + break; + + case SC_EXEC_SCSI_CMD: + return NtScsiExecSCSICommand( (LPSRB_EXECSCSICMD)lpsrb, FALSE ); + break; + + case SC_RESET_DEV: + default: + lpsrb->SRB_Status = SS_ERR; + return SS_ERR; + break; + } + + return SS_ERR; // should never get to here... +} + + +/* + * Universal function to get a file handle to the CD device. Since + * NT 4.0 wants just the GENERIC_READ flag, and Win2K wants both + * GENERIC_READ and GENERIC_WRITE (why a read-only CD device needs + * GENERIC_WRITE access is beyond me...), the easist workaround is to just + * try them both. + */ +static HANDLE GetFileHandle( BYTE i ) +{ + wchar_t buf[12] = {0}; + HANDLE fh = NULL; + OSVERSIONINFO osver; + DWORD dwFlags; + + memset( &osver, 0x00, sizeof(osver) ); + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx( &osver ); + + // if Win2K or greater, add GENERIC_WRITE + dwFlags = GENERIC_READ; + + if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osver.dwMajorVersion > 4) ) + { + dwFlags |= GENERIC_WRITE; + } + + wsprintf( buf, L"\\\\.\\%c:", (wchar_t)('A'+i) ); + fh = CreateFile( buf, dwFlags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING, 0, NULL ); + + if ( fh == INVALID_HANDLE_VALUE ) + { + // it went foobar somewhere, so try it with the GENERIC_WRITE bit flipped + dwFlags ^= GENERIC_WRITE; + fh = CreateFile( buf, dwFlags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + } + + if ( fh == INVALID_HANDLE_VALUE ) + { + } + else + { + } + + return fh; +} + + + +/* + * fills in a pDrive structure with information from a SCSI_INQUIRY + * and obtains the ha:tgt:lun values via IOCTL_SCSI_GET_ADDRESS + */ +void GetDriveInformation( BYTE i, NTSCSIDRIVE *pDrive ) +{ + HANDLE fh; + char buf[2048] = {0}; + BOOL status; + PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER pswb; + PSCSI_ADDRESS pscsiAddr; + ULONG length, returned; + BYTE inqData[100] = {0}; + + fh = GetFileHandle( i ); + + if ( fh == INVALID_HANDLE_VALUE ) + { + return; + } + + /* + * Get the drive inquiry data + */ + ZeroMemory( &buf, 2048 ); + ZeroMemory( inqData, 100 ); + pswb = (PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)buf; + pswb->spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + pswb->spt.CdbLength = 6; + pswb->spt.SenseInfoLength = 24; + pswb->spt.DataIn = SCSI_IOCTL_DATA_IN; + pswb->spt.DataTransferLength = 100; + pswb->spt.TimeOutValue = 2; + pswb->spt.DataBuffer = inqData; + pswb->spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf ); + pswb->spt.Cdb[0] = 0x12; + pswb->spt.Cdb[4] = 100; + + length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); + status = DeviceIoControl( fh, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + pswb, + length, + pswb, + length, + &returned, + NULL ); + + if ( !status ) + { + CloseHandle( fh ); + return; + } + + memcpy( pDrive->inqData, inqData, 36 ); + + /* + * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS + */ + ZeroMemory( &buf, 2048 ); + pscsiAddr = (PSCSI_ADDRESS)buf; + pscsiAddr->Length = sizeof(SCSI_ADDRESS); + if ( DeviceIoControl( fh, IOCTL_SCSI_GET_ADDRESS, NULL, 0, + pscsiAddr, sizeof(buf), &returned, + NULL ) ) + { + pDrive->bUsed = TRUE; + pDrive->ha = pscsiAddr->PortNumber; + pDrive->tgt = pscsiAddr->TargetId; + pDrive->lun = pscsiAddr->Lun; + pDrive->driveLetter = i; + pDrive->hDevice = INVALID_HANDLE_VALUE; + } + else if (50 == GetLastError()) // usb/firewire + { + pDrive->bUsed = TRUE; + pDrive->ha = i; + pDrive->tgt = 0; + pDrive->lun = 0; + pDrive->driveLetter = i; + pDrive->hDevice = INVALID_HANDLE_VALUE; + } + else + { + pDrive->bUsed = FALSE; + } + + CloseHandle( fh ); +} + + + +DWORD NtScsiHandleHaInquiry( LPSRB_HAINQUIRY lpsrb ) +{ + DWORD *pMTL; + + lpsrb->HA_Count = NtScsiDrives.numAdapters; + + if ( lpsrb->SRB_HaId >= NtScsiDrives.numAdapters ) + { + lpsrb->SRB_Status = SS_INVALID_HA; + return SS_INVALID_HA; + } + lpsrb->HA_SCSI_ID = 7; // who cares... we're not really an ASPI manager + memcpy( lpsrb->HA_ManagerId, "blahblahblahblah", 16 ); + memcpy( lpsrb->HA_Identifier, "blahblahblahblah", 16 ); + lpsrb->HA_Identifier[13] = (char)('0'+lpsrb->SRB_HaId); + ZeroMemory( lpsrb->HA_Unique, 16 ); + lpsrb->HA_Unique[3] = 8; + pMTL = (LPDWORD)&lpsrb->HA_Unique[4]; + *pMTL = 64 * 1024; + + lpsrb->SRB_Status = SS_COMP; + return SS_COMP; +} + + +/* + * Scans through the drive array and returns DTYPE_CDROM type for all items + * found, and DTYPE_UNKNOWN for all others. + */ +DWORD NtScsiGetDeviceType( LPSRB_GDEVBLOCK lpsrb ) +{ + lpsrb->SRB_Status = SS_NO_DEVICE; + if ( NtScsiGetDeviceIndex( lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun ) ) + lpsrb->SRB_Status = SS_COMP; + + if ( lpsrb->SRB_Status == SS_COMP ) + lpsrb->SRB_DeviceType = DTC_CDROM; + else + lpsrb->SRB_DeviceType = DTC_UNKNOWN; + + return lpsrb->SRB_Status; +} + + +/* + * Looks up the index in the drive array for a given ha:tgt:lun triple + */ +BYTE NtScsiGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun ) +{ + BYTE i; + + for( i = 2; i < 26; i++ ) + { + if ( NtScsiDrives.drive[i].bUsed ) + { + NTSCSIDRIVE *lpd; + lpd = &NtScsiDrives.drive[i]; + if ( (lpd->ha == ha) && (lpd->tgt == tgt) && (lpd->lun == lun) ) + return i; + } + } + return 0; +} + +/* + * Converts ASPI-style SRB to SCSI Pass Through IOCTL + */ +DWORD NtScsiExecSCSICommand( LPSRB_EXECSCSICMD lpsrb, BOOL bBeenHereBefore ) +{ + BOOL status; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + ULONG length, returned; + BYTE idx; + + idx = NtScsiGetDeviceIndex( lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun ); + + if ( idx == 0 ) + { + lpsrb->SRB_Status = SS_ERR; + return SS_ERR; + } + + if ( lpsrb->CDBByte[0] == 0x12 ) // is it an INQUIRY? + { + lpsrb->SRB_Status = SS_COMP; + memcpy( lpsrb->SRB_BufPointer, NtScsiDrives.drive[idx].inqData, 36 ); + return SS_COMP; + } + + if ( NtScsiDrives.drive[idx].hDevice == INVALID_HANDLE_VALUE ) + NtScsiDrives.drive[idx].hDevice = GetFileHandle( NtScsiDrives.drive[idx].driveLetter ); + + ZeroMemory( &swb, sizeof(swb) ); + swb.spt.Length = sizeof(SCSI_PASS_THROUGH); + swb.spt.CdbLength = lpsrb->SRB_CDBLen; + if ( lpsrb->SRB_Flags & SRB_DIR_IN ) + swb.spt.DataIn = SCSI_IOCTL_DATA_IN; + else if ( lpsrb->SRB_Flags & SRB_DIR_OUT ) + swb.spt.DataIn = SCSI_IOCTL_DATA_OUT; + else + swb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; + swb.spt.DataTransferLength = lpsrb->SRB_BufLen; + swb.spt.TimeOutValue = 5; + swb.spt.DataBuffer = lpsrb->SRB_BufPointer; + swb.spt.SenseInfoOffset = + offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf ); + memcpy( swb.spt.Cdb, lpsrb->CDBByte, lpsrb->SRB_CDBLen ); + length = sizeof(swb); + + status = DeviceIoControl( NtScsiDrives.drive[idx].hDevice, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &swb, + length, + &swb, + length, + &returned, + NULL ); + + if ( status ) + { + lpsrb->SRB_Status = SS_COMP; + } + else + { + DWORD dwErrCode; + + lpsrb->SRB_Status = SS_ERR; + lpsrb->SRB_TargStat = 0x0004; + dwErrCode = GetLastError(); + /* + * KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT! + * Whenever a disk changer switches disks, it may render the device + * handle invalid. We try to catch these errors here and recover + * from them. + */ + if ( !bBeenHereBefore && + ((dwErrCode == ERROR_MEDIA_CHANGED) || (dwErrCode == ERROR_INVALID_HANDLE)) ) + { + if ( dwErrCode != ERROR_INVALID_HANDLE ) + CloseHandle( NtScsiDrives.drive[idx].hDevice ); + GetDriveInformation( idx, &NtScsiDrives.drive[idx] ); + + return NtScsiExecSCSICommand( lpsrb, TRUE ); + } + } + + return lpsrb->SRB_Status; +} + + + +BOOL UsingSCSIPT( void ) +{ + return bUseNtScsi; +} + + + +/* + * Calls GetFileHandle for the CD refered to by ha:tgt:lun to open it for + * use + */ +void NtScsiOpenCDHandle( BYTE ha, BYTE tgt, BYTE lun ) +{ + BYTE idx; + + idx = NtScsiGetDeviceIndex( ha, tgt, lun ); + + if ( idx && NtScsiDrives.drive[idx].hDevice == INVALID_HANDLE_VALUE ) + NtScsiDrives.drive[idx].hDevice = GetFileHandle( NtScsiDrives.drive[idx].driveLetter ); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/NTScsi.h b/Src/Plugins/Input/in_cdda/windac/NTScsi.h new file mode 100644 index 00000000..895c787d --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/NTScsi.h @@ -0,0 +1,147 @@ +/* + * distilled information from various header files from Microsoft's + * DDK for Windows NT 4.0 + */ +#ifndef NTSCSI_H_INCLUDED +#define NTSCSI_H_INCLUDED + +#include <windows.h> +#include "Aspi.h" + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + + +typedef struct { + SCSI_PASS_THROUGH spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; + UCHAR ucDataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; + + +typedef struct { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + + + +typedef struct { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +} SCSI_BUS_DATA, *PSCSI_BUS_DATA; + + +typedef struct { + UCHAR NumberOfBusses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + + +typedef struct { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + + +typedef struct { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} SCSI_ADDRESS, *PSCSI_ADDRESS; + + +/* + * method codes + */ +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + * file access values + */ +#define FILE_ANY_ACCESS 0 +#ifndef FILE_READ_ACCESS +#define FILE_READ_ACCESS (0x0001) +#define FILE_WRITE_ACCESS (0x0002) +#endif + + +#define IOCTL_SCSI_BASE 0x00000004 + +/* + * constants for DataIn member of SCSI_PASS_THROUGH* structures + */ +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* + * Standard IOCTL define + */ +#define CTL_CODE( DevType, Function, Method, Access ) ( \ + ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS ) + +int NtScsiInit( void ); +int NtScsiDeInit( void ); + +BYTE NtScsiGetNumAdapters( void ); +DWORD NtScsiGetASPI32SupportInfo( void ); +DWORD NtScsiGetDeviceType( LPSRB_GDEVBLOCK lpsrb ); +BYTE NtScsiGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun ); + +DWORD NtScsiHandleHaInquiry( LPSRB_HAINQUIRY lpsrb ); +extern "C" DWORD NtScsiSendASPI32Command( LPSRB lpsrb ); +DWORD NtScsiExecSCSICommand( LPSRB_EXECSCSICMD lpsrb, BOOL bBeenHereBefore ); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/RESOURCE.H b/Src/Plugins/Input/in_cdda/windac/RESOURCE.H new file mode 100644 index 00000000..3a24dff9 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/RESOURCE.H @@ -0,0 +1,17 @@ +#if USE_WINDAC +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dac32.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/SCSIDEFS.H b/Src/Plugins/Input/in_cdda/windac/SCSIDEFS.H new file mode 100644 index 00000000..5012429f --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/SCSIDEFS.H @@ -0,0 +1,252 @@ +//********************************************************************** +// +// Name: SCSIDEFS.H +// +// Description: SCSI definitions ('C' Language) +// +//********************************************************************** +//********************************************************************** +// %%% TARGET STATUS VALUES %%% +//********************************************************************** +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full +//********************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//********************************************************************** +#define MAXLUN 7 // Maximum Logical Unit Id +#define MAXTARG 7 // Maximum Target Id +#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs +#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +//********************************************************************** +// %%% Commands for all Device Types %%% +//********************************************************************** +#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_COPY 0x18 // Copy (O) +#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) +#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) +#define SCSI_LOG_SELECT 0x4C // Log Select (O) +#define SCSI_LOG_SENSE 0x4D // Log Sense (O) +#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) +#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) +#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) +#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) +#define SCSI_READ_BUFF 0x3C // Read Buffer (O) +#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) +#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) +#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) +#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) +//********************************************************************** +// %%% Commands Unique to Direct Access Devices %%% +//********************************************************************** +#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) +#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) +#define SCSI_PREFETCH 0x34 // Prefetch (O) +#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) +#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) +#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) +#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) +#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) +#define SCSI_READ_LONG 0x3E // Read Long (O) +#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) +#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) +#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) +#define SCSI_REZERO 0x01 // Rezero Unit (O) +#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) +#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) +#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) +#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) +#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) +#define SCSI_SET_LIMIT 0x33 // Set Limits (O) +#define SCSI_START_STP 0x1B // Start/Stop Unit (O) +#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) +#define SCSI_VERIFY 0x2F // Verify (O) +#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) +#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) +#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) +#define SCSI_WRITE_LONG 0x3F // Write Long (O) +#define SCSI_WRITE_SAME 0x41 // Write Same (O) +//********************************************************************** +// %%% Commands Unique to Sequential Access Devices %%% +//********************************************************************** +#define SCSI_ERASE 0x19 // Erase (MANDATORY) +#define SCSI_LOAD_UN 0x1B // Load/Unload (O) +#define SCSI_LOCATE 0x2B // Locate (O) +#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) +#define SCSI_READ_POS 0x34 // Read Position (O) +#define SCSI_READ_REV 0x0F // Read Reverse (O) +#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) +#define SCSI_REWIND 0x01 // Rewind (MANDATORY) +#define SCSI_SPACE 0x11 // Space (MANDATORY) +#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) +#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) +#define SCSI_PARTITION 0x0D // DAT/QFA Partition Select +#define SCSI_READWRITE 0x06 // Set Read/Write Parameters +//********************************************************************** +// %%% Commands Unique to Printer Devices %%% +//********************************************************************** +#define SCSI_PRINT 0x0A // Print (MANDATORY) +#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) +#define SCSI_STOP_PNT 0x1B // Stop Print (O) +#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) +//********************************************************************** +// %%% Commands Unique to Processor Devices %%% +//********************************************************************** +#define SCSI_RECEIVE 0x08 // Receive (O) +#define SCSI_SEND 0x0A // Send (O) +//********************************************************************** +// %%% Commands Unique to Write-Once Devices %%% +//********************************************************************** +#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) +#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) +#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) +#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) +#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) +#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) +#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) +#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) +#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) +#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) +#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) +#define SCSI_WRITE12 0xAA // Write 12-Byte (O) +#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) +#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) +//********************************************************************** +// %%% Commands Unique to CD-ROM Devices %%% +//********************************************************************** +#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) +#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) +#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) +#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) +#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) +#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) +#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) +#define SCSI_READHEADER 0x44 // Read Header (O) +#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) +#define SCSI_READ_TOC 0x43 // Read TOC (O) +//********************************************************************** +// %%% Commands Unique to Scanner Devices %%% +//********************************************************************** +#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) +#define SCSI_GETWINDOW 0x25 // Get Window (O) +#define SCSI_OBJECTPOS 0x31 // Object Position (O) +#define SCSI_SCAN 0x1B // Scan (O) +#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) +//********************************************************************** +// %%% Commands Unique to Optical Memory Devices %%% +//********************************************************************** +#define SCSI_UpdateBlk 0x3D // Update Block (O) +//********************************************************************** +// %%% Commands Unique to Medium Changer Devices %%% +//********************************************************************** +#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) +#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) +#define SCSI_POSTOELEM 0x2B // Position to Element (O) +#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) +#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) +//********************************************************************** +// %%% Commands Unique to Communication Devices %%% +//********************************************************************** +#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) +#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) +#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) +#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) +#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) +#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% END OF SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +//********************************************************************** +// %%% Request Sense Data Format %%% +//********************************************************************** +typedef struct { + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier +// BYTE FieldRepUCode; // Field Replaceable Unit Code +// BYTE SenKeySpec15; // Sense Key Specific 15th byte +// BYTE SenKeySpec16; // Sense Key Specific 16th byte +// BYTE SenKeySpec17; // Sense Key Specific 17th byte +// BYTE AddSenseBytes; // Additional Sense Bytes +} SENSE_DATA_FMT; +//********************************************************************** +// %%% REQUEST SENSE ERROR CODE %%% +//********************************************************************** +#define SERROR_CURRENT 0x70 // Current Errors +#define SERROR_DEFERED 0x71 // Deferred Errors +//********************************************************************** +// %%% REQUEST SENSE BIT DEFINITIONS %%% +//********************************************************************** +#define SENSE_VALID 0x80 // Byte 0 Bit 7 +#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 +#define SENSE_EOM 0x40 // Byte 2 Bit 6 +#define SENSE_ILI 0x20 // Byte 2 Bit 5 +//********************************************************************** +// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% +//********************************************************************** +#define KEY_NOSENSE 0x00 // No Sense +#define KEY_RECERROR 0x01 // Recovered Error +#define KEY_NOTREADY 0x02 // Not Ready +#define KEY_MEDIUMERR 0x03 // Medium Error +#define KEY_HARDERROR 0x04 // Hardware Error +#define KEY_ILLGLREQ 0x05 // Illegal Request +#define KEY_UNITATT 0x06 // Unit Attention +#define KEY_DATAPROT 0x07 // Data Protect +#define KEY_BLANKCHK 0x08 // Blank Check +#define KEY_VENDSPEC 0x09 // Vendor Specific +#define KEY_COPYABORT 0x0A // Copy Abort +#define KEY_ABORT 0x0B // Abort +#define KEY_EQUAL 0x0C // Equal (Search) +#define KEY_VOLOVRFLW 0x0D // Volume Overflow +#define KEY_MISCOMP 0x0E // Miscompare (Search) +#define KEY_RESERVED 0x0F // Reserved +//********************************************************************** +// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% +//********************************************************************** +#define DTYPE_DASD 0x00 // Disk Device +#define DTYPE_SEQD 0x01 // Tape Device +#define DTYPE_PRNT 0x02 // Printer +#define DTYPE_PROC 0x03 // Processor +#define DTYPE_WORM 0x04 // Write-once read-multiple +#define DTYPE_CROM 0x05 // CD-ROM device +#define DTYPE_SCAN 0x06 // Scanner device +#define DTYPE_OPTI 0x07 // Optical memory device +#define DTYPE_JUKE 0x08 // Medium Changer device +#define DTYPE_COMM 0x09 // Communications device +#define DTYPE_RESL 0x0A // Reserved (low) +#define DTYPE_RESH 0x1E // Reserved (high) +#define DTYPE_UNKNOWN 0x1F // Unknown or no device type +//********************************************************************** +// %%% ANSI APPROVED VERSION DEFINITIONS %%% +//********************************************************************** +#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand +#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) +#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 +#define ANSI_RESLO 0x3 // Reserved (low) +#define ANSI_RESHI 0x7 // Reserved (high)
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/windac/Winaspi.h b/Src/Plugins/Input/in_cdda/windac/Winaspi.h new file mode 100644 index 00000000..5fc78fe5 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/windac/Winaspi.h @@ -0,0 +1,229 @@ +//********************************************************************** +// +// Name: WINASPI.H +// +// Description: ASPI for Windows definitions ('C' Language) +// +//********************************************************************** + +#ifndef _WINASPI_H +#define _WINASPI_H + +typedef BYTE *LPSRB; +#define SENSE_LEN 14 // Default sense buffer length +#define SRB_DIR_SCSI 0x00 // Direction determined by SCSI command +#define SRB_DIR_IN 0x08 // Transfer from SCSI target to host +#define SRB_DIR_OUT 0x10 // Transfer from host to SCSI targetw +#define SRB_POSTING 0x01 // Enable ASPI posting +#define SRB_EVENT_NOTIFY 0x40 // Enable ASPI command notification +#define SRB_ENABLE_RESIDUAL_COUNT 0x04 //Enable reporting of residual byte count +#define WM_ASPIPOST 0x4D42 // ASPI Post message +#define TIMEOUT 30000 // Wait 30 seconds + +//********************************************************************** +// %%% ASPI Command Definitions %%% +//********************************************************************** +#define SC_HA_INQUIRY 0x00 // Host adapter inquiry +#define SC_GET_DEV_TYPE 0x01 // Get device type +#define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI command +#define SC_ABORT_SRB 0x03 // Abort an SRB +#define SC_RESET_DEV 0x04 // SCSI bus device reset +//********************************************************************** +// %%% SRB Status %%% +//********************************************************************** +#define SS_PENDING 0x00 // SRB being processed +#define SS_COMP 0x01 // SRB completed without error +#define SS_ABORTED 0x02 // SRB aborted +#define SS_ABORT_FAIL 0x03 // Unable to abort SRB +#define SS_ERR 0x04 // SRB completed with error +#define SS_INVALID_CMD 0x80 // Invalid ASPI command +#define SS_INVALID_HA 0x81 // Invalid host adapter number +#define SS_NO_DEVICE 0x82 // SCSI device not installed +#define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB +#define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Window +#define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode +#define SS_NO_ASPI 0xE3 // No ASPI managers resident +#define SS_FAILED_INIT 0xE4 // ASPI for windows failed init +#define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute cmd +#define SS_BUFFER_TO_BIG 0xE6 // Buffer size to big to handle! +//********************************************************************** +// %%% Host Adapter Status %%% +//********************************************************************** +#define HASTAT_OK 0x00 // Host adapter did not detect an error +#define HASTAT_SEL_TO 0x11 // Selection Timeout +#define HASTAT_DO_DU 0x12 // Data overrun data underrun +#define HASTAT_BUS_FREE 0x13 // Unexpected bus free +#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence failure + + + + + +//********************************************************************** +// %%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY %%% +//********************************************************************** +#pragma pack(push,ASPI_Structures,1) + +typedef BYTE TDriveMode[64]; + +struct THAUnique +{ + WORD BufferAlignmentMask; + BYTE AdapterUniqueFlags; + BYTE MaximumSCSITargets; + DWORD MaximumTransferLen; + BYTE Reserved[8]; +}; + +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_HA_INQUIRY + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 + BYTE HA_Count; // Number of host adapters present + BYTE HA_SCSI_ID; // SCSI ID of host adapter + BYTE HA_ManagerId[16]; // String describing the manager + BYTE HA_Identifier[16]; // String describing the host adapter + THAUnique HA_Unique; // Host Adapter Unique parameters + WORD HA_Rsvd1; +} SRB_HAInquiry, *PSRB_HAInquiry; +//********************************************************************** +// %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE %%% +//********************************************************************** +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_GET_DEV_TYPE + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // Reserved + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + BYTE SRB_DeviceType; // Target's peripheral device type + BYTE SRB_Rsvd1; // Reserved for alignment +} SRB_GDEVBlock, *PSRB_GDEVBlock; +//********************************************************************** +// %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD %%% +//********************************************************************** +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_EXEC_SCSI_CMD + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + WORD SRB_Rsvd1; // Reserved for Alignment + DWORD SRB_BufLen; // Data Allocation Length + BYTE *SRB_BufPointer; // Data Buffer Point + BYTE SRB_SenseLen; // Sense Allocation Length + BYTE SRB_CDBLen; // CDB Length + BYTE SRB_HaStat; // Host Adapter Status + BYTE SRB_TargStat; // Target Status + void (*SRB_PostProc)(); // Post routine + void *SRB_Rsvd2; // Reserved + BYTE SRB_Rsvd3[16]; // Reserved for expansion + BYTE CDBByte[16]; // SCSI CDB + BYTE SenseArea[SENSE_LEN+2]; // Request Sense buffer +} SRB_ExecSCSICmd, *PSRB_ExecSCSICmd; +//********************************************************************** +// %%% SRB - ABORT AN SRB - SC_ABORT_SRB %%% +//********************************************************************** +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_ABORT_SRB + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // ASPI request flags + DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 + LPSRB SRB_ToAbort; // Pointer to SRB to abort +} SRB_Abort; +//********************************************************************** +// %%% SRB - BUS DEVICE RESET - SC_RESET_DEV %%% +//********************************************************************** +typedef struct +{ + BYTE SRB_Cmd; // ASPI command code = SC_RESET_DEV + BYTE SRB_Status; // ASPI command status byte + BYTE SRB_HaId; // ASPI host adapter number + BYTE SRB_Flags; // Reserved + DWORD SRB_Hdr_Rsvd; // Reserved + BYTE SRB_Target; // Target's SCSI ID + BYTE SRB_Lun; // Target's LUN number + BYTE SRB_Rsvd1[12]; // Reserved for Alignment + BYTE SRB_HaStat; // Host Adapter Status + BYTE SRB_TargStat; // Target Status + void *SRB_PostProc; // Post routine + void *SRB_Rsvd2; // Reserved + BYTE SRB_Rsvd3[32]; // Reserved +} SRB_BusDeviceReset, *PSRB_BusDeviceReset; + + +//********************************************************************** +// %%% Header for TOC Reading %%% +//********************************************************************** +struct TTrackInfo +{ + BYTE Reserved1; + BYTE AdrCtrl; + BYTE TrackNummer; + BYTE Reserved2; + DWORD AbsCDAdress; +}; + +struct TTOCHeader +{ + WORD TOCDataLength; + BYTE FirstTrack; + BYTE LastTrack; + TTrackInfo Info[100]; +}; + +//********************************************************************** +// %%% Structure for Read Sub-Channel %%% +//********************************************************************** +struct TQChannelInfo +{ + BYTE Reserved1; + BYTE AudioStatus; + WORD DataLen; + BYTE FormatCode; + BYTE ADRCtrl; + BYTE TrackNumber; + BYTE IndexNumber; + long AbsCDAdress; + long RelTrackAdress; +}; + +//********************************************************************** +// %%% Request Sense Data Format %%% +//********************************************************************** +typedef struct { + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier + BYTE FieldRepUCode; // Field Replaceable Unit Code + BYTE SenKeySpec15; // Sense Key Specific 15th byte + BYTE SenKeySpec16; // Sense Key Specific 16th byte + BYTE SenKeySpec17; // Sense Key Specific 17th byte + BYTE AddSenseBytes; // Additional Sense Bytes +} TSenseInfo; + +#pragma pack(pop,ASPI_Structures) + + +#endif //_WINASPI_H
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/workorder.cpp b/Src/Plugins/Input/in_cdda/workorder.cpp new file mode 100644 index 00000000..b5f8e8e9 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/workorder.cpp @@ -0,0 +1,53 @@ +#include "workorder.h" +#include "main.h" +#include "cddb.h" +#include <shlwapi.h> +CDDBModuleWorkOrderManagerInterface *workorder=0; +static HMODULE musicIDLib = 0; + +void OpenMusicIDWorkOrder() +{ + if (!workorder) + { + char pluginpath[MAX_PATH] = {0}; + GetModuleFileNameA(line.hDllInstance, pluginpath, MAX_PATH); + PathRemoveFileSpecA(pluginpath); + PathAppendA(pluginpath, "Gracenote"); + + char musicidpath[MAX_PATH] = {0}; + PathCombineA(musicidpath, pluginpath, "CddbWOManagerWinamp.dll"); + + musicIDLib = LoadLibraryA(musicidpath); + if (musicIDLib) + { + CDDBModuleQueryInterfaceFunc qi = (CDDBModuleQueryInterfaceFunc)GetProcAddress(musicIDLib, "CDDBModuleQueryInterface"); + if (qi) + { + ICDDBControl *pControl; + Cddb_GetIControl((void**)&pControl); + workorder = (CDDBModuleWorkOrderManagerInterface*)qi("workordermanager"); + if (!(workorder && workorder->base.version == CDDBMODULE_VERSION && workorder->version == CDDBMODULE_WORKORDER_MGR_VERSION + && workorder->base.Init && workorder->base.Init(0) + && workorder->Initialize(pControl, pluginpath) == 0)) + { + workorder = 0; + FreeLibrary(musicIDLib); + musicIDLib=0; + } + if (pControl) pControl->Release(); + } + } + } +} + +void ShutdownMusicIDWorkOrder() +{ + if (workorder) + workorder->Shutdown(); + + workorder=0; + + if (musicIDLib) + FreeLibrary(musicIDLib); + musicIDLib=0; +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_cdda/workorder.h b/Src/Plugins/Input/in_cdda/workorder.h new file mode 100644 index 00000000..664e77fa --- /dev/null +++ b/Src/Plugins/Input/in_cdda/workorder.h @@ -0,0 +1,10 @@ +#ifndef NULLSOFT_IN_CDDA_WORKORDER_H +#define NULLSOFT_IN_CDDA_WORKORDER_H + +#include "../gracenote/CDDBPluginWorkOrderManager.h" + +extern CDDBModuleWorkOrderManagerInterface *workorder; +void OpenMusicIDWorkOrder(); +void ShutdownMusicIDWorkOrder(); + +#endif
\ No newline at end of file |