comparison src/audio/SDL_audiocvt.c @ 2662:5470680ca587 gsoc2008_audio_resampling

Made a very significant optimization to the FIR filter which I believe I can take a little further. Right now the FIR filter size is 768 and I get some free() bugs, so this is something I need to debug.
author Aaron Wishnick <schnarf@gmail.com>
date Thu, 10 Jul 2008 07:02:18 +0000
parents d38309be5178
children 0caed045d01b
comparison
equal deleted inserted replaced
2661:d38309be5178 2662:5470680ca587
1534 Note: We can make a big optimization here by taking advantage 1534 Note: We can make a big optimization here by taking advantage
1535 of the fact that the signal is zero stuffed, so we can do 1535 of the fact that the signal is zero stuffed, so we can do
1536 significantly fewer multiplications and additions. However, this 1536 significantly fewer multiplications and additions. However, this
1537 depends on the zero stuffing ratio, so it may not pay off. 1537 depends on the zero stuffing ratio, so it may not pay off.
1538 */ 1538 */
1539 /* We only calculate the values of samples which are 0 (mod len_div) because those are the only ones used */
1539 #define filter_sinc(type, mult) { \ 1540 #define filter_sinc(type, mult) { \
1540 type *sinc = (type *)cvt->coeff; \ 1541 type *sinc = (type *)cvt->coeff; \
1541 type *state = (type *)cvt->state_buf; \ 1542 type *state = (type *)cvt->state_buf; \
1542 type *buf = (type *)cvt->buf; \ 1543 type *buf = (type *)cvt->buf; \
1543 for(i = 0; i < n; ++i) { \ 1544 for(i = 0; i < n; ++i) { \
1544 state[cvt->state_pos] = buf[i]; \ 1545 state[cvt->state_pos] = buf[i]; \
1545 buf[i] = 0; \ 1546 buf[i] = 0; \
1546 for(j = 0; j < m; ++j) { \ 1547 if( i % cvt->len_div == 0 ) { \
1547 buf[i] += mult(sinc[j], state[(cvt->state_pos + j) % m]); \ 1548 for(j = 0; j < m; ++j) { \
1548 } \ 1549 buf[i] += mult(sinc[j], state[(cvt->state_pos + j) % m]); \
1550 } \
1551 }\
1549 cvt->state_pos = (cvt->state_pos + 1) % m; \ 1552 cvt->state_pos = (cvt->state_pos + 1) % m; \
1550 } \ 1553 } \
1551 } 1554 }
1552 1555
1553 /* If it's floating point, do it normally, otherwise used fixed-point code */ 1556 /* If it's floating point, do it normally, otherwise used fixed-point code */
1614 /* Set up the filter parameters */ 1617 /* Set up the filter parameters */
1615 fc = (cvt->len_mult > cvt->len_div) ? 0.5f / (float)cvt->len_mult : 0.5f / (float)cvt->len_div; 1618 fc = (cvt->len_mult > cvt->len_div) ? 0.5f / (float)cvt->len_mult : 0.5f / (float)cvt->len_div;
1616 #ifdef DEBUG_CONVERT 1619 #ifdef DEBUG_CONVERT
1617 printf("Lowpass cutoff frequency = %f\n", fc); 1620 printf("Lowpass cutoff frequency = %f\n", fc);
1618 #endif 1621 #endif
1619 // fc = 0.02f;
1620 two_pi_fc = 2.0f * M_PI * fc; 1622 two_pi_fc = 2.0f * M_PI * fc;
1621 two_pi_over_m = 2.0f * M_PI / (float)m; 1623 two_pi_over_m = 2.0f * M_PI / (float)m;
1622 four_pi_over_m = 2.0f * two_pi_over_m; 1624 four_pi_over_m = 2.0f * two_pi_over_m;
1623 m_over_two = (float)m / 2.0f; 1625 m_over_two = (float)m / 2.0f;
1624 norm_sum = 0.0f; 1626 norm_sum = 0.0f;
1633 } 1635 }
1634 norm_sum += fabs(fSinc[i]); 1636 norm_sum += fabs(fSinc[i]);
1635 } 1637 }
1636 1638
1637 #define convert_fixed(type, fix) { \ 1639 #define convert_fixed(type, fix) { \
1638 norm_fact = 0.7f / norm_sum; \ 1640 norm_fact = 0.5f / norm_sum; \
1639 type *dst = (type *)cvt->coeff; \ 1641 type *dst = (type *)cvt->coeff; \
1640 for( i = 0; i <= m; ++i ) { \ 1642 for( i = 0; i <= m; ++i ) { \
1641 dst[i] = fix(fSinc[i] * norm_fact); \ 1643 dst[i] = fix(fSinc[i] * norm_fact); \
1642 } \ 1644 } \
1643 } 1645 }
1707 } 1709 }
1708 1710
1709 #define discard_mono(type) { \ 1711 #define discard_mono(type) { \
1710 const type *src = (const type *) (cvt->buf); \ 1712 const type *src = (const type *) (cvt->buf); \
1711 type *dst = (type *) (cvt->buf); \ 1713 type *dst = (type *) (cvt->buf); \
1712 for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \ 1714 for (i = 0; i < (cvt->len_cvt / sizeof(type)) / cvt->len_div; ++i) { \
1713 dst[0] = src[0]; \ 1715 dst[0] = src[0]; \
1714 src += cvt->len_div; \ 1716 src += cvt->len_div; \
1715 ++dst; \ 1717 ++dst; \
1716 } \ 1718 } \
1717 } 1719 }
1733 } 1735 }
1734 1736
1735 cvt->len_cvt *= cvt->len_mult; 1737 cvt->len_cvt *= cvt->len_mult;
1736 1738
1737 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies 1739 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
1738 SDL_FilterFIR( cvt, format ); 1740 QSDL_FilterFIR( cvt, format );
1741
1742 // OPTIMIZATION: we only need to calculate the non-discarded samples. This could be a big speedup!
1739 1743
1740 // Step 3: Discard unnecessary samples 1744 // Step 3: Discard unnecessary samples
1745
1741 #ifdef DEBUG_CONVERT 1746 #ifdef DEBUG_CONVERT
1742 printf("Discarding samples by a factor of %u\n", cvt->len_div); 1747 printf("Discarding samples by a factor of %u\n", cvt->len_div);
1743 #endif 1748 #endif
1744 switch (SDL_AUDIO_BITSIZE(format)) { 1749 switch (SDL_AUDIO_BITSIZE(format)) {
1745 case 8: 1750 case 8:
1857 cvt->len_mult = dst_rate / rate_gcd; 1862 cvt->len_mult = dst_rate / rate_gcd;
1858 cvt->len_div = src_rate / rate_gcd; 1863 cvt->len_div = src_rate / rate_gcd;
1859 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div; 1864 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
1860 cvt->filters[cvt->filter_index++] = SDL_Resample; 1865 cvt->filters[cvt->filter_index++] = SDL_Resample;
1861 //SDL_BuildIIRLowpass(cvt, dst_fmt); 1866 //SDL_BuildIIRLowpass(cvt, dst_fmt);
1862 SDL_BuildWindowedSinc(cvt, dst_fmt, 20); 1867 SDL_BuildWindowedSinc(cvt, dst_fmt, 768);
1863 1868
1864 /*cvt->rate_incr = 0.0; 1869 /*cvt->rate_incr = 0.0;
1865 if ((src_rate / 100) != (dst_rate / 100)) { 1870 if ((src_rate / 100) != (dst_rate / 100)) {
1866 Uint32 hi_rate, lo_rate; 1871 Uint32 hi_rate, lo_rate;
1867 int len_mult; 1872 int len_mult;