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) (eng)) ^ MAGIC_MASK
512
513 #define CHECK_MAGIC_NUMBER(eng) \
514 ((eng)->magic == (((picoos_uint32) (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