diff options
Diffstat (limited to 'Src/Plugins/Input/in_cdda/Main.cpp')
-rw-r--r-- | Src/Plugins/Input/in_cdda/Main.cpp | 598 |
1 files changed, 598 insertions, 0 deletions
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 |