840 lines
28 KiB
C
840 lines
28 KiB
C
/*
|
|
* 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 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_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) (uintptr_t) (eng)) ^ MAGIC_MASK
|
|
|
|
#define CHECK_MAGIC_NUMBER(eng) \
|
|
((eng)->magic == (((picoos_uint32) (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 */
|