summaryrefslogtreecommitdiffstats
path: root/pico/lib/picoacph.c
diff options
context:
space:
mode:
Diffstat (limited to 'pico/lib/picoacph.c')
-rw-r--r--pico/lib/picoacph.c1430
1 files changed, 1430 insertions, 0 deletions
diff --git a/pico/lib/picoacph.c b/pico/lib/picoacph.c
new file mode 100644
index 0000000..98feb6e
--- /dev/null
+++ b/pico/lib/picoacph.c
@@ -0,0 +1,1430 @@
+/*
+ * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file picoacph.c
+ *
+ * accentuation and phrasing
+ *
+ * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
+ * All rights reserved.
+ *
+ * History:
+ * - 2009-04-20 -- initial version
+ *
+ */
+
+#include "picoos.h"
+#include "picodbg.h"
+#include "picobase.h"
+#include "picodata.h"
+#include "picoacph.h"
+#include "picokdt.h"
+#include "picoklex.h"
+#include "picoktab.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}
+#endif
+
+/* PU acphStep states */
+#define SA_STEPSTATE_COLLECT 0
+#define SA_STEPSTATE_PROCESS_PHR 12
+#define SA_STEPSTATE_PROCESS_ACC 13
+#define SA_STEPSTATE_FEED 2
+
+
+/* boundary strength state */
+#define SA_BOUNDSTRENGTH_SSEP 0 /* sentence separator */
+#define SA_BOUNDSTRENGTH_PPHR 1 /* primary phrase separator */
+
+
+/* subobject : AccPhrUnit
+ * shortcut : acph
+ * context size : one phrase, max. 30 non-PUNC items, for non-processed items
+ * one item if internal input empty
+ */
+
+/**
+ * @addtogroup picoacph
+ *
+ * <b> Pico Accentuation and Phrasing </b>\n
+ *
+ internal buffers:
+
+ - headx : array for extended item heads of fixed size (head plus
+ index for content, plus two fields for boundary strength/type)
+ - cbuf : buffer for item contents (referenced by index in
+ headx).
+
+ 0. bottom up filling of items in headx and cbuf
+
+ 1. phrasing (right-to-left):
+
+ e.g. from WP WP WP WP WP PUNC WP WP PUNC WP WP WP PUNC FLUSH \n
+ e.g. to BSBEG WP WP WP BPHR3 WP WP BPHR1 WP WP BSEND BSBEG WP WP WP BSEND BTERM \n
+ |1 |2 |3 |4 \n
+
+ 2-level bound state: The internal buffer contains one primary phrase (sometimes forced, if buffer
+ allmost full), with the trailing PUNCT item included (last item).\n
+ If the trailing PUNC is a a primary phrase separator, the
+ item is not output, but instead, the bound state is set to PPHR, so that the correct BOUND can
+ be output at the start of the next primary phrase.\n
+ Otherwise,
+ the item is converted to the corresponding BOUND and output. the bound state is set to SSEP,
+ so that a BOUND of type SBEG is output at the start of the next primary phrase.
+
+ trailing PUNC item bound states \n
+ SSEP PPHR \n
+ PUNC(SENTEND, X) B(B,X)>SSEP B(P1,X)>SSEP (X = T | Q | E) \n
+ PUNC(FLUSH, T) B(B,T)>SSEP* B(P1,T)>SSEP \n
+ PUNC(PHRASEEND, P) B(B,P)>PPHR B(P1,P)>PPHR \n
+ PUNC(PHRASEEND, FORC) B(B,P)>PPHR B(P1,P)>PPHR \n
+
+ If more than one sentence separators follow each other (e.g. SEND-FLUSH, SEND-SEND) then
+ all but the first will be treated as an (empty) phrase containing just this item.
+ If this (single) item is a flush, creation of SBEG is suppressed.
+
+
+ - dtphr phrasing tree ("subphrasing")
+ determines
+ - BOUND_PHR2
+ - BOUND_PHR3
+ - boundary strenghts are determined for every word (except the
+ first one) from right-to-left. The boundary types mark the phrase
+ type of the phrase following the boundary.
+ - number of items actually changed (new BOUND items added): because
+ of fixed size without content, two fields are contained in headx
+ to indicate if a BOUND needs to be added to the LEFT of the item.
+ -> headx further extended with boundary strength and type info to
+ indicate that to the left of the headx ele a BOUND needs to be
+ inserted when outputting.
+
+ 2. accentuation:
+ - number of items unchanged, content unchanged, only head info changes
+ -> changed in place in headx
+*/
+
+
+typedef struct {
+ picodata_itemhead_t head;
+ picoos_uint16 cind;
+ picoos_uint8 boundstrength; /* bstrength to the left, 0 if not set */
+ picoos_uint8 boundtype; /* btype for following phrase, 0 if not set */
+} picoacph_headx_t;
+
+
+typedef struct acph_subobj {
+ picoos_uint8 procState; /* for next processing step decision */
+ picoos_uint8 boundStrengthState; /* boundary strength state */
+
+ picoos_uint8 inspaceok; /* flag: headx/cbuf has space for an item */
+ picoos_uint8 needsmoreitems; /* flag: need more items */
+
+ picoos_uint8 tmpbuf[PICODATA_MAX_ITEMSIZE]; /* tmp. location for an item */
+
+ picoacph_headx_t headx[PICOACPH_MAXNR_HEADX];
+ picoos_uint16 headxBottom; /* bottom */
+ picoos_uint16 headxLen; /* length, 0 if empty */
+
+ picoos_uint8 cbuf[PICOACPH_MAXSIZE_CBUF];
+ picoos_uint16 cbufBufSize; /* actually allocated size */
+ picoos_uint16 cbufLen; /* length, 0 if empty */
+
+ /* tab knowledge base */
+ picoktab_Phones tabphones;
+
+ /* dtphr knowledge base */
+ picokdt_DtPHR dtphr;
+
+ /* dtacc knowledge base */
+ picokdt_DtACC dtacc;
+} acph_subobj_t;
+
+
+static pico_status_t acphInitialize(register picodata_ProcessingUnit this) {
+ acph_subobj_t * acph;
+ picoos_uint16 i;
+
+ PICODBG_DEBUG(("calling"));
+
+ if (NULL == this || NULL == this->subObj) {
+ return picoos_emRaiseException(this->common->em,
+ PICO_ERR_NULLPTR_ACCESS, NULL, NULL);
+ }
+ acph = (acph_subobj_t *) this->subObj;
+ acph->procState = SA_STEPSTATE_COLLECT;
+ acph->boundStrengthState = SA_BOUNDSTRENGTH_SSEP;
+
+ acph->inspaceok = TRUE;
+ acph->needsmoreitems = TRUE;
+
+ acph->headxBottom = 0;
+ acph->headxLen = 0;
+ acph->cbufBufSize = PICOACPH_MAXSIZE_CBUF;
+ acph->cbufLen = 0;
+
+ /* init headx, cbuf */
+ for (i = 0; i < PICOACPH_MAXNR_HEADX; i++){
+ acph->headx[i].head.type = 0;
+ acph->headx[i].head.info1 = 0;
+ acph->headx[i].head.info2 = 0;
+ acph->headx[i].head.len = 0;
+ acph->headx[i].cind = 0;
+ acph->headx[i].boundstrength = 0;
+ acph->headx[i].boundtype = 0;
+ }
+ for (i = 0; i < PICOACPH_MAXSIZE_CBUF; i++) {
+ acph->cbuf[i] = 0;
+ }
+
+ /* kb tabphones */
+ acph->tabphones =
+ picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]);
+ if (acph->tabphones == NULL) {
+ return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING,
+ NULL, NULL);
+ }
+ PICODBG_DEBUG(("got tabphones"));
+
+#ifdef PICO_DEBUG_1
+ {
+ picoos_uint16 itmp;
+ for (itmp = 0; itmp < 256; itmp++) {
+ if (picoktab_hasVowelProp(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones hasVowel: %d", itmp));
+ }
+ if (picoktab_hasDiphthProp(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones hasDiphth: %d", itmp));
+ }
+ if (picoktab_hasGlottProp(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones hasGlott: %d", itmp));
+ }
+ if (picoktab_hasNonsyllvowelProp(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones hasNonsyllvowel: %d", itmp));
+ }
+ if (picoktab_hasSyllconsProp(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones hasSyllcons: %d", itmp));
+ }
+
+ if (picoktab_isPrimstress(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones isPrimstress: %d", itmp));
+ }
+ if (picoktab_isSecstress(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones isSecstress: %d", itmp));
+ }
+ if (picoktab_isSyllbound(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones isSyllbound: %d", itmp));
+ }
+ if (picoktab_isPause(acph->tabphones, itmp)) {
+ PICODBG_DEBUG(("tabphones isPause: %d", itmp));
+ }
+ }
+
+ PICODBG_DEBUG(("tabphones primstressID: %d",
+ picoktab_getPrimstressID(acph->tabphones)));
+ PICODBG_DEBUG(("tabphones secstressID: %d",
+ picoktab_getSecstressID(acph->tabphones)));
+ PICODBG_DEBUG(("tabphones syllboundID: %d",
+ picoktab_getSyllboundID(acph->tabphones)));
+ PICODBG_DEBUG(("tabphones pauseID: %d",
+ picoktab_getPauseID(acph->tabphones)));
+ }
+#endif
+
+
+ /* kb dtphr */
+ acph->dtphr = picokdt_getDtPHR(this->voice->kbArray[PICOKNOW_KBID_DT_PHR]);
+ if (acph->dtphr == NULL) {
+ return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING,
+ NULL, NULL);
+ }
+ PICODBG_DEBUG(("got dtphr"));
+
+ /* kb dtacc */
+ acph->dtacc = picokdt_getDtACC(this->voice->kbArray[PICOKNOW_KBID_DT_ACC]);
+ if (acph->dtacc == NULL) {
+ return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING,
+ NULL, NULL);
+ }
+ PICODBG_DEBUG(("got dtacc"));
+
+ return PICO_OK;
+}
+
+static picodata_step_result_t acphStep(register picodata_ProcessingUnit this,
+ picoos_int16 mode,
+ picoos_uint16 *numBytesOutput);
+
+static pico_status_t acphTerminate(register picodata_ProcessingUnit this)
+{
+ return PICO_OK;
+}
+
+static pico_status_t acphSubObjDeallocate(register picodata_ProcessingUnit this,
+ picoos_MemoryManager mm) {
+ mm = mm; /* avoid warning "var not used in this function"*/
+ if (NULL != this) {
+ picoos_deallocate(this->common->mm, (void *) &this->subObj);
+ }
+ return PICO_OK;
+}
+
+
+picodata_ProcessingUnit picoacph_newAccPhrUnit(picoos_MemoryManager mm,
+ picoos_Common common,
+ picodata_CharBuffer cbIn,
+ picodata_CharBuffer cbOut,
+ picorsrc_Voice voice) {
+ picodata_ProcessingUnit this;
+
+ this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice);
+ if (this == NULL) {
+ return NULL;
+ }
+
+ this->initialize = acphInitialize;
+ PICODBG_DEBUG(("set this->step to acphStep"));
+ this->step = acphStep;
+ this->terminate = acphTerminate;
+ this->subDeallocate = acphSubObjDeallocate;
+ this->subObj = picoos_allocate(mm, sizeof(acph_subobj_t));
+ if (this->subObj == NULL) {
+ picoos_deallocate(mm, (void *)&this);
+ picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL);
+ return NULL;
+ }
+
+ acphInitialize(this);
+ return this;
+}
+
+
+/* ***********************************************************************/
+/* PROCESS_PHR/ACC support functions */
+/* ***********************************************************************/
+
+
+static picoos_uint8 acphGetNrSylls(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind) {
+ picoos_uint8 i;
+ picoos_uint8 ch;
+ picoos_uint8 count;
+
+ count = 1;
+ for (i = 0; i < acph->headx[ind].head.len; i++) {
+ ch = acph->cbuf[acph->headx[ind].cind + i];
+ if (picoktab_isSyllbound(acph->tabphones, ch)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+
+/* ***********************************************************************/
+/* PROCESS_PHR functions */
+/* ***********************************************************************/
+
+
+/* find next POS to the left of 'ind' and return its POS and index */
+static picoos_uint8 acphPhrItemSeqGetPosLeft(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind,
+ picoos_uint16 *leftind) {
+ picoos_uint8 val;
+ picoos_int32 i;
+
+ val = PICOKDT_EPSILON;
+ for (i = ind - 1; ((val == PICOKDT_EPSILON) && (i >= 0)); i--) {
+ if ((acph->headx[i].head.type == PICODATA_ITEM_WORDPHON)) {
+ val = acph->headx[i].head.info1;
+ }
+ }
+ *leftind = i + 1;
+ return val;
+}
+
+
+/* right-to-left, for each WORDPHON do phr */
+static pico_status_t acphSubPhrasing(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph) {
+ picokdt_classify_result_t dtres;
+ picoos_uint8 valbuf[5];
+ picoos_uint16 nrwordspre;
+ picoos_uint16 nrwordsfol;
+ picoos_uint16 nrsyllsfol;
+ picoos_uint16 lastprev2; /* last index of POS(es) found to the left */
+ picoos_uint8 curpos; /* POS(es) of current word */
+ picoos_uint16 upbound; /* index of last WORDPHON item (with POS) */
+ picoos_uint8 okay;
+ picoos_uint8 nosubphrases;
+ picoos_int32 i;
+
+ /* set initial values */
+ okay = TRUE;
+ nosubphrases = TRUE;
+ curpos = PICOKDT_EPSILON; /* needs to be in 2^8 */
+
+ /* set upbound to last WORDPHON, don't worry about first one */
+ upbound = acph->headxLen - 1;
+ while ((upbound > 0) &&
+ (acph->headx[upbound].head.type != PICODATA_ITEM_WORDPHON)) {
+ upbound--;
+ }
+
+ /* zero or one WORDPHON, no subphrasing needed, but handling of
+ BOUND strength state is needed */
+ if (upbound <= 0) {
+ /* phrase not containing more than one WORDPHON */
+ PICODBG_DEBUG(("less than two WORDPHON in phrase -> no subphrasing"));
+ }
+
+ lastprev2 = upbound;
+
+ /* set initial nr pre/fol words/sylls, upbound is ind of last WORDPHON */
+ nrwordsfol = 0;
+ nrsyllsfol = 0;
+ nrwordspre = 0;
+ for (i = 0; i < upbound; i++) {
+ if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) {
+ nrwordspre++;
+ }
+ }
+
+ nrwordspre++; /* because we later have a decrement before being used */
+
+
+ /* set POS of current word in valbuf[1], will be shifted right afterwards */
+ valbuf[1] = acph->headx[upbound].head.info1;
+ /* find first POS to the left and set valbuf[0] */
+ valbuf[0] = acphPhrItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2);
+ for (i = 2; i < 5; i++) {
+ valbuf[i] = PICOKDT_EPSILON;
+ }
+
+ PICODBG_TRACE(("headxLen: %d", acph->headxLen));
+
+ /* at least two WORDPHON items */
+ /* process from right-to-left all items in headx, except for 1st WORDPHON */
+ for (i = upbound; (i > 0) && (nrwordspre > 1); i--) {
+ okay = TRUE;
+
+ PICODBG_TRACE(("iter: %d, type: %c", i, acph->headx[i].head.type));
+
+ /* if not (WORDPHON) */
+ if ((acph->headx[i].head.type != PICODATA_ITEM_WORDPHON)) {
+ continue;
+ }
+
+ PICODBG_TRACE(("iter: %d, curpos: %d", i, acph->headx[i].head.info1));
+
+ /* get and set POS of current item, must be WORDPHON */
+ curpos = acph->headx[i].head.info1;
+
+ /* no continue so far => at [i] we have a WORDPHON item */
+ /* shift all POS elements one position to the right */
+ valbuf[4] = valbuf[3];
+ valbuf[3] = valbuf[2];
+ valbuf[2] = valbuf[1];
+ valbuf[1] = valbuf[0];
+ /* find next POS to the left and set valbuf[0] */
+ valbuf[0] = acphPhrItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2);
+
+ /* better check double than never */
+ if (curpos != valbuf[2]) {
+ PICODBG_WARN(("syncing POS"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR,
+ NULL, NULL);
+ valbuf[2] = curpos;
+ }
+
+ nrwordsfol++;
+ nrsyllsfol += acphGetNrSylls(this, acph, i);
+ nrwordspre--;
+
+ PICODBG_TRACE(("%d: [%d,%d|%d|%d,%d|%d,%d,%d]",
+ i, valbuf[0], valbuf[1], valbuf[2], valbuf[3],
+ valbuf[4], nrwordspre, nrwordsfol, nrsyllsfol));
+
+ /* no continue so far => subphrasing needed */
+ /* construct input vector, which is set in dtphr */
+ if (!picokdt_dtPHRconstructInVec(acph->dtphr, valbuf[0], valbuf[1],
+ valbuf[2], valbuf[3], valbuf[4],
+ nrwordspre, nrwordsfol, nrsyllsfol)) {
+ /* error constructing invec */
+ PICODBG_WARN(("problem with invec"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR,
+ NULL, NULL);
+ okay = FALSE;
+ }
+ /* classify */
+ if (okay && (!picokdt_dtPHRclassify(acph->dtphr))) {
+ /* error doing classification */
+ PICODBG_WARN(("problem classifying"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION,
+ NULL, NULL);
+ okay = FALSE;
+ }
+ /* decompose */
+ if (okay && (!picokdt_dtPHRdecomposeOutClass(acph->dtphr, &dtres))) {
+ /* error decomposing */
+ PICODBG_WARN(("problem decomposing"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR,
+ NULL, NULL);
+ okay = FALSE;
+ }
+
+ if (okay && dtres.set) {
+ PICODBG_DEBUG(("%d - inpos: %d, out: %d", i,valbuf[2],dtres.class));
+ } else {
+ PICODBG_WARN(("problem determining subphrase boundary strength"));
+ dtres.class = PICODATA_ITEMINFO1_ERR;
+ }
+
+ if (dtres.class > 255) {
+ PICODBG_WARN(("dt class outside valid range, setting to PHR0"));
+ dtres.class = PICODATA_ITEMINFO1_BOUND_PHR0;
+ }
+ acph->headx[i].boundstrength = (picoos_uint8)dtres.class;
+ if ((dtres.class == PICODATA_ITEMINFO1_BOUND_PHR2) ||
+ (dtres.class == PICODATA_ITEMINFO1_BOUND_PHR3)) {
+ if (nosubphrases) {
+ /* it's the last secondary phrase in the primary phrase */
+ /* add type info */
+ switch (acph->headx[acph->headxLen - 1].head.info2) {
+ case PICODATA_ITEMINFO2_PUNC_SENT_T:
+ acph->headx[i].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_T;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_SENT_Q:
+ acph->headx[i].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_Q;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_SENT_E:
+ acph->headx[i].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_E;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_PHRASE:
+ case PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED:
+ acph->headx[i].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_P;
+ break;
+ default:
+ PICODBG_WARN(("invalid boundary type, not set"));
+ break;
+ }
+ nosubphrases = FALSE;
+
+ } else {
+ acph->headx[i].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_P;
+ }
+ /* reset nr following words and sylls counters */
+ nrwordsfol = 0;
+ nrsyllsfol = 0;
+ }
+ }
+
+ /* process first item, add bound-info */
+ switch (acph->boundStrengthState) {
+ case SA_BOUNDSTRENGTH_SSEP:
+ acph->headx[0].boundstrength =
+ PICODATA_ITEMINFO1_BOUND_SBEG;
+ break;
+ case SA_BOUNDSTRENGTH_PPHR:
+ acph->headx[0].boundstrength =
+ PICODATA_ITEMINFO1_BOUND_PHR1;
+ break;
+ default:
+ PICODBG_WARN(("invalid boundary strength, not set"));
+ break;
+ }
+
+ /* set boundary strength state */
+ switch (acph->headx[acph->headxLen - 1].head.info1) {
+ case PICODATA_ITEMINFO1_PUNC_SENTEND:
+ case PICODATA_ITEMINFO1_PUNC_FLUSH:
+ acph->boundStrengthState = SA_BOUNDSTRENGTH_SSEP;
+ break;
+ case PICODATA_ITEMINFO1_PUNC_PHRASEEND:
+ acph->boundStrengthState = SA_BOUNDSTRENGTH_PPHR;
+ break;
+ default:
+ PICODBG_WARN(("invalid boundary strength state, not changed"));
+ break;
+ }
+
+ if (nosubphrases) {
+ /* process first item, add type info */
+ switch (acph->headx[acph->headxLen - 1].head.info2) {
+ case PICODATA_ITEMINFO2_PUNC_SENT_T:
+ acph->headx[0].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_T;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_SENT_Q:
+ acph->headx[0].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_Q;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_SENT_E:
+ acph->headx[0].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_E;
+ break;
+ case PICODATA_ITEMINFO2_PUNC_PHRASE:
+ case PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED:
+ acph->headx[0].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_P;
+ break;
+ default:
+ PICODBG_WARN(("invalid boundary type, not set"));
+ break;
+ }
+ } else {
+ acph->headx[0].boundtype =
+ PICODATA_ITEMINFO2_BOUNDTYPE_P;
+ }
+
+ return PICO_OK;
+}
+
+
+/* ***********************************************************************/
+/* PROCESS_ACC functions */
+/* ***********************************************************************/
+
+/* find next POS to the left of 'ind' and return its POS and index */
+static picoos_uint8 acphAccItemSeqGetPosLeft(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind,
+ picoos_uint16 *leftind) {
+ picoos_uint8 val;
+ picoos_int32 i;
+
+ val = PICOKDT_EPSILON;
+ for (i = ind - 1; ((val == PICOKDT_EPSILON) && (i >= 0)); i--) {
+ if ((acph->headx[i].head.type == PICODATA_ITEM_WORDPHON)) {
+ val = acph->headx[i].head.info1;
+ }
+ }
+ *leftind = i + 1;
+ return val;
+}
+
+
+/* s1: nr sylls in word before the first primary stressed syll,
+ s2: nr sylls in word after (but excluding) the first primary stressed syll */
+static picoos_uint8 acphAccNrSyllParts(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind,
+ picoos_uint8 *s1,
+ picoos_uint8 *s2) {
+ picoos_uint16 pind;
+ picoos_uint16 pend; /* phone string start+len */
+ picoos_uint8 afterprim;
+
+ /* check ind is in valid range */
+ if (ind >= acph->headxLen) {
+ return FALSE;
+ }
+
+ *s1 = 0;
+ *s2 = 0;
+ afterprim = FALSE;
+ pend = acph->headx[ind].cind + acph->headx[ind].head.len;
+ for (pind = acph->headx[ind].cind; pind < pend; pind++) {
+ if (picoktab_isPrimstress(acph->tabphones, acph->cbuf[pind])) {
+ afterprim = TRUE;
+ } else if (picoktab_isSyllbound(acph->tabphones, acph->cbuf[pind])) {
+ if (afterprim) {
+ (*s2)++;
+ } else {
+ (*s1)++;
+ }
+ }
+ }
+ if (afterprim) {
+ (*s2)++;
+ } else {
+ (*s1)++;
+ }
+
+ /* exclude the stressed syllable */
+ if ((*s2) > 0) {
+ (*s2)--;
+ }
+ /* handle the case when there is no primstress */
+ if (!afterprim) {
+ (*s2) = (*s1);
+ }
+ return TRUE;
+}
+
+
+static picoos_uint8 acphAccGetNrsRight(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind,
+ picoos_uint16 *nrwordsfol,
+ picoos_uint16 *nrsyllsfol,
+ picoos_uint16 *footwordsfol,
+ picoos_uint16 *footsyllsfol) {
+ picoos_uint16 i;
+ picoos_uint8 s1;
+ picoos_uint8 s2;
+
+ if (!acphAccNrSyllParts(this, acph, ind, &s1, &s2)) {
+ return FALSE;
+ }
+
+ *nrwordsfol = 0;
+ *nrsyllsfol = s2;
+ i = ind + 1;
+ while ((i < acph->headxLen) &&
+ (acph->headx[i].boundstrength == PICODATA_ITEMINFO1_BOUND_PHR0)) {
+ if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) {
+ (*nrwordsfol)++;
+ *nrsyllsfol += acphGetNrSylls(this, acph, i);
+ }
+ i++;
+ }
+
+ *footwordsfol = 0;
+ *footsyllsfol = s2;
+ i = ind + 1;
+ while ((i < acph->headxLen) &&
+ (acph->headx[i].head.info2 != PICODATA_ACC1)) {
+ if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) {
+ (*footwordsfol)++;
+ *footsyllsfol += acphGetNrSylls(this, acph, i);
+ }
+ i++;
+ }
+ if ((i < acph->headxLen) && (acph->headx[i].head.info2 == PICODATA_ACC1)) {
+ if (!acphAccNrSyllParts(this, acph, i, &s1, &s2)) {
+ return FALSE;
+ }
+ *footsyllsfol += s1;
+ }
+ return TRUE;
+}
+
+
+static picoos_uint8 acphAccGetNrsLeft(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind,
+ picoos_uint16 *nrwordspre,
+ picoos_uint16 *nrsyllspre) {
+ picoos_int32 i;
+ picoos_uint8 s1;
+ picoos_uint8 s2;
+
+ if (!acphAccNrSyllParts(this, acph, ind, &s1, &s2)) {
+ return FALSE;
+ }
+
+ *nrwordspre = 0;
+ *nrsyllspre = s1;
+ i = ind - 1;
+ while ((i >= 0) &&
+ (acph->headx[i].boundstrength == PICODATA_ITEMINFO1_BOUND_PHR0)) {
+ if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) {
+ (*nrwordspre)++;
+ *nrsyllspre += acphGetNrSylls(this, acph, i);
+ }
+ i--;
+ }
+
+ if ((acph->headx[i].boundstrength != PICODATA_ITEMINFO1_BOUND_PHR0) &&
+ (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON)) {
+ (*nrwordspre)++;
+ *nrsyllspre += acphGetNrSylls(this, acph, i);
+ }
+ return TRUE;
+}
+
+
+/* return TRUE if wordphon contains no stress, FALSE otherwise */
+static picoos_uint8 acphIsWordWithoutStress(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint16 ind) {
+ picoos_uint8 i;
+ picoos_uint16 pos;
+
+ pos = acph->headx[ind].cind;
+ for (i = 0; i < acph->headx[ind].head.len; i++) {
+ if (picoktab_isPrimstress(acph->tabphones, acph->cbuf[pos + i]) ||
+ picoktab_isSecstress(acph->tabphones, acph->cbuf[pos + i])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/* right-to-left, for each WORDPHON do acc */
+static pico_status_t acphAccentuation(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph) {
+ picokdt_classify_result_t dtres;
+ picoos_uint8 valbuf[5];
+ picoos_uint16 hist1;
+ picoos_uint16 hist2;
+ picoos_uint16 nrwordspre;
+ picoos_uint16 nrsyllspre;
+ picoos_uint16 nrwordsfol;
+ picoos_uint16 nrsyllsfol;
+ picoos_uint16 footwordsfol;
+ picoos_uint16 footsyllsfol;
+ picoos_uint16 lastprev2; /* last index of POS(es) found to the left */
+ picoos_uint8 curpos; /* POS(es) of current word */
+ picoos_uint16 prevout;
+ picoos_uint8 okay;
+ picoos_int32 upbound; /* index of last WORDPHON item (with POS) */
+ picoos_uint16 i;
+
+ /* set initial values */
+ okay = TRUE;
+ curpos = PICOKDT_EPSILON; /* needs to be < 2^8 */
+
+ /* set upbound to last WORDPHON */
+ upbound = acph->headxLen - 1;
+ while ((upbound >= 0) &&
+ (acph->headx[upbound].head.type != PICODATA_ITEM_WORDPHON)) {
+ upbound--;
+ }
+
+ if (upbound < 0) {
+ /* phrase containing zero WORDPHON */
+ PICODBG_DEBUG(("no WORDPHON in phrase -> no accentuation"));
+ return PICO_OK;
+ }
+
+ lastprev2 = upbound;
+
+ /* set initial history values */
+ prevout = PICOKDT_HISTORY_ZERO;
+ hist1 = PICOKDT_HISTORY_ZERO;
+ hist2 = PICOKDT_HISTORY_ZERO;
+
+ /* set initial nr pre/fol words/sylls, upbound is ind of last WORDPHON */
+ nrwordsfol = 0;
+ nrsyllsfol = 0;
+ footwordsfol = 0;
+ footsyllsfol = 0;
+ nrwordspre = 0;
+ nrsyllspre = 0;
+
+ /* set POS of current word in valbuf[1], will be shifted right afterwards */
+ valbuf[1] = acph->headx[upbound].head.info1;
+ /* find first POS to the left and set valbuf[0] */
+ valbuf[0] = acphAccItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2);
+ for (i = 2; i < 5; i++) {
+ valbuf[i] = PICOKDT_EPSILON;
+ }
+
+ PICODBG_TRACE(("headxLen: %d", acph->headxLen));
+
+ /* process from right-to-left all items in headx */
+ for (i = upbound+1; i > 0; ) {
+ i--;
+
+ okay = TRUE;
+
+ PICODBG_TRACE(("iter: %d, type: %c", i, acph->headx[i].head.type));
+
+ /* if not (WORDPHON) */
+ if ((acph->headx[i].head.type != PICODATA_ITEM_WORDPHON)) {
+ continue;
+ }
+
+ PICODBG_TRACE(("iter: %d, curpos: %d", i, acph->headx[i].head.info1));
+
+ /* get and set POS of current item, must be WORDPHON */
+ curpos = acph->headx[i].head.info1;
+
+ /* no continue so far => at [i] we have a WORDPHON item */
+ /* shift all POS elements one position to the right */
+ valbuf[4] = valbuf[3];
+ valbuf[3] = valbuf[2];
+ valbuf[2] = valbuf[1];
+ valbuf[1] = valbuf[0];
+ /* find next POS to the left and set valbuf[0] */
+ valbuf[0] = acphAccItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2);
+
+ /* better check double than never */
+ if (curpos != valbuf[2]) {
+ PICODBG_WARN(("syncing POS"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR,
+ NULL, NULL);
+ valbuf[2] = curpos;
+ }
+
+ /* set history values */
+ hist2 = hist1;
+ hist1 = prevout;
+
+ /* ************************************************************ */
+ /* many speedups possible by avoiding double calc of attribtues */
+ /* ************************************************************ */
+
+ /* get distances */
+ if ((!acphAccGetNrsRight(this, acph, i, &nrwordsfol, &nrsyllsfol,
+ &footwordsfol, &footsyllsfol)) ||
+ (!acphAccGetNrsLeft(this, acph, i, &nrwordspre, &nrsyllspre))) {
+ PICODBG_WARN(("problem setting distances in invec"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR,
+ NULL, NULL);
+ okay = FALSE;
+ }
+
+ PICODBG_TRACE(("%d: [%d,%d,%d,%d,%d|%d,%d|%d,%d,%d,%d|%d,%d]", i,
+ valbuf[0], valbuf[1], valbuf[2], valbuf[3], valbuf[4],
+ hist1, hist2, nrwordspre, nrsyllspre,
+ nrwordsfol, nrsyllsfol, footwordsfol, footsyllsfol));
+
+ /* no continue so far => accentuation needed */
+ /* construct input vector, which is set in dtacc */
+ if (!picokdt_dtACCconstructInVec(acph->dtacc, valbuf[0], valbuf[1],
+ valbuf[2], valbuf[3], valbuf[4],
+ hist1, hist2, nrwordspre, nrsyllspre,
+ nrwordsfol, nrsyllsfol, footwordsfol,
+ footsyllsfol)) {
+ /* error constructing invec */
+ PICODBG_WARN(("problem with invec"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR,
+ NULL, NULL);
+ okay = FALSE;
+ }
+ /* classify */
+ if (okay && (!picokdt_dtACCclassify(acph->dtacc, &prevout))) {
+ /* error doing classification */
+ PICODBG_WARN(("problem classifying"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION,
+ NULL, NULL);
+ okay = FALSE;
+ }
+ /* decompose */
+ if (okay && (!picokdt_dtACCdecomposeOutClass(acph->dtacc, &dtres))) {
+ /* error decomposing */
+ PICODBG_WARN(("problem decomposing"));
+ picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR,
+ NULL, NULL);
+ okay = FALSE;
+ }
+
+ if (dtres.class > 255) {
+ PICODBG_WARN(("dt class outside valid range, setting to ACC0"));
+ dtres.class = PICODATA_ACC0;
+ }
+
+ if (okay && dtres.set) {
+ PICODBG_DEBUG(("%d - inpos: %d, out: %d", i,valbuf[2],dtres.class));
+ if (acphIsWordWithoutStress(this, acph, i)) {
+ if (dtres.class != PICODATA_ACC0) {
+ acph->headx[i].head.info2 = PICODATA_ACC3;
+ } else {
+ acph->headx[i].head.info2 = (picoos_uint8)dtres.class;
+ }
+ } else {
+ acph->headx[i].head.info2 = (picoos_uint8)dtres.class;
+ }
+ PICODBG_DEBUG(("%d - after-nostress-corr: %d",
+ i, acph->headx[i].head.info2));
+ } else {
+ PICODBG_WARN(("problem determining accentuation level"));
+ dtres.class = PICODATA_ITEMINFO1_ERR;
+ }
+ }
+ return PICO_OK;
+}
+
+
+
+/* ***********************************************************************/
+/* acphStep support functions */
+/* ***********************************************************************/
+
+static picoos_uint8 acphPutBoundItem(register picodata_ProcessingUnit this,
+ register acph_subobj_t *acph,
+ const picoos_uint8 strength,
+ const picoos_uint8 type,
+ picoos_uint8 *dopuoutfull,
+ picoos_uint16 *numBytesOutput) {
+ pico_status_t rv = PICO_OK;
+ picoos_uint16 blen = 0;
+ picodata_itemhead_t tmphead;
+
+ *dopuoutfull = FALSE;
+
+ /* construct BOUND item in tmpbuf and put item */
+ tmphead.type = PICODATA_ITEM_BOUND;
+ tmphead.info1 = strength;
+ tmphead.info2 = type;
+ tmphead.len = 0;
+ rv = picodata_put_itemparts(&tmphead, NULL, 0, acph->tmpbuf,
+ PICODATA_MAX_ITEMSIZE, &blen);
+ if (rv != PICO_OK) {
+ PICODBG_ERROR(("problem creating BOUND item"));
+ picoos_emRaiseException(this->common->em, rv, NULL, NULL);
+ return FALSE;
+ }
+ /* put constructed item to ext. charbuf */
+ rv = picodata_cbPutItem(this->cbOut, acph->tmpbuf, blen, &blen);
+
+ *numBytesOutput += blen;
+ if (rv == PICO_EXC_BUF_OVERFLOW) {
+ PICODBG_DEBUG(("overflow in cb output buffer"));
+ *dopuoutfull = TRUE; /* ie. do PU_OUT_FULL later */
+ return FALSE;
+ } else if (rv != PICO_OK) {
+ PICODBG_ERROR(("problem putting BOUND item"));
+ picoos_emRaiseException(this->common->em, rv, NULL, NULL);
+ return FALSE;
+ }
+
+ PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG],
+ (picoos_uint8 *)"acph: ", acph->tmpbuf, blen);
+
+ return TRUE;
+}
+
+
+
+/* ***********************************************************************/
+/* acphStep function */
+/* ***********************************************************************/
+
+/*
+complete phrase processed in one step, if not fast enough -> rework
+
+init, collect into internal buffer, process, and then feed to
+output buffer
+
+init state: INIT ext ext
+state trans: in hc1 hc2 out
+
+INIT | putItem = 0 0 +1 | BUSY -> COLL (put B-SBEG item,
+ set do-init to false)
+
+ inspace-ok-hc1
+ needs-more-items-(phrase-or-flush)
+COLL1 |getItems -n +n 0 1 | ATOMIC -> PPOSD (got items,
+ if flush set do-init)
+COLL2 |getItems -n +n 1 0 | ATOMIC -> PPOSD (got items, forced)
+COLL3 |getItems -n +n 1 1 | IDLE (got items, need more)
+COLL4 |getItems = = 1 1 | IDLE (got no items)
+
+PPOSD | posd = ~n~n | BUSY -> PWP (posd done)
+PWP | lex/g2p = ~n-n 0+n | BUSY -> PPHR (lex/g2p done)
+PPHR | phr = -n 0 +m=n | BUSY -> PACC (phr done, m>=n)
+PACC | acc = 0 0 ~m=n | BUSY -> FEED (acc done)
+
+ doinit-flag
+FEED | putItems 0 0 0 -m-n +m 0 | BUSY -> COLL (put items)
+FEED | putItems 0 0 0 -m-n +m 1 | BUSY -> INIT (put items)
+FEED | putItems 0 0 0 -d-d +d | OUT_FULL (put some items)
+*/
+
+static picodata_step_result_t acphStep(register picodata_ProcessingUnit this,
+ picoos_int16 mode,
+ picoos_uint16 *numBytesOutput) {
+ register acph_subobj_t *acph;
+ pico_status_t rv = PICO_OK;
+ pico_status_t rvP = PICO_OK;
+ picoos_uint16 blen = 0;
+ picoos_uint16 clen = 0;
+ picoos_uint16 i;
+
+
+ if (NULL == this || NULL == this->subObj) {
+ return PICODATA_PU_ERROR;
+ }
+ acph = (acph_subobj_t *) this->subObj;
+ mode = mode; /* avoid warning "var not used in this function"*/
+ *numBytesOutput = 0;
+ while (1) { /* exit via return */
+ PICODBG_DEBUG(("doing state %i, hLen|c1Len: %d|%d",
+ acph->procState, acph->headxLen, acph->cbufLen));
+
+ switch (acph->procState) {
+
+ /* *********************************************************/
+ /* collect state: get item(s) from charBuf and store in
+ * internal buffers, need a complete punctuation-phrase
+ */
+ case SA_STEPSTATE_COLLECT:
+
+ while (acph->inspaceok && acph->needsmoreitems && (PICO_OK ==
+ (rv = picodata_cbGetItem(this->cbIn, acph->tmpbuf,
+ PICODATA_MAX_ITEMSIZE, &blen)))) {
+ rvP = picodata_get_itemparts(acph->tmpbuf,
+ PICODATA_MAX_ITEMSIZE, &(acph->headx[acph->headxLen].head),
+ &(acph->cbuf[acph->cbufLen]), acph->cbufBufSize
+ - acph->cbufLen, &clen);
+ if (rvP != PICO_OK) {
+ PICODBG_ERROR(("problem getting item parts"));
+ picoos_emRaiseException(this->common->em, rvP,
+ NULL, NULL);
+ return PICODATA_PU_ERROR;
+ }
+
+ /* if CMD(...FLUSH...) -> PUNC(...FLUSH...),
+ construct PUNC-FLUSH item in headx */
+ if ((acph->headx[acph->headxLen].head.type
+ == PICODATA_ITEM_CMD)
+ && (acph->headx[acph->headxLen].head.info1
+ == PICODATA_ITEMINFO1_CMD_FLUSH)) {
+ acph->headx[acph->headxLen].head.type
+ = PICODATA_ITEM_PUNC;
+ acph->headx[acph->headxLen].head.info1
+ = PICODATA_ITEMINFO1_PUNC_FLUSH;
+ acph->headx[acph->headxLen].head.info2
+ = PICODATA_ITEMINFO2_PUNC_SENT_T;
+ acph->headx[acph->headxLen].head.len = 0;
+ }
+
+ /* check/set needsmoreitems */
+ if (acph->headx[acph->headxLen].head.type
+ == PICODATA_ITEM_PUNC) {
+ acph->needsmoreitems = FALSE;
+ }
+
+ /* check/set inspaceok, keep spare slot for forcing */
+ if ((acph->headxLen >= (PICOACPH_MAXNR_HEADX - 2))
+ || ((acph->cbufBufSize - acph->cbufLen)
+ < PICODATA_MAX_ITEMSIZE)) {
+ acph->inspaceok = FALSE;
+ }
+
+ if (clen > 0) {
+ acph->headx[acph->headxLen].cind = acph->cbufLen;
+ acph->cbufLen += clen;
+ } else {
+ acph->headx[acph->headxLen].cind = 0;
+ }
+ acph->headxLen++;
+ }
+
+ if (!acph->needsmoreitems) {
+ /* 1, phrase buffered */
+ acph->procState = SA_STEPSTATE_PROCESS_PHR;
+ return PICODATA_PU_ATOMIC;
+ } else if (!acph->inspaceok) {
+ /* 2, forced phrase end */
+ /* at least one slot is still free, use it to
+ force a trailing PUNC item */
+ acph->headx[acph->headxLen].head.type = PICODATA_ITEM_PUNC;
+ acph->headx[acph->headxLen].head.info1 =
+ PICODATA_ITEMINFO1_PUNC_PHRASEEND;
+ acph->headx[acph->headxLen].head.info2 =
+ PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED;
+ acph->headx[acph->headxLen].head.len = 0;
+ acph->needsmoreitems = FALSE; /* not really needed for now */
+ acph->headxLen++;
+ PICODBG_WARN(("forcing phrase end, added PUNC_PHRASEEND"));
+ picoos_emRaiseWarning(this->common->em,
+ PICO_WARN_FALLBACK, NULL,
+ (picoos_char *)"forced phrase end");
+ acph->procState = SA_STEPSTATE_PROCESS_PHR;
+ return PICODATA_PU_ATOMIC;
+ } else if (rv == PICO_EOF) {
+ /* 3, 4 */
+ return PICODATA_PU_IDLE;
+ } else if ((rv == PICO_EXC_BUF_UNDERFLOW) ||
+ (rv == PICO_EXC_BUF_OVERFLOW)) {
+ /* error, no valid item in cb (UNDER) */
+ /* or tmpbuf not large enough, not possible (OVER) */
+ /* no exception raised, left for ctrl to handle */
+ PICODBG_ERROR(("buffer under/overflow, rv: %d", rv));
+ return PICODATA_PU_ERROR;
+ } else {
+ /* error, only possible if cbGetItem implementation
+ changes without this function being adapted*/
+ PICODBG_ERROR(("untreated return value, rv: %d", rv));
+ return PICODATA_PU_ERROR;
+ }
+ break;
+
+
+
+
+ /* *********************************************************/
+ /* process phr state: process items in headx and modify
+ * headx in place
+ */
+ case SA_STEPSTATE_PROCESS_PHR:
+ /* ensure there is an item in inBuf */
+ if (acph->headxLen > 0) {
+ /* we have a phrase in headx, cbuf1 (can be
+ single PUNC item), do phrasing and modify headx */
+
+ if (PICO_OK != acphSubPhrasing(this, acph)) {
+ picoos_emRaiseException(this->common->em,
+ PICO_ERR_OTHER, NULL, NULL);
+ return PICODATA_PU_ERROR;
+ }
+ acph->procState = SA_STEPSTATE_PROCESS_ACC;
+ } else if (acph->headxLen == 0) { /* no items in inBuf */
+ PICODBG_WARN(("no items in inBuf"));
+ acph->procState = SA_STEPSTATE_COLLECT;
+ return PICODATA_PU_BUSY;
+ }
+
+#if defined (PICO_DEBUG_NOTNEEDED)
+ if (1) {
+ picoos_uint8 i, j, ittype;
+ for (i = 0; i < acph->headxLen; i++) {
+ if ((acph->headx[i].boundstrength != 0) &&
+ (acph->headx[i].boundstrength !=
+ PICODATA_ITEMINFO1_BOUND_PHR0)) {
+ PICODBG_INFO(("acph-p: boundstrength '%c', "
+ "boundtype '%c'",
+ acph->headx[i].boundstrength,
+ acph->headx[i].boundtype));
+ }
+
+ ittype = acph->headx[i].head.type;
+ PICODBG_INFO_CTX();
+ PICODBG_INFO_MSG(("acph-p: ("));
+ PICODBG_INFO_MSG(("'%c',", ittype));
+ if ((32 <= acph->headx[i].head.info1) &&
+ (acph->headx[i].head.info1 < 127) &&
+ (ittype != PICODATA_ITEM_WORDPHON)) {
+ PICODBG_INFO_MSG(("'%c',",acph->headx[i].head.info1));
+ } else {
+ PICODBG_INFO_MSG(("%3d,", acph->headx[i].head.info1));
+ }
+ if ((32 <= acph->headx[i].head.info2) &&
+ (acph->headx[i].head.info2 < 127)) {
+ PICODBG_INFO_MSG(("'%c',",acph->headx[i].head.info2));
+ } else {
+ PICODBG_INFO_MSG(("%3d,", acph->headx[i].head.info2));
+ }
+ PICODBG_INFO_MSG(("%3d)", acph->headx[i].head.len));
+
+ for (j = 0; j < acph->headx[i].head.len; j++) {
+ if ((ittype == PICODATA_ITEM_CMD)) {
+ PICODBG_INFO_MSG(("%c",
+ acph->cbuf[acph->headx[i].cind+j]));
+ } else {
+ PICODBG_INFO_MSG(("%4d",
+ acph->cbuf[acph->headx[i].cind+j]));
+ }
+ }
+ PICODBG_INFO_MSG(("\n"));
+ }
+ }
+#endif
+
+ break;
+
+
+ /* *********************************************************/
+ /* process acc state: process items in headx and modify
+ * headx in place
+ */
+ case SA_STEPSTATE_PROCESS_ACC:
+ /* ensure there is an item in inBuf */
+ if (acph->headxLen > 0) {
+ /* we have a phrase in headx, cbuf (can be
+ single PUNC item), do accentuation and modify headx */
+ if (PICO_OK != acphAccentuation(this, acph)) {
+ picoos_emRaiseException(this->common->em,
+ PICO_ERR_OTHER, NULL, NULL);
+ return PICODATA_PU_ERROR;
+ }
+ acph->procState = SA_STEPSTATE_FEED;
+ } else if (acph->headxLen == 0) { /* no items in inBuf */
+ PICODBG_WARN(("no items in inBuf"));
+ acph->procState = SA_STEPSTATE_COLLECT;
+ return PICODATA_PU_BUSY;
+ }
+ break;
+
+
+ /* *********************************************************/
+ /* feed state: copy item in internal outBuf to output charBuf */
+ case SA_STEPSTATE_FEED: {
+ picoos_uint16 indupbound;
+ picoos_uint8 dopuoutfull;
+
+ PICODBG_DEBUG(("put out items (bot, len): (%d, %d)",
+ acph->headxBottom, acph->headxLen));
+
+ indupbound = acph->headxBottom + acph->headxLen;
+ dopuoutfull = FALSE;
+
+ if (acph->headxBottom == 0) {
+ /* construct first BOUND item in tmpbuf and put item */
+ /* produce BOUND unless it is followed by a term/flush) */
+ if (acph->headx[0].head.info1
+ != PICODATA_ITEMINFO1_PUNC_FLUSH) {
+ if (!acphPutBoundItem(this, acph,
+ acph->headx[0].boundstrength,
+ acph->headx[0].boundtype, &dopuoutfull,
+ numBytesOutput)) {
+ if (dopuoutfull) {
+ PICODBG_DEBUG(("feeding overflow"));
+ return PICODATA_PU_OUT_FULL;
+ } else {
+ /* ERR-msg and exception done in acphPutBoundItem */
+ return PICODATA_PU_ERROR;
+ }
+ }
+ }
+ }
+
+ /* for all items in headx, cbuf */
+ for (i = acph->headxBottom; i < indupbound; i++) {
+
+ switch (acph->headx[i].head.type) {
+ case PICODATA_ITEM_PUNC:
+ /* if sentence end, put SEND bound */
+ if ((acph->headx[i].head.info1 ==
+ PICODATA_ITEMINFO1_PUNC_SENTEND) &&
+ (i == (indupbound - 1))) {
+ /* construct and put BOUND item */
+ if (!acphPutBoundItem(this, acph,
+ PICODATA_ITEMINFO1_BOUND_SEND,
+ PICODATA_ITEMINFO2_NA,
+ &dopuoutfull, numBytesOutput)) {
+ if (dopuoutfull) {
+ PICODBG_DEBUG(("feeding overflow"));
+ return PICODATA_PU_OUT_FULL;
+ } else {
+ /* ERR-msg and exception done
+ in acphPutBoundItem */
+ return PICODATA_PU_ERROR;
+ }
+ }
+ } else if ((acph->headx[i].head.info1 ==
+ PICODATA_ITEMINFO1_PUNC_FLUSH) &&
+ (i == (indupbound - 1))) {
+ /* construct and put BOUND item */
+ if (!acphPutBoundItem(this, acph,
+ PICODATA_ITEMINFO1_BOUND_TERM,
+ PICODATA_ITEMINFO2_NA,
+ &dopuoutfull, numBytesOutput)) {
+ if (dopuoutfull) {
+ PICODBG_DEBUG(("feeding overflow"));
+ return PICODATA_PU_OUT_FULL;
+ } else {
+ /* ERR-msg and exception done
+ in acphPutBoundItem */
+ return PICODATA_PU_ERROR;
+ }
+ }
+ }
+ /* else, good-bye PUNC, not needed anymore */
+ break;
+ default:
+
+ /* PHR2/3 maybe existing, check and add
+ BOUND item now, if needed */
+ if ((acph->headx[i].boundstrength ==
+ PICODATA_ITEMINFO1_BOUND_PHR2) ||
+ (acph->headx[i].boundstrength ==
+ PICODATA_ITEMINFO1_BOUND_PHR3)) {
+ if (!acphPutBoundItem(this, acph,
+ acph->headx[i].boundstrength,
+ acph->headx[i].boundtype,
+ &dopuoutfull, numBytesOutput)) {
+ if (dopuoutfull) {
+ PICODBG_DEBUG(("feeding overflow"));
+ return PICODATA_PU_OUT_FULL;
+ } else {
+ /* ERR-msg and exception done
+ in acphPutBoundItem */
+ return PICODATA_PU_ERROR;
+ }
+ }
+ }
+
+ /* copy item unmodified */
+ rv = picodata_put_itemparts(&(acph->headx[i].head),
+ &(acph->cbuf[acph->headx[i].cind]),
+ acph->headx[i].head.len,
+ acph->tmpbuf, PICODATA_MAX_ITEMSIZE,
+ &blen);
+
+ rvP = picodata_cbPutItem(this->cbOut, acph->tmpbuf,
+ PICODATA_MAX_ITEMSIZE, &clen);
+
+ *numBytesOutput += clen;
+
+ PICODBG_DEBUG(("put item, status: %d", rvP));
+
+ if (rvP == PICO_OK) {
+ acph->headxBottom++;
+ acph->headxLen--;
+ } else if (rvP == PICO_EXC_BUF_OVERFLOW) {
+ /* try again next time, but PHR2/3
+ bound already added if existing,
+ ensure it's not output a 2nd
+ time */
+ PICODBG_DEBUG(("feeding overflow"));
+ acph->headx[i].boundstrength = 0;
+ return PICODATA_PU_OUT_FULL;
+ } else {
+ /* error, should never happen */
+ PICODBG_ERROR(("untreated return value, rvP: %d", rvP));
+ return PICODATA_PU_ERROR;
+ }
+
+ PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG],
+ (picoos_uint8 *)"acph: ",
+ acph->tmpbuf, PICODATA_MAX_ITEMSIZE);
+
+ break;
+ } /*switch*/
+ } /*for*/
+
+ /* reset headx, cbuf */
+ acph->headxBottom = 0;
+ acph->headxLen = 0;
+ acph->cbufLen = 0;
+ for (i = 0; i < PICOACPH_MAXNR_HEADX; i++) {
+ acph->headx[i].boundstrength = 0;
+ }
+
+ /* reset collect state support variables */
+ acph->inspaceok = TRUE;
+ acph->needsmoreitems = TRUE;
+
+ acph->procState = SA_STEPSTATE_COLLECT;
+ return PICODATA_PU_BUSY;
+ break;
+ }
+
+ default:
+ break;
+ } /* switch */
+
+ } /* while */
+
+ /* should be never reached */
+ PICODBG_ERROR(("reached end of function"));
+ picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL);
+ return PICODATA_PU_ERROR;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* end */