/* * Sample Wine Driver for Linux * * Copyright 1994 Martin Ayotte */ #ifndef WINELIB #define BUILTIN_MMSYSTEM #endif #ifdef BUILTIN_MMSYSTEM #define EMULATE_SB16 #include #include #include #include #include #include "windows.h" #include "user.h" #include "driver.h" #include "mmsystem.h" #include "ldt.h" #include "stackframe.h" #ifdef linux #include #endif #include "stddebug.h" #include "debug.h" #ifdef linux #define SOUND_DEV "/dev/dsp" #ifdef SOUND_VERSION #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0)) #else #define IOCTL(a,b,c) (c = ioctl(a,b,c) ) #endif #define MAX_WAVOUTDRV 2 #define MAX_WAVINDRV 2 #define MAX_MCIWAVDRV 2 typedef struct { int unixdev; int state; DWORD bufsize; WAVEOPENDESC waveDesc; WORD wFlags; PCMWAVEFORMAT Format; LPWAVEHDR lpQueueHdr; DWORD dwTotalPlayed; } LINUX_WAVEOUT; typedef struct { int unixdev; int state; DWORD bufsize; /* Linux '/dev/dsp' give us that size */ WAVEOPENDESC waveDesc; WORD wFlags; PCMWAVEFORMAT Format; LPWAVEHDR lpQueueHdr; DWORD dwTotalRecorded; } LINUX_WAVEIN; typedef struct { int nUseCount; /* Incremented for each shared open */ BOOL fShareable; /* TRUE if first open was shareable */ WORD wNotifyDeviceID; /* MCI device ID with a pending notification */ HANDLE hCallback; /* Callback handle for pending notification */ HMMIO16 hFile; /* mmio file handle open as Element */ MCI_WAVE_OPEN_PARMS openParms; PCMWAVEFORMAT WaveFormat; WAVEHDR WaveHdr; } LINUX_MCIWAVE; static LINUX_WAVEOUT WOutDev[MAX_WAVOUTDRV]; static LINUX_WAVEIN WInDev[MAX_WAVOUTDRV]; static LINUX_MCIWAVE MCIWavDev[MAX_MCIWAVDRV]; /************************************************************************** * WAVE_NotifyClient [internal] */ static DWORD WAVE_NotifyClient(UINT wDevID, WORD wMsg, DWORD dwParam1, DWORD dwParam2) { if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback( WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, WInDev[wDevID].waveDesc.hWave, wMsg, WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) { dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n"); return MMSYSERR_NOERROR; } return 0; } /************************************************************************** * WAVE_mciOpen */ static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS lpParms) { HANDLE hFormat; LPPCMWAVEFORMAT lpWaveFormat; HANDLE hDesc; LPWAVEOPENDESC lpDesc; LPSTR lpstrElementName; DWORD dwRet; char str[128]; dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID); if (MCIWavDev[wDevID].nUseCount > 0) { /* The driver already open on this channel */ /* If the driver was opened shareable before and this open specifies */ /* shareable then increment the use count */ if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE)) ++MCIWavDev[wDevID].nUseCount; else return MCIERR_MUST_USE_SHAREABLE; } else { MCIWavDev[wDevID].nUseCount = 1; MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE; } lpParms->wDeviceID = wDevID; dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID); dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n"); if (dwFlags & MCI_OPEN_ELEMENT) { lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName); dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName); if (strlen(lpstrElementName) > 0) { strcpy(str, lpstrElementName); AnsiUpper(str); MCIWavDev[wDevID].hFile = mmioOpen(str, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE); if (MCIWavDev[wDevID].hFile == 0) { dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str); return MCIERR_FILE_NOT_FOUND; } } else MCIWavDev[wDevID].hFile = 0; } dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile); memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS)); MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID; lpWaveFormat = &MCIWavDev[wDevID].WaveFormat; hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC)); lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc); lpDesc->hWave = 0; /* lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM; lpWaveFormat->wBitsPerSample = 8; lpWaveFormat->wf.nChannels = 1; lpWaveFormat->wf.nSamplesPerSec = 11025; lpWaveFormat->wf.nAvgBytesPerSec = 11025; lpWaveFormat->wf.nBlockAlign = 1; */ if (MCIWavDev[wDevID].hFile != 0) { MMCKINFO mmckInfo; MMCKINFO ckMainRIFF; if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) { return MCIERR_INTERNAL; } dprintf_mciwave(stddeb, "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize); if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) { return MCIERR_INTERNAL; } mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) { return MCIERR_INTERNAL; } dprintf_mciwave(stddeb, "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat, (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT)) { return MCIERR_INTERNAL; } mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) { return MCIERR_INTERNAL; } dprintf_mciwave(stddeb, "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); dprintf_mciwave(stddeb, "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n", lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec); lpWaveFormat->wBitsPerSample = 0; } lpWaveFormat->wf.nAvgBytesPerSec = lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign; hFormat = USER_HEAP_ALLOC(sizeof(PCMWAVEFORMAT)); lpDesc->lpFormat = (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat); memcpy(lpDesc->lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT)); lpDesc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hDesc); dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL); dwRet = widMessage(0, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL); USER_HEAP_FREE(hFormat); USER_HEAP_FREE(hDesc); return 0; } /************************************************************************** * WAVE_mciClose [internal] */ static DWORD WAVE_mciClose(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) { DWORD dwRet; dprintf_mciwave(stddeb, "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms); MCIWavDev[wDevID].nUseCount--; if (MCIWavDev[wDevID].nUseCount == 0) { if (MCIWavDev[wDevID].hFile != 0) { mmioClose(MCIWavDev[wDevID].hFile, 0); MCIWavDev[wDevID].hFile = 0; } dwRet = wodMessage(0, WODM_CLOSE, 0, 0L, 0L); if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL; dwRet = widMessage(0, WIDM_CLOSE, 0, 0L, 0L); if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL; } return 0; } /************************************************************************** * WAVE_mciPlay [internal] */ static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms) { int start, end; LONG bufsize, count; HANDLE hData; HANDLE hWaveHdr; LPWAVEHDR lpWaveHdr; LPWAVEHDR lp16WaveHdr; DWORD dwRet; dprintf_mciwave(stddeb, "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (MCIWavDev[wDevID].hFile == 0) { dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%s' !\n", MCIWavDev[wDevID].openParms.lpstrElementName); return MCIERR_FILE_NOT_FOUND; } start = 1; end = 99999; if (dwFlags & MCI_FROM) { start = lpParms->dwFrom; dprintf_mciwave(stddeb, "WAVE_mciPlay // MCI_FROM=%d \n", start); } if (dwFlags & MCI_TO) { end = lpParms->dwTo; dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end); } #if 0 if (dwFlags & MCI_NOTIFY) { dprintf_mciwave(stddeb, "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback); switch(fork()) { case -1: dprintf_mciwave(stddeb, "WAVE_mciPlay // Can't 'fork' process !\n"); break; case 0: break; default: dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n"); return 0; } } #endif bufsize = 64000; lpWaveHdr = &MCIWavDev[wDevID].WaveHdr; hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize); lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData); lpWaveHdr->dwUser = 0L; lpWaveHdr->dwFlags = 0L; lpWaveHdr->dwLoops = 0L; hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR)); lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr); memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR)); lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr); dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); while(TRUE) { count = mmioRead(MCIWavDev[wDevID].hFile, PTR_SEG_TO_LIN(lpWaveHdr->lpData), bufsize); dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count); if (count < 1) break; lpWaveHdr->dwBufferLength = count; /* lpWaveHdr->dwBytesRecorded = count; */ dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n", lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded); dwRet = wodMessage(0, WODM_WRITE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); } dwRet = wodMessage(0, WODM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); if (lpWaveHdr->lpData != NULL) { GlobalUnlock16(hData); GlobalFree16(hData); lpWaveHdr->lpData = NULL; } USER_HEAP_FREE(hWaveHdr); if (dwFlags & MCI_NOTIFY) { dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); } return 0; } /************************************************************************** * WAVE_mciRecord [internal] */ static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms) { int start, end; LONG bufsize; HANDLE hData; HANDLE hWaveHdr; LPWAVEHDR lpWaveHdr; LPWAVEHDR lp16WaveHdr; DWORD dwRet; dprintf_mciwave(stddeb, "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (MCIWavDev[wDevID].hFile == 0) { dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%s' !\n", MCIWavDev[wDevID].openParms.lpstrElementName); return MCIERR_FILE_NOT_FOUND; } start = 1; end = 99999; if (dwFlags & MCI_FROM) { start = lpParms->dwFrom; dprintf_mciwave(stddeb, "WAVE_mciRecord // MCI_FROM=%d \n", start); } if (dwFlags & MCI_TO) { end = lpParms->dwTo; dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end); } bufsize = 64000; lpWaveHdr = &MCIWavDev[wDevID].WaveHdr; hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize); lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData); lpWaveHdr->dwBufferLength = bufsize; lpWaveHdr->dwUser = 0L; lpWaveHdr->dwFlags = 0L; lpWaveHdr->dwLoops = 0L; hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR)); lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr); memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR)); lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr); dwRet = widMessage(0, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n"); while(TRUE) { lpWaveHdr->dwBytesRecorded = 0; dwRet = widMessage(0, WIDM_START, 0, 0L, 0L); dprintf_mciwave(stddeb, "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n", lpWaveHdr, lpWaveHdr->dwBytesRecorded); if (lpWaveHdr->dwBytesRecorded == 0) break; } dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n"); dwRet = widMessage(0, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n"); if (lpWaveHdr->lpData != NULL) { GlobalUnlock16(hData); GlobalFree16(hData); lpWaveHdr->lpData = NULL; } USER_HEAP_FREE(hWaveHdr); if (dwFlags & MCI_NOTIFY) { dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); } return 0; } /************************************************************************** * WAVE_mciStop [internal] */ static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; return 0; } /************************************************************************** * WAVE_mciPause [internal] */ static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; return 0; } /************************************************************************** * WAVE_mciResume [internal] */ static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; return 0; } /************************************************************************** * WAVE_mciSet [internal] */ static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; dprintf_mciwave(stddeb, "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat); dprintf_mciwave(stddeb, "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio); if (dwFlags & MCI_SET_TIME_FORMAT) { switch (lpParms->dwTimeFormat) { case MCI_FORMAT_MILLISECONDS: dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n"); break; case MCI_FORMAT_BYTES: dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n"); break; case MCI_FORMAT_SAMPLES: dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n"); break; default: dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n"); return MCIERR_BAD_TIME_FORMAT; } } if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION; if (dwFlags & MCI_SET_AUDIO) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n"); if (dwFlags && MCI_SET_ON) { dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n"); if (dwFlags && MCI_SET_AUDIO_LEFT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n"); if (dwFlags && MCI_SET_AUDIO_RIGHT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n"); } if (dwFlags & MCI_SET_OFF) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n"); if (dwFlags & MCI_WAVE_INPUT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n"); if (dwFlags & MCI_WAVE_OUTPUT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n"); if (dwFlags & MCI_WAVE_SET_ANYINPUT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n"); if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n"); if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n"); if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n"); if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n"); if (dwFlags & MCI_WAVE_SET_CHANNELS) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n"); if (dwFlags & MCI_WAVE_SET_FORMATTAG) dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n"); if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n"); return 0; } /************************************************************************** * WAVE_mciStatus [internal] */ static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; if (dwFlags & MCI_STATUS_ITEM) { switch(lpParms->dwItem) { case MCI_STATUS_CURRENT_TRACK: lpParms->dwReturn = 1; break; case MCI_STATUS_LENGTH: lpParms->dwReturn = 5555; if (dwFlags & MCI_TRACK) { lpParms->dwTrack = 1; lpParms->dwReturn = 2222; } break; case MCI_STATUS_MODE: lpParms->dwReturn = MCI_MODE_STOP; break; case MCI_STATUS_MEDIA_PRESENT: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n"); lpParms->dwReturn = TRUE; break; case MCI_STATUS_NUMBER_OF_TRACKS: lpParms->dwReturn = 1; break; case MCI_STATUS_POSITION: lpParms->dwReturn = 3333; if (dwFlags & MCI_STATUS_START) { lpParms->dwItem = 1; } if (dwFlags & MCI_TRACK) { lpParms->dwTrack = 1; lpParms->dwReturn = 777; } break; case MCI_STATUS_READY: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n"); lpParms->dwReturn = TRUE; break; case MCI_STATUS_TIME_FORMAT: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n"); lpParms->dwReturn = MCI_FORMAT_MILLISECONDS; break; case MCI_WAVE_INPUT: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n"); lpParms->dwReturn = 0; break; case MCI_WAVE_OUTPUT: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n"); lpParms->dwReturn = 0; break; case MCI_WAVE_STATUS_AVGBYTESPERSEC: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n"); lpParms->dwReturn = 22050; break; case MCI_WAVE_STATUS_BITSPERSAMPLE: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n"); lpParms->dwReturn = 8; break; case MCI_WAVE_STATUS_BLOCKALIGN: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n"); lpParms->dwReturn = 1; break; case MCI_WAVE_STATUS_CHANNELS: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n"); lpParms->dwReturn = 1; break; case MCI_WAVE_STATUS_FORMATTAG: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n"); lpParms->dwReturn = WAVE_FORMAT_PCM; break; case MCI_WAVE_STATUS_LEVEL: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n"); lpParms->dwReturn = 0xAAAA5555; break; case MCI_WAVE_STATUS_SAMPLESPERSEC: dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n"); lpParms->dwReturn = 22050; break; default: dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem); return MCIERR_UNRECOGNIZED_COMMAND; } } if (dwFlags & MCI_NOTIFY) { dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); } return 0; } /************************************************************************** * WAVE_mciGetDevCaps [internal] */ static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; if (dwFlags & MCI_GETDEVCAPS_ITEM) { switch(lpParms->dwItem) { case MCI_GETDEVCAPS_CAN_RECORD: lpParms->dwReturn = TRUE; break; case MCI_GETDEVCAPS_HAS_AUDIO: lpParms->dwReturn = TRUE; break; case MCI_GETDEVCAPS_HAS_VIDEO: lpParms->dwReturn = FALSE; break; case MCI_GETDEVCAPS_DEVICE_TYPE: lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO; break; case MCI_GETDEVCAPS_USES_FILES: lpParms->dwReturn = TRUE; break; case MCI_GETDEVCAPS_COMPOUND_DEVICE: lpParms->dwReturn = TRUE; break; case MCI_GETDEVCAPS_CAN_EJECT: lpParms->dwReturn = FALSE; break; case MCI_GETDEVCAPS_CAN_PLAY: lpParms->dwReturn = TRUE; break; case MCI_GETDEVCAPS_CAN_SAVE: lpParms->dwReturn = TRUE; break; case MCI_WAVE_GETDEVCAPS_INPUTS: lpParms->dwReturn = 1; break; case MCI_WAVE_GETDEVCAPS_OUTPUTS: lpParms->dwReturn = 1; break; default: return MCIERR_UNRECOGNIZED_COMMAND; } } return 0; } /************************************************************************** * WAVE_mciInfo [internal] */ static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms) { dprintf_mciwave(stddeb, "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (lpParms == NULL) return MCIERR_INTERNAL; lpParms->lpstrReturn = NULL; switch(dwFlags) { case MCI_INFO_PRODUCT: lpParms->lpstrReturn = "Linux Sound System 0.5"; break; case MCI_INFO_FILE: lpParms->lpstrReturn = (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName; break; case MCI_WAVE_INPUT: lpParms->lpstrReturn = "Linux Sound System 0.5"; break; case MCI_WAVE_OUTPUT: lpParms->lpstrReturn = "Linux Sound System 0.5"; break; default: return MCIERR_UNRECOGNIZED_COMMAND; } if (lpParms->lpstrReturn != NULL) lpParms->dwRetSize = strlen(lpParms->lpstrReturn); else lpParms->dwRetSize = 0; return 0; } /*-----------------------------------------------------------------------*/ /************************************************************************** * wodGetDevCaps [internal] */ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS lpCaps, DWORD dwSize) { int audio; int smplrate; int samplesize = 16; int dsp_stereo = 1; int bytespersmpl; dprintf_mciwave(stddeb, "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); if (lpCaps == NULL) return MMSYSERR_NOTENABLED; audio = open (SOUND_DEV, O_WRONLY, 0); if (audio == -1) return MMSYSERR_NOTENABLED; #ifdef EMULATE_SB16 lpCaps->wMid = 0x0002; lpCaps->wPid = 0x0104; strcpy(lpCaps->szPname, "SB16 Wave Out"); #else lpCaps->wMid = 0x00FF; /* Manufac ID */ lpCaps->wPid = 0x0001; /* Product ID */ strcpy(lpCaps->szPname, "Linux WAVOUT Driver"); #endif lpCaps->dwFormats = 0x00000000; lpCaps->dwSupport = WAVECAPS_VOLUME; lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2; if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME; bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2; smplrate = 44100; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_4M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_4M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16; } } smplrate = 22050; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_2M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_2M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16; } } smplrate = 11025; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_1M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_1M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16; } } close(audio); dprintf_mciwave(stddeb, "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats); return MMSYSERR_NOERROR; } /************************************************************************** * wodOpen [internal] */ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) { int audio; int abuf_size; int smplrate; int samplesize; int dsp_stereo; LPWAVEFORMAT lpFormat; dprintf_mciwave(stddeb, "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= MAX_WAVOUTDRV) { dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n"); return MMSYSERR_ALLOCATED; } WOutDev[wDevID].unixdev = 0; audio = open (SOUND_DEV, O_WRONLY, 0); if (audio == -1) { dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n"); return MMSYSERR_NOTENABLED; } IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size); if (abuf_size < 4096 || abuf_size > 65536) { if (abuf_size == -1) dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n"); else dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n"); return MMSYSERR_NOTENABLED; } WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); switch(WOutDev[wDevID].wFlags) { case DCB_NULL: dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n"); break; case DCB_WINDOW: dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n"); break; case DCB_TASK: dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n"); break; case DCB_FUNCTION: dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n"); break; } WOutDev[wDevID].lpQueueHdr = NULL; WOutDev[wDevID].unixdev = audio; WOutDev[wDevID].dwTotalPlayed = 0; WOutDev[wDevID].bufsize = abuf_size; memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC)); /* lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat); */ lpFormat = lpDesc->lpFormat; if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) { dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n", lpFormat->wFormatTag); dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n", lpFormat->nChannels); dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n", lpFormat->nSamplesPerSec); return WAVERR_BADFORMAT; } memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT)); if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT; if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT; dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample); if (WOutDev[wDevID].Format.wBitsPerSample == 0) { WOutDev[wDevID].Format.wBitsPerSample = 8 * (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / WOutDev[wDevID].Format.wf.nSamplesPerSec) / WOutDev[wDevID].Format.wf.nChannels; } samplesize = WOutDev[wDevID].Format.wBitsPerSample; smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec; dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE; IOCTL(audio, SNDCTL_DSP_SPEED, smplrate); IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize); IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo); dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample); dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nAvgBytesPerSec); dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nSamplesPerSec); dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n", WOutDev[wDevID].Format.wf.nChannels); if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; } /************************************************************************** * wodClose [internal] */ static DWORD wodClose(WORD wDevID) { dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n"); return MMSYSERR_NOTENABLED; } close(WOutDev[wDevID].unixdev); WOutDev[wDevID].unixdev = 0; WOutDev[wDevID].bufsize = 0; WOutDev[wDevID].lpQueueHdr = NULL; if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; } /************************************************************************** * wodWrite [internal] */ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { int count; LPSTR lpData; dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n"); return MMSYSERR_NOTENABLED; } if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED; if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED; if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; lpWaveHdr->dwFlags &= ~WHDR_DONE; lpWaveHdr->dwFlags |= WHDR_INQUEUE; dprintf_mciwave(stddeb, "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength); dprintf_mciwave(stddeb, "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev); lpData = PTR_SEG_TO_LIN(lpWaveHdr->lpData); count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength); dprintf_mciwave(stddeb, "wodWrite() // write returned count %u !\n", count); if (count != lpWaveHdr->dwBufferLength) { dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n"); return MMSYSERR_NOTENABLED; } WOutDev[wDevID].dwTotalPlayed += count; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; } /************************************************************************** * wodPrepare [internal] */ static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { dprintf_mciwave(stddeb, "wodPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n"); return MMSYSERR_NOTENABLED; } /* the COOL waveeditor feels much better without this check... * someone please have a look at available documentation if (WOutDev[wDevID].lpQueueHdr != NULL) { dprintf_mciwave(stddeb,"Linux 'wodPrepare' // already prepare !\n"); return MMSYSERR_NOTENABLED; } */ WOutDev[wDevID].dwTotalPlayed = 0; WOutDev[wDevID].lpQueueHdr = lpWaveHdr; if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; lpWaveHdr->dwFlags |= WHDR_PREPARED; lpWaveHdr->dwFlags &= ~WHDR_DONE; return MMSYSERR_NOERROR; } /************************************************************************** * wodUnprepare [internal] */ static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { dprintf_mciwave(stddeb, "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n"); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; } /************************************************************************** * wodRestart [internal] */ static DWORD wodRestart(WORD wDevID) { dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n"); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; } /************************************************************************** * wodReset [internal] */ static DWORD wodReset(WORD wDevID) { dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n"); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; } /************************************************************************** * wodGetPosition [internal] */ static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) { int time; dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize); if (WOutDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n"); return MMSYSERR_NOTENABLED; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; switch(lpTime->wType) { case TIME_BYTES: lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed; dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb); break; case TIME_SAMPLES: dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n", WOutDev[wDevID].dwTotalPlayed); dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n", WOutDev[wDevID].Format.wBitsPerSample); lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 / WOutDev[wDevID].Format.wBitsPerSample; dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample); break; case TIME_SMPTE: time = WOutDev[wDevID].dwTotalPlayed / (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); lpTime->u.smpte.hour = time / 108000; time -= lpTime->u.smpte.hour * 108000; lpTime->u.smpte.min = time / 1800; time -= lpTime->u.smpte.min * 1800; lpTime->u.smpte.sec = time / 30; time -= lpTime->u.smpte.sec * 30; lpTime->u.smpte.frame = time; lpTime->u.smpte.fps = 30; dprintf_mciwave(stddeb, "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n", lpTime->u.smpte.hour, lpTime->u.smpte.min, lpTime->u.smpte.sec, lpTime->u.smpte.frame); break; default: dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n"); lpTime->wType = TIME_MS; case TIME_MS: lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed / (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms); break; } return MMSYSERR_NOERROR; } /************************************************************************** * wodGetVolume [internal] */ static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol) { int mixer; int volume, left, right; dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol); if (lpdwVol == NULL) return MMSYSERR_NOTENABLED; if ((mixer = open("/dev/mixer", O_RDONLY)) < 0) { dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n"); return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) { dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n"); return MMSYSERR_NOTENABLED; } close(mixer); left = volume & 0x7F; right = (volume >> 8) & 0x7F; printf("Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right); *lpdwVol = MAKELONG(left << 9, right << 9); return MMSYSERR_NOERROR; } /************************************************************************** * wodSetVolume [internal] */ static DWORD wodSetVolume(WORD wDevID, DWORD dwParam) { int mixer; int volume; dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam); volume = (LOWORD(dwParam) >> 9 & 0x7F) + ((HIWORD(dwParam) >> 9 & 0x7F) << 8); if ((mixer = open("/dev/mixer", O_WRONLY)) < 0) { dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n"); return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) { dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n"); return MMSYSERR_NOTENABLED; } close(mixer); return MMSYSERR_NOERROR; } #endif /* linux */ /************************************************************************** * wodMessage [sample driver] */ DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); #ifdef linux switch(wMsg) { case WODM_OPEN: return wodOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_CLOSE: return wodClose(wDevID); case WODM_WRITE: return wodWrite(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_PAUSE: return 0L; case WODM_GETPOS: return wodGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_BREAKLOOP: return 0L; case WODM_PREPARE: return wodPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_UNPREPARE: return wodUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_GETDEVCAPS: return wodGetDevCaps(wDevID, (LPWAVEOUTCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WODM_GETNUMDEVS: return 1L; case WODM_GETPITCH: return 0L; case WODM_SETPITCH: return 0L; case WODM_GETPLAYBACKRATE: return 0L; case WODM_SETPLAYBACKRATE: return 0L; case WODM_GETVOLUME: return wodGetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1)); case WODM_SETVOLUME: return wodSetVolume(wDevID, dwParam1); case WODM_RESTART: return wodRestart(wDevID); case WODM_RESET: return wodReset(wDevID); default: dprintf_mciwave(stddeb,"wodMessage // unknown message !\n"); } return MMSYSERR_NOTSUPPORTED; #else return MMSYSERR_NOTENABLED; #endif } /*-----------------------------------------------------------------------*/ #ifdef linux /************************************************************************** * widGetDevCaps [internal] */ static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS lpCaps, DWORD dwSize) { int audio; int smplrate; int samplesize = 16; int dsp_stereo = 1; int bytespersmpl; dprintf_mciwave(stddeb, "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); if (lpCaps == NULL) return MMSYSERR_NOTENABLED; audio = open (SOUND_DEV, O_RDONLY, 0); if (audio == -1) return MMSYSERR_NOTENABLED; #ifdef EMULATE_SB16 lpCaps->wMid = 0x0002; lpCaps->wPid = 0x0004; strcpy(lpCaps->szPname, "SB16 Wave Out"); #else lpCaps->wMid = 0x00FF; /* Manufac ID */ lpCaps->wPid = 0x0001; /* Product ID */ strcpy(lpCaps->szPname, "Linux WAVIN Driver"); #endif lpCaps->dwFormats = 0x00000000; lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2; bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2; smplrate = 44100; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_4M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_4M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16; } } smplrate = 22050; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_2M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_2M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16; } } smplrate = 11025; if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { lpCaps->dwFormats |= WAVE_FORMAT_1M08; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08; if (bytespersmpl > 1) { lpCaps->dwFormats |= WAVE_FORMAT_1M16; if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16; } } close(audio); dprintf_mciwave(stddeb, "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats); return MMSYSERR_NOERROR; } /************************************************************************** * widOpen [internal] */ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) { int audio; int abuf_size; int smplrate; int samplesize; int dsp_stereo; LPWAVEFORMAT lpFormat; dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= MAX_WAVINDRV) { dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n"); return MMSYSERR_ALLOCATED; } WInDev[wDevID].unixdev = 0; audio = open (SOUND_DEV, O_RDONLY, 0); if (audio == -1) { dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n"); return MMSYSERR_NOTENABLED; } IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size); if (abuf_size < 4096 || abuf_size > 65536) { if (abuf_size == -1) dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n"); else dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n"); return MMSYSERR_NOTENABLED; } WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); switch(WInDev[wDevID].wFlags) { case DCB_NULL: dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_NULL !\n"); break; case DCB_WINDOW: dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_WINDOW !\n"); break; case DCB_TASK: dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_TASK !\n"); break; case DCB_FUNCTION: dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_FUNCTION !\n"); break; } WInDev[wDevID].lpQueueHdr = NULL; WInDev[wDevID].unixdev = audio; WInDev[wDevID].bufsize = abuf_size; WInDev[wDevID].dwTotalRecorded = 0; memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC)); lpFormat = lpDesc->lpFormat; if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) { dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n", lpFormat->wFormatTag); return WAVERR_BADFORMAT; } memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT)); WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */ if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT; if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT; if (WInDev[wDevID].Format.wBitsPerSample == 0) { WInDev[wDevID].Format.wBitsPerSample = 8 * (WInDev[wDevID].Format.wf.nAvgBytesPerSec / WInDev[wDevID].Format.wf.nSamplesPerSec) / WInDev[wDevID].Format.wf.nChannels; } samplesize = WInDev[wDevID].Format.wBitsPerSample; smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec; dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE; IOCTL(audio, SNDCTL_DSP_SPEED, smplrate); IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize); IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo); dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n", WInDev[wDevID].Format.wBitsPerSample); dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n", WInDev[wDevID].Format.wf.nSamplesPerSec); dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n", WInDev[wDevID].Format.wf.nChannels); dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec); if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; } /************************************************************************** * widClose [internal] */ static DWORD widClose(WORD wDevID) { dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n"); return MMSYSERR_NOTENABLED; } close(WInDev[wDevID].unixdev); WInDev[wDevID].unixdev = 0; WInDev[wDevID].bufsize = 0; if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; } /************************************************************************** * widAddBuffer [internal] */ static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { int count = 1; LPWAVEHDR lpWIHdr; dprintf_mciwave(stddeb, "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n"); return MMSYSERR_NOTENABLED; } if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) { dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n"); return WAVERR_UNPREPARED; } if (lpWaveHdr->dwFlags & WHDR_INQUEUE) { dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n"); return WAVERR_STILLPLAYING; } lpWaveHdr->dwFlags |= WHDR_PREPARED; lpWaveHdr->dwFlags |= WHDR_INQUEUE; lpWaveHdr->dwFlags &= ~WHDR_DONE; lpWaveHdr->dwBytesRecorded = 0; if (WInDev[wDevID].lpQueueHdr == NULL) { /* begin the queue with a first header ... */ WInDev[wDevID].lpQueueHdr = lpWaveHdr; WInDev[wDevID].dwTotalRecorded = 0; } else { /* added to the queue, except if it's the one just prepared ... */ lpWIHdr = WInDev[wDevID].lpQueueHdr; while (lpWIHdr->lpNext != NULL) { lpWIHdr = lpWIHdr->lpNext; count++; } lpWIHdr->lpNext = lpWaveHdr; count++; } dprintf_mciwave(stddeb, "widAddBuffer // buffer added ! (now %u in queue)\n", count); return MMSYSERR_NOERROR; } /************************************************************************** * widPrepare [internal] */ static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { dprintf_mciwave(stddeb, "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n"); return MMSYSERR_NOTENABLED; } if (WInDev[wDevID].lpQueueHdr != NULL) { dprintf_mciwave(stddeb,"Linux 'widPrepare' // already prepare !\n"); return WAVERR_BADFORMAT; } if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; lpWaveHdr->dwFlags |= WHDR_PREPARED; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags &= ~WHDR_DONE; lpWaveHdr->dwBytesRecorded = 0; dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n"); return MMSYSERR_NOERROR; } /************************************************************************** * widUnprepare [internal] */ static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) { dprintf_mciwave(stddeb, "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n"); return MMSYSERR_NOTENABLED; } lpWaveHdr->dwFlags &= ~WHDR_PREPARED; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; WInDev[wDevID].lpQueueHdr = NULL; dprintf_mciwave(stddeb, "Linux 'widUnprepare' // all headers unprepared !\n"); return MMSYSERR_NOERROR; } /************************************************************************** * widStart [internal] */ static DWORD widStart(WORD wDevID) { int count = 1; LPWAVEHDR lpWIHdr; dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n"); return MMSYSERR_NOTENABLED; } if (WInDev[wDevID].lpQueueHdr == NULL || WInDev[wDevID].lpQueueHdr->lpData == NULL) { dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n"); return WAVERR_UNPREPARED; } lpWIHdr = WInDev[wDevID].lpQueueHdr; while(lpWIHdr != NULL) { lpWIHdr->dwBufferLength &= 0xFFFF; dprintf_mciwave(stddeb, "widStart // recording buf#%u=%p size=%lu \n", count, lpWIHdr->lpData, lpWIHdr->dwBufferLength); fflush(stddeb); read (WInDev[wDevID].unixdev, PTR_SEG_TO_LIN(lpWIHdr->lpData), lpWIHdr->dwBufferLength); lpWIHdr->dwBytesRecorded = lpWIHdr->dwBufferLength; WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded; lpWIHdr->dwFlags &= ~WHDR_INQUEUE; lpWIHdr->dwFlags |= WHDR_DONE; if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWIHdr, 0L) != MMSYSERR_NOERROR) { dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n"); return MMSYSERR_INVALPARAM; } lpWIHdr = lpWIHdr->lpNext; count++; } dprintf_mciwave(stddeb,"widStart // end of recording !\n"); fflush(stdout); return MMSYSERR_NOERROR; } /************************************************************************** * widStop [internal] */ static DWORD widStop(WORD wDevID) { dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n"); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; } /************************************************************************** * widReset [internal] */ static DWORD widReset(WORD wDevID) { dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n"); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; } /************************************************************************** * widGetPosition [internal] */ static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) { int time; dprintf_mciwave(stddeb, "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize); if (WInDev[wDevID].unixdev == 0) { dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n"); return MMSYSERR_NOTENABLED; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n", lpTime->wType); dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n", WInDev[wDevID].Format.wBitsPerSample); dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n", WInDev[wDevID].Format.wf.nSamplesPerSec); dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n", WInDev[wDevID].Format.wf.nChannels); dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec); fflush(stddeb); switch(lpTime->wType) { case TIME_BYTES: lpTime->u.cb = WInDev[wDevID].dwTotalRecorded; dprintf_mciwave(stddeb, "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb); break; case TIME_SAMPLES: lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 / WInDev[wDevID].Format.wBitsPerSample; dprintf_mciwave(stddeb, "widGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample); break; case TIME_SMPTE: time = WInDev[wDevID].dwTotalRecorded / (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); lpTime->u.smpte.hour = time / 108000; time -= lpTime->u.smpte.hour * 108000; lpTime->u.smpte.min = time / 1800; time -= lpTime->u.smpte.min * 1800; lpTime->u.smpte.sec = time / 30; time -= lpTime->u.smpte.sec * 30; lpTime->u.smpte.frame = time; lpTime->u.smpte.fps = 30; dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n", lpTime->u.smpte.hour, lpTime->u.smpte.min, lpTime->u.smpte.sec, lpTime->u.smpte.frame); break; default: dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n"); lpTime->wType = TIME_MS; case TIME_MS: lpTime->u.ms = WInDev[wDevID].dwTotalRecorded / (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); dprintf_mciwave(stddeb, "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms); break; } return MMSYSERR_NOERROR; } #endif /* linux */ /************************************************************************** * widMessage [sample driver] */ DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); #ifdef linux switch(wMsg) { case WIDM_OPEN: return widOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_CLOSE: return widClose(wDevID); case WIDM_ADDBUFFER: return widAddBuffer(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_PREPARE: return widPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_UNPREPARE: return widUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_GETDEVCAPS: return widGetDevCaps(wDevID, (LPWAVEINCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_GETNUMDEVS: return 1; case WIDM_GETPOS: return widGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2); case WIDM_RESET: return widReset(wDevID); case WIDM_START: return widStart(wDevID); case WIDM_STOP: return widStop(wDevID); default: dprintf_mciwave(stddeb,"widMessage // unknown message !\n"); } return MMSYSERR_NOTSUPPORTED; #else return MMSYSERR_NOTENABLED; #endif } /************************************************************************** * AUDIO_DriverProc [sample driver] */ LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, DWORD dwParam1, DWORD dwParam2) { #ifdef linux dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID, hDriv, wMsg, dwParam1, dwParam2); switch(wMsg) { case DRV_LOAD: return 1; case DRV_FREE: return 1; case DRV_OPEN: return 1; case DRV_CLOSE: return 1; case DRV_ENABLE: return 1; case DRV_DISABLE: return 1; case DRV_QUERYCONFIGURE: return 1; case DRV_CONFIGURE: MessageBox((HWND)NULL, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1; case DRV_INSTALL: return DRVCNF_RESTART; case DRV_REMOVE: return DRVCNF_RESTART; case MCI_OPEN_DRIVER: case MCI_OPEN: return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_CLOSE_DRIVER: case MCI_CLOSE: return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_PLAY: return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_RECORD: return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_STOP: return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_SET: return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_PAUSE: return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_RESUME: return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_STATUS: return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2)); case MCI_INFO: return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS)PTR_SEG_TO_LIN(dwParam2)); default: return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); } #else return MMSYSERR_NOTENABLED; #endif } #endif /* #ifdef BUILTIN_MMSYSTEM */