📄 mciwave.c
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Sample Wine Driver for MCI wave forms * * Copyright 1994 Martin Ayotte * 1999,2000 Eric Pouech * 2000 Francois Jacques * * 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 */#include <stdarg.h>#include "winerror.h"#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "mmddk.h"#include "wownt32.h"#include "digitalv.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(mciwave);typedef struct { UINT wDevID; HANDLE hWave; int nUseCount; /* Incremented for each shared open */ BOOL fShareable; /* TRUE if first open was shareable */ HMMIO hFile; /* mmio file handle open as Element */ MCI_WAVE_OPEN_PARMSA openParms; WAVEFORMATEX wfxRef; LPWAVEFORMATEX lpWaveFormat; BOOL fInput; /* FALSE = Output, TRUE = Input */ volatile WORD dwStatus; /* one from MCI_MODE_xxxx */ DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */ DWORD dwPosition; /* position in bytes in chunk */ HANDLE hEvent; /* for synchronization */ DWORD dwEventCount; /* for synchronization */ BOOL bTemporaryFile; /* temporary file (MCI_RECORD) */ MMCKINFO ckMainRIFF; /* main RIFF chunk */ MMCKINFO ckWaveData; /* data chunk */} WINE_MCIWAVE;/* =================================================================== * =================================================================== * FIXME: should be using the new mmThreadXXXX functions from WINMM * instead of those * it would require to add a wine internal flag to mmThreadCreate * in order to pass a 32 bit function instead of a 16 bit one * =================================================================== * =================================================================== */struct SCA { UINT wDevID; UINT wMsg; DWORD dwParam1; DWORD dwParam2;};/************************************************************************** * MCI_SCAStarter [internal] */static DWORD CALLBACK MCI_SCAStarter(LPVOID arg){ struct SCA* sca = (struct SCA*)arg; DWORD ret; TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n", sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2); ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2); TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n", sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2); HeapFree(GetProcessHeap(), 0, sca); ExitThread(ret); WARN("Should not happen ? what's wrong \n"); /* should not go after this point */ return ret;}/************************************************************************** * MCI_SendCommandAsync [internal] */static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2, UINT size){ struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size); if (sca == 0) return MCIERR_OUT_OF_MEMORY; sca->wDevID = wDevID; sca->wMsg = wMsg; sca->dwParam1 = dwParam1; if (size && dwParam2) { sca->dwParam2 = (DWORD)sca + sizeof(struct SCA); /* copy structure passed by program in dwParam2 to be sure * we can still use it whatever the program does */ memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size); } else { sca->dwParam2 = dwParam2; } if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) { WARN("Couldn't allocate thread for async command handling, sending synchonously\n"); return MCI_SCAStarter(&sca); } return 0;}/*======================================================================* * MCI WAVE implemantation * *======================================================================*/static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);/************************************************************************** * MCIWAVE_drvOpen [internal] */static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp){ WINE_MCIWAVE* wmw; if (modp == NULL) return 0xFFFFFFFF; wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE)); if (!wmw) return 0; wmw->wDevID = modp->wDeviceID; mciSetDriverData(wmw->wDevID, (DWORD)wmw); modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE; modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO; wmw->wfxRef.wFormatTag = WAVE_FORMAT_PCM; wmw->wfxRef.nChannels = 1; /* MONO */ wmw->wfxRef.nSamplesPerSec = 11025; wmw->wfxRef.nAvgBytesPerSec = 11025; wmw->wfxRef.nBlockAlign = 1; wmw->wfxRef.wBitsPerSample = 8; wmw->wfxRef.cbSize = 0; /* don't care */ return modp->wDeviceID;}/************************************************************************** * MCIWAVE_drvClose [internal] */static DWORD WAVE_drvClose(DWORD dwDevID){ WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID); if (wmw) { HeapFree(GetProcessHeap(), 0, wmw); mciSetDriverData(dwDevID, 0); return 1; } return (dwDevID == 0xFFFFFFFF) ? 1 : 0;}/************************************************************************** * WAVE_mciGetOpenDev [internal] */static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID){ WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID); if (wmw == NULL || wmw->nUseCount == 0) { WARN("Invalid wDevID=%u\n", wDevID); return 0; } return wmw;}/************************************************************************** * WAVE_ConvertByteToTimeFormat [internal] */static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet){ DWORD ret = 0; switch (wmw->dwMciTimeFormat) { case MCI_FORMAT_MILLISECONDS: ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec); break; case MCI_FORMAT_BYTES: ret = val; break; case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */ ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample; break; default: WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat); } TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret); *lpRet = 0; return ret;}/************************************************************************** * WAVE_ConvertTimeFormatToByte [internal] */static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val){ DWORD ret = 0; switch (wmw->dwMciTimeFormat) { case MCI_FORMAT_MILLISECONDS: ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000; break; case MCI_FORMAT_BYTES: ret = val; break; case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */ ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8; break; default: WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat); } TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret); return ret;}/************************************************************************** * WAVE_mciReadFmt [internal] */static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF){ MMCKINFO mmckInfo; long r; mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) return MCIERR_INVALID_FILE; TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize); if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM; r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize); if (r < sizeof(WAVEFORMAT)) return MCIERR_INVALID_FILE; TRACE("wFormatTag=%04X !\n", wmw->lpWaveFormat->wFormatTag); TRACE("nChannels=%d \n", wmw->lpWaveFormat->nChannels); TRACE("nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nSamplesPerSec); TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec); TRACE("nBlockAlign=%d \n", wmw->lpWaveFormat->nBlockAlign); TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample); if (r >= (long)sizeof(WAVEFORMATEX)) TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize); mmioAscend(wmw->hFile, &mmckInfo, 0); wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) { TRACE("can't find data chunk\n"); return MCIERR_INVALID_FILE; } TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize); TRACE("nChannels=%d nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec); return 0;}/************************************************************************** * WAVE_mciCreateRIFFSkeleton [internal] */static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw){ MMCKINFO ckWaveFormat; LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF); LPMMCKINFO lpckWaveData = &(wmw->ckWaveData); lpckRIFF->ckid = FOURCC_RIFF; lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E'); lpckRIFF->cksize = 0; if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF)) goto err; ckWaveFormat.fccType = 0; ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' '); ckWaveFormat.cksize = sizeof(PCMWAVEFORMAT); if (!wmw->lpWaveFormat) { wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmw->lpWaveFormat)); if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM; memcpy(wmw->lpWaveFormat, &wmw->wfxRef, sizeof(wmw->wfxRef)); } /* we can only record PCM files... there is no way in the MCI API to specify * the necessary data to initialize the extra bytes of the WAVEFORMATEX * structure */ if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM) goto err; if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0)) goto err; if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, sizeof(PCMWAVEFORMAT))) goto err; if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0)) goto err; lpckWaveData->cksize = 0; lpckWaveData->fccType = 0; lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a'); /* create data chunk */ if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0)) goto err; return 0;err: if (wmw->lpWaveFormat) HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat); wmw->lpWaveFormat = NULL; return MCIERR_INVALID_FILE;}/************************************************************************** * WAVE_mciOpen [internal] */static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms){ DWORD dwRet = 0; WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID); CHAR* pszTmpFileName = 0; TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms); if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID; if (dwFlags & MCI_OPEN_SHAREABLE) return MCIERR_HARDWARE; if (wmw->nUseCount > 0) { /* The driver is already opened on this channel * Wave driver cannot be shared */ return MCIERR_DEVICE_OPEN; } wmw->nUseCount++; wmw->fInput = FALSE; wmw->hWave = 0; wmw->dwStatus = MCI_MODE_NOT_READY; TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID); if (dwFlags & MCI_OPEN_ELEMENT) { if (dwFlags & MCI_OPEN_ELEMENT_ID) { /* could it be that (DWORD)lpOpenParms->lpstrElementName * contains the hFile value ? */ dwRet = MCIERR_UNRECOGNIZED_COMMAND; } else { if (strlen(lpOpenParms->lpstrElementName) > 0) { lpOpenParms->lpstrElementName = lpOpenParms->lpstrElementName; /* FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */ TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName); if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) { wmw->hFile = mmioOpenA((LPSTR)lpOpenParms->lpstrElementName, NULL, MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE); if (wmw->hFile == 0) { WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName); dwRet = MCIERR_FILE_NOT_FOUND; } else { LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF; /* make sure we're are the beginning of the file */ mmioSeek(wmw->hFile, 0, SEEK_SET); /* first reading of this file. read the waveformat chunk */ if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) { dwRet = MCIERR_INVALID_FILE; } else { TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&(lpckMainRIFF->ckid), (LPSTR) &(lpckMainRIFF->fccType), (lpckMainRIFF->cksize)); if ((lpckMainRIFF->ckid != FOURCC_RIFF) || lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) { dwRet = MCIERR_INVALID_FILE; } else { dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -