| /* |
| * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @file 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 |
| * |
| */ |
| |
| #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 r_mode) { |
| 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], r_mode); |
| 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_uint32 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_uint32) (eng)) ^ MAGIC_MASK |
| |
| #define CHECK_MAGIC_NUMBER(eng) \ |
| ((eng)->magic == (((picoos_uint32) (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 r_mode) |
| { |
| 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, r_mode); |
| } |
| 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 */ |