/// <summary> /// sets the mode /// if sinc set, it overrides interp or filtercnt /// </summary> public void SetMode(bool interp, int filtercnt, bool sinc, int sinc_size = 64, int sinc_interpsize = 32) { m_sincsize = sinc && sinc_size >= 4 ? sinc_size > 8192 ? 8192 : sinc_size : 0; m_sincoversize = m_sincsize != 0 ? (sinc_interpsize <= 1 ? 1 : sinc_interpsize >= 4096 ? 4096 : sinc_interpsize) : 1; m_filtercnt = m_sincsize != 0 ? 0 : (filtercnt <= 0 ? 0 : filtercnt >= WDL_RESAMPLE_MAX_FILTERS ? WDL_RESAMPLE_MAX_FILTERS : filtercnt); m_interp = interp && m_sincsize == 0; //Debug.WriteLine(String.Format("setting interp={0}, filtercnt={1}, sinc={2},{3}\n", m_interp, m_filtercnt, m_sincsize, m_sincoversize)); if (m_sincsize == 0) { m_filter_coeffs = new float[0]; //.Resize(0); m_filter_coeffs_size = 0; } if (m_filtercnt == 0) { m_iirfilter = null; } }
// if numsamples_in < the value return by ResamplePrepare(), then it will be flushed to produce all remaining valid samples // do NOT call with nsamples_in greater than the value returned from resamplerprpare()! the extra samples will be ignored. // returns number of samples successfully outputted to out public int ResampleOut(WDL_ResampleSample[] outBuffer, int outBufferIndex, int nsamples_in, int nsamples_out, int nch) { if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) { return(0); } if (m_filtercnt > 0) { if (m_ratio > 1.0 && nsamples_in > 0) // filter input { if (m_iirfilter == null) { m_iirfilter = new WDL_Resampler_IIRFilter(); } int n = m_filtercnt; m_iirfilter.setParms((1.0 / m_ratio) * m_filterpos, m_filterq); int bufIndex = m_samples_in_rsinbuf * nch; int a, x; int offs = 0; for (x = 0; x < nch; x++) { for (a = 0; a < n; a++) { m_iirfilter.Apply(m_rsinbuf, bufIndex + x, m_rsinbuf, bufIndex + x, nsamples_in, nch, offs++); } } } } m_samples_in_rsinbuf += Math.Min(nsamples_in, m_last_requested); // prevent the user from corrupting the internal state int rsinbuf_availtemp = m_samples_in_rsinbuf; if (nsamples_in < m_last_requested) // flush out to ensure we can deliver { int fsize = (m_last_requested - nsamples_in) * 2 + m_sincsize * 2; int alloc_size = (m_samples_in_rsinbuf + fsize) * nch; Array.Resize(ref m_rsinbuf, alloc_size); if (m_rsinbuf.Length == alloc_size) { Array.Clear(m_rsinbuf, m_samples_in_rsinbuf * nch, fsize * nch); rsinbuf_availtemp = m_samples_in_rsinbuf + fsize; } } int ret = 0; double srcpos = m_fracpos; double drspos = m_ratio; int localin = 0; // localin is an index into m_rsinbuf int outptr = outBufferIndex; // outptr is an index into outBuffer; int ns = nsamples_out; int outlatadj = 0; if (m_sincsize != 0) // sinc interpolating { if (m_ratio > 1.0) { BuildLowPass(1.0 / (m_ratio * 1.03)); } else { BuildLowPass(1.0); } int filtsz = m_filter_coeffs_size; int filtlen = rsinbuf_availtemp - filtsz; outlatadj = filtsz / 2 - 1; int filter = 0; // filter is an index into m_filter_coeffs m_filter_coeffs.Get(); if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) { break; // quit decoding, not enough input samples } SincSample1(outBuffer, outptr, m_rsinbuf, localin + ipos, srcpos - ipos, m_filter_coeffs, filter, filtsz); outptr++; srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) { break; // quit decoding, not enough input samples } SincSample2(outBuffer, outptr, m_rsinbuf, localin + ipos * 2, srcpos - ipos, m_filter_coeffs, filter, filtsz); outptr += 2; srcpos += drspos; ret++; } } else { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) { break; // quit decoding, not enough input samples } SincSample(outBuffer, outptr, m_rsinbuf, localin + ipos * nch, srcpos - ipos, nch, m_filter_coeffs, filter, filtsz); outptr += nch; srcpos += drspos; ret++; } } } else if (!m_interp) // point sampling { if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) { break; // quit decoding, not enough input samples } outBuffer[outptr++] = m_rsinbuf[localin + ipos]; srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) { break; // quit decoding, not enough input samples } ipos += ipos; outBuffer[outptr + 0] = m_rsinbuf[localin + ipos]; outBuffer[outptr + 1] = m_rsinbuf[localin + ipos + 1]; outptr += 2; srcpos += drspos; ret++; } } else { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) { break; // quit decoding, not enough input samples } Array.Copy(m_rsinbuf, localin + ipos * nch, outBuffer, outptr, nch); outptr += nch; srcpos += drspos; ret++; } } } else // linear interpolation { if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int inptr = localin + ipos; outBuffer[outptr++] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + 1] * (fracpos)); srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int inptr = localin + ipos * 2; outBuffer[outptr + 0] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + 2] * (fracpos)); outBuffer[outptr + 1] = (WDL_ResampleSample)(m_rsinbuf[inptr + 1] * (ifracpos) + m_rsinbuf[inptr + 3] * (fracpos)); outptr += 2; srcpos += drspos; ret++; } } else { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int ch = nch; int inptr = localin + ipos * nch; while (ch-- != 0) { outBuffer[outptr++] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + nch] * (fracpos)); inptr++; } srcpos += drspos; ret++; } } } if (m_filtercnt > 0) { if (m_ratio < 1.0 && ret > 0) // filter output { if (m_iirfilter == null) { m_iirfilter = new WDL_Resampler_IIRFilter(); } int n = m_filtercnt; m_iirfilter.setParms(m_ratio * m_filterpos, m_filterq); int x, a; int offs = 0; for (x = 0; x < nch; x++) { for (a = 0; a < n; a++) { m_iirfilter.Apply(outBuffer, x, outBuffer, x, ret, nch, offs++); } } } } if (ret > 0 && rsinbuf_availtemp > m_samples_in_rsinbuf) // we had to pad!! { // check for the case where rsinbuf_availtemp>m_samples_in_rsinbuf, decrease ret down to actual valid samples double adj = (srcpos - m_samples_in_rsinbuf + outlatadj) / drspos; if (adj > 0) { ret -= (int)(adj + 0.5); if (ret < 0) { ret = 0; } } } int isrcpos = (int)srcpos; m_fracpos = srcpos - isrcpos; m_samples_in_rsinbuf -= isrcpos; if (m_samples_in_rsinbuf <= 0) { m_samples_in_rsinbuf = 0; } else { // TODO: bug here Array.Copy(m_rsinbuf, localin + isrcpos * nch, m_rsinbuf, localin, m_samples_in_rsinbuf * nch); } return(ret); }
// if numsamples_in < the value return by ResamplePrepare(), then it will be flushed to produce all remaining valid samples // do NOT call with nsamples_in greater than the value returned from resamplerprpare()! the extra samples will be ignored. // returns number of samples successfully outputted to out public int ResampleOut(WDL_ResampleSample[] outBuffer, int outBufferIndex, int nsamples_in, int nsamples_out, int nch) { if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) { return 0; } if (m_filtercnt > 0) { if (m_ratio > 1.0 && nsamples_in > 0) // filter input { if (m_iirfilter == null) m_iirfilter = new WDL_Resampler_IIRFilter(); int n = m_filtercnt; m_iirfilter.setParms((1.0 / m_ratio) * m_filterpos, m_filterq); int bufIndex = m_samples_in_rsinbuf * nch; int a, x; int offs = 0; for (x = 0; x < nch; x++) for (a = 0; a < n; a++) m_iirfilter.Apply(m_rsinbuf, bufIndex + x, m_rsinbuf, bufIndex + x, nsamples_in, nch, offs++); } } m_samples_in_rsinbuf += Math.Min(nsamples_in, m_last_requested); // prevent the user from corrupting the internal state int rsinbuf_availtemp = m_samples_in_rsinbuf; if (nsamples_in < m_last_requested) // flush out to ensure we can deliver { int fsize = (m_last_requested - nsamples_in) * 2 + m_sincsize * 2; int alloc_size = (m_samples_in_rsinbuf + fsize) * nch; Array.Resize(ref m_rsinbuf, alloc_size); if (m_rsinbuf.Length == alloc_size) { Array.Clear(m_rsinbuf, m_samples_in_rsinbuf * nch, fsize * nch); rsinbuf_availtemp = m_samples_in_rsinbuf + fsize; } } int ret = 0; double srcpos = m_fracpos; double drspos = m_ratio; int localin = 0; // localin is an index into m_rsinbuf int outptr = outBufferIndex; // outptr is an index into outBuffer; int ns = nsamples_out; int outlatadj = 0; if (m_sincsize != 0) // sinc interpolating { if (m_ratio > 1.0) BuildLowPass(1.0 / (m_ratio * 1.03)); else BuildLowPass(1.0); int filtsz = m_filter_coeffs_size; int filtlen = rsinbuf_availtemp - filtsz; outlatadj = filtsz / 2 - 1; int filter = 0; // filter is an index into m_filter_coeffs m_filter_coeffs.Get(); if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) break; // quit decoding, not enough input samples SincSample1(outBuffer, outptr, m_rsinbuf, localin + ipos, srcpos - ipos, m_filter_coeffs, filter, filtsz); outptr++; srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) break; // quit decoding, not enough input samples SincSample2(outBuffer, outptr, m_rsinbuf, localin + ipos * 2, srcpos - ipos, m_filter_coeffs, filter, filtsz); outptr += 2; srcpos += drspos; ret++; } } else { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= filtlen - 1) break; // quit decoding, not enough input samples SincSample(outBuffer, outptr, m_rsinbuf, localin + ipos * nch, srcpos - ipos, nch, m_filter_coeffs, filter, filtsz); outptr += nch; srcpos += drspos; ret++; } } } else if (!m_interp) // point sampling { if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples outBuffer[outptr++] = m_rsinbuf[localin + ipos]; srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples ipos += ipos; outBuffer[outptr + 0] = m_rsinbuf[localin + ipos]; outBuffer[outptr + 1] = m_rsinbuf[localin + ipos + 1]; outptr += 2; srcpos += drspos; ret++; } } else while (ns-- != 0) { int ipos = (int)srcpos; if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples Array.Copy(m_rsinbuf, localin + ipos * nch, outBuffer, outptr, nch); outptr += nch; srcpos += drspos; ret++; } } else // linear interpolation { if (nch == 1) { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int inptr = localin + ipos; outBuffer[outptr++] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + 1] * (fracpos)); srcpos += drspos; ret++; } } else if (nch == 2) { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int inptr = localin + ipos * 2; outBuffer[outptr + 0] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + 2] * (fracpos)); outBuffer[outptr + 1] = (WDL_ResampleSample)(m_rsinbuf[inptr + 1] * (ifracpos) + m_rsinbuf[inptr + 3] * (fracpos)); outptr += 2; srcpos += drspos; ret++; } } else { while (ns-- != 0) { int ipos = (int)srcpos; double fracpos = srcpos - ipos; if (ipos >= rsinbuf_availtemp - 1) { break; // quit decoding, not enough input samples } double ifracpos = 1.0 - fracpos; int ch = nch; int inptr = localin + ipos * nch; while (ch-- != 0) { outBuffer[outptr++] = (WDL_ResampleSample)(m_rsinbuf[inptr] * (ifracpos) + m_rsinbuf[inptr + nch] * (fracpos)); inptr++; } srcpos += drspos; ret++; } } } if (m_filtercnt > 0) { if (m_ratio < 1.0 && ret > 0) // filter output { if (m_iirfilter == null) m_iirfilter = new WDL_Resampler_IIRFilter(); int n = m_filtercnt; m_iirfilter.setParms(m_ratio * m_filterpos, m_filterq); int x, a; int offs = 0; for (x = 0; x < nch; x++) for (a = 0; a < n; a++) m_iirfilter.Apply(outBuffer, x, outBuffer, x, ret, nch, offs++); } } if (ret > 0 && rsinbuf_availtemp > m_samples_in_rsinbuf) // we had to pad!! { // check for the case where rsinbuf_availtemp>m_samples_in_rsinbuf, decrease ret down to actual valid samples double adj = (srcpos - m_samples_in_rsinbuf + outlatadj) / drspos; if (adj > 0) { ret -= (int)(adj + 0.5); if (ret < 0) ret = 0; } } int isrcpos = (int)srcpos; m_fracpos = srcpos - isrcpos; m_samples_in_rsinbuf -= isrcpos; if (m_samples_in_rsinbuf <= 0) { m_samples_in_rsinbuf = 0; } else { // TODO: bug here Array.Copy(m_rsinbuf, localin + isrcpos * nch, m_rsinbuf, localin, m_samples_in_rsinbuf * nch); } return ret; }
/// <summary> /// sets the mode /// if sinc set, it overrides interp or filtercnt /// </summary> public void SetMode(bool interp, int filtercnt, bool sinc, int sinc_size = 64, int sinc_interpsize = 32) { m_sincsize = sinc && sinc_size >= 4 ? sinc_size > 8192 ? 8192 : sinc_size : 0; m_sincoversize = (m_sincsize != 0) ? (sinc_interpsize <= 1 ? 1 : sinc_interpsize >= 4096 ? 4096 : sinc_interpsize) : 1; m_filtercnt = (m_sincsize != 0) ? 0 : (filtercnt <= 0 ? 0 : filtercnt >= WDL_RESAMPLE_MAX_FILTERS ? WDL_RESAMPLE_MAX_FILTERS : filtercnt); m_interp = interp && (m_sincsize == 0); //Debug.WriteLine(String.Format("setting interp={0}, filtercnt={1}, sinc={2},{3}\n", m_interp, m_filtercnt, m_sincsize, m_sincoversize)); if (m_sincsize == 0) { m_filter_coeffs = new WDL_SincFilterSample[0]; //.Resize(0); m_filter_coeffs_size = 0; } if (m_filtercnt == 0) { m_iirfilter = null; } }