191097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn/*
291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn *
491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * you may not use this file except in compliance with the License.
691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * You may obtain a copy of the License at
791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn *
891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn *     http://www.apache.org/licenses/LICENSE-2.0
991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn *
1091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * 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
52extern "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 */
76typedef 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 */
93static 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 */
133static 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 */
236static 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 */
262static 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 */
295static 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*/
404void 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 */
420picodata_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 */
484void 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 */
498typedef 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 */
524pico_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 */
558picoos_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 */
574picoctrl_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 */
663void 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 */
688void 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 */
704picoos_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 */
723pico_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 */
749picodata_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 */
802picodata_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 */
823picodata_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