comparison src/audio/SDL_audiocvt.c @ 2657:29306e52dab8 gsoc2008_audio_resampling

Implemented a lot of fixed point code for the filters. The SDL_FixMpy functions currently don't work properly -- there are some issues with signed vs unsigned.
author Aaron Wishnick <schnarf@gmail.com>
date Wed, 18 Jun 2008 22:42:27 +0000
parents dd74182b3c3c
children de29a03cb108
comparison
equal deleted inserted replaced
2656:dd74182b3c3c 2657:29306e52dab8
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 29
30 #define DEBUG_CONVERT 30 #define DEBUG_CONVERT
31
32 /* Perform fractional multiplication of two 32-bit integers to produce a 32-bit result. Assumes sizeof(long) = 4 */
33 /*#define SDL_FixMpy32(v1, v2, dest) { \
34 long a, b, c, d; \
35 long x, y; \
36 a = (v1 >> 16) & 0xffff; \
37 b = v1 & 0xffff; \
38 c = (v2 >> 16); \
39 d = v2 & 0xffff; \
40 x = a * d + c * b; \
41 y = (((b*d) >> 16) & 0xffff) + x; \
42 dest = ((y >> 16) & 0xffff) + (a * c); \
43 }*/
44 /* TODO: Check if 64-bit type exists. If not, see http://www.8052.com/mul16.phtml or http://www.cs.uaf.edu/~cs301/notes/Chapter5/node5.html */
45
46 #define SDL_FixMpy32(a, b) ((((long long)a * (long long)b) >> 32) & 0xffffffff)
47 #ifdef DEBUG_CONVERT
48 #define SDL_FixMpy16(a, b) ((((long)a * (long)b) >> 16) & 0xffff); printf("%f * %f = %f\n", (float)a / 16384.0f, (float)b / 16384.0f, (float)((((long)a * (long)b) >> 16) & 0xffff) / 16384.0f);
49 #else
50 #define SDL_FixMpy16(a, b) ((((long)a * (long)b) >> 16) & 0xffff)
51 #endif
52 #define SDL_FixMpy8(a, b) ((((short)a * (short)b) >> 8) & 0xff)
53
54 #define SDL_Make_1_7(a) (Uint8)(a * 128.0f)
55 #define SDL_Make_1_15(a) (Uint16)(a * 32768.0f)
56 #define SDL_Make_1_31(a) (Uint32)(a * 2147483648.0f)
57 #define SDL_Make_2_6(a) (Uint8)(a * 64.0f)
58 #define SDL_Make_2_14(a) (Uint16)(a * 16384.0f)
59 #define SDL_Make_2_30(a) (Uint32)(a * 1073741824.0f)
31 60
32 /* Effectively mix right and left channels into a single channel */ 61 /* Effectively mix right and left channels into a single channel */
33 static void SDLCALL 62 static void SDLCALL
34 SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) 63 SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
35 { 64 {
1230 if (cvt->filters[++cvt->filter_index]) { 1259 if (cvt->filters[++cvt->filter_index]) {
1231 cvt->filters[cvt->filter_index] (cvt, format); 1260 cvt->filters[cvt->filter_index] (cvt, format);
1232 } 1261 }
1233 } 1262 }
1234 1263
1235 /* Perform proper resampling */
1236 static void SDLCALL
1237 SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format)
1238 {
1239 int i, j;
1240
1241 #ifdef DEBUG_CONVERT
1242 printf("Converting audio rate via proper resampling (mono)\n");
1243 #endif
1244
1245 #define zerostuff_mono(type) { \
1246 const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
1247 type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \
1248 for (i = cvt->len_cvt / sizeof (type); i; --i) { \
1249 src--; \
1250 dst[-1] = src[0]; \
1251 for( j = -cvt->len_mult; j < -1; ++j ) { \
1252 dst[j] = 0; \
1253 } \
1254 dst -= cvt->len_mult; \
1255 } \
1256 }
1257
1258 #define discard_mono(type) { \
1259 const type *src = (const type *) (cvt->buf); \
1260 type *dst = (type *) (cvt->buf); \
1261 for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
1262 dst[0] = src[0]; \
1263 src += cvt->len_div; \
1264 ++dst; \
1265 } \
1266 }
1267
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
1272 switch (SDL_AUDIO_BITSIZE(format)) {
1273 case 8:
1274 zerostuff_mono(Uint8);
1275 break;
1276 case 16:
1277 zerostuff_mono(Uint16);
1278 break;
1279 case 32:
1280 zerostuff_mono(Uint32);
1281 break;
1282 }
1283
1284 cvt->len_cvt *= cvt->len_mult;
1285
1286 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
1287
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
1292 switch (SDL_AUDIO_BITSIZE(format)) {
1293 case 8:
1294 discard_mono(Uint8);
1295 break;
1296 case 16:
1297 discard_mono(Uint16);
1298 break;
1299 case 32:
1300 discard_mono(Uint32);
1301 break;
1302 }
1303
1304 #undef zerostuff_mono
1305 #undef discard_mono
1306
1307 cvt->len_cvt /= cvt->len_div;
1308
1309 if (cvt->filters[++cvt->filter_index]) {
1310 cvt->filters[cvt->filter_index] (cvt, format);
1311 }
1312 }
1313
1314 int 1264 int
1315 SDL_ConvertAudio(SDL_AudioCVT * cvt) 1265 SDL_ConvertAudio(SDL_AudioCVT * cvt)
1316 { 1266 {
1317 /* Make sure there's data to convert */ 1267 /* Make sure there's data to convert */
1318 if (cvt->buf == NULL) { 1268 if (cvt->buf == NULL) {
1402 int SDL_BuildIIRLowpass(SDL_AudioCVT * cvt, SDL_AudioFormat format) { 1352 int SDL_BuildIIRLowpass(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
1403 float fc; /* cutoff frequency */ 1353 float fc; /* cutoff frequency */
1404 float coeff[6]; /* floating point iir coefficients b0, b1, b2, a0, a1, a2 */ 1354 float coeff[6]; /* floating point iir coefficients b0, b1, b2, a0, a1, a2 */
1405 float scale; 1355 float scale;
1406 float w0, alpha, cosw0; 1356 float w0, alpha, cosw0;
1357 int i;
1407 1358
1408 /* The higher Q is, the higher CUTOFF can be. Need to find a good balance to avoid aliasing */ 1359 /* The higher Q is, the higher CUTOFF can be. Need to find a good balance to avoid aliasing */
1409 static const float Q = 5.0f; 1360 static const float Q = 5.0f;
1410 static const float CUTOFF = 0.4f; 1361 static const float CUTOFF = 0.4f;
1411 1362
1425 coeff[3] = 1.0f; /* a0 is normalized to 1 */ 1376 coeff[3] = 1.0f; /* a0 is normalized to 1 */
1426 coeff[4] = -2.0f * cosw0 * scale; 1377 coeff[4] = -2.0f * cosw0 * scale;
1427 coeff[5] = (1.0f - alpha) * scale; 1378 coeff[5] = (1.0f - alpha) * scale;
1428 1379
1429 /* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */ 1380 /* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */
1381 #define convert_fixed(type, fix) { \
1382 type *cvt_coeff = (type *)cvt->coeff; \
1383 for(i = 0; i < 6; ++i) { \
1384 cvt_coeff[i] = fix(coeff[i]); \
1385 } \
1386 }
1387
1430 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { 1388 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1431 float *cvt_coeff = (float *)cvt->coeff; 1389 float *cvt_coeff = (float *)cvt->coeff;
1432 int i;
1433 for(i = 0; i < 6; ++i) { 1390 for(i = 0; i < 6; ++i) {
1434 cvt_coeff[i] = coeff[i]; 1391 cvt_coeff[i] = coeff[i];
1435 } 1392 }
1436 } else { 1393 } else {
1394 switch(SDL_AUDIO_BITSIZE(format)) {
1395 case 8:
1396 convert_fixed(Uint8, SDL_Make_2_6);
1397 break;
1398 case 16:
1399 convert_fixed(Uint16, SDL_Make_2_14);
1400 break;
1401 case 32:
1402 convert_fixed(Uint32, SDL_Make_2_30);
1403 break;
1404 }
1437 } 1405 }
1406
1407 #ifdef DEBUG_CONVERT
1408 #define debug_iir(type) { \
1409 type *cvt_coeff = (type *)cvt->coeff; \
1410 for(i = 0; i < 6; ++i) { \
1411 printf("coeff[%u] = %f = 0x%x\n", i, coeff[i], cvt_coeff[i]); \
1412 } \
1413 }
1414 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1415 float *cvt_coeff = (float *)cvt->coeff;
1416 for(i = 0; i < 6; ++i) { \
1417 printf("coeff[%u] = %f = %f\n", i, coeff[i], cvt_coeff[i]); \
1418 }
1419 } else {
1420 switch(SDL_AUDIO_BITSIZE(format)) {
1421 case 8:
1422 debug_iir(Uint8);
1423 break;
1424 case 16:
1425 debug_iir(Uint16);
1426 break;
1427 case 32:
1428 debug_iir(Uint32);
1429 break;
1430 }
1431 }
1432 #undef debug_iir
1433 #endif
1438 1434
1439 /* Initialize the state buffer to all zeroes, and set initial position */ 1435 /* Initialize the state buffer to all zeroes, and set initial position */
1440 memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4); 1436 memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4);
1441 cvt->state_pos = 0; 1437 cvt->state_pos = 0;
1438 #undef convert_fixed
1442 } 1439 }
1443 1440
1444 /* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */ 1441 /* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */
1445 int SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { 1442 static void SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
1446 int i, n; 1443 int i, n;
1447 1444
1448 n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4); 1445 n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
1449 1446
1447 /* Note that the coefficients are 2_x and the input is 1_x. Do we need to shift left at the end here? */
1448 #define iir_fix(type, mult) {\
1449 type *coeff = (type *)cvt->coeff; \
1450 type *state = (type *)cvt->state_buf; \
1451 type *buf = (type *)cvt->buf; \
1452 type temp; \
1453 for(i = 0; i < n; ++i) { \
1454 temp = buf[n] >> 1; \
1455 if(cvt->state_pos) { \
1456 buf[n] = mult(coeff[0], temp) + mult(coeff[1], state[0]) + mult(coeff[2], state[1]) - mult(coeff[4], state[2]) - mult(coeff[5], state[3]); \
1457 state[1] = temp; \
1458 state[3] = buf[n]; \
1459 cvt->state_pos = 0; \
1460 } else { \
1461 buf[n] = mult(coeff[0], temp) + mult(coeff[1], state[1]) +mult(coeff[2], state[0]) - mult(coeff[4], state[3]) - mult(coeff[5], state[2]); \
1462 state[0] = temp; \
1463 state[2] = buf[n]; \
1464 cvt->state_pos = 0; \
1465 } \
1466 } \
1467 }
1468
1450 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { 1469 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1451 float *coeff = (float *)cvt->coeff; 1470 float *coeff = (float *)cvt->coeff;
1452 float *state = (float *)cvt->state_buf; 1471 float *state = (float *)cvt->state_buf;
1453 float *buf = (float *)cvt->buf; 1472 float *buf = (float *)cvt->buf;
1454 float temp; 1473 float temp;
1455 1474
1456
1457 for(i = 0; i < n; ++i) { 1475 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] */ 1476 /* 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]; 1477 temp = buf[n];
1460 if( cvt->state_pos ) { 1478 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]; 1479 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; 1480 state[1] = temp;
1463 state[3] = buf[n]; 1481 state[3] = buf[n];
1464 cvt->state_pos = 0; 1482 cvt->state_pos = 0;
1465 } else { 1483 } else {
1468 state[2] = buf[n]; 1486 state[2] = buf[n];
1469 cvt->state_pos = 1; 1487 cvt->state_pos = 1;
1470 } 1488 }
1471 } 1489 }
1472 } else { 1490 } else {
1491 switch(SDL_AUDIO_BITSIZE(format)) {
1492 case 8:
1493 iir_fix(Uint8, SDL_FixMpy8);
1494 break;
1495 case 16:
1496 iir_fix(Uint16, SDL_FixMpy16);
1497 break;
1498 case 32:
1499 iir_fix(Uint32, SDL_FixMpy32);
1500 break;
1501 }
1473 } 1502 }
1503 #undef iir_fix
1474 } 1504 }
1475 1505
1476 /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */ 1506 /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */
1477 int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) { 1507 static void SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
1478 int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4); 1508 int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
1479 int m = cvt->len_sinc; 1509 int m = cvt->len_sinc;
1480 int i, j; 1510 int i, j;
1481 1511
1482 /* Note: this makes use of the symmetry of the sinc filter. 1512 /* Note: this makes use of the symmetry of the sinc filter.
1483 We can also make a big optimization here by taking advantage 1513 We can also make a big optimization here by taking advantage
1484 of the fact that the signal is zero stuffed, so we can do 1514 of the fact that the signal is zero stuffed, so we can do
1485 significantly fewer multiplications and additions. 1515 significantly fewer multiplications and additions.
1486 */ 1516 */
1487 #define filter_sinc(type, shift_bits) { \ 1517 #define filter_sinc(type, mult) { \
1488 type *sinc = (type *)cvt->coeff; \ 1518 type *sinc = (type *)cvt->coeff; \
1489 type *state = (type *)cvt->state_buf; \ 1519 type *state = (type *)cvt->state_buf; \
1490 type *buf = (type *)cvt->buf; \ 1520 type *buf = (type *)cvt->buf; \
1491 for(i = 0; i < n; ++i) { \ 1521 for(i = 0; i < n; ++i) { \
1492 state[cvt->state_pos++] = buf[i] >> shift_bits; \
1493 if(cvt->state_pos == m) cvt->state_pos = 0; \ 1522 if(cvt->state_pos == m) cvt->state_pos = 0; \
1494 buf[i] = 0; \ 1523 buf[i] = 0; \
1495 for(j = 0; j < m; ++j) { \ 1524 for(j = 0; j < m; ++j) { \
1496 buf[i] += state[j] * sinc[j]; \ 1525 buf[i] += mult(state[j], sinc[j]); \
1497 } \ 1526 } \
1498 } \ 1527 } \
1499 } 1528 }
1500 1529
1501 /* If it's floating point, we don't need to do any shifting */ 1530 /* If it's floating point, we don't need to do any shifting */
1513 } 1542 }
1514 } 1543 }
1515 } else { 1544 } else {
1516 switch (SDL_AUDIO_BITSIZE(format)) { 1545 switch (SDL_AUDIO_BITSIZE(format)) {
1517 case 8: 1546 case 8:
1518 filter_sinc(Uint8, 4); 1547 filter_sinc(Uint8, SDL_FixMpy8);
1519 break; 1548 break;
1520 case 16: 1549 case 16:
1521 filter_sinc(Uint16, 8); 1550 filter_sinc(Uint16, SDL_FixMpy16);
1522 break; 1551 break;
1523 case 32: 1552 case 32:
1524 filter_sinc(Uint32, 16); 1553 filter_sinc(Uint32, SDL_FixMpy32);
1525 break; 1554 break;
1526 } 1555 }
1527 } 1556 }
1528 1557
1529 #undef filter_sinc 1558 #undef filter_sinc
1579 } 1608 }
1580 1609
1581 /* Now normalize and convert to fixed point. We scale everything to half the precision 1610 /* Now normalize and convert to fixed point. We scale everything to half the precision
1582 of whatever datatype we're using, for example, 16 bit data means we use 8 bits */ 1611 of whatever datatype we're using, for example, 16 bit data means we use 8 bits */
1583 1612
1584 #define convert_fixed(type, size) { \ 1613 #define convert_fixed(type, fix) { \
1585 norm_fact = size / norm_sum; \ 1614 norm_fact = 1.0f / norm_sum; \
1586 type *dst = (type *)cvt->coeff; \ 1615 type *dst = (type *)cvt->coeff; \
1587 for( i = 0; i <= m; ++i ) { \ 1616 for( i = 0; i <= m; ++i ) { \
1588 dst[i] = (type)(fSinc[i] * norm_fact); \ 1617 dst[i] = fix(fSinc[i] * norm_fact); \
1589 } \ 1618 } \
1590 } 1619 }
1591 1620
1592 /* If we're using floating point, we only need to normalize */ 1621 /* If we're using floating point, we only need to normalize */
1593 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) { 1622 if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
1597 fDest[i] = fSinc[i] * norm_fact; 1626 fDest[i] = fSinc[i] * norm_fact;
1598 } 1627 }
1599 } else { 1628 } else {
1600 switch (SDL_AUDIO_BITSIZE(format)) { 1629 switch (SDL_AUDIO_BITSIZE(format)) {
1601 case 8: 1630 case 8:
1602 convert_fixed(Uint8, 0x0e); 1631 convert_fixed(Uint8, SDL_Make_1_7);
1603 break; 1632 break;
1604 case 16: 1633 case 16:
1605 convert_fixed(Uint16, 0xfe); 1634 convert_fixed(Uint16, SDL_Make_1_15);
1606 break; 1635 break;
1607 case 32: 1636 case 32:
1608 convert_fixed(Uint32, 0xfffe); 1637 convert_fixed(Uint32, SDL_Make_1_31);
1609 break; 1638 break;
1610 } 1639 }
1611 } 1640 }
1612 1641
1613 /* Initialize the state buffer to all zeroes, and set initial position */ 1642 /* Initialize the state buffer to all zeroes, and set initial position */
1628 b = temp; 1657 b = temp;
1629 } 1658 }
1630 return a; 1659 return a;
1631 } 1660 }
1632 1661
1662 /* Perform proper resampling */
1663 static void SDLCALL
1664 SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format)
1665 {
1666 int i, j;
1667
1668 #ifdef DEBUG_CONVERT
1669 printf("Converting audio rate via proper resampling (mono)\n");
1670 #endif
1671
1672 #define zerostuff_mono(type) { \
1673 const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
1674 type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \
1675 for (i = cvt->len_cvt / sizeof (type); i; --i) { \
1676 src--; \
1677 dst[-1] = src[0]; \
1678 for( j = -cvt->len_mult; j < -1; ++j ) { \
1679 dst[j] = 0; \
1680 } \
1681 dst -= cvt->len_mult; \
1682 } \
1683 }
1684
1685 #define discard_mono(type) { \
1686 const type *src = (const type *) (cvt->buf); \
1687 type *dst = (type *) (cvt->buf); \
1688 for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
1689 dst[0] = src[0]; \
1690 src += cvt->len_div; \
1691 ++dst; \
1692 } \
1693 }
1694
1695 // Step 1: Zero stuff the conversion buffer
1696 #ifdef DEBUG_CONVERT
1697 printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
1698 #endif
1699 switch (SDL_AUDIO_BITSIZE(format)) {
1700 case 8:
1701 zerostuff_mono(Uint8);
1702 break;
1703 case 16:
1704 zerostuff_mono(Uint16);
1705 break;
1706 case 32:
1707 zerostuff_mono(Uint32);
1708 break;
1709 }
1710
1711 cvt->len_cvt *= cvt->len_mult;
1712
1713 // Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
1714 SDL_FilterIIR( cvt, format );
1715
1716 // Step 3: Discard unnecessary samples
1717 #ifdef DEBUG_CONVERT
1718 printf("Discarding samples by a factor of %u\n", cvt->len_div);
1719 #endif
1720 switch (SDL_AUDIO_BITSIZE(format)) {
1721 case 8:
1722 discard_mono(Uint8);
1723 break;
1724 case 16:
1725 discard_mono(Uint16);
1726 break;
1727 case 32:
1728 discard_mono(Uint32);
1729 break;
1730 }
1731
1732 #undef zerostuff_mono
1733 #undef discard_mono
1734
1735 cvt->len_cvt /= cvt->len_div;
1736
1737 if (cvt->filters[++cvt->filter_index]) {
1738 cvt->filters[cvt->filter_index] (cvt, format);
1739 }
1740 }
1741
1633 1742
1634 /* Creates a set of audio filters to convert from one format to another. 1743 /* Creates a set of audio filters to convert from one format to another.
1635 Returns -1 if the format conversion is not supported, 0 if there's 1744 Returns -1 if the format conversion is not supported, 0 if there's
1636 no conversion needed, or 1 if the audio filter is set up. 1745 no conversion needed, or 1 if the audio filter is set up.
1637 */ 1746 */
1719 } 1828 }
1720 1829
1721 /* Do rate conversion */ 1830 /* Do rate conversion */
1722 int rate_gcd; 1831 int rate_gcd;
1723 rate_gcd = SDL_GCD(src_rate, dst_rate); 1832 rate_gcd = SDL_GCD(src_rate, dst_rate);
1724 cvt->len_mult = dst_rate / rate_gcd; 1833 cvt->len_mult = 2 * dst_rate / rate_gcd;
1725 cvt->len_div = src_rate / rate_gcd; 1834 cvt->len_div = 2 * src_rate / rate_gcd;
1726 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div; 1835 cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
1727 cvt->filters[cvt->filter_index++] = SDL_Resample; 1836 cvt->filters[cvt->filter_index++] = SDL_Resample;
1837 SDL_BuildIIRLowpass(cvt, dst_fmt);
1728 1838
1729 /*cvt->rate_incr = 0.0; 1839 /*cvt->rate_incr = 0.0;
1730 if ((src_rate / 100) != (dst_rate / 100)) { 1840 if ((src_rate / 100) != (dst_rate / 100)) {
1731 Uint32 hi_rate, lo_rate; 1841 Uint32 hi_rate, lo_rate;
1732 int len_mult; 1842 int len_mult;
1817 cvt->filters[cvt->filter_index] = NULL; 1927 cvt->filters[cvt->filter_index] = NULL;
1818 } 1928 }
1819 return (cvt->needed); 1929 return (cvt->needed);
1820 } 1930 }
1821 1931
1932 #undef SDL_FixMpy8
1933 #undef SDL_FixMpy16
1934 #undef SDL_FixMpy32
1935 #undef SDL_Make_1_7
1936 #undef SDL_Make_1_15
1937 #undef SDL_Make_1_31
1938 #undef SDL_Make_2_6
1939 #undef SDL_Make_2_14
1940 #undef SDL_Make_2_30
1941
1822 /* vi: set ts=4 sw=4 expandtab: */ 1942 /* vi: set ts=4 sw=4 expandtab: */