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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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