1/*---------------------------------------------------------------------------* 2 * ann_api.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20#include <stdlib.h> 21#include <string.h> 22#ifndef _RTT 23#include <stdio.h> 24#endif 25 26#ifdef unix 27#include <unistd.h> 28#endif 29#include <assert.h> 30 31#include "duk_args.h" 32#ifndef _RTT 33#include "duk_io.h" 34#endif 35 36#include "simapi.h" 37#include "portable.h" 38#include "fpi_tgt.h" 39#include "fronttyp.h" 40#include "sh_down.h" 41 42#define REMOVE_QUIET_CHUNKS 1 43 44/***************************************************************************************** 45 * 46 *****************************************************************************************/ 47CA_Annotation* CA_AllocateAnnotation(void) 48{ 49 CA_Annotation* hAnnotation = NULL; 50 51 TRY_CA_EXCEPT 52 53 hAnnotation = (CA_Annotation*) VAR_ALLOCATE_CLR(1, sizeof(CA_Annotation), "ca.CA_Annotation"); 54 hAnnotation->data = allocate_annotation(); 55 hAnnotation->has_segments = False; 56 hAnnotation->ca_rtti = CA_ANNOTATION_SIGNATURE; 57 hAnnotation->label = NULL; 58 hAnnotation->data->snr = 0; 59 return hAnnotation; 60 BEG_CATCH_CA_EXCEPT; 61 END_CATCH_CA_EXCEPT(hAnnotation); 62} 63 64 65/***************************************************************************************** 66 * 67 *****************************************************************************************/ 68void CA_FreeAnnotation(CA_Annotation* hAnnotation) 69{ 70 TRY_CA_EXCEPT 71 72 ASSERT(hAnnotation); 73 74 if (hAnnotation->has_segments) 75 { 76 SERVICE_ERROR(ANNOTATE_SEGMENTS_EXIST); 77 } 78 79 free_annotation(hAnnotation->data); 80 VAR_FREE(hAnnotation, "hAnnotation"); 81 82 BEG_CATCH_CA_EXCEPT 83 END_CATCH_CA_EXCEPT(hAnnotation) 84} 85 86 87/***************************************************************************************** 88 * 89 *****************************************************************************************/ 90void CA_ClearAnnotation(CA_Annotation* hAnnotation) 91{ 92 TRY_CA_EXCEPT 93 94 /* if( !hAnnotation->has_segments ) 95 { 96 SERVICE_ERROR ( ANNOTATE_NO_SEGMENTS ); 97 } 98 */ 99 annotation_delete_segment_info(hAnnotation->data); 100 if (hAnnotation->label) 101 VAR_FREE(hAnnotation->label, "annotation_label"); 102 hAnnotation->label = NULL; 103 hAnnotation->has_segments = False; 104 105 BEG_CATCH_CA_EXCEPT 106 END_CATCH_CA_EXCEPT(hAnnotation) 107} 108 109 110/***************************************************************************************** 111 * 112 *****************************************************************************************/ 113int CA_AnnotateFromResults(CA_Annotation* hAnnotation, CA_Recog *hRecog) 114{ 115 TRY_CA_EXCEPT 116 117 int seg_cnt = 0; 118 119 ASSERT(hRecog); 120 ASSERT(hAnnotation); 121 122 if (hAnnotation->has_segments) 123 { 124 SERVICE_ERROR(ANNOTATE_SEGMENTS_EXIST); 125 } 126 seg_cnt = annotation_from_results(hAnnotation->data, &hRecog->rec); 127 128 if (hAnnotation->data->numWords > 0) 129 { 130 annotation_decorate_labels(hAnnotation->data, hAnnotation->label); 131 hAnnotation->has_segments = True; 132 } 133 134 return (hAnnotation->data->numWords); 135 136 BEG_CATCH_CA_EXCEPT 137 END_CATCH_CA_EXCEPT(hAnnotation) 138} 139 140 141/***************************************************************************************** 142 * 143 *****************************************************************************************/ 144int CA_AnnotateFromVoicing(CA_Annotation* hAnnotation, CA_Utterance *hUtterance, CA_Pattern *hPattern) 145{ 146 TRY_CA_EXCEPT 147 148 ASSERT(hAnnotation); 149 ASSERT(hUtterance); 150 ASSERT(hPattern); 151 152 if (hAnnotation->has_segments) 153 { 154 SERVICE_ERROR(ANNOTATE_SEGMENTS_EXIST); 155 } 156 157 annotation_from_voicing(hAnnotation->data, &hUtterance->data, hPattern->data.prep); 158 159 if (hAnnotation->data->numWords > 0) 160 { 161 hAnnotation->has_segments = True; 162 } 163 164 return (hAnnotation->data->numWords); 165 166 BEG_CATCH_CA_EXCEPT 167 END_CATCH_CA_EXCEPT(hAnnotation) 168} 169 170 171/***************************************************************************************** 172 * 173 *****************************************************************************************/ 174void CA_SaveAnnotation(CA_Annotation* hAnnotation, char* FileName) 175{ 176 TRY_CA_EXCEPT 177#ifndef _RTT 178 179 ASSERT(hAnnotation); 180 181 if (!hAnnotation->has_segments) 182 { 183 SERVICE_ERROR(ANNOTATE_NO_SEGMENTS); 184 } 185 save_annotations(hAnnotation->data, FileName); 186 return; 187#else 188 log_report("RTT not in module\n"); 189 SERVICE_ERROR(FEATURE_NOT_SUPPORTED); 190 return; 191#endif 192 BEG_CATCH_CA_EXCEPT 193 END_CATCH_CA_EXCEPT(hAnnotation) 194 195} 196 197 198/***************************************************************************************** 199 * 200 *****************************************************************************************/ 201void CA_SetAnnotationLabel(CA_Annotation *hAnnotation, char *label) 202{ 203 TRY_CA_EXCEPT 204 205 ASSERT(hAnnotation); 206 ASSERT(label); 207 208 if ((strchr(label, '<') || (strchr(label, '>')))) 209 SERVICE_ERROR(BAD_LABEL); 210 if (hAnnotation->label) 211 VAR_FREE(hAnnotation, "annotation_label"); 212 hAnnotation->label = NULL; 213 hAnnotation->label = (char *) VAR_ALLOCATE(strlen(label) + 1, sizeof(char), "ca.annotation_label"); 214 strcpy(hAnnotation->label, label); 215 216 BEG_CATCH_CA_EXCEPT 217 END_CATCH_CA_EXCEPT(hAnnotation) 218} 219 220 221/***************************************************************************************** 222 * 223 *****************************************************************************************/ 224 225int CA_GetAnnotationLabel(CA_Annotation *hAnnotation, char *label, int length) 226{ 227 int required_length; 228 229 TRY_CA_EXCEPT 230 231 ASSERT(hAnnotation); 232 ASSERT(label); 233 234 if (length <= 0) 235 SERVICE_ERROR(BAD_ARGUMENT); 236 if (hAnnotation->label) 237 { 238 required_length = strlen(hAnnotation->label) + 1; 239 if (required_length > length) 240 { 241 if (length > 1) 242 { 243 strncpy(label, hAnnotation->label, length - 2); 244 label[length - 1] = '\0'; 245 } 246 else 247 *label = '\0'; 248 return (required_length); 249 } 250 else 251 strcpy(label, hAnnotation->label); 252 return (0); 253 } 254 *label = '\0'; 255 return (0); 256 257 BEG_CATCH_CA_EXCEPT 258 END_CATCH_CA_EXCEPT(hAnnotation) 259} 260 261 262/***************************************************************************************** 263 * 264 *****************************************************************************************/ 265int CA_CompareAnnotations(CA_Annotation *testAnnotation, CA_Annotation *refAnnotation) 266{ 267 TRY_CA_EXCEPT 268 269 int score; 270 271 ASSERT(testAnnotation); 272 ASSERT(refAnnotation); 273 274 if ((!testAnnotation->has_segments) || (!refAnnotation->has_segments)) 275 { 276 SERVICE_ERROR(ANNOTATE_NO_SEGMENTS); 277 } 278 279 score = annotation_compare(testAnnotation->data, refAnnotation->data); 280 281 return (score); 282 283 BEG_CATCH_CA_EXCEPT 284 END_CATCH_CA_EXCEPT(testAnnotation) 285} 286 287 288/***************************************************************************************** 289 * 290 *****************************************************************************************/ 291int CA_GetAnnotationSegmentCount(CA_Annotation *hAnnotation) 292{ 293 TRY_CA_EXCEPT 294 295 ASSERT(hAnnotation); 296 297 if (!hAnnotation->has_segments) 298 return (0); 299 ASSERT(hAnnotation->data); 300 return (hAnnotation->data->numWords); 301 302 BEG_CATCH_CA_EXCEPT 303 END_CATCH_CA_EXCEPT(hAnnotation) 304} 305 306 307/***************************************************************************************** 308 * 309 *****************************************************************************************/ 310int CA_SegmentUtterance(CA_Annotation* hAnnotation, CA_Utterance* hUtt, 311 CA_Pattern* hPattern) 312{ 313 TRY_CA_EXCEPT 314 int seg_cnt = 0; 315 int ii; 316 int total_length; 317 int num_segments_to_keep = 0; 318 int no_beep = False; 319 int has_trailing_silence = False; 320#if REMOVE_QUIET_CHUNKS 321 int jj; 322 featdata *peakC0; 323 int max_peak; 324#endif 325 ASSERT(hAnnotation); 326 ASSERT(hUtt); 327 ASSERT(hPattern); 328 ASSERT(hPattern->data.prep); 329 330#if DO_SUBTRACTED_SEGMENTATION 331 if (hPattern->data.prep->is_setup_for_noise == False) 332 { 333 SERVICE_ERROR(PATTERN_NOT_SETUP_FOR_NOISE); 334 } 335#endif 336 if (hUtt->data.utt_type == FILE_OUTPUT) 337 SERVICE_ERROR(UTTERANCE_INVALID); 338 if (hUtt->data.utt_type != FILE_INPUT && 339 hUtt->data.utt_type != LIVE_INPUT) 340 { 341 SERVICE_ERROR(UTTERANCE_NOT_INITIALISED); 342 } 343 if (isFrameBufferActive(hUtt->data.gen_utt.frame)) 344 { 345 SERVICE_ERROR(FB_INVALID_STATE); 346 } 347 if (!hAnnotation->label) 348 { 349 SERVICE_ERROR(ANNOTATE_NO_LABEL); 350 } 351 if (hAnnotation->has_segments) 352 { 353 SERVICE_ERROR(ANNOTATE_SEGMENTS_EXIST); 354 } 355 356 hAnnotation->has_segments = False; 357 /* Segment the utterance using DP on c0 */ 358 seg_cnt = annotation_segment_utterance(hAnnotation->data, 359 &hUtt->data, 360 hPattern->data.prep, 361 hAnnotation->label, &has_trailing_silence); 362 if (seg_cnt <= 0) 363 { 364 if (seg_cnt < 0) 365 return (seg_cnt); 366 return (NO_SEGMENTS_FOUND); 367 } 368 /* SPECIAL OPERATIONS: 369 ** Now manipulate the segmentation to order: 370 1. Remove parts of a multi-segment utt that are % below some energy 371 measure of the "loudest" segment. NB this may remove a final chunk 372 that previously caused a NO_TRAILING_SILENCE 373 2. Declare it invalid if the first chunk is within n frames of the start. 374 3. Delete unwanted leading segment(s). The criteria are: 375 3a. Min/max segment duration. 376 3b. Min silence gap to next chunk 377 4. Check min/max overall length. 378 NB check MAX then look for trailing silence. 379 */ 380#if REMOVE_QUIET_CHUNKS 381 /* 1. Remove parts of a multi-segment utt that are % below some energy 382 measure of the "loudest" segment. */ 383 /* TODO :Add par hPattern->data.prep->end.min_segment_rel_c0 */ 384 if ((hPattern->data.prep->end.min_segment_rel_c0 > 0) && (seg_cnt > 1)) 385 { 386 peakC0 = (featdata*) VAR_ALLOCATE_CLR(seg_cnt, sizeof(featdata), "ca.peakC0"); 387 max_peak = 0; 388 for (ii = 0; ii < seg_cnt; ii++) 389 { 390 peakC0[ii] = get_c0_peak_over_range(hUtt->data.gen_utt.frame, 391 hAnnotation->data->tcp[ii].begin, 392 hAnnotation->data->tcp[ii].begin 393 + hAnnotation->data->tcp[ii].end); 394 if (peakC0[ii] > max_peak) 395 { 396 max_peak = peakC0[ii]; 397 } 398 } 399 max_peak = max_peak - hPattern->data.prep->end.min_segment_rel_c0; 400 for (ii = 0; ii < seg_cnt; ii++) 401 { 402 if (peakC0[ii] < max_peak) 403 { 404 annotation_delete_segment(hAnnotation->data, ii); 405 /* reset flag if last seg is deleted */ 406 if (!has_trailing_silence && (ii == seg_cnt - 1)) 407 { 408 has_trailing_silence = True; 409 } 410 for (jj = ii; jj < seg_cnt - 1; jj++) 411 { 412 peakC0[jj] = peakC0[jj+1]; 413 } 414 seg_cnt--; 415 ii--; 416 } 417 } 418 VAR_FREE((char *) peakC0, "peakC0"); 419 if (seg_cnt < 1) 420 { 421 422 return (seg_cnt); 423 } 424 } 425#endif 426 427 /* 428 ** 2. Declare it invalid if the first chunk is within n frames of the start. 429 */ 430 if (hAnnotation->data->tcp[0].begin 431 < hPattern->data.prep->end.min_initial_quiet_frames) 432 { 433 annotation_delete_segment_info(hAnnotation->data); 434 hAnnotation->has_segments = False; 435 return (INITIAL_SILENCE_NOT_FOUND) ; 436 } 437 438 /* 439 ** 3. Delete unwanted leading segment(s) - a beep, for example. 440 */ 441 if (hPattern->data.prep->end.delete_leading_segments > 0) 442 { 443 if (hPattern->data.prep->end.leading_segment_accept_if_not_found) 444 num_segments_to_keep = 1; 445 else 446 num_segments_to_keep = 0; 447 if (!annotation_delete_leading_segments(hAnnotation->data, 448 hPattern->data.prep->end.delete_leading_segments, 449 num_segments_to_keep, 450 hPattern->data.prep->end.leading_segment_min_frames, 451 hPattern->data.prep->end.leading_segment_max_frames, 452 hPattern->data.prep->end.leading_segment_min_silence_gap_frames)) 453 { 454 if (hPattern->data.prep->end.leading_segment_accept_if_not_found) 455 no_beep = True; 456 else 457 { 458 annotation_delete_segment_info(hAnnotation->data); 459 hAnnotation->has_segments = False; 460 return (INITIAL_SEGMENT_NOT_IDENTIFIED) ; 461 } 462 } 463 } 464 465 /* 466 ** 4. Check min/max overall length. "Beep" has already been deleted. 467 */ 468 total_length = 0; 469 for (ii = 0; ii < hAnnotation->data->numWords; ii++) 470 total_length += hAnnotation->data->tcp[ii].end; 471 if (total_length > hPattern->data.prep->end.max_annotation_frames) 472 { 473 annotation_delete_segment_info(hAnnotation->data); 474 hAnnotation->has_segments = False; 475 return (ANNOTATION_TOO_LONG); 476 } 477 /* Check for TOO LONG before checking for trailing silence - recognizer gernerally 478 terminates on speech when it runs out of hypos. BP */ 479 if (!has_trailing_silence) 480 { 481 annotation_delete_segment_info(hAnnotation->data); 482 hAnnotation->has_segments = False; 483 return (NO_TRAILING_SILENCE); 484 } 485 if (total_length < hPattern->data.prep->end.min_annotation_frames) 486 { 487 annotation_delete_segment_info(hAnnotation->data); 488 hAnnotation->has_segments = False; 489 return (ANNOTATION_TOO_SHORT); 490 } 491 492 if (hAnnotation->data->numWords > 0) 493 { 494 annotation_decorate_labels(hAnnotation->data, hAnnotation->label); 495 hAnnotation->has_segments = True; 496 } 497#if DEBUG 498 if (no_beep) 499 log_report("W: Initial segment not found\n"); 500#endif 501 ASSERT(hAnnotation->data->numWords > 0); 502 return (hAnnotation->data->numWords); 503 BEG_CATCH_CA_EXCEPT 504 END_CATCH_CA_EXCEPT(hAnnotation) 505} 506 507int CA_GetAnnotationSNR(CA_Annotation* hAnnotation) 508{ 509 TRY_CA_EXCEPT 510 511 ASSERT(hAnnotation); 512#if DO_SUBTRACTED_SEGMENTATION 513 return hAnnotation->data->snr; 514#endif 515 /* SERVICE_ERROR (FEATURE_NOT_SUPPORTED); */ 516 log_report("W: CA_GetAnnotationSNR - function not supported.\n"); 517 return 0; 518 BEG_CATCH_CA_EXCEPT 519 END_CATCH_CA_EXCEPT(hAnnotation) 520 521} 522 523/***************************************************************************************** 524 * TODO : wrap this into a lower level function 525 *****************************************************************************************/ 526void CA_GetAnnotationData(CA_Annotation* hAnnotation, int id, 527 int* begin, int* end, char* buff, int buffLen) 528{ 529 TRY_CA_EXCEPT 530 531 ASSERT(hAnnotation); 532 533 if ((id < 0) || (id >= hAnnotation->data->numWords)) 534 SERVICE_ERROR(BAD_INDEX); 535 if (!hAnnotation->has_segments) 536 { 537 SERVICE_ERROR(ANNOTATE_NO_SEGMENTS); 538 } 539 540 annotation_get_data(hAnnotation->data, id, begin, end, buff, buffLen); 541 542 BEG_CATCH_CA_EXCEPT 543 END_CATCH_CA_EXCEPT(hAnnotation) 544} 545 546 547/***************************************************************************************** 548 * 549 *****************************************************************************************/ 550int CA_AddUttSegmentsToAcousticWhole(CA_Acoustic *hAcoust, CA_Pattern *hPattern, 551 CA_Utterance *hUtt, CA_Annotation *hAnnotation) 552{ 553 int retCode; 554 TRY_CA_EXCEPT 555 556 ASSERT(hAcoust); 557 ASSERT(hPattern); 558 ASSERT(hUtt); 559 ASSERT(hAnnotation); 560 if (hPattern->setup_whole) 561 SERVICE_ERROR(PATTERN_ALREADY_SETUP); 562 563 if (!hAnnotation->has_segments) 564 { 565 SERVICE_ERROR(ANNOTATE_NO_SEGMENTS); 566 } 567 if (!hAnnotation->label) 568 SERVICE_ERROR(ANNOTATE_NO_LABEL); 569 if (CA_IsAcousticWholeModelExtant(hAcoust, hAnnotation->label)) 570 return (0); /* TODO: ERROR CODE? */ 571 572 if (!hAcoust->acc.base_model) 573 { 574 hAcoust->acc.base_model = allocate_hmm(0, &hAcoust->acc.base_sort); 575 hAcoust->acc.base_model->dim = hPattern->data.prep->dim; 576 hAcoust->acc.num_pars = hAcoust->acc.base_model->dim; 577 hAcoust->acc.mod_type = SEGM; 578 hAcoust->acc.mod_style = SEG_STYLE; 579#if USE_CONTEXT_MASK 580 construct_context_groups_for_wholeword(&hAcoust->acc); 581#endif 582 583 } 584 else 585 if (hAcoust->acc.base_model->dim != hPattern->data.prep->dim) 586 SERVICE_ERROR(UTTERANCE_DIMEN_MISMATCH); 587 /* Redundant. We now add the whole set of segments. 588 if ((id < 0) || (id >= hAnnotation->data->numWords)) 589 SERVICE_ERROR ( BAD_INDEX ); 590 */ 591 /* This fn now returns number of models added */ 592 retCode = annotation_add_utt_segment_to_acoustic(&hAcoust->acc, 593 hPattern->data.prep, 594 &hUtt->data, 595 hAnnotation->data, 596 hAnnotation->label, 597 hAcoust->has_backup_means); 598 if (retCode > 0) 599 { 600 hAcoust->is_loaded = True; 601 } 602 return retCode; 603 BEG_CATCH_CA_EXCEPT 604 END_CATCH_CA_EXCEPT(hAcoust) 605} 606 607 608 609int CA_LocateBeepInUtterance(CA_Annotation* hAnnotation, 610 CA_Utterance* hUtterance, 611 CA_Utterance* hBeepUtterance, 612 CA_Pattern *hPattern, 613 int beep_start_point) 614{ 615 int start, end; 616 int success; 617 TRY_CA_EXCEPT 618 619 ASSERT(hUtterance); 620 ASSERT(hBeepUtterance); 621 ASSERT(hAnnotation); 622 ASSERT(hAnnotation->data); 623 ASSERT(hPattern->data.prep); 624 625 start = end = 0; 626 annotation_create_tcp_entry(hAnnotation->data, NULL); /* null label avoids alloc */ 627 success = detect_beep_by_shape(hPattern->data.prep, &hBeepUtterance->data, &hUtterance->data, 628 &start, &end); 629 if (success >= 0) 630 { 631 hAnnotation->data->tcp[0].begin = start; 632 hAnnotation->data->tcp[0].end = end - start; 633 } 634 /* If beep detection fails, back off to a fixed speech start point */ 635 else 636 { 637 hAnnotation->data->tcp[0].begin = beep_start_point; 638 hAnnotation->data->tcp[0].end = hPattern->data.prep->end.beep_size; 639 } 640 annotation_decorate_labels(hAnnotation->data, hAnnotation->label); 641 hAnnotation->has_segments = True; 642 /* 643 ** Call fn to diff the utts' c0 profiles here. 644 ** Stuff the annotation object with the beep start and end points. 645 */ 646 if (success >= 0) 647 return (True); 648 else 649 return (False); 650 651 BEG_CATCH_CA_EXCEPT 652 END_CATCH_CA_EXCEPT(hAcoust) 653} 654 655 656int CA_CorrectAnnotationForBeep(CA_Annotation* hAnnotation, 657 CA_Annotation* hBeepAnnotation) 658{ 659 int beep_start; 660 int beep_end; 661 int chopped_frames; 662 663 TRY_CA_EXCEPT 664 665 ASSERT(hAnnotation); 666 ASSERT(hBeepAnnotation); 667 ASSERT(hAnnotation->data); 668 ASSERT(hBeepAnnotation->data); 669 ASSERT(hAnnotation->label); 670 /* 671 ** Correct annotation's start point if necessary by moving it 672 ** forward of the end of the beep. 673 */ 674 if ((hAnnotation->data->numWords <= 0) || (hBeepAnnotation->data->numWords <= 0)) 675 return (hAnnotation->data->numWords); 676 ASSERT(hBeepAnnotation->data->numWords == 1); /* valid? */ 677 678 /* NB speech end is length, not endpoint! */ 679 beep_start = hBeepAnnotation->data->tcp[0].begin; 680 beep_end = hBeepAnnotation->data->tcp[hBeepAnnotation->data->numWords-1].begin 681 + hBeepAnnotation->data->tcp[hBeepAnnotation->data->numWords-1].end; 682 683#if DEBUG && 0 684 printf("Speech1 begin %d, Speech1 end %d\nBeep begin %d\tBeep end\n", 685 hAnnotation->data->tcp[0].begin, 686 hAnnotation->data->tcp[0].begin + hAnnotation->data->tcp[0].end, 687 beep_start, beep_end); 688 689 690#endif 691 692 693 /* Delete all speech segments that finish before or at the end of beep. 694 WARNING: You must re-label the annotation segments so that they begin 695 at 0! i.e. {Name[0] ~Name[1] }Name[2] 696 */ 697 while ((hAnnotation->data->numWords > 0) 698 && ((hAnnotation->data->tcp[0].begin + hAnnotation->data->tcp[0].end) <= beep_end)) 699 { 700 annotation_delete_segment(hAnnotation->data, 0); 701 } 702 if (hAnnotation->data->numWords == 0) 703 return (hAnnotation->data->numWords); 704 705 /* Speech before end of beep? - chop it out. 706 */ 707 if (beep_end > hAnnotation->data->tcp[0].begin) 708 { 709 ASSERT(beep_end <= (hAnnotation->data->tcp[hAnnotation->data->numWords-1].begin 710 + hAnnotation->data->tcp[hAnnotation->data->numWords-1].end)); /* valid? */ 711 chopped_frames = beep_end - hAnnotation->data->tcp[0].begin; 712 hAnnotation->data->tcp[0].begin += chopped_frames; 713 hAnnotation->data->tcp[0].end -= chopped_frames; 714 ASSERT(hAnnotation->data->tcp[0].end >= 0); 715 } 716 annotation_decorate_labels(hAnnotation->data, hAnnotation->label); 717 return (hAnnotation->data->numWords); 718 BEG_CATCH_CA_EXCEPT 719 END_CATCH_CA_EXCEPT(hAcoust) 720} 721 722int CA_TruncateAnnotation(CA_Annotation* hAnnotation, 723 int start) 724{ 725 int speech_end; 726 TRY_CA_EXCEPT 727 728 ASSERT(hAnnotation); 729 ASSERT(hAnnotation->data); 730 /* 731 ** Correct annotation's start point if necessary by moving it 732 ** forward of "start". 733 */ 734 if (hAnnotation->data->numWords <= 0) 735 return (hAnnotation->data->numWords); 736 /* NB speech end is length, not endpoint! */ 737 speech_end = hAnnotation->data->tcp[hAnnotation->data->numWords-1].begin 738 + hAnnotation->data->tcp[hAnnotation->data->numWords-1].end; 739 /* Delete all speech segments that finish before end of beep 740 */ 741 while ((hAnnotation->data->numWords > 0) 742 && (hAnnotation->data->tcp[0].begin + hAnnotation->data->tcp[0].end < start)) 743 { 744 annotation_delete_segment(hAnnotation->data, 0); 745 } 746 if (hAnnotation->data->numWords == 0) 747 return (hAnnotation->data->numWords); 748 /* Speech before end of beep? - chop it out. 749 */ 750 if (start > hAnnotation->data->tcp[0].begin) 751 { 752 ASSERT(start <= hAnnotation->data->tcp[hAnnotation->data->numWords-1].begin 753 + hAnnotation->data->tcp[hAnnotation->data->numWords-1].end); /* valid? */ 754 hAnnotation->data->tcp[0].begin = start; 755 } 756 return (hAnnotation->data->numWords); 757 BEG_CATCH_CA_EXCEPT 758 END_CATCH_CA_EXCEPT(hAcoust) 759} 760