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 &lt;stdarg.h&gt;<br>+#include &lt;math.h&gt;<br>+<br>+#define NONAMELESSSTRUCT<br>+#define NONAMELESSUNION<br>+#include &quot;windef.h&quot;<br>
+#include &quot;winbase.h&quot;<br>+#include &quot;mmsystem.h&quot;<br>+#include &quot;winternl.h&quot;<br>+#include &quot;wine/debug.h&quot;<br>+#include &quot;dsound.h&quot;<br>+#include &quot;dsdriver.h&quot;<br>+#include &quot;dsound_private.h&quot;<br>
+<br>+#include &quot;firtab.h&quot;<br>+<br>+WINE_DEFAULT_DEBUG_CHANNEL(dsound);<br>+<br>+<br>+#define MAXCHAN 16<br>+<br>+#define CLIPSAMPLE(x,max) if(x&gt;max)x=max;if(x&lt;-max)x=-max;<br>+#define SAMPLE24(p) (*((BYTE*)p)|*((BYTE*)p+1)&lt;&lt;8|*((CHAR*)p+2)&lt;&lt;16)<br>
+#ifdef WORDS_BIGENDIAN<br>+#define SAMPLE16(p) (*((BYTE*)p)|*((CHAR*)p+1)&lt;&lt;8)<br>+#define PUT16(p,s) *((BYTE*)p)=s;*((BYTE*)p+1)=(s&gt;&gt;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>+  &amp;firfast,<br>+  &amp;firgood,<br>+  &amp;firbest,<br>+  &amp;firslow,<br>+#if RESAMPLE_INSANE<br>+  &amp;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 &amp; 0xff;<br>+    ismp &gt;&gt;= 8;<br>
+    *((BYTE *) buf + 1) = ismp &amp; 0xff;<br>+    ismp &gt;&gt;= 8;<br>+    *((BYTE *) buf + 2) = ismp &amp; 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>
+ * &#39;writepos&#39; and &#39;mixlen&#39; 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-&gt;quality];<br>+<br>+  iAdvance = dsb-&gt;pwfx-&gt;nBlockAlign;<br>
+  oAdvance = dsb-&gt;device-&gt;pwfx-&gt;nBlockAlign;<br>+  iBPS = dsb-&gt;pwfx-&gt;wBitsPerSample &gt;&gt; 3;<br>+  oBPS = dsb-&gt;device-&gt;pwfx-&gt;wBitsPerSample &gt;&gt; 3;<br>+  outlen = 0;<br>+  iChans = dsb-&gt;pwfx-&gt;nChannels;<br>
+  oChans = dsb-&gt;device-&gt;pwfx-&gt;nChannels;<br>+<br>+  if (iChans &gt;= MAXCHAN)<br>+    iChans = MAXCHAN - 1;<br>+  if (oChans &gt;= MAXCHAN)<br>+    oChans = MAXCHAN - 1;<br>+<br>+  firstep = dsb-&gt;firstep;<br>
+<br>+  amp[0] = (DOUBLE) dsb-&gt;volpan.dwTotalLeftAmpFactor<br>+    * ((DOUBLE) firstep / 65536.0);<br>+  if (oChans &gt; 1)<br>+  {<br>+    amp[1] = (DOUBLE) dsb-&gt;volpan.dwTotalRightAmpFactor<br>+      * ((DOUBLE) firstep / 65536.0);<br>
+    if (oChans &gt; 2)<br>+      amp[2] = (DOUBLE) dsb-&gt;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 &gt; mixlen)<br>+    {<br>+      outlen -= oAdvance;<br>+      break;<br>+    }<br>+<br>+    if ((dsb-&gt;inpos + iAdvance) &gt; dsb-&gt;buflen)<br>+    {<br>+      TRACE(&quot;Buffer not sample aligned (%p,%d,%d)\n&quot;,<br>
+            dsb, dsb-&gt;buflen, iAdvance);<br>+      dsb-&gt;inpos = 0;<br>+    }<br>+<br>+    bufptr = dsb-&gt;buffer-&gt;memory + dsb-&gt;inpos;<br>+<br>+    if (dsb-&gt;freq != dsb-&gt;outfreq)<br>+    {<br>+      firpos = (double) fir-&gt;size - 1<br>
+        - ((double) firstep * dsb-&gt;infrac * dsb-&gt;outfreq_1);<br>+<br>+      firfrac = firpos - floor(firpos);<br>+      firpos_i = firpos;<br>+<br>+      for (chan = 0; chan &lt; iChans; chan++)<br>+        rsum[chan] = 0.0;<br>
+<br>+      /* right wing */<br>+      while (firpos_i &gt;= 0)<br>+      {<br>+        for (chan = iChans - 1; chan &gt;= 0; chan--)<br>+        {<br>+          bufptr -= iBPS;<br>+          if (bufptr &lt; dsb-&gt;buffer-&gt;memory)<br>
+            bufptr += dsb-&gt;buflen;<br>+<br>+          smp[chan] = getsample(bufptr, iBPS);<br>+        }<br>+<br>+        ifir = (1.0 - firfrac) * fir-&gt;wing[firpos_i]<br>+          + firfrac * fir-&gt;wing[firpos_i + 1];<br>
+<br>+        for (chan = 0; chan &lt; 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 &gt; 0.0)<br>
+      {<br>+        firfrac = 1.0 - firfrac;<br>+        firpos_i--;<br>+      }<br>+<br>+      while (firpos_i &lt; (fir-&gt;size - 1))<br>+      {<br>+        for (chan = iChans - 1; chan &gt;= 0; chan--)<br>+        {<br>
+          bufptr -= iBPS;<br>+          if (bufptr &lt; dsb-&gt;buffer-&gt;memory)<br>+            bufptr += dsb-&gt;buflen;<br>+<br>+          smp[chan] = getsample(bufptr, iBPS);<br>+        }<br>+<br>+        ifir = (1.0 - firfrac) * fir-&gt;wing[firpos_i]<br>
+          + firfrac * fir-&gt;wing[firpos_i + 1];<br>+<br>+        for (chan = 0; chan &lt; iChans; chan++)<br>+          rsum[chan] += ifir * smp[chan];<br>+<br>+        firpos_i += firstep;<br>+      }<br>+    }<br>+    else<br>
+    {<br>+      for (chan = iChans - 1; chan &gt;= 0; chan--)<br>+      {<br>+        bufptr -= iBPS;<br>+        if (bufptr &lt; dsb-&gt;buffer-&gt;memory)<br>+          bufptr += dsb-&gt;buflen;<br>+<br>+        rsum[chan] = getsample(bufptr, iBPS);<br>
+      }<br>+    }<br>+<br>+<br>+    if ((writepos + oAdvance) &gt; dsb-&gt;device-&gt;buflen)<br>+    {<br>+      TRACE(&quot;Device buffer not sample aligned (%p,%d,%d)\n&quot;,<br>+            dsb, dsb-&gt;device-&gt;buflen, oAdvance);<br>
+      writepos = 0;<br>+    }<br>+<br>+    bufptr = dsb-&gt;device-&gt;buffer + writepos;<br>+<br>+    for (chan = 0; chan &lt; oChans; chan++)<br>+    {<br>+      if (chan &gt;= iChans)<br>+      {<br>+        if (iChans &gt; 1)<br>
+          break;<br>+        if (chan &gt; 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 &lt; 2) ? chan : 2]);<br>
+<br>+      bufptr += oBPS;<br>+    }<br>+<br>+    /* advance pointers */<br>+    dsb-&gt;infrac += dsb-&gt;freq;<br>+    while (dsb-&gt;infrac &gt;= dsb-&gt;outfreq)<br>+    {<br>+      dsb-&gt;infrac -= dsb-&gt;outfreq;<br>
+      dsb-&gt;inpos += iAdvance;<br>+      if (dsb-&gt;inpos &gt;= dsb-&gt;buflen)<br>+      {<br>+        if (dsb-&gt;playflags &amp; DSBPLAY_LOOPING)<br>+          dsb-&gt;inpos -= dsb-&gt;buflen;<br>+        else<br>+        {<br>
+          dsb-&gt;inpos = dsb-&gt;infrac = 0;<br>+          dsb-&gt;state = STATE_STOPPED;<br>+        }<br>+      }<br>+    }<br>+<br>+    writepos += oAdvance;<br>+    if (writepos &gt;= dsb-&gt;device-&gt;buflen)<br>+      writepos -= dsb-&gt;device-&gt;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 &lt;= ds_resample_quality; cnt++)<br>+  {<br>+    if (!g_fir[cnt])<br>+      break;<br>+  }<br>+  dsb-&gt;quality = cnt - 1;<br>
+<br>+  dsb-&gt;nAvgBytesPerSec = dsb-&gt;freq * dsb-&gt;pwfx-&gt;nBlockAlign;<br>+<br>+  dsb-&gt;outfreq = dsb-&gt;device-&gt;pwfx-&gt;nSamplesPerSec;<br>+  dsb-&gt;outfreq_1 = 1.0 / dsb-&gt;outfreq;<br>+<br>+  dsb-&gt;firstep = g_fir[dsb-&gt;quality]-&gt;step;<br>
+  if (dsb-&gt;outfreq &lt; dsb-&gt;freq)<br>+  {<br>+    /* move transition band below output nuquist */<br>+    dsb-&gt;firstep = (9 * dsb-&gt;firstep * dsb-&gt;outfreq) / (10 * dsb-&gt;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-&gt;firstep &lt; 1)<br>+      dsb-&gt;firstep = 1;<br>+  }<br>+  if (dsb-&gt;freq == dsb-&gt;outfreq)<br>
+  {<br>+    dsb-&gt;firstep = 1;<br>+    dsb-&gt;firdelay = 1;<br>+  }<br>+  else<br>+    dsb-&gt;firdelay = (2 * g_fir[dsb-&gt;quality]-&gt;size / dsb-&gt;firstep) + 1;<br>+<br>+  dsb-&gt;firdelay *= dsb-&gt;pwfx-&gt;nBlockAlign;<br>
+<br>+  dsb-&gt;infrac = 0;<br>+  dsb-&gt;inpos = dsb-&gt;firdelay;<br>+<br>+  TRACE(&quot;resample quality: %d\n&quot;, dsb-&gt;quality);<br>+  TRACE(&quot;resample firstep %d\n&quot;, dsb-&gt;firstep);<br>+  TRACE(&quot;resample firdelay %d\n&quot;, dsb-&gt;firdelay);<br>
+  TRACE(&quot;resample output: %d Hz, %d channels, %d bits\n&quot;,<br>+        dsb-&gt;outfreq, dsb-&gt;device-&gt;pwfx-&gt;nChannels,<br>+        dsb-&gt;device-&gt;pwfx-&gt;wBitsPerSample);<br>+}<br>-- <br>1.7.2.3<br>
<br><br>