📄 audio.c
字号:
*/static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){ TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (wDevID >= MAX_WAVEOUTDRV) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; lpWaveHdr->dwFlags &= ~WHDR_PREPARED; lpWaveHdr->dwFlags |= WHDR_DONE; return MMSYSERR_NOERROR;}/************************************************************************** * wodPause [internal] */static DWORD wodPause(WORD wDevID){ TRACE("(%u);!\n", wDevID); if (wDevID >= MAX_WAVEOUTDRV || AuServ == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } TRACE("imhere[3-PAUSING]\n"); NAS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodRestart [internal] */static DWORD wodRestart(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= MAX_WAVEOUTDRV || AuServ == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (WOutDev[wDevID].state == WINE_WS_PAUSED) { TRACE("imhere[3-RESTARTING]\n"); NAS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE); } /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */ /* FIXME: Myst crashes with this ... hmm -MM return wodNotifyClient(wwo, WOM_DONE, 0L, 0L); */ return MMSYSERR_NOERROR;}/************************************************************************** * wodReset [internal] */static DWORD wodReset(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= MAX_WAVEOUTDRV || AuServ == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } TRACE("imhere[3-RESET]\n"); NAS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodGetPosition [internal] */static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize){ int time; DWORD val; WINE_WAVEOUT* wwo; TRACE("%u, %p, %lu);\n", wDevID, lpTime, uSize); if (wDevID >= MAX_WAVEOUTDRV || AuServ == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; wwo = &WOutDev[wDevID];#if 0 NAS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);#endif val = wwo->WrittenTotal; TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n", lpTime->wType, wwo->format.wBitsPerSample, wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels, wwo->format.wf.nAvgBytesPerSec); TRACE("PlayedTotal=%lu\n", val); switch (lpTime->wType) { case TIME_BYTES: lpTime->u.cb = val; TRACE("TIME_BYTES=%lu\n", lpTime->u.cb); break; case TIME_SAMPLES: lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample / wwo->format.wf.nChannels; TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample); break; case TIME_SMPTE: time = val / (wwo->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; TRACE("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: FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType); lpTime->wType = TIME_MS; case TIME_MS: lpTime->u.ms = val / (wwo->format.wf.nAvgBytesPerSec / 1000); TRACE("TIME_MS=%lu\n", lpTime->u.ms); break; } return MMSYSERR_NOERROR;}/************************************************************************** * wodBreakLoop [internal] */static DWORD wodBreakLoop(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= MAX_WAVEOUTDRV || AuServ == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } NAS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodGetVolume [internal] */static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol){ DWORD left, right; left = WOutDev[wDevID].volume_left; right = WOutDev[wDevID].volume_right; TRACE("(%u, %p);\n", wDevID, lpdwVol); *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) << 16); return MMSYSERR_NOERROR;}/************************************************************************** * wodSetVolume [internal] */static DWORD wodSetVolume(WORD wDevID, DWORD dwParam){ DWORD left, right; left = (LOWORD(dwParam) * 100) / 0xFFFFl; right = (HIWORD(dwParam) * 100) / 0xFFFFl; TRACE("(%u, %08lX);\n", wDevID, dwParam); WOutDev[wDevID].volume_left = left; WOutDev[wDevID].volume_right = right; return MMSYSERR_NOERROR;}/************************************************************************** * wodGetNumDevs [internal] */static DWORD wodGetNumDevs(void){ return MAX_WAVEOUTDRV;}/************************************************************************** * wodMessage (WINENAS.@) */DWORD WINAPI NAS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); switch (wMsg) { case DRVM_INIT: case DRVM_EXIT: case DRVM_ENABLE: case DRVM_DISABLE: /* FIXME: Pretend this is supported */ return 0; case WODM_OPEN: return wodOpen (wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2); case WODM_CLOSE: return wodClose (wDevID); case WODM_WRITE: return wodWrite (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_PAUSE: return wodPause (wDevID); case WODM_GETPOS: return wodGetPosition (wDevID, (LPMMTIME)dwParam1, dwParam2); case WODM_BREAKLOOP: return wodBreakLoop (wDevID); case WODM_PREPARE: return wodPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_UNPREPARE: return wodUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2); case WODM_GETNUMDEVS: return wodGetNumDevs (); case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; case WODM_GETVOLUME: return wodGetVolume (wDevID, (LPDWORD)dwParam1); case WODM_SETVOLUME: return wodSetVolume (wDevID, dwParam1); case WODM_RESTART: return wodRestart (wDevID); case WODM_RESET: return wodReset (wDevID); case DRV_QUERYDSOUNDIFACE: return wodDsCreate (wDevID, (PIDSDRIVER*)dwParam1); case DRV_QUERYDSOUNDDESC: return wodDsDesc (wDevID, (PDSDRIVERDESC)dwParam1); case DRV_QUERYDSOUNDGUID: return wodDsGuid (wDevID, (LPGUID)dwParam1); default: FIXME("unknown message %d!\n", wMsg); } return MMSYSERR_NOTSUPPORTED;}/*======================================================================* * Low level DSOUND implementation * *======================================================================*/static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv){ /* we can't perform memory mapping as we don't have a file stream interface with nas like we do with oss */ MESSAGE("This sound card s driver does not support direct access\n"); MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n"); return MMSYSERR_NOTSUPPORTED;}static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc){ memset(desc, 0, sizeof(*desc)); strcpy(desc->szDesc, "Wine NAS DirectSound Driver"); strcpy(desc->szDrvName, "winenas.drv"); return MMSYSERR_NOERROR;}static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid){ memcpy(pGuid, &DSDEVID_DefaultPlayback, sizeof(GUID)); return MMSYSERR_NOERROR;}static int nas_init(void) { TRACE("NAS INIT\n"); if (!(AuServ = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) return 0; return 1;}static int nas_finddev(WINE_WAVEOUT* wwo) { int i; for (i = 0; i < AuServerNumDevices(wwo->AuServ); i++) { if ((AuDeviceKind(AuServerDevice(wwo->AuServ, i)) == AuComponentKindPhysicalOutput) && AuDeviceNumTracks(AuServerDevice(wwo->AuServ, i)) == wwo->format.wf.nChannels) { wwo->AuDev = AuDeviceIdentifier(AuServerDevice(wwo->AuServ, i)); break; } } if (wwo->AuDev == AuNone) return 0; return 1;}static int nas_open(WINE_WAVEOUT* wwo) { AuElement elements[3]; if (!wwo->AuServ) return 0; if (!nas_finddev(wwo)) return 0; if (!(wwo->AuFlow = AuCreateFlow(wwo->AuServ, NULL))) return 0; wwo->BufferSize = FRAG_SIZE * FRAG_COUNT; AuMakeElementImportClient(&elements[0], wwo->format.wf.nSamplesPerSec, wwo->format.wBitsPerSample == 16 ? AuFormatLinearSigned16LSB : AuFormatLinearUnsigned8, wwo->format.wf.nChannels, AuTrue, wwo->BufferSize, wwo->BufferSize / 2, 0, NULL); AuMakeElementExportDevice(&elements[1], 0, wwo->AuDev, wwo->format.wf.nSamplesPerSec, AuUnlimitedSamples, 0, NULL); AuSetElements(wwo->AuServ, wwo->AuFlow, AuTrue, 2, elements, NULL); AuRegisterEventHandler(wwo->AuServ, AuEventHandlerIDMask, 0, wwo->AuFlow, event_handler, (AuPointer) wwo); wwo->PlayedTotal = 0; wwo->WrittenTotal = 0; wwo->open = 1; wwo->BufferUsed = 0; wwo->writeBytes = 0; wwo->freeBytes = 0; wwo->sendBytes = 0; wwo->SoundBuffer = NULL; wwo->FlowStarted = 0; AuStartFlow(wwo->AuServ, wwo->AuFlow, NULL); AuPauseFlow(wwo->AuServ, wwo->AuFlow, NULL); wwo->FlowStarted = 1; return 1;}static AuBoolevent_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd){ WINE_WAVEOUT *wwo = (WINE_WAVEOUT *)hnd->data; switch (ev->type) { case AuEventTypeElementNotify: { AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev; switch (event->kind) { case AuElementNotifyKindLowWater: wwo->freeBytes += event->num_bytes; if (wwo->writeBytes > 0) wwo->sendBytes += event->num_bytes; if (wwo->freeBytes && wwo->BufferUsed) nas_send_buffer(wwo); break; case AuElementNotifyKindState: TRACE("ev: kind %s state %s->%s reason %s numbytes %ld freeB %lu\n", nas_elementnotify_kind(event->kind), nas_state(event->prev_state), nas_state(event->cur_state), nas_reason(event->reason), event->num_bytes, wwo->freeBytes); if (event->cur_state == AuStatePause && event->reason != AuReasonUser) { wwo->freeBytes += event->num_bytes; if (wwo->writeBytes > 0) wwo->sendBytes += event->num_bytes; if (wwo->sendBytes > wwo->writeBytes) wwo->sendBytes = wwo->writeBytes; if (wwo->freeBytes && wwo->BufferUsed) nas_send_buffer(wwo); } break; } } } return AuTrue;}static voidbuffer_resize(WINE_WAVEOUT* wwo, int len){ void *newbuf = malloc(wwo->BufferUsed + len); void *oldbuf = wwo->SoundBuffer; memcpy(newbuf, oldbuf, wwo->BufferUsed); wwo->SoundBuffer = newbuf; if (oldbuf != NULL) free(oldbuf);}static int nas_add_buffer(WINE_WAVEOUT* wwo) { int len = wwo->lpPlayPtr->dwBufferLength; buffer_resize(wwo, len); memcpy(wwo->SoundBuffer + wwo->BufferUsed, wwo->lpPlayPtr->lpData, len); wwo->BufferUsed += len; wwo->WrittenTotal += len; return len;}static int nas_send_buffer(WINE_WAVEOUT* wwo) { int oldb , len; char *ptr, *newdata; newdata = NULL; oldb = len = 0; if (wwo->freeBytes <= 0) return 0; if (wwo->SoundBuffer == NULL || wwo->BufferUsed == 0) { return 0; } if (wwo->BufferUsed <= wwo->freeBytes) { len = wwo->BufferUsed; ptr = wwo->SoundBuffer; } else { len = wwo->freeBytes; ptr = malloc(len); memcpy(ptr,wwo->SoundBuffer,len); newdata = malloc(wwo->BufferUsed - len); memcpy(newdata, wwo->SoundBuffer + len, wwo->BufferUsed - len); } TRACE("envoye de %d bytes / %lu bytes / freeBytes %lu\n", len, wwo->BufferUsed, wwo->freeBytes); AuWriteElement(wwo->AuServ, wwo->AuFlow, 0, len, ptr, AuFalse, NULL); wwo->BufferUsed -= len; wwo->freeBytes -= len; wwo->writeBytes += len; free(ptr); wwo->SoundBuffer = NULL; if (newdata != NULL) wwo->SoundBuffer = newdata; return len;}static int nas_free(WINE_WAVEOUT* wwo){ if (!wwo->FlowStarted && wwo->BufferUsed) { AuStartFlow(wwo->AuServ, wwo->AuFlow, NULL); wwo->FlowStarted = 1; } while (wwo->BufferUsed || wwo->writeBytes != wwo->sendBytes) { if (wwo->freeBytes) nas_send_buffer(wwo); AuHandleEvents(wwo->AuServ); } AuFlush(wwo->AuServ); return TRUE;}static int nas_close(WINE_WAVEOUT* wwo){ AuEvent ev; nas_free(wwo); AuStopFlow(wwo->AuServ, wwo->AuFlow, NULL); AuDestroyFlow(wwo->AuServ, wwo->AuFlow, NULL); AuFlush(wwo->AuServ); AuNextEvent(wwo->AuServ, AuTrue, &ev); AuDispatchEvent(wwo->AuServ, &ev); wwo->AuFlow = 0; wwo->open = 0; wwo->BufferUsed = 0; wwo->freeBytes = 0; wwo->SoundBuffer = NULL; return 1;}static int nas_end(void){ AuCloseServer(AuServ); AuServ = 0; return 1;}#else /* !HAVE_NAS *//************************************************************************** * wodMessage (WINENAS.@) */DWORD WINAPI NAS_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ FIXME("(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); return MMSYSERR_NOTENABLED;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -