⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavemap.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Wine Wave mapper driver * * Copyright 	1999,2001 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 *//* TODOs *	+ better protection against evilish dwUser parameters *	+ use asynchronous ACM conversion *	+ don't use callback functions when none is required in open *	+ the buffer sizes may not be accurate, so there may be some *	  remaining bytes in src and dst buffers after ACM conversions... *		those should be taken care of... */#include <stdarg.h>#include <string.h>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "mmddk.h"#include "mmreg.h"#include "msacm.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(msacm);typedef	struct tagWAVEMAPDATA {    struct tagWAVEMAPDATA*	self;    union {        struct {            HWAVEOUT	hOuterWave;            HWAVEOUT	hInnerWave;        } out;        struct {            HWAVEIN	hOuterWave;            HWAVEIN	hInnerWave;        } in;    } u;    HACMSTREAM	hAcmStream;    /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */    DWORD	dwCallback;    DWORD	dwClientInstance;    DWORD	dwFlags;    /* ratio to compute position from a PCM playback to any format */    DWORD       avgSpeedOuter;    DWORD       avgSpeedInner;} WAVEMAPDATA;static	BOOL	WAVEMAP_IsData(WAVEMAPDATA* wm){    return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);}/*======================================================================* *                  WAVE OUT part                                       * *======================================================================*/static void	CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance,				     DWORD dwParam1, DWORD dwParam2){    WAVEMAPDATA*	wom = (WAVEMAPDATA*)dwInstance;    TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);    if (!WAVEMAP_IsData(wom)) {	ERR("Bad data\n");	return;    }    if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)	ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);    switch (uMsg) {    case WOM_OPEN:    case WOM_CLOSE:	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */	break;    case WOM_DONE:	if (wom->hAcmStream) {	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)dwParam1;	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;	    lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;	    lpWaveHdrSrc->dwFlags |= WHDR_DONE;	    dwParam1 = (DWORD)lpWaveHdrSrc;	}	break;    default:	ERR("Unknown msg %u\n", uMsg);    }    DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,		   uMsg, wom->dwClientInstance, dwParam1, dwParam2);}/****************************************************************** *		wodOpenHelper * * */static	DWORD	wodOpenHelper(WAVEMAPDATA* wom, UINT idx,			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,			      DWORD dwFlags){    DWORD	ret;    /* destination is always PCM, so the formulas below apply */    lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;    lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;    if (dwFlags & WAVE_FORMAT_QUERY) {	ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);    } else {	ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);    }    if (ret == MMSYSERR_NOERROR) {	ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,			  (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {	    acmStreamClose(wom->hAcmStream, 0);	    wom->hAcmStream = 0;	}    }    return ret;}static	DWORD	wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags){    UINT 		ndlo, ndhi;    UINT		i;    WAVEMAPDATA*	wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));    TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);    if (!wom)	return MMSYSERR_NOMEM;    ndhi = waveOutGetNumDevs();    if (dwFlags & WAVE_MAPPED) {	if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;	ndlo = lpDesc->uMappedDeviceID;	ndhi = ndlo + 1;	dwFlags &= ~WAVE_MAPPED;    } else {	ndlo = 0;    }    wom->self = wom;    wom->dwCallback = lpDesc->dwCallback;    wom->dwFlags = dwFlags;    wom->dwClientInstance = lpDesc->dwInstance;    wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;    wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;    for (i = ndlo; i < ndhi; i++) {	/* if no ACM stuff is involved, no need to handle callbacks at this	 * level, this will be done transparently	 */	if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback,			(DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {	    wom->hAcmStream = 0;	    goto found;	}    }    if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {        WAVEFORMATEX	wfx;        wfx.wFormatTag = WAVE_FORMAT_PCM;        wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */        /* try some ACM stuff */#define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \                        switch (wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \                            case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \                            case WAVERR_BADFORMAT: break; \                            default: goto error; \                        }        /* Our resampling algorithm is quite primitive so first try         * to just change the bit depth and number of channels         */        for (i = ndlo; i < ndhi; i++) {            wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;            wfx.nChannels = lpDesc->lpFormat->nChannels;            TRY(wfx.nSamplesPerSec, 16);            TRY(wfx.nSamplesPerSec, 8);            wfx.nChannels ^= 3;            TRY(wfx.nSamplesPerSec, 16);            TRY(wfx.nSamplesPerSec, 8);        }        for (i = ndlo; i < ndhi; i++) {            /* first try with same stereo/mono option as source */            wfx.nChannels = lpDesc->lpFormat->nChannels;            TRY(96000, 16);            TRY(48000, 16);            TRY(44100, 16);            TRY(22050, 16);            TRY(11025, 16);            /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */            wfx.nChannels ^= 3;            TRY(96000, 16);            TRY(48000, 16);            TRY(44100, 16);            TRY(22050, 16);            TRY(11025, 16);            /* first try with same stereo/mono option as source */            wfx.nChannels = lpDesc->lpFormat->nChannels;            TRY(96000, 8);            TRY(48000, 8);            TRY(44100, 8);            TRY(22050, 8);            TRY(11025, 8);            /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */            wfx.nChannels ^= 3;            TRY(96000, 8);            TRY(48000, 8);            TRY(44100, 8);            TRY(22050, 8);            TRY(11025, 8);        }#undef TRY    }    HeapFree(GetProcessHeap(), 0, wom);    return WAVERR_BADFORMAT;found:    if (dwFlags & WAVE_FORMAT_QUERY) {	*lpdwUser = 0L;	HeapFree(GetProcessHeap(), 0, wom);    } else {	*lpdwUser = (DWORD)wom;    }    return MMSYSERR_NOERROR;error:    HeapFree(GetProcessHeap(), 0, wom);    return MMSYSERR_ERROR;}static	DWORD	wodClose(WAVEMAPDATA* wom){    DWORD ret = waveOutClose(wom->u.out.hInnerWave);    if (ret == MMSYSERR_NOERROR) {	if (wom->hAcmStream) {	    ret = acmStreamClose(wom->hAcmStream, 0);	}	if (ret == MMSYSERR_NOERROR) {	    HeapFree(GetProcessHeap(), 0, wom);	}    }    return ret;}static	DWORD	wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2){    PACMSTREAMHEADER	ash;    LPWAVEHDR		lpWaveHdrDst;    if (!wom->hAcmStream) {	return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);    }    lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;    ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;    /* acmStreamConvert will actually check that the new size is less than initial size */    ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;    if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR)	return MMSYSERR_ERROR;    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));    if (ash->cbSrcLength > ash->cbSrcLengthUsed)        FIXME("Not all src buffer has been written, expect bogus sound\n");    else if (ash->cbSrcLength < ash->cbSrcLengthUsed)        ERR("CoDec has read more data than it is allowed to\n");    if (ash->cbDstLengthUsed == 0)    {        /* something went wrong in decoding */        FIXME("Got 0 length\n");        return MMSYSERR_ERROR;    }    lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;    return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));}static	DWORD	wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2){    PACMSTREAMHEADER	ash;    DWORD		size;    DWORD		dwRet;    LPWAVEHDR		lpWaveHdrDst;    if (!wom->hAcmStream) {	return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);    }    if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR)	return MMSYSERR_ERROR;    ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);    if (ash == NULL)	return MMSYSERR_NOMEM;    ash->cbStruct = sizeof(*ash);    ash->fdwStatus = 0L;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -