comparison src/audio/SDL_audiocvt.c @ 2661:d38309be5178 gsoc2008_audio_resampling

The windowed sinc filter generation code seems to be working fine. The FIR filtering code is also now working reasonably well. Occasionally the FIR filter will pop, but setting the normalization factor lower seems to help this. I suspect the problem is in the fixed point multiply/add. I also have a hunch the zero stuffing/sample discarding code is not correct, and I'll look at that soon to get it sorted out.
author Aaron Wishnick <schnarf@gmail.com>
date Wed, 02 Jul 2008 08:04:50 +0000
parents a55543cef395
children 5470680ca587
comparison
equal deleted inserted replaced
2660:a55543cef395 2661:d38309be5178
1528 static void SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { 1528 static void SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
1529 int n = 8 * cvt->len_cvt / SDL_AUDIO_BITSIZE(format); 1529 int n = 8 * cvt->len_cvt / SDL_AUDIO_BITSIZE(format);
1530 int m = cvt->len_sinc; 1530 int m = cvt->len_sinc;
1531 int i, j; 1531 int i, j;
1532 1532
1533 /* Note: this makes use of the symmetry of the sinc filter. 1533 /*
1534 We can also 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. 1536 significantly fewer multiplications and additions. However, this
1537 depends on the zero stuffing ratio, so it may not pay off.
1537 */ 1538 */
1538 #define filter_sinc(type, mult) { \ 1539 #define filter_sinc(type, mult) { \
1539 type *sinc = (type *)cvt->coeff; \ 1540 type *sinc = (type *)cvt->coeff; \
1540 type *state = (type *)cvt->state_buf; \ 1541 type *state = (type *)cvt->state_buf; \
1541 type *buf = (type *)cvt->buf; \ 1542 type *buf = (type *)cvt->buf; \
1542 for(i = 0; i < n; ++i) { \ 1543 for(i = 0; i < n; ++i) { \
1543 cvt->state_pos++; \
1544 if(cvt->state_pos >= m) cvt->state_pos = 0; \
1545 state[cvt->state_pos] = buf[i]; \ 1544 state[cvt->state_pos] = buf[i]; \
1546 buf[i] = 0; \ 1545 buf[i] = 0; \
1547 for(j = 0; j < m; ++j) { \ 1546 for(j = 0; j < m; ++j) { \
1548 buf[i] += mult(state[(cvt->state_pos - j) % m], sinc[j]); \ 1547 buf[i] += mult(sinc[j], state[(cvt->state_pos + j) % m]); \
1549 } \ 1548 } \
1549 cvt->state_pos = (cvt->state_pos + 1) % m; \
1550 } \ 1550 } \
1551 } 1551 }
1552 1552
1553 /* If it's floating point, do it normally, otherwise used fixed-point code */ 1553 /* If it's floating point, do it normally, otherwise used fixed-point code */
1554 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { 1554 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1555 float *sinc = (float *)cvt->coeff; 1555 float *sinc = (float *)cvt->coeff;
1556 float *state = (float *)cvt->state_buf; 1556 float *state = (float *)cvt->state_buf;
1557 float *buf = (float *)cvt->buf; 1557 float *buf = (float *)cvt->buf;
1558 1558
1559 for(i = 0; i < n; ++i) { 1559 for(i = 0; i < n; ++i) {
1560 state[cvt->state_pos++] = buf[i]; 1560 state[cvt->state_pos] = buf[i];
1561 if(cvt->state_pos == m) cvt->state_pos = 0;
1562 buf[i] = 0.0f; 1561 buf[i] = 0.0f;
1563 for(j = 0; j < m; ++j) { 1562 for(j = 0; j < m; ++j) {
1564 buf[i] += state[(cvt->state_pos - j) % m] * sinc[j]; 1563 buf[i] += sinc[j] * state[(cvt->state_pos + j) % m];
1565 } 1564 }
1565 cvt->state_pos = (cvt->state_pos + 1) % m;
1566 } 1566 }
1567 } else { 1567 } else {
1568 switch (SDL_AUDIO_BITSIZE(format)) { 1568 switch (SDL_AUDIO_BITSIZE(format)) {
1569 case 8: 1569 case 8:
1570 filter_sinc(Sint8, SDL_FixMpy8); 1570 filter_sinc(Sint8, SDL_FixMpy8);
1611 return -1; 1611 return -1;
1612 } 1612 }
1613 1613
1614 /* Set up the filter parameters */ 1614 /* 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; 1615 fc = (cvt->len_mult > cvt->len_div) ? 0.5f / (float)cvt->len_mult : 0.5f / (float)cvt->len_div;
1616 fc = 0.04f; 1616 #ifdef DEBUG_CONVERT
1617 printf("Lowpass cutoff frequency = %f\n", fc);
1618 #endif
1619 // fc = 0.02f;
1617 two_pi_fc = 2.0f * M_PI * fc; 1620 two_pi_fc = 2.0f * M_PI * fc;
1618 two_pi_over_m = 2.0f * M_PI / (float)m; 1621 two_pi_over_m = 2.0f * M_PI / (float)m;
1619 four_pi_over_m = 2.0f * two_pi_over_m; 1622 four_pi_over_m = 2.0f * two_pi_over_m;
1620 m_over_two = (float)m / 2.0f; 1623 m_over_two = (float)m / 2.0f;
1621 norm_sum = 0.0f; 1624 norm_sum = 0.0f;
1626 } else { 1629 } else {
1627 fSinc[i] = sinf(two_pi_fc * ((float)i - m_over_two)) / ((float)i - m_over_two); 1630 fSinc[i] = sinf(two_pi_fc * ((float)i - m_over_two)) / ((float)i - m_over_two);
1628 /* Apply blackman window */ 1631 /* Apply blackman window */
1629 fSinc[i] *= 0.42f - 0.5f * cosf(two_pi_over_m * (float)i) + 0.08f * cosf(four_pi_over_m * (float)i); 1632 fSinc[i] *= 0.42f - 0.5f * cosf(two_pi_over_m * (float)i) + 0.08f * cosf(four_pi_over_m * (float)i);
1630 } 1633 }
1631 fSinc[i] = 0.0f;
1632 norm_sum += fabs(fSinc[i]); 1634 norm_sum += fabs(fSinc[i]);
1633 printf("%f\n", fSinc[i]);
1634 } 1635 }
1635 1636
1636 #define convert_fixed(type, fix) { \ 1637 #define convert_fixed(type, fix) { \
1637 norm_fact = 0.8f / norm_sum; \ 1638 norm_fact = 0.7f / norm_sum; \
1638 type *dst = (type *)cvt->coeff; \ 1639 type *dst = (type *)cvt->coeff; \
1639 for( i = 0; i <= m; ++i ) { \ 1640 for( i = 0; i <= m; ++i ) { \
1640 dst[i] = fix(fSinc[i] * norm_fact); \ 1641 dst[i] = fix(fSinc[i] * norm_fact); \
1641 printf("%f = 0x%x\n", fSinc[i] * norm_fact, dst[i]); \
1642 } \ 1642 } \
1643 } 1643 }
1644 1644
1645 /* If we're using floating point, we only need to normalize */ 1645 /* If we're using floating point, we only need to normalize */
1646 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { 1646 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1662 break; 1662 break;
1663 } 1663 }
1664 } 1664 }
1665 1665
1666 /* Initialize the state buffer to all zeroes, and set initial position */ 1666 /* Initialize the state buffer to all zeroes, and set initial position */
1667 //memset(cvt->state_buf, 0, cvt->len_sinc * SDL_AUDIO_BITSIZE(format) / 4); 1667 memset(cvt->state_buf, 0, cvt->len_sinc * SDL_AUDIO_BITSIZE(format) / 4);
1668 cvt->state_pos = 0; 1668 cvt->state_pos = 0;
1669 1669
1670 /* Clean up */ 1670 /* Clean up */
1671 #undef convert_fixed 1671 #undef convert_fixed
1672 free(fSinc); 1672 free(fSinc);
1715 ++dst; \ 1715 ++dst; \
1716 } \ 1716 } \
1717 } 1717 }
1718 1718
1719 // Step 1: Zero stuff the conversion buffer 1719 // Step 1: Zero stuff the conversion buffer
1720 /*#ifdef DEBUG_CONVERT 1720 #ifdef DEBUG_CONVERT
1721 printf("Zero-stuffing by a factor of %u\n", cvt->len_mult); 1721 printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
1722 #endif 1722 #endif
1723 switch (SDL_AUDIO_BITSIZE(format)) { 1723 switch (SDL_AUDIO_BITSIZE(format)) {
1724 case 8: 1724 case 8:
1725 zerostuff_mono(Uint8); 1725 zerostuff_mono(Uint8);
1730 case 32: 1730 case 32:
1731 zerostuff_mono(Uint32); 1731 zerostuff_mono(Uint32);
1732 break; 1732 break;
1733 } 1733 }
1734 1734
1735 cvt->len_cvt *= cvt->len_mult;*/ 1735 cvt->len_cvt *= cvt->len_mult;
1736 1736
1737 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies 1737 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
1738 SDL_FilterFIR( cvt, format ); 1738 SDL_FilterFIR( cvt, format );
1739 1739
1740 // Step 3: Discard unnecessary samples 1740 // Step 3: Discard unnecessary samples
1741 /*#ifdef DEBUG_CONVERT 1741 #ifdef DEBUG_CONVERT
1742 printf("Discarding samples by a factor of %u\n", cvt->len_div); 1742 printf("Discarding samples by a factor of %u\n", cvt->len_div);
1743 #endif 1743 #endif
1744 switch (SDL_AUDIO_BITSIZE(format)) { 1744 switch (SDL_AUDIO_BITSIZE(format)) {
1745 case 8: 1745 case 8:
1746 discard_mono(Uint8); 1746 discard_mono(Uint8);
1754 } 1754 }
1755 1755
1756 #undef zerostuff_mono 1756 #undef zerostuff_mono
1757 #undef discard_mono 1757 #undef discard_mono
1758 1758
1759 cvt->len_cvt /= cvt->len_div;*/ 1759 cvt->len_cvt /= cvt->len_div;
1760 1760
1761 if (cvt->filters[++cvt->filter_index]) { 1761 if (cvt->filters[++cvt->filter_index]) {
1762 cvt->filters[cvt->filter_index] (cvt, format); 1762 cvt->filters[cvt->filter_index] (cvt, format);
1763 } 1763 }
1764 } 1764 }
1857 cvt->len_mult = dst_rate / rate_gcd; 1857 cvt->len_mult = dst_rate / rate_gcd;
1858 cvt->len_div = src_rate / rate_gcd; 1858 cvt->len_div = src_rate / rate_gcd;
1859 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div; 1859 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
1860 cvt->filters[cvt->filter_index++] = SDL_Resample; 1860 cvt->filters[cvt->filter_index++] = SDL_Resample;
1861 //SDL_BuildIIRLowpass(cvt, dst_fmt); 1861 //SDL_BuildIIRLowpass(cvt, dst_fmt);
1862 SDL_BuildWindowedSinc(cvt, dst_fmt, 12); 1862 SDL_BuildWindowedSinc(cvt, dst_fmt, 20);
1863 1863
1864 /*cvt->rate_incr = 0.0; 1864 /*cvt->rate_incr = 0.0;
1865 if ((src_rate / 100) != (dst_rate / 100)) { 1865 if ((src_rate / 100) != (dst_rate / 100)) {
1866 Uint32 hi_rate, lo_rate; 1866 Uint32 hi_rate, lo_rate;
1867 int len_mult; 1867 int len_mult;