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