- Timestamp:
- Apr 9, 2007 7:06:08 AM (18 years ago)
- Location:
- pjproject/branches/split-3rd-party/third_party/resample/src
- Files:
-
- 1 added
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/split-3rd-party/third_party/resample/src/resamplesubs.c
r1176 r1177 1 1 /* $Id$ */ 2 2 /* 3 * Based on:4 * resample-1.8.tar.gz from the5 3 * Digital Audio Resampling Home Page located at 6 4 * http://www-ccrma.stanford.edu/~jos/resample/. … … 42 40 * - const correctness. 43 41 */ 44 #include <pjmedia/resample.h> 45 #include <pjmedia/errno.h> 46 #include <pj/assert.h> 47 #include <pj/log.h> 48 #include <pj/pool.h> 49 50 51 #define THIS_FILE "resample.c" 52 53 54 /* 55 * Taken from stddefs.h 56 */ 57 #ifndef PI 58 #define PI (3.14159265358979232846) 59 #endif 60 61 #ifndef PI2 62 #define PI2 (6.28318530717958465692) 63 #endif 64 65 #define D2R (0.01745329348) /* (2*pi)/360 */ 66 #define R2D (57.29577951) /* 360/(2*pi) */ 67 68 #ifndef MAX 69 #define MAX(x,y) ((x)>(y) ?(x):(y)) 70 #endif 71 #ifndef MIN 72 #define MIN(x,y) ((x)<(y) ?(x):(y)) 73 #endif 74 75 #ifndef ABS 76 #define ABS(x) ((x)<0 ?(-(x)):(x)) 77 #endif 78 79 #ifndef SGN 80 #define SGN(x) ((x)<0 ?(-1):((x)==0?(0):(1))) 81 #endif 82 83 typedef char RES_BOOL; 84 typedef short RES_HWORD; 85 typedef int RES_WORD; 86 typedef unsigned short RES_UHWORD; 87 typedef unsigned int RES_UWORD; 88 89 #define MAX_HWORD (32767) 90 #define MIN_HWORD (-32768) 91 92 #ifdef DEBUG 93 #define INLINE 94 #else 95 #define INLINE inline 96 #endif 97 98 /* 99 * Taken from resample.h 100 * 101 * The configuration constants below govern 102 * the number of bits in the input sample and filter coefficients, the 103 * number of bits to the right of the binary-point for fixed-point math, etc. 104 * 105 */ 106 107 /* Conversion constants */ 108 #define Nhc 8 109 #define Na 7 110 #define Np (Nhc+Na) 111 #define Npc (1<<Nhc) 112 #define Amask ((1<<Na)-1) 113 #define Pmask ((1<<Np)-1) 114 #define Nh 16 115 #define Nb 16 116 #define Nhxn 14 117 #define Nhg (Nh-Nhxn) 118 #define NLpScl 13 119 120 /* Description of constants: 121 * 122 * Npc - is the number of look-up values available for the lowpass filter 123 * between the beginning of its impulse response and the "cutoff time" 124 * of the filter. The cutoff time is defined as the reciprocal of the 125 * lowpass-filter cut off frequence in Hz. For example, if the 126 * lowpass filter were a sinc function, Npc would be the index of the 127 * impulse-response lookup-table corresponding to the first zero- 128 * crossing of the sinc function. (The inverse first zero-crossing 129 * time of a sinc function equals its nominal cutoff frequency in Hz.) 130 * Npc must be a power of 2 due to the details of the current 131 * implementation. The default value of 512 is sufficiently high that 132 * using linear interpolation to fill in between the table entries 133 * gives approximately 16-bit accuracy in filter coefficients. 134 * 135 * Nhc - is log base 2 of Npc. 136 * 137 * Na - is the number of bits devoted to linear interpolation of the 138 * filter coefficients. 139 * 140 * Np - is Na + Nhc, the number of bits to the right of the binary point 141 * in the integer "time" variable. To the left of the point, it indexes 142 * the input array (X), and to the right, it is interpreted as a number 143 * between 0 and 1 sample of the input X. Np must be less than 16 in 144 * this implementation. 145 * 146 * Nh - is the number of bits in the filter coefficients. The sum of Nh and 147 * the number of bits in the input data (typically 16) cannot exceed 32. 148 * Thus Nh should be 16. The largest filter coefficient should nearly 149 * fill 16 bits (32767). 150 * 151 * Nb - is the number of bits in the input data. The sum of Nb and Nh cannot 152 * exceed 32. 153 * 154 * Nhxn - is the number of bits to right shift after multiplying each input 155 * sample times a filter coefficient. It can be as great as Nh and as 156 * small as 0. Nhxn = Nh-2 gives 2 guard bits in the multiply-add 157 * accumulation. If Nhxn=0, the accumulation will soon overflow 32 bits. 158 * 159 * Nhg - is the number of guard bits in mpy-add accumulation (equal to Nh-Nhxn) 160 * 161 * NLpScl - is the number of bits allocated to the unity-gain normalization 162 * factor. The output of the lowpass filter is multiplied by LpScl and 163 * then right-shifted NLpScl bits. To avoid overflow, we must have 164 * Nb+Nhg+NLpScl < 32. 165 */ 42 43 #include <resamplesubs.h> 44 #include "config.h" 45 #include "stddefs.h" 46 #include "resample.h" 166 47 167 48 … … 174 55 #endif 175 56 176 #if defined( PJMEDIA_HAS_SMALL_FILTER) && PJMEDIA_HAS_SMALL_FILTER!=057 #if defined(RESAMPLE_HAS_SMALL_FILTER) && RESAMPLE_HAS_SMALL_FILTER!=0 177 58 # include "smallfilter.h" 178 59 #else … … 184 65 #endif 185 66 186 #if defined( PJMEDIA_HAS_LARGE_FILTER) && PJMEDIA_HAS_LARGE_FILTER!=067 #if defined(RESAMPLE_HAS_LARGE_FILTER) && RESAMPLE_HAS_LARGE_FILTER!=0 187 68 # include "largefilter.h" 188 69 #else … … 439 320 440 321 441 /* *************************************************************************** 442 * 443 * PJMEDIA RESAMPLE 444 * 445 * *************************************************************************** 446 */ 447 448 struct pjmedia_resample 449 { 450 double factor; /* Conversion factor = rate_out / rate_in. */ 451 pj_bool_t large_filter; /* Large filter? */ 452 pj_bool_t high_quality; /* Not fast? */ 453 unsigned xoff; /* History and lookahead size, in samples */ 454 unsigned frame_size; /* Samples per frame. */ 455 pj_int16_t *buffer; /* Input buffer. */ 456 }; 457 458 459 PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool, 460 pj_bool_t high_quality, 461 pj_bool_t large_filter, 462 unsigned channel_count, 463 unsigned rate_in, 464 unsigned rate_out, 465 unsigned samples_per_frame, 466 pjmedia_resample **p_resample) 467 { 468 pjmedia_resample *resample; 469 470 PJ_ASSERT_RETURN(pool && p_resample && rate_in && 471 rate_out && samples_per_frame, PJ_EINVAL); 472 473 resample = pj_pool_alloc(pool, sizeof(pjmedia_resample)); 474 PJ_ASSERT_RETURN(resample, PJ_ENOMEM); 475 476 PJ_UNUSED_ARG(channel_count); 477 478 /* 479 * If we're downsampling, always use the fast algorithm since it seems 480 * to yield the same quality. 481 */ 482 if (rate_out < rate_in) { 483 //no this is not a good idea. It sounds pretty good with speech, 484 //but very poor with background noise etc. 485 //high_quality = 0; 486 } 487 488 #if !defined(PJMEDIA_HAS_LARGE_FILTER) || PJMEDIA_HAS_LARGE_FILTER==0 489 /* 490 * If large filter is excluded in the build, then prevent application 491 * from using it. 492 */ 493 if (high_quality && large_filter) { 494 large_filter = PJ_FALSE; 495 PJ_LOG(5,(THIS_FILE, 496 "Resample uses small filter because large filter is " 497 "disabled")); 498 } 499 #endif 500 501 #if !defined(PJMEDIA_HAS_SMALL_FILTER) || PJMEDIA_HAS_SMALL_FILTER==0 502 /* 503 * If small filter is excluded in the build and application wants to 504 * use it, then drop to linear conversion. 505 */ 506 if (high_quality && large_filter == 0) { 507 high_quality = PJ_FALSE; 508 PJ_LOG(4,(THIS_FILE, 509 "Resample uses linear because small filter is disabled")); 510 } 511 #endif 512 513 resample->factor = rate_out * 1.0 / rate_in; 514 resample->large_filter = large_filter; 515 resample->high_quality = high_quality; 516 resample->frame_size = samples_per_frame; 517 518 if (high_quality) { 519 unsigned size; 520 521 /* This is a bug in xoff calculation, thanks Stephane Lussier 522 * of Macadamian dot com. 523 * resample->xoff = large_filter ? 32 : 6; 524 */ 525 if (large_filter) 526 resample->xoff = (LARGE_FILTER_NMULT + 1) / 2.0 * 527 MAX(1.0, 1.0/resample->factor); 322 int res_SrcLinear(const RES_HWORD X[], RES_HWORD Y[], 323 double pFactor, RES_UHWORD nx) 324 { 325 return SrcLinear(X, Y, pFactor, nx); 326 } 327 328 int res_Resample(const RES_HWORD X[], RES_HWORD Y[], double pFactor, 329 RES_UHWORD nx, RES_BOOL LargeF, RES_BOOL Interp) 330 { 331 if (pFactor >= 1) { 332 333 if (LargeF) 334 return SrcUp(X, Y, pFactor, nx, 335 LARGE_FILTER_NWING, LARGE_FILTER_SCALE, 336 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp); 528 337 else 529 resample->xoff = (SMALL_FILTER_NMULT + 1) / 2.0 * 530 MAX(1.0, 1.0/resample->factor); 531 532 533 size = (samples_per_frame + 2*resample->xoff) * sizeof(pj_int16_t); 534 resample->buffer = pj_pool_alloc(pool, size); 535 PJ_ASSERT_RETURN(resample->buffer, PJ_ENOMEM); 536 537 pjmedia_zero_samples(resample->buffer, resample->xoff*2); 538 338 return SrcUp(X, Y, pFactor, nx, 339 SMALL_FILTER_NWING, SMALL_FILTER_SCALE, 340 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp); 539 341 540 342 } else { 541 resample->xoff = 0; 542 } 543 544 *p_resample = resample; 545 546 PJ_LOG(5,(THIS_FILE, "resample created: %s qualiy, %s filter, in/out " 547 "rate=%d/%d", 548 (high_quality?"high":"low"), 549 (large_filter?"large":"small"), 550 rate_in, rate_out)); 551 return PJ_SUCCESS; 552 } 553 554 555 556 PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample, 557 const pj_int16_t *input, 558 pj_int16_t *output ) 559 { 560 PJ_ASSERT_ON_FAIL(resample, return); 561 562 if (resample->high_quality) { 563 pj_int16_t *dst_buf; 564 const pj_int16_t *src_buf; 565 566 /* Okay chaps, here's how we do resampling. 567 * 568 * The original resample algorithm requires xoff samples *before* the 569 * input buffer as history, and another xoff samples *after* the 570 * end of the input buffer as lookahead. Since application can only 571 * supply framesize buffer on each run, PJMEDIA needs to arrange the 572 * buffer to meet these requirements. 573 * 574 * So here comes the trick. 575 * 576 * First of all, because of the history and lookahead requirement, 577 * resample->buffer need to accomodate framesize+2*xoff samples in its 578 * buffer. This is done when the buffer is created. 579 * 580 * On the first run, the input frame (supplied by application) is 581 * copied to resample->buffer at 2*xoff position. The first 2*xoff 582 * samples are initially zeroed (in the initialization). The resample 583 * algorithm then invoked at resample->buffer+xoff ONLY, thus giving 584 * it one xoff at the beginning as zero, and one xoff at the end 585 * as the end of the original input. The resample algorithm will see 586 * that the first xoff samples in the input as zero. 587 * 588 * So here's the layout of resample->buffer on the first run. 589 * 590 * run 0 591 * +------+------+--------------+ 592 * | 0000 | 0000 | frame0... | 593 * +------+------+--------------+ 594 * ^ ^ ^ ^ 595 * 0 xoff 2*xoff size+2*xoff 596 * 597 * (Note again: resample algorithm is called at resample->buffer+xoff) 598 * 599 * At the end of the run, 2*xoff samples from the end of 600 * resample->buffer are copied to the beginning of resample->buffer. 601 * The first xoff part of this will be used as history for the next 602 * run, and the second xoff part of this is actually the start of 603 * resampling for the next run. 604 * 605 * And the first run completes, the function returns. 606 * 607 * 608 * On the next run, the input frame supplied by application is again 609 * copied at 2*xoff position in the resample->buffer, and the 610 * resample algorithm is again invoked at resample->buffer+xoff 611 * position. So effectively, the resample algorithm will start its 612 * operation on the last xoff from the previous frame, and gets the 613 * history from the last 2*xoff of the previous frame, and the look- 614 * ahead from the last xoff of current frame. 615 * 616 * So on this run, the buffer layout is: 617 * 618 * run 1 619 * +------+------+--------------+ 620 * | frm0 | frm0 | frame1... | 621 * +------+------+--------------+ 622 * ^ ^ ^ ^ 623 * 0 xoff 2*xoff size+2*xoff 624 * 625 * As you can see from above diagram, the resampling algorithm is 626 * actually called from the last xoff part of previous frame (frm0). 627 * 628 * And so on the process continues for the next frame, and the next, 629 * and the next, ... 630 * 631 */ 632 dst_buf = resample->buffer + resample->xoff*2; 633 pjmedia_copy_samples(dst_buf, input, resample->frame_size); 634 635 if (resample->factor >= 1) { 636 637 if (resample->large_filter) { 638 SrcUp(resample->buffer + resample->xoff, output, 639 resample->factor, resample->frame_size, 640 LARGE_FILTER_NWING, LARGE_FILTER_SCALE, 641 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, 642 PJ_TRUE); 643 } else { 644 SrcUp(resample->buffer + resample->xoff, output, 645 resample->factor, resample->frame_size, 646 SMALL_FILTER_NWING, SMALL_FILTER_SCALE, 647 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, 648 PJ_TRUE); 649 } 650 651 } else { 652 653 if (resample->large_filter) { 654 655 SrcUD( resample->buffer + resample->xoff, output, 656 resample->factor, resample->frame_size, 657 LARGE_FILTER_NWING, 658 LARGE_FILTER_SCALE * resample->factor + 0.5, 659 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, 660 PJ_TRUE); 661 662 } else { 663 664 SrcUD( resample->buffer + resample->xoff, output, 665 resample->factor, resample->frame_size, 666 SMALL_FILTER_NWING, 667 SMALL_FILTER_SCALE * resample->factor + 0.5, 668 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, 669 PJ_TRUE); 670 671 } 672 673 } 674 675 dst_buf = resample->buffer; 676 src_buf = input + resample->frame_size - resample->xoff*2; 677 pjmedia_copy_samples(dst_buf, src_buf, resample->xoff * 2); 678 679 } else { 680 SrcLinear( input, output, resample->factor, resample->frame_size); 681 } 682 } 683 684 PJ_DEF(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample) 685 { 686 PJ_ASSERT_RETURN(resample != NULL, 0); 687 return resample->frame_size; 688 } 689 690 PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) 691 { 692 PJ_UNUSED_ARG(resample); 693 } 694 695 343 344 if (LargeF) 345 return SrcUD(X, Y, pFactor, nx, 346 LARGE_FILTER_NWING, LARGE_FILTER_SCALE * pFactor + 0.5, 347 LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp); 348 else 349 return SrcUD(X, Y, pFactor, nx, 350 SMALL_FILTER_NWING, SMALL_FILTER_SCALE * pFactor + 0.5, 351 SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp); 352 353 } 354 } 355 356 int res_GetXOFF(double pFactor, RES_BOOL LargeF) 357 { 358 if (LargeF) 359 return (LARGE_FILTER_NMULT + 1) / 2.0 * 360 MAX(1.0, 1.0/pFactor); 361 else 362 return (SMALL_FILTER_NMULT + 1) / 2.0 * 363 MAX(1.0, 1.0/pFactor); 364 } 365
Note: See TracChangeset
for help on using the changeset viewer.