1/*---------------------------------------------------------------------------*
2 *  fpi_tgt.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
21
22
23
24#ifndef _RTT
25#include <stdio.h>
26#endif
27#include <assert.h>
28
29#include "all_defs.h"
30#include "fpi_tgt.h"
31#include "voicing.h"
32#include "portable.h"
33
34#include "fpi_tgt.inl"
35
36#define DEBUG_REWIND 0
37
38/************************************************************************
39 * Create a Frame Buffer                                                *
40 ************************************************************************
41 *
42 * On the Real Time Target (_RTT) the caller of this function is
43 * responsible for publically declaring the location of the Frame Buffer
44 * so that the REC unit can locate it.  This is achived by use of the
45 * 'setPublicLocation()' and 'publicLocation()' functions.
46 *
47 ************************************************************************
48 *
49 * Arguments: "fCnt"       Size of Frame Stack
50 *            "dimen"      Size of Frame
51 *            "blockLen"   Blocking length (if Using)
52 *            "doVoice"    Reserve voicing parameter
53 *
54 * Returns:   fepFramePkt* Pointer to frame buffer
55 *                          NULL on error
56 *
57 ************************************************************************/
58
59static int  incThisFramePtr(fepFramePkt* frmPkt, featdata** parPtr);
60static int  decThisFramePtr(fepFramePkt* frmPkt, featdata** parPtr);
61
62
63
64fepFramePkt* createFrameBuffer(int fCnt, int dimen, int blockLen, int doVoice)
65{
66  fepFramePkt* frmPkt;
67#if QUICK
68  unsigned long frame_mask = 1, tmpsiz;
69#endif
70
71  ASSERT(fCnt > 0);
72  ASSERT(dimen > 0);
73
74  /* Allocate space for the Frame Packet  *
75   * and then accommodate the Frame Stack */
76
77  frmPkt = (fepFramePkt*) CALLOC_CLR(1, sizeof(fepFramePkt), "clib.Frame_Buffer");
78  if (frmPkt == NULL)
79    return NULL;
80
81#if QUICK
82  tmpsiz = blockLen;
83  frame_mask = 1;
84  tmpsiz >>= 1;
85  while (tmpsiz)
86  {
87    frame_mask = (frame_mask << 1) | 0x01;
88    tmpsiz >>= 1;
89  }
90  blockLen = frame_mask + 1;
91  frmPkt->stackMask = frame_mask;
92#endif
93
94  frmPkt->uttDim = dimen;
95  if (doVoice) dimen++;
96
97  frmPkt->frameStackSize  = fCnt;
98  frmPkt->frameSize       = dimen;
99  frmPkt->featuresInStack = fCnt * dimen;
100  frmPkt->blockLen = blockLen;
101  if (doVoice) frmPkt->haveVoiced = True;
102  else frmPkt->haveVoiced = False;
103
104  frmPkt->frameStack = (featdata *) CALLOC(fCnt,
105                       sizeof(featdata) * dimen, "clib.Frame_Stack");
106  if (frmPkt == NULL)
107    return NULL;
108  frmPkt->lastFrameInStack = frmPkt->frameStack + (fCnt - 1) * dimen;
109
110  /* Use standard function to clear the buffer,    *
111   * we don't care about the return code because   *
112   * we built it, others should care...            */
113
114  (void) clearFrameBuffer(frmPkt);
115
116  frmPkt->uttTimeout = 20;             /* default setting */
117
118  return frmPkt;
119}
120
121
122/************************************************************************
123 * Clear an existing Frame Buffer                                       *
124 ************************************************************************
125 *
126 * Given a pointer to a previously created frame buffer structure
127 * this funtion will reset its member components to their initial
128 * values.
129 *
130 ************************************************************************
131 *
132 * Arguments: "frmPkt"     Frame Buffer Structure Pointer
133 *
134 * Returns:   int          non-ZERO on Error
135 *
136 ************************************************************************/
137
138int clearFrameBuffer(fepFramePkt* frmPkt)
139{
140  ASSERT(frmPkt != NULL);
141
142  /* Clear the frame stack to ZERO as  *
143   * this is done by model_allocate()  */
144
145  memset(frmPkt->frameStack, 0,  /*  TODO: do we need this? */
146         sizeof(featdata) * frmPkt->frameSize * frmPkt->frameStackSize);
147
148  /* Reset Structure Members           */
149
150  frmPkt->isCollecting = FB_IDLE;
151  frmPkt->pullp       = frmPkt->frameStack;
152
153  frmPkt->pushp       = frmPkt->frameStack;
154  frmPkt->pushBlkp    = frmPkt->frameStack;
155  frmPkt->pushBlocked = False;
156  frmPkt->blockTime   = 0;
157  frmPkt->pushTime    = 1;    /* 0 == invalid frame ID, 1 == first    */
158  frmPkt->pullTime    = 1;
159  frmPkt->startTime   = 0;    /* 0 == start hasn't been called        */
160  frmPkt->stopTime    = 0;    /* 0 == stop  hasn't been called        */
161
162  clearEndOfUtterance(frmPkt);
163  clearC0Entries(frmPkt);
164
165  return False;
166}
167
168/************************************************************************
169 * Destroy a Previously Created Frame Buffer                            *
170 ************************************************************************
171 *
172 * On the Real Time Target (_RTT) the caller of this function is
173 * responsible for publically declaring the location of the Frame Buffer
174 * so that the REC unit can locate it.  This is achived by use of the
175 * 'setPublicLocation()' and 'publicLocation()' functions.
176 *
177 ************************************************************************
178 *
179 * Arguments: fepFramePkt* Pointer to frame buffer to destroy
180 *
181 * Returns:   int          non-ZERO on error
182 *
183 ************************************************************************/
184
185int destroyFrameBuffer(fepFramePkt* frmPkt)
186{
187  ASSERT(frmPkt);
188  /* De-allocate space for the Frame Stack *
189   * and then the Frame Packet             */
190
191  FREE(frmPkt->frameStack);
192  FREE(frmPkt);
193  return False;
194}
195
196/************************************************************************
197 * To Start Collecting Frames                                           *
198 ***********************************************************************/
199
200void startFrameCollection(fepFramePkt* frmPkt)
201{
202  ASSERT(frmPkt);
203  if (frmPkt->isCollecting == FB_IDLE)
204  {
205    clearEndOfUtterance(frmPkt);
206    clearC0Entries(frmPkt);
207
208    frmPkt->startTime = frmPkt->pushTime;
209    frmPkt->stopTime = 0;
210    frmPkt->isCollecting = FB_ACTIVE;
211  }
212  return;
213}
214
215/************************************************************************
216 * To Stop Collecting Frames                                            *
217 ***********************************************************************/
218
219int stopFrameCollection(fepFramePkt* frmPkt)
220{
221  ASSERT(frmPkt);
222  ASSERT(frmPkt->startTime != 0);
223
224  if (frmPkt->isCollecting == FB_ACTIVE)
225  {
226
227    /* Remember, pushTime is the ID of the next frame to arrive
228     * The buffer starts empty, with pushTime == 1.
229     * So if Stop occurs at this point, then the start and end frames
230     * will be
231     */
232
233    frmPkt->stopTime = frmPkt->pushTime;
234    frmPkt->isCollecting = FB_IDLE;
235
236    return (True);
237  }
238
239  return (False);
240}
241
242/************************************************************************
243 ***********************************************************************/
244
245void setupEndOfUtterance(fepFramePkt* frmPkt, long timeout, long holdOff)
246{
247  ASSERT(frmPkt);
248  ASSERT(timeout >= 0);
249  ASSERT(holdOff >= 0);
250  frmPkt->uttTimeout = timeout;
251  frmPkt->holdOffPeriod = holdOff;
252  frmPkt->holdOff = 0;
253  return;
254}
255
256/************************************************************************
257 ***********************************************************************/
258
259void clearEndOfUtterance(fepFramePkt* frmPkt)
260{
261  ASSERT(frmPkt);
262  ASSERT(frmPkt->holdOffPeriod >= 0);
263  frmPkt->voicingDetected = 0;
264  frmPkt->quietFrames = 0;
265  frmPkt->utt_ended = False;
266  frmPkt->holdOff = frmPkt->holdOffPeriod;
267
268  return;
269}
270
271void releaseBlockedFramesInBuffer(fepFramePkt* frmPkt)
272{
273  frmPkt->pullp = frmPkt->pushp;     /*  Move the Blocker to pullp */
274  frmPkt->pushBlkp = frmPkt->pushp;     /*  Move the Blocker to pullp */
275  frmPkt->pullTime = frmPkt->pushTime;
276  frmPkt->blockTime = frmPkt->pushTime;
277
278  return;
279}
280
281/************************************************************************
282 * Push a Single Frame into Frame Buffer                                *
283 ************************************************************************
284 *
285 * Inserts a new frame into the frame buffer.
286 *
287 * If there is no room in the buffer (the frame maker has exhausted the
288 * space which is being slowly 'eaten' by the associated recognizer) then
289 * the data is not inserted and an error value is returned.  For this to
290 * happen, blockLen member must be set.  Otherwise pushBlkp will always
291 * point to the oldest valid frame in the buffer.
292 *
293 ************************************************************************
294 *
295 * Arguments: "frmPkt"  Frame Buffer Pointer
296 *            "parPtr"  Pointer to contiguous block of Frame Parameters
297 *
298 * Returns:   int       non-ZERO on ERROR
299 *
300 ************************************************************************/
301
302int pushSingleFEPframe(fepFramePkt* frmPkt, featdata* parPtr, int voiceData)
303{
304  featdata*   destFrmPtr;
305  featdata*   nextFrmPtr;
306
307  ASSERT(frmPkt);
308  ASSERT(parPtr);
309
310  /* 'pushp' must be either within the frame buffer or NULL. *
311   * If it is NULL then the frame is just discarded.         */
312
313  if (frmPkt->isCollecting != FB_ACTIVE) return True;
314  if ((destFrmPtr = nextFrmPtr = (featdata*) frmPkt->pushp) == NULL)
315    return (0);
316
317#if DEBUG_REWIND
318  log_report("U: voicing at %d was %x\n", frmPkt->pushTime, voiceData);
319#endif
320
321  /* Copy the frame into the buffer.  Once this is done     *
322   * advance 'pushp' (unless it is up against the 'blocker' *
323   * The frame consists of Parameters and Signal Data       */
324
325  memcpy(destFrmPtr, parPtr, frmPkt->uttDim * sizeof(featdata));
326  if (frmPkt->haveVoiced)
327    destFrmPtr[frmPkt->uttDim] = voiceData;
328
329  /* The following (vocing detection which triggers EOU),
330   * is only active when the 'holdOff' member is 0.
331   * The intension is to delay 'voicing' signal for at least
332  * 'holdOffPeriod' frames.
333   */
334  if (frmPkt->holdOff <= 0)
335  {
336    if (frmPkt->haveVoiced && frmPkt->utt_ended == False)
337    {
338      if (voiceData & VOICE_BIT)
339      {
340        frmPkt->voicingDetected = 1;
341      }
342      if (voiceData & QUIET_BIT)
343      {
344        frmPkt->quietFrames++;
345        if (frmPkt->voicingDetected
346            && frmPkt->quietFrames > frmPkt->uttTimeout)
347        {
348          log_report("Level based utterance ended at %d\n",
349                     frmPkt->pushTime);
350          frmPkt->utt_ended = True;
351        }
352      }
353      else
354        frmPkt->quietFrames = 0;
355    }
356  }
357  else
358  {
359    ASSERT(frmPkt->holdOff > 0);
360    frmPkt->holdOff--;
361  }
362
363  /*  Track C0 values
364  */
365  if (frmPkt->maxC0 < parPtr[0])      /* only works if the 0th entry - */
366    frmPkt->maxC0 = parPtr[0];       /* is C0 */
367
368  if (frmPkt->minC0 > parPtr[0])      /* only works if the 0th entry - */
369    frmPkt->minC0 = parPtr[0];       /* is C0 */
370
371  frmPkt->pushTime++;
372  if (frmPkt->pushTime == 0L)          /* Check for wrap - and ensure */
373    frmPkt->pushTime++;              /* ZERO is NEVER used          */
374
375  /* Try to move the push pointer on, if it meets the *
376   * push blocker it should not increment.            */
377
378  nextFrmPtr = (featdata *) NEXT_FRAME_POINTER(frmPkt, frmPkt->pushp);
379
380  if (nextFrmPtr == frmPkt->pullp)
381  {
382    /* Latest Frame was blocked, so record the fact and then *
383    * record the frame time that this occured (useful?)     */
384
385    frmPkt->pushBlocked++;
386    frmPkt->blockTime = frmPkt->pushTime;
387
388    return True;
389  }
390
391  else if (nextFrmPtr == frmPkt->pushBlkp)
392  {
393    if (frmPkt->blockLen == 0)
394    {
395      /* Simply move pushBlkp along */
396
397      frmPkt->pushBlkp = NEXT_FRAME_POINTER(frmPkt, frmPkt->pushBlkp);
398    }
399    else
400    {
401      /* Latest Frame was blocked, so record the fact and then *
402       * record the frame time that this occured (useful?)     */
403
404      frmPkt->pushBlocked++;
405      frmPkt->blockTime = frmPkt->pushTime;
406
407      return True;
408    }
409  }
410
411  /* Free to move ahead, so increment the push pointer     *
412   * and increase the frame-count between pull & push      */
413
414  frmPkt->pushp = nextFrmPtr;
415  /*      Increment semaphore count for each frame pushed.
416   Decrement is in waitforsinglefepframe */
417  return False;
418}
419
420/************************************************************************
421 * Sets oldest frame pointer (Use with caution)                         *
422 ************************************************************************
423 *
424 * NOTES
425 *
426 * If 'masterREC', 'pullp' is manipulated, otherwise one of the
427 * multiple recognition pointers, 'auxPullp[]' is used.
428 *
429 ************************************************************************
430 *
431 * CAUTION
432 *
433 * With multiple recognizers, the gap-test doesn't work !!!
434 *
435 ************************************************************************
436 *
437 * Arguments: "frmPkt"     Pointer to Frame Packet
438 *            "fCnt"       Frame offset from Newest Frame
439 *                              +ve == Increase Distance between oldest & newest
440 *                              -ve == Decrease Distance
441 *            "mode"           ZERO means movement wrt Newest Frame
442 *                         non-ZERO means movement wrt Current Oldest Frame
443 *
444 * Retunrs:   int          Status of operation
445 *                          No Problems: False
446 *                          No FEP     : DUKRC_NOFEP
447 *
448 * Critical section code!
449 *
450 ************************************************************************/
451
452int setRECframePtr(fepFramePkt* frmPkt, int fCnt, int mode)
453{
454  int   gap;
455
456  ASSERT(frmPkt);
457
458  if (mode != 0) /* wrt Current Oldest Frame */
459  {
460    /************
461    * Relative *
462    ************/
463
464    /* Can it go backwards? */
465
466    gap = POINTER_GAP(frmPkt, frmPkt->pullp, frmPkt->pushBlkp);
467    if (fCnt > gap)                         /* Limit movement      */
468      fCnt = gap;
469
470    /* Can it go forwards? */
471
472    gap = POINTER_GAP(frmPkt, frmPkt->pushp, frmPkt->pullp);
473    if (fCnt < -gap)                         /* Limit movement      */
474      fCnt = -gap;
475
476    frmPkt->pullp = FIX_FRAME_POINTER(frmPkt,
477                                      frmPkt->pullp - fCnt * frmPkt->frameSize);
478    frmPkt->pullTime -= fCnt;
479
480  }
481  else  /* wrt Newest Frame */
482  {
483    /************
484    * Absolute *
485    ************/
486
487    /* ASSERT(fCnt); moved from the above block, do we need this? */
488    ASSERT(frmPkt->isCollecting != FB_DEAD);
489
490    gap = POINTER_GAP(frmPkt, frmPkt->pushp, frmPkt->pushBlkp);
491
492    if (fCnt > gap)                         /* Limit movement      */
493      fCnt = gap;
494
495    frmPkt->pullp = FIX_FRAME_POINTER(frmPkt,
496                                      frmPkt->pushp - fCnt * frmPkt->frameSize);
497    frmPkt->pullTime = frmPkt->pushTime - fCnt;
498
499  }
500
501  return (fCnt);
502  ;
503}
504
505/************************************************************************
506 * Returns Pointer to Oldest unread REC frame                           *
507 ************************************************************************
508 *
509 * Arguments: "frmPkt"  Frame Buffer Pointer
510 *
511 * Retunrs:   featdata*   Pointer to newest frame
512 *                          NULL on Error
513 *
514 ************************************************************************/
515
516featdata* currentRECframePtr(fepFramePkt* frmPkt)
517{
518  ASSERT(frmPkt);
519  if (frmPkt->pushp == frmPkt->pushBlkp)            /* uninitialized? */
520    return NULL;
521  return ((featdata *)frmPkt->pullp);
522}
523
524/************************************************************************
525 * Returns Pointer to Newest Complete frame of given channel            *
526 ************************************************************************
527 *
528 * Arguments: "frmPkt"  Frame Buffer Pointer
529 *
530 * Retunrs:   featdata*   Pointer to newest frame
531 *                          NULL on Error.
532 *
533 ************************************************************************/
534
535featdata* currentFEPframePtr(fepFramePkt* frmPkt)
536{
537  featdata* frmPtr;
538
539  ASSERT(frmPkt);
540  frmPtr = frmPkt->pushp;  /* Where is FEP?    */
541  if (frmPtr == NULL)
542    return NULL;
543  (void) decThisFramePtr(frmPkt, &frmPtr);/* Move backwards   */
544  return frmPtr;
545}
546
547/************************************************************************
548 * Moves REC's Frame Pointer backwards one Frame (if it can)            *
549 ************************************************************************
550 *
551 * NOTES
552 *
553 * If 'masterREC', 'pullp' is manipulated, otherwise one of the
554 * multiple recognition pointers, 'auxPullp[]' is used. (not sure about this)
555 * The pushBlkp is also moved accordingly.
556 *
557 ************************************************************************
558 *
559 * Arguments: "n"      Channel Number of Selected Frame
560 *
561 * Retunrs:   int      Non-zero on error
562 *
563 ************************************************************************/
564
565int incRECframePtr(fepFramePkt* frmPkt)
566{
567  ASSERT(frmPkt);
568
569  /* Ensure that the frame buffer for *
570   * the channel specified exists     */
571
572  if (frmPkt->pullp == frmPkt->pushp)
573    return True;
574
575
576  frmPkt->pullp = NEXT_FRAME_POINTER(frmPkt, frmPkt->pullp);
577
578  frmPkt->pullTime++;
579  if (frmPkt->pullTime == 0)  /* Check for wrap and ensure */
580    frmPkt->pullTime++;     /* that it is never ZERO     */
581
582  /* New 'pushBlkp' */
583  if (frmPkt->blockLen > 0 && frmPkt->isCollecting == FB_ACTIVE)
584  {
585    if (POINTER_GAP(frmPkt, frmPkt->pullp, frmPkt->pushBlkp) >= frmPkt->blockLen)
586    {
587      frmPkt->pushBlkp = NEXT_FRAME_POINTER(frmPkt, frmPkt->pushBlkp);
588    }
589  }
590
591  return False;
592}
593
594/************************************************************************
595 * Moves REC's Frame Pointer backwards one Frame (if it can)            *
596 ************************************************************************
597 *
598 * NOTES
599 *
600 * If 'masterREC', 'pullp' is manipulated, otherwise one of the
601 * multiple recognition pointers, 'auxPullp[]' is used. (not sure about this)
602 * The pushBlkp is also moved accordingly.
603 *
604 ************************************************************************
605 *
606 * Arguments: "n"      Channel Number of Selected Frame
607 *
608 * Retunrs:   int      Non-zero on error
609 *
610 ************************************************************************/
611
612int decRECframePtr(fepFramePkt* frmPkt)
613{
614  ASSERT(frmPkt);
615
616  /* Ensure that the frame buffer for *
617   * the channel specified exists     */
618
619  /* New 'pullp' */
620
621  if (frmPkt->pullp == frmPkt->pushBlkp) return True;
622  frmPkt->pullp = PREV_FRAME_POINTER(frmPkt, frmPkt->pullp);
623  frmPkt->pullTime--;
624  return False;
625}
626
627/************************************************************************
628 * Moves a Frame Pointer forwards one Frame (if it can)                 *
629 ************************************************************************
630 *
631 * Arguments: "n"      Channel Number of Selected Frame
632 *            "parPtr" Current Frame Pointer
633 *
634 * Retunrs:   int      Non-zero on error
635 *                     "parPtr" and "sigPtr" may have changed
636 *
637 * Caution:            Does not test to see whether 'parPtr' lies
638 *                     legally within the appropriate buffer or on an
639 *                     appropriate valid frame boundary
640 *
641 *                     The caller should NEVER modify frame buffer
642 *                     pointers by hand, always call an RTT-supplied function
643 *
644 ************************************************************************/
645
646static int incThisFramePtr(fepFramePkt* frmPkt, featdata** parPtr)
647{
648  ASSERT(frmPkt);
649  ASSERT(parPtr);
650  if (*parPtr == frmPkt->pushp)
651    return True;
652  *parPtr = NEXT_FRAME_POINTER(frmPkt, *parPtr);
653  return False;
654}
655
656/************************************************************************
657 * Moves a Frame Pointer backwards one Frame (if it can)                *
658 ************************************************************************
659 *
660 * Arguments: "frmPkt" Frame Buffer Pointer
661 *            "parPtr" Current Frame Pointer
662 *            "sigPtr" Signal Pointer
663 *                          Set to NULL if not required
664 *
665 * Retunrs:   int      Non-zero on error
666 *                     "parPtr" may have changed
667 *
668 * Caution:            Checks for bound within pushBlkp.
669 *                     The caller should NEVER modify frame buffer
670 *                     pointers by hand, always call an RTT-supplied function
671 *
672 ************************************************************************/
673
674static int decThisFramePtr(fepFramePkt* frmPkt, featdata** parPtr)
675{
676  ASSERT(frmPkt);
677  ASSERT(parPtr);
678  if (*parPtr == frmPkt->pushBlkp)
679    return True;
680  *parPtr = PREV_FRAME_POINTER(frmPkt, *parPtr);
681  return False;
682}
683
684/************************************************************************
685 ************************************************************************/
686
687featdata getVoicingCode(fepFramePkt* frmPkt, featdata *frmptr)
688{
689  ASSERT(frmPkt);
690  frmptr = CHECK_BOUND(frmPkt, frmptr);
691  if (frmptr && frmPkt->haveVoiced)
692    return (frmptr[frmPkt->uttDim]);
693  else
694    return (0);
695}
696
697/************************************************************************
698 ************************************************************************/
699
700void setVoicingCode(fepFramePkt* frmPkt, featdata *frmptr, featdata vcode)
701{
702  ASSERT(frmPkt);
703  frmptr = CHECK_BOUND(frmPkt, frmptr);
704  if (frmptr && frmPkt->haveVoiced)
705    frmptr[frmPkt->uttDim] =
706      SET_VOICING_CODES(frmptr[frmPkt->uttDim], vcode);
707  return;
708}
709
710/************************************************************************
711 ************************************************************************/
712
713void clearC0Entries(fepFramePkt* frmPkt)
714{
715  ASSERT(frmPkt);
716  frmPkt->maxC0 = 0;           /*  Assuming a normal range of 0 - 255 */
717  frmPkt->minC0 = 255;
718  return;
719}
720
721int get_background_statistics(fepFramePkt *frmPkt, int start, int end,
722                              spect_dist_info **spec, int num,
723                              int relative_to_pullp)
724{
725  int len, /* count= 0, */ num_frames = 0;
726  int ii, jj, got;
727  featdata  *frame_ptr;
728#ifndef NDEBUG
729  featdata  *base_ptr = NULL;
730#endif
731
732  ASSERT(frmPkt);
733  ASSERT(spec);
734  if (!frmPkt->haveVoiced) return(0);
735  if (start == end || (start == 0 && !relative_to_pullp))
736    return (0);
737
738  /*  Cannot access the frames
739  */
740  if (relative_to_pullp && getBlockGap(frmPkt) < start)
741    return (0);
742
743  ASSERT(base_ptr = frmPkt->pullp);
744  got = setRECframePtr(frmPkt, end, relative_to_pullp);
745  if (got != end)
746  {
747    (void) setRECframePtr(frmPkt, -got, relative_to_pullp);
748    ASSERT(base_ptr == currentRECframePtr(frmPkt));
749    return (0);
750  }
751  len = start - end;
752
753  for (ii = 0; ii < len; ii++)
754  {
755    decRECframePtr(frmPkt);
756    frame_ptr   = currentRECframePtr(frmPkt);
757#if DEBUG
758    log_report("%d %d %x\n", frame_ptr[0],
759               frame_ptr[frmPkt->uttDim], frame_ptr);
760#endif
761    if ((frame_ptr[frmPkt->uttDim] & BELOW_THRESHOLD_BIT))
762    {
763      num_frames++;
764      for (jj = 0; jj < num; jj++)
765      {
766        ASSERT(spec[jj]);
767        add_distribution_data(spec[jj], (int) frame_ptr[jj]);
768      }
769    }
770  }
771#if DEBUG
772  log_report("End of chunk\n");
773#endif
774
775  /* Put it back in the same place !
776  */
777  if (start != 0)
778    (void) setRECframePtr(frmPkt, -start, relative_to_pullp);
779  ASSERT(base_ptr == currentRECframePtr(frmPkt));
780  return (num_frames);
781}
782
783void utterance_detection_fixup(fepFramePkt *frmPkt, featdata **last_pushp,
784                               int voice_duration, int quite_duration, int unsure_duration)
785{
786  featdata  *fram;
787  long   gotstat, count, voistat;
788  featdata  *fepFrmPtr, *recFrmPtr, *last_push, voice_result;
789
790  /* Adjust for delay in decision making by voicing_analysis
791  */
792  ASSERT(frmPkt);
793  ASSERT(last_pushp);
794  fepFrmPtr = currentFEPframePtr(frmPkt);
795  last_push = *last_pushp;
796  if (last_push == fepFrmPtr)
797    return;
798
799  recFrmPtr = currentRECframePtr(frmPkt);
800  if (last_push == NULL)
801  {
802    last_push = recFrmPtr;
803    voistat = FAST_MATCH_DATA(getVoicingCode(frmPkt, last_push));
804  }
805  else if (decThisFramePtr(frmPkt, &last_push) == False)
806  {
807    voistat = FAST_MATCH_DATA(getVoicingCode(frmPkt, last_push));
808    (void) incThisFramePtr(frmPkt, &last_push);
809  }
810  else
811    voistat = FAST_MATCH_DATA(getVoicingCode(frmPkt, last_push));
812
813  while (last_push != fepFrmPtr)
814  {
815
816    gotstat = FAST_MATCH_DATA(getVoicingCode(frmPkt, last_push));
817    if (gotstat != voistat)
818    {
819      /*  Voicing status has changed
820      */
821      fram = last_push;
822      voice_result = getVoicingCode(frmPkt, fram);
823      if (FAST_BIT_SET(voice_result))
824      {
825        for (count = voice_duration; count > 0 && fram != recFrmPtr;
826             count--)
827        {
828          if (decThisFramePtr(frmPkt, &fram) != False)
829            break;
830#if DEBUG_REWIND
831          log_report("U: voice rewind at %d was %x\n", frmPkt->pullTime
832                     + POINTER_GAP(frmPkt, fram, recFrmPtr),
833                     getVoicingCode(frmPkt, fram));
834#endif
835          setVoicingCode(frmPkt, fram, REC_VOICE_BIT);
836        }
837
838        /* set to unsure for start period of voicing
839        */
840        for (count = 0; count < unsure_duration && fram != recFrmPtr;
841             count++)
842        {
843          if (decThisFramePtr(frmPkt, &fram) != False)
844            break;
845#if DEBUG_REWIND
846          log_report("U: unsure rewind at %d was %x\n", frmPkt->pullTime
847                     + POINTER_GAP(frmPkt, fram, recFrmPtr),
848                     getVoicingCode(frmPkt, fram));
849#endif
850          setVoicingCode(frmPkt, fram, REC_UNSURE_BIT);
851        }
852      }
853
854      else if (QUIET_BIT_SET(voice_result))
855      {
856        for (count = quite_duration; count > 0 && fram != recFrmPtr;
857             count--)
858        {
859          if (decThisFramePtr(frmPkt, &fram) != False)
860            break;
861#if DEBUG_REWIND
862          log_report("U: quiet rewind at %d was %x\n", frmPkt->pullTime
863                     + POINTER_GAP(frmPkt, fram, recFrmPtr),
864                     getVoicingCode(frmPkt, fram));
865#endif
866          setVoicingCode(frmPkt, fram, REC_QUIET_BIT);
867        }
868      }
869
870      voistat = gotstat;
871    }
872
873    /* copy to recognizer bits if status not changed */
874#if DEBUG_REWIND
875    log_report("U: copying at %d was %x\n", frmPkt->pullTime
876               + POINTER_GAP(frmPkt, last_push, recFrmPtr),
877               getVoicingCode(frmPkt, last_push));
878#endif
879    if (QUIET_BIT_SET(getVoicingCode(frmPkt, last_push)))
880      setVoicingCode(frmPkt, last_push, REC_QUIET_BIT);
881    else if (FAST_BIT_SET(getVoicingCode(frmPkt, last_push)))
882      setVoicingCode(frmPkt, last_push, REC_VOICE_BIT);
883    else
884      setVoicingCode(frmPkt, last_push, REC_UNSURE_BIT);
885
886    if (incThisFramePtr(frmPkt, &last_push) != False) break;
887  }
888
889  *last_pushp = last_push;
890  return;
891}
892
893int rec_frame_voicing_status(fepFramePkt *frmPkt)
894{
895  ASSERT(frmPkt);
896  return (getVoicingCode(frmPkt, (featdata *)frmPkt->pullp));
897}
898