From d0ba990059db44a703ea7cbe0236c6aa6f148d78 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Wed, 14 Jul 2004 18:30:54 +0000 Subject: [PATCH] Sync msacm32 with Winehq cvs. will merge my tweaks soon. This gets Winamp5 loading. svn path=/trunk/; revision=10115 --- reactos/lib/msacm/Makefile.in | 2 + reactos/lib/msacm/Makefile.ros | 33 +- reactos/lib/msacm/Makefile.ros-template | 6 +- reactos/lib/msacm/driver.c | 185 +++- reactos/lib/msacm/format.c | 34 +- reactos/lib/msacm/internal.c | 78 +- reactos/lib/msacm/makefile | 16 +- reactos/lib/msacm/msacm.rc | 2 + reactos/lib/msacm/msacm32_main.c | 12 + reactos/lib/msacm/msacm_Es.rc | 56 ++ reactos/lib/msacm/msacm_It.rc | 2 +- reactos/lib/msacm/msacm_Ja.rc | 56 ++ reactos/lib/msacm/pcmconverter.c | 1223 +++++++++++++++++++++++ reactos/lib/msacm/stream.c | 478 +++++++++ reactos/lib/msacm/wineacm.h | 363 +++++++ 15 files changed, 2418 insertions(+), 128 deletions(-) create mode 100644 reactos/lib/msacm/msacm_Es.rc create mode 100644 reactos/lib/msacm/msacm_Ja.rc create mode 100644 reactos/lib/msacm/pcmconverter.c create mode 100644 reactos/lib/msacm/stream.c create mode 100644 reactos/lib/msacm/wineacm.h diff --git a/reactos/lib/msacm/Makefile.in b/reactos/lib/msacm/Makefile.in index f4cb7c1376c..247b6816e67 100644 --- a/reactos/lib/msacm/Makefile.in +++ b/reactos/lib/msacm/Makefile.in @@ -22,6 +22,8 @@ C_SRCS16 = \ RC_SRCS = msacm.rc +SUBDIRS = tests + @MAKE_DLL_RULES@ ### Dependencies: diff --git a/reactos/lib/msacm/Makefile.ros b/reactos/lib/msacm/Makefile.ros index 3fc9715f3e9..e53d73cd5ac 100644 --- a/reactos/lib/msacm/Makefile.ros +++ b/reactos/lib/msacm/Makefile.ros @@ -1,21 +1,12 @@ -# $Id: Makefile.ros,v 1.1 2004/03/10 15:22:44 silverblade Exp $ - -TARGET_NAME = msacm32 - -TARGET_OBJECTS = driver.o filter.o format.o internal.o msacm32_main.o pcmconverter.o stream.o - -TARGET_CFLAGS = -D__REACTOS__ - -TARGET_SDKLIBS = winmm.a libwine.a advapi32.a kernel32.a ws2_32.a wine_uuid.a ntdll.a - -TARGET_BASE = 0x77300000 - -TARGET_RC_SRCS = msacm.rc -TARGET_RC_BINSRC = msacm.rc -TARGET_RC_BINARIES = - -default: all - -DEP_OBJECTS = $(TARGET_OBJECTS) - -include $(TOOLS_PATH)/depend.mk +# $Id: Makefile.ros,v 1.2 2004/07/14 18:30:54 sedwards Exp $ +TARGET_NAME = msacm32 +TARGET_OBJECTS = driver.o filter.o format.o internal.o msacm32_main.o pcmconverter.o stream.o +TARGET_CFLAGS = -D__REACTOS__ +TARGET_SDKLIBS = winmm.a user32.a advapi32.a kernel32.a ntdll.a libwine.a +TARGET_BASE = $(TARGET_BASE_LIB_MSACM) +TARGET_RC_SRCS = msacm.rc +TARGET_RC_BINSRC = +TARGET_RC_BINARIES = +default: all +DEP_OBJECTS = $(TARGET_OBJECTS) +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/msacm/Makefile.ros-template b/reactos/lib/msacm/Makefile.ros-template index ad08d203471..b9a2fa1f289 100644 --- a/reactos/lib/msacm/Makefile.ros-template +++ b/reactos/lib/msacm/Makefile.ros-template @@ -1,12 +1,12 @@ -# $Id: Makefile.ros-template,v 1.2 2004/05/29 21:24:44 hbirr Exp $ +# $Id: Makefile.ros-template,v 1.3 2004/07/14 18:30:54 sedwards Exp $ -TARGET_NAME = iphlpapi +TARGET_NAME = msacm32 TARGET_OBJECTS = @C_SRCS@ TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ -TARGET_SDKLIBS = @IMPORTS@ libwine.a advapi32.a kernel32.a ws2_32.a wine_uuid.a ntdll.a +TARGET_SDKLIBS = @IMPORTS@ ntdll.a libwine.a TARGET_BASE = $(TARGET_BASE_LIB_MSACM) diff --git a/reactos/lib/msacm/driver.c b/reactos/lib/msacm/driver.c index b473f9c4d73..dab014f4db3 100644 --- a/reactos/lib/msacm/driver.c +++ b/reactos/lib/msacm/driver.c @@ -49,19 +49,28 @@ WINE_DEFAULT_DEBUG_CHANNEL(msacm); MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule, LPARAM lParam, DWORD dwPriority, DWORD fdwAdd) { - if (!phadid) + TRACE("(%p, %p, %08lx, %08lx, %08lx)\n", + phadid, hinstModule, lParam, dwPriority, fdwAdd); + + if (!phadid) { + WARN("invalid parameter\n"); return MMSYSERR_INVALPARAM; + } /* Check if any unknown flags */ if (fdwAdd & ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND| - ACM_DRIVERADDF_GLOBAL)) + ACM_DRIVERADDF_GLOBAL)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } /* Check if any incompatible flags */ if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && - (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) + (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a * LoadDriver on it, to be sure we can call SendDriverMessage on the @@ -98,12 +107,18 @@ MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose) PWINE_ACMDRIVERID padid; PWINE_ACMDRIVER* tpad; - if (fdwClose) + TRACE("(%p, %08lx)\n", had, fdwClose); + + if (fdwClose) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } pad = MSACM_GetDriver(had); - if (!pad) + if (!pad) { + WARN("invalid handle\n"); return MMSYSERR_INVALHANDLE; + } padid = pad->obj.pACMDriverID; @@ -132,29 +147,44 @@ MMRESULT WINAPI acmDriverDetailsA(HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, D MMRESULT mmr; ACMDRIVERDETAILSW addw; + TRACE("(%p, %p, %08lx)\n", hadid, padd, fdwDetails); + + if (!padd) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + if (padd->cbStruct < 4) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + addw.cbStruct = sizeof(addw); mmr = acmDriverDetailsW(hadid, &addw, fdwDetails); if (mmr == 0) { - padd->fccType = addw.fccType; - padd->fccComp = addw.fccComp; - padd->wMid = addw.wMid; - padd->wPid = addw.wPid; - padd->vdwACM = addw.vdwACM; - padd->vdwDriver = addw.vdwDriver; - padd->fdwSupport = addw.fdwSupport; - padd->cFormatTags = addw.cFormatTags; - padd->cFilterTags = addw.cFilterTags; - padd->hicon = addw.hicon; - WideCharToMultiByte( CP_ACP, 0, addw.szShortName, -1, padd->szShortName, - sizeof(padd->szShortName), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, addw.szLongName, -1, padd->szLongName, - sizeof(padd->szLongName), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, addw.szCopyright, -1, padd->szCopyright, - sizeof(padd->szCopyright), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, addw.szLicensing, -1, padd->szLicensing, - sizeof(padd->szLicensing), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, addw.szFeatures, -1, padd->szFeatures, - sizeof(padd->szFeatures), NULL, NULL ); + ACMDRIVERDETAILSA padda; + + padda.fccType = addw.fccType; + padda.fccComp = addw.fccComp; + padda.wMid = addw.wMid; + padda.wPid = addw.wPid; + padda.vdwACM = addw.vdwACM; + padda.vdwDriver = addw.vdwDriver; + padda.fdwSupport = addw.fdwSupport; + padda.cFormatTags = addw.cFormatTags; + padda.cFilterTags = addw.cFilterTags; + padda.hicon = addw.hicon; + WideCharToMultiByte( CP_ACP, 0, addw.szShortName, -1, padda.szShortName, + sizeof(padda.szShortName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, addw.szLongName, -1, padda.szLongName, + sizeof(padda.szLongName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, addw.szCopyright, -1, padda.szCopyright, + sizeof(padda.szCopyright), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, addw.szLicensing, -1, padda.szLicensing, + sizeof(padda.szLicensing), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, addw.szFeatures, -1, padda.szFeatures, + sizeof(padda.szFeatures), NULL, NULL ); + memcpy(padd, &padda, min(padd->cbStruct, sizeof(*padd))); } return mmr; } @@ -167,14 +197,30 @@ MMRESULT WINAPI acmDriverDetailsW(HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, D HACMDRIVER acmDrvr; MMRESULT mmr; - if (fdwDetails) + TRACE("(%p, %p, %08lx)\n", hadid, padd, fdwDetails); + + if (!padd) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + if (padd->cbStruct < 4) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + if (fdwDetails) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } mmr = acmDriverOpen(&acmDrvr, hadid, 0); if (mmr == MMSYSERR_NOERROR) { - mmr = (MMRESULT)MSACM_Message(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM)padd, 0); + ACMDRIVERDETAILSW paddw; + mmr = (MMRESULT)MSACM_Message(acmDrvr, ACMDM_DRIVER_DETAILS, (LPARAM)&paddw, 0); acmDriverClose(acmDrvr, 0); + memcpy(padd, &paddw, min(padd->cbStruct, sizeof(*padd))); } return mmr; @@ -188,10 +234,17 @@ MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWOR PWINE_ACMDRIVERID padid; DWORD fdwSupport; - if (!fnCallback) return MMSYSERR_INVALPARAM; + TRACE("(%p, %08lx, %08lx)\n", fnCallback, dwInstance, fdwEnum); - if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) + if (!fnCallback) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + if (fdwEnum & ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) { fdwSupport = padid->fdwSupport; @@ -216,15 +269,23 @@ MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID { PWINE_ACMOBJ pao; - if (!phadid) - return MMSYSERR_INVALPARAM; + TRACE("(%p, %p, %08lx)\n", hao, phadid, fdwDriverID); - if (fdwDriverID) + if (fdwDriverID) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } pao = MSACM_GetObj(hao, WINE_ACMOBJ_DONTCARE); - if (!pao) + if (!pao) { + WARN("invalid handle\n"); return MMSYSERR_INVALHANDLE; + } + + if (!phadid) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } *phadid = (HACMDRIVERID) pao->pACMDriverID; @@ -237,11 +298,15 @@ MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID */ LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2) { + TRACE("(%p, %04x, %08lx, %08lx\n", had, uMsg, lParam1, lParam2); + if ((uMsg >= ACMDM_USER && uMsg < ACMDM_RESERVED_LOW) || uMsg == ACMDM_DRIVER_ABOUT || uMsg == DRV_QUERYCONFIGURE || uMsg == DRV_CONFIGURE) return MSACM_Message(had, uMsg, lParam1, lParam2); + + WARN("invalid parameter\n"); return MMSYSERR_INVALPARAM; } @@ -256,19 +321,27 @@ MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpe TRACE("(%p, %p, %08lu)\n", phad, hadid, fdwOpen); - if (!phad) + if (!phad) { + WARN("invalid parameter\n"); return MMSYSERR_INVALPARAM; + } - if (fdwOpen) + if (fdwOpen) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } padid = MSACM_GetDriverID(hadid); - if (!padid) + if (!padid) { + WARN("invalid handle\n"); return MMSYSERR_INVALHANDLE; + } pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER)); - if (!pad) + if (!pad) { + WARN("no memory\n"); return MMSYSERR_NOMEM; + } pad->obj.dwType = WINE_ACMOBJ_DRIVER; pad->obj.pACMDriverID = padid; @@ -317,6 +390,7 @@ MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpe return MMSYSERR_NOERROR; gotError: + WARN("failed: ret = %08x\n", ret); if (pad && !pad->hDrvr) HeapFree(MSACM_hHeap, 0, pad); return ret; @@ -335,25 +409,35 @@ MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fd HKEY hPriorityKey; DWORD dwPriorityCounter; + TRACE("(%p, %08lx, %08lx)\n", hadid, dwPriority, fdwPriority); + padid = MSACM_GetDriverID(hadid); - if (!padid) + if (!padid) { + WARN("invalid handle\n"); return MMSYSERR_INVALHANDLE; + } /* Check for unknown flags */ if (fdwPriority & ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE| - ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) + ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } /* Check for incompatible flags */ if ((fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) && - (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) + (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } /* Check for incompatible flags */ if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) && - (fdwPriority & ACM_DRIVERPRIORITYF_END)) + (fdwPriority & ACM_DRIVERPRIORITYF_END)) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } lError = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Multimedia\\" @@ -361,8 +445,10 @@ MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fd &hPriorityKey ); /* FIXME: Create key */ - if (lError != ERROR_SUCCESS) + if (lError != ERROR_SUCCESS) { + WARN("RegOpenKeyA failed\n"); return MMSYSERR_ERROR; + } for (dwPriorityCounter = 1; ; dwPriorityCounter++) { snprintf(szSubKey, 17, "Priority%ld", dwPriorityCounter); @@ -377,6 +463,7 @@ MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fd RegCloseKey(hPriorityKey); + WARN("RegQueryValueA failed\n"); return MMSYSERR_ERROR; } @@ -387,12 +474,18 @@ MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove) { PWINE_ACMDRIVERID padid; - padid = MSACM_GetDriverID(hadid); - if (!padid) - return MMSYSERR_INVALHANDLE; + TRACE("(%p, %08lx)\n", hadid, fdwRemove); - if (fdwRemove) + padid = MSACM_GetDriverID(hadid); + if (!padid) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + + if (fdwRemove) { + WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; + } MSACM_UnregisterDriver(padid); diff --git a/reactos/lib/msacm/format.c b/reactos/lib/msacm/format.c index b6825689140..b64f8b0db5d 100644 --- a/reactos/lib/msacm/format.c +++ b/reactos/lib/msacm/format.c @@ -317,8 +317,8 @@ MMRESULT WINAPI acmFormatDetailsA(HACMDRIVER had, PACMFORMATDETAILSA pafd, MMRESULT WINAPI acmFormatDetailsW(HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD fdwDetails) { MMRESULT mmr; - static WCHAR fmt1[] = {'%','d',' ','H','z',0}; - static WCHAR fmt2[] = {';',' ','%','d',' ','b','i','t','s',0}; + static const WCHAR fmt1[] = {'%','d',' ','H','z',0}; + static const WCHAR fmt2[] = {';',' ','%','d',' ','b','i','t','s',0}; ACMFORMATTAGDETAILSA aftd; TRACE("(%p, %p, %ld)\n", had, pafd, fdwDetails); @@ -411,6 +411,12 @@ MMRESULT WINAPI acmFormatEnumA(HACMDRIVER had, PACMFORMATDETAILSA pafda, ACMFORMATDETAILSW afdw; struct MSACM_FormatEnumWtoA_Instance afei; + if (!pafda) + return MMSYSERR_INVALPARAM; + + if (pafda->cbStruct < sizeof(*pafda)) + return MMSYSERR_INVALPARAM; + memset(&afdw, 0, sizeof(afdw)); afdw.cbStruct = sizeof(afdw); afdw.dwFormatIndex = pafda->dwFormatIndex; @@ -489,7 +495,11 @@ MMRESULT WINAPI acmFormatEnumW(HACMDRIVER had, PACMFORMATDETAILSW pafd, TRACE("(%p, %p, %p, %ld, %ld)\n", had, pafd, fnCallback, dwInstance, fdwEnum); - if (pafd->cbStruct < sizeof(*pafd)) return MMSYSERR_INVALPARAM; + if (!pafd) + return MMSYSERR_INVALPARAM; + + if (pafd->cbStruct < sizeof(*pafd)) + return MMSYSERR_INVALPARAM; if (fdwEnum & (ACM_FORMATENUMF_WFORMATTAG|ACM_FORMATENUMF_NCHANNELS| ACM_FORMATENUMF_NSAMPLESPERSEC|ACM_FORMATENUMF_WBITSPERSAMPLE| @@ -731,6 +741,15 @@ MMRESULT WINAPI acmFormatTagEnumA(HACMDRIVER had, PACMFORMATTAGDETAILSA paftda, ACMFORMATTAGDETAILSW aftdw; struct MSACM_FormatTagEnumWtoA_Instance aftei; + if (!paftda) + return MMSYSERR_INVALPARAM; + + if (paftda->cbStruct < sizeof(*paftda)) + return MMSYSERR_INVALPARAM; + + if (fdwEnum != 0) + return MMSYSERR_INVALFLAG; + memset(&aftdw, 0, sizeof(aftdw)); aftdw.cbStruct = sizeof(aftdw); aftdw.dwFormatTagIndex = paftda->dwFormatTagIndex; @@ -758,7 +777,14 @@ MMRESULT WINAPI acmFormatTagEnumW(HACMDRIVER had, PACMFORMATTAGDETAILSW paftd, TRACE("(%p, %p, %p, %ld, %ld)\n", had, paftd, fnCallback, dwInstance, fdwEnum); - if (paftd->cbStruct < sizeof(*paftd)) return MMSYSERR_INVALPARAM; + if (!paftd) + return MMSYSERR_INVALPARAM; + + if (paftd->cbStruct < sizeof(*paftd)) + return MMSYSERR_INVALPARAM; + + if (fdwEnum != 0) + return MMSYSERR_INVALFLAG; /* (WS) MSDN info page says that if had != 0, then we should find * the specific driver to get its tags from. Therefore I'm removing diff --git a/reactos/lib/msacm/internal.c b/reactos/lib/msacm/internal.c index d54c7640214..9cb8002a380 100644 --- a/reactos/lib/msacm/internal.c +++ b/reactos/lib/msacm/internal.c @@ -236,7 +236,7 @@ static BOOL MSACM_WriteCache(PWINE_ACMDRIVERID padid) /*********************************************************************** * MSACM_RegisterDriver() */ -PWINE_ACMDRIVERID MSACM_RegisterDriver(LPWSTR pszDriverAlias, LPWSTR pszFileName, +PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName, HINSTANCE hinstModule) { PWINE_ACMDRIVERID padid; @@ -283,48 +283,50 @@ PWINE_ACMDRIVERID MSACM_RegisterDriver(LPWSTR pszDriverAlias, LPWSTR pszFileName */ void MSACM_RegisterAllDrivers(void) { - LPWSTR pszBuffer; - DWORD dwBufferLength; - static WCHAR msacm32[] = {'m','s','a','c','m','3','2','.','d','l','l','\0'}; - static WCHAR msacmW[] = {'M','S','A','C','M','.'}; - static WCHAR drv32[] = {'d','r','i','v','e','r','s','3','2','\0'}; - static WCHAR sys[] = {'s','y','s','t','e','m','.','i','n','i','\0'}; + static const WCHAR msacm32[] = {'m','s','a','c','m','3','2','.','d','l','l','\0'}; + static const WCHAR msacmW[] = {'M','S','A','C','M','.'}; + static const WCHAR drv32[] = {'d','r','i','v','e','r','s','3','2','\0'}; + static const WCHAR sys[] = {'s','y','s','t','e','m','.','i','n','i','\0'}; + static const WCHAR drvkey[] = {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'D','r','i','v','e','r','s','3','2','\0'}; + DWORD i, cnt = 0, bufLen, lRet; + WCHAR buf[2048], *name, *s; + FILETIME lastWrite; + HKEY hKey; - /* FIXME - * What if the user edits system.ini while the program is running? - * Does Windows handle that? - */ - if (MSACM_pFirstACMDriverID) - return; + /* FIXME: What if the user edits system.ini while the program is running? + * Does Windows handle that? */ + if (MSACM_pFirstACMDriverID) return; - /* FIXME: Does not work! How do I determine the section length? */ - dwBufferLength = 1024; -/* EPP GetPrivateProfileSectionA("drivers32", NULL, 0, "system.ini"); */ - - pszBuffer = (LPWSTR) HeapAlloc(MSACM_hHeap, 0, dwBufferLength * sizeof(WCHAR)); - if (GetPrivateProfileSectionW(drv32, pszBuffer, dwBufferLength, sys)) - { - LPWSTR s = pszBuffer, s2; - - while (*s) - { - CharUpperBuffW(s, 6); - if (memcmp(s, msacmW, 6 * sizeof(WCHAR)) == 0) - { - s2 = s; - while (*s2 != '\0' && *s2 != '=') s2++; - if (*s2) - { - *s2 = '\0'; - MSACM_RegisterDriver(s, s2 + 1, 0); - *s2 = '='; - } - } - s += strlenW(s) + 1; /* Either next char or \0 */ + lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drvkey, 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) { + RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); + for (i = 0; i < cnt; i++) { + bufLen = sizeof(buf) / sizeof(buf[0]); + lRet = RegEnumKeyExW(hKey, i, buf, &bufLen, 0, 0, 0, &lastWrite); + if (lRet != ERROR_SUCCESS) continue; + if (strncmpiW(buf, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue; + if (!(name = strchrW(buf, '='))) continue; + *name = 0; + MSACM_RegisterDriver(buf, name + 1, 0); } + RegCloseKey( hKey ); } - HeapFree(MSACM_hHeap, 0, pszBuffer); + if (GetPrivateProfileSectionW(drv32, buf, sizeof(buf)/sizeof(buf[0]), sys)) + { + for(s = buf; *s; s += strlenW(s) + 1) + { + if (strncmpiW(s, msacmW, sizeof(msacmW)/sizeof(msacmW[0]))) continue; + if (!(name = strchrW(s, '='))) continue; + *name = 0; + MSACM_RegisterDriver(s, name + 1, 0); + *name = '='; + } + } MSACM_RegisterDriver(msacm32, msacm32, 0); } diff --git a/reactos/lib/msacm/makefile b/reactos/lib/msacm/makefile index 24c40308492..fbf1cf844af 100644 --- a/reactos/lib/msacm/makefile +++ b/reactos/lib/msacm/makefile @@ -1,23 +1,9 @@ -# $Id: makefile +# $Id: makefile,v 1.2 2004/07/14 18:30:54 sedwards Exp $ PATH_TO_TOP = ../.. TARGET_TYPE = winedll -TARGET_NAME = msacm32 - -TARGET_BASE = 0x777c0000 - -TARGET_CFLAGS += -DYDEBUG -DUNICODE -D_UNICODE -D__USE_W32API -D__REACTOS__ -Wall -Werror -# -D_WIN32_WINNT=0x0500 - -TARGET_SDKLIBS = ntdll.a winmm.a - -DEP_OBJECTS = $(TARGET_OBJECTS) - include $(PATH_TO_TOP)/rules.mak include $(TOOLS_PATH)/helper.mk - -include $(TOOLS_PATH)/depend.mk - diff --git a/reactos/lib/msacm/msacm.rc b/reactos/lib/msacm/msacm.rc index 3aee776beeb..186ab00b7de 100644 --- a/reactos/lib/msacm/msacm.rc +++ b/reactos/lib/msacm/msacm.rc @@ -24,7 +24,9 @@ #include "wineacm.h" #include "msacm_En.rc" +#include "msacm_Es.rc" #include "msacm_Fr.rc" #include "msacm_It.rc" +#include "msacm_Ja.rc" #include "msacm_Nl.rc" #include "msacm_Pt.rc" diff --git a/reactos/lib/msacm/msacm32_main.c b/reactos/lib/msacm/msacm32_main.c index 6ca97e9e3be..dde962a2dfe 100644 --- a/reactos/lib/msacm/msacm32_main.c +++ b/reactos/lib/msacm/msacm32_main.c @@ -120,6 +120,7 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) /* fall through */ case ACM_METRIC_COUNT_LOCAL_DRIVERS: if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && CheckLocal(padid)) val++; @@ -131,6 +132,7 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) /* fall through */ case ACM_METRIC_COUNT_LOCAL_CODECS: if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) && @@ -144,6 +146,7 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) /* fall through */ case ACM_METRIC_COUNT_LOCAL_CONVERTERS: if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER) && @@ -157,6 +160,7 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) /* fall through */ case ACM_METRIC_COUNT_LOCAL_FILTERS: if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_FILTER) && @@ -170,6 +174,7 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) /* fall through */ case ACM_METRIC_COUNT_LOCAL_DISABLED: if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; for (padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) if ((padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) && CheckLocal(padid)) val++; @@ -204,10 +209,17 @@ MMRESULT WINAPI acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric) } else { return MMSYSERR_INVALHANDLE; } + if (!pMetric) return MMSYSERR_INVALPARAM; *(LPDWORD)pMetric = val; break; case ACM_METRIC_COUNT_HARDWARE: + if (hao) return MMSYSERR_INVALHANDLE; + if (!pMetric) return MMSYSERR_INVALPARAM; + *(LPDWORD)pMetric = 0; + FIXME("ACM_METRIC_COUNT_HARDWARE not implemented\n"); + break; + case ACM_METRIC_HARDWARE_WAVE_INPUT: case ACM_METRIC_HARDWARE_WAVE_OUTPUT: case ACM_METRIC_MAX_SIZE_FILTER: diff --git a/reactos/lib/msacm/msacm_Es.rc b/reactos/lib/msacm/msacm_Es.rc new file mode 100644 index 00000000000..642e06780c5 --- /dev/null +++ b/reactos/lib/msacm/msacm_Es.rc @@ -0,0 +1,56 @@ +/* + * Spanish resource file for MS ACM + * + * Copyright 2004 José Manuel Ferrer Ortiz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_SPANISH, SUBLANG_DEFAULT + +DLG_ACMFORMATCHOOSE_ID DIALOG DISCARDABLE 10, 20, 225, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Selección de sonido" +FONT 8, "MS Shell Dlg" +BEGIN + + LTEXT "&Nombre:", -1, 5, 5, 115, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_CUSTOM, 5, 15, 115, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON "&Guardar como...", IDD_ACMFORMATCHOOSE_BTN_SETNAME, 125, 14, 45, 14 + PUSHBUTTON "&Eliminar", IDD_ACMFORMATCHOOSE_BTN_DELNAME, 175, 14, 45, 14 + + LTEXT "&Formato:", -1, 5, 41, 44, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, 50, 39, 170, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + LTEXT "A&tributos:", -1, 5, 59, 44, 8, NOT WS_GROUP + +#if 0 + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP | + CBS_OWNERDRAWFIXED | CBS_HASSTRINGS +#else + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +#endif + DEFPUSHBUTTON "Aceptar", IDOK, 48, 80, 40, 14 + PUSHBUTTON "Cancelar", IDCANCEL, 92, 80, 40, 14 + PUSHBUTTON "&Ayuda", IDD_ACMFORMATCHOOSE_BTN_HELP, 136, 80, 40, 14 + +END diff --git a/reactos/lib/msacm/msacm_It.rc b/reactos/lib/msacm/msacm_It.rc index 40d93d64e3e..4fdfb93a9aa 100644 --- a/reactos/lib/msacm/msacm_It.rc +++ b/reactos/lib/msacm/msacm_It.rc @@ -2,7 +2,7 @@ * Italian resource file for MS ACM * * Copyright 2000 Eric Pouech - * Copyright 2003 Ivan Leo Murray-Smith + * Copyright 2003 Ivan Leo Puoti * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/reactos/lib/msacm/msacm_Ja.rc b/reactos/lib/msacm/msacm_Ja.rc new file mode 100644 index 00000000000..01e7ba31372 --- /dev/null +++ b/reactos/lib/msacm/msacm_Ja.rc @@ -0,0 +1,56 @@ +/* + * Japanese resource file for MS ACM + * + * Copyright 2000 Hajime Segawa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT + +DLG_ACMFORMATCHOOSE_ID DIALOG DISCARDABLE 10, 20, 225, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "ƒTƒEƒ“ƒh‚Ì‘I‘ð" +FONT 9, "MS UI Gothic" +BEGIN + + LTEXT "–¼‘O(&N):", -1, 5, 5, 115, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_CUSTOM, 5, 15, 115, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON "–¼‘O‚ð•t‚¯‚Ä•Û‘¶(&S)...", IDD_ACMFORMATCHOOSE_BTN_SETNAME, 125, 14, 45, 14 + PUSHBUTTON "íœ(&R)", IDD_ACMFORMATCHOOSE_BTN_DELNAME, 175, 14, 45, 14 + + LTEXT "ƒtƒH[ƒ}ƒbƒg(&F):", -1, 5, 41, 44, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, 50, 39, 170, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + LTEXT "‘®«(&A):", -1, 5, 59, 44, 8, NOT WS_GROUP + +#if 0 + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP | + CBS_OWNERDRAWFIXED | CBS_HASSTRINGS +#else + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +#endif + DEFPUSHBUTTON "OK", IDOK, 48, 80, 40, 14 + PUSHBUTTON "ƒLƒƒƒ“ƒZƒ‹", IDCANCEL, 92, 80, 40, 14 + PUSHBUTTON "ƒwƒ‹ƒv(&H)", IDD_ACMFORMATCHOOSE_BTN_HELP, 136, 80, 40, 14 + +END diff --git a/reactos/lib/msacm/pcmconverter.c b/reactos/lib/msacm/pcmconverter.c new file mode 100644 index 00000000000..3f335d005ce --- /dev/null +++ b/reactos/lib/msacm/pcmconverter.c @@ -0,0 +1,1223 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MSACM32 library + * + * Copyright 2000 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME / TODO list + * + most of the computation should be done in fixed point arithmetic + * instead of floating point (16 bits for integral part, and 16 bits + * for fractional part for example) + * + implement PCM_FormatSuggest function + * + get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export + * a DriverProc, but this would require implementing a generic + * embedded driver handling scheme in msacm32.dll which isn't done yet + */ + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "mmreg.h" +#include "msacm.h" +#include "wingdi.h" +#include "winnls.h" +#include "winuser.h" + +#include "msacmdrv.h" +#include "wineacm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msacm); + +/*********************************************************************** + * PCM_drvOpen + */ +static DWORD PCM_drvOpen(LPCSTR str, PACMDRVOPENDESCW adod) +{ + TRACE("(%p, %p)\n", str, adod); + + return (adod == NULL) || + (adod->fccType == ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC && + adod->fccComp == ACMDRIVERDETAILS_FCCCOMP_UNDEFINED); +} + +/*********************************************************************** + * PCM_drvClose + */ +static DWORD PCM_drvClose(DWORD dwDevID) +{ + TRACE("(%ld)\n", dwDevID); + + return 1; +} + +#define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) +#define NUM_OF(a,b) (((a)+(b)-1)/(b)) + +/* flags for fdwDriver */ +#define PCM_RESAMPLE 1 + +/* data used while converting */ +typedef struct tagAcmPcmData { + /* conversion routine, depending if rate conversion is required */ + union { + void (*cvtKeepRate)(const unsigned char*, int, unsigned char*); + void (*cvtChangeRate)(struct tagAcmPcmData*, const unsigned char*, + LPDWORD, unsigned char*, LPDWORD); + } cvt; + /* the following fields are used only with rate conversion) */ + DWORD srcPos; /* position in source stream */ + double dstPos; /* position in destination stream */ + double dstIncr; /* value to increment dst stream when src stream + is incremented by 1 */ + /* last source stream value read */ + union { + unsigned char b; /* 8 bit value */ + short s; /* 16 bit value */ + } last[2]; /* two channels max (stereo) */ +} AcmPcmData; + +/* table to list all supported formats... those are the basic ones. this + * also helps given a unique index to each of the supported formats + */ +static struct { + int nChannels; + int nBits; + int rate; +} PCM_Formats[] = { + {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000}, + {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025}, + {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050}, + {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100}, + {1, 8, 48000}, {2, 8, 48000}, {1, 16, 48000}, {2, 16, 48000}, + {1, 8, 96000}, {2, 8, 96000}, {1, 16, 96000}, {2, 16, 96000} +}; + +/*********************************************************************** + * PCM_GetFormatIndex + */ +static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx) +{ + int i; + TRACE("(%p)\n", wfx); + + for (i = 0; i < NUM_PCM_FORMATS; i++) { + if (wfx->nChannels == PCM_Formats[i].nChannels && + wfx->nSamplesPerSec == PCM_Formats[i].rate && + wfx->wBitsPerSample == PCM_Formats[i].nBits) + return i; + } + return 0xFFFFFFFF; +} + +/* PCM Conversions: + * + * parameters: + * + 8 bit unsigned vs 16 bit signed + * + mono vs stereo (1 or 2 channels) + * + sampling rate (8.0, 11.025, 22.05, 44.1 kHz are defined, but algo + * shall work in all cases) + * + * mono => stereo: copy the same sample on Left & Right channels + * stereo =) mono: use the average value of samples from Left & Right channels + * resampling; we lookup for each destination sample the two source adjacent + * samples were src <= dst < src+1 (dst is increased by a fractional + * value which is equivalent to the increment by one on src); then we + * use a linear interpolation between src and src+1 + */ + +/*********************************************************************** + * C816 + * + * Converts a 8 bit sample to a 16 bit one + */ +static inline short C816(unsigned char b) +{ + return (short)((b+(b << 8))-32768); +} + +/*********************************************************************** + * C168 + * + * Converts a 16 bit sample to a 8 bit one (data loss !!) + */ +static inline unsigned char C168(short s) +{ + return HIBYTE(s) ^ (unsigned char)0x80; +} + +/*********************************************************************** + * R16 + * + * Read a 16 bit sample (correctly handles endianess) + */ +static inline short R16(const unsigned char* src) +{ + return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8)); +} + +/*********************************************************************** + * W16 + * + * Write a 16 bit sample (correctly handles endianess) + */ +static inline void W16(unsigned char* dst, short s) +{ + dst[0] = LOBYTE(s); + dst[1] = HIBYTE(s); +} + +/*********************************************************************** + * M16 + * + * Convert the (l,r) 16 bit stereo sample into a 16 bit mono + * (takes the mid-point of the two values) + */ +static inline short M16(short l, short r) +{ + return (l + r) / 2; +} + +/*********************************************************************** + * M8 + * + * Convert the (l,r) 8 bit stereo sample into a 8 bit mono + * (takes the mid-point of the two values) + */ +static inline unsigned char M8(unsigned char a, unsigned char b) +{ + return (unsigned char)((a + b) / 2); +} + +/* the conversion routines without rate conversion are labelled cvtK + * where : + * is the (M)ono/(S)tereo configuration of input channel + * is the (M)ono/(S)tereo configuration of output channel + * is the number of bits of input channel (8 or 16) + * is the number of bits of output channel (8 or 16) + * + * in the parameters, ns is always the number of samples, so the size of input + * buffer (resp output buffer) is ns * ( == 'Mono' ? 1:2) * ( == 8 ? 1:2) + */ + +static void cvtMM88K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + memcpy(dst, src, ns); +} + +static void cvtSS88K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + memcpy(dst, src, ns * 2); +} + +static void cvtMM1616K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + memcpy(dst, src, ns * 2); +} + +static void cvtSS1616K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + memcpy(dst, src, ns * 4); +} + +static void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + *dst++ = *src; + *dst++ = *src++; + } +} + +static void cvtMS816K(const unsigned char* src, int ns, unsigned char* dst) +{ + short v; + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + v = C816(*src++); + W16(dst, v); dst += 2; + W16(dst, v); dst += 2; + } +} + +static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst) +{ + unsigned char v; + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + v = C168(R16(src)); src += 2; + *dst++ = v; + *dst++ = v; + } +} + +static void cvtMS1616K(const unsigned char* src, int ns, unsigned char* dst) +{ + short v; + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + v = R16(src); src += 2; + W16(dst, v); dst += 2; + W16(dst, v); dst += 2; + } +} + +static void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + *dst++ = M8(src[0], src[1]); + src += 2; + } +} + +static void cvtSM816K(const unsigned char* src, int ns, unsigned char* dst) +{ + short v; + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + v = M16(C816(src[0]), C816(src[1])); + src += 2; + W16(dst, v); dst += 2; + } +} + +static void cvtSM168K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + *dst++ = C168(M16(R16(src), R16(src + 2))); + src += 4; + } +} + +static void cvtSM1616K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + W16(dst, M16(R16(src),R16(src+2))); dst += 2; + src += 4; + } +} + +static void cvtMM816K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + W16(dst, C816(*src++)); dst += 2; + } +} + +static void cvtSS816K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + W16(dst, C816(*src++)); dst += 2; + W16(dst, C816(*src++)); dst += 2; + } +} + +static void cvtMM168K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + *dst++ = C168(R16(src)); src += 2; + } +} + +static void cvtSS168K(const unsigned char* src, int ns, unsigned char* dst) +{ + TRACE("(%p, %d, %p)\n", src, ns, dst); + + while (ns--) { + *dst++ = C168(R16(src)); src += 2; + *dst++ = C168(R16(src)); src += 2; + } +} + +static void (*PCM_ConvertKeepRate[16])(const unsigned char*, int, unsigned char*) = { + cvtSS88K, cvtSM88K, cvtMS88K, cvtMM88K, + cvtSS816K, cvtSM816K, cvtMS816K, cvtMM816K, + cvtSS168K, cvtSM168K, cvtMS168K, cvtMM168K, + cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K, +}; + +/*********************************************************************** + * I + * + * Interpolate the value at r (r in ]0, 1]) between the two points v1 and v2 + * Linear interpolation is used + */ +static inline double I(double v1, double v2, double r) +{ + if (0.0 >= r || r > 1.0) FIXME("r!! %f\n", r); + return (1.0 - r) * v1 + r * v2; +} + +static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->last[1].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + *dst++ = I(apd->last[0].b, src[0], r); + *dst++ = I(apd->last[1].b, src[1], r); + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +/* the conversion routines with rate conversion are labelled cvtC + * where : + * is the (M)ono/(S)tereo configuration of input channel + * is the (M)ono/(S)tereo configuration of output channel + * is the number of bits of input channel (8 or 16) + * is the number of bits of output channel (8 or 16) + * + */ +static void cvtSM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->last[1].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + *dst++ = I(M8(apd->last[0].b, apd->last[1].b), M8(src[0], src[1]), r); + else + *dst++ = M8(apd->last[0].b, apd->last[1].b); + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + dst[0] = dst[1] = I(apd->last[0].b, src[0], r); + else + dst[0] = dst[1] = apd->last[0].b; + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + *dst++ = I(apd->last[0].b, src[0], r); + else + *dst++ = apd->last[0].b; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->last[1].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(C816(apd->last[0].b), C816(src[0]), r)); + else + W16(dst, C816(apd->last[0].b)); + dst += 2; + if (*nsrc) /* don't go off end of data */ + W16(dst, I(C816(apd->last[1].b), C816(src[1]), r)); + else + W16(dst, C816(apd->last[1].b)); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->last[1].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(M16(C816(apd->last[0].b), C816(apd->last[1].b)), + M16(C816(src[0]), C816(src[1])), r)); + else + W16(dst, M16(C816(apd->last[0].b), C816(apd->last[1].b))); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + short v; + TRACE("(%p, %p, %p->(%ld), %p, %p->(%ld))\n", apd, src, nsrc, *nsrc, dst, ndst, *ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + v = I(C816(apd->last[0].b), C816(src[0]), r); + else + v = C816(apd->last[0].b); + W16(dst, v); dst += 2; + W16(dst, v); dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].b = *src++; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(C816(apd->last[0].b), C816(src[0]), r)); + else + W16(dst, C816(apd->last[0].b)); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->last[1].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) { /* don't go off end of data */ + *dst++ = C168(I(apd->last[0].s, R16(src) , r)); + *dst++ = C168(I(apd->last[1].s, R16(src+2), r)); + } else { + *dst++ = C168(apd->last[0].s); + *dst++ = C168(apd->last[1].s); + } + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->last[1].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + *dst++ = C168(I(M16(apd->last[0].s, apd->last[1].s), + M16(R16(src), R16(src + 2)), r)); + else + *dst++ = C168(M16(apd->last[0].s, apd->last[1].s)); + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + + +static void cvtMS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + dst[0] = dst[1] = C168(I(apd->last[0].s, R16(src), r)); + else + dst[0] = dst[1] = C168(apd->last[0].s); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + + +static void cvtMM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + *dst++ = C168(I(apd->last[0].s, R16(src), r)); + else + *dst++ = C168(apd->last[0].s); + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->last[1].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(apd->last[0].s, R16(src), r)); + else + W16(dst, apd->last[0].s); + dst += 2; + if (*nsrc) /* don't go off end of data */ + W16(dst, I(apd->last[1].s, R16(src+2), r)); + else + W16(dst, apd->last[1].s); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtSM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->last[1].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(M16(apd->last[0].s, apd->last[1].s), + M16(R16(src), R16(src+2)), r)); + else + W16(dst, M16(apd->last[0].s, apd->last[1].s)); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + short v; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + v = I(apd->last[0].s, R16(src), r); + else + v = apd->last[0].s; + W16(dst, v); dst += 2; + W16(dst, v); dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void cvtMM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) +{ + double r; + TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); + + while (*nsrc != 0 && *ndst != 0) { + while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { + if (*nsrc == 0) return; + apd->last[0].s = R16(src); src += 2; + apd->srcPos++; + (*nsrc)--; + } + /* now do the interpolation */ + if (*nsrc) /* don't go off end of data */ + W16(dst, I(apd->last[0].s, R16(src), r)); + else + W16(dst, apd->last[0].s); + dst += 2; + apd->dstPos += apd->dstIncr; + (*ndst)--; + } +} + +static void (*PCM_ConvertChangeRate[16])(AcmPcmData* apd, + const unsigned char* src, LPDWORD nsrc, + unsigned char* dst, LPDWORD ndst) = { + cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C, + cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C, + cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C, + cvtSS1616C, cvtSM1616C, cvtMS1616C, cvtMM1616C, +}; + +/*********************************************************************** + * PCM_DriverDetails + * + */ +static LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add) +{ + TRACE("(%p)\n", add); + + add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; + add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; + add->wMid = 0xFF; + add->wPid = 0x00; + add->vdwACM = 0x01000000; + add->vdwDriver = 0x01000000; + add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; + add->cFormatTags = 1; + add->cFilterTags = 0; + add->hicon = NULL; + MultiByteToWideChar( CP_ACP, 0, "WINE-PCM", -1, + add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, "Wine PCM converter", -1, + add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, + add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, + add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); + add->szFeatures[0] = 0; + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_FormatTagDetails + * + */ +static LRESULT PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) +{ + TRACE("(%p, %08lx)\n", aftd, dwQuery); + + switch (dwQuery) { + case ACM_FORMATTAGDETAILSF_INDEX: + if (aftd->dwFormatTagIndex != 0) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + break; + case ACM_FORMATTAGDETAILSF_FORMATTAG: + if (aftd->dwFormatTag != WAVE_FORMAT_PCM) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + break; + case ACM_FORMATTAGDETAILSF_LARGESTSIZE: + if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN && + aftd->dwFormatTag != WAVE_FORMAT_PCM) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + break; + default: + WARN("Unsupported query %08lx\n", dwQuery); + return MMSYSERR_NOTSUPPORTED; + } + + aftd->dwFormatTagIndex = 0; + aftd->dwFormatTag = WAVE_FORMAT_PCM; + aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); + aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; + aftd->cStandardFormats = NUM_PCM_FORMATS; + aftd->szFormatTag[0] = 0; + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_FormatDetails + * + */ +static LRESULT PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) +{ + TRACE("(%p, %08lx)\n", afd, dwQuery); + + switch (dwQuery) { + case ACM_FORMATDETAILSF_FORMAT: + if (PCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) { + return ACMERR_NOTPOSSIBLE; + WARN("not possible\n"); + } + break; + case ACM_FORMATDETAILSF_INDEX: + assert(afd->dwFormatIndex < NUM_PCM_FORMATS); + afd->pwfx->wFormatTag = WAVE_FORMAT_PCM; + afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; + afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; + afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; + /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not + * accessible afd->pwfx->cbSize = 0; + */ + afd->pwfx->nBlockAlign = + (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; + afd->pwfx->nAvgBytesPerSec = + afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; + break; + default: + WARN("Unsupported query %08lx\n", dwQuery); + return MMSYSERR_NOTSUPPORTED; + } + + afd->dwFormatTag = WAVE_FORMAT_PCM; + afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER; + afd->szFormat[0] = 0; /* let MSACM format this for us... */ + afd->cbwfx = sizeof(PCMWAVEFORMAT); + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_FormatSuggest + * + */ +static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) +{ + TRACE("(%p)\n", adfs); + + /* some tests ... */ + if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || + adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || + PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + + /* is no suggestion for destination, then copy source value */ + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) { + adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; + } + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) { + adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; + } + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) { + adfs->pwfxDst->wBitsPerSample = adfs->pwfxSrc->wBitsPerSample; + } + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) { + if (adfs->pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + adfs->pwfxDst->wFormatTag = adfs->pwfxSrc->wFormatTag; + } + /* check if result is ok */ + if (PCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + + /* recompute other values */ + adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; + adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_Reset + * + */ +static void PCM_Reset(AcmPcmData* apd, int srcNumBits) +{ + TRACE("(%p, %d)\n", apd, srcNumBits); + + apd->srcPos = 0; + apd->dstPos = 0; + /* initialize with neutral value */ + if (srcNumBits == 16) { + apd->last[0].s = 0; + apd->last[1].s = 0; + } else { + apd->last[0].b = (BYTE)0x80; + apd->last[1].b = (BYTE)0x80; + } +} + +/*********************************************************************** + * PCM_StreamOpen + * + */ +static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) +{ + AcmPcmData* apd; + int idx = 0; + + TRACE("(%p)\n", adsi); + + assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); + + if (PCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || + PCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) { + WARN("not possible\n"); + return ACMERR_NOTPOSSIBLE; + } + + apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData)); + if (apd == 0) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + adsi->dwDriver = (DWORD)apd; + adsi->fdwDriver = 0; + + if (adsi->pwfxSrc->wBitsPerSample == 16) idx += 8; + if (adsi->pwfxDst->wBitsPerSample == 16) idx += 4; + if (adsi->pwfxSrc->nChannels == 1) idx += 2; + if (adsi->pwfxDst->nChannels == 1) idx += 1; + + if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) { + apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx]; + } else { + adsi->fdwDriver |= PCM_RESAMPLE; + apd->dstIncr = (double)(adsi->pwfxSrc->nSamplesPerSec) / + (double)(adsi->pwfxDst->nSamplesPerSec); + PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample); + apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx]; + } + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_StreamClose + * + */ +static LRESULT PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi) +{ + TRACE("(%p)\n", adsi); + + HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_round + * + */ +static inline DWORD PCM_round(DWORD a, DWORD b, DWORD c) +{ + assert(c); + /* to be sure, always return an entire number of c... */ + return ((double)a * (double)b + (double)c - 1) / (double)c; +} + +/*********************************************************************** + * PCM_StreamSize + * + */ +static LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss) +{ + DWORD srcMask = ~(adsi->pwfxSrc->nBlockAlign - 1); + DWORD dstMask = ~(adsi->pwfxDst->nBlockAlign - 1); + + TRACE("(%p, %p)\n", adsi, adss); + + switch (adss->fdwSize) { + case ACM_STREAMSIZEF_DESTINATION: + /* cbDstLength => cbSrcLength */ + adss->cbSrcLength = PCM_round(adss->cbDstLength & dstMask, + adsi->pwfxSrc->nAvgBytesPerSec, + adsi->pwfxDst->nAvgBytesPerSec) & srcMask; + break; + case ACM_STREAMSIZEF_SOURCE: + /* cbSrcLength => cbDstLength */ + adss->cbDstLength = PCM_round(adss->cbSrcLength & srcMask, + adsi->pwfxDst->nAvgBytesPerSec, + adsi->pwfxSrc->nAvgBytesPerSec) & dstMask; + break; + default: + WARN("Unsupported query %08lx\n", adss->fdwSize); + return MMSYSERR_NOTSUPPORTED; + } + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * PCM_StreamConvert + * + */ +static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) +{ + AcmPcmData* apd = (AcmPcmData*)adsi->dwDriver; + DWORD nsrc = NUM_OF(adsh->cbSrcLength, adsi->pwfxSrc->nBlockAlign); + DWORD ndst = NUM_OF(adsh->cbDstLength, adsi->pwfxDst->nBlockAlign); + + TRACE("(%p, %p)\n", adsi, adsh); + + TRACE("nsrc=%ld,adsh->cbSrcLength=%ld\n", nsrc, adsh->cbSrcLength); + TRACE("ndst=%ld,adsh->cbDstLength=%ld\n", ndst, adsh->cbDstLength); + TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + adsi->pwfxSrc->wFormatTag, adsi->pwfxSrc->nChannels, adsi->pwfxSrc->nSamplesPerSec, adsi->pwfxSrc->nAvgBytesPerSec, + adsi->pwfxSrc->nBlockAlign, adsi->pwfxSrc->wBitsPerSample, adsi->pwfxSrc->cbSize); + TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + adsi->pwfxDst->wFormatTag, adsi->pwfxDst->nChannels, adsi->pwfxDst->nSamplesPerSec, adsi->pwfxDst->nAvgBytesPerSec, + adsi->pwfxDst->nBlockAlign, adsi->pwfxDst->wBitsPerSample, adsi->pwfxDst->cbSize); + + if (adsh->fdwConvert & + ~(ACM_STREAMCONVERTF_BLOCKALIGN| + ACM_STREAMCONVERTF_END| + ACM_STREAMCONVERTF_START)) { + FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert); + } + /* ACM_STREAMCONVERTF_BLOCKALIGN + * currently all conversions are block aligned, so do nothing for this flag + * ACM_STREAMCONVERTF_END + * no pending data, so do nothing for this flag + */ + if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) && + (adsi->fdwDriver & PCM_RESAMPLE)) { + PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample); + } + + /* do the job */ + if (adsi->fdwDriver & PCM_RESAMPLE) { + DWORD nsrc2 = nsrc; + DWORD ndst2 = ndst; + + apd->cvt.cvtChangeRate(apd, adsh->pbSrc, &nsrc2, adsh->pbDst, &ndst2); + nsrc -= nsrc2; + ndst -= ndst2; + } else { + if (nsrc < ndst) ndst = nsrc; else nsrc = ndst; + + /* nsrc is now equal to ndst */ + apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst); + } + + adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign; + adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * DriverProc (MSACM32.@) + */ +LRESULT CALLBACK PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg, + LPARAM dwParam1, LPARAM dwParam2) +{ + TRACE("(%08lx %08lx %u %08lx %08lx);\n", + dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2); + + switch (wMsg) { + case DRV_LOAD: return 1; + case DRV_FREE: return 1; + case DRV_OPEN: return PCM_drvOpen((LPSTR)dwParam1, (PACMDRVOPENDESCW)dwParam2); + case DRV_CLOSE: return PCM_drvClose(dwDevID); + case DRV_ENABLE: return 1; + case DRV_DISABLE: return 1; + case DRV_QUERYCONFIGURE: return 1; + case DRV_CONFIGURE: MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1; + case DRV_INSTALL: return DRVCNF_RESTART; + case DRV_REMOVE: return DRVCNF_RESTART; + + case ACMDM_DRIVER_NOTIFY: + /* no caching from other ACM drivers is done so far */ + return MMSYSERR_NOERROR; + + case ACMDM_DRIVER_DETAILS: + return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); + + case ACMDM_FORMATTAG_DETAILS: + return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); + + case ACMDM_FORMAT_DETAILS: + return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); + + case ACMDM_FORMAT_SUGGEST: + return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); + + case ACMDM_STREAM_OPEN: + return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); + + case ACMDM_STREAM_CLOSE: + return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); + + case ACMDM_STREAM_SIZE: + return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); + + case ACMDM_STREAM_CONVERT: + return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); + + case ACMDM_HARDWARE_WAVE_CAPS_INPUT: + case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: + /* this converter is not a hardware driver */ + case ACMDM_FILTERTAG_DETAILS: + case ACMDM_FILTER_DETAILS: + /* this converter is not a filter */ + case ACMDM_STREAM_RESET: + /* only needed for asynchronous driver... we aren't, so just say it */ + case ACMDM_STREAM_PREPARE: + case ACMDM_STREAM_UNPREPARE: + /* nothing special to do here... so don't do anything */ + return MMSYSERR_NOTSUPPORTED; + + default: + return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); + } + return 0; +} diff --git a/reactos/lib/msacm/stream.c b/reactos/lib/msacm/stream.c new file mode 100644 index 00000000000..5c427ec62d4 --- /dev/null +++ b/reactos/lib/msacm/stream.c @@ -0,0 +1,478 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MSACM32 library + * + * Copyright 1998 Patrik Stridvall + * 1999 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* TODO + * + asynchronous conversion is not implemented + * + callback/notification + * * acmStreamMessage + * + properly close ACM streams + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "mmsystem.h" +#include "mmreg.h" +#include "msacm.h" +#include "msacmdrv.h" +#include "wineacm.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msacm); + +static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has) +{ + TRACE("(%p)\n", has); + + return (PWINE_ACMSTREAM)has; +} + +/*********************************************************************** + * acmStreamClose (MSACM32.@) + */ +MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose) +{ + PWINE_ACMSTREAM was; + MMRESULT ret; + + TRACE("(%p, %ld)\n", has, fdwClose); + + if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0); + if (ret == MMSYSERR_NOERROR) { + if (was->hAcmDriver) + acmDriverClose(was->hAcmDriver, 0L); + HeapFree(MSACM_hHeap, 0, was); + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamConvert (MSACM32.@) + */ +MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwConvert) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(%p, %p, %ld)\n", has, pash, fdwConvert); + + if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) { + WARN("unprepared header\n"); + return ACMERR_UNPREPARED; + } + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + /* check that pointers have not been modified */ + if (padsh->pbPreparedSrc != padsh->pbSrc || + padsh->cbPreparedSrcLength < padsh->cbSrcLength || + padsh->pbPreparedDst != padsh->pbDst || + padsh->cbPreparedDstLength < padsh->cbDstLength) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + padsh->fdwConvert = fdwConvert; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR) { + padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE; + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamMessage (MSACM32.@) + */ +MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1, + LPARAM lParam2) +{ + FIXME("(%p, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return MMSYSERR_ERROR; +} + +/*********************************************************************** + * acmStreamOpen (MSACM32.@) + */ +MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc, + PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + PWINE_ACMSTREAM was; + PWINE_ACMDRIVER wad; + MMRESULT ret; + int wfxSrcSize; + int wfxDstSize; + WAVEFORMATEX wfxSrc, wfxDst; + + TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n", + phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen); + + /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than + * WAVEFORMATEX so don't use them directly when not sure */ + if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) { + memcpy(&wfxSrc, pwfxSrc, sizeof(PCMWAVEFORMAT)); + wfxSrc.wBitsPerSample = pwfxSrc->wBitsPerSample; + wfxSrc.cbSize = 0; + pwfxSrc = &wfxSrc; + } + + if (pwfxDst->wFormatTag == WAVE_FORMAT_PCM) { + memcpy(&wfxDst, pwfxDst, sizeof(PCMWAVEFORMAT)); + wfxDst.wBitsPerSample = pwfxDst->wBitsPerSample; + wfxDst.cbSize = 0; + pwfxDst = &wfxDst; + } + + TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, + pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize); + + TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, + pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize); + + /* (WS) In query mode, phas should be NULL. If it is not, then instead + * of returning an error we are making sure it is NULL, preventing some + * applications that pass garbage for phas from crashing. + */ + if (fdwOpen & ACM_STREAMOPENF_QUERY) phas = NULL; + + if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX); + if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize; + if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize; + + was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + + ((pwfltr) ? sizeof(WAVEFILTER) : 0)); + if (was == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + was->drvInst.cbStruct = sizeof(was->drvInst); + was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was)); + memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize); + was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize); + memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize); + if (pwfltr) { + was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize); + memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER)); + } else { + was->drvInst.pwfltr = NULL; + } + was->drvInst.dwCallback = dwCallback; + was->drvInst.dwInstance = dwInstance; + was->drvInst.fdwOpen = fdwOpen; + was->drvInst.fdwDriver = 0L; + was->drvInst.dwDriver = 0L; + /* real value will be stored once ACMDM_STREAM_OPEN succeeds */ + was->drvInst.has = 0L; + + if (had) { + if (!(wad = MSACM_GetDriver(had))) { + ret = MMSYSERR_INVALPARAM; + goto errCleanUp; + } + + was->obj.dwType = WINE_ACMOBJ_STREAM; + was->obj.pACMDriverID = wad->obj.pACMDriverID; + was->pDrv = wad; + was->hAcmDriver = 0; /* not to close it in acmStreamClose */ + + ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L); + if (ret != MMSYSERR_NOERROR) + goto errCleanUp; + } else { + PWINE_ACMDRIVERID wadi; + + ret = ACMERR_NOTPOSSIBLE; + for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) { + if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) || + !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) || + !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL)) + continue; + ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L); + if (ret != MMSYSERR_NOERROR) + continue; + if ((wad = MSACM_GetDriver(had)) != 0) { + was->obj.dwType = WINE_ACMOBJ_STREAM; + was->obj.pACMDriverID = wad->obj.pACMDriverID; + was->pDrv = wad; + was->hAcmDriver = had; + + ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L); + TRACE("%s => %08x\n", debugstr_w(wadi->pszDriverAlias), ret); + if (ret == MMSYSERR_NOERROR) { + if (fdwOpen & ACM_STREAMOPENF_QUERY) { + acmDriverClose(had, 0L); + } + break; + } + } + /* no match, close this acm driver and try next one */ + acmDriverClose(had, 0L); + } + if (ret != MMSYSERR_NOERROR) { + ret = ACMERR_NOTPOSSIBLE; + goto errCleanUp; + } + } + ret = MMSYSERR_NOERROR; + was->drvInst.has = (HACMSTREAM)was; + if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) { + if (phas) + *phas = (HACMSTREAM)was; + TRACE("=> (%d)\n", ret); + return ret; + } +errCleanUp: + if (phas) + *phas = NULL; + HeapFree(MSACM_hHeap, 0, was); + TRACE("=> (%d)\n", ret); + return ret; +} + + +/*********************************************************************** + * acmStreamPrepareHeader (MSACM32.@) + */ +MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwPrepare) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(%p, %p, %ld)\n", has, pash, fdwPrepare); + + if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + if (fdwPrepare) + ret = MMSYSERR_INVALFLAG; + + if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE) + return MMSYSERR_NOERROR; + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + padsh->fdwConvert = fdwPrepare; + padsh->padshNext = NULL; + padsh->fdwDriver = padsh->dwDriver = 0L; + + padsh->fdwPrepared = 0; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = 0; + padsh->cbPreparedSrcLength = 0; + padsh->pbPreparedDst = 0; + padsh->cbPreparedDstLength = 0; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) { + ret = MMSYSERR_NOERROR; + padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE); + padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED; + padsh->fdwPrepared = padsh->fdwStatus; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = padsh->pbSrc; + padsh->cbPreparedSrcLength = padsh->cbSrcLength; + padsh->pbPreparedDst = padsh->pbDst; + padsh->cbPreparedDstLength = padsh->cbDstLength; + } else { + padsh->fdwPrepared = 0; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = 0; + padsh->cbPreparedSrcLength = 0; + padsh->pbPreparedDst = 0; + padsh->cbPreparedDstLength = 0; + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamReset (MSACM32.@) + */ +MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p, %ld)\n", has, fdwReset); + + if (fdwReset) { + WARN("invalid flag\n"); + ret = MMSYSERR_INVALFLAG; + } else if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) { + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0); + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamSize (MSACM32.@) + */ +MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, + LPDWORD pdwOutputBytes, DWORD fdwSize) +{ + PWINE_ACMSTREAM was; + ACMDRVSTREAMSIZE adss; + MMRESULT ret; + + TRACE("(%p, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize); + + if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) { + WARN("invalid flag\n"); + return MMSYSERR_INVALFLAG; + } + + *pdwOutputBytes = 0L; + + switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) { + case ACM_STREAMSIZEF_DESTINATION: + adss.cbDstLength = cbInput; + adss.cbSrcLength = 0; + break; + case ACM_STREAMSIZEF_SOURCE: + adss.cbSrcLength = cbInput; + adss.cbDstLength = 0; + break; + default: + WARN("invalid flag\n"); + return MMSYSERR_INVALFLAG; + } + + adss.cbStruct = sizeof(adss); + adss.fdwSize = fdwSize; + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, + (DWORD)&was->drvInst, (DWORD)&adss); + if (ret == MMSYSERR_NOERROR) { + switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) { + case ACM_STREAMSIZEF_DESTINATION: + *pdwOutputBytes = adss.cbSrcLength; + break; + case ACM_STREAMSIZEF_SOURCE: + *pdwOutputBytes = adss.cbDstLength; + break; + } + } + TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes); + return ret; +} + +/*********************************************************************** + * acmStreamUnprepareHeader (MSACM32.@) + */ +MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwUnprepare) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(%p, %p, %ld)\n", has, pash, fdwUnprepare); + + if ((was = ACM_GetStream(has)) == NULL) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) { + WARN("unprepared header\n"); + return ACMERR_UNPREPARED; + } + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + /* check that pointers have not been modified */ + if (padsh->pbPreparedSrc != padsh->pbSrc || + padsh->cbPreparedSrcLength < padsh->cbSrcLength || + padsh->pbPreparedDst != padsh->pbDst || + padsh->cbPreparedDstLength < padsh->cbDstLength) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + padsh->fdwConvert = fdwUnprepare; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) { + ret = MMSYSERR_NOERROR; + padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED); + } + TRACE("=> (%d)\n", ret); + return ret; +} diff --git a/reactos/lib/msacm/wineacm.h b/reactos/lib/msacm/wineacm.h new file mode 100644 index 00000000000..5244bfb1800 --- /dev/null +++ b/reactos/lib/msacm/wineacm.h @@ -0,0 +1,363 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Copyright 2000 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_WINEACM_H +#define __WINE_WINEACM_H + +#ifndef __REACTOS__ +#include "wine/windef16.h" +//#include "wine/mmsystem16.h" + +/*********************************************************************** + * Win16 definitions + */ +typedef BOOL16 (CALLBACK *ACMDRIVERENUMCB16)( + HACMDRIVERID16 hadid, DWORD dwInstance, DWORD fdwSupport +); +typedef UINT (CALLBACK *ACMFILTERCHOOSEHOOKPROC16)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); +typedef UINT16 (CALLBACK *ACMFORMATCHOOSEHOOKPROC16)( + HWND16 hwnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam +); + +typedef struct _ACMDRIVERDETAILS16 +{ + DWORD cbStruct; + + FOURCC fccType; + FOURCC fccComp; + + WORD wMid; + WORD wPid; + + DWORD vdwACM; + DWORD vdwDriver; + + DWORD fdwSupport; + DWORD cFormatTags; + DWORD cFilterTags; + + HICON16 hicon; + + CHAR szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS]; + CHAR szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS]; + CHAR szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS]; + CHAR szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS]; + CHAR szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS]; +} ACMDRIVERDETAILS16, *NPACMDRIVERDETAILS16, *LPACMDRIVERDETAILS16; + +typedef struct _ACMFILTERCHOOSE16 +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND16 hwndOwner; + + LPWAVEFILTER pwfltr; + DWORD cbwfltr; + + LPCSTR pszTitle; + + char szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; + char szFilter[ACMFILTERDETAILS_FILTER_CHARS]; + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + LPWAVEFILTER pwfltrEnum; + + HINSTANCE16 hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFILTERCHOOSEHOOKPROC16 pfnHook; +} ACMFILTERCHOOSE16, *NPACMFILTERCHOOSE16, *LPACMFILTERCHOOSE16; + +typedef struct _ACMFILTERDETAILS16 +{ + DWORD cbStruct; + DWORD dwFilterIndex; + DWORD dwFilterTag; + DWORD fdwSupport; + LPWAVEFILTER pwfltr; + DWORD cbwfltr; + CHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; +} ACMFILTERDETAILS16, *NPACMFILTERDETAILS16, *LPACMFILTERDETAILS16; + +typedef struct _ACMFILTERTAGDETAILS16 +{ + DWORD cbStruct; + DWORD dwFilterTagIndex; + DWORD dwFilterTag; + DWORD cbFilterSize; + DWORD fdwSupport; + DWORD cStandardFilters; + CHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; +} ACMFILTERTAGDETAILS16, *NPACMFILTERTAGDETAILS16, *LPACMFILTERTAGDETAILS16; + +typedef struct _ACMFORMATCHOOSE16 +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND16 hwndOwner; + + LPWAVEFORMATEX pwfx; + DWORD cbwfx; + LPCSTR pszTitle; + + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + LPWAVEFORMATEX pwfxEnum; + + HINSTANCE16 hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFORMATCHOOSEHOOKPROC16 pfnHook; +} ACMFORMATCHOOSE16, *NPACMFORMATCHOOSE16, *LPACMFORMATCHOOSE16; + +typedef struct _ACMFORMATDETAILS16 +{ + DWORD cbStruct; + DWORD dwFormatIndex; + DWORD dwFormatTag; + DWORD fdwSupport; + LPWAVEFORMATEX pwfx; + DWORD cbwfx; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; +} ACMFORMATDETAILS16, *NPACMFORMATDETAILS16, *LPACMFORMATDETAILS16; + +typedef struct _ACMFORMATTAGDETAILS16 +{ + DWORD cbStruct; + DWORD dwFormatTagIndex; + DWORD dwFormatTag; + DWORD cbFormatSize; + DWORD fdwSupport; + DWORD cStandardFormats; + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; +} ACMFORMATTAGDETAILS16, *NPACMFORMATTAGDETAILS16, *LPACMFORMATTAGDETAILS16; + +typedef ACMSTREAMHEADER ACMSTREAMHEADER16, *NPACMSTREAMHEADER16, *LPACMSTREAMHEADER16; + +typedef BOOL16 (CALLBACK *ACMFILTERENUMCB16)( + HACMDRIVERID16 hadid, LPACMFILTERDETAILS16 pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef BOOL16 (CALLBACK *ACMFILTERTAGENUMCB16)( + HACMDRIVERID16 hadid, LPACMFILTERTAGDETAILS16 paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef BOOL16 (CALLBACK *ACMFORMATENUMCB16)( + HACMDRIVERID16 hadid, LPACMFORMATDETAILS16 pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef BOOL16 (CALLBACK *ACMFORMATTAGENUMCB16)( + HACMDRIVERID16 hadid, LPACMFORMATTAGDETAILS16 paftd, + DWORD dwInstance, DWORD fdwSupport +); + +/*********************************************************************** + * Functions - Win16 + */ + +DWORD WINAPI acmGetVersion16( +); +MMRESULT16 WINAPI acmMetrics16( + HACMOBJ16 hao, UINT16 uMetric, LPVOID pMetric +); +MMRESULT16 WINAPI acmDriverEnum16( + ACMDRIVERENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmDriverDetails16( + HACMDRIVERID16 hadid, LPACMDRIVERDETAILS16 padd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmDriverAdd16( + LPHACMDRIVERID16 phadid, HINSTANCE16 hinstModule, + LPARAM lParam, DWORD dwPriority, DWORD fdwAdd +); +MMRESULT16 WINAPI acmDriverRemove16( + HACMDRIVERID16 hadid, DWORD fdwRemove +); +MMRESULT16 WINAPI acmDriverOpen16( + LPHACMDRIVER16 phad, HACMDRIVERID16 hadid, DWORD fdwOpen +); +MMRESULT16 WINAPI acmDriverClose16( + HACMDRIVER16 had, DWORD fdwClose +); +LRESULT WINAPI acmDriverMessage16( + HACMDRIVER16 had, UINT16 uMsg, LPARAM lParam1, LPARAM lParam2 +); +MMRESULT16 WINAPI acmDriverID16( + HACMOBJ16 hao, LPHACMDRIVERID16 phadid, DWORD fdwDriverID +); +MMRESULT16 WINAPI acmDriverPriority16( + HACMDRIVERID16 hadid, DWORD dwPriority, DWORD fdwPriority +); +MMRESULT16 WINAPI acmFormatTagDetails16( + HACMDRIVER16 had, LPACMFORMATTAGDETAILS16 paftd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFormatTagEnum16( + HACMDRIVER16 had, LPACMFORMATTAGDETAILS16 paftd, + ACMFORMATTAGENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFormatChoose16( + LPACMFORMATCHOOSE16 pafmtc +); +MMRESULT16 WINAPI acmFormatDetails16( + HACMDRIVER16 had, LPACMFORMATDETAILS16 pafd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFormatEnum16( + HACMDRIVER16 had, LPACMFORMATDETAILS16 pafd, + ACMFORMATENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFormatSuggest16( + HACMDRIVER16 had, LPWAVEFORMATEX pwfxSrc, + LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest +); +MMRESULT16 WINAPI acmFilterTagDetails16( + HACMDRIVER16 had, LPACMFILTERTAGDETAILS16 paftd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFilterTagEnum16( + HACMDRIVER16 had, LPACMFILTERTAGDETAILS16 paftd, + ACMFILTERTAGENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFilterChoose16( + LPACMFILTERCHOOSE16 pafltrc +); +MMRESULT16 WINAPI acmFilterDetails16( + HACMDRIVER16 had, LPACMFILTERDETAILS16 pafd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFilterEnum16( + HACMDRIVER16 had, LPACMFILTERDETAILS16 pafd, + ACMFILTERENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmStreamOpen16( + LPHACMSTREAM16 phas, HACMDRIVER16 had, + LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, + LPWAVEFILTER pwfltr, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen +); +MMRESULT16 WINAPI acmStreamClose16( + HACMSTREAM16 has, DWORD fdwClose +); +MMRESULT16 WINAPI acmStreamSize16( + HACMSTREAM16 has, DWORD cbInput, + LPDWORD pdwOutputBytes, DWORD fdwSize +); +MMRESULT16 WINAPI acmStreamConvert16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwConvert +); +MMRESULT16 WINAPI acmStreamReset16( + HACMSTREAM16 has, DWORD fdwReset +); +MMRESULT16 WINAPI acmStreamPrepareHeader16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwPrepare +); +MMRESULT16 WINAPI acmStreamUnprepareHeader16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwUnprepare +); +#endif + +/*********************************************************************** + * Wine specific - Win32 + */ +typedef struct _WINE_ACMDRIVERID *PWINE_ACMDRIVERID; +typedef struct _WINE_ACMDRIVER *PWINE_ACMDRIVER; + +#define WINE_ACMOBJ_DONTCARE 0x5EED0000 +#define WINE_ACMOBJ_DRIVERID 0x5EED0001 +#define WINE_ACMOBJ_DRIVER 0x5EED0002 +#define WINE_ACMOBJ_STREAM 0x5EED0003 + +typedef struct _WINE_ACMOBJ +{ + DWORD dwType; + PWINE_ACMDRIVERID pACMDriverID; +} WINE_ACMOBJ, *PWINE_ACMOBJ; + +typedef struct _WINE_ACMDRIVER +{ + WINE_ACMOBJ obj; + HDRVR hDrvr; + PWINE_ACMDRIVER pNextACMDriver; +} WINE_ACMDRIVER; + +typedef struct _WINE_ACMSTREAM +{ + WINE_ACMOBJ obj; + PWINE_ACMDRIVER pDrv; + ACMDRVSTREAMINSTANCE drvInst; + HACMDRIVER hAcmDriver; +} WINE_ACMSTREAM, *PWINE_ACMSTREAM; + +typedef struct _WINE_ACMDRIVERID +{ + WINE_ACMOBJ obj; + LPWSTR pszDriverAlias; + LPWSTR pszFileName; + HINSTANCE hInstModule; /* NULL if global */ + PWINE_ACMDRIVER pACMDriverList; + PWINE_ACMDRIVERID pNextACMDriverID; + PWINE_ACMDRIVERID pPrevACMDriverID; + /* information about the driver itself, either gotten from registry or driver itself */ + DWORD cFilterTags; + DWORD cFormatTags; + DWORD fdwSupport; + struct { + DWORD dwFormatTag; + DWORD cbwfx; + }* aFormatTag; +} WINE_ACMDRIVERID; + +/* From internal.c */ +extern HANDLE MSACM_hHeap; +extern PWINE_ACMDRIVERID MSACM_pFirstACMDriverID; +extern PWINE_ACMDRIVERID MSACM_pLastACMDriverID; +extern PWINE_ACMDRIVERID MSACM_RegisterDriver(LPCWSTR pszDriverAlias, LPCWSTR pszFileName, + HINSTANCE hinstModule); +extern void MSACM_RegisterAllDrivers(void); +extern PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p); +extern void MSACM_UnregisterAllDrivers(void); +extern PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID); +extern PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver); +extern PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj, DWORD type); + +extern MMRESULT MSACM_Message(HACMDRIVER, UINT, LPARAM, LPARAM); +extern BOOL MSACM_FindFormatTagInCache(WINE_ACMDRIVERID*, DWORD, LPDWORD); + +/* From msacm32.c */ +extern HINSTANCE MSACM_hInstance32; + +/* From pcmcnvtr.c */ +LRESULT CALLBACK PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg, + LPARAM dwParam1, LPARAM dwParam2); + +/* Dialog box templates */ +#include "msacmdlg.h" + +#endif /* __WINE_WINEACM_H */