Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /**
     17  * @file picocep.c
     18  *
     19  * Phonetic to Acoustic Mapping PU - Implementation
     20  *
     21  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
     22  * All rights reserved.
     23  *
     24  * History:
     25  * - 2009-04-20 -- initial version
     26  *
     27  */
     28 
     29 /**
     30  * @addtogroup picocep
     31  * <b> Pico Cepstral Smoothing </b>\n
     32  *
     33  itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content
     34  in the following
     35 
     36  items input
     37 
     38  processed:
     39 
     40  - PHONE(PHONID,StatesPerPhone)[FramesPerState|f0Index|mgcIndex]{StatesPerPhone}
     41 
     42  (StatesPerPhone is a constant (5) for the time being. The content size is therfore allways 34)
     43 
     44  unprocessed:
     45  - all other item types are forwarded through the PU without modification
     46 
     47  items output
     48 
     49  FRAME(PHONID,F0 [?])ceps{25}
     50 
     51  each PHONE produces at least StatesPerPhone FRAME (if each state has FramesPerState == 1), but usually more.
     52 
     53  minimal input size (before processing starts)
     54 
     55  other limitations
     56 
     57  */
     58 #include "picodefs.h"
     59 #include "picoos.h"
     60 #include "picodbg.h"
     61 #include "picodata.h"
     62 #include "picokpdf.h"
     63 #include "picodsp.h"
     64 #include "picocep.h"
     65 
     66 #ifdef __cplusplus
     67 extern "C" {
     68 #endif
     69 #if 0
     70 }
     71 #endif
     72 
     73 #define PICOCEP_MAXWINLEN 10000  /* maximum number of frames that can be smoothed, i.e. maximum sentence length */
     74 #define PICOCEP_MSGSTR_SIZE 32
     75 #define PICOCEP_IN_BUFF_SIZE PICODATA_BUFSIZE_DEFAULT
     76 
     77 #define PICOCEP_OUT_DATA_FORMAT PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FIXED /* we output coefficients as fixed point values */
     78 
     79 #define PICOCEP_STEPSTATE_COLLECT         0
     80 #define PICOCEP_STEPSTATE_PROCESS_PARSE   1
     81 #define PICOCEP_STEPSTATE_PROCESS_SMOOTH  2
     82 #define PICOCEP_STEPSTATE_PROCESS_FRAME   3
     83 #define PICOCEP_STEPSTATE_FEED            4
     84 
     85 #define PICOCEP_LFZINVPOW 31  /* cannot be higher than 31 because 1<<invpow must fit in uint32 */
     86 #define PICOCEP_MGCINVPOW 24
     87 #define PICOCEP_LFZDOUBLEDEC 1
     88 #define PICOCEP_MGCDOUBLEDEC 0
     89 
     90 typedef enum picocep_WantMeanOrIvar
     91 {
     92     PICOCEP_WANTMEAN, PICOCEP_WANTIVAR
     93 } picocep_WantMeanOrIvar_t;
     94 
     95 typedef enum picocep_WantStaticOrDeltax
     96 {
     97     PICOCEP_WANTSTATIC, PICOCEP_WANTDELTA, PICOCEP_WANTDELTA2
     98 } picocep_WantStaticOrDelta_t;
     99 
    100 /*
    101  *   Fixedpoint arithmetic (might go into a separate module if general enough and needed by other modules)
    102  */
    103 
    104 #if defined(PICO_DEBUG) || defined(PICO_DEVEL_MODE)
    105 int numlongmult = 0, numshortmult = 0;
    106 #endif
    107 
    108 #define POW1 (0x1)
    109 #define POW2 (0x2)
    110 #define POW3 (0x4)
    111 #define POW4 (0x8)
    112 #define POW5 (0x10)
    113 #define POW6 (0x20)
    114 #define POW7 (0x40)
    115 #define POW8 (0x80)
    116 #define POW9 (0x100)
    117 #define POW10 (0x200)
    118 #define POW11 (0x400)
    119 #define POW12 (0x800)
    120 #define POW13 (0x1000)
    121 #define POW14 (0x2000)
    122 #define POW15 (0x4000)
    123 #define POW16 (0x8000)
    124 #define POW17 (0x10000)
    125 #define POW18 (0x20000)
    126 #define POW19 (0x40000)
    127 #define POW20 (0x80000)
    128 #define POW21 (0x100000)
    129 #define POW22 (0x200000)
    130 #define POW23 (0x400000)
    131 #define POW24 (0x800000)
    132 #define POW25 (0x1000000)
    133 #define POW26 (0x2000000)
    134 #define POW27 (0x4000000)
    135 #define POW28 (0x8000000)
    136 #define POW29 (0x10000000)
    137 #define POW30 (0x20000000)
    138 #define POW31 (0x40000000)
    139 
    140 /* item num restriction: maximum number of extended item heads in headx */
    141 #define PICOCEP_MAXNR_HEADX    60
    142 /* item num restriction: maximum size of all item contents together in cont */
    143 #define PICOCEP_MAXSIZE_CBUF 7680 /* (128 * PICOCEP_MAXNR_HEADX) */
    144 
    145 typedef struct
    146 {
    147     picodata_itemhead_t head;
    148     picoos_uint16 cind;
    149     picoos_uint16 frame; /* sync position */
    150 } picoacph_headx_t;
    151 
    152 /*----------------------------------------------------------
    153  //    Name    :    cep_subobj
    154  //    Function:    subobject definition for the cep processing
    155  //    Shortcut:    cep
    156  //---------------------------------------------------------*/
    157 typedef struct cep_subobj
    158 {
    159     /*----------------------PU voice management------------------------------*/
    160     /* picorsrc_Voice voice; */
    161     /*----------------------PU state management------------------------------*/
    162     picoos_uint8 procState; /* where to take up work at next processing step */
    163     picoos_bool needMoreInput; /* more data necessary to start processing   */
    164     /* picoos_uint8 force; *//* forced processing (needMoreData but buffers full */
    165     picoos_uint8 sentenceEnd;
    166     picoos_uint8 feedFollowState;
    167     picoos_bool inIgnoreState;
    168     /*----------------------PU input management------------------------------*/
    169     picoos_uint8 inBuf[PICODATA_MAX_ITEMSIZE]; /* internal input buffer */
    170     picoos_uint16 inBufSize; /* actually allocated size */
    171     picoos_uint16 inReadPos, inWritePos; /* next pos to read/write from/to inBuf*/
    172     picoos_uint16 nextInPos;
    173 
    174     picoacph_headx_t headx[PICOCEP_MAXNR_HEADX];
    175     picoos_uint16 headxBottom; /* bottom */
    176     picoos_uint16 headxWritePos; /* next free position; headx is empty if headxBottom == headxWritePos */
    177 
    178     picoos_uint8 cbuf[PICOCEP_MAXSIZE_CBUF];
    179     picoos_uint16 cbufBufSize; /* actually allocated size */
    180     picoos_uint16 cbufWritePos; /* length, 0 if empty */
    181 
    182     /*----------------------PU output management-----------------------------*/
    183     picodata_itemhead_t framehead;
    184     picoos_uint8 outBuf[PICODATA_MAX_ITEMSIZE]; /* internal output buffer (one item) */
    185     picoos_uint16 outBufSize; /* allocated outBuf size */
    186     picoos_uint16 outReadPos, outWritePos; /* next pos to read/write from/to outBuf*/
    187 
    188     picoos_uint32 nNumFrames;
    189     /*---------------------- other working variables ---------------------------*/
    190 
    191     picoos_int32 diag0[PICOCEP_MAXWINLEN], diag1[PICOCEP_MAXWINLEN],
    192             diag2[PICOCEP_MAXWINLEN], WUm[PICOCEP_MAXWINLEN],
    193             invdiag0[PICOCEP_MAXWINLEN];
    194 
    195     /*---------------------- constants --------------------------------------*/
    196     picoos_int32 xi[5], x1[2], x2[3], xm[3], xn[2];
    197     picoos_int32 xsqi[5], xsq1[2], xsq2[3], xsqm[3], xsqn[2];
    198 
    199     picoos_uint32 scmeanpowLFZ, scmeanpowMGC;
    200     picoos_uint32 scmeanLFZ, scmeanMGC;
    201 
    202     /*---------------------- indices --------------------------------------*/
    203     /* index buffer to hold indices as input for smoothing */
    204     picoos_uint16 indicesLFZ[PICOCEP_MAXWINLEN];
    205     picoos_uint16 indicesMGC[PICOCEP_MAXWINLEN];
    206     picoos_uint16 indexReadPos, indexWritePos;
    207     picoos_uint16 activeEndPos; /* end position of indices to be considered */
    208 
    209     /* this is used for input and output */
    210     picoos_uint8 phoneId[PICOCEP_MAXWINLEN]; /* synchronised with indexReadPos */
    211 
    212     /*---------------------- coefficients --------------------------------------*/
    213     /* output coefficients buffer */
    214     picoos_int16 * outF0;
    215     picoos_uint16 outF0ReadPos, outF0WritePos;
    216     picoos_int16 * outXCep;
    217     picoos_uint32 outXCepReadPos, outXCepWritePos;  /* uint32 needed for MAXWINLEN*ceporder > 2^16 */
    218     picoos_uint8 * outVoiced;
    219     picoos_uint16 outVoicedReadPos, outVoicedWritePos;
    220 
    221     /*---------------------- LINGWARE related data -------------------*/
    222     /* pdflfz knowledge base */
    223     picokpdf_PdfMUL pdflfz, pdfmgc;
    224 
    225 } cep_subobj_t;
    226 
    227 /**
    228  * picocep_highestBit
    229  * @brief        find the highest non-zero bit in input x
    230  * @remarks        this may be implemented by comparing x to powers of 2
    231  *                or instead of calling this function perform multiplication
    232  *                and consult overflow register if available on target
    233  * @note        implemented as a series of macros
    234  */
    235 
    236 #define picocep_highestBitNZ(x) (x>=POW17?(x>=POW25?(x>=POW29?(x>=POW31?31:(x>=POW30?30:29)):(x>=POW27?(x>=POW28?28:27):(x>=POW26?26:25))):(x>=POW21?(x>=POW23?(x>=POW24?24:23):(x>=POW22?22:21)):(x>=POW19?(x>=POW20?20:19):(x>=POW18?18:17)))):(x>=POW9?(x>=POW13?(x>=POW15?(x>=POW16?16:15):(x>=POW14?14:13)):(x>=POW11?(x>=POW12?12:11):(x>=POW10?10:9))):(x>=POW5?(x>=POW7?(x>=POW8?8:7):(x>=POW6?6:5)):(x>=POW3?(x>=POW4?4:3):(x>=POW2?2:1)))))
    237 #define picocep_highestBitU(x) (x==0?0:picocep_highestBitNZ(x))
    238 #define picocep_highestBitS(x,zz) (x==0?0:(x<0?((zz)=(-x),picocep_highestBitNZ(zz)):picocep_highestBitNZ(x)))
    239 
    240 /* ------------------------------------------------------------------------------
    241  Internal function definitions
    242  ---------------------------------------------------------------------------------*/
    243 
    244 static void initSmoothing(cep_subobj_t * cep);
    245 
    246 static picoos_int32 getFromPdf(picokpdf_PdfMUL pdf, picoos_uint32 vecstart,
    247         picoos_uint8 cepnum, picocep_WantMeanOrIvar_t wantMeanOrIvar,
    248         picocep_WantStaticOrDelta_t wantStaticOrDeltax);
    249 
    250 static void invMatrix(cep_subobj_t * cep, picoos_uint16 N,
    251         picoos_int16 *smoothcep, picoos_uint8 cepnum,
    252         picokpdf_PdfMUL pdf, picoos_uint8 invpow, picoos_uint8 invDoubleDec);
    253 
    254 static picoos_uint8 makeWUWandWUm(cep_subobj_t * cep, picokpdf_PdfMUL pdf,
    255         picoos_uint16 *indices, picoos_uint16 b, picoos_uint16 N,
    256         picoos_uint8 cepnum);
    257 
    258 static void getDirect(picokpdf_PdfMUL pdf, picoos_uint16 *indices,
    259         picoos_uint16 activeEndPos,
    260         picoos_uint8 cepnum, picoos_int16 *smoothcep);
    261 
    262 static void getVoiced(picokpdf_PdfMUL pdf, picoos_uint16 *indices,
    263         picoos_uint16 activeEndPos,
    264         picoos_uint8 *smoothcep);
    265 
    266 static picoos_uint16 get_pi_uint16(picoos_uint8 * buf, picoos_uint16 *pos);
    267 
    268 static void treat_phone(cep_subobj_t * cep, picodata_itemhead_t * ihead);
    269 
    270 static picoos_uint8 forwardingItem(picodata_itemhead_t * ihead);
    271 
    272 static picodata_step_result_t cepStep(register picodata_ProcessingUnit this,
    273         picoos_int16 mode, picoos_uint16 * numBytesOutput);
    274 
    275 /* --------------------------------------------
    276  *   generic PU management
    277  * --------------------------------------------
    278  */
    279 
    280 /**
    281  * initialization of a cep PU (processing unit)
    282  * @param    this : handle to a cep PU struct
    283  * @return  PICO_OK : init succeded
    284  * @return  PICO_ERR_OTHER : init failed
    285  * @callgraph
    286  * @callergraph
    287  */
    288 static pico_status_t cepInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode)
    289 {
    290     /*pico_status_t nRes;*/
    291     cep_subobj_t * cep;
    292     if (NULL == this || NULL == this->subObj) {
    293         return PICO_ERR_OTHER;
    294     }
    295     cep = (cep_subobj_t *) this->subObj;
    296     /* inBuf */
    297     cep->inBufSize = PICODATA_BUFSIZE_CEP;
    298     cep->inReadPos = 0;
    299     cep->inWritePos = 0;
    300     /* headx and cbuf */
    301     cep->headxBottom = cep->headxWritePos = 0;
    302     cep->cbufBufSize = PICOCEP_MAXSIZE_CBUF;
    303     cep->cbufWritePos = 0;
    304     /* outBuf */
    305     cep->outBufSize = PICODATA_MAX_ITEMSIZE;
    306     cep->outReadPos = 0;
    307     cep->outWritePos = 0;
    308     /* indices* */
    309     cep->indexReadPos = 0;
    310     cep->indexWritePos = 0;
    311     /* outCep, outF0, outVoiced */
    312     cep->outXCepReadPos = 0;
    313     cep->outXCepWritePos = 0;
    314     cep->outVoicedReadPos = 0;
    315     cep->outVoicedWritePos = 0;
    316     cep->outF0ReadPos = 0;
    317     cep->outF0WritePos = 0;
    318 
    319     cep->needMoreInput = 0;
    320     cep->inIgnoreState = 0;
    321     cep->sentenceEnd = FALSE;
    322     cep->procState = PICOCEP_STEPSTATE_COLLECT;
    323 
    324     cep->nNumFrames = 0;
    325 
    326     /*-----------------------------------------------------------------
    327      * MANAGE Item I/O control management
    328      ------------------------------------------------------------------*/
    329     cep->activeEndPos = PICOCEP_MAXWINLEN;
    330 
    331     if (resetMode == PICO_RESET_FULL) {
    332         /* kb pdflfz */
    333         cep->pdflfz = picokpdf_getPdfMUL(
    334                 this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]);
    335 
    336         /* kb pdfmgc */
    337         cep->pdfmgc = picokpdf_getPdfMUL(
    338                 this->voice->kbArray[PICOKNOW_KBID_PDF_MGC]);
    339 
    340         /* kb tab phones */
    341         /* cep->phones =
    342          picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); */
    343 
    344         /*---------------------- other working variables ---------------------------*/
    345         /* define the (constant) FRAME_PAR item header */
    346         cep->framehead.type = PICODATA_ITEM_FRAME_PAR;
    347         cep->framehead.info1 = PICOCEP_OUT_DATA_FORMAT;
    348         cep->framehead.info2 = cep->pdfmgc->ceporder;
    349         cep->framehead.len = sizeof(picoos_uint16) + (cep->framehead.info2 + 4)
    350                 * sizeof(picoos_uint16);
    351         cep->scmeanpowLFZ = cep->pdflfz->bigpow - cep->pdflfz->meanpow;
    352         cep->scmeanpowMGC = cep->pdfmgc->bigpow - cep->pdfmgc->meanpow;
    353 
    354         cep->scmeanLFZ = (1 << (picoos_uint32) cep->scmeanpowLFZ);
    355 
    356         cep->scmeanMGC = (1 << (picoos_uint32) cep->scmeanpowMGC);
    357 
    358     }
    359     /* constants used in makeWUWandWUm */
    360     initSmoothing(cep);
    361 
    362 
    363     return PICO_OK;
    364 }/*cepInitialize*/
    365 
    366 /**
    367  * termination of a cep PU (processing unit)
    368  * @param    this : handle to a cep PU struct
    369  * @return  PICO_OK : termination succeded
    370  * @return  PICO_ERR_OTHER : termination failed
    371  * @callgraph
    372  * @callergraph
    373  */
    374 static pico_status_t cepTerminate(register picodata_ProcessingUnit this)
    375 {
    376     return PICO_OK;
    377 }
    378 
    379 /**
    380  * deallocation of a cep PU internal sub object
    381  * @param    this : handle to a cep PU struct
    382  * @param    mm : handle of the engine memory manager
    383  * @return  PICO_OK : deallocation succeded
    384  * @return  PICO_ERR_OTHER : deallocation failed
    385  * @callgraph
    386  * @callergraph
    387  */
    388 static pico_status_t cepSubObjDeallocate(register picodata_ProcessingUnit this,
    389         picoos_MemoryManager mm)
    390 {
    391 
    392     mm = mm; /* avoid warning "var not used in this function"*/
    393 #if defined(PICO_DEVEL_MODE)
    394     printf("number of long mult is %d, number of short mult is %i\n",numlongmult,numshortmult);
    395 #else
    396     PICODBG_INFO_MSG(("number of long mult is %d, number of short mult is %i\n",numlongmult,numshortmult));
    397 #endif
    398     if (NULL != this) {
    399         cep_subobj_t * cep = (cep_subobj_t *) this->subObj;
    400         picoos_deallocate(this->common->mm, (void *) &cep->outXCep);
    401         picoos_deallocate(this->common->mm, (void *) &cep->outVoiced);
    402         picoos_deallocate(this->common->mm, (void *) &cep->outF0);
    403         picoos_deallocate(this->common->mm, (void *) &this->subObj);
    404     }
    405     return PICO_OK;
    406 }
    407 
    408 /**
    409  * creates a new cep PU (processing unit)
    410  * @param    mm : engine memory manager object pointer
    411  * @param    common : engine common object pointer
    412  * @param    cbIn : PU input buffer
    413  * @param    cbOut : PU output buffer
    414  * @param    voice : the voice descriptor object
    415  * @return  a valid PU handle if creation succeded
    416  * @return  NULL : creation failed
    417  * @callgraph
    418  * @callergraph
    419  */
    420 picodata_ProcessingUnit picocep_newCepUnit(picoos_MemoryManager mm,
    421         picoos_Common common, picodata_CharBuffer cbIn,
    422         picodata_CharBuffer cbOut, picorsrc_Voice voice)
    423 {
    424     picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn,
    425             cbOut, voice);
    426     cep_subobj_t * cep;
    427 
    428     if (this == NULL) {
    429         return NULL;
    430     }
    431     this->initialize = cepInitialize;
    432 
    433     PICODBG_DEBUG(("set this->step to cepStep"));
    434 
    435     this->step = cepStep;
    436     this->terminate = cepTerminate;
    437     this->subDeallocate = cepSubObjDeallocate;
    438     this->subObj = picoos_allocate(mm, sizeof(cep_subobj_t));
    439 
    440     cep = (cep_subobj_t *) this->subObj;
    441 
    442     if (this->subObj == NULL) {
    443         picoos_deallocate(mm, (void*) &this);
    444         return NULL;
    445     };
    446 
    447     /* allocate output coeeficient buffers */
    448     cep->outF0 = (picoos_int16 *) picoos_allocate(this->common->mm,
    449             PICOCEP_MAXWINLEN * PICOKPDF_MAX_MUL_LFZ_CEPORDER
    450                     * sizeof(picoos_int16));
    451     cep->outXCep = (picoos_int16 *) picoos_allocate(this->common->mm,
    452             PICOCEP_MAXWINLEN * PICOKPDF_MAX_MUL_MGC_CEPORDER
    453                     * sizeof(picoos_int16));
    454     cep->outVoiced = (picoos_uint8 *) picoos_allocate(this->common->mm,
    455             PICOCEP_MAXWINLEN * sizeof(picoos_uint8));
    456 
    457     if ((NULL == cep->outF0) || (NULL == cep->outXCep) || (NULL
    458             == cep->outVoiced)) {
    459         picoos_deallocate(this->common->mm, (void *) &(cep->outF0));
    460         picoos_deallocate(this->common->mm, (void *) &(cep->outXCep));
    461         picoos_deallocate(this->common->mm, (void *) &(cep->outVoiced));
    462         picoos_deallocate(mm, (void*) &cep);
    463         picoos_deallocate(mm, (void*) &this);
    464         return NULL;
    465     }
    466     cepInitialize(this, PICO_RESET_FULL);
    467 
    468     return this;
    469 }/*picocep_newCepUnit*/
    470 
    471 /* --------------------------------------------
    472  *   processing and internal functions
    473  * --------------------------------------------
    474  */
    475 
    476 /**
    477  * multiply by 1<<pow and check overflow
    478  * @param    a : input value
    479  * @param    pow : shift value
    480  * @return  multiplied value
    481  * @callgraph
    482  * @callergraph
    483  */
    484 static picoos_int32 picocep_fixptmultpow(picoos_int32 a, picoos_uint8 pow)
    485 {
    486     picoos_int32 b;
    487     picoos_int32 zzz;
    488 
    489     if (picocep_highestBitS(a,zzz) + pow < 32) {
    490         b = a << pow;
    491     } else {
    492         /* clip to maximum positive or negative value */
    493         b = 1 << 31; /* maximum negative value */
    494         if (a > 0) {
    495             b -= 1; /* maximum positive value */
    496         }PICODBG_WARN(("picocep_fixptmultpow warning: overflow in fixed point multiplication %i*1<<%i.  Clipping to %i\n", a, pow, b));
    497     }
    498     return b;
    499 }
    500 
    501 /**
    502  * divide by 1<<pow with rounding
    503  * @param    a : input value
    504  * @param    pow : shift value
    505  * @return  divided value
    506  * @callgraph
    507  * @callergraph
    508  */
    509 static picoos_int32 picocep_fixptdivpow(picoos_int32 a, picoos_uint8 pow)
    510 {
    511     picoos_int32 big;
    512 
    513     if (a == 0) {
    514         return a;
    515     }
    516     big = 1 << (pow - 1);
    517     if (a > 0) {
    518         a = (a + big) >> pow;
    519     } else {
    520         a = -1 * ((-1 * a + big) >> pow);
    521     }
    522 
    523     return a;
    524 }
    525 
    526 /**
    527  * fixed point multiplication of x and y for large values of x or y or both
    528  * @param    x,y  : operands 1 & 2, in fixed point S:M:N representation
    529  * @param    bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits
    530  * @param    invDoubleDec : boolean indicating that x has double decimal size.
    531  *             do extra division by 1<<bigpow so that result has again single decimal size
    532  * @return  z(int) : result, in fixed point S:M:N representation
    533  * @callgraph
    534  * @callergraph
    535  */
    536 static picoos_int32 picocep_fixptmultdouble(picoos_int32 x, picoos_int32 y,
    537         picoos_uint8 bigpow, picoos_uint8 invDoubleDec)
    538 {
    539     picoos_int32 a, b, c, d, e, z;
    540     picoos_int32 big;
    541 
    542     big = 1 << bigpow;
    543 
    544     /* a = floor(x/big); */
    545     if (x >= 0) {
    546         a = x >> bigpow;
    547         b = x - (a << bigpow);
    548     } else {
    549         a = -1 * ((x * -1) >> bigpow); /* most significant 2 bytes of x */
    550         b = x - (a << bigpow);
    551     }
    552 
    553     /* least significant 2 bytes of x i.e. x modulo big */
    554     /* c = floor(y/big); */
    555     if (y >= 0) {
    556         c = y >> bigpow;
    557         d = y - (c << bigpow);
    558     } else {
    559         c = -1 * ((y * -1) >> bigpow);
    560         d = y - (c << bigpow);
    561     }
    562 
    563     if (invDoubleDec == 1) {
    564         e = a * d + b * c + picocep_fixptdivpow(b * d, bigpow);
    565         z = a * c + picocep_fixptdivpow(e, bigpow);
    566     } else {
    567         z = ((a * c) << bigpow) + (a * d + b * c) + picocep_fixptdivpow(b * d,
    568                 bigpow); /* 4 mult and 3 add instead of 1 mult. */
    569     }
    570 
    571     return z;
    572 }
    573 
    574 /**
    575  * fixed point multiplication of x and y
    576  * @param    x,y : operands 1 & 2, in fixed point S:M:N representation
    577  * @param    bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits
    578  * @param    invDoubleDec : boolean indicating that x has double decimal size.
    579  *             do extra division by 1<<bigpow so that result has again single decimal size
    580  * @return  z(int) : result, in fixed point S:M:N representation
    581  * Notes
    582  * - input and output values are 32 bit signed integers
    583  *   meant to represent a S.M.N encoding of a floating point value where
    584  *   - S : 1 sign bit
    585  *   - M : number of binary integer digits (M=32-1-N)
    586  *   - N : number of binary decimal digits (N=log2(big))
    587  *   the routine supports 2 methods
    588  * -# standard multiplication of x and y
    589  * -# long multiplication of x and y
    590  * under PICO_DEBUG the number of double and single precision multiplications is monitored for accuracy/performance tuning
    591  * Calls
    592  * - picocep_highestBit
    593  * - picocep_fixptmultdouble
    594  * @callgraph
    595  * @callergraph
    596  */
    597 static picoos_int32 picocep_fixptmult(picoos_int32 x, picoos_int32 y,
    598         picoos_uint8 bigpow, picoos_uint8 invDoubleDec)
    599 {
    600     picoos_int32 z;
    601     picoos_uint8 multsz, pow;
    602     picoos_int32 zz1, zz2;
    603 
    604     /* in C, the evaluation order of f() + g() is not defined, so
    605      * if both have a side effect on e.g. zz, the outcome of zz is not defined.
    606      * For that reason, picocep_highestBitS(x,zz) + picocep_highestBitS(y,zz)
    607      * would generate a warning "operation on zz may be undefined" which we
    608      * avoid by using two different variables zz1 and zz2 */
    609     multsz = picocep_highestBitS(x,zz1) + picocep_highestBitS(y,zz2);
    610     pow = bigpow;
    611     if (invDoubleDec == 1) {
    612         pow += bigpow;
    613     }
    614 
    615     if (multsz <= 30) { /* x*y < 1<<30 is safe including rounding in picocep_fixptdivpow, x*y < 1<<31 is safe but not with rounding */
    616         /* alternatively perform multiplication and consult overflow register */
    617         z = picocep_fixptdivpow(x * y, pow);
    618 #if defined(PICO_DEBUG)
    619         numshortmult++; /*  keep track of number of short multiplications */
    620 #endif
    621     } else {
    622 #if defined(PICO_DEBUG)
    623         if (multsz> 31 + pow) {
    624             PICODBG_WARN(("picocep_fixptmult warning: overflow in fixed point multiplication %i*%i, multsz = %i, pow = %i, decrease bigpow\n", x, y, multsz, pow));
    625         }
    626 #endif
    627         z = picocep_fixptmultdouble(x, y, bigpow, invDoubleDec); /*  perform long multiplication for large x and y */
    628 #if defined(PICO_DEBUG)
    629         numlongmult++; /*  keep track of number of long multiplications */
    630 #endif
    631     }
    632     return z;
    633 }/* picocep_fixptmult */
    634 
    635 /**
    636  * fixed point ^division of a vs b
    637  * @param    a,b : operands 1 & 2, in fixed point S:M:N representation
    638  * @param    bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits
    639  * @return  z(int) : result, in fixed point S:M:N representation
    640  * Notes
    641  * - input and output values are 32 bit signed integers
    642  *   meant to represent a S.M.N encoding of a floating point value where
    643  *   - S : 1 sign bit
    644  *   - M : number of binary integer digits (M=32-1-N)
    645  *   - N : number of binary decimal digits (N=log2(big))
    646  * - standard implementation of division by iteratively calculating
    647  * the remainder and setting corresponding bit
    648  * calculate integer part by integer division (DIV),
    649  * then add X bits of precision in decimal part
    650  * @callgraph
    651  * @callergraph
    652  */
    653 static picoos_int32 picocep_fixptdiv(picoos_int32 a, picoos_int32 b,
    654         picoos_uint8 bigpow)
    655 {
    656     picoos_int32 r, c, f, h, stop;
    657     r = (a < 0) ? -a : a; /* take absolute value; b is already guaranteed to be positive in smoothing operation */
    658     if (r == 0) {
    659         return 0;
    660     }
    661     c = 0;
    662     stop = 0;
    663 
    664     /* can speed up slightly by setting stop = 2 => slightly less precision */
    665     h = r / b; /* in first loop h can be multiple bits, after first loop h can only be 0 or 1 */
    666     /* faster implementation on target by using comparison instead of DIV? */
    667     /* For our LDL even in first loop h <= 1, but not in backward step */
    668     c = c + (h << bigpow); /* after first loop simply set bit */
    669     r = r - h * b; /* corresponds to modulo operation */
    670     bigpow--;
    671     r <<= 1;
    672 
    673     while ((bigpow > stop) && (r != 0)) { /* calculate bigpow bits after fixed point */
    674         /* can speed up slightly by setting stop = 2 => slightly less precision */
    675         if (r >= b) {
    676             c += (1 << bigpow); /* after first loop simply set bit */
    677             r -= b; /* corresponds to modulo operation */
    678         }
    679         bigpow--;
    680         r <<= 1;
    681     }
    682 
    683     if (r != 0) {
    684         f = r + (b >> 1);
    685         if (f >= b) {
    686             if (f >= b + b) {
    687                 c += 2;
    688             } else {
    689                 c++;
    690             }
    691         }
    692     }
    693     /* final step: do rounding (experimentally improves accuracy for our problem) */
    694     c = (a >= 0) ? c : -c; /* b is guaranteed to be positive because corresponds to diag0 */
    695     return c;
    696 }/* picocep_fixptdiv */
    697 
    698 /**
    699  * perform inversion of diagonal element of WUW matrix
    700  * @param    d : diagonal element to be inverted
    701  * @param    rowscpow (int) : fixed point base for each dimension of the vectors stored in the database
    702  * @param    bigpow (int) : fixed point base used during cepstral smoothing
    703  * @param    invpow : fixed point base of inverted pivot elements
    704  * @return   inverted pivot element
    705  * @note
    706  * - d is guaranteed positive
    707  * @callgraph
    708  * @callergraph
    709  */
    710 static picoos_int32 picocep_fixptInvDiagEle(picoos_uint32 d,
    711         picoos_uint8* rowscpow, picoos_uint8 bigpow, picoos_uint8 invpow)
    712 {
    713     picoos_uint32 r, b, c, h, f, stop;
    714     picoos_uint8 dlen;
    715     /* picoos_int32 zz; */
    716     c = 0;
    717     stop = 0;
    718 
    719     dlen = picocep_highestBitU(d);
    720     if (invpow + bigpow > 30 + dlen) { /* c must be < 2^32, hence d which is >= 2^(dlen-1) must be > 2^(invpow+bigpow-32), or invpow+bigpow must be <= dlen+30*/
    721         *rowscpow = invpow + bigpow - 30 - dlen;PICODBG_DEBUG(("input to picocep_fixptInvDiagEle is %i <= 1<<%i = 1<<invpow+bigpow-32. Choose lower invpow. For now scaling row by 1<<%i\n", d, invpow+bigpow-32, *rowscpow));
    722     } else {
    723         *rowscpow = 0;
    724     }
    725     r = 1 << invpow;
    726     b = d << (*rowscpow);
    727 
    728     /* first */
    729     h = r / b;
    730     if (h > 0) {
    731         c += (h << bigpow);
    732         r -= h * b;
    733     }
    734     bigpow--;
    735     r <<= 1;
    736 
    737     /* loop */
    738     while ((bigpow > stop) && (r != 0)) {
    739         if (r >= b) {
    740             c += (1 << bigpow);
    741             r -= b;
    742         }
    743         bigpow--;
    744         r <<= 1;
    745     }
    746 
    747     if (r != 0) {
    748         f = r + (b >> 1);
    749         if (f >= b) {
    750             if (f >= b + b) {
    751                 c += 2;
    752             } else {
    753                 c++;
    754             }
    755         }
    756     }
    757 
    758     return c;
    759 }/* picocep_fixptInvDiagEle */
    760 
    761 /**
    762  * perform division of two operands a and b by multiplication by inverse of b
    763  * @param    a (int32) : operand 1 in fixed point S:M:N representation
    764  * @param    invb(uint32)   : inverse of operand b, in fixed point P:Q representation (sign is positive)
    765  * @param    bigpow(uint8)  : N = bigpow when invDoubleDec==0, else N = 2*bigpow
    766  * @param    invpow(uint8)  : Q = invpow = number of binary decimal digits for invb
    767  * @param      invDoubleDec   : boolean to indicate that a and the return value c have 2*N binary decimal digits instead of N
    768  * @return  c(int32)       : result in fixed point S:v:w where w = 2*N when invDoubleDec == 1
    769  * @note Calls
    770  * - picocep_fixptmult
    771  * @callgraph
    772  * @callergraph
    773  */
    774 static picoos_int32 picocep_fixptinv(picoos_int32 a, picoos_uint32 invb,
    775         picoos_uint8 bigpow, picoos_uint8 invpow, picoos_uint8 invDoubleDec)
    776 {
    777     picoos_int32 c;
    778     picoos_int8 normpow;
    779 
    780     c = picocep_fixptmult(a, invb, bigpow, invDoubleDec);
    781 
    782     /* if invDoubleDec==0, picocep_fixptmult assumes a and invb are in base 1<<bigpow and returns c = (a*b)/1<<bigpow
    783      Since invb is in base 1<<invpow instead of 1<<bigpow, normalize c by 1<<(bigpow-invpow)
    784      if invDoubleDec==1:
    785      multiply additionally by 1<<bigpow*2 (for invb and c) so that base of c is again 2*bigpow
    786      this can be seen by setting a=A*big, b=B*big, invb=big2/B, mult(a,invb) = a*invb/(big*big) = A/B*big*big2/(big*big) = A/B*big2/big
    787      and we want c = A/B*big*big => normfactor = big^3/big2
    788      */
    789     if (invDoubleDec == 1) {
    790         normpow = 3 * bigpow;
    791     } else {
    792         normpow = bigpow;
    793     }
    794     if (normpow < invpow) {
    795         /* divide with rounding */
    796         c = picocep_fixptdivpow(c, invpow - normpow);
    797     } else {
    798         c = picocep_fixptmultpow(c, normpow - invpow);
    799     }
    800     return c;
    801 }
    802 
    803 /**
    804  * initializes the coefficients to calculate delta and delta-delta values and the squares of the coefficients
    805  * @param    cep : the CEP PU sub-object handle
    806  * @callgraph
    807  * @callergraph
    808  */
    809 static void initSmoothing(cep_subobj_t * cep)
    810 {
    811     cep->xi[0] = 1;
    812     cep->xi[1] = -1;
    813     cep->xi[2] = 2;
    814     cep->xi[3] = -4;
    815     cep->xi[4] = 2;
    816     cep->xsqi[0] = 1;
    817     cep->xsqi[1] = 1;
    818     cep->xsqi[2] = 4;
    819     cep->xsqi[3] = 16;
    820     cep->xsqi[4] = 4;
    821 
    822     cep->x1[0] = -1;
    823     cep->x1[1] = 2;
    824     cep->xsq1[0] = 1;
    825     cep->xsq1[1] = 4;
    826 
    827     cep->x2[0] = -1;
    828     cep->x2[1] = -4;
    829     cep->x2[2] = 2;
    830     cep->xsq2[0] = 1;
    831     cep->xsq2[1] = 16;
    832     cep->xsq2[2] = 4;
    833 
    834     cep->xm[0] = 1;
    835     cep->xm[1] = 2;
    836     cep->xm[2] = -4;
    837     cep->xsqm[0] = 1;
    838     cep->xsqm[1] = 4;
    839     cep->xsqm[2] = 16;
    840 
    841     cep->xn[0] = 1;
    842     cep->xn[1] = 2;
    843     cep->xsqn[0] = 1;
    844     cep->xsqn[1] = 4;
    845 }
    846 
    847 /**
    848  * matrix inversion
    849  * @param    cep : PU sub object pointer
    850  * @param    N
    851  * @param    smoothcep : pointer to picoos_int16, sequence of smoothed cepstral vectors
    852  * @param    cepnum :  cepstral dimension to be treated
    853  * @param    pdf :  pdf resource
    854  * @param    invpow :  fixed point base for inverse
    855  * @param    invDoubleDec : boolean indicating that result of picocep_fixptinv has fixed point base 2*bigpow
    856  *             picocep_fixptmult absorbs double decimal size by dividing its result by extra factor big
    857  * @return  void
    858  * @remarks diag0, diag1, diag2, WUm, invdiag0  globals needed in this function (object members in pico)
    859  * @callgraph
    860  * @callergraph
    861  */
    862 static void invMatrix(cep_subobj_t * cep, picoos_uint16 N,
    863         picoos_int16 *smoothcep, picoos_uint8 cepnum,
    864         picokpdf_PdfMUL pdf, picoos_uint8 invpow, picoos_uint8 invDoubleDec)
    865 {
    866     picoos_int32 j, v1, v2, h;
    867     picoos_uint32 k;
    868     picoos_uint8 rowscpow, prevrowscpow;
    869     picoos_uint8 ceporder = pdf->ceporder;
    870     picoos_uint8 bigpow = pdf->bigpow;
    871     picoos_uint8 meanpow = pdf->meanpow;
    872 
    873     /* LDL factorization */
    874     prevrowscpow = 0;
    875     cep->invdiag0[0] = picocep_fixptInvDiagEle(cep->diag0[0], &rowscpow,
    876             bigpow, invpow); /* inverse has fixed point basis 1<<invpow */
    877     cep->diag1[0] = picocep_fixptinv((cep->diag1[0]) << rowscpow,
    878             cep->invdiag0[0], bigpow, invpow, invDoubleDec); /* perform division via inverse */
    879     cep->diag2[0] = picocep_fixptinv((cep->diag2[0]) << rowscpow,
    880             cep->invdiag0[0], bigpow, invpow, invDoubleDec);
    881     cep->WUm[0] = (cep->WUm[0]) << rowscpow; /* if diag0 too low, multiply LHS and RHS of row in matrix equation by 1<<rowscpow */
    882     for (j = 1; j < N; j++) {
    883         /* do forward substitution */
    884         cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag1[j - 1],
    885                 cep->WUm[j - 1], bigpow, invDoubleDec);
    886         if (j > 1) {
    887             cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag2[j - 2],
    888                     cep->WUm[j - 2], bigpow, invDoubleDec);
    889         }
    890 
    891         /* update row j */
    892         v1 = picocep_fixptmult((cep->diag1[j - 1]) / (1 << rowscpow),
    893                 cep->diag0[j - 1], bigpow, invDoubleDec); /* undo scaling by 1<<rowscpow because diag1(j-1) refers to symm ele in column j-1 not in row j-1 */
    894         cep->diag0[j] = cep->diag0[j] - picocep_fixptmult(cep->diag1[j - 1],
    895                 v1, bigpow, invDoubleDec);
    896         if (j > 1) {
    897             v2 = picocep_fixptmult((cep->diag2[j - 2]) / (1 << prevrowscpow),
    898                     cep->diag0[j - 2], bigpow, invDoubleDec); /* undo scaling by 1<<prevrowscpow because diag1(j-2) refers to symm ele in column j-2 not in row j-2 */
    899             cep->diag0[j] = cep->diag0[j] - picocep_fixptmult(
    900                     cep->diag2[j - 2], v2, bigpow, invDoubleDec);
    901         }
    902         prevrowscpow = rowscpow;
    903         cep->invdiag0[j] = picocep_fixptInvDiagEle(cep->diag0[j], &rowscpow,
    904                 bigpow, invpow); /* inverse has fixed point basis 1<<invpow */
    905         cep->WUm[j] = (cep->WUm[j]) << rowscpow;
    906         if (j < N - 1) {
    907             h = picocep_fixptmult(cep->diag2[j - 1], v1, bigpow, invDoubleDec);
    908             cep->diag1[j] = picocep_fixptinv((cep->diag1[j] - h) << rowscpow,
    909                     cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */
    910         }
    911         if (j < N - 2) {
    912             cep->diag2[j] = picocep_fixptinv((cep->diag2[j]) << rowscpow,
    913                     cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */
    914         }
    915     }
    916 
    917     /* divide all entries of WUm by diag0 */
    918     for (j = 0; j < N; j++) {
    919         cep->WUm[j] = picocep_fixptinv(cep->WUm[j], cep->invdiag0[j], bigpow,
    920                 invpow, invDoubleDec);
    921         if (invDoubleDec == 1) {
    922             cep->WUm[j] = picocep_fixptdivpow(cep->WUm[j], bigpow);
    923         }
    924     }
    925 
    926     /* backward substitution */
    927     for (j = N - 2; j >= 0; j--) {
    928         cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag1[j], cep->WUm[j
    929                 + 1], bigpow, invDoubleDec);
    930         if (j < N - 2) {
    931             cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag2[j],
    932                     cep->WUm[j + 2], bigpow, invDoubleDec);
    933         }
    934     }
    935     /* copy N frames into smoothcep (only for coeff # "cepnum")  */
    936     /* coefficients normalized to occupy short; for correct waveform energy, divide by (1<<(bigpow-meanpow)) then convert e.g. to picoos_single */
    937     k = cepnum;
    938     for (j = 0; j < N; j++) {
    939         smoothcep[k] = (picoos_int16)(cep->WUm[j]/(1<<meanpow));
    940         k += ceporder;
    941     }
    942 
    943 }/* invMatrix*/
    944 
    945 /**
    946  * Calculate matrix products needed to implement the solution
    947  * @param    cep : PU sub object pointer
    948  * @param    pdf :  pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3
    949  * @param    indices : indices of pdf vectors for all frames in current sentence
    950  * @param    b, N :  to be smoothed frames indices (range will be from b to b+N-1)
    951  * @param    cepnum :  cepstral dimension to be treated
    952  * @return  void
    953  * @remarks diag0, diag1, diag2, WUm, invdiag0  globals needed in this function (object members in pico)
    954  * @remarks WUW --> At x W x A
    955  * @remarks WUm --> At x W x b
    956  * @callgraph
    957  * @callergraph
    958  */
    959 static picoos_uint8 makeWUWandWUm(cep_subobj_t * cep, picokpdf_PdfMUL pdf,
    960         picoos_uint16 *indices, picoos_uint16 b, picoos_uint16 N,
    961         picoos_uint8 cepnum)
    962 {
    963     picoos_uint16 Id[2], Idd[3];
    964     /*picoos_uint32      vecstart, k;*/
    965     picoos_uint32 vecstart;
    966     picoos_int32 *x = NULL, *xsq = NULL;
    967     picoos_int32 mean, ivar;
    968     picoos_uint16 i, j, numd = 0, numdd = 0;
    969     picoos_uint8 vecsize = pdf->vecsize;
    970     picoos_int32 prev_WUm, prev_diag0, prev_diag1, prev_diag1_1, prev_diag2;
    971 
    972     prev_WUm = prev_diag0 = prev_diag1 = prev_diag1_1 = prev_diag2 = 0;
    973     for (i = 0; i < N; i++) {
    974 
    975         if ((1 < i) && (i < N - 2)) {
    976             x = cep->xi;
    977             xsq = cep->xsqi;
    978             numd = 2;
    979             numdd = 3;
    980             Id[0] = Idd[0] = i - 1;
    981             Id[1] = Idd[2] = i + 1;
    982             Idd[1] = i;
    983         } else if (i == 0) {
    984             x = cep->x1;
    985             xsq = cep->xsq1;
    986             numd = numdd = 1;
    987             Id[0] = Idd[0] = 1;
    988         } else if (i == 1) {
    989             x = cep->x2;
    990             xsq = cep->xsq2;
    991             numd = 1;
    992             numdd = 2;
    993             Id[0] = Idd[1] = 2;
    994             Idd[0] = 1;
    995         } else if (i == N - 2) {
    996             x = cep->xm;
    997             xsq = cep->xsqm;
    998             numd = 1;
    999             numdd = 2;
   1000             Id[0] = Idd[0] = N - 3;
   1001             Idd[1] = N - 2;
   1002         } else if (i == N - 1) {
   1003             x = cep->xn;
   1004             xsq = cep->xsqn;
   1005             numd = numdd = 1;
   1006             Id[0] = Idd[0] = N - 2;
   1007         }
   1008 
   1009         /* process static means and static inverse variances */
   1010         if (i > 0 && indices[b + i] == indices[b + i - 1]) {
   1011             cep->diag0[i] = prev_diag0;
   1012             cep->WUm[i] = prev_WUm;
   1013         } else {
   1014             vecstart = indices[b + i] * vecsize;
   1015             ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1016                     PICOCEP_WANTSTATIC);
   1017             prev_diag0 = cep->diag0[i] = ivar << 2; /* multiply ivar by 4 (4 used to be first entry of xsq) */
   1018             mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN,
   1019                     PICOCEP_WANTSTATIC);
   1020             prev_WUm = cep->WUm[i] = mean << 1; /* multiply mean by 2 (2 used to be first entry of x) */
   1021         }
   1022 
   1023         /* process delta means and delta inverse variances */
   1024         for (j = 0; j < numd; j++) {
   1025             vecstart = indices[b + Id[j]] * vecsize;
   1026             ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1027                     PICOCEP_WANTDELTA);
   1028             cep->diag0[i] += xsq[j] * ivar;
   1029 
   1030             mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN,
   1031                     PICOCEP_WANTDELTA);
   1032             if (mean != 0) {
   1033                 cep->WUm[i] += x[j] * mean;
   1034             }
   1035         }
   1036 
   1037         /* process delta delta means and delta delta inverse variances */
   1038         for (j = 0; j < numdd; j++) {
   1039             vecstart = indices[b + Idd[j]] * vecsize;
   1040             ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1041                     PICOCEP_WANTDELTA2);
   1042             cep->diag0[i] += xsq[numd + j] * ivar;
   1043 
   1044             mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN,
   1045                     PICOCEP_WANTDELTA2);
   1046             if (mean != 0) {
   1047                 cep->WUm[i] += x[numd + j] * mean;
   1048             }
   1049         }
   1050 
   1051         cep->diag0[i] = (cep->diag0[i] + 2) / 4; /* long DIV with rounding */
   1052         cep->WUm[i] = (cep->WUm[i] + 1) / 2; /* long DIV with rounding */
   1053 
   1054         /* calculate diag(A,-1) */
   1055         if (i < N - 1) {
   1056             if (i < N - 2) {
   1057                 if (i > 0 && indices[b + i + 1] == indices[b + i]) {
   1058                     cep->diag1[i] = prev_diag1;
   1059                 } else {
   1060                     vecstart = indices[b + i + 1] * vecsize;
   1061                     /*
   1062                      diag1[i] = getFromPdf(pdf, vecstart, numvuv, ceporder, numdeltas, cepnum,
   1063                      bigpow, meanpowUm, ivarpow, PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2);
   1064                      */
   1065                     prev_diag1 = cep->diag1[i] = getFromPdf(pdf, vecstart,
   1066                             cepnum, PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2);
   1067                 }
   1068                 /*
   1069                  k = vecstart +pdf->numvuv+pdf->ceporder*2 +    pdf->numdeltas*3 +
   1070                  pdf->ceporder*2 +cepnum;
   1071                  cep->diag1[i] = (picoos_int32)(pdf->content[k]) << pdf->bigpow;
   1072                  */
   1073             } else {
   1074                 cep->diag1[i] = 0;
   1075             }
   1076             if (i > 0) {
   1077                 if (i > 1 && indices[b + i] == indices[b + i - 1]) {
   1078                     cep->diag1[i] += prev_diag1_1;
   1079                 } else {
   1080                     vecstart = indices[b + i] * vecsize;
   1081                     /*
   1082                      k = vecstart + pdf->numvuv + pdf->ceporder * 2 + pdf->numdeltas * 3 + pdf->ceporder * 2 + cepnum;
   1083                      cep->diag1[i] += (picoos_int32)(pdf->content[k]) << pdf->bigpow; */
   1084                     /* cepnum'th delta delta ivar */
   1085 
   1086                     prev_diag1_1 = getFromPdf(pdf, vecstart, cepnum,
   1087                             PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2);
   1088                     cep->diag1[i] += prev_diag1_1;
   1089                 }
   1090 
   1091             } /*i < N-1 */
   1092             cep->diag1[i] *= -2;
   1093         }
   1094     }
   1095 
   1096     /* calculate diag(A,-2) */
   1097     for (i = 0; i < N - 2; i++) {
   1098         if (i > 0 && indices[b + i + 1] == indices[b + i]) {
   1099             cep->diag2[i] = prev_diag2;
   1100         } else {
   1101             vecstart = indices[b + i + 1] * vecsize;
   1102             /*
   1103              k = vecstart + pdf->numvuv + pdf->ceporder * 2 + pdf->numdeltas * 3 + pdf->ceporder * 2 + cepnum;
   1104              cep->diag2[i] = (picoos_int32)(pdf->content[k]) << pdf->bigpow;
   1105              k -= pdf->ceporder;
   1106              ivar = (picoos_int32)(pdf->content[k]) << pdf->bigpow;
   1107              */
   1108             cep->diag2[i] = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1109                     PICOCEP_WANTDELTA2);
   1110             ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1111                     PICOCEP_WANTDELTA);
   1112             cep->diag2[i] -= (ivar + 2) / 4;
   1113             prev_diag2 = cep->diag2[i];
   1114         }
   1115     }
   1116 
   1117     return 0;
   1118 }/* makeWUWandWUm */
   1119 
   1120 /**
   1121  * Retrieve actual values for MGC from PDF resource
   1122  * @param    pdf :  pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3
   1123  * @param    vecstart : indices of pdf vectors for all frames in current sentence
   1124  * @param    cepnum :  cepstral dimension to be treated
   1125  * @param    wantMeanOrIvar :  flag to select mean or variance values
   1126  * @param    wantStaticOrDeltax :  flag to select static or delta values
   1127  * @return  the actual value retrieved
   1128  * @callgraph
   1129  * @callergraph
   1130  */
   1131 static picoos_int32 getFromPdf(picokpdf_PdfMUL pdf, picoos_uint32 vecstart,
   1132         picoos_uint8 cepnum, picocep_WantMeanOrIvar_t wantMeanOrIvar,
   1133         picocep_WantStaticOrDelta_t wantStaticOrDeltax)
   1134 {
   1135     picoos_uint8 s, ind;
   1136     picoos_uint8 *p;
   1137     picoos_uint8 ceporder, ceporder2, cc;
   1138     picoos_uint32 k;
   1139     picoos_int32 mean = 0, ivar = 0;
   1140 
   1141     if (pdf->numdeltas == 0xFF) {
   1142         switch (wantMeanOrIvar) {
   1143             case PICOCEP_WANTMEAN:
   1144                 switch (wantStaticOrDeltax) {
   1145                     case PICOCEP_WANTSTATIC:
   1146                         p = pdf->content
   1147                                 + (vecstart + pdf->numvuv + cepnum * 2); /* cepnum'th static mean */
   1148                         mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8))
   1149                                 | *p) << (pdf->meanpowUm[cepnum]);
   1150                         break;
   1151                     case PICOCEP_WANTDELTA:
   1152                 cc = pdf->ceporder + cepnum;
   1153                 p = pdf->content + (vecstart + pdf->numvuv + cc * 2); /* cepnum'th delta mean */
   1154                         mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8))
   1155                                 | *p) << (pdf->meanpowUm[cc]);
   1156                         break;
   1157                     case PICOCEP_WANTDELTA2:
   1158                 cc = pdf->ceporder * 2 + cepnum;
   1159                 p = pdf->content + (vecstart + pdf->numvuv + cc * 2); /* cepnum'th delta delta mean */
   1160                         mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8))
   1161                                 | *p) << (pdf->meanpowUm[cc]);
   1162                         break;
   1163                     default:
   1164                         /* should never come here */
   1165                 PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax));
   1166             }
   1167                 return mean;
   1168                 break;
   1169             case PICOCEP_WANTIVAR:
   1170                 switch (wantStaticOrDeltax) {
   1171                     case PICOCEP_WANTSTATIC:
   1172                 k = vecstart + pdf->numvuv + pdf->ceporder * 6 + cepnum; /* cepnum'th static ivar */
   1173                 ivar = (picoos_int32) (pdf->content[k])
   1174                         << (pdf->ivarpow[cepnum]);
   1175                         break;
   1176                     case PICOCEP_WANTDELTA:
   1177                 ceporder = pdf->ceporder;
   1178                 k = vecstart + pdf->numvuv + ceporder * 7 + cepnum; /* cepnum'th delta ivar */
   1179                 ivar = (picoos_int32) (pdf->content[k])
   1180                         << (pdf->ivarpow[ceporder + cepnum]);
   1181                         break;
   1182                     case PICOCEP_WANTDELTA2:
   1183                 ceporder = pdf->ceporder;
   1184                 k = vecstart + pdf->numvuv + ceporder * 8 + cepnum; /* cepnum'th delta delta ivar */
   1185                         ivar = (picoos_int32) (pdf->content[k])
   1186                                 << (pdf->ivarpow[2 * ceporder + cepnum]);
   1187                         break;
   1188                     default:
   1189                         /* should never get here */
   1190                 PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax));
   1191             }
   1192                 return ivar;
   1193                 break;
   1194             default:
   1195                 /* should never come here */
   1196             PICODBG_ERROR(("unknown type wantMeanOrIvar = %n", wantMeanOrIvar));
   1197                 return 0;
   1198         }
   1199     } else {
   1200         switch (wantMeanOrIvar) {
   1201             case PICOCEP_WANTMEAN:
   1202                 switch (wantStaticOrDeltax) {
   1203                     case PICOCEP_WANTSTATIC:
   1204                         p = pdf->content
   1205                                 + (vecstart + pdf->numvuv + cepnum * 2); /* cepnum'th static mean */
   1206                         mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8))
   1207                                 | *p) << (pdf->meanpowUm[cepnum]);
   1208                 return mean;
   1209                         break;
   1210                     case PICOCEP_WANTDELTA:
   1211                 ceporder = pdf->ceporder;
   1212                 s = 0;
   1213                 ind = 0;
   1214                         while ((s < pdf->numdeltas) && (ind < cepnum || (ind
   1215                                 == 0 && cepnum == 0))) { /* rawmean deltas are sparse so investigate indices in column */
   1216                     k = vecstart + pdf->numvuv + ceporder * 2 + s; /* s'th delta index */
   1217                     ind = (picoos_uint8) (pdf->content[k]); /* is already picoos_uint8 but just to make explicit */
   1218                     if (ind == cepnum) {
   1219                         k = vecstart + pdf->numvuv + ceporder * 2
   1220                                 + pdf->numdeltas + s * 2; /* s'th sparse delta mean, corresponds to cepnum'th delta mean */
   1221                                 mean
   1222                                         = ((picoos_int32) ((picoos_int16) ((pdf->content[k
   1223                                 + 1]) << 8)) | pdf->content[k])
   1224                                                 << (pdf->meanpowUm[ceporder
   1225                                                         + cepnum]);
   1226                         return mean;
   1227                     }
   1228                     s++;
   1229                 }
   1230                 return 0;
   1231                         break;
   1232                     case PICOCEP_WANTDELTA2:
   1233                 ceporder = pdf->ceporder;
   1234                 ceporder2 = ceporder * 2;
   1235                 s = pdf->numdeltas;
   1236                 ind = 2 * ceporder;
   1237                 while ((s-- > 0) && (ind > ceporder + cepnum)) { /* rawmean deltas are sparse so investigate indices in column */
   1238                     k = vecstart + pdf->numvuv + ceporder2 + s; /* s'th delta index */
   1239                     ind = (picoos_uint8) (pdf->content[k]); /* is already picoos_uint8 but just to make explicit */
   1240                     if (ind == ceporder + cepnum) {
   1241                                 k = vecstart + pdf->numvuv + ceporder2
   1242                                         + pdf->numdeltas + s * 2; /* s'th sparse delta mean, corresponds to cepnum'th delta delta mean */
   1243                                 mean
   1244                                         = ((picoos_int32) ((picoos_int16) ((pdf->content[k
   1245                                 + 1]) << 8)) | pdf->content[k])
   1246                                                 << (pdf->meanpowUm[ceporder2
   1247                                                         + cepnum]);
   1248                         return mean;
   1249                     }
   1250                 }
   1251                 return 0;
   1252                         break;
   1253                     default:
   1254                 PICODBG_ERROR(("getFromPdf: unknown type wantStaticOrDeltax = %i\n", wantStaticOrDeltax));
   1255                         return 0;
   1256             }
   1257                 break;
   1258             case PICOCEP_WANTIVAR:
   1259                 switch (wantStaticOrDeltax) {
   1260                     case PICOCEP_WANTSTATIC:
   1261                         k = vecstart + pdf->numvuv + pdf->ceporder * 2
   1262                                 + pdf->numdeltas * 3 + cepnum; /* cepnum'th static ivar */
   1263                 ivar = (picoos_int32) (pdf->content[k])
   1264                         << (pdf->ivarpow[cepnum]);
   1265                         break;
   1266                     case PICOCEP_WANTDELTA:
   1267                 ceporder = pdf->ceporder;
   1268                         k = vecstart + pdf->numvuv + ceporder * 3
   1269                                 + pdf->numdeltas * 3 + cepnum; /* cepnum'th delta ivar */
   1270                 ivar = (picoos_int32) (pdf->content[k])
   1271                         << (pdf->ivarpow[ceporder + cepnum]);
   1272                         break;
   1273                     case PICOCEP_WANTDELTA2:
   1274                 ceporder2 = 2 * pdf->ceporder;
   1275                         k = vecstart + pdf->numvuv + ceporder2 + pdf->numdeltas
   1276                                 * 3 + ceporder2 + cepnum; /* cepnum'th delta delta ivar */
   1277                 ivar = (picoos_int32) (pdf->content[k])
   1278                         << (pdf->ivarpow[ceporder2 + cepnum]);
   1279                         break;
   1280                     default:
   1281                 PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax));
   1282             }
   1283                 return ivar;
   1284                 break;
   1285             default:
   1286             PICODBG_ERROR(("unknown type wantMeanOrIvar = %i", wantMeanOrIvar));
   1287                 return 0;
   1288         }
   1289     }
   1290     return 0;
   1291 }
   1292 
   1293 /**
   1294  * Retrieve actual values for MGC from PDF resource - Variant "Direct"
   1295  * @param    pdf :  pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3
   1296  * @param    indices : indices of pdf vectors for all frames in current sentence
   1297  * @param    activeEndPos :  ??
   1298  * @param    cepnum :  cepstral dimension to be treated
   1299  * @param    smoothcep :  ??
   1300  * @return  the actual value retrieved
   1301  * @callgraph
   1302  * @callergraph
   1303  */
   1304 static void getDirect(picokpdf_PdfMUL pdf, picoos_uint16 *indices,
   1305         picoos_uint16 activeEndPos,
   1306         picoos_uint8 cepnum, picoos_int16 *smoothcep)
   1307 {
   1308     picoos_uint16 i;
   1309     picoos_uint32 j;
   1310     picoos_uint32 vecstart;
   1311     picoos_int32 mean, ivar;
   1312     picoos_int32 prev_mean;
   1313     picoos_uint8 vecsize = pdf->vecsize;
   1314     picoos_uint8 order = pdf->ceporder;
   1315 
   1316     j = cepnum;
   1317     prev_mean = 0;
   1318     for (i = 0; i < activeEndPos; i++) {
   1319         if (i > 0 && indices[i] == indices[i - 1]) {
   1320             mean = prev_mean;
   1321         } else {
   1322             vecstart = indices[i] * vecsize;
   1323             mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN,
   1324                     PICOCEP_WANTSTATIC);
   1325             ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR,
   1326                     PICOCEP_WANTSTATIC);
   1327             prev_mean = mean = picocep_fixptdiv(mean, ivar, pdf->bigpow);
   1328         }
   1329         smoothcep[j] = (picoos_int16)(mean/(1<<pdf->meanpow));
   1330         j += order;
   1331     }
   1332 }
   1333 
   1334 /**
   1335  * Retrieve actual values for voicing from PDF resource
   1336  * @param    pdf :  pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3
   1337  * @param    indices : indices of pdf vectors for all frames in current sentence
   1338  * @param    activeEndPos : end position of indices to be considered
   1339  * @return    smoothcep : the values retrieved
   1340  * @callgraph
   1341  * @callergraph
   1342  */
   1343 static void getVoiced(picokpdf_PdfMUL pdf, picoos_uint16 *indices,
   1344         picoos_uint16 activeEndPos,
   1345         picoos_uint8 *smoothcep)
   1346 {
   1347     picoos_uint16 i, j;
   1348     picoos_uint32 vecstart;
   1349     picoos_uint8 vecsize = pdf->vecsize;
   1350 
   1351     if (pdf->numvuv == 0) {
   1352         /* do nothing */
   1353     } else {
   1354         for (i = 0, j = 0; i < activeEndPos; i++, j++) {
   1355             vecstart = indices[i] * vecsize;
   1356             smoothcep[j] = pdf->content[vecstart]; /* odd value is voiced, even if unvoiced */
   1357         }
   1358     }
   1359 }
   1360 
   1361 /** reads platform-independent uint16 from buffer at *pos and advances *pos
   1362  * @param    buf : buffer picoos_uint8
   1363  * @param    *pos : start position inside buffer of pi uint16
   1364  * @return   the uint16
   1365  * @callgraph
   1366  * @callergraph
   1367  */
   1368 static picoos_uint16 get_pi_uint16(picoos_uint8 * buf, picoos_uint16 *pos)
   1369 {
   1370     picoos_uint16 res;
   1371     res = buf[(*pos)] | ((picoos_uint16) buf[(*pos) + 1] << 8);
   1372     *pos += 2;
   1373     return res;
   1374 }
   1375 /**
   1376  * Looks up indices of one phone item and fills index buffers. Consumes Item
   1377  * @param    cep :  the CEP PU sub object pointer
   1378  * @param    ihead : pointer to the start of the phone item
   1379  * @callgraph
   1380  * @callergraph
   1381  */
   1382 static void treat_phone(cep_subobj_t * cep, picodata_itemhead_t * ihead)
   1383 {
   1384     picoos_uint16 state, frame, frames;
   1385     picoos_uint16 indlfz, indmgc;
   1386     picoos_uint16 pos;
   1387     picoos_uint8  bufferFull;
   1388 
   1389     /* treat all states
   1390      *    for each state, repeat putting the index into the index buffer framesperstate times.
   1391      */
   1392     /* set state and frame to the first state and frame in the phone to be considered */
   1393     state = 0; /* the first state to be considered */
   1394     frame = 0; /* the first frame to be considered */
   1395     /* numFramesPerState: 2 byte, lf0Index: 2 byte, mgcIndex: 2 byte -> 6 bytes per state */
   1396     PICODBG_DEBUG(("skipping to phone state %i ",state));
   1397     pos = cep->inReadPos + PICODATA_ITEM_HEADSIZE + state * 6;
   1398     /*  */
   1399     PICODBG_DEBUG(("state info starts at inBuf pos %i ",pos));
   1400     /* get the current frames per state */
   1401     frames = get_pi_uint16(cep->inBuf, &pos);
   1402     /*  */
   1403     PICODBG_DEBUG(("number of frames for this phone state: %i",frames));
   1404     /*  */
   1405     PICODBG_DEBUG(("PARSE starting with frame %i",frame));
   1406 
   1407     bufferFull = cep->indexWritePos >= PICOCEP_MAXWINLEN;
   1408     while ((state < ihead->info2) && (bufferFull == FALSE)) {
   1409 
   1410         /* get the current state's lf0 and mgc indices and adjust according to state */
   1411         /*   the indices have to be calculated as follows:
   1412          *   new index = (index-1) + stateoffset(state) */
   1413 
   1414         indlfz = get_pi_uint16(cep->inBuf, &pos); /* lfz index */
   1415         indlfz += -1 + cep->pdflfz->stateoffset[state]; /* transform index */
   1416         indmgc = get_pi_uint16(cep->inBuf, &pos); /* mgc index */
   1417         indmgc += -1 + cep->pdfmgc->stateoffset[state]; /* transform index */
   1418 
   1419         /* are we reaching the end of the index buffers? */
   1420         if ((cep->indexWritePos - frame) + frames > PICOCEP_MAXWINLEN) {
   1421             /* number of frames that will still fit */
   1422             frames = PICOCEP_MAXWINLEN - (cep->indexWritePos - frame);
   1423             bufferFull = TRUE;
   1424             PICODBG_DEBUG(("smoothing buffer full at state=%i frame=%i",state, frame));
   1425         }
   1426         while (frame < frames) {
   1427             cep->indicesMGC[cep->indexWritePos] = indmgc;
   1428             cep->indicesLFZ[cep->indexWritePos] = indlfz;
   1429             cep->phoneId[cep->indexWritePos] = ihead->info1;
   1430             cep->indexWritePos++;
   1431             frame++;
   1432         }
   1433         /* proceed to next state */
   1434         PICODBG_DEBUG(("finished state %i with %i frames, now at index write pos %i",
   1435                         state, frames,cep->indexWritePos));
   1436         state++;
   1437         if (state < ihead->info2) {
   1438             frame = 0;
   1439             frames = get_pi_uint16(cep->inBuf, &pos);
   1440         }
   1441     }
   1442     /* consume the phone item */
   1443     cep->inReadPos = cep->nextInPos;
   1444     /* */
   1445     PICODBG_DEBUG(("finished phone, advancing inReadPos to %i",cep->inReadPos));
   1446 }
   1447 
   1448 /**
   1449  * Returns true if an Item has to be forwarded to next PU
   1450  * @param   ihead : pointer to item head structure
   1451  * @return  TRUE : the item should be forwarded
   1452  * @return  FALSE : the item should be consumed
   1453  * @callgraph
   1454  * @callergraph
   1455  */
   1456 static picoos_uint8 forwardingItem(picodata_itemhead_t * ihead)
   1457 {
   1458     if ((PICODATA_ITEM_CMD == ihead->type) && (PICODATA_ITEMINFO1_CMD_IGNSIG
   1459             == ihead->info1)) {
   1460         return FALSE;
   1461     } else {
   1462         return TRUE;
   1463     }
   1464 }
   1465 
   1466 /**
   1467  * performs a step of the cep processing
   1468  * @param    this : pointer to current PU (Control Unit)
   1469  * @param    mode : mode for the PU (not used)
   1470  * @param    numBytesOutput : pointer to output number fo bytes produced
   1471  * @return  one of the "picodata_step_result_t" values
   1472  * @callgraph
   1473  * @callergraph
   1474  */
   1475 static picodata_step_result_t cepStep(register picodata_ProcessingUnit this,
   1476         picoos_int16 mode, picoos_uint16 * numBytesOutput)
   1477 {
   1478     register cep_subobj_t * cep;
   1479     picodata_itemhead_t ihead /* , ohead */;
   1480     picoos_uint8 * icontents;
   1481     pico_status_t sResult = PICO_OK;
   1482     picoos_uint16 blen, clen;
   1483     picoos_uint16 numinb, numoutb;
   1484 
   1485 #if defined (PICO_DEBUG)
   1486     picoos_char msgstr[PICOCEP_MSGSTR_SIZE];
   1487 #endif
   1488     numinb = 0;
   1489     numoutb = 0;
   1490 
   1491     if (NULL == this || NULL == this->subObj) {
   1492         return PICODATA_PU_ERROR;
   1493     }
   1494     cep = (cep_subobj_t *) this->subObj;
   1495     mode = mode; /* avoid warning "var not used in this function"*/
   1496 
   1497     /*Init number of output bytes*/
   1498     *numBytesOutput = 0;
   1499 
   1500     while (1) { /* exit via return */
   1501 
   1502         PICODBG_DEBUG(("doing pu state %i", cep->procState));
   1503 
   1504         switch (cep->procState) {
   1505 
   1506             case PICOCEP_STEPSTATE_COLLECT:
   1507                 /* *************** item collector ***********************************/
   1508 
   1509                 PICODBG_TRACE(("COLLECT"));
   1510 
   1511                 /*collecting items from the PU input buffer*/
   1512                 sResult = picodata_cbGetItem(this->cbIn,
   1513                         &(cep->inBuf[cep->inWritePos]), cep->inBufSize
   1514                                 - cep->inWritePos, &blen);
   1515                 if (PICO_EOF == sResult) { /* there are no more items available and we always need more data here */
   1516                     PICODBG_DEBUG(("COLLECT need more data, returning IDLE"));
   1517                     return PICODATA_PU_IDLE;
   1518                 }
   1519 
   1520                 PICODBG_DEBUG(("got item, status: %d", sResult));
   1521 
   1522                 if ((PICO_OK == sResult) && (blen > 0)) {
   1523                     /* we now have one item */
   1524                     cep->inWritePos += blen;
   1525                     cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE;
   1526                 } else {
   1527                     /* ignore item and stay in collect */
   1528                     PICODBG_ERROR(("COLLECT got bad result %i", sResult));
   1529                     cep->inReadPos = cep->inWritePos = 0;
   1530                 }
   1531                 /* return PICODATA_PU_ATOMIC; */
   1532                 break;
   1533 
   1534             case PICOCEP_STEPSTATE_PROCESS_PARSE:
   1535                 /* **************** put item indices into index buffers (with repetition)  ******************/
   1536 
   1537                 PICODBG_TRACE(("PARSE"));
   1538 
   1539                 PICODBG_DEBUG(("getting info from inBuf in range: [%i,%i[", cep->inReadPos, cep->inWritePos));
   1540                 if (cep->inWritePos <= cep->inReadPos) {
   1541                     /* no more items in inBuf */
   1542                     /* we try to get more data */
   1543                     PICODBG_DEBUG(("no more items in inBuf, try to collect more"));
   1544                     /* cep->needMoreInput = TRUE; */
   1545                     cep->inReadPos = cep->inWritePos = 0;
   1546                     cep->procState = PICOCEP_STEPSTATE_COLLECT;
   1547                     break;
   1548                 }
   1549                 /* look at the current item */
   1550                 /*verify that current item is valid */
   1551                 if (!picodata_is_valid_item(cep->inBuf + cep->inReadPos,
   1552                         cep->inWritePos - cep->inReadPos)) {
   1553                     PICODBG_ERROR(("found invalid item"));
   1554                     sResult = picodata_get_iteminfo(
   1555                             cep->inBuf + cep->inReadPos, cep->inWritePos
   1556                                     - cep->inReadPos, &ihead, &icontents);PICODBG_DEBUG(("PARSE bad item %s",picodata_head_to_string(&ihead,msgstr,PICOCEP_MSGSTR_SIZE)));
   1557 
   1558                     return PICODATA_PU_ERROR;
   1559                 }
   1560 
   1561                 sResult = picodata_get_iteminfo(cep->inBuf + cep->inReadPos,
   1562                         cep->inWritePos - cep->inReadPos, &ihead, &icontents);
   1563 
   1564                 if (PICO_EXC_BUF_UNDERFLOW == sResult) {
   1565                     /* no more items in inBuf */
   1566                     /* we try to get more data */
   1567                     PICODBG_DEBUG(("no more items in inBuf, try to collect more"));
   1568                     /* cep->needMoreInput = TRUE; */
   1569                     cep->inReadPos = cep->inWritePos = 0;
   1570                     cep->procState = PICOCEP_STEPSTATE_COLLECT;
   1571                     break;
   1572                 } else if (PICO_OK != sResult) {
   1573                     PICODBG_ERROR(("unknown exception (sResult == %i)",sResult));
   1574                     return (picodata_step_result_t) picoos_emRaiseException(
   1575                             this->common->em, sResult, NULL, NULL);
   1576                     break;
   1577                 }
   1578 
   1579                 PICODBG_DEBUG(("PARSE looking at item %s",picodata_head_to_string(&ihead,msgstr,PICOCEP_MSGSTR_SIZE)));
   1580 
   1581                 cep->nextInPos = PICODATA_ITEM_HEADSIZE + ihead.len;
   1582 
   1583                 /* we decide what to do next depending on the item and the state of the index buffer:
   1584                  * - process buffer if buffer not empty and sentence end or flush or ignsig/start (don't consume item yet)
   1585                  * - fill buffer with (part of) phone contents if item is a phone
   1586                  * - consume or copy for later output otherwise
   1587                  */
   1588 
   1589                 if (cep->inIgnoreState) {
   1590                     if ((PICODATA_ITEM_CMD == ihead.type)
   1591                             && (PICODATA_ITEMINFO1_CMD_IGNSIG == ihead.info1)
   1592                             && (PICODATA_ITEMINFO2_CMD_END == ihead.info2)) {
   1593                         cep->inIgnoreState = 0;
   1594                     }PICODBG_DEBUG(("cep: PARSE consuming item of inBuf"));
   1595                     cep->inReadPos = cep->nextInPos;
   1596                     break;
   1597                 }
   1598 
   1599                 /* see if it is a sentence end boundary or termination boundary (flush) and there are indices to smooth -> smooth */
   1600                 if ((PICODATA_ITEM_BOUND == ihead.type)
   1601                         && ((PICODATA_ITEMINFO1_BOUND_SEND == ihead.info1)
   1602                                 || (PICODATA_ITEMINFO1_BOUND_TERM == ihead.info1))
   1603                         && (cep->indexWritePos > 0)) {
   1604                     /* we smooth the buffer */
   1605                     cep->activeEndPos = cep->indexWritePos;
   1606                     cep->sentenceEnd = TRUE;
   1607                     /* output whatever we got */
   1608                     PICODBG_DEBUG(("cep: PARSE found sentence terminator; setting activeEndPos to %i",cep->activeEndPos));
   1609                     cep->procState = PICOCEP_STEPSTATE_PROCESS_SMOOTH;
   1610                     break;
   1611                 } else if (PICODATA_ITEM_PHONE == ihead.type) {
   1612                     /* it is a phone */
   1613                     PICODBG_DEBUG(("cep: PARSE treating PHONE"));
   1614                     treat_phone(cep, &ihead);
   1615 
   1616                 } else {
   1617                     if ((PICODATA_ITEM_CMD == ihead.type)
   1618                             && (PICODATA_ITEMINFO1_CMD_IGNSIG == ihead.info1)
   1619                             && (PICODATA_ITEMINFO2_CMD_START == ihead.info2)) {
   1620                         cep->inIgnoreState = 1;
   1621                     }
   1622                     /* sentence end or flush remaining after frame or other non-processable item, e.g. command */
   1623                     /* do we have to forward? */
   1624                     if (forwardingItem(&ihead)) {
   1625                         /* if no active frames, output immediately */
   1626                         if (cep->indexWritePos <= 0) {
   1627                             /* copy item to outBuf */
   1628                             PICODBG_DEBUG(("PARSE copy item in inBuf to outBuf"));
   1629                             picodata_copy_item(cep->inBuf + cep->inReadPos,
   1630                                     cep->inWritePos - cep->inReadPos,
   1631                                     cep->outBuf, cep->outBufSize, &blen);
   1632                             cep->outWritePos += blen;
   1633                             PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG],
   1634                                     (picoos_uint8 *)"cep: do forward item ",
   1635                                     cep->outBuf, PICODATA_MAX_ITEMSIZE);
   1636                             /* output item and then go to parse to treat a new item. */
   1637                             cep->feedFollowState
   1638                                     = PICOCEP_STEPSTATE_PROCESS_PARSE;
   1639                             cep->procState = PICOCEP_STEPSTATE_FEED;
   1640                         } else if ((cep->headxWritePos < PICOCEP_MAXNR_HEADX)
   1641                                 && (cep->cbufWritePos + ihead.len
   1642                                         < cep->cbufBufSize)) {
   1643                             /* there is enough space to store item */
   1644                             PICODBG_DEBUG(("unhandled item (type %c, length %i). Storing associated with index %i",ihead.type, ihead.len, cep->indexWritePos));
   1645                             sResult
   1646                                     = picodata_get_itemparts(
   1647                                             cep->inBuf + cep->inReadPos,
   1648                                             cep->inWritePos - cep->inReadPos,
   1649                                             &(cep->headx[cep->headxWritePos].head),
   1650                                             &(cep->cbuf[cep->cbufWritePos]),
   1651                                             cep->cbufBufSize
   1652                                                     - cep->cbufWritePos, &clen);
   1653 
   1654                             if (sResult != PICO_OK) {
   1655                                 PICODBG_ERROR(("problem getting item parts"));
   1656                                 picoos_emRaiseException(this->common->em,
   1657                                         sResult, NULL, NULL);
   1658                                 return PICODATA_PU_ERROR;
   1659                             }
   1660                             /* remember sync position */
   1661                             cep->headx[cep->headxWritePos].frame
   1662                                     = cep->indexWritePos;
   1663 
   1664                             if (clen > 0) {
   1665                                 cep->headx[cep->headxWritePos].cind
   1666                                         = cep->cbufWritePos;
   1667                                 cep->cbufWritePos += clen;
   1668                             } else {
   1669                                 cep->headx[cep->headxWritePos].cind = 0;
   1670                             }
   1671                             cep->headxWritePos++;
   1672                         } else {
   1673                             /* buffer full, smooth and output whatever we got */
   1674                             PICODBG_DEBUG(("PARSE is forced to smooth prematurely; setting activeEndPos to %i", cep->activeEndPos));
   1675                             cep->procState = PICOCEP_STEPSTATE_PROCESS_SMOOTH;
   1676                             /* don't consume item yet */
   1677                             break;
   1678                         }
   1679                     } else {
   1680                     }PICODBG_DEBUG(("cep: PARSE consuming item of inBuf"));
   1681                     cep->inReadPos = cep->nextInPos;
   1682                 }
   1683                 break;
   1684 
   1685             case PICOCEP_STEPSTATE_PROCESS_SMOOTH:
   1686                 /* **************** smooth (indexed) coefficients and store smoothed in outBuffers  ****************/
   1687 
   1688                 PICODBG_TRACE(("SMOOTH"));
   1689                 {
   1690                     picokpdf_PdfMUL pdf;
   1691 
   1692                     /* picoos_uint16 framesTreated = 0; */
   1693                     picoos_uint8 cepnum;
   1694                     picoos_uint16 N;
   1695 
   1696                     N = cep->activeEndPos; /* numframes in current step */
   1697 
   1698                     /* the range to be smoothed starts at 0 and is N long */
   1699 
   1700                     /* smooth each cepstral dimension separately */
   1701                     /* still to be experimented if higher order coeff can remain unsmoothed, i.e. simple copy from pdf */
   1702 
   1703                     /* reset the f0, ceps and voiced outfuffers */
   1704                     cep->outXCepReadPos = cep->outXCepWritePos = 0;
   1705                     cep->outVoicedReadPos = cep->outVoicedWritePos = 0;
   1706                     cep->outF0ReadPos = cep->outF0WritePos = 0;
   1707 
   1708                     PICODBG_DEBUG(("smoothing %d frames\n", N));
   1709 
   1710                     /* smooth f0 */
   1711                     pdf = cep->pdflfz;
   1712                     for (cepnum = 0; cepnum < pdf->ceporder; cepnum++) {
   1713                         if (cep->activeEndPos <= 0) {
   1714                             /* do nothing */
   1715                         } else if (3 < N) {
   1716                             makeWUWandWUm(cep, pdf, cep->indicesLFZ, 0, N,
   1717                                     cepnum); /* update diag0, diag1, diag2, WUm */
   1718                             invMatrix(cep, N, cep->outF0 + cep->outF0WritePos, cepnum, pdf,
   1719                                     PICOCEP_LFZINVPOW, PICOCEP_LFZDOUBLEDEC);
   1720                         } else {
   1721                             getDirect(pdf, cep->indicesLFZ, cep->activeEndPos,
   1722                                     cepnum, cep->outF0 + cep->outF0WritePos);
   1723                         }
   1724                     }/* end for cepnum  */
   1725                     cep->outF0WritePos += cep->activeEndPos * pdf->ceporder;
   1726 
   1727                     /* smooth mgc */
   1728                     pdf = cep->pdfmgc;
   1729                     for (cepnum = 0; cepnum < pdf->ceporder; cepnum++) {
   1730                         if (cep->activeEndPos <= 0) {
   1731                             /* do nothing */
   1732                         } else if (3 < N) {
   1733                             makeWUWandWUm(cep, pdf, cep->indicesMGC, 0, N,
   1734                                     cepnum); /* update diag0, diag1, diag2, WUm */
   1735                             invMatrix(cep, N, cep->outXCep
   1736                                             + cep->outXCepWritePos, cepnum,
   1737                                     pdf, PICOCEP_MGCINVPOW,
   1738                                     PICOCEP_MGCDOUBLEDEC);
   1739                         } else {
   1740                             getDirect(pdf, cep->indicesMGC, cep->activeEndPos,
   1741                                     cepnum, cep->outXCep + cep->outXCepWritePos);
   1742                         }
   1743                     }/* end for cepnum  */
   1744                     cep->outXCepWritePos += cep->activeEndPos * pdf->ceporder;
   1745 
   1746                     getVoiced(pdf, cep->indicesMGC, cep->activeEndPos, cep->outVoiced
   1747                                     + cep->outVoicedWritePos);
   1748                     cep->outVoicedWritePos += cep->activeEndPos;
   1749 
   1750                 }
   1751                 /* setting indexReadPos to the next active index to be used. (will be advanced by FRAME when
   1752                  * reading the phoneId */
   1753                 cep->indexReadPos = 0;
   1754                 cep->procState = PICOCEP_STEPSTATE_PROCESS_FRAME;
   1755                 return PICODATA_PU_BUSY; /*data to feed*/
   1756 
   1757                 break;
   1758 
   1759             case PICOCEP_STEPSTATE_PROCESS_FRAME:
   1760 
   1761                 /* *************** creating output items (type FRAME) ***********************************/
   1762 
   1763                 PICODBG_TRACE(("FRAME"));
   1764 
   1765                 if ((cep->headxBottom < cep->headxWritePos)
   1766                         && (cep->headx[cep->headxBottom].frame
   1767                                 <= cep->indexReadPos)) {
   1768 
   1769                     /* output item in headx/cbuf */
   1770                     /* copy item to outBuf */
   1771                     PICODBG_DEBUG(("FRAME copy item in inBuf to outBuf"));
   1772                     picodata_put_itemparts(
   1773                             &(cep->headx[cep->headxBottom].head),
   1774                             &(cep->cbuf[cep->headx[cep->headxBottom].cind]),
   1775                             cep->headx[cep->headxBottom].head.len, cep->outBuf,
   1776                             cep->outBufSize, &blen);
   1777                     cep->outWritePos += blen;
   1778                     /* consume item in headx/cbuf */
   1779                     PICODBG_DEBUG(("PARSE consuming item of headx/cbuf"));
   1780                     cep->headxBottom++;
   1781 
   1782                     /* output item and then go to parse to treat a new item. */
   1783                     cep->feedFollowState = PICOCEP_STEPSTATE_PROCESS_FRAME;
   1784                     cep->procState = PICOCEP_STEPSTATE_FEED;
   1785                     break;
   1786                 }
   1787 
   1788                 if (cep->indexReadPos < cep->activeEndPos) {
   1789                     /*------------  there are frames to output ----------------------------------------*/
   1790                     /* still frames to output, create new FRAME_PAR item */
   1791 
   1792                     cep->nNumFrames++;
   1793 
   1794                     PICODBG_DEBUG(("FRAME creating FRAME_PAR: active: [0,%i[, read=%i, write=%i",
   1795                                     cep->activeEndPos, cep->indexReadPos, cep->indexWritePos
   1796                             ));
   1797 
   1798                     /* create FRAME_PAR items from cep->outXX one by one */
   1799 
   1800                     /* converting the ceps shorts into floats:
   1801                      * scmeanpow = pdf->bigpow - pdf->meanpow;
   1802                      * for all sval:
   1803                      *   fval = (picoos_single) sval / scmeanpow;
   1804                      */
   1805 
   1806                     cep->outWritePos = cep->outReadPos = 0;
   1807                     cep->outBuf[cep->outWritePos++] = cep->framehead.type;
   1808                     cep->outBuf[cep->outWritePos++] = cep->framehead.info1;
   1809                     cep->outBuf[cep->outWritePos++] = cep->framehead.info2;
   1810                     cep->outBuf[cep->outWritePos++] = cep->framehead.len;
   1811 
   1812                     PICODBG_DEBUG(("FRAME  writing position after header: %i",cep->outWritePos));
   1813 
   1814                     {
   1815                         picoos_uint16 tmpUint16;
   1816                         picoos_int16 tmpInt16;
   1817                         picoos_uint16 i;
   1818 
   1819                         /* */
   1820                         PICODBG_DEBUG(("FRAME reading phoneId[%i] = %c:",cep->indexReadPos, cep->phoneId[cep->indexReadPos]));
   1821                         /* */
   1822 
   1823                         tmpUint16
   1824                                 = (picoos_uint16) cep->phoneId[cep->indexReadPos];
   1825 
   1826                         picoos_mem_copy((void *) &tmpUint16,
   1827                                 (void *) &cep->outBuf[cep->outWritePos],
   1828                                 sizeof(tmpUint16));
   1829 
   1830                         cep->outWritePos += sizeof(tmpUint16);
   1831 
   1832                         PICODBG_DEBUG(("FRAME  writing position after phone id: %i",cep->outWritePos));
   1833 
   1834                         for (i = 0; i < cep->pdflfz->ceporder; i++) {
   1835 
   1836                             tmpUint16 = (cep->outVoiced[cep->outVoicedReadPos]
   1837                                     & 0x01) ? cep->outF0[cep->outF0ReadPos]
   1838                                     : (picoos_uint16) 0;
   1839 
   1840                             picoos_mem_copy((void *) &tmpUint16,
   1841                                     (void *) &cep->outBuf[cep->outWritePos],
   1842                                     sizeof(tmpUint16));
   1843                             cep->outWritePos += sizeof(tmpUint16);
   1844 
   1845                             tmpUint16
   1846                                     = (picoos_uint16) (cep->outVoiced[cep->outVoicedReadPos]);
   1847                             picoos_mem_copy((void *) &tmpUint16,
   1848                                     (void *) &cep->outBuf[cep->outWritePos],
   1849                                     sizeof(tmpUint16));
   1850                             cep->outWritePos += sizeof(tmpUint16);
   1851                             tmpUint16
   1852                                     = (picoos_uint16) (cep->outF0[cep->outF0ReadPos]);
   1853                             picoos_mem_copy((void *) &tmpUint16,
   1854                                     (void *) &cep->outBuf[cep->outWritePos],
   1855                                     sizeof(tmpUint16));
   1856                             cep->outWritePos += sizeof(tmpUint16);
   1857 
   1858                             cep->outVoicedReadPos++;
   1859                             cep->outF0ReadPos++;
   1860                         }
   1861 
   1862                         PICODBG_DEBUG(("FRAME writing position after f0: %i",cep->outWritePos));
   1863 
   1864                         for (i = 0; i < cep->pdfmgc->ceporder; i++) {
   1865                             tmpInt16 = cep->outXCep[cep->outXCepReadPos++];
   1866                             picoos_mem_copy((void *) &tmpInt16,
   1867                                     (void *) &cep->outBuf[cep->outWritePos],
   1868                                     sizeof(tmpInt16));
   1869                             cep->outWritePos += sizeof(tmpInt16);
   1870                         }
   1871 
   1872                         PICODBG_DEBUG(("FRAME  writing position after cepstrals: %i",cep->outWritePos));
   1873 
   1874                         tmpUint16
   1875                                 = (picoos_uint16) cep->indicesMGC[cep->indexReadPos++];
   1876 
   1877                         picoos_mem_copy((void *) &tmpUint16,
   1878                                 (void *) &cep->outBuf[cep->outWritePos],
   1879                                 sizeof(tmpUint16));
   1880 
   1881                         PICODBG_DEBUG(("FRAME  writing position after mgc index: %i",cep->outWritePos));
   1882 
   1883                         cep->outWritePos += sizeof(tmpUint16);
   1884 
   1885                     }
   1886                     /* finished to create FRAME_PAR, now output and then come back*/
   1887                     cep->feedFollowState = PICOCEP_STEPSTATE_PROCESS_FRAME;
   1888                     cep->procState = PICOCEP_STEPSTATE_FEED;
   1889 
   1890                 } else if (cep->sentenceEnd) {
   1891                     /*------------  no more frames to output at end of sentence ----------------------------------------*/
   1892                     PICODBG_INFO(("End of sentence - Processed frames : %d",
   1893                                     cep->nNumFrames));
   1894                     cep->nNumFrames = 0;PICODBG_DEBUG(("FRAME no more active frames for this sentence"));
   1895                     /* no frames left in this sentence*/
   1896                     /* reset for new sentence */
   1897                     initSmoothing(cep);
   1898                     cep->sentenceEnd = FALSE;
   1899                     cep->indexReadPos = cep->indexWritePos = 0;
   1900                     cep->activeEndPos = PICOCEP_MAXWINLEN;
   1901                     cep->headxBottom = cep->headxWritePos = 0;
   1902                     cep->cbufWritePos = 0;
   1903                     cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE;
   1904                 } else {
   1905                     /*------------  no more frames can be output but sentence end not reached ----------------------------------------*/
   1906                     PICODBG_DEBUG(("Maximum number of frames per sentence reached"));
   1907                     cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE;
   1908                 }
   1909                 /*----------------------------------------------------*/
   1910                 break;
   1911 
   1912             case PICOCEP_STEPSTATE_FEED:
   1913                 /* ***********************************************************************/
   1914                 /* FEED: combine input item with pos/phon pairs to output item */
   1915                 /* ***********************************************************************/
   1916 
   1917                 PICODBG_DEBUG(("FEED"));
   1918 
   1919                 PICODBG_DEBUG(("FEED putting outBuf item into cb"));
   1920 
   1921                 /*feeding items to PU output buffer*/
   1922                 sResult = picodata_cbPutItem(this->cbOut, cep->outBuf,
   1923                         cep->outBufSize, &blen);
   1924 
   1925                 if (PICO_EXC_BUF_OVERFLOW == sResult) {
   1926                     /* we have to redo this item */
   1927                     PICODBG_DEBUG(("FEED got overflow, returning PICODATA_PU_OUT_FULL"));
   1928                     return PICODATA_PU_OUT_FULL;
   1929                 } else if (PICO_OK == sResult) {
   1930 
   1931                     if (cep->outBuf[0] != 'k') {
   1932                         PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG],
   1933                                 (picoos_uint8 *)"cep: ",
   1934                                 cep->outBuf, PICODATA_MAX_ITEMSIZE);
   1935                     }
   1936 
   1937                     *numBytesOutput += blen;
   1938                     /*-------------------------*/
   1939                     /*reset the output pointers*/
   1940                     /*-------------------------*/
   1941                     if (cep->outReadPos >= cep->outWritePos) {
   1942                         cep->outReadPos = 0;
   1943                         cep->outWritePos = 0;
   1944                     }
   1945                     cep->procState = cep->feedFollowState;
   1946                     PICODBG_DEBUG(("FEED ok, going back to procState %i", cep->procState));
   1947                     return PICODATA_PU_BUSY;
   1948                 } else {
   1949                     PICODBG_DEBUG(("FEED got exception %i when trying to output item",sResult));
   1950                     cep->procState = cep->feedFollowState;
   1951                     return (picodata_step_result_t) sResult;
   1952                 }
   1953                 break;
   1954 
   1955             default:
   1956                 /*NOT feeding items*/
   1957                 sResult = PICO_EXC_BUF_IGNORE;
   1958                 break;
   1959         }/*end switch (cep->procState) */
   1960         return PICODATA_PU_BUSY; /*check if there is more data to process after feeding*/
   1961 
   1962     }/*end while*/
   1963     /* we should never come here */
   1964     return PICODATA_PU_ERROR;
   1965 }/*cepStep*/
   1966 
   1967 /* Picocep.c end */
   1968