Changeset 1844
- Timestamp:
- Mar 4, 2008 3:37:45 PM (17 years ago)
- Location:
- pjproject/trunk/pjmedia
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/wsola.h
r1831 r1844 76 76 * @param clock_rate Sampling rate of audio playback. 77 77 * @param samples_per_frame Number of samples per frame. 78 * @param channel_count Number of channels. 78 79 * @param options Option flags, bitmask combination of 79 80 * #pjmedia_wsola_option. … … 85 86 unsigned clock_rate, 86 87 unsigned samples_per_frame, 88 unsigned channel_count, 87 89 unsigned options, 88 90 pjmedia_wsola **p_wsola); -
pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c
r1840 r1844 158 158 } 159 159 160 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 160 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, 161 161 PJMEDIA_WSOLA_NO_PLC, &b->wsola); 162 162 if (status != PJ_SUCCESS) -
pjproject/trunk/pjmedia/src/pjmedia/splitcomb.c
r1840 r1844 49 49 #define OP_GET (-1) 50 50 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 */ 52 61 enum sc_dir 53 62 { 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. 56 67 */ 57 68 DIR_DOWNSTREAM, 58 69 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. 61 74 */ 62 75 DIR_UPSTREAM 63 76 }; 64 77 65 66 67 #if 068 # define TRACE_UP_(x) PJ_LOG(5,x)69 # define TRACE_DN_(x) PJ_LOG(5,x)70 #else71 # define TRACE_UP_(x)72 # define TRACE_DN_(x)73 #endif74 78 75 79 … … 107 111 unsigned ch_num; 108 112 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 */ 110 125 int max_burst; 111 126 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 */ 113 141 unsigned max_null_frames; 114 142 115 /* A reverse port need a temporary buffer to store frame 143 /* A reverse port need a temporary buffer to store frames 116 144 * (because of the different phase, see splitcomb.h for details). 117 145 * Since we can not expect get_frame() and put_frame() to be … … 314 342 port->on_destroy = &rport_on_destroy; 315 343 316 344 /* Buffer settings */ 317 345 buf_cnt = options & 0xFF; 318 346 if (buf_cnt == 0) … … 323 351 324 352 /* Create downstream/put buffers */ 325 status = pjmedia_delay_buf_create(pool, "scomb -down",353 status = pjmedia_delay_buf_create(pool, "scombdb-dn", 326 354 port->info.clock_rate, 327 355 port->info.samples_per_frame, … … 333 361 334 362 /* Create upstream/get buffers */ 335 status = pjmedia_delay_buf_create(pool, "scomb -up",363 status = pjmedia_delay_buf_create(pool, "scombdb-up", 336 364 port->info.clock_rate, 337 365 port->info.samples_per_frame, … … 446 474 447 475 /* 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. 450 479 */ 451 480 static pj_status_t put_frame(pjmedia_port *this_port, … … 466 495 } else { 467 496 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 will471 * cause delaybuf to generate missing frame and the last472 * frame transmitted to delaybuf will be replayed multiple473 * times, which doesn't sound good.474 */475 497 476 498 /* Update the number of NULL frames received. Once we have too … … 490 512 } 491 513 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 492 521 /* Update rport state. */ 493 522 op_update(rport, DIR_DOWNSTREAM, OP_PUT); … … 498 527 499 528 /* Generate zero frame. */ 500 pjmedia_zero_samples( rport->tmp_up_buf,529 pjmedia_zero_samples(sc->put_buf, 501 530 this_port->info.samples_per_frame); 502 531 503 532 /* Put frame to delay buffer */ 504 533 pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, 505 rport->tmp_up_buf);534 sc->put_buf); 506 535 507 536 } … … 566 595 567 596 /* 568 * Get a multichannel frame .597 * Get a multichannel frame upstream. 569 598 * This will get mono channel frame from each port and put the 570 599 * mono frame into the multichannel frame. … … 617 646 } else { 618 647 pjmedia_zero_samples(sc->get_buf, 619 rport->base.info.samples_per_frame);648 port->info.samples_per_frame); 620 649 } 621 650 … … 628 657 this_port->info.channel_count, 629 658 this_port->info.samples_per_frame); 630 631 632 659 633 660 has_frame = PJ_TRUE; … … 647 674 static pj_status_t on_destroy(pjmedia_port *this_port) 648 675 { 649 /* Nothing to do */ 676 /* Nothing to do for the splitcomb 677 * Reverse ports must be destroyed separately. 678 */ 650 679 PJ_UNUSED_ARG(this_port); 651 680 … … 655 684 656 685 /* 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. 658 688 */ 659 689 static pj_status_t rport_put_frame(pjmedia_port *this_port, … … 666 696 /* Handle NULL frame */ 667 697 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 will673 * cause delaybuf to generate missing frame and the last674 * frame transmitted to delaybuf will be replayed multiple675 * times, which doesn't sound good.676 */677 678 698 /* Update the number of NULL frames received. Once we have too 679 699 * many of this, we'll stop calling op_update() to let the … … 688 708 } 689 709 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 690 717 /* Update rport state. */ 691 718 op_update(rport, DIR_UPSTREAM, OP_PUT); … … 730 757 731 758 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. 734 761 */ 735 762 static pj_status_t rport_get_frame(pjmedia_port *this_port, -
pjproject/trunk/pjmedia/src/pjmedia/wsola.c
r1838 r1844 37 37 38 38 /* Generate extra samples, in msec */ 39 #define GEN_EXTRA_PTIME ( 0.0)39 #define GEN_EXTRA_PTIME (5) 40 40 41 41 /* Number of frames in erase buffer */ … … 54 54 55 55 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 */ 56 81 struct pjmedia_wsola 57 82 { 58 83 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) */ 60 86 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) */ 63 89 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) */ 67 93 pj_uint16_t expand_cnt; /* Number of expansion currently done */ 68 94 … … 124 150 } 125 151 126 TRACE_((THIS_FILE, "found pitch at %u", best-beg));152 /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/ 127 153 return best; 128 154 } … … 208 234 } 209 235 210 TRACE_((THIS_FILE, "found pitch at %u", best-beg));236 /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/ 211 237 return best; 212 238 } … … 293 319 unsigned clock_rate, 294 320 unsigned samples_per_frame, 321 unsigned channel_count, 295 322 unsigned options, 296 323 pjmedia_wsola **p_wsola) … … 302 329 PJ_ASSERT_RETURN(clock_rate <= 65535, PJ_EINVAL); 303 330 PJ_ASSERT_RETURN(samples_per_frame < clock_rate, PJ_EINVAL); 331 PJ_ASSERT_RETURN(channel_count > 0, PJ_EINVAL); 304 332 305 333 wsola = PJ_POOL_ZALLOC_T(pool, pjmedia_wsola); … … 307 335 wsola->clock_rate= (pj_uint16_t) clock_rate; 308 336 wsola->samples_per_frame = (pj_uint16_t) samples_per_frame; 337 wsola->channel_count = (pj_uint16_t) channel_count; 309 338 wsola->options = (pj_uint16_t) options; 310 339 wsola->hist_cnt = (pj_uint16_t)(samples_per_frame * HISTSZ); … … 360 389 PJ_UNUSED_ARG(options); 361 390 362 pjmedia_zero_samples(wsola->buf, wsola->cur_cnt);363 391 wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt + 364 392 wsola->samples_per_frame); 393 pjmedia_zero_samples(wsola->buf, wsola->cur_cnt); 365 394 return PJ_SUCCESS; 366 395 } … … 374 403 375 404 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, 381 415 wsola->template_size, 1); 382 416 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 383 422 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); 386 424 } 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, 393 433 wsola->buf+wsola->cur_cnt - (start+frmsz)); 394 434 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 */ 397 439 wsola->cur_cnt = (pj_uint16_t)(wsola->cur_cnt + dist); 440 441 pj_assert(wsola->cur_cnt <= wsola->buf_cnt); 442 398 443 generated += dist; 399 444 400 445 if (generated >= needed) { 401 assert(wsola->cur_cnt <= wsola->buf_cnt);402 446 TRACE_((THIS_FILE, "WSOLA frame expanded after %d iterations", 403 447 rep)); … … 469 513 if (prev_lost && extra >= wsola->min_extra) { 470 514 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 */ 473 519 overlapp_add_simple(dst, extra, dst, frm); 474 520 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 */ 479 526 pjmedia_copy_samples(frm, wsola->frm, wsola->samples_per_frame); 527 528 /* Remove excess samples */ 480 529 wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt + 481 530 wsola->samples_per_frame); 531 532 /* Shift buffer */ 482 533 pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, 483 534 wsola->cur_cnt); … … 490 541 } 491 542 543 /* Append frame */ 492 544 pjmedia_copy_samples(wsola->buf + wsola->cur_cnt, frm, 493 545 wsola->samples_per_frame); 546 547 /* Retrieve frame */ 494 548 pjmedia_copy_samples(frm, wsola->frm, 495 549 wsola->samples_per_frame); 550 551 /* Shift buffer */ 496 552 pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, 497 553 wsola->cur_cnt); -
pjproject/trunk/pjmedia/src/test/wsola_test.c
r1833 r1844 6 6 #include <assert.h> 7 7 8 #define CLOCK_RATE 441008 #define CLOCK_RATE 16000 9 9 #define SAMPLES_PER_FRAME (10 * CLOCK_RATE / 1000) 10 10 … … 86 86 if (!out) return 1; 87 87 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); 89 89 90 90 samples = 0; … … 201 201 if (!out) return 1; 202 202 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); 204 204 205 205 elapsed.u64 = 0; … … 320 320 pj_caching_pool cp; 321 321 pj_pool_t *pool; 322 int rc;322 int i, rc; 323 323 324 324 //test_find_pitch(); … … 330 330 srand(2); 331 331 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 } 334 339 335 340 if (rc != 0) {
Note: See TracChangeset
for help on using the changeset viewer.