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