mixer.c
来自「一个类似windows」· C语言 代码 · 共 1,178 行 · 第 1/3 页
C
1,178 行
/* DirectSound * * Copyright 1998 Marcus Meissner * Copyright 1998 Rob Riggs * Copyright 2000-2002 TransGaming Technologies, Inc. * * 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 <assert.h>#include <stdarg.h>#include <math.h> /* Insomnia - pow() function */#define NONAMELESSSTRUCT#define NONAMELESSUNION#include "windef.h"#include "winbase.h"#include "mmsystem.h"#include "winreg.h"#include "winternl.h"#include "wine/debug.h"#include "dsound.h"#include "dsdriver.h"#include "dsound_private.h"WINE_DEFAULT_DEBUG_CHANNEL(dsound);void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan){ double temp; TRACE("(%p)\n",volpan); TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan); /* the AmpFactors are expressed in 16.16 fixed point */ volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 0xffff); /* FIXME: dwPan{Left|Right}AmpFactor */ /* FIXME: use calculated vol and pan ampfactors */ temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0)); volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0)); volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor);}void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan){ double left,right; TRACE("(%p)\n",volpan); TRACE("left=%lx, right=%lx\n",volpan->dwTotalLeftAmpFactor,volpan->dwTotalRightAmpFactor); if (volpan->dwTotalLeftAmpFactor==0) left=-10000; else left=600 * log(((double)volpan->dwTotalLeftAmpFactor) / 0xffff) / log(2); if (volpan->dwTotalRightAmpFactor==0) right=-10000; else right=600 * log(((double)volpan->dwTotalRightAmpFactor) / 0xffff) / log(2); if (left<right) { volpan->lVolume=right; volpan->dwVolAmpFactor=volpan->dwTotalRightAmpFactor; } else { volpan->lVolume=left; volpan->dwVolAmpFactor=volpan->dwTotalLeftAmpFactor; } if (volpan->lVolume < -10000) volpan->lVolume=-10000; volpan->lPan=right-left; if (volpan->lPan < -10000) volpan->lPan=-10000; TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan);}void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb){ TRACE("(%p)\n",dsb); /* calculate the 10ms write lead */ dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign;}void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len){ int i; DWORD offset; LPDSBPOSITIONNOTIFY event; TRACE("(%p,%d)\n",dsb,len); if (dsb->nrofnotifies == 0) return; TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n", dsb, dsb->buflen, dsb->playpos, len); for (i = 0; i < dsb->nrofnotifies ; i++) { event = dsb->notifies + i; offset = event->dwOffset; TRACE("checking %d, position %ld, event = %p\n", i, offset, event->hEventNotify); /* DSBPN_OFFSETSTOP has to be the last element. So this is */ /* OK. [Inside DirectX, p274] */ /* */ /* This also means we can't sort the entries by offset, */ /* because DSBPN_OFFSETSTOP == -1 */ if (offset == DSBPN_OFFSETSTOP) { if (dsb->state == STATE_STOPPED) { SetEvent(event->hEventNotify); TRACE("signalled event %p (%d)\n", event->hEventNotify, i); return; } else return; } if ((dsb->playpos + len) >= dsb->buflen) { if ((offset < ((dsb->playpos + len) % dsb->buflen)) || (offset >= dsb->playpos)) { TRACE("signalled event %p (%d)\n", event->hEventNotify, i); SetEvent(event->hEventNotify); } } else { if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) { TRACE("signalled event %p (%d)\n", event->hEventNotify, i); SetEvent(event->hEventNotify); } } }}/* WAV format info can be found at: * * http://www.cwi.nl/ftp/audio/AudioFormats.part2 * ftp://ftp.cwi.nl/pub/audio/RIFF-format * * Import points to remember: * 8-bit WAV is unsigned * 16-bit WAV is signed */ /* Use the same formulas as pcmconverter.c */static inline INT16 cvtU8toS16(BYTE b){ return (short)((b+(b << 8))-32768);}static inline BYTE cvtS16toU8(INT16 s){ return (s >> 8) ^ (unsigned char)0x80;}static inline void cp_fields(const IDirectSoundBufferImpl *dsb, BYTE *ibuf, BYTE *obuf ){ DirectSoundDevice * device = dsb->dsound->device; INT fl,fr; if (dsb->pwfx->wBitsPerSample == 8) { if (device->pwfx->wBitsPerSample == 8 && device->pwfx->nChannels == dsb->pwfx->nChannels) { /* avoid needless 8->16->8 conversion */ *obuf=*ibuf; if (dsb->pwfx->nChannels==2) *(obuf+1)=*(ibuf+1); return; } fl = cvtU8toS16(*ibuf); fr = (dsb->pwfx->nChannels==2 ? cvtU8toS16(*(ibuf + 1)) : fl); } else { fl = *((INT16 *)ibuf); fr = (dsb->pwfx->nChannels==2 ? *(((INT16 *)ibuf) + 1) : fl); } if (device->pwfx->nChannels == 2) { if (device->pwfx->wBitsPerSample == 8) { *obuf = cvtS16toU8(fl); *(obuf + 1) = cvtS16toU8(fr); return; } if (device->pwfx->wBitsPerSample == 16) { *((INT16 *)obuf) = fl; *(((INT16 *)obuf) + 1) = fr; return; } } if (device->pwfx->nChannels == 1) { fl = (fl + fr) >> 1; if (device->pwfx->wBitsPerSample == 8) { *obuf = cvtS16toU8(fl); return; } if (device->pwfx->wBitsPerSample == 16) { *((INT16 *)obuf) = fl; return; } }}/* Now with PerfectPitch (tm) technology */static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len){ INT i, size, ipos, ilen; BYTE *ibp, *obp; INT iAdvance = dsb->pwfx->nBlockAlign; INT oAdvance = dsb->dsound->device->pwfx->nBlockAlign; ibp = dsb->buffer->memory + dsb->buf_mixpos; obp = buf; TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb, ibp, obp, dsb->buf_mixpos); /* Check for the best case */ if ((dsb->freq == dsb->dsound->device->pwfx->nSamplesPerSec) && (dsb->pwfx->wBitsPerSample == dsb->dsound->device->pwfx->wBitsPerSample) && (dsb->pwfx->nChannels == dsb->dsound->device->pwfx->nChannels)) { INT bytesleft = dsb->buflen - dsb->buf_mixpos; TRACE("(%p) Best case\n", dsb); if (len <= bytesleft ) CopyMemory(obp, ibp, len); else { /* wrap */ CopyMemory(obp, ibp, bytesleft); CopyMemory(obp + bytesleft, dsb->buffer->memory, len - bytesleft); } return len; } /* Check for same sample rate */ if (dsb->freq == dsb->dsound->device->pwfx->nSamplesPerSec) { TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb, dsb->freq, dsb->dsound->device->pwfx->nSamplesPerSec); ilen = 0; for (i = 0; i < len; i += oAdvance) { cp_fields(dsb, ibp, obp ); ibp += iAdvance; ilen += iAdvance; obp += oAdvance; if (ibp >= (BYTE *)(dsb->buffer->memory + dsb->buflen)) ibp = dsb->buffer->memory; /* wrap */ } return (ilen); } /* Mix in different sample rates */ /* */ /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */ /* Patent Pending :-] */ /* Patent enhancements (c) 2000 Ove K鍁en, * TransGaming Technologies Inc. */ /* FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n", dsb, dsb->freq, dsb->dsound->device->pwfx->nSamplesPerSec); */ size = len / oAdvance; ilen = 0; ipos = dsb->buf_mixpos; for (i = 0; i < size; i++) { cp_fields(dsb, (dsb->buffer->memory + ipos), obp); obp += oAdvance; dsb->freqAcc += dsb->freqAdjust; if (dsb->freqAcc >= (1<<DSOUND_FREQSHIFT)) { ULONG adv = (dsb->freqAcc>>DSOUND_FREQSHIFT) * iAdvance; dsb->freqAcc &= (1<<DSOUND_FREQSHIFT)-1; ipos += adv; ilen += adv; ipos %= dsb->buflen; } } return ilen;}static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len){ INT i; BYTE *bpc = buf; INT16 *bps = (INT16 *) buf; TRACE("(%p,%p,%d)\n",dsb,buf,len); TRACE("left = %lx, right = %lx\n", dsb->cvolpan.dwTotalLeftAmpFactor, dsb->cvolpan.dwTotalRightAmpFactor); if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->cvolpan.lPan == 0)) && (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->cvolpan.lVolume == 0)) && !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) return; /* Nothing to do */ /* If we end up with some bozo coder using panning or 3D sound */ /* with a mono primary buffer, it could sound very weird using */ /* this method. Oh well, tough patooties. */ switch (dsb->dsound->device->pwfx->wBitsPerSample) { case 8: /* 8-bit WAV is unsigned, but we need to operate */ /* on signed data for this to work properly */ switch (dsb->dsound->device->pwfx->nChannels) { case 1: for (i = 0; i < len; i++) { INT val = *bpc - 128; val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; *bpc = val + 128; bpc++; } break; case 2: for (i = 0; i < len; i+=2) { INT val = *bpc - 128; val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; *bpc++ = val + 128; val = *bpc - 128; val = (val * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; *bpc = val + 128; bpc++; } break; default: FIXME("doesn't support %d channels\n", dsb->dsound->device->pwfx->nChannels); break; } break; case 16: /* 16-bit WAV is signed -- much better */ switch (dsb->dsound->device->pwfx->nChannels) { case 1: for (i = 0; i < len; i += 2) { *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; bps++; } break; case 2: for (i = 0; i < len; i += 4) { *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; bps++; *bps = (*bps * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; bps++; } break; default: FIXME("doesn't support %d channels\n", dsb->dsound->device->pwfx->nChannels); break; } break; default: FIXME("doesn't support %d bit samples\n", dsb->dsound->device->pwfx->wBitsPerSample); break; }}static LPBYTE DSOUND_tmpbuffer(DirectSoundDevice *device, DWORD len){ TRACE("(%p,%ld)\n", device, len); if (len > device->tmp_buffer_len) { if (device->tmp_buffer) device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, device->tmp_buffer, len); else device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, len); device->tmp_buffer_len = len; } return device->tmp_buffer;}static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen){ INT i, len, ilen, field, todo; BYTE *buf, *ibuf; TRACE("(%p,%ld,%ld)\n",dsb,writepos,fraglen); len = fraglen; if (!(dsb->playflags & DSBPLAY_LOOPING)) { int secondary_remainder = dsb->buflen - dsb->buf_mixpos; int adjusted_remainder = MulDiv(dsb->dsound->device->pwfx->nAvgBytesPerSec, secondary_remainder, dsb->nAvgBytesPerSec); assert(adjusted_remainder >= 0); TRACE("secondary_remainder = %d, adjusted_remainder = %d, len = %d\n", secondary_remainder, adjusted_remainder, len); if (adjusted_remainder < len) { TRACE("clipping len to remainder of secondary buffer\n"); len = adjusted_remainder; } if (len == 0) return 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?