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 picoctrl.c
     18  *
     19  * Control 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 #include "picodefs.h"
     30 #include "picoos.h"
     31 #include "picodbg.h"
     32 #include "picodata.h"
     33 #include "picorsrc.h"
     34 
     35 /* processing unit definitions */
     36 #include "picotok.h"
     37 #include "picopr.h"
     38 #include "picowa.h"
     39 #include "picosa.h"
     40 #include "picoacph.h"
     41 #include "picospho.h"
     42 #include "picopam.h"
     43 #include "picocep.h"
     44 #include "picosig.h"
     45 #if defined(PICO_DEVEL_MODE)
     46 #include "../history/picosink.h"
     47 #endif
     48 
     49 #include "picoctrl.h"
     50 
     51 #ifdef __cplusplus
     52 extern "C" {
     53 #endif
     54 #if 0
     55 }
     56 #endif
     57 
     58 /**
     59  * @addtogroup picoctrl
     60  * @b Control
     61  * The "control" is a processing unit (PU) that contains and governs a sequence of sub-PUs
     62  * (TTS processing chain).
     63  * At each step (ctrlStep) it passes control to one of the sub-PUs (currrent PU). It may re-assign
     64  * the role of "current PU" to another sub-PU, according to the status information returned from each PU.
     65  */
     66 
     67 /*----------------------------------------------------------
     68  *  object   : Control
     69  *  shortcut     : ctrl
     70  *  derived from : picodata_ProcessingUnit
     71  *  implements a ProcessingUnit by creating and controlling
     72  *  a sequence of Processing Units (of possibly different
     73  *  implementations) exchanging data via CharBuffers
     74  * ---------------------------------------------------------*/
     75 /* control sub-object */
     76 typedef struct ctrl_subobj {
     77     picoos_uint8 numProcUnits;
     78     picoos_uint8 curPU;
     79     picoos_uint8 lastItemTypeProduced;
     80     picodata_ProcessingUnit procUnit [PICOCTRL_MAX_PROC_UNITS];
     81     picodata_step_result_t procStatus [PICOCTRL_MAX_PROC_UNITS];
     82     picodata_CharBuffer procCbOut [PICOCTRL_MAX_PROC_UNITS];
     83 } ctrl_subobj_t;
     84 
     85 /**
     86  * performs Control PU initialization
     87  * @param    this : pointer to Control PU
     88  * @return    PICO_OK : processing done
     89  * @return    PICO_ERR_OTHER : init error
     90  * @callgraph
     91  * @callergraph
     92  */
     93 static pico_status_t ctrlInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) {
     94     register ctrl_subobj_t * ctrl;
     95     pico_status_t status= PICO_OK;
     96     picoos_int8 i;
     97 
     98     if (NULL == this || NULL == this->subObj) {
     99         return PICO_ERR_OTHER;
    100     }
    101     ctrl = (ctrl_subobj_t *) this->subObj;
    102     ctrl->curPU = 0;
    103     ctrl->lastItemTypeProduced=0;    /*no item produced by default*/
    104     status = PICO_OK;
    105     for (i = 0; i < ctrl->numProcUnits; i++) {
    106         if (PICO_OK == status) {
    107             status = ctrl->procUnit[i]->initialize(ctrl->procUnit[i], resetMode);
    108             PICODBG_DEBUG(("(re-)initializing procUnit[%i] returned status %i",i, status));
    109         }
    110         if (PICO_OK == status) {
    111             status = picodata_cbReset(ctrl->procCbOut[i]);
    112             PICODBG_DEBUG(("(re-)initializing procCbOut[%i] returned status %i",i, status));
    113         }
    114     }
    115     if (PICO_OK != status) {
    116         picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*)"problem (re-)initializing the engine");
    117     }
    118     return status;
    119 }/*ctrlInitialize*/
    120 
    121 
    122 /**
    123  * performs one processing step
    124  * @param    this : pointer to Control PU
    125  * @param    mode : activation mode (unused)
    126  * @param    bytesOutput : number of bytes produced during this step (output)
    127  * @return    PICO_OK : processing done
    128  * @return    PICO_EXC_OUT_OF_MEM : no more memory available
    129  * @return    PICO_ERR_OTHER : other error
    130  * @callgraph
    131  * @callergraph
    132  */
    133 static picodata_step_result_t ctrlStep(register picodata_ProcessingUnit this,
    134         picoos_int16 mode, picoos_uint16 * bytesOutput) {
    135     /* rules/invariants:
    136      * - all pu's above current have status idle except possibly pu+1, which may  be busy.
    137      *   (The latter is set if any pu->step produced output)
    138      * - a pu returns idle iff its cbIn is empty and it has no more data ready for output */
    139 
    140     register ctrl_subobj_t * ctrl = (ctrl_subobj_t *) this->subObj;
    141     picodata_step_result_t status;
    142     picoos_uint16 puBytesOutput;
    143 #if defined(PICO_DEVEL_MODE)
    144     picoos_uint8  btype;
    145 #endif
    146 
    147     *bytesOutput = 0;
    148     ctrl->lastItemTypeProduced=0; /*no item produced by default*/
    149 
    150     /* --------------------- */
    151     /* do step of current pu */
    152     /* --------------------- */
    153     status = ctrl->procStatus[ctrl->curPU] = ctrl->procUnit[ctrl->curPU]->step(
    154             ctrl->procUnit[ctrl->curPU], mode, &puBytesOutput);
    155 
    156     if (puBytesOutput) {
    157 
    158 #if defined(PICO_DEVEL_MODE)
    159         /*store the type of item produced*/
    160         btype =  picodata_cbGetFrontItemType(ctrl->procUnit[ctrl->curPU]->cbOut);
    161         ctrl->lastItemTypeProduced=(picoos_uint8)btype;
    162 #endif
    163 
    164         if (ctrl->curPU < ctrl->numProcUnits-1) {
    165             /* data was output to internal PU buffers : set following pu to busy */
    166             ctrl->procStatus[ctrl->curPU + 1] = PICODATA_PU_BUSY;
    167         } else {
    168             /* data was output to caller output buffer */
    169             *bytesOutput = puBytesOutput;
    170         }
    171     }
    172     /* recalculate state depending on pu status returned from curPU */
    173     switch (status) {
    174         case PICODATA_PU_ATOMIC:
    175             PICODBG_DEBUG(("got PICODATA_PU_ATOMIC"));
    176             return status;
    177             break;
    178 
    179         case PICODATA_PU_BUSY:
    180             PICODBG_DEBUG(("got PICODATA_PU_BUSY"));
    181             if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY
    182                     == ctrl->procStatus[ctrl->curPU+1])) {
    183                 ctrl->curPU++;
    184             }
    185             return status;
    186             break;
    187 
    188         case PICODATA_PU_IDLE:
    189             PICODBG_DEBUG(("got PICODATA_PU_IDLE"));
    190             if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY
    191                     == ctrl->procStatus[ctrl->curPU+1])) {
    192                 /* still data to process below */
    193                 ctrl->curPU++;
    194             } else if (0 == ctrl->curPU) { /* all pu's are idle */
    195                 /* nothing to do */
    196             } else { /* find non-idle pu above */
    197                 PICODBG_DEBUG((
    198                     "find non-idle pu above from pu %d with status %d",
    199                     ctrl->curPU, ctrl->procStatus[ctrl->curPU]));
    200                 while ((ctrl->curPU > 0) && (PICODATA_PU_IDLE
    201                         == ctrl->procStatus[ctrl->curPU])) {
    202                     ctrl->curPU--;
    203                 }
    204                 ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY;
    205             }
    206             PICODBG_DEBUG(("going to pu %d with status %d",
    207                            ctrl->curPU, ctrl->procStatus[ctrl->curPU]));
    208             /*update last scheduled PU*/
    209             return ctrl->procStatus[ctrl->curPU];
    210             break;
    211 
    212         case PICODATA_PU_OUT_FULL:
    213             PICODBG_DEBUG(("got PICODATA_PU_OUT_FULL"));
    214             if (ctrl->curPU+1 < ctrl->numProcUnits) { /* let pu below empty buffer */
    215                 ctrl->curPU++;
    216                 ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY;
    217             } else {
    218                 /* nothing more to do, out_full will be returned to caller */
    219             }
    220             return ctrl->procStatus[ctrl->curPU];
    221             break;
    222         default:
    223             return PICODATA_PU_ERROR;
    224             break;
    225     }
    226 }/*ctrlStep*/
    227 
    228 /**
    229  * terminates Control PU
    230  * @param    this : pointer to Control PU
    231  * @return    PICO_OK : processing done
    232  * @return    PICO_ERR_OTHER : other error
    233  * @callgraph
    234  * @callergraph
    235  */
    236 static pico_status_t ctrlTerminate(register picodata_ProcessingUnit this) {
    237     pico_status_t status = PICO_OK;
    238     picoos_int16 i;
    239     register ctrl_subobj_t * ctrl;
    240     if (NULL == this || NULL == this->subObj) {
    241         return PICO_ERR_OTHER;
    242     }
    243     ctrl = (ctrl_subobj_t *) this->subObj;
    244     for (i = 0; i < ctrl->numProcUnits; i++) {
    245         status = ctrl->procUnit[i]->terminate(ctrl->procUnit[i]);
    246         PICODBG_DEBUG(("terminating procUnit[%i] returned status %i",i, status));
    247         if (PICO_OK != status) {
    248             return status;
    249         }
    250     }
    251     return status;
    252 }/*ctrlTerminate*/
    253 
    254 /**
    255  * deallocates Control PU's subobject
    256  * @param    this : pointer to Control PU
    257  * @return    PICO_OK : processing done
    258  * @return    PICO_ERR_OTHER : other error
    259  * @callgraph
    260  * @callergraph
    261  */
    262 static pico_status_t ctrlSubObjDeallocate(register picodata_ProcessingUnit this,
    263         picoos_MemoryManager mm) {
    264     register ctrl_subobj_t * ctrl;
    265     picoos_int16 i;
    266 
    267     if (NULL == this || NULL == this->subObj) {
    268         return PICO_ERR_OTHER;
    269     }
    270     ctrl = (ctrl_subobj_t *) this->subObj;
    271     mm = mm;        /* fix warning "var not used in this function"*/
    272     /* deallocate members (procCbOut and procUnit) */
    273     for (i = ctrl->numProcUnits-1; i >= 0; i--) {
    274         picodata_disposeProcessingUnit(this->common->mm,&ctrl->procUnit[i]);
    275         picodata_disposeCharBuffer(this->common->mm, &ctrl->procCbOut[i]);
    276     }
    277     /* deallocate object itself */
    278     picoos_deallocate(this->common->mm, (void *) &this->subObj);
    279 
    280     return PICO_OK;
    281 }/*ctrlSubObjDeallocate*/
    282 
    283 /**
    284  * inserts a new PU in the TTS processing chain
    285  * @param    this : pointer to Control PU
    286  * @param    puType : type of the PU to be inserted
    287  * @param    last : if true, inserted PU is the last in the TTS processing chain
    288  * @return    PICO_OK : processing done
    289  * @return    PICO_EXC_OUT_OF_MEM : no more memory available
    290  * @return    PICO_ERR_OTHER : other error
    291  * @remarks    Calls the PU object creation method
    292  * @callgraph
    293  * @callergraph
    294  */
    295 static pico_status_t ctrlAddPU(register picodata_ProcessingUnit this,
    296         picodata_putype_t puType,
    297         picoos_bool levelAwareCbOut,
    298         picoos_bool last)
    299 {
    300     picoos_uint16 bufSize;
    301     register ctrl_subobj_t * ctrl;
    302     picodata_CharBuffer cbIn;
    303     picoos_uint8 newPU;
    304     if (this == NULL) {
    305         return PICO_ERR_OTHER;
    306     }
    307     ctrl = (ctrl_subobj_t *) this->subObj;
    308     if (ctrl == NULL) {
    309         return PICO_ERR_OTHER;
    310     }
    311     newPU = ctrl->numProcUnits;
    312     if (0 == newPU) {
    313         PICODBG_DEBUG(("taking cbIn of this because adding first pu"));
    314         cbIn = this->cbIn;
    315     } else {
    316         PICODBG_DEBUG(("taking cbIn of previous pu"));
    317         cbIn = ctrl->procCbOut[newPU-1];
    318     }
    319     if (last) {
    320         PICODBG_DEBUG(("taking cbOut of this because adding last pu"));
    321         ctrl->procCbOut[newPU] = this->cbOut;
    322     } else {
    323         PICODBG_DEBUG(("creating intermediate cbOut of pu[%i]", newPU));
    324         bufSize = picodata_get_default_buf_size(puType);
    325         ctrl->procCbOut[newPU] = picodata_newCharBuffer(this->common->mm,
    326                 this->common,bufSize);
    327 
    328         PICODBG_DEBUG(("intermediate cbOut of pu[%i] (address %i)", newPU,
    329                        (picoos_uint32) ctrl->procCbOut[newPU]));
    330         if (NULL == ctrl->procCbOut[newPU]) {
    331             return PICO_EXC_OUT_OF_MEM;
    332         }
    333     }
    334     ctrl->procStatus[newPU] = PICODATA_PU_IDLE;
    335     /*...............*/
    336     switch (puType) {
    337     case PICODATA_PUTYPE_TOK:
    338             PICODBG_DEBUG(("creating TokenizeUnit for pu %i", newPU));
    339             ctrl->procUnit[newPU] = picotok_newTokenizeUnit(this->common->mm,
    340                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    341         break;
    342     case PICODATA_PUTYPE_PR:
    343             PICODBG_DEBUG(("creating PreprocUnit for pu %i", newPU));
    344             ctrl->procUnit[newPU] = picopr_newPreprocUnit(this->common->mm,
    345                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    346         break;
    347     case PICODATA_PUTYPE_WA:
    348             PICODBG_DEBUG(("creating WordAnaUnit for pu %i", newPU));
    349             ctrl->procUnit[newPU] = picowa_newWordAnaUnit(this->common->mm,
    350                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    351         break;
    352     case PICODATA_PUTYPE_SA:
    353             PICODBG_DEBUG(("creating SentAnaUnit for pu %i", newPU));
    354             ctrl->procUnit[newPU] = picosa_newSentAnaUnit(this->common->mm,
    355                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    356         break;
    357     case PICODATA_PUTYPE_ACPH:
    358             PICODBG_DEBUG(("creating AccPhrUnit for pu %i", newPU));
    359             ctrl->procUnit[newPU] = picoacph_newAccPhrUnit(this->common->mm,
    360                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    361         break;
    362     case PICODATA_PUTYPE_SPHO:
    363             PICODBG_DEBUG(("creating SentPhoUnit for pu %i", newPU));
    364             ctrl->procUnit[newPU] = picospho_newSentPhoUnit(this->common->mm,
    365                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    366             break;
    367     case PICODATA_PUTYPE_PAM:
    368             PICODBG_DEBUG(("creating PAMUnit for pu %i", newPU));
    369             ctrl->procUnit[newPU] = picopam_newPamUnit(this->common->mm,
    370                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    371         break;
    372     case PICODATA_PUTYPE_CEP:
    373             PICODBG_DEBUG(("creating CepUnit for pu %i", newPU));
    374             ctrl->procUnit[newPU] = picocep_newCepUnit(this->common->mm,
    375                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    376         break;
    377 #if defined(PICO_DEVEL_MODE)
    378         case PICODATA_PUTYPE_SINK:
    379             PICODBG_DEBUG(("creating SigUnit for pu %i", newPU));
    380             ctrl->procUnit[newPU] = picosink_newSinkUnit(this->common->mm,
    381                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    382         break;
    383 #endif
    384         case PICODATA_PUTYPE_SIG:
    385             PICODBG_DEBUG(("creating SigUnit for pu %i", newPU));
    386             ctrl->procUnit[newPU] = picosig_newSigUnit(this->common->mm,
    387                     this->common, cbIn, ctrl->procCbOut[newPU], this->voice);
    388         break;
    389     default:
    390             ctrl->procUnit[newPU] = picodata_newProcessingUnit(
    391                     this->common->mm, this->common, cbIn,
    392                     ctrl->procCbOut[newPU], this->voice);
    393         break;
    394     }
    395     if (NULL == ctrl->procUnit[newPU]) {
    396         picodata_disposeCharBuffer(this->common->mm,&ctrl->procCbOut[newPU]);
    397         return PICO_EXC_OUT_OF_MEM;
    398     }
    399     ctrl->numProcUnits++;
    400     return PICO_OK;
    401 }/*ctrlAddPU*/
    402 
    403 /*forward declaration : see below for full function body*/
    404 void picoctrl_disposeControl(picoos_MemoryManager mm,
    405         picodata_ProcessingUnit * this);
    406 
    407 /**
    408  * initializes a control PU object
    409  * @param    mm : memory manager
    410  * @param    common : the common object
    411  * @param    cbIn : the input char buffer
    412  * @param    cbOut : the output char buffer
    413  * @param    voice : the voice object
    414  * @return    the pointer to the PU object created if OK
    415  * @return    PICO_EXC_OUT_OF_MEM : no more memory available
    416  * @return    NULL otherwise
    417  * @callgraph
    418  * @callergraph
    419  */
    420 picodata_ProcessingUnit picoctrl_newControl(picoos_MemoryManager mm,
    421         picoos_Common common, picodata_CharBuffer cbIn,
    422         picodata_CharBuffer cbOut, picorsrc_Voice voice) {
    423     picoos_int16 i;
    424     register ctrl_subobj_t * ctrl;
    425     picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn,
    426             cbOut,voice);
    427     if (this == NULL) {
    428         return NULL;
    429     }
    430 
    431     this->initialize = ctrlInitialize;
    432     this->step = ctrlStep;
    433     this->terminate = ctrlTerminate;
    434     this->subDeallocate = ctrlSubObjDeallocate;
    435 
    436     this->subObj = picoos_allocate(mm, sizeof(ctrl_subobj_t));
    437     if (this->subObj == NULL) {
    438         picoos_deallocate(mm, (void **)(void*)&this);
    439         return NULL;
    440     }
    441 
    442     ctrl = (ctrl_subobj_t *) this->subObj;
    443 
    444     for (i=0; i < PICOCTRL_MAX_PROC_UNITS; i++) {
    445         ctrl->procUnit[i] = NULL;
    446         ctrl->procStatus[i] = PICODATA_PU_IDLE;
    447         ctrl->procCbOut[i] = NULL;
    448     }
    449     ctrl->numProcUnits = 0;
    450 
    451     if (
    452             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_TOK, FALSE, /*last*/FALSE)) &&
    453             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PR, FALSE, FALSE)) &&
    454             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_WA, FALSE, FALSE)) &&
    455             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SA, FALSE, FALSE)) &&
    456             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_ACPH, FALSE, FALSE)) &&
    457             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SPHO, FALSE, FALSE)) &&
    458             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PAM, FALSE, FALSE)) &&
    459             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_CEP, FALSE, FALSE)) &&
    460             (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SIG, FALSE, TRUE))
    461          ) {
    462 
    463         /* we don't call ctrlInitialize here because ctrlAddPU does initialize the PUs allready and the only thing
    464          * remaining to initialize is:
    465          */
    466         ctrl->curPU = 0;
    467         return this;
    468     } else {
    469         picoctrl_disposeControl(this->common->mm,&this);
    470         return NULL;
    471     }
    472 
    473 }/*picoctrl_newControl*/
    474 
    475 /**
    476  * disposes a Control PU
    477  * @param    mm : memory manager
    478  * @param    this : pointer to Control PU
    479  *
    480  * @return    void
    481  * @callgraph
    482  * @callergraph
    483  */
    484 void picoctrl_disposeControl(picoos_MemoryManager mm,
    485         picodata_ProcessingUnit * this)
    486 {
    487     picodata_disposeProcessingUnit(mm, this);
    488 }/*picoctrl_disposeControl*/
    489 
    490 /* **************************************************************************
    491  *
    492  *      Engine
    493  *
    494  ****************************************************************************/
    495 /** object       : Engine
    496  *  shortcut     : eng
    497  */
    498 typedef struct picoctrl_engine {
    499     picoos_uint32 magic;        /* magic number used to validate handles */
    500     void *raw_mem;
    501     picoos_Common common;
    502     picorsrc_Voice voice;
    503     picodata_ProcessingUnit control;
    504     picodata_CharBuffer cbIn, cbOut;
    505 } picoctrl_engine_t;
    506 
    507 
    508 #define MAGIC_MASK 0x5069436F  /* PiCo */
    509 
    510 #define SET_MAGIC_NUMBER(eng) \
    511     (eng)->magic = ((picoos_uint32) (uintptr_t) (eng)) ^ MAGIC_MASK
    512 
    513 #define CHECK_MAGIC_NUMBER(eng) \
    514     ((eng)->magic == (((picoos_uint32) (uintptr_t) (eng)) ^ MAGIC_MASK))
    515 
    516 /**
    517  * performs an engine reset
    518  * @param    this : the engine object
    519  * @return    PICO_OK : reset performed
    520  * @return    otherwise error code
    521  * @callgraph
    522  * @callergraph
    523  */
    524 pico_status_t picoctrl_engReset(picoctrl_Engine this, picoos_int32 resetMode)
    525 {
    526     pico_status_t status;
    527 
    528     if (NULL == this) {
    529         return PICO_ERR_NULLPTR_ACCESS;
    530     }
    531     picoos_emReset(this->common->em);
    532 
    533     status = this->control->terminate(this->control);
    534     if (PICO_OK == status) {
    535         status = this->control->initialize(this->control, resetMode);
    536     }
    537     if (PICO_OK == status) {
    538         status = picodata_cbReset(this->cbIn);
    539     }
    540     if (PICO_OK == status) {
    541         status = picodata_cbReset(this->cbOut);
    542     }
    543     if (PICO_OK != status) {
    544         picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*) "problem resetting engine");
    545     }
    546     return status;
    547 }
    548 
    549 /**
    550  * checks an engine handle
    551  * @param    this : the engine object
    552  * @return    PICO_OK : reset performed
    553  * @return    non-zero if 'this' is a valid engine handle
    554  * @return  zero otherwise
    555  * @callgraph
    556  * @callergraph
    557  */
    558 picoos_int16 picoctrl_isValidEngineHandle(picoctrl_Engine this)
    559 {
    560     return (this != NULL) && CHECK_MAGIC_NUMBER(this);
    561 }/*picoctrl_isValidEngineHandle*/
    562 
    563 /**
    564  * creates a new engine object
    565  * @param    mm : memory manager to be used for this engine
    566  * @param    rm : resource manager to be used for this engine
    567  * @param    voiceName : voice definition to be used for this engine
    568  * @return    PICO_OK : reset performed
    569  * @return    new engine handle
    570  * @return  NULL otherwise
    571  * @callgraph
    572  * @callergraph
    573  */
    574 picoctrl_Engine picoctrl_newEngine(picoos_MemoryManager mm,
    575         picorsrc_ResourceManager rm, const picoos_char * voiceName) {
    576     picoos_uint8 done= TRUE;
    577 
    578     picoos_uint16 bSize;
    579 
    580     picoos_MemoryManager engMM;
    581     picoos_ExceptionManager engEM;
    582 
    583     picoctrl_Engine this = (picoctrl_Engine) picoos_allocate(mm, sizeof(*this));
    584 
    585     PICODBG_DEBUG(("creating engine for voice '%s'",voiceName));
    586 
    587     done = (NULL != this);
    588 
    589     if (done) {
    590         this->magic = 0;
    591         this->common = NULL;
    592         this->voice = NULL;
    593         this->control = NULL;
    594         this->cbIn = NULL;
    595         this->cbOut = NULL;
    596 
    597         this->raw_mem = picoos_allocate(mm, PICOCTRL_DEFAULT_ENGINE_SIZE);
    598         if (NULL == this->raw_mem) {
    599             done = FALSE;
    600         }
    601     }
    602 
    603     if (done) {
    604         engMM = picoos_newMemoryManager(this->raw_mem, PICOCTRL_DEFAULT_ENGINE_SIZE,
    605                     /*enableMemProt*/ FALSE);
    606         done = (NULL != engMM);
    607     }
    608     if (done) {
    609         this->common = picoos_newCommon(engMM);
    610         engEM = picoos_newExceptionManager(engMM);
    611         done = (NULL != this->common) && (NULL != engEM);
    612     }
    613     if (done) {
    614         this->common->mm = engMM;
    615         this->common->em = engEM;
    616 
    617         done = (PICO_OK == picorsrc_createVoice(rm,voiceName,&(this->voice)));
    618     }
    619     if (done)  {
    620         bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_TEXT);
    621 
    622         this->cbIn = picodata_newCharBuffer(this->common->mm,
    623                 this->common, bSize);
    624         bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_SIG);
    625 
    626         this->cbOut = picodata_newCharBuffer(this->common->mm,
    627                 this->common, bSize);
    628 
    629         PICODBG_DEBUG(("cbOut has address %i", (picoos_uint32) this->cbOut));
    630 
    631 
    632         this->control = picoctrl_newControl(this->common->mm, this->common,
    633                 this->cbIn, this->cbOut, this->voice);
    634         done = (NULL != this->cbIn) && (NULL != this->cbOut)
    635                 && (NULL != this->control);
    636     }
    637     if (done) {
    638         SET_MAGIC_NUMBER(this);
    639     } else {
    640         if (NULL != this) {
    641             if (NULL != this->voice) {
    642                 picorsrc_releaseVoice(rm,&(this->voice));
    643             }
    644             if(NULL != this->raw_mem) {
    645                 picoos_deallocate(mm,&(this->raw_mem));
    646             }
    647             picoos_deallocate(mm,(void *)&this);
    648         }
    649     }
    650     return this;
    651 }/*picoctrl_newEngine*/
    652 
    653 /**
    654  * disposes an engine object
    655  * @param    mm : memory manager associated to the engine
    656  * @param    rm : resource manager associated to the engine
    657  * @param    this : handle of the engine to dispose
    658  * @return    PICO_OK : reset performed
    659  * @return    void
    660  * @callgraph
    661  * @callergraph
    662  */
    663 void picoctrl_disposeEngine(picoos_MemoryManager mm, picorsrc_ResourceManager rm,
    664         picoctrl_Engine * this)
    665 {
    666     if (NULL != (*this)) {
    667         if (NULL != (*this)->voice) {
    668             picorsrc_releaseVoice(rm,&((*this)->voice));
    669         }
    670         if(NULL != (*this)->control) {
    671             picoctrl_disposeControl((*this)->common->mm,&((*this)->control));
    672         }
    673         if(NULL != (*this)->raw_mem) {
    674             picoos_deallocate(mm,&((*this)->raw_mem));
    675         }
    676         (*this)->magic ^= 0xFFFEFDFC;
    677         picoos_deallocate(mm,(void **)this);
    678     }
    679 }/*picoctrl_disposeEngine*/
    680 
    681 /**
    682  * resets the exception manager of an engine
    683  * @param    this : handle of the engine
    684  * @return    void
    685  * @callgraph
    686  * @callergraph
    687  */
    688 void picoctrl_engResetExceptionManager(
    689         picoctrl_Engine this
    690         )
    691 {
    692         picoos_emReset(this->common->em);
    693 }/*picoctrl_engResetExceptionManager*/
    694 
    695 /**
    696  * returns the engine common pointer
    697  * @param    this : handle of the engine
    698  * @return    PICO_OK : reset performed
    699  * @return    the engine common pointer
    700  * @return    NULL if error
    701  * @callgraph
    702  * @callergraph
    703  */
    704 picoos_Common picoctrl_engGetCommon(picoctrl_Engine this) {
    705     if (NULL == this) {
    706         return NULL;
    707     } else {
    708         return this->common;
    709     }
    710 }/*picoctrl_engGetCommon*/
    711 
    712 /**
    713  * feed raw 'text' into 'engine'. text may contain '\\0'.
    714  * @param    this : handle of the engine
    715  * @param    text : the input text
    716  * @param    textSize : size of the input text
    717  * @param    *bytesPut : the number of bytes effectively consumed from 'text'.
    718  * @return    PICO_OK : feeding succeded
    719  * @return    PICO_ERR_OTHER : if error
    720  * @callgraph
    721  * @callergraph
    722  */
    723 pico_status_t picoctrl_engFeedText(picoctrl_Engine this,
    724         picoos_char * text,
    725         picoos_int16 textSize, picoos_int16 * bytesPut) {
    726     if (NULL == this) {
    727         return PICO_ERR_OTHER;
    728     }
    729     PICODBG_DEBUG(("get \"%.100s\"", text));
    730     *bytesPut = 0;
    731     while ((*bytesPut < textSize) && (PICO_OK == picodata_cbPutCh(this->cbIn, text[*bytesPut]))) {
    732         (*bytesPut)++;
    733     }
    734 
    735     return PICO_OK;
    736 }/*picoctrl_engFeedText*/
    737 
    738 /**
    739  * gets engine output bytes
    740  * @param    this : handle of the engine
    741  * @param    buffer : the destination buffer
    742  * @param    bufferSize : max size of the destinatioon buffer
    743  * @param    *bytesReceived : the number of bytes effectively returned
    744  * @return    PICO_OK : feeding succeded
    745  * @return    PICO_ERR_OTHER : if error
    746  * @callgraph
    747  * @callergraph
    748  */
    749 picodata_step_result_t picoctrl_engFetchOutputItemBytes(
    750         picoctrl_Engine this,
    751         picoos_char *buffer,
    752         picoos_int16 bufferSize,
    753         picoos_int16 *bytesReceived) {
    754     picoos_uint16 ui;
    755     picodata_step_result_t stepResult;
    756     pico_status_t rv;
    757 
    758     if (NULL == this) {
    759         return (picodata_step_result_t)PICO_STEP_ERROR;
    760     }
    761     PICODBG_DEBUG(("doing one step"));
    762     stepResult = this->control->step(this->control,/* mode */0,&ui);
    763     if (PICODATA_PU_ERROR != stepResult) {
    764         PICODBG_TRACE(("filling output buffer"));
    765         rv = picodata_cbGetSpeechData(this->cbOut, (picoos_uint8 *)buffer,
    766                                       bufferSize, &ui);
    767 
    768         if (ui > 255) {   /* because picoapi uses signed int16 */
    769             return (picodata_step_result_t)PICO_STEP_ERROR;
    770         } else {
    771             *bytesReceived = ui;
    772         }
    773         if ((rv == PICO_EXC_BUF_UNDERFLOW) || (rv == PICO_EXC_BUF_OVERFLOW)) {
    774             PICODBG_ERROR(("problem getting speech data"));
    775             return (picodata_step_result_t)PICO_STEP_ERROR;
    776         }
    777         /* rv must now be PICO_OK or PICO_EOF */
    778         PICODBG_ASSERT(((PICO_EOF == rv) || (PICO_OK == rv)));
    779         if ((PICODATA_PU_IDLE == stepResult) && (PICO_EOF == rv)) {
    780             PICODBG_DEBUG(("IDLE"));
    781             return (picodata_step_result_t)PICO_STEP_IDLE;
    782         } else if (PICODATA_PU_ERROR == stepResult) {
    783             PICODBG_DEBUG(("ERROR"));
    784             return (picodata_step_result_t)PICO_STEP_ERROR;
    785         } else {
    786             PICODBG_DEBUG(("BUSY"));
    787             return (picodata_step_result_t)PICO_STEP_BUSY;
    788         }
    789     } else {
    790         return (picodata_step_result_t)PICO_STEP_ERROR;
    791     }
    792 }/*picoctrl_engFetchOutputItemBytes*/
    793 
    794 /**
    795  * returns the last scheduled PU
    796  * @param    this : handle of the engine
    797  * @return    a value >= 0 : last scheduled PU index
    798  * @remarks    designed to be used for performance evaluation
    799  * @callgraph
    800  * @callergraph
    801  */
    802 picodata_step_result_t picoctrl_getLastScheduledPU(
    803         picoctrl_Engine this
    804         )
    805 {
    806     ctrl_subobj_t * ctrl;
    807     if (NULL == this || NULL == this->control->subObj) {
    808         return PICO_ERR_OTHER;
    809     }
    810     ctrl = (ctrl_subobj_t *) ((*this).control->subObj);
    811     return (picodata_step_result_t) ctrl->curPU;
    812 }/*picoctrl_getLastScheduledPU*/
    813 
    814 /**
    815  * returns the last item type produced by the last scheduled PU
    816  * @param    this : handle of the engine
    817  * @return    a value >= 0 : item type (see picodata.h for item types)
    818  * @return    a value = 0 : no item produced
    819  * @remarks    designed to be used for performance evaluation
    820  * @callgraph
    821  * @callergraph
    822  */
    823 picodata_step_result_t picoctrl_getLastProducedItemType(
    824         picoctrl_Engine this
    825         )
    826 {
    827     ctrl_subobj_t * ctrl;
    828     if (NULL == this || NULL == this->control->subObj) {
    829         return PICO_ERR_OTHER;
    830     }
    831     ctrl = (ctrl_subobj_t *) ((*this).control->subObj);
    832     return (picodata_step_result_t) ctrl->lastItemTypeProduced;
    833 }/*picoctrl_getLastProducedItemType*/
    834 
    835 
    836 #ifdef __cplusplus
    837 }
    838 #endif
    839 
    840 /* Picoctrl.c end */
    841