| /* |
| * 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 */ |