Changeset 2292
 Timestamp:
 Sep 18, 2008 11:14:21 AM (11 years ago)
 Location:
 pjproject/trunk/pjmedia
 Files:

 2 edited
Legend:
 Unmodified
 Added
 Removed

pjproject/trunk/pjmedia/include/pjmedia/config.h
r2290 r2292 542 542 543 543 544 /* 545 * Below specifies the various tone generator backend algorithm. 546 */ 547 548 /** 549 * The math's sine(), floating point. This has very good precision 550 * but it's the slowest and requires floating point support and 551 * linking with the math library. 552 */ 553 #define PJMEDIA_TONEGEN_SINE 1 554 555 /** 556 * Floating point approximation of sine(). This has relatively good 557 * precision and much faster than plain sine(), but it requires floating 558 * point support and linking with the math library. 559 */ 560 #define PJMEDIA_TONEGEN_FLOATING_POINT 2 561 562 /** 563 * Fixed point using sine signal generated by Cordic algorithm. This 564 * algorithm can be tuned to provide balance between precision and 565 * performance by tuning the PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 566 * setting, and may be suitable for platforms that lack floatingpoint 567 * support. 568 */ 569 #define PJMEDIA_TONEGEN_FIXED_POINT_CORDIC 3 570 571 /** 572 * Fast fixed point using some approximation to generate sine waves. 573 * The tone generated by this algorithm is not very precise, however 574 * the algorithm is very fast. 575 */ 576 #define PJMEDIA_TONEGEN_FAST_FIXED_POINT 4 577 578 579 /** 580 * Specify the tone generator algorithm to be used. 581 * 582 * Default value: 583 *  PJMEDIA_TONEGEN_FLOATING_POINT when PJ_HAS_FLOATING_POINT is set 584 *  PJMEDIA_TONEGEN_FIXED_POINT_CORDIC when PJ_HAS_FLOATING_POINT is not set 585 */ 586 #ifndef PJMEDIA_TONEGEN_ALG 587 # if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT 588 # define PJMEDIA_TONEGEN_ALG PJMEDIA_TONEGEN_FLOATING_POINT 589 # else 590 # define PJMEDIA_TONEGEN_ALG PJMEDIA_TONEGEN_FIXED_POINT_CORDIC 591 # endif 592 #endif 593 594 595 /** 596 * Specify the number of calculation loops to generate the tone, when 597 * PJMEDIA_TONEGEN_FIXED_POINT_CORDIC algorithm is used. With more calculation 598 * loops, the tone signal gets more precise, but this will add more 599 * processing. 600 * 601 * Valid values are 1 to 28. 602 * 603 * Default value: 7 604 */ 605 #ifndef PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 606 # define PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 7 607 #endif 608 609 544 610 /** 545 611 * Enable high quality of tone generation, the better quality will cost … … 548 614 * By default it is enabled when PJ_HAS_FLOATING_POINT is set. 549 615 * 550 * @see PJMEDIA_TONEGEN_FORCE_FLOAT 551 */ 552 #ifndef PJMEDIA_USE_HIGH_QUALITY_TONEGEN 553 # define PJMEDIA_USE_HIGH_QUALITY_TONEGEN PJ_HAS_FLOATING_POINT 554 #endif 555 556 557 /** 558 * Force the tone generation to use floating point computation, even when 559 * PJ_HAS_FLOATING_POINT is disabled. This may be necessary if the tone 560 * generator is used to produce DTMF to be sent inband, since the fixed 561 * point algorithm may not have the correct frequency accuracy. 562 * 563 * This option, combined with PJ_HAS_FLOATING_POINT will produce the 564 * following selection of tone generator algorithm: 565 *  if both PJ_HAS_FLOATING_POINT and PJMEDIA_USE_HIGH_QUALITY_TONEGEN 566 * are set, the standard sin() function will be used. This will produce 567 * the highest quality tones, at the expense of more processing power. 568 *  if PJ_HAS_FLOATING_POINT is not set: 569 *  if both PJMEDIA_USE_HIGH_QUALITY_TONEGEN and 570 * PJMEDIA_TONEGEN_FORCE_FLOAT are set, sin() based algorithm will 571 * be used (similar as above). 572 *  if PJMEDIA_USE_HIGH_QUALITY_TONEGEN is not set but the 573 * PJMEDIA_TONEGEN_FORCE_FLOAT is set, a floating point approximation 574 * algorithm will be used. This should produce good enough tone 575 * for most uses, and the performance is faster than using pure 576 * sin() based algorithm. Note that linking to math library may 577 * still be needed. 578 *  if both are not set, the fixed point approximation algorithm 579 * will be used. 580 * 581 * Default: 1 582 */ 583 #ifndef PJMEDIA_TONEGEN_FORCE_FLOAT 584 # define PJMEDIA_TONEGEN_FORCE_FLOAT 1 616 * This macro has been deprecated in version 1.0rc3. 617 */ 618 #ifdef PJMEDIA_USE_HIGH_QUALITY_TONEGEN 619 # error "The PJMEDIA_USE_HIGH_QUALITY_TONEGEN macro is obsolete" 585 620 #endif 586 621 
pjproject/trunk/pjmedia/src/pjmedia/tonegen.c
r2284 r2292 26 26 #include <pj/pool.h> 27 27 28 29 /* float can be twice slower on i686! */30 #define DATA double31 32 28 /* amplitude */ 33 29 #define AMP PJMEDIA_TONEGEN_VOLUME 34 35 30 36 31 #ifndef M_PI … … 38 33 #endif 39 34 40 41 #if (defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0)  \ 42 (defined(PJMEDIA_TONEGEN_FORCE_FLOAT) && PJMEDIA_TONEGEN_FORCE_FLOAT != 0) 43 # include <math.h> 44 45 # if defined(PJMEDIA_USE_HIGH_QUALITY_TONEGEN) && \ 46 PJMEDIA_USE_HIGH_QUALITY_TONEGEN!=0 47 48 /* 49 * This is the good old tone generator using sin(). 50 * Speed = 222.5 cycles per sample. 35 #if PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_SINE 36 #include <math.h> 37 #define DATA double 38 39 /* 40 * This is the good old tone generator using sin(). 41 * Speed = 1347 usec to generate 1 second, 8KHz dualtones (2.66GHz P4). 42 * approx. 10.91 MIPS 43 */ 44 struct gen 45 { 46 DATA add; 47 DATA c; 48 DATA vol; 49 }; 50 51 #define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A 52 #define GEN_SAMP(val,var) val = (short)(sin(var.c * 2 * M_PI) * \ 53 var.vol); \ 54 var.c += var.add 55 56 #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FLOATING_POINT 57 #include <math.h> 58 #define DATA float 59 60 /* 61 * Default floatingpoint based tone generation using sine wave 62 * generation from: 63 * http://www.musicdsp.org/showone.php?id=10. 64 * This produces good quality tone in relatively faster time than 65 * the normal sin() generator. 66 * Speed = 350 usec to generate 1 second, 8KHz dualtones (2.66GHz P4). 67 * approx. 2.84 MIPS 68 */ 69 struct gen 70 { 71 DATA a, s0, s1; 72 }; 73 74 #define GEN_INIT(var,R,F,A) var.a = (DATA) (2.0 * sin(M_PI * F / R)); \ 75 var.s0 = 0; \ 76 var.s1 = (DATA)(0  (int)A) 77 #define GEN_SAMP(val,var) var.s0 = var.s0  var.a * var.s1; \ 78 var.s1 = var.s1 + var.a * var.s0; \ 79 val = (short) var.s0 80 81 #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FIXED_POINT_CORDIC 82 /* Cordic algorithm with 28 bit size, from: 83 * http://www.dcs.gla.ac.uk/~jhw/cordic/ 84 * Speed = 742 usec to generate 1 second, 8KHz dualtones (2.66GHz P4). 85 * (PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP=7) 86 * approx. 6.01 MIPS 87 */ 88 #define CORDIC_1K 0x026DD3B6 89 #define CORDIC_HALF_PI 0x06487ED5 90 #define CORDIC_PI (CORDIC_HALF_PI * 2) 91 #define CORDIC_MUL_BITS 26 92 #define CORDIC_MUL (1 << CORDIC_MUL_BITS) 93 #define CORDIC_NTAB 28 94 #define CORDIC_LOOP PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 95 96 static int cordic_ctab [] = 97 { 98 0x03243F6A, 0x01DAC670, 0x00FADBAF, 0x007F56EA, 0x003FEAB7, 99 0x001FFD55, 0x000FFFAA, 0x0007FFF5, 0x0003FFFE, 0x0001FFFF, 100 0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF, 101 0x000007FF, 0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F, 102 0x0000003F, 0x0000001F, 0x0000000F, 0x00000007, 0x00000003, 103 0x00000001, 0x00000000, 0x00000000 104 }; 105 106 static pj_int32_t cordic(pj_int32_t theta, unsigned n) 107 { 108 unsigned k; 109 int d; 110 pj_int32_t tx; 111 pj_int32_t x = CORDIC_1K, y = 0, z = theta; 112 113 for (k=0; k<n; ++k) { 114 #if 0 115 d = (z>=0) ? 0 : 1; 116 #else 117 /* Only slightly (~2.5%) faster, but not portable? */ 118 d = z>>27; 119 #endif 120 tx = x  (((y>>k) ^ d)  d); 121 y = y + (((x>>k) ^ d)  d); 122 z = z  ((cordic_ctab[k] ^ d)  d); 123 x = tx; 124 } 125 return y; 126 } 127 128 /* Note: theta must be uint32 here */ 129 static pj_int32_t cordic_sin(pj_uint32_t theta, unsigned n) 130 { 131 if (theta < CORDIC_HALF_PI) 132 return cordic(theta, n); 133 else if (theta < CORDIC_PI) 134 return cordic(CORDIC_HALF_PI(thetaCORDIC_HALF_PI), n); 135 else if (theta < CORDIC_PI + CORDIC_HALF_PI) 136 return cordic(theta  CORDIC_PI, n); 137 else if (theta < 2 * CORDIC_PI) 138 return cordic(CORDIC_HALF_PI(theta3*CORDIC_HALF_PI), n); 139 else { 140 pj_assert(!"Invalid cordic_sin() value"); 141 return 0; 142 } 143 } 144 145 struct gen 146 { 147 unsigned add; 148 pj_uint32_t c; 149 unsigned vol; 150 }; 151 152 #define VOL(var,v) (((v) * var.vol) >> 15) 153 #define GEN_INIT(var,R,F,A) gen_init(&var, R, F, A) 154 #define GEN_SAMP(val,var) val = gen_samp(&var) 155 156 static void gen_init(struct gen *var, unsigned R, unsigned F, unsigned A) 157 { 158 var>add = 2*CORDIC_PI/R * F; 159 var>c = 0; 160 var>vol = A; 161 } 162 163 PJ_INLINE(short) gen_samp(struct gen *var) 164 { 165 pj_int32_t val; 166 val = cordic_sin(var>c, CORDIC_LOOP); 167 /*val = (val * 32767) / CORDIC_MUL; 168 *val = VOL((*var), val); 51 169 */ 52 struct gen 53 { 54 DATA add; 55 DATA c; 56 DATA vol; 57 }; 58 59 # define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A 60 # define GEN_SAMP(val,var) val = (short)(sin(var.c * 2 * M_PI) * \ 61 var.vol); \ 62 var.c += var.add 63 64 # else 65 66 /* 67 * Default floatingpoint based tone generation using sine wave 68 * generation from: 69 * http://www.musicdsp.org/showone.php?id=10. 70 * This produces good quality tone in relatively faster time than 71 * the normal sin() generator. 72 * Speed = 40.6 cycles per sample. 73 */ 74 struct gen 75 { 76 DATA a, s0, s1; 77 }; 78 79 # define GEN_INIT(var,R,F,A) var.a = (DATA) (2.0 * sin(M_PI * F / R)); \ 80 var.s0 = A; \ 81 var.s1 = 0 82 # define GEN_SAMP(val,var) var.s0 = var.s0  var.a * var.s1; \ 83 var.s1 = var.s1 + var.a * var.s0; \ 84 val = (short) var.s0 85 # endif 86 87 #else 170 val = ((val >> 10) * var>vol) >> 16; 171 var>c += var>add; 172 if (var>c > 2*CORDIC_PI) 173 var>c = (2 * CORDIC_PI); 174 return (short) val; 175 } 176 177 #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FAST_FIXED_POINT 88 178 89 179 /* … … 93 183 * http://www.audiomulch.com/~rossb/code/sinusoids/ 94 184 * Quality wise not so good, but it's blazing fast! 95 * Speed: 96 *  with volume adjustment: 14 cycles per sample 97 *  without volume adjustment: 12.22 cycles per sample 185 * Speed = 117 usec to generate 1 second, 8KHz dualtones (2.66GHz P4). 186 * approx. 0.95 MIPS 98 187 */ 99 188 PJ_INLINE(int) approximate_sin3(unsigned x) … … 113 202 }; 114 203 115 # define MAXI ((unsigned)0xFFFFFFFF) 116 # define SIN approximate_sin3 117 # if 1 /* set this to 0 to disable volume adjustment */ 118 # define VOL(var,v) (((v) * var.vol) >> 15) 119 # else 120 # define VOL(var,v) (v) 121 # endif 122 # define GEN_INIT(var,R,F,A) var.add = MAXI/R * F, var.c=0, var.vol=A 123 # define GEN_SAMP(val,var) val = (short) VOL(var,SIN(var.c)>>16);\ 204 #define MAXI ((unsigned)0xFFFFFFFF) 205 #define SIN approximate_sin3 206 #define VOL(var,v) (((v) * var.vol) >> 15) 207 #define GEN_INIT(var,R,F,A) var.add = MAXI/R * F, var.c=0, var.vol=A 208 #define GEN_SAMP(val,var) val = (short) VOL(var,SIN(var.c)>>16); \ 124 209 var.c += var.add 125 210 211 #else 212 #error "PJMEDIA_TONEGEN_ALG is not set correctly" 126 213 #endif 127 214
Note: See TracChangeset
for help on using the changeset viewer.