Mercurial > sdl-ios-xcode
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; |