diff options
Diffstat (limited to 'lib/picoacph.c')
-rw-r--r-- | lib/picoacph.c | 1430 |
1 files changed, 1430 insertions, 0 deletions
diff --git a/lib/picoacph.c b/lib/picoacph.c new file mode 100644 index 0000000..98feb6e --- /dev/null +++ b/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 */ |