Changeset 1844


Ignore:
Timestamp:
Mar 4, 2008 3:37:45 PM (16 years ago)
Author:
bennylp
Message:

More ticket #438: improve docs, added channel_count in wsola, etc.

Location:
pjproject/trunk/pjmedia
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/wsola.h

    r1831 r1844  
    7676 * @param clock_rate        Sampling rate of audio playback. 
    7777 * @param samples_per_frame Number of samples per frame. 
     78 * @param channel_count     Number of channels. 
    7879 * @param options           Option flags, bitmask combination of 
    7980 *                          #pjmedia_wsola_option. 
     
    8586                                          unsigned clock_rate, 
    8687                                          unsigned samples_per_frame, 
     88                                          unsigned channel_count, 
    8789                                          unsigned options, 
    8890                                          pjmedia_wsola **p_wsola); 
  • pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c

    r1840 r1844  
    158158    } 
    159159 
    160     status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame,  
     160    status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, 
    161161                                  PJMEDIA_WSOLA_NO_PLC, &b->wsola); 
    162162    if (status != PJ_SUCCESS) 
  • pjproject/trunk/pjmedia/src/pjmedia/splitcomb.c

    r1840 r1844  
    4949#define OP_GET              (-1) 
    5050 
    51 /* Media flow directions */ 
     51 
     52/*  
     53 * Media flow directions: 
     54 * 
     55 *             put_frame() +-----+ 
     56 *  UPSTREAM  ------------>|split|<--> DOWNSTREAM 
     57 *            <------------|comb | 
     58 *             get_frame() +-----+ 
     59 * 
     60 */ 
    5261enum sc_dir 
    5362{ 
    54     /* This is the direction from the splitcomb to the downstream 
    55      * port(s), or when put_frame() is called to the splitcomb. 
     63    /* This is the media direction from the splitcomb to the  
     64     * downstream port(s), which happens when: 
     65     *  - put_frame() is called to the splitcomb 
     66     *  - get_frame() is called to the reverse channel port. 
    5667     */ 
    5768    DIR_DOWNSTREAM, 
    5869 
    59     /* This is the direction from the downstream port to the splitcomb, 
    60      * or when get_frame() is called to the splitcomb. 
     70    /* This is the media direction from the downstream port to  
     71     * the splitcomb, which happens when: 
     72     *  - get_frame() is called to the splitcomb 
     73     *  - put_frame() is called to the reverse channel port. 
    6174     */ 
    6275    DIR_UPSTREAM 
    6376}; 
    6477 
    65  
    66  
    67 #if 0 
    68 #   define TRACE_UP_(x) PJ_LOG(5,x) 
    69 #   define TRACE_DN_(x) PJ_LOG(5,x) 
    70 #else 
    71 #   define TRACE_UP_(x) 
    72 #   define TRACE_DN_(x) 
    73 #endif 
    7478 
    7579 
     
    107111    unsigned         ch_num; 
    108112 
    109     /* Maximum burst before media flow is suspended */ 
     113    /* Maximum burst before media flow is suspended. 
     114     * With reverse port, it's possible that either end of the  
     115     * port doesn't actually process the media flow (meaning, it 
     116     * stops calling get_frame()/put_frame()). When this happens, 
     117     * the other end will encounter excessive underflow or overflow, 
     118     * depending on which direction is not actively processed by 
     119     * the stopping end. 
     120     * 
     121     * To avoid excessive underflow/overflow, the media flow will 
     122     * be suspended once underflow/overflow goes over this max_burst 
     123     * limit. 
     124     */ 
    110125    int              max_burst; 
    111126 
    112     /* Maximum NULL frames received before media flow is suspended. */ 
     127    /* When the media interface port of the splitcomb or the reverse 
     128     * channel port is registered to conference bridge, the bridge 
     129     * will transmit NULL frames to the media port when the media 
     130     * port is not receiving any audio from other slots (for example, 
     131     * when no other slots are connected to the media port). 
     132     * 
     133     * When this happens, we will generate zero frame to our buffer, 
     134     * to avoid underflow/overflow. But after too many NULL frames 
     135     * are received, we will pause the media flow instead, to save 
     136     * some processing. 
     137     * 
     138     * This value controls how many NULL frames can be received 
     139     * before we suspend media flow for a particular direction. 
     140     */ 
    113141    unsigned         max_null_frames; 
    114142 
    115     /* A reverse port need a temporary buffer to store frame 
     143    /* A reverse port need a temporary buffer to store frames 
    116144     * (because of the different phase, see splitcomb.h for details).  
    117145     * Since we can not expect get_frame() and put_frame() to be 
     
    314342    port->on_destroy = &rport_on_destroy; 
    315343 
    316  
     344    /* Buffer settings */ 
    317345    buf_cnt = options & 0xFF; 
    318346    if (buf_cnt == 0) 
     
    323351 
    324352    /* Create downstream/put buffers */ 
    325     status = pjmedia_delay_buf_create(pool, "scomb-down", 
     353    status = pjmedia_delay_buf_create(pool, "scombdb-dn", 
    326354                                      port->info.clock_rate, 
    327355                                      port->info.samples_per_frame, 
     
    333361 
    334362    /* Create upstream/get buffers */ 
    335     status = pjmedia_delay_buf_create(pool, "scomb-up", 
     363    status = pjmedia_delay_buf_create(pool, "scombdb-up", 
    336364                                      port->info.clock_rate, 
    337365                                      port->info.samples_per_frame, 
     
    446474 
    447475/* 
    448  * "Write" a multichannel frame. This would split the multichannel frame 
    449  * into individual mono channel, and write it to the appropriate port. 
     476 * "Write" a multichannel frame downstream. This would split  
     477 * the multichannel frame into individual mono channel, and write  
     478 * it to the appropriate port. 
    450479 */ 
    451480static pj_status_t put_frame(pjmedia_port *this_port,  
     
    466495            } else { 
    467496                struct reverse_port *rport = (struct reverse_port*)port; 
    468  
    469                 /* Write zero port to delaybuf so that it doesn't underflow.  
    470                  * If we don't do this, get_frame() on this direction will 
    471                  * cause delaybuf to generate missing frame and the last 
    472                  * frame transmitted to delaybuf will be replayed multiple 
    473                  * times, which doesn't sound good. 
    474                  */ 
    475497 
    476498                /* Update the number of NULL frames received. Once we have too 
     
    490512                } 
    491513 
     514                /* Write zero port to delaybuf so that it doesn't underflow.  
     515                 * If we don't do this, get_frame() on this direction will 
     516                 * cause delaybuf to generate missing frame and the last 
     517                 * frame transmitted to delaybuf will be replayed multiple 
     518                 * times, which doesn't sound good. 
     519                 */ 
     520 
    492521                /* Update rport state. */ 
    493522                op_update(rport, DIR_DOWNSTREAM, OP_PUT); 
     
    498527 
    499528                /* Generate zero frame. */ 
    500                 pjmedia_zero_samples(rport->tmp_up_buf,  
     529                pjmedia_zero_samples(sc->put_buf,  
    501530                                     this_port->info.samples_per_frame); 
    502531 
    503532                /* Put frame to delay buffer */ 
    504533                pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, 
    505                                       rport->tmp_up_buf); 
     534                                      sc->put_buf); 
    506535 
    507536            } 
     
    566595 
    567596/* 
    568  * Get a multichannel frame. 
     597 * Get a multichannel frame upstream. 
    569598 * This will get mono channel frame from each port and put the 
    570599 * mono frame into the multichannel frame. 
     
    617646            } else { 
    618647                pjmedia_zero_samples(sc->get_buf,  
    619                                       rport->base.info.samples_per_frame); 
     648                                     port->info.samples_per_frame); 
    620649            } 
    621650 
     
    628657                         this_port->info.channel_count, 
    629658                         this_port->info.samples_per_frame); 
    630  
    631  
    632659 
    633660        has_frame = PJ_TRUE; 
     
    647674static pj_status_t on_destroy(pjmedia_port *this_port) 
    648675{ 
    649     /* Nothing to do */ 
     676    /* Nothing to do for the splitcomb 
     677     * Reverse ports must be destroyed separately. 
     678     */ 
    650679    PJ_UNUSED_ARG(this_port); 
    651680 
     
    655684 
    656685/* 
    657  * Get a mono frame from a reversed phase channel. 
     686 * Put a frame in the reverse port (upstream direction). This frame 
     687 * will be picked up by get_frame() above. 
    658688 */ 
    659689static pj_status_t rport_put_frame(pjmedia_port *this_port,  
     
    666696    /* Handle NULL frame */ 
    667697    if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) { 
    668         TRACE_UP_((THIS_FILE, "Upstream write %d null samples at buf pos %d", 
    669                    this_port->info.samples_per_frame, rport->up_write_pos)); 
    670  
    671         /* Write zero port to delaybuf so that it doesn't underflow.  
    672          * If we don't do this, get_frame() on this direction will 
    673          * cause delaybuf to generate missing frame and the last 
    674          * frame transmitted to delaybuf will be replayed multiple 
    675          * times, which doesn't sound good. 
    676          */ 
    677  
    678698        /* Update the number of NULL frames received. Once we have too 
    679699         * many of this, we'll stop calling op_update() to let the 
     
    688708        } 
    689709 
     710        /* Write zero port to delaybuf so that it doesn't underflow.  
     711         * If we don't do this, get_frame() on this direction will 
     712         * cause delaybuf to generate missing frame and the last 
     713         * frame transmitted to delaybuf will be replayed multiple 
     714         * times, which doesn't sound good. 
     715         */ 
     716 
    690717        /* Update rport state. */ 
    691718        op_update(rport, DIR_UPSTREAM, OP_PUT); 
     
    730757 
    731758 
    732 /* 
    733  * Get a mono frame from a reversed phase channel. 
     759/* Get a mono frame from a reversed phase channel (downstream direction). 
     760 * The frame is put by put_frame() call to the splitcomb. 
    734761 */ 
    735762static pj_status_t rport_get_frame(pjmedia_port *this_port,  
  • pjproject/trunk/pjmedia/src/pjmedia/wsola.c

    r1838 r1844  
    3737 
    3838/* Generate extra samples, in msec */ 
    39 #define GEN_EXTRA_PTIME (0.0) 
     39#define GEN_EXTRA_PTIME (5) 
    4040 
    4141/* Number of frames in erase buffer */ 
     
    5454 
    5555 
     56/* Buffer content: 
     57 * 
     58 *   t0   time    tn 
     59 *   ----------------> 
     60 * 
     61 * +---------+-------+-------+---          --+ 
     62 * | history | frame | extra | ...empty...   | 
     63 * +---------+-------+-------+----        ---+ 
     64 * ^         ^               ^               ^ 
     65 * buf    hist_cnt        cur_cnt          buf_cnt 
     66 *           or 
     67 *       frm pointer 
     68 * 
     69 * History count (hist_cnt) is a constant value, initialized upon  
     70 * creation. 
     71 * 
     72 * At any particular time, the buffer will contain at least  
     73 * (hist_cnt+samples_per_frame) samples. 
     74 * 
     75 * A "save" operation will append the frame to the end of the  
     76 * buffer, return the samples right after history (the frm pointer), 
     77 * and shift the buffer by one frame. 
     78 */ 
     79 
     80/* WSOLA structure */ 
    5681struct pjmedia_wsola 
    5782{ 
    5883    unsigned    clock_rate;     /* Sampling rate.                       */ 
    59     pj_uint16_t samples_per_frame;/* Samples per frame.                 */ 
     84    pj_uint16_t samples_per_frame;/* Samples per frame (const)          */ 
     85    pj_uint16_t channel_count;  /* Samples per frame (const)            */ 
    6086    pj_uint16_t options;        /* Options.                             */ 
    61     pj_uint16_t hist_cnt;       /* # of history samples.                */ 
    62     pj_uint16_t buf_cnt;        /* Total buffer capacity                */ 
     87    pj_uint16_t hist_cnt;       /* # of history samples (const)         */ 
     88    pj_uint16_t buf_cnt;        /* Total buffer capacity (const)        */ 
    6389    pj_uint16_t cur_cnt;        /* Cur # of samples, inc. history       */ 
    64     pj_uint16_t template_size;  /* Template size.                       */ 
    65     pj_uint16_t min_extra;      /* Min extra samples for merging.       */ 
    66     pj_uint16_t gen_extra;      /* Generate extra samples.              */ 
     90    pj_uint16_t template_size;  /* Template size (const)                */ 
     91    pj_uint16_t min_extra;      /* Min extra samples for merging (const)*/ 
     92    pj_uint16_t gen_extra;      /* Generate extra samples (const)       */ 
    6793    pj_uint16_t expand_cnt;     /* Number of expansion currently done   */ 
    6894 
     
    124150    } 
    125151 
    126     TRACE_((THIS_FILE, "found pitch at %u", best-beg)); 
     152    /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/ 
    127153    return best; 
    128154} 
     
    208234    } 
    209235 
    210     TRACE_((THIS_FILE, "found pitch at %u", best-beg)); 
     236    /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/ 
    211237    return best; 
    212238} 
     
    293319                                          unsigned clock_rate, 
    294320                                          unsigned samples_per_frame, 
     321                                          unsigned channel_count, 
    295322                                          unsigned options, 
    296323                                          pjmedia_wsola **p_wsola) 
     
    302329    PJ_ASSERT_RETURN(clock_rate <= 65535, PJ_EINVAL); 
    303330    PJ_ASSERT_RETURN(samples_per_frame < clock_rate, PJ_EINVAL); 
     331    PJ_ASSERT_RETURN(channel_count > 0, PJ_EINVAL); 
    304332 
    305333    wsola = PJ_POOL_ZALLOC_T(pool, pjmedia_wsola); 
     
    307335    wsola->clock_rate= (pj_uint16_t) clock_rate; 
    308336    wsola->samples_per_frame = (pj_uint16_t) samples_per_frame; 
     337    wsola->channel_count = (pj_uint16_t) channel_count; 
    309338    wsola->options   = (pj_uint16_t) options; 
    310339    wsola->hist_cnt  = (pj_uint16_t)(samples_per_frame * HISTSZ); 
     
    360389    PJ_UNUSED_ARG(options); 
    361390 
    362     pjmedia_zero_samples(wsola->buf, wsola->cur_cnt); 
    363391    wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt +  
    364392                                   wsola->samples_per_frame); 
     393    pjmedia_zero_samples(wsola->buf, wsola->cur_cnt); 
    365394    return PJ_SUCCESS; 
    366395} 
     
    374403 
    375404    for (rep=1;; ++rep) { 
    376         short *start; 
    377         unsigned dist; 
    378  
    379         start = find_pitch(wsola->frm, wsola->buf,  
    380                            wsola->frm - (wsola->samples_per_frame >> 1), 
     405        short *start, *frm; 
     406        unsigned min_dist, max_dist, dist; 
     407 
     408        frm = wsola->buf + wsola->cur_cnt - frmsz; 
     409        pj_assert(frm - wsola->buf >= wsola->hist_cnt); 
     410 
     411        max_dist = wsola->hist_cnt; 
     412        min_dist = frmsz >> 1; 
     413 
     414        start = find_pitch(frm, frm - max_dist, frm - min_dist, 
    381415                           wsola->template_size, 1); 
    382416 
     417        /* Should we make sure that "start" is really aligned to 
     418         * channel #0, in case of stereo? Probably not necessary, as 
     419         * find_pitch() should have found the best match anyway. 
     420         */ 
     421 
    383422        if (wsola->options & PJMEDIA_WSOLA_NO_HANNING) { 
    384             overlapp_add_simple(wsola->mergebuf, wsola->samples_per_frame, 
    385                                 wsola->frm, start); 
     423            overlapp_add_simple(wsola->mergebuf, frmsz,frm, start); 
    386424        } else { 
    387             overlapp_add(wsola->mergebuf, wsola->samples_per_frame, 
    388                          wsola->frm, start, wsola->hanning); 
    389         } 
    390  
    391         dist = wsola->frm - start; 
    392         pjmedia_move_samples(wsola->frm + frmsz, start + frmsz,  
     425            overlapp_add(wsola->mergebuf, frmsz, frm, start, wsola->hanning); 
     426        } 
     427 
     428        /* How many new samples do we have */ 
     429        dist = frm - start; 
     430 
     431        /* Copy the "tail" (excess frame) to the end */ 
     432        pjmedia_move_samples(frm + frmsz, start + frmsz,  
    393433                             wsola->buf+wsola->cur_cnt - (start+frmsz)); 
    394434 
    395         pjmedia_copy_samples(wsola->frm, wsola->mergebuf, frmsz); 
    396  
     435        /* Copy the merged frame */ 
     436        pjmedia_copy_samples(frm, wsola->mergebuf, frmsz); 
     437 
     438        /* We have new samples */ 
    397439        wsola->cur_cnt = (pj_uint16_t)(wsola->cur_cnt + dist); 
     440 
     441        pj_assert(wsola->cur_cnt <= wsola->buf_cnt); 
     442 
    398443        generated += dist; 
    399444 
    400445        if (generated >= needed) { 
    401             assert(wsola->cur_cnt <= wsola->buf_cnt); 
    402446            TRACE_((THIS_FILE, "WSOLA frame expanded after %d iterations",  
    403447                    rep)); 
     
    469513    if (prev_lost && extra >= wsola->min_extra) { 
    470514        short *dst = wsola->buf + wsola->hist_cnt + wsola->samples_per_frame; 
    471         unsigned i; 
    472  
     515 
     516        /* Smoothen the transition. This will also erase the excess 
     517         * samples 
     518         */ 
    473519        overlapp_add_simple(dst, extra, dst, frm); 
    474520 
    475         for (i=extra; i<wsola->samples_per_frame; ++i) 
    476             dst[i] = frm[i]; 
    477  
    478          
     521        /* Copy remaining samples from the frame */ 
     522        pjmedia_copy_samples(dst+extra, frm+extra,  
     523                             wsola->samples_per_frame-extra); 
     524 
     525        /* Retrieve frame */ 
    479526        pjmedia_copy_samples(frm, wsola->frm, wsola->samples_per_frame); 
     527 
     528        /* Remove excess samples */ 
    480529        wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt +  
    481530                                       wsola->samples_per_frame); 
     531 
     532        /* Shift buffer */ 
    482533        pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, 
    483534                              wsola->cur_cnt); 
     
    490541        } 
    491542 
     543        /* Append frame */ 
    492544        pjmedia_copy_samples(wsola->buf + wsola->cur_cnt, frm,  
    493545                             wsola->samples_per_frame); 
     546 
     547        /* Retrieve frame */ 
    494548        pjmedia_copy_samples(frm, wsola->frm,  
    495549                             wsola->samples_per_frame); 
     550 
     551        /* Shift buffer */ 
    496552        pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, 
    497553                             wsola->cur_cnt); 
  • pjproject/trunk/pjmedia/src/test/wsola_test.c

    r1833 r1844  
    66#include <assert.h> 
    77 
    8 #define CLOCK_RATE          44100 
     8#define CLOCK_RATE          16000 
    99#define SAMPLES_PER_FRAME   (10 * CLOCK_RATE / 1000) 
    1010 
     
    8686    if (!out) return 1; 
    8787 
    88     pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 0, &wsola); 
     88    pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola); 
    8989 
    9090    samples = 0; 
     
    201201    if (!out) return 1; 
    202202 
    203     pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 0, &wsola); 
     203    pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola); 
    204204 
    205205    elapsed.u64 = 0; 
     
    320320    pj_caching_pool cp; 
    321321    pj_pool_t *pool; 
    322     int rc; 
     322    int i, rc; 
    323323 
    324324    //test_find_pitch(); 
     
    330330    srand(2); 
    331331 
    332     rc = expand(pool, "beet44.pcm", "output.pcm", 0, 0, 0); 
    333     //rc = compress(pool, "beet44.pcm", "output.pcm", 2); 
     332    rc = expand(pool, "galileo16.pcm", "temp1.pcm", 20, 0, 0); 
     333    rc = compress(pool, "temp1.pcm", "output.pcm", 1); 
     334 
     335    for (i=0; i<2; ++i) { 
     336        rc = expand(pool, "output.pcm", "temp1.pcm", 20, 0, 0); 
     337        rc = compress(pool, "temp1.pcm", "output.pcm", 1); 
     338    } 
    334339 
    335340    if (rc != 0) { 
Note: See TracChangeset for help on using the changeset viewer.