/* * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland * Modifications (C) 2019 Paolo Jovon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file picoctrl.c * * Control PU -- Implementation * * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland * All rights reserved. * * History: * - 2009-04-20 -- initial version * - 2019-08-28 -- x86_64 compatibility fixes * */ #include "picodefs.h" #include "picoos.h" #include "picodbg.h" #include "picodata.h" #include "picorsrc.h" /* processing unit definitions */ #include "picotok.h" #include "picopr.h" #include "picowa.h" #include "picosa.h" #include "picoacph.h" #include "picospho.h" #include "picopam.h" #include "picocep.h" #include "picosig.h" #if defined(PICO_DEVEL_MODE) #include "../history/picosink.h" #endif #include "picoctrl.h" #ifdef __cplusplus extern "C" { #endif #if 0 } #endif /** * @addtogroup picoctrl * @b Control * The "control" is a processing unit (PU) that contains and governs a sequence of sub-PUs * (TTS processing chain). * At each step (ctrlStep) it passes control to one of the sub-PUs (currrent PU). It may re-assign * the role of "current PU" to another sub-PU, according to the status information returned from each PU. */ /*---------------------------------------------------------- * object : Control * shortcut : ctrl * derived from : picodata_ProcessingUnit * implements a ProcessingUnit by creating and controlling * a sequence of Processing Units (of possibly different * implementations) exchanging data via CharBuffers * ---------------------------------------------------------*/ /* control sub-object */ typedef struct ctrl_subobj { picoos_uint8 numProcUnits; picoos_uint8 curPU; picoos_uint8 lastItemTypeProduced; picodata_ProcessingUnit procUnit [PICOCTRL_MAX_PROC_UNITS]; picodata_step_result_t procStatus [PICOCTRL_MAX_PROC_UNITS]; picodata_CharBuffer procCbOut [PICOCTRL_MAX_PROC_UNITS]; } ctrl_subobj_t; /** * performs Control PU initialization * @param this : pointer to Control PU * @return PICO_OK : processing done * @return PICO_ERR_OTHER : init error * @callgraph * @callergraph */ static pico_status_t ctrlInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) { register ctrl_subobj_t * ctrl; pico_status_t status= PICO_OK; picoos_int8 i; if (NULL == this || NULL == this->subObj) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) this->subObj; ctrl->curPU = 0; ctrl->lastItemTypeProduced=0; /*no item produced by default*/ status = PICO_OK; for (i = 0; i < ctrl->numProcUnits; i++) { if (PICO_OK == status) { status = ctrl->procUnit[i]->initialize(ctrl->procUnit[i], resetMode); PICODBG_DEBUG(("(re-)initializing procUnit[%i] returned status %i",i, status)); } if (PICO_OK == status) { status = picodata_cbReset(ctrl->procCbOut[i]); PICODBG_DEBUG(("(re-)initializing procCbOut[%i] returned status %i",i, status)); } } if (PICO_OK != status) { picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*)"problem (re-)initializing the engine"); } return status; }/*ctrlInitialize*/ /** * performs one processing step * @param this : pointer to Control PU * @param mode : activation mode (unused) * @param bytesOutput : number of bytes produced during this step (output) * @return PICO_OK : processing done * @return PICO_EXC_OUT_OF_MEM : no more memory available * @return PICO_ERR_OTHER : other error * @callgraph * @callergraph */ static picodata_step_result_t ctrlStep(register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * bytesOutput) { /* rules/invariants: * - all pu's above current have status idle except possibly pu+1, which may be busy. * (The latter is set if any pu->step produced output) * - a pu returns idle iff its cbIn is empty and it has no more data ready for output */ register ctrl_subobj_t * ctrl = (ctrl_subobj_t *) this->subObj; picodata_step_result_t status; picoos_uint16 puBytesOutput; #if defined(PICO_DEVEL_MODE) picoos_uint8 btype; #endif *bytesOutput = 0; ctrl->lastItemTypeProduced=0; /*no item produced by default*/ /* --------------------- */ /* do step of current pu */ /* --------------------- */ status = ctrl->procStatus[ctrl->curPU] = ctrl->procUnit[ctrl->curPU]->step( ctrl->procUnit[ctrl->curPU], mode, &puBytesOutput); if (puBytesOutput) { #if defined(PICO_DEVEL_MODE) /*store the type of item produced*/ btype = picodata_cbGetFrontItemType(ctrl->procUnit[ctrl->curPU]->cbOut); ctrl->lastItemTypeProduced=(picoos_uint8)btype; #endif if (ctrl->curPU < ctrl->numProcUnits-1) { /* data was output to internal PU buffers : set following pu to busy */ ctrl->procStatus[ctrl->curPU + 1] = PICODATA_PU_BUSY; } else { /* data was output to caller output buffer */ *bytesOutput = puBytesOutput; } } /* recalculate state depending on pu status returned from curPU */ switch (status) { case PICODATA_PU_ATOMIC: PICODBG_DEBUG(("got PICODATA_PU_ATOMIC")); return status; break; case PICODATA_PU_BUSY: PICODBG_DEBUG(("got PICODATA_PU_BUSY")); if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY == ctrl->procStatus[ctrl->curPU+1])) { ctrl->curPU++; } return status; break; case PICODATA_PU_IDLE: PICODBG_DEBUG(("got PICODATA_PU_IDLE")); if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY == ctrl->procStatus[ctrl->curPU+1])) { /* still data to process below */ ctrl->curPU++; } else if (0 == ctrl->curPU) { /* all pu's are idle */ /* nothing to do */ } else { /* find non-idle pu above */ PICODBG_DEBUG(( "find non-idle pu above from pu %d with status %d", ctrl->curPU, ctrl->procStatus[ctrl->curPU])); while ((ctrl->curPU > 0) && (PICODATA_PU_IDLE == ctrl->procStatus[ctrl->curPU])) { ctrl->curPU--; } ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY; } PICODBG_DEBUG(("going to pu %d with status %d", ctrl->curPU, ctrl->procStatus[ctrl->curPU])); /*update last scheduled PU*/ return ctrl->procStatus[ctrl->curPU]; break; case PICODATA_PU_OUT_FULL: PICODBG_DEBUG(("got PICODATA_PU_OUT_FULL")); if (ctrl->curPU+1 < ctrl->numProcUnits) { /* let pu below empty buffer */ ctrl->curPU++; ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY; } else { /* nothing more to do, out_full will be returned to caller */ } return ctrl->procStatus[ctrl->curPU]; break; default: return PICODATA_PU_ERROR; break; } }/*ctrlStep*/ /** * terminates Control PU * @param this : pointer to Control PU * @return PICO_OK : processing done * @return PICO_ERR_OTHER : other error * @callgraph * @callergraph */ static pico_status_t ctrlTerminate(register picodata_ProcessingUnit this) { pico_status_t status = PICO_OK; picoos_int16 i; register ctrl_subobj_t * ctrl; if (NULL == this || NULL == this->subObj) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) this->subObj; for (i = 0; i < ctrl->numProcUnits; i++) { status = ctrl->procUnit[i]->terminate(ctrl->procUnit[i]); PICODBG_DEBUG(("terminating procUnit[%i] returned status %i",i, status)); if (PICO_OK != status) { return status; } } return status; }/*ctrlTerminate*/ /** * deallocates Control PU's subobject * @param this : pointer to Control PU * @return PICO_OK : processing done * @return PICO_ERR_OTHER : other error * @callgraph * @callergraph */ static pico_status_t ctrlSubObjDeallocate(register picodata_ProcessingUnit this, picoos_MemoryManager mm) { register ctrl_subobj_t * ctrl; picoos_int16 i; if (NULL == this || NULL == this->subObj) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) this->subObj; mm = mm; /* fix warning "var not used in this function"*/ /* deallocate members (procCbOut and procUnit) */ for (i = ctrl->numProcUnits-1; i >= 0; i--) { picodata_disposeProcessingUnit(this->common->mm,&ctrl->procUnit[i]); picodata_disposeCharBuffer(this->common->mm, &ctrl->procCbOut[i]); } /* deallocate object itself */ picoos_deallocate(this->common->mm, (void *) &this->subObj); return PICO_OK; }/*ctrlSubObjDeallocate*/ /** * inserts a new PU in the TTS processing chain * @param this : pointer to Control PU * @param puType : type of the PU to be inserted * @param last : if true, inserted PU is the last in the TTS processing chain * @return PICO_OK : processing done * @return PICO_EXC_OUT_OF_MEM : no more memory available * @return PICO_ERR_OTHER : other error * @remarks Calls the PU object creation method * @callgraph * @callergraph */ static pico_status_t ctrlAddPU(register picodata_ProcessingUnit this, picodata_putype_t puType, picoos_bool levelAwareCbOut, picoos_bool last) { picoos_uint16 bufSize; register ctrl_subobj_t * ctrl; picodata_CharBuffer cbIn; picoos_uint8 newPU; if (this == NULL) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) this->subObj; if (ctrl == NULL) { return PICO_ERR_OTHER; } newPU = ctrl->numProcUnits; if (0 == newPU) { PICODBG_DEBUG(("taking cbIn of this because adding first pu")); cbIn = this->cbIn; } else { PICODBG_DEBUG(("taking cbIn of previous pu")); cbIn = ctrl->procCbOut[newPU-1]; } if (last) { PICODBG_DEBUG(("taking cbOut of this because adding last pu")); ctrl->procCbOut[newPU] = this->cbOut; } else { PICODBG_DEBUG(("creating intermediate cbOut of pu[%i]", newPU)); bufSize = picodata_get_default_buf_size(puType); ctrl->procCbOut[newPU] = picodata_newCharBuffer(this->common->mm, this->common,bufSize); PICODBG_DEBUG(("intermediate cbOut of pu[%i] (address %i)", newPU, (picoos_uint32) ctrl->procCbOut[newPU])); if (NULL == ctrl->procCbOut[newPU]) { return PICO_EXC_OUT_OF_MEM; } } ctrl->procStatus[newPU] = PICODATA_PU_IDLE; /*...............*/ switch (puType) { case PICODATA_PUTYPE_TOK: PICODBG_DEBUG(("creating TokenizeUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picotok_newTokenizeUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_PR: PICODBG_DEBUG(("creating PreprocUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picopr_newPreprocUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_WA: PICODBG_DEBUG(("creating WordAnaUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picowa_newWordAnaUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_SA: PICODBG_DEBUG(("creating SentAnaUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picosa_newSentAnaUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_ACPH: PICODBG_DEBUG(("creating AccPhrUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picoacph_newAccPhrUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_SPHO: PICODBG_DEBUG(("creating SentPhoUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picospho_newSentPhoUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_PAM: PICODBG_DEBUG(("creating PAMUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picopam_newPamUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; case PICODATA_PUTYPE_CEP: PICODBG_DEBUG(("creating CepUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picocep_newCepUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; #if defined(PICO_DEVEL_MODE) case PICODATA_PUTYPE_SINK: PICODBG_DEBUG(("creating SigUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picosink_newSinkUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; #endif case PICODATA_PUTYPE_SIG: PICODBG_DEBUG(("creating SigUnit for pu %i", newPU)); ctrl->procUnit[newPU] = picosig_newSigUnit(this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; default: ctrl->procUnit[newPU] = picodata_newProcessingUnit( this->common->mm, this->common, cbIn, ctrl->procCbOut[newPU], this->voice); break; } if (NULL == ctrl->procUnit[newPU]) { picodata_disposeCharBuffer(this->common->mm,&ctrl->procCbOut[newPU]); return PICO_EXC_OUT_OF_MEM; } ctrl->numProcUnits++; return PICO_OK; }/*ctrlAddPU*/ /*forward declaration : see below for full function body*/ void picoctrl_disposeControl(picoos_MemoryManager mm, picodata_ProcessingUnit * this); /** * initializes a control PU object * @param mm : memory manager * @param common : the common object * @param cbIn : the input char buffer * @param cbOut : the output char buffer * @param voice : the voice object * @return the pointer to the PU object created if OK * @return PICO_EXC_OUT_OF_MEM : no more memory available * @return NULL otherwise * @callgraph * @callergraph */ picodata_ProcessingUnit picoctrl_newControl(picoos_MemoryManager mm, picoos_Common common, picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, picorsrc_Voice voice) { picoos_int16 i; register ctrl_subobj_t * ctrl; picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, cbOut,voice); if (this == NULL) { return NULL; } this->initialize = ctrlInitialize; this->step = ctrlStep; this->terminate = ctrlTerminate; this->subDeallocate = ctrlSubObjDeallocate; this->subObj = picoos_allocate(mm, sizeof(ctrl_subobj_t)); if (this->subObj == NULL) { picoos_deallocate(mm, (void **)(void*)&this); return NULL; } ctrl = (ctrl_subobj_t *) this->subObj; for (i=0; i < PICOCTRL_MAX_PROC_UNITS; i++) { ctrl->procUnit[i] = NULL; ctrl->procStatus[i] = PICODATA_PU_IDLE; ctrl->procCbOut[i] = NULL; } ctrl->numProcUnits = 0; if ( (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_TOK, FALSE, /*last*/FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PR, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_WA, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SA, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_ACPH, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SPHO, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PAM, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_CEP, FALSE, FALSE)) && (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SIG, FALSE, TRUE)) ) { /* we don't call ctrlInitialize here because ctrlAddPU does initialize the PUs allready and the only thing * remaining to initialize is: */ ctrl->curPU = 0; return this; } else { picoctrl_disposeControl(this->common->mm,&this); return NULL; } }/*picoctrl_newControl*/ /** * disposes a Control PU * @param mm : memory manager * @param this : pointer to Control PU * * @return void * @callgraph * @callergraph */ void picoctrl_disposeControl(picoos_MemoryManager mm, picodata_ProcessingUnit * this) { picodata_disposeProcessingUnit(mm, this); }/*picoctrl_disposeControl*/ /* ************************************************************************** * * Engine * ****************************************************************************/ /** object : Engine * shortcut : eng */ typedef struct picoctrl_engine { picoos_uintptr_t magic; /* magic number used to validate handles */ void *raw_mem; picoos_Common common; picorsrc_Voice voice; picodata_ProcessingUnit control; picodata_CharBuffer cbIn, cbOut; } picoctrl_engine_t; #define MAGIC_MASK 0x5069436F /* PiCo */ #define SET_MAGIC_NUMBER(eng) \ (eng)->magic = ((picoos_uintptr_t) (eng)) ^ MAGIC_MASK #define CHECK_MAGIC_NUMBER(eng) \ ((eng)->magic == (((picoos_uintptr_t) (eng)) ^ MAGIC_MASK)) /** * performs an engine reset * @param this : the engine object * @return PICO_OK : reset performed * @return otherwise error code * @callgraph * @callergraph */ pico_status_t picoctrl_engReset(picoctrl_Engine this, picoos_int32 resetMode) { pico_status_t status; if (NULL == this) { return PICO_ERR_NULLPTR_ACCESS; } picoos_emReset(this->common->em); status = this->control->terminate(this->control); if (PICO_OK == status) { status = this->control->initialize(this->control, resetMode); } if (PICO_OK == status) { status = picodata_cbReset(this->cbIn); } if (PICO_OK == status) { status = picodata_cbReset(this->cbOut); } if (PICO_OK != status) { picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*) "problem resetting engine"); } return status; } /** * checks an engine handle * @param this : the engine object * @return PICO_OK : reset performed * @return non-zero if 'this' is a valid engine handle * @return zero otherwise * @callgraph * @callergraph */ picoos_int16 picoctrl_isValidEngineHandle(picoctrl_Engine this) { return (this != NULL) && CHECK_MAGIC_NUMBER(this); }/*picoctrl_isValidEngineHandle*/ /** * creates a new engine object * @param mm : memory manager to be used for this engine * @param rm : resource manager to be used for this engine * @param voiceName : voice definition to be used for this engine * @return PICO_OK : reset performed * @return new engine handle * @return NULL otherwise * @callgraph * @callergraph */ picoctrl_Engine picoctrl_newEngine(picoos_MemoryManager mm, picorsrc_ResourceManager rm, const picoos_char * voiceName) { picoos_uint8 done= TRUE; picoos_uint16 bSize; picoos_MemoryManager engMM; picoos_ExceptionManager engEM; picoctrl_Engine this = (picoctrl_Engine) picoos_allocate(mm, sizeof(*this)); PICODBG_DEBUG(("creating engine for voice '%s'",voiceName)); done = (NULL != this); if (done) { this->magic = 0; this->common = NULL; this->voice = NULL; this->control = NULL; this->cbIn = NULL; this->cbOut = NULL; this->raw_mem = picoos_allocate(mm, PICOCTRL_DEFAULT_ENGINE_SIZE); if (NULL == this->raw_mem) { done = FALSE; } } if (done) { engMM = picoos_newMemoryManager(this->raw_mem, PICOCTRL_DEFAULT_ENGINE_SIZE, /*enableMemProt*/ FALSE); done = (NULL != engMM); } if (done) { this->common = picoos_newCommon(engMM); engEM = picoos_newExceptionManager(engMM); done = (NULL != this->common) && (NULL != engEM); } if (done) { this->common->mm = engMM; this->common->em = engEM; done = (PICO_OK == picorsrc_createVoice(rm,voiceName,&(this->voice))); } if (done) { bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_TEXT); this->cbIn = picodata_newCharBuffer(this->common->mm, this->common, bSize); bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_SIG); this->cbOut = picodata_newCharBuffer(this->common->mm, this->common, bSize); PICODBG_DEBUG(("cbOut has address %i", (picoos_uint32) this->cbOut)); this->control = picoctrl_newControl(this->common->mm, this->common, this->cbIn, this->cbOut, this->voice); done = (NULL != this->cbIn) && (NULL != this->cbOut) && (NULL != this->control); } if (done) { SET_MAGIC_NUMBER(this); } else { if (NULL != this) { if (NULL != this->voice) { picorsrc_releaseVoice(rm,&(this->voice)); } if(NULL != this->raw_mem) { picoos_deallocate(mm,&(this->raw_mem)); } picoos_deallocate(mm,(void *)&this); } } return this; }/*picoctrl_newEngine*/ /** * disposes an engine object * @param mm : memory manager associated to the engine * @param rm : resource manager associated to the engine * @param this : handle of the engine to dispose * @return PICO_OK : reset performed * @return void * @callgraph * @callergraph */ void picoctrl_disposeEngine(picoos_MemoryManager mm, picorsrc_ResourceManager rm, picoctrl_Engine * this) { if (NULL != (*this)) { if (NULL != (*this)->voice) { picorsrc_releaseVoice(rm,&((*this)->voice)); } if(NULL != (*this)->control) { picoctrl_disposeControl((*this)->common->mm,&((*this)->control)); } if(NULL != (*this)->raw_mem) { picoos_deallocate(mm,&((*this)->raw_mem)); } (*this)->magic ^= 0xFFFEFDFC; picoos_deallocate(mm,(void **)this); } }/*picoctrl_disposeEngine*/ /** * resets the exception manager of an engine * @param this : handle of the engine * @return void * @callgraph * @callergraph */ void picoctrl_engResetExceptionManager( picoctrl_Engine this ) { picoos_emReset(this->common->em); }/*picoctrl_engResetExceptionManager*/ /** * returns the engine common pointer * @param this : handle of the engine * @return PICO_OK : reset performed * @return the engine common pointer * @return NULL if error * @callgraph * @callergraph */ picoos_Common picoctrl_engGetCommon(picoctrl_Engine this) { if (NULL == this) { return NULL; } else { return this->common; } }/*picoctrl_engGetCommon*/ /** * feed raw 'text' into 'engine'. text may contain '\\0'. * @param this : handle of the engine * @param text : the input text * @param textSize : size of the input text * @param *bytesPut : the number of bytes effectively consumed from 'text'. * @return PICO_OK : feeding succeded * @return PICO_ERR_OTHER : if error * @callgraph * @callergraph */ pico_status_t picoctrl_engFeedText(picoctrl_Engine this, picoos_char * text, picoos_int16 textSize, picoos_int16 * bytesPut) { if (NULL == this) { return PICO_ERR_OTHER; } PICODBG_DEBUG(("get \"%.100s\"", text)); *bytesPut = 0; while ((*bytesPut < textSize) && (PICO_OK == picodata_cbPutCh(this->cbIn, text[*bytesPut]))) { (*bytesPut)++; } return PICO_OK; }/*picoctrl_engFeedText*/ /** * gets engine output bytes * @param this : handle of the engine * @param buffer : the destination buffer * @param bufferSize : max size of the destinatioon buffer * @param *bytesReceived : the number of bytes effectively returned * @return PICO_OK : feeding succeded * @return PICO_ERR_OTHER : if error * @callgraph * @callergraph */ picodata_step_result_t picoctrl_engFetchOutputItemBytes( picoctrl_Engine this, picoos_char *buffer, picoos_int16 bufferSize, picoos_int16 *bytesReceived) { picoos_uint16 ui; picodata_step_result_t stepResult; pico_status_t rv; if (NULL == this) { return (picodata_step_result_t)PICO_STEP_ERROR; } PICODBG_DEBUG(("doing one step")); stepResult = this->control->step(this->control,/* mode */0,&ui); if (PICODATA_PU_ERROR != stepResult) { PICODBG_TRACE(("filling output buffer")); rv = picodata_cbGetSpeechData(this->cbOut, (picoos_uint8 *)buffer, bufferSize, &ui); if (ui > 255) { /* because picoapi uses signed int16 */ return (picodata_step_result_t)PICO_STEP_ERROR; } else { *bytesReceived = ui; } if ((rv == PICO_EXC_BUF_UNDERFLOW) || (rv == PICO_EXC_BUF_OVERFLOW)) { PICODBG_ERROR(("problem getting speech data")); return (picodata_step_result_t)PICO_STEP_ERROR; } /* rv must now be PICO_OK or PICO_EOF */ PICODBG_ASSERT(((PICO_EOF == rv) || (PICO_OK == rv))); if ((PICODATA_PU_IDLE == stepResult) && (PICO_EOF == rv)) { PICODBG_DEBUG(("IDLE")); return (picodata_step_result_t)PICO_STEP_IDLE; } else if (PICODATA_PU_ERROR == stepResult) { PICODBG_DEBUG(("ERROR")); return (picodata_step_result_t)PICO_STEP_ERROR; } else { PICODBG_DEBUG(("BUSY")); return (picodata_step_result_t)PICO_STEP_BUSY; } } else { return (picodata_step_result_t)PICO_STEP_ERROR; } }/*picoctrl_engFetchOutputItemBytes*/ /** * returns the last scheduled PU * @param this : handle of the engine * @return a value >= 0 : last scheduled PU index * @remarks designed to be used for performance evaluation * @callgraph * @callergraph */ picodata_step_result_t picoctrl_getLastScheduledPU( picoctrl_Engine this ) { ctrl_subobj_t * ctrl; if (NULL == this || NULL == this->control->subObj) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) ((*this).control->subObj); return (picodata_step_result_t) ctrl->curPU; }/*picoctrl_getLastScheduledPU*/ /** * returns the last item type produced by the last scheduled PU * @param this : handle of the engine * @return a value >= 0 : item type (see picodata.h for item types) * @return a value = 0 : no item produced * @remarks designed to be used for performance evaluation * @callgraph * @callergraph */ picodata_step_result_t picoctrl_getLastProducedItemType( picoctrl_Engine this ) { ctrl_subobj_t * ctrl; if (NULL == this || NULL == this->control->subObj) { return PICO_ERR_OTHER; } ctrl = (ctrl_subobj_t *) ((*this).control->subObj); return (picodata_step_result_t) ctrl->lastItemTypeProduced; }/*picoctrl_getLastProducedItemType*/ #ifdef __cplusplus } #endif /* Picoctrl.c end */