High quality sample rate converter.<br>New code seems simplier and faster despite the big sound quality improvement.<br><br>This patchset only makes sense when applying all 13 parts.<br><br>Fixes bug:<br><a href="http://bugs.winehq.org/show_bug.cgi?id=14717">http://bugs.winehq.org/show_bug.cgi?id=14717</a><br>
<br><br>---<br> dlls/dsound/resample.c | 381 ++++++++++++++++++++++++++++++++++++++++++++++++<br> 1 files changed, 381 insertions(+), 0 deletions(-)<br> create mode 100644 dlls/dsound/resample.c<br><br>diff --git a/dlls/dsound/resample.c b/dlls/dsound/resample.c<br>
new file mode 100644<br>index 0000000..7738dd4<br>--- /dev/null<br>+++ b/dlls/dsound/resample.c<br>@@ -0,0 +1,381 @@<br>+/* DirectSound<br>+ *<br>+ * Resample core<br>+ * Copyright 2010, 2011 Krzysztof Nikiel<br>+ *<br>+ * Initially based on resample:<br>
+ * <a href="http://www-ccrma.stanford.edu/~jos/resample/">http://www-ccrma.stanford.edu/~jos/resample/</a><br>+ *<br>+ *<br>+ * This library is free software; you can redistribute it and/or<br>+ * modify it under the terms of the GNU Lesser General Public<br>
+ * License as published by the Free Software Foundation; either<br>+ * version 2.1 of the License, or (at your option) any later version.<br>+ *<br>+ * This library is distributed in the hope that it will be useful,<br>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br>+ * Lesser General Public License for more details.<br>+ *<br>+ * You should have received a copy of the GNU Lesser General Public<br>+ * License along with this library; if not, write to the Free Software<br>
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA<br>+ */<br>+<br>+#include <stdarg.h><br>+#include <math.h><br>+<br>+#define NONAMELESSSTRUCT<br>+#define NONAMELESSUNION<br>+#include "windef.h"<br>
+#include "winbase.h"<br>+#include "mmsystem.h"<br>+#include "winternl.h"<br>+#include "wine/debug.h"<br>+#include "dsound.h"<br>+#include "dsdriver.h"<br>+#include "dsound_private.h"<br>
+<br>+#include "firtab.h"<br>+<br>+WINE_DEFAULT_DEBUG_CHANNEL(dsound);<br>+<br>+<br>+#define MAXCHAN 16<br>+<br>+#define CLIPSAMPLE(x,max) if(x>max)x=max;if(x<-max)x=-max;<br>+#define SAMPLE24(p) (*((BYTE*)p)|*((BYTE*)p+1)<<8|*((CHAR*)p+2)<<16)<br>
+#ifdef WORDS_BIGENDIAN<br>+#define SAMPLE16(p) (*((BYTE*)p)|*((CHAR*)p+1)<<8)<br>+#define PUT16(p,s) *((BYTE*)p)=s;*((BYTE*)p+1)=(s>>8)<br>+#else<br>+#define SAMPLE16(p) (*((SHORT*)p))<br>+#define PUT16(p,s) *((SHORT*)p)=s<br>
+#endif<br>+<br>+<br>+typedef double sample_t;<br>+<br>+static fir_t *g_fir[] = {<br>+ &firfast,<br>+ &firgood,<br>+ &firbest,<br>+ &firslow,<br>+#if RESAMPLE_INSANE<br>+ &firinsane,<br>+#endif<br>
+ NULL<br>+};<br>+<br>+<br>+static inline sample_t getsample(LPBYTE buf, INT bps)<br>+{<br>+ sample_t tmp;<br>+<br>+ switch (bps)<br>+ {<br>+ case 1:<br>+ tmp = ((sample_t) (*((BYTE *) buf)) - 128.0);<br>+ tmp *= 256.0;<br>
+ break;<br>+ case 2:<br>+ tmp = SAMPLE16(buf);<br>+ break;<br>+ case 3:<br>+ tmp = SAMPLE24(buf);<br>+ tmp *= (1.0 / 256.0);<br>+ break;<br>+ case 4:<br>+ tmp = *((INT *) buf);<br>+ tmp *= (1.0 / 65536.0);<br>
+ break;<br>+ }<br>+ return tmp;<br>+}<br>+<br>+static inline void putsample(LPBYTE buf, INT bps, sample_t smp)<br>+{<br>+ INT ismp;<br>+<br>+ switch (bps)<br>+ {<br>+ case 1:<br>+ ismp = lrint(smp);<br>+ ismp /= 0x100;<br>
+ ismp += (INT) * ((BYTE *) buf) - 0x80;<br>+ CLIPSAMPLE(ismp, 0x7f);<br>+ *((BYTE *) buf) = ismp + 0x80;<br>+ break;<br>+ case 2:<br>+ ismp = lrint(smp);<br>+ ismp += SAMPLE16(buf);<br>+ CLIPSAMPLE(ismp, 0x7fff);<br>
+ PUT16(buf, ismp);<br>+ break;<br>+ case 3:<br>+ ismp = lrint(smp * 256.0);<br>+ ismp += SAMPLE24(buf);<br>+ CLIPSAMPLE(ismp, 0x7fffff);<br>+ *((BYTE *) buf) = ismp & 0xff;<br>+ ismp >>= 8;<br>
+ *((BYTE *) buf + 1) = ismp & 0xff;<br>+ ismp >>= 8;<br>+ *((BYTE *) buf + 2) = ismp & 0xff;<br>+ break;<br>+ case 4:<br>+ CLIPSAMPLE(smp, (double) 0x7fff);<br>+ ismp = lrint(smp * 65536.0);<br>
+ *((INT *) buf) += ismp;<br>+ break;<br>+ }<br>+}<br>+<br>+<br>+/*<br>+ * Takes buffer data starting from current position and mixes new samples<br>+ * with primary buffer, starting at writepos.<br>+ * At most mixlen bytes can be mixed.<br>
+ * 'writepos' and 'mixlen' should be block aligned.<br>+ */<br>+DWORD DSOUND_PullBuffer(IDirectSoundBufferImpl * dsb, DWORD writepos,<br>+ DWORD mixlen)<br>+{<br>+ INT iAdvance, oAdvance, iBPS, oBPS;<br>
+ sample_t rsum[MAXCHAN], smp[MAXCHAN];<br>+ BYTE *bufptr;<br>+ DWORD outlen;<br>+ INT iChans, oChans;<br>+ INT chan;<br>+ INT firstep;<br>+ DOUBLE amp[3];<br>+ fir_t *fir = g_fir[dsb->quality];<br>+<br>+ iAdvance = dsb->pwfx->nBlockAlign;<br>
+ oAdvance = dsb->device->pwfx->nBlockAlign;<br>+ iBPS = dsb->pwfx->wBitsPerSample >> 3;<br>+ oBPS = dsb->device->pwfx->wBitsPerSample >> 3;<br>+ outlen = 0;<br>+ iChans = dsb->pwfx->nChannels;<br>
+ oChans = dsb->device->pwfx->nChannels;<br>+<br>+ if (iChans >= MAXCHAN)<br>+ iChans = MAXCHAN - 1;<br>+ if (oChans >= MAXCHAN)<br>+ oChans = MAXCHAN - 1;<br>+<br>+ firstep = dsb->firstep;<br>
+<br>+ amp[0] = (DOUBLE) dsb->volpan.dwTotalLeftAmpFactor<br>+ * ((DOUBLE) firstep / 65536.0);<br>+ if (oChans > 1)<br>+ {<br>+ amp[1] = (DOUBLE) dsb->volpan.dwTotalRightAmpFactor<br>+ * ((DOUBLE) firstep / 65536.0);<br>
+ if (oChans > 2)<br>+ amp[2] = (DOUBLE) dsb->volpan.dwVolAmpFactor<br>+ * ((DOUBLE) firstep / 65536.0);<br>+ }<br>+<br>+ while (1)<br>+ {<br>+ double firpos, firfrac;<br>+ int firpos_i;<br>+ double ifir;<br>
+<br>+ outlen += oAdvance;<br>+ if (outlen > mixlen)<br>+ {<br>+ outlen -= oAdvance;<br>+ break;<br>+ }<br>+<br>+ if ((dsb->inpos + iAdvance) > dsb->buflen)<br>+ {<br>+ TRACE("Buffer not sample aligned (%p,%d,%d)\n",<br>
+ dsb, dsb->buflen, iAdvance);<br>+ dsb->inpos = 0;<br>+ }<br>+<br>+ bufptr = dsb->buffer->memory + dsb->inpos;<br>+<br>+ if (dsb->freq != dsb->outfreq)<br>+ {<br>+ firpos = (double) fir->size - 1<br>
+ - ((double) firstep * dsb->infrac * dsb->outfreq_1);<br>+<br>+ firfrac = firpos - floor(firpos);<br>+ firpos_i = firpos;<br>+<br>+ for (chan = 0; chan < iChans; chan++)<br>+ rsum[chan] = 0.0;<br>
+<br>+ /* right wing */<br>+ while (firpos_i >= 0)<br>+ {<br>+ for (chan = iChans - 1; chan >= 0; chan--)<br>+ {<br>+ bufptr -= iBPS;<br>+ if (bufptr < dsb->buffer->memory)<br>
+ bufptr += dsb->buflen;<br>+<br>+ smp[chan] = getsample(bufptr, iBPS);<br>+ }<br>+<br>+ ifir = (1.0 - firfrac) * fir->wing[firpos_i]<br>+ + firfrac * fir->wing[firpos_i + 1];<br>
+<br>+ for (chan = 0; chan < iChans; chan++)<br>+ rsum[chan] += ifir * smp[chan];<br>+<br>+ firpos_i -= firstep;<br>+ }<br>+<br>+ /* left wing */<br>+ firpos_i = -firpos_i;<br>+ if (firfrac > 0.0)<br>
+ {<br>+ firfrac = 1.0 - firfrac;<br>+ firpos_i--;<br>+ }<br>+<br>+ while (firpos_i < (fir->size - 1))<br>+ {<br>+ for (chan = iChans - 1; chan >= 0; chan--)<br>+ {<br>
+ bufptr -= iBPS;<br>+ if (bufptr < dsb->buffer->memory)<br>+ bufptr += dsb->buflen;<br>+<br>+ smp[chan] = getsample(bufptr, iBPS);<br>+ }<br>+<br>+ ifir = (1.0 - firfrac) * fir->wing[firpos_i]<br>
+ + firfrac * fir->wing[firpos_i + 1];<br>+<br>+ for (chan = 0; chan < iChans; chan++)<br>+ rsum[chan] += ifir * smp[chan];<br>+<br>+ firpos_i += firstep;<br>+ }<br>+ }<br>+ else<br>
+ {<br>+ for (chan = iChans - 1; chan >= 0; chan--)<br>+ {<br>+ bufptr -= iBPS;<br>+ if (bufptr < dsb->buffer->memory)<br>+ bufptr += dsb->buflen;<br>+<br>+ rsum[chan] = getsample(bufptr, iBPS);<br>
+ }<br>+ }<br>+<br>+<br>+ if ((writepos + oAdvance) > dsb->device->buflen)<br>+ {<br>+ TRACE("Device buffer not sample aligned (%p,%d,%d)\n",<br>+ dsb, dsb->device->buflen, oAdvance);<br>
+ writepos = 0;<br>+ }<br>+<br>+ bufptr = dsb->device->buffer + writepos;<br>+<br>+ for (chan = 0; chan < oChans; chan++)<br>+ {<br>+ if (chan >= iChans)<br>+ {<br>+ if (iChans > 1)<br>
+ break;<br>+ if (chan > 1)<br>+ break;<br>+<br>+ /* convert mono input to stereo output */<br>+ rsum[chan] = rsum[0];<br>+ }<br>+<br>+ putsample(bufptr, oBPS, rsum[chan] * amp[(chan < 2) ? chan : 2]);<br>
+<br>+ bufptr += oBPS;<br>+ }<br>+<br>+ /* advance pointers */<br>+ dsb->infrac += dsb->freq;<br>+ while (dsb->infrac >= dsb->outfreq)<br>+ {<br>+ dsb->infrac -= dsb->outfreq;<br>
+ dsb->inpos += iAdvance;<br>+ if (dsb->inpos >= dsb->buflen)<br>+ {<br>+ if (dsb->playflags & DSBPLAY_LOOPING)<br>+ dsb->inpos -= dsb->buflen;<br>+ else<br>+ {<br>
+ dsb->inpos = dsb->infrac = 0;<br>+ dsb->state = STATE_STOPPED;<br>+ }<br>+ }<br>+ }<br>+<br>+ writepos += oAdvance;<br>+ if (writepos >= dsb->device->buflen)<br>+ writepos -= dsb->device->buflen;<br>
+ }<br>+<br>+ return outlen;<br>+}<br>+<br>+<br>+/**<br>+ * Should be called when one of the following things occur:<br>+ * - Primary buffer format is changed<br>+ * - This buffer format (frequency) is changed<br>+ */<br>
+void DSOUND_RecalcFormat(IDirectSoundBufferImpl * dsb)<br>+{<br>+ int cnt;<br>+<br>+ for (cnt = 0; cnt <= ds_resample_quality; cnt++)<br>+ {<br>+ if (!g_fir[cnt])<br>+ break;<br>+ }<br>+ dsb->quality = cnt - 1;<br>
+<br>+ dsb->nAvgBytesPerSec = dsb->freq * dsb->pwfx->nBlockAlign;<br>+<br>+ dsb->outfreq = dsb->device->pwfx->nSamplesPerSec;<br>+ dsb->outfreq_1 = 1.0 / dsb->outfreq;<br>+<br>+ dsb->firstep = g_fir[dsb->quality]->step;<br>
+ if (dsb->outfreq < dsb->freq)<br>+ {<br>+ /* move transition band below output nuquist */<br>+ dsb->firstep = (9 * dsb->firstep * dsb->outfreq) / (10 * dsb->freq);<br>+ /*<br>+ * If firstep==0 the resample loop will hang.<br>
+ * Maybe it would be a better idea to return some error if downsample<br>+ * ratio is too high.<br>+ */<br>+ if (dsb->firstep < 1)<br>+ dsb->firstep = 1;<br>+ }<br>+ if (dsb->freq == dsb->outfreq)<br>
+ {<br>+ dsb->firstep = 1;<br>+ dsb->firdelay = 1;<br>+ }<br>+ else<br>+ dsb->firdelay = (2 * g_fir[dsb->quality]->size / dsb->firstep) + 1;<br>+<br>+ dsb->firdelay *= dsb->pwfx->nBlockAlign;<br>
+<br>+ dsb->infrac = 0;<br>+ dsb->inpos = dsb->firdelay;<br>+<br>+ TRACE("resample quality: %d\n", dsb->quality);<br>+ TRACE("resample firstep %d\n", dsb->firstep);<br>+ TRACE("resample firdelay %d\n", dsb->firdelay);<br>
+ TRACE("resample output: %d Hz, %d channels, %d bits\n",<br>+ dsb->outfreq, dsb->device->pwfx->nChannels,<br>+ dsb->device->pwfx->wBitsPerSample);<br>+}<br>-- <br>1.7.2.3<br>
<br><br>