Ignore:
Timestamp:
Sep 18, 2008 11:14:21 AM (16 years ago)
Author:
bennylp
Message:

Large reorganization of the tonegen for ticket #619:

  • Deprecate the automatic selection of algorithm
  • Introduced various constants for tonegen backends
  • Allow user to specify/override the algorithm by setting
  • Fix the floating-point approximation backend
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/tonegen.c

    r2284 r2292  
    2626#include <pj/pool.h> 
    2727 
    28  
    29 /* float can be twice slower on i686! */ 
    30 #define DATA    double 
    31  
    3228/* amplitude */ 
    3329#define AMP     PJMEDIA_TONEGEN_VOLUME 
    34  
    3530 
    3631#ifndef M_PI 
     
    3833#endif 
    3934 
    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 dual-tones (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 floating-point 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 dual-tones (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 dual-tones (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-(theta-CORDIC_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-(theta-3*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); 
    51169         */ 
    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 floating-point 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 
    88178 
    89179    /*  
     
    93183     *    http://www.audiomulch.com/~rossb/code/sinusoids/  
    94184     * 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 dual-tones (2.66GHz P4). 
     186     *         approx. 0.95 MIPS 
    98187     */ 
    99188    PJ_INLINE(int) approximate_sin3(unsigned x) 
     
    113202    }; 
    114203 
    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); \ 
    124209                                var.c += var.add 
    125210 
     211#else 
     212    #error "PJMEDIA_TONEGEN_ALG is not set correctly" 
    126213#endif 
    127214 
Note: See TracChangeset for help on using the changeset viewer.