Mercurial > sdl-ios-xcode
comparison src/audio/SDL_audiocvt.c @ 2656:dd74182b3c3c gsoc2008_audio_resampling
Began implementing IIR and FIR filters, and got zero stuffing and sample discarding working.
author | Aaron Wishnick <schnarf@gmail.com> |
---|---|
date | Wed, 18 Jun 2008 18:55:50 +0000 |
parents | b8e736c8a5a8 |
children | 29306e52dab8 |
comparison
equal
deleted
inserted
replaced
2655:b8e736c8a5a8 | 2656:dd74182b3c3c |
---|---|
24 | 24 |
25 /* Functions for audio drivers to perform runtime conversion of audio format */ | 25 /* Functions for audio drivers to perform runtime conversion of audio format */ |
26 | 26 |
27 #include "SDL_audio.h" | 27 #include "SDL_audio.h" |
28 #include "SDL_audio_c.h" | 28 #include "SDL_audio_c.h" |
29 | |
30 #define DEBUG_CONVERT | |
29 | 31 |
30 /* Effectively mix right and left channels into a single channel */ | 32 /* Effectively mix right and left channels into a single channel */ |
31 static void SDLCALL | 33 static void SDLCALL |
32 SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) | 34 SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) |
33 { | 35 { |
1235 SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format) | 1237 SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format) |
1236 { | 1238 { |
1237 int i, j; | 1239 int i, j; |
1238 | 1240 |
1239 #ifdef DEBUG_CONVERT | 1241 #ifdef DEBUG_CONVERT |
1240 fprintf(stderr, "Converting audio rate via proper resampling (mono)\n"); | 1242 printf("Converting audio rate via proper resampling (mono)\n"); |
1241 #endif | 1243 #endif |
1242 | 1244 |
1243 #define zerostuff_mono(type) { \ | 1245 #define zerostuff_mono(type) { \ |
1244 const type *src = (const type *) (cvt->buf + cvt->len_cvt); \ | 1246 const type *src = (const type *) (cvt->buf + cvt->len_cvt); \ |
1245 type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \ | 1247 type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \ |
1254 } | 1256 } |
1255 | 1257 |
1256 #define discard_mono(type) { \ | 1258 #define discard_mono(type) { \ |
1257 const type *src = (const type *) (cvt->buf); \ | 1259 const type *src = (const type *) (cvt->buf); \ |
1258 type *dst = (type *) (cvt->buf); \ | 1260 type *dst = (type *) (cvt->buf); \ |
1259 for (i = 0; i < cvt->len_cvt / sizeof (type); ++i) { \ | 1261 for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \ |
1260 dst[0] = src[0]; \ | 1262 dst[0] = src[0]; \ |
1261 src += cvt->len_div; \ | 1263 src += cvt->len_div; \ |
1262 ++dst; \ | 1264 ++dst; \ |
1263 } \ | 1265 } \ |
1264 } | 1266 } |
1265 | 1267 |
1266 // Step 1: Zero stuff the conversion buffer | 1268 // Step 1: Zero stuff the conversion buffer |
1269 #ifdef DEBUG_CONVERT | |
1270 printf("Zero-stuffing by a factor of %u\n", cvt->len_mult); | |
1271 #endif | |
1267 switch (SDL_AUDIO_BITSIZE(format)) { | 1272 switch (SDL_AUDIO_BITSIZE(format)) { |
1268 case 8: | 1273 case 8: |
1269 zerostuff_mono(Uint8); | 1274 zerostuff_mono(Uint8); |
1270 break; | 1275 break; |
1271 case 16: | 1276 case 16: |
1279 cvt->len_cvt *= cvt->len_mult; | 1284 cvt->len_cvt *= cvt->len_mult; |
1280 | 1285 |
1281 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies | 1286 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies |
1282 | 1287 |
1283 // Step 3: Discard unnecessary samples | 1288 // Step 3: Discard unnecessary samples |
1289 #ifdef DEBUG_CONVERT | |
1290 printf("Discarding samples by a factor of %u\n", cvt->len_div); | |
1291 #endif | |
1284 switch (SDL_AUDIO_BITSIZE(format)) { | 1292 switch (SDL_AUDIO_BITSIZE(format)) { |
1285 case 8: | 1293 case 8: |
1286 discard_mono(Uint8); | 1294 discard_mono(Uint8); |
1287 break; | 1295 break; |
1288 case 16: | 1296 case 16: |
1416 | 1424 |
1417 coeff[3] = 1.0f; /* a0 is normalized to 1 */ | 1425 coeff[3] = 1.0f; /* a0 is normalized to 1 */ |
1418 coeff[4] = -2.0f * cosw0 * scale; | 1426 coeff[4] = -2.0f * cosw0 * scale; |
1419 coeff[5] = (1.0f - alpha) * scale; | 1427 coeff[5] = (1.0f - alpha) * scale; |
1420 | 1428 |
1421 /* Convert coefficients to fixed point, using the range (-2.0, 2.0) */ | 1429 /* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */ |
1430 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { | |
1431 float *cvt_coeff = (float *)cvt->coeff; | |
1432 int i; | |
1433 for(i = 0; i < 6; ++i) { | |
1434 cvt_coeff[i] = coeff[i]; | |
1435 } | |
1436 } else { | |
1437 } | |
1422 | 1438 |
1423 /* Initialize the state buffer to all zeroes, and set initial position */ | 1439 /* Initialize the state buffer to all zeroes, and set initial position */ |
1424 memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4); | 1440 memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4); |
1425 cvt->state_pos = 0; | 1441 cvt->state_pos = 0; |
1442 } | |
1443 | |
1444 /* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */ | |
1445 int SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { | |
1446 int i, n; | |
1447 | |
1448 n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4); | |
1449 | |
1450 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { | |
1451 float *coeff = (float *)cvt->coeff; | |
1452 float *state = (float *)cvt->state_buf; | |
1453 float *buf = (float *)cvt->buf; | |
1454 float temp; | |
1455 | |
1456 | |
1457 for(i = 0; i < n; ++i) { | |
1458 /* y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a[2] * y[n-2] */ | |
1459 temp = buf[n]; | |
1460 if( cvt->state_pos ) { | |
1461 buf[n] = coeff[0] * buf[n] + coeff[1] * state[0] + coeff[2] * state[1] - coeff[4] * state[2] - coeff[5] * state[3]; | |
1462 state[1] = temp; | |
1463 state[3] = buf[n]; | |
1464 cvt->state_pos = 0; | |
1465 } else { | |
1466 buf[n] = coeff[0] * buf[n] + coeff[1] * state[1] + coeff[2] * state[0] - coeff[4] * state[3] - coeff[5] * state[2]; | |
1467 state[0] = temp; | |
1468 state[2] = buf[n]; | |
1469 cvt->state_pos = 1; | |
1470 } | |
1471 } | |
1472 } else { | |
1473 } | |
1426 } | 1474 } |
1427 | 1475 |
1428 /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */ | 1476 /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */ |
1429 int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { | 1477 int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { |
1430 int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4); | 1478 int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4); |
1435 We can also make a big optimization here by taking advantage | 1483 We can also make a big optimization here by taking advantage |
1436 of the fact that the signal is zero stuffed, so we can do | 1484 of the fact that the signal is zero stuffed, so we can do |
1437 significantly fewer multiplications and additions. | 1485 significantly fewer multiplications and additions. |
1438 */ | 1486 */ |
1439 #define filter_sinc(type, shift_bits) { \ | 1487 #define filter_sinc(type, shift_bits) { \ |
1440 type *sinc = (type *)cvt->sinc; \ | 1488 type *sinc = (type *)cvt->coeff; \ |
1441 type *state = (type *)cvt->state_buf; \ | 1489 type *state = (type *)cvt->state_buf; \ |
1442 type *buf = (type *)cvt->buf; \ | 1490 type *buf = (type *)cvt->buf; \ |
1443 for(i = 0; i < n; ++i) { \ | 1491 for(i = 0; i < n; ++i) { \ |
1444 state[cvt->state_pos++] = buf[i] >> shift_bits; \ | 1492 state[cvt->state_pos++] = buf[i] >> shift_bits; \ |
1445 if(cvt->state_pos == m) cvt->state_pos = 0; \ | 1493 if(cvt->state_pos == m) cvt->state_pos = 0; \ |
1447 for(j = 0; j < m; ++j) { \ | 1495 for(j = 0; j < m; ++j) { \ |
1448 buf[i] += state[j] * sinc[j]; \ | 1496 buf[i] += state[j] * sinc[j]; \ |
1449 } \ | 1497 } \ |
1450 } \ | 1498 } \ |
1451 } | 1499 } |
1452 | 1500 |
1453 switch (SDL_AUDIO_BITSIZE(format)) { | 1501 /* If it's floating point, we don't need to do any shifting */ |
1454 case 8: | 1502 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { |
1455 filter_sinc(Uint8, 4); | 1503 float *sinc = (float *)cvt->coeff; |
1456 break; | 1504 float *state = (float *)cvt->state_buf; |
1457 case 16: | 1505 float *buf = (float *)cvt->buf; |
1458 filter_sinc(Uint16, 8); | 1506 |
1459 break; | 1507 for(i = 0; i < n; ++i) { |
1460 case 32: | 1508 state[cvt->state_pos++] = buf[i]; |
1461 filter_sinc(Uint32, 16); | 1509 if(cvt->state_pos == m) cvt->state_pos = 0; |
1462 break; | 1510 buf[i] = 0.0f; |
1511 for(j = 0; j < m; ++j) { | |
1512 buf[i] += state[j] * sinc[j]; | |
1513 } | |
1514 } | |
1515 } else { | |
1516 switch (SDL_AUDIO_BITSIZE(format)) { | |
1517 case 8: | |
1518 filter_sinc(Uint8, 4); | |
1519 break; | |
1520 case 16: | |
1521 filter_sinc(Uint16, 8); | |
1522 break; | |
1523 case 32: | |
1524 filter_sinc(Uint32, 16); | |
1525 break; | |
1526 } | |
1463 } | 1527 } |
1464 | 1528 |
1465 #undef filter_sinc | 1529 #undef filter_sinc |
1466 | 1530 |
1467 } | 1531 } |
1480 float two_pi_fc, two_pi_over_m, four_pi_over_m, m_over_two; | 1544 float two_pi_fc, two_pi_over_m, four_pi_over_m, m_over_two; |
1481 float norm_sum, norm_fact; | 1545 float norm_sum, norm_fact; |
1482 unsigned int i; | 1546 unsigned int i; |
1483 | 1547 |
1484 /* Check that the buffer is allocated */ | 1548 /* Check that the buffer is allocated */ |
1485 if( cvt->sinc == NULL ) { | 1549 if( cvt->coeff == NULL ) { |
1486 return -1; | 1550 return -1; |
1487 } | 1551 } |
1488 | 1552 |
1489 /* Set the length */ | 1553 /* Set the length */ |
1490 cvt->len_sinc = m; | 1554 cvt->len_sinc = m; |
1517 /* Now normalize and convert to fixed point. We scale everything to half the precision | 1581 /* Now normalize and convert to fixed point. We scale everything to half the precision |
1518 of whatever datatype we're using, for example, 16 bit data means we use 8 bits */ | 1582 of whatever datatype we're using, for example, 16 bit data means we use 8 bits */ |
1519 | 1583 |
1520 #define convert_fixed(type, size) { \ | 1584 #define convert_fixed(type, size) { \ |
1521 norm_fact = size / norm_sum; \ | 1585 norm_fact = size / norm_sum; \ |
1522 type *dst = (type *)cvt->sinc; \ | 1586 type *dst = (type *)cvt->coeff; \ |
1523 for( i = 0; i <= m; ++i ) { \ | 1587 for( i = 0; i <= m; ++i ) { \ |
1524 dst[i] = (type)(fSinc[i] * norm_fact); \ | 1588 dst[i] = (type)(fSinc[i] * norm_fact); \ |
1525 } \ | 1589 } \ |
1526 } | 1590 } |
1527 | 1591 |
1528 /* If we're using floating point, we only need to normalize */ | 1592 /* If we're using floating point, we only need to normalize */ |
1529 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { | 1593 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { |
1530 float *fDest = (float *)cvt->sinc; | 1594 float *fDest = (float *)cvt->coeff; |
1531 norm_fact = 1.0f / norm_sum; | 1595 norm_fact = 1.0f / norm_sum; |
1532 for(i = 0; i <= m; ++i) { | 1596 for(i = 0; i <= m; ++i) { |
1533 fDest[i] = fSinc[i] * norm_fact; | 1597 fDest[i] = fSinc[i] * norm_fact; |
1534 } | 1598 } |
1535 } else { | 1599 } else { |
1553 /* Clean up */ | 1617 /* Clean up */ |
1554 #undef convert_fixed | 1618 #undef convert_fixed |
1555 free(fSinc); | 1619 free(fSinc); |
1556 } | 1620 } |
1557 | 1621 |
1622 /* This is used to reduce the resampling ratio */ | |
1623 inline int SDL_GCD(int a, int b) { | |
1624 int temp; | |
1625 while(b != 0) { | |
1626 temp = a % b; | |
1627 a = b; | |
1628 b = temp; | |
1629 } | |
1630 return a; | |
1631 } | |
1632 | |
1558 | 1633 |
1559 /* Creates a set of audio filters to convert from one format to another. | 1634 /* Creates a set of audio filters to convert from one format to another. |
1560 Returns -1 if the format conversion is not supported, 0 if there's | 1635 Returns -1 if the format conversion is not supported, 0 if there's |
1561 no conversion needed, or 1 if the audio filter is set up. | 1636 no conversion needed, or 1 if the audio filter is set up. |
1562 */ | 1637 */ |
1642 /* Uh oh.. */ ; | 1717 /* Uh oh.. */ ; |
1643 } | 1718 } |
1644 } | 1719 } |
1645 | 1720 |
1646 /* Do rate conversion */ | 1721 /* Do rate conversion */ |
1647 cvt->rate_incr = 0.0; | 1722 int rate_gcd; |
1723 rate_gcd = SDL_GCD(src_rate, dst_rate); | |
1724 cvt->len_mult = dst_rate / rate_gcd; | |
1725 cvt->len_div = src_rate / rate_gcd; | |
1726 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div; | |
1727 cvt->filters[cvt->filter_index++] = SDL_Resample; | |
1728 | |
1729 /*cvt->rate_incr = 0.0; | |
1648 if ((src_rate / 100) != (dst_rate / 100)) { | 1730 if ((src_rate / 100) != (dst_rate / 100)) { |
1649 Uint32 hi_rate, lo_rate; | 1731 Uint32 hi_rate, lo_rate; |
1650 int len_mult; | 1732 int len_mult; |
1651 double len_ratio; | 1733 double len_ratio; |
1652 SDL_AudioFilter rate_cvt = NULL; | 1734 SDL_AudioFilter rate_cvt = NULL; |
1691 default: | 1773 default: |
1692 return -1; | 1774 return -1; |
1693 } | 1775 } |
1694 len_mult = 2; | 1776 len_mult = 2; |
1695 len_ratio = 2.0; | 1777 len_ratio = 2.0; |
1696 } | 1778 }*/ |
1697 /* If hi_rate = lo_rate*2^x then conversion is easy */ | 1779 /* If hi_rate = lo_rate*2^x then conversion is easy */ |
1698 while (((lo_rate * 2) / 100) <= (hi_rate / 100)) { | 1780 /*while (((lo_rate * 2) / 100) <= (hi_rate / 100)) { |
1699 cvt->filters[cvt->filter_index++] = rate_cvt; | 1781 cvt->filters[cvt->filter_index++] = rate_cvt; |
1700 cvt->len_mult *= len_mult; | 1782 cvt->len_mult *= len_mult; |
1701 lo_rate *= 2; | 1783 lo_rate *= 2; |
1702 cvt->len_ratio *= len_ratio; | 1784 cvt->len_ratio *= len_ratio; |
1703 } | 1785 }*/ |
1704 /* We may need a slow conversion here to finish up */ | 1786 /* We may need a slow conversion here to finish up */ |
1705 if ((lo_rate / 100) != (hi_rate / 100)) { | 1787 /*if ((lo_rate / 100) != (hi_rate / 100)) {*/ |
1706 #if 1 | 1788 #if 1 |
1707 /* The problem with this is that if the input buffer is | 1789 /* The problem with this is that if the input buffer is |
1708 say 1K, and the conversion rate is say 1.1, then the | 1790 say 1K, and the conversion rate is say 1.1, then the |
1709 output buffer is 1.1K, which may not be an acceptable | 1791 output buffer is 1.1K, which may not be an acceptable |
1710 buffer size for the audio driver (not a power of 2) | 1792 buffer size for the audio driver (not a power of 2) |
1720 cvt->rate_incr = (double) hi_rate / lo_rate; | 1802 cvt->rate_incr = (double) hi_rate / lo_rate; |
1721 cvt->len_ratio *= cvt->rate_incr; | 1803 cvt->len_ratio *= cvt->rate_incr; |
1722 } | 1804 } |
1723 cvt->filters[cvt->filter_index++] = SDL_RateSLOW; | 1805 cvt->filters[cvt->filter_index++] = SDL_RateSLOW; |
1724 #endif | 1806 #endif |
1725 } | 1807 /* } |
1726 } | 1808 }*/ |
1727 | 1809 |
1728 /* Set up the filter information */ | 1810 /* Set up the filter information */ |
1729 if (cvt->filter_index != 0) { | 1811 if (cvt->filter_index != 0) { |
1730 cvt->needed = 1; | 1812 cvt->needed = 1; |
1731 cvt->src_format = src_fmt; | 1813 cvt->src_format = src_fmt; |