blob: 50ee4e34ca748b185e5c8ce685cffc0ff189eedc [file] [log] [blame]
/*
* Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file picopam.c
*
* Phonetic to Acoustic Mapping PU - Implementation
*
* Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
* All rights reserved.
*
* History:
* - 2009-04-20 -- initial version
*
*/
#include "picodefs.h"
#include "picoos.h"
#include "picodbg.h"
#include "picodata.h"
#include "picopam.h"
#include "picokdt.h"
#include "picokpdf.h"
#include "picoktab.h"
#include "picokdbg.h"
#include "picodsp.h"
#ifdef __cplusplus
extern "C" {
#endif
#if 0
}
#endif
#define PICOPAM_IN_BUFF_SIZE PICODATA_BUFSIZE_PAM /*input buffer size for PAM */
#define PICOPAM_OUT_PAM_SIZE PICODATA_BUFSIZE_PAM /*output buffer size for PAM*/
#define PICOPAM_DT_NRLFZ 5 /* nr of lfz decision trees per phoneme */
#define PICOPAM_DT_NRMGC 5 /* nr of mgc decision trees per phoneme */
#define PICOPAM_NRSTPF 5 /* nr of states per phone */
#define PICOPAM_COLLECT 0
#define PICOPAM_SCHEDULE 1
#define PICOPAM_IMMEDIATE 2
#define PICOPAM_FORWARD 3
#define PICOPAM_FORWARD_FORCE_TERM 4
#define PICOPAM_PROCESS 5
#define PICOPAM_PLAY 6
#define PICOPAM_FEED 7
#define PICOPAM_CONTINUE 100
#define PICOPAM_GOTO_SCHEDULE 1
#define PICOPAM_FLUSH_RECEIVED 6
#define PICOPAM_GOTO_FEED 7
#define PICOPAM_PRE_SYLL_ENDED 10
#define PICOPAM_BREAK_ADD_SIZE 4 /*syllable feature vector increment dued to BREAK and SILENCE*/
#define PICOPAM_VECT_SIZE 64+PICOPAM_BREAK_ADD_SIZE /*syllable feature vector size (bytes)*/
#define PICOPAM_INVEC_SIZE 60 /*phone feature vector size */
#define PICOPAM_MAX_SYLL_PER_SENT 100 /*maximum number of syllables per sentece*/
#define PICOPAM_MAX_PH_PER_SENT 400 /*maximum number of phonemes per sentece*/
#define PICOPAM_MAX_ITEM_PER_SENT 255 /*maximum number of attached items per sentence*/
#define PICOPAM_MAX_ITEM_SIZE_PER_SENT 4096 /*maximum size of attached items per sentence*/
#define PICOPAM_READY 20 /*PAM could start backward processing*/
#define PICOPAM_MORE 21 /*PAM has still to collect */
#define PICOPAM_NA 22 /*PAM has not to deal with this item*/
#define PICOPAM_ERR 23 /*input item is not a valid item*/
/*sentence types:cfr pam_map_sentence_type*/
#define PICOPAM_DECLARATIVE 0
#define PICOPAM_INTERROGATIVE 1
#define PICOPAM_EXCLAMATIVE 2
#define PICOPAM_T 0
#define PICOPAM_P 1
#define PICOPAM_p 2
#define PICOPAM_Y 3
#if 1
#define PAM_PHR2_WITH_PR1 1 /*deal with PHR2 boundaries as with PHR1*/
#else
#define PAM_PHR2_WITH_PR3 1 /*deal with PHR2 boundaries as with PHR3*/
#endif
#define PICOPAM_DONT_CARE_VALUE 250 /*don't care value for tree printout */
#define PICOPAM_DONT_CARE_VAL 10 /*don't care value for tree feeding */
#define PICOPAM_PH_DONT_CARE_VAL 7 /*don't care value for tree feeding (phonetic)*/
#define PICOPAM_MAX_STATES_PER_PHONE 5 /*number of states per phone */
#define PICOPAM_STATE_SIZE_IN_ITEM 6 /*size of a state in frame item */
#define PICOPAM_FRAME_ITEM_SIZE 4+PICOPAM_MAX_STATES_PER_PHONE*PICOPAM_STATE_SIZE_IN_ITEM
#define PICOPAM_DIR_FORW 0 /*forward adapter processing*/
#define PICOPAM_DIR_BACK 1 /*backward adapter processing*/
#define PICOPAM_DIR_SIL 2 /*final silence attributes*/
#define PICOPAM_SYLL_PAUSE 0 /*syllable but containing a pause phone*/
#define PICOPAM_SYLL_SYLL 1 /*a real syllable with phonemes*/
#define PICOPAM_EVENT_P_BOUND 0 /*primary boundary*/
#define PICOPAM_EVENT_S_BOUND 1 /*secondary boundary*/
#define PICOPAM_EVENT_W_BOUND 3 /*word boundary*/
#define PICOPAM_EVENT_SYLL 4 /*syllable*/
/* ----- CONSTANTS FOR BREAK COMMAND SUPPORT ----- */
#define PICOPAM_PWIDX_SBEG 0
#define PICOPAM_PWIDX_PHR1 1
#define PICOPAM_PWIDX_PHR2 2
#define PICOPAM_PWIDX_SEND 3
#define PICOPAM_PWIDX_DEFA 4
#define PICOPAM_PWIDX_SIZE 5
/*----------------------------------------------------------------*/
/*structure related to the feature vectors for feeding the trees */
/*NOTE : the same data structure is used to manage the syllables */
/* Using the first 8 fields for marking the boundaries */
/* and using the last 4 bytes as follows */
/* byte 61 : 1st attached non PAM item id(0=no item attached) */
/* in the "sSyllItemOffs" data structure */
/* byte 62 : last attached non PAM item id(0=no item attached)*/
/* in the "sSyllItemOffs" data structure */
/* byte 63..64 : offset of the start of the syllable in */
/* the "sPhIds" data structure */
typedef struct
{
picopal_uint8 phoneV[PICOPAM_VECT_SIZE];
} sFtVect, *pSftVect;
/*----------------------------------------------------------
Name : pam_subobj
Function: subobject definition for the pam processing
Shortcut: pam
---------------------------------------------------------*/
typedef struct pam_subobj
{
/*----------------------PU voice management------------------------------*/
/* picorsrc_Voice voice; */
/*----------------------PU state management------------------------------*/
picoos_uint8 procState; /* where to take up work at next processing step */
picoos_uint8 retState; /* where to go back from feed state at next p.s. */
picoos_uint8 needMoreInput; /* more data necessary to start processing */
/*----------------------PU input management------------------------------*/
picoos_uint8 inBuf[PICOPAM_IN_BUFF_SIZE]; /* internal input buffer */
picoos_uint16 inBufSize; /* actually allocated size */
picoos_uint16 inReadPos, inWritePos; /* next pos to read/write from/to inBuf*/
/*----------------------PU output management-----------------------------*/
picoos_uint8 outBuf[PICOPAM_OUT_PAM_SIZE]; /* internal output buffer */
picoos_uint16 outBufSize; /* actually allocated size */
picoos_uint16 outReadPos, outWritePos; /* next pos to read/write from/to outBuf*/
/*---------------------- adapter working buffers --------------------*/
picoos_uint8 *sPhFeats; /*feature vector for a single phone */
sFtVect *sSyllFeats; /*Syllable feature vector set for the
full sentence */
picoos_uint8 *sPhIds; /*phone ids for the full sentence */
picoos_uint8 *sSyllItems; /*items attached to the syllable */
picoos_int16 *sSyllItemOffs;/*offset of items attached to the syllable*/
/*---------------------- adapter general variables ---------------------*/
picoos_int16 nTotalPhonemes; /*number of phonemes in the sentence*/
picoos_int16 nCurrPhoneme; /*current phoneme in the sentence */
picoos_int16 nSyllPhoneme; /*current phoneme in the syllable */
picoos_int16 nCurrSyllable; /*current syllable in the sentence */
picoos_int16 nTotalSyllables; /*number of syllables in the sentence -> J1*/
picoos_uint8 nLastAttachedItemId;/*last attached item id*/
picoos_uint8 nCurrAttachedItem; /*current attached item*/
picoos_int16 nAttachedItemsSize; /*total size of the attached items*/
picoos_uint8 sType; /*Sentence type*/
picoos_uint8 pType; /*Phrase type*/
picoos_single pMod; /*pitch modifier*/
picoos_single dMod; /*Duration modifier*/
picoos_single dRest; /*Duration modifier rest*/
/*---------------------- adapter specific component variables ----------*/
picoos_uint8 a3_overall_syllable; /* A3 */
picoos_uint8 a3_primary_phrase_syllable;
picoos_uint8 b4_b5_syllable; /* B4,B5 */
picoos_uint8 b6_b7_syllable; /* B6,B7 */
picoos_uint8 b6_b7_state;
picoos_uint8 b8_b9_stressed_syllable; /* B8,B9 */
picoos_uint8 b10_b11_accented_syllable; /* B10,B11 */
picoos_uint8 b12_b13_syllable; /* B12,B13 */
picoos_uint8 b12_b13_state;
picoos_uint8 b14_b15_syllable; /* B14,B15 */
picoos_uint8 b14_b15_state;
picoos_uint8 b17_b19_syllable; /* B17,B19 */
picoos_uint8 b17_b19_state;
picoos_uint8 b18_b20_b21_syllable; /* B18,B20,B21 */
picoos_uint8 b18_b20_b21_state;
picoos_uint8 c3_overall_syllable; /* C3 */
picoos_uint8 c3_primary_phrase_syllable;
picoos_uint8 d2_syllable_in_word; /* D2 */
picoos_uint8 d2_prev_syllable_in_word;
picoos_uint8 d2_current_primary_phrase_word;
picoos_int8 e1_syllable_word_start; /* E1 */
picoos_int8 e1_syllable_word_end;
picoos_uint8 e1_content;
picoos_int8 e2_syllable_word_start; /* E2 */
picoos_int8 e2_syllable_word_end;
picoos_uint8 e3_e4_word; /* E3,E4 */
picoos_uint8 e3_e4_state;
picoos_uint8 e5_e6_content_word; /* E5,E6 */
picoos_uint8 e5_e6_content;
picoos_uint8 e7_e8_word; /* E7,E8 */
picoos_uint8 e7_e8_content;
picoos_uint8 e7_e8_state;
picoos_uint8 e9_e11_word; /* E9,E11 */
picoos_uint8 e9_e11_saw_word;
picoos_uint8 e9_e11_state;
picoos_uint8 e10_e12_e13_word; /* E10,E12,E13 */
picoos_uint8 e10_e12_e13_state;
picoos_uint8 e10_e12_e13_saw_word;
picoos_uint8 f2_overall_word; /* F2 */
picoos_uint8 f2_word_syllable;
picoos_uint8 f2_next_word_syllable;
picoos_uint8 f2_current_primary_phrase_word;
picoos_int8 g1_current_secondary_phrase_syllable; /*G1 */
picoos_int8 g1_current_syllable;
picoos_int8 g2_current_secondary_phrase_word; /*G2 */
picoos_int8 g2_current_word;
picoos_uint8 h1_current_secondary_phrase_syll; /*H1 */
picoos_uint8 h2_current_secondary_phrase_word; /*H2 */
picoos_uint8 h3_h4_current_secondary_phrase_word; /*H3,H4 */
picoos_uint8 h5_current_phrase_type; /*H5 */
picoos_uint8 h5_syllable; /* H5 */
picoos_uint8 h5_state;
picoos_uint8 i1_secondary_phrase_syllable; /*I1 */
picoos_uint8 i1_next_secondary_phrase_syllable;
picoos_uint8 i2_secondary_phrase_word; /*I2 */
picoos_uint8 i2_next_secondary_phrase_word;
picoos_uint8 j1_utterance_syllable; /*J1 */
picoos_uint8 j2_utterance_word; /*J2 */
picoos_uint8 j3_utterance_sec_phrases; /*J3 */
/*---------------------- constant data -------------------*/
picoos_uint16 sil_weights[PICOPAM_PWIDX_SIZE][PICOPAM_MAX_STATES_PER_PHONE];
/*---------------------- LINGWARE related data -------------------*/
picokdt_DtPAM dtdur; /* dtdur knowledge base */
picokdt_DtPAM dtlfz[PICOPAM_DT_NRLFZ]; /* dtlfz knowledge bases */
picokdt_DtPAM dtmgc[PICOPAM_DT_NRMGC]; /* dtmgc knowledge bases */
/*---------------------- Pdfs related data -------------------*/
picokpdf_PdfDUR pdfdur; /* pdfdur knowledge base */
picokpdf_PdfMUL pdflfz; /* pdflfz knowledge base */
/*---------------------- Tree traversal related data -------------------*/
picoos_uint16 durIndex;
picoos_uint8 numFramesState[PICOPAM_DT_NRLFZ];
picoos_uint16 lf0Index[PICOPAM_DT_NRLFZ];
picoos_uint16 mgcIndex[PICOPAM_DT_NRMGC];
/*---------------------- temps for updating the feature vector ---------*/
picoos_uint16 phonDur;
picoos_single phonF0[PICOPAM_DT_NRLFZ];
/*---------------------- Phones related data -------------------*/
picoktab_Phones tabphones;
} pam_subobj_t;
/* ----- CONSTANTS FOR FEATURE VECTOR BUILDING (NOT PREFIXED WITH "PICOPAM_" FOR BREVITY) ----- */
#define P1 0 /*field 1 of the input vector*/
#define P2 1
#define P3 2
#define P4 3
#define P5 4
#define P6 5
#define P7 6
#define bnd 6 /*boundary type item associated to the syllable = P7 */
#define P8 7
#define A3 8
#define B1 9
#define B2 10
#define B3 11
#define B4 12
#define B5 13
#define B6 14
#define B7 15
#define B8 16
#define B9 17
#define B10 18
#define B11 19
#define B12 20
#define B13 21
#define B14 22
#define B15 23
#define B16 24
#define B17 25
#define B18 26
#define B19 27
#define B20 28
#define B21 29
#define C3 30
#define D2 31
#define E1 32
#define E2 33
#define E3 34
#define E4 35
#define E5 36
#define E6 37
#define E7 38
#define E8 39
#define E9 40
#define E10 41
#define E11 42
#define E12 43
#define E13 44
#define F2 45
#define G1 46
#define G2 47
#define H1 48
#define H2 49
#define H3 50
#define H4 51
#define H5 52
#define I1 53
#define I2 54
#define J1 55
#define J2 56
#define J3 57
#define DUR 58 /*duration component*/
#define F0 59 /*F0 component*/
#define ITM 60 /*Item Offset into sSyllItems item list*/
#define itm 61 /*second byte of the Item Offset */
#define FID 62 /*Phoneme offset in the sPhIds phoneme list*/
#define fid 63 /*second byte of the Phoneme offset */
#define Min 64 /*offset to min syllable duration (uint 16,pauses)*/
#define Max 66 /*offset to max syllable duration (uint 16,pauses)*/
/* -------------------------------------------------------------------
PAM feature vector indices position changes,
------------------------------------------------------------------- */
#define T_B1 8
#define T_B2 9
#define T_B3 10
#define T_B4 11
#define T_B5 12
#define T_B6 13
#define T_B7 14
#define T_B8 15
#define T_B9 16
#define T_B10 17
#define T_B11 18
#define T_B12 19
#define T_B13 20
#define T_B14 21
#define T_B15 22
#define T_B16 23
#define T_B17 24
#define T_B18 25
#define T_B19 26
#define T_B20 27
#define T_B21 28
#define T_E1 29
#define T_E2 30
#define T_E3 31
#define T_E4 32
#define T_E5 33
#define T_E6 34
#define T_E7 35
#define T_E8 36
#define T_E9 37
#define T_E10 38
#define T_E11 39
#define T_E12 40
#define T_E13 41
#define T_A3 42
#define T_C3 43
#define T_D2 44
#define T_F2 45
#define T_G1 46
#define T_I1 47
#define T_G2 48
#define T_I2 49
#define T_H1 50
#define T_H2 51
#define T_H3 52
#define T_H4 53
#define T_H5 54
/*------------------------------------------------------------------
Service routines :
------------------------------------------------------------------*/
static pico_status_t pam_initialize(register picodata_ProcessingUnit this, picoos_int32 resetMode);
static pico_status_t pam_terminate(register picodata_ProcessingUnit this);
static pico_status_t pam_allocate(picoos_MemoryManager mm, pam_subobj_t *pam);
static void pam_deallocate(picoos_MemoryManager mm, pam_subobj_t *pam);
static pico_status_t pam_subobj_deallocate(register picodata_ProcessingUnit this,
picoos_MemoryManager mm);
/*------------------------------------------------------------------
Processing routines :
------------------------------------------------------------------*/
static picodata_step_result_t pam_step(register picodata_ProcessingUnit this,
picoos_int16 mode, picoos_uint16 * numBytesOutput);
static pico_status_t pam_deal_with(const picoos_uint8 *item);
/*Utility*/
static picoos_uint8 pam_get_vowel_name(register picodata_ProcessingUnit this,
picoos_uint8 *item, picoos_uint8 *pos);
static picoos_uint8 pam_get_pause_id(register picodata_ProcessingUnit this);
static picoos_uint8 pam_map_sentence_type(picoos_uint8 iteminfo1,
picoos_uint8 iteminfo2);
static picoos_uint8 pam_map_phrase_type(picoos_uint8 iteminfo1,
picoos_uint8 iteminfo2);
/*Adapter*/
static pico_status_t pam_reset_processors(register picodata_ProcessingUnit this);
static pico_status_t pam_reset_processors_back(
register picodata_ProcessingUnit this);
static pico_status_t pam_create_syllable(register picodata_ProcessingUnit this,
picoos_uint8 syllType, picoos_uint8 *sContent, picoos_uint8 sentType,
picoos_uint8 phType, picoos_uint8 uBoundType, picoos_uint16 uMin,
picoos_uint16 uMax);
static pico_status_t pam_process_event_feature(
register picodata_ProcessingUnit this, picoos_uint8 nFeat,
picoos_uint8 event_type, picoos_uint8 direction);
static pico_status_t pam_process_event(register picodata_ProcessingUnit this,
picoos_uint8 event_type, picoos_uint8 direction);
static pico_status_t pam_adapter_forward_step(
register picodata_ProcessingUnit this, picoos_uint8 *itemBase);
static pico_status_t pam_adapter_backward_step(
register picodata_ProcessingUnit this);
static pico_status_t pam_do_pause(register picodata_ProcessingUnit this);
static pico_status_t pam_adapter_do_pauses(register picodata_ProcessingUnit this);
/*-------------- tree traversal ---------------------------------------*/
static pico_status_t pam_expand_vector(register picodata_ProcessingUnit this);
static picoos_uint8 pam_do_tree(register picodata_ProcessingUnit this,
const picokdt_DtPAM dtpam, const picoos_uint8 *invec,
const picoos_uint8 inveclen, picokdt_classify_result_t *dtres);
static pico_status_t pam_get_f0(register picodata_ProcessingUnit this,
picoos_uint16 *lf0Index, picoos_uint8 nState, picoos_single *phonF0);
static pico_status_t pam_get_duration(register picodata_ProcessingUnit this,
picoos_uint16 durIndex, picoos_uint16 *phonDur,
picoos_uint8 *numFramesState);
static pico_status_t pam_update_vector(register picodata_ProcessingUnit this);
/*-------------- FINAL ITEM FEEDING -----------------------------------------*/
static pico_status_t pam_put_item(register picodata_ProcessingUnit this,
picoos_uint8 *outBuff, picoos_uint16 outWritePos,
picoos_uint8 *bytesWr);
static pico_status_t pam_put_term(picoos_uint8 *outBuff,
picoos_uint16 outWritePos, picoos_uint8 *bytesWr);
static pico_status_t is_pam_command(const picoos_uint8 *qItem);
static void get_default_boundary_limit(picoos_uint8 uBoundType,
picoos_uint16 *uMinDur, picoos_uint16 *uMaxDur);
/* -------------------------------------------------------------
* Pico System functions
* -------------------------------------------------------------
*/
/**
* allocation for PAM memory on pam PU
* @param mm : handle to engine memory manager
* @param pam : handle to a pam struct
* @return PICO_OK : allocation successful
* @return PICO_ERR_OTHER : allocation errors
* @callgraph
* @callergraph
*/
static pico_status_t pam_allocate(picoos_MemoryManager mm, pam_subobj_t *pam)
{
picoos_uint8 *data;
picoos_int16 *dataI;
pam->sSyllFeats = NULL;
pam->sPhIds = NULL;
pam->sPhFeats = NULL;
pam->sSyllItems = NULL;
pam->sSyllItemOffs = NULL;
/*-----------------------------------------------------------------
* PAM Local buffers ALLOCATION
------------------------------------------------------------------*/
/*PAM Local buffers*/
data = (picopal_uint8 *) picoos_allocate(mm, sizeof(sFtVect)
* PICOPAM_MAX_SYLL_PER_SENT);
if (data == NULL)
return PICO_ERR_OTHER;
pam->sSyllFeats = (sFtVect*) data;
data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8)
* PICOPAM_MAX_PH_PER_SENT);
if (data == NULL) {
pam_deallocate(mm, pam);
return PICO_ERR_OTHER;
}
pam->sPhIds = (picopal_uint8*) data;
data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8)
* PICOPAM_VECT_SIZE);
if (data == NULL) {
pam_deallocate(mm, pam);
return PICO_ERR_OTHER;
}
pam->sPhFeats = (picopal_uint8*) data;
data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8)
* PICOPAM_MAX_ITEM_SIZE_PER_SENT);
if (data == NULL) {
pam_deallocate(mm, pam);
return PICO_ERR_OTHER;
}
pam->sSyllItems = (picopal_uint8*) data;
dataI = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16)
* PICOPAM_MAX_ITEM_PER_SENT);
if (data == NULL) {
pam_deallocate(mm, pam);
return PICO_ERR_OTHER;
}
pam->sSyllItemOffs = (picoos_int16*) dataI;
return PICO_OK;
}/*pam_allocate*/
/**
* frees allocation for DSP memory on PAM PU
* @param mm : memory manager
* @param pam : pam PU internal sub-object
* @return void
* @remarks modified and inserted in sub obj removal PP 15.09.08
* @callgraph
* @callergraph
*/
static void pam_deallocate(picoos_MemoryManager mm, pam_subobj_t *pam)
{
/*-----------------------------------------------------------------
* Memory de-allocations
* ------------------------------------------------------------------*/
if (pam->sSyllFeats != NULL)
picoos_deallocate(mm, (void *) &pam->sSyllFeats);
if (pam->sPhIds != NULL)
picoos_deallocate(mm, (void *) &pam->sPhIds);
if (pam->sPhFeats != NULL)
picoos_deallocate(mm, (void *) &pam->sPhFeats);
if (pam->sSyllItems != NULL)
picoos_deallocate(mm, (void *) &pam->sSyllItems);
if (pam->sSyllItemOffs != NULL)
picoos_deallocate(mm, (void *) &pam->sSyllItemOffs);
}/*pam_deallocate*/
/**
* initialization of a pam PU
* @param this : handle to a PU struct
* @return PICO_OK : init OK
* @return PICO_ERR_OTHER : error on getting pkbs addresses
* @callgraph
* @callergraph
*/
static pico_status_t pam_initialize(register picodata_ProcessingUnit this, picoos_int32 resetMode)
{
pico_status_t nI, nJ;
pam_subobj_t *pam;
if (NULL == this || NULL == this->subObj) {
return PICO_ERR_OTHER;
}
pam = (pam_subobj_t *) this->subObj;
pam->inBufSize = PICOPAM_IN_BUFF_SIZE;
pam->outBufSize = PICOPAM_OUT_PAM_SIZE;
pam->inReadPos = 0;
pam->inWritePos = 0;
pam->outReadPos = 0;
pam->outWritePos = 0;
pam->needMoreInput = 0;
pam->procState = 0;
/*-----------------------------------------------------------------
* MANAGE INTERNAL INITIALIZATION
------------------------------------------------------------------*/
/*init the syllable structure*/
for (nI = 0; nI < PICOPAM_MAX_SYLL_PER_SENT; nI++)
for (nJ = 0; nJ < PICOPAM_VECT_SIZE; nJ++)
pam->sSyllFeats[nI].phoneV[nJ] = 0;
for (nI = 0; nI < PICOPAM_MAX_PH_PER_SENT; nI++)
pam->sPhIds[nI] = 0;
for (nI = 0; nI < PICOPAM_VECT_SIZE; nI++)
pam->sPhFeats[nI] = 0;
for (nI = 0; nI < PICOPAM_MAX_ITEM_SIZE_PER_SENT; nI++)
pam->sSyllItems[nI] = 0;
for (nI = 0; nI < PICOPAM_MAX_ITEM_PER_SENT; nI++)
pam->sSyllItemOffs[nI] = 0;
/*Other variables*/
pam_reset_processors(this);
pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0;
pam->nAttachedItemsSize = 0;
if (resetMode == PICO_RESET_SOFT) {
/*following initializations needed only at startup or after a full reset*/
return PICO_OK;
}
/*pitch and duration modifiers*/
pam->pMod = 1.0f;
pam->dMod = 1.0f;
pam->dRest = 0.0f;
/* constant tables */
{
picoos_uint8 i, j;
picoos_uint16 tmp_weights[PICOPAM_PWIDX_SIZE][PICOPAM_MAX_STATES_PER_PHONE] = {
{10, 10, 10, 10, 1 }, /*SBEG*/
{ 1, 4, 8, 4, 1 }, /*PHR1*/
{ 1, 4, 8, 4, 1 }, /*PHR2*/
{ 1, 10, 10, 10, 10 },/*SEND*/
{ 1, 1, 1, 1, 1 } /*DEFAULT*/
};
for (i = 0; i < PICOPAM_PWIDX_SIZE; i++) {
for (j = 0; j < PICOPAM_PWIDX_SIZE; j++) {
pam->sil_weights[j][j] = tmp_weights[i][j];
}
}
}
/*-----------------------------------------------------------------
* MANAGE LINGWARE INITIALIZATION IF NEEDED
------------------------------------------------------------------*/
/* kb dtdur */
pam->dtdur = picokdt_getDtPAM(this->voice->kbArray[PICOKNOW_KBID_DT_DUR]);
if (pam->dtdur == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL,
NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got dtdur"));
/* kb dtlfz* */
pam->dtlfz[0] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_LFZ1]);
pam->dtlfz[1] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_LFZ2]);
pam->dtlfz[2] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_LFZ3]);
pam->dtlfz[3] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_LFZ4]);
pam->dtlfz[4] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_LFZ5]);
for (nI = 0; nI < PICOPAM_DT_NRLFZ; nI++) {
if (pam->dtlfz[nI] == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING,
NULL, NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got dtlfz%d", nI+1));
}
/* kb dtmgc* */
pam->dtmgc[0] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_MGC1]);
pam->dtmgc[1] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_MGC2]);
pam->dtmgc[2] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_MGC3]);
pam->dtmgc[3] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_MGC4]);
pam->dtmgc[4] = picokdt_getDtPAM(
this->voice->kbArray[PICOKNOW_KBID_DT_MGC5]);
for (nI = 0; nI < PICOPAM_DT_NRMGC; nI++) {
if (pam->dtmgc[nI] == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING,
NULL, NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got dtmgc%d", nI+1));
}
/* kb pdfdur* */
pam->pdfdur = picokpdf_getPdfDUR(
this->voice->kbArray[PICOKNOW_KBID_PDF_DUR]);
if (pam->pdfdur == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL,
NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got pdfdur"));
/* kb pdflfz* */
pam->pdflfz = picokpdf_getPdfMUL(
this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]);
if (pam->pdflfz == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL,
NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got pdflfz"));
/* kb tabphones */
pam->tabphones = picoktab_getPhones(
this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]);
if (pam->tabphones == NULL) {
picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL,
NULL);
return PICO_ERR_OTHER;
}PICODBG_DEBUG(("got tabphones"));
return PICO_OK;
}/*pam_initialize*/
/**
* termination of a pam PU
* @param this : handle to a pam PU struct
* @return PICO_OK
* @callgraph
* @callergraph
*/
static pico_status_t pam_terminate(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
if (NULL == this || NULL == this->subObj) {
return PICO_ERR_OTHER;
}
pam = (pam_subobj_t *) this->subObj;
return PICO_OK;
}/*pam_terminate*/
/**
* deallocaton of a pam PU
* @param this : handle to a pam PU struct
* @param mm : engine memory manager
* @return PICO_OK
* @callgraph
* @callergraph
*/
static pico_status_t pam_subobj_deallocate(register picodata_ProcessingUnit this,
picoos_MemoryManager mm)
{
pam_subobj_t* pam;
if (NULL != this) {
pam = (pam_subobj_t *) this->subObj;
mm = mm; /* avoid warning "var not used in this function"*/
/*-----------------------------------------------------------------
* Memory de-allocations
* ------------------------------------------------------------------*/
if (pam->sSyllFeats != NULL) {
picoos_deallocate(this->common->mm, (void *) &pam->sSyllFeats);
}
if (pam->sPhIds != NULL) {
picoos_deallocate(this->common->mm, (void *) &pam->sPhIds);
}
if (pam->sPhFeats != NULL) {
picoos_deallocate(this->common->mm, (void *) &pam->sPhFeats);
}
if (pam->sSyllItems != NULL) {
picoos_deallocate(this->common->mm, (void *) &pam->sSyllItems);
}
if (pam->sSyllItemOffs != NULL) {
picoos_deallocate(this->common->mm, (void *) &pam->sSyllItemOffs);
}
picoos_deallocate(this->common->mm, (void *) &this->subObj);
}
return PICO_OK;
}/*pam_subobj_deallocate*/
/**
* creates a new pam processing unit
* @param mm : engine memory manager
* @param common : engine common object pointer
* @param cbIn : pointer to input buffer
* @param cbOut : pointer to output buffer
* @param voice : pointer to voice structure
* @return this : pam PU handle if success
* @return NULL : if error
* @callgraph
* @callergraph
*/
picodata_ProcessingUnit picopam_newPamUnit(picoos_MemoryManager mm,
picoos_Common common, picodata_CharBuffer cbIn,
picodata_CharBuffer cbOut, picorsrc_Voice voice)
{
register pam_subobj_t * pam;
picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn,
cbOut, voice);
if (this == NULL) {
return NULL;
}
this->initialize = pam_initialize;
PICODBG_DEBUG(("picotok_newPamUnit -- set this->step to pam_step"));
this->step = pam_step;
this->terminate = pam_terminate;
this->subDeallocate = pam_subobj_deallocate;
this->subObj = picoos_allocate(mm, sizeof(pam_subobj_t));
if (this->subObj == NULL) {
PICODBG_ERROR(("Error in Pam Object allocation"));
picoos_deallocate(mm, (void*) &this);
return NULL;
};
/*-----------------------------------------------------------------
* Allocate internal memory for PAM (only at PU creation time)
* ------------------------------------------------------------------*/
pam = (pam_subobj_t *) this->subObj;
if (PICO_OK != pam_allocate(mm, pam)) {
PICODBG_ERROR(("Error in Pam buffers Allocation"));
picoos_deallocate(mm, (void *) &this->subObj);
picoos_deallocate(mm, (void *) &this);
return NULL;
}
/*-----------------------------------------------------------------
* Initialize memory for PAM (this may be re-used elsewhere, e.g.Reset)
* ------------------------------------------------------------------*/
if (PICO_OK != pam_initialize(this, PICO_RESET_FULL)) {
PICODBG_ERROR(("problem initializing the pam sub-object"));
}
return this;
}/*picopam_newPamUnit*/
/*-------------------------------------------------------------------------------
PROCESSING AND INTERNAL FUNCTIONS
--------------------------------------------------------------------------------*/
/**
* initializes default duration limits for boundary items
* @param uBoundType : type of input boundary type
* @param *uMinDur, *uMaxDur : addresses of values to initialize
* @return void
* @remarks so far initializes to 0 both values; this will leave the values given by tree prediction
* @callgraph
* @callergraph
*/
static void get_default_boundary_limit(picoos_uint8 uBoundType,
picoos_uint16 *uMinDur, picoos_uint16 *uMaxDur)
{
switch (uBoundType) {
case PICODATA_ITEMINFO1_BOUND_SBEG:
*uMinDur = 0;
*uMaxDur = 20;
break;
case PICODATA_ITEMINFO1_BOUND_SEND:
*uMinDur = 550;
*uMaxDur = 650;
break;
case PICODATA_ITEMINFO1_BOUND_TERM:
*uMinDur = 0;
*uMaxDur = 0;
break;
case PICODATA_ITEMINFO1_BOUND_PHR0:
*uMinDur = 0;
*uMaxDur = 0;
break;
case PICODATA_ITEMINFO1_BOUND_PHR1:
*uMinDur = 275;
*uMaxDur = 325;
break;
case PICODATA_ITEMINFO1_BOUND_PHR2:
*uMinDur = 4;
*uMaxDur = 60;
break;
case PICODATA_ITEMINFO1_BOUND_PHR3:
*uMinDur = 0;
*uMaxDur = 0;
break;
default:
break;
}
}/*get_default_boundary_limit*/
/**
* checks if "neededSize" is available on "nCurrPhoneme"
* @param pam : pam subobj
* @param neededSize : the requested size
* @return PICO_OK : size is available
* @return !=PICO_OK : size not available
* @callgraph
* @callergraph
*/
static pico_status_t check_phones_size(pam_subobj_t *pam,
picoos_int16 neededSize)
{
if ((pam->nCurrPhoneme + neededSize) > PICOPAM_MAX_PH_PER_SENT - 1) {
return PICO_ERR_OTHER;
}
return PICO_OK;
}/*check_phones_size*/
/**
* checks if neededSize is available on "nCurrSyllable"
* @param pam : pam subobj
* @param neededSize : the requested size
* @return PICO_OK : size is available
* @return !=PICO_OK : size not available
* @callgraph
* @callergraph
*/
static pico_status_t check_syllables_size(pam_subobj_t *pam,
picoos_int16 neededSize)
{
if ((pam->nCurrSyllable + neededSize) > PICOPAM_MAX_SYLL_PER_SENT - 1) {
return PICO_ERR_OTHER;
}
return PICO_OK;
}/*check_syllables_size*/
/**
* verifies that local storage has enough space to receive 1 item
* @param this : pointer to current PU struct
* @param item : pointer to current item head
* @return TRUE : resource limits would be reached during processing of input item
* @return FALSE : item could be processed normally
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static pico_status_t pamCheckResourceLimits(
register picodata_ProcessingUnit this, const picoos_uint8 *item)
{
register pam_subobj_t * pam;
picodata_itemhead_t head;
pico_status_t sResult;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
sResult = TRUE; /*default : resource limits reached*/
head.type = item[0];
head.info1 = item[1];
head.info2 = item[2];
head.len = item[3];
switch (head.type) {
/*commands that generate syllables/phonemes*/
case PICODATA_ITEM_SYLLPHON:
if (pam->nCurrSyllable >= PICOPAM_MAX_SYLL_PER_SENT - 2) {
return sResult; /*no room for more syllables*/
}
if ((pam->nCurrPhoneme + head.len) >= PICOPAM_MAX_PH_PER_SENT - 2) {
return sResult; /*no room for more phoneme*/
}
break;
case PICODATA_ITEM_BOUND:
if ((head.info1 == PICODATA_ITEMINFO1_BOUND_SBEG) || (head.info1
== PICODATA_ITEMINFO1_BOUND_SEND) || (head.info1
== PICODATA_ITEMINFO1_BOUND_TERM) || (head.info1
== PICODATA_ITEMINFO1_BOUND_PHR1)
#ifdef PAM_PHR2_WITH_PR1
|| (head.info1 == PICODATA_ITEMINFO1_BOUND_PHR2)
#endif
) {
if (pam->nCurrSyllable >= PICOPAM_MAX_SYLL_PER_SENT - 2) {
return sResult; /*no room for more syllables*/
}
if ((pam->nCurrPhoneme + 1) >= PICOPAM_MAX_PH_PER_SENT - 2) {
return sResult; /*no room for more phoneme*/
}
}
break;
default:
/*all other commands has to be queued*/
if ((pam->nAttachedItemsSize + head.len)
>= PICOPAM_MAX_ITEM_SIZE_PER_SENT - 1) {
return sResult; /*no room for more items*/
}
break;
}
return FALSE; /*no resource limits apply to current item*/
} /*pamCheckResourceLimits*/
/**
* selects items to be sent to next PU immedately
* @param this : pointer to current PU struct
* @param item : pointer to current item head
* @return TRUE : item should be passed on next PU NOW
* @return FALSE : item should not be passed on next PU now but should be processed
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static pico_status_t pam_check_immediate(register picodata_ProcessingUnit this,
const picoos_uint8 *item)
{
register pam_subobj_t * pam;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
if (pam->nCurrSyllable <= -1) {
if (item[0] == PICODATA_ITEM_SYLLPHON)
return FALSE;
if ((item[0] == PICODATA_ITEM_BOUND) && (item[1]
== PICODATA_ITEMINFO1_BOUND_SBEG))
return FALSE;
if (is_pam_command((picoos_uint8 *) item) == TRUE)
return FALSE;
return TRUE; /*no need to process data : send it*/
}
return FALSE; /*syllable struct not void : do standard processing*/
} /*pam_check_immediate*/
/**
* checks if the input item has to be queued in local storage for later resynch
* @param this : pointer to current PU struct
* @param item : pointer to current item head
* @return TRUE : item should be queued
* @return FALSE : item should not be queued
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static pico_status_t pam_hastobe_queued(register picodata_ProcessingUnit this,
const picoos_uint8 *item)
{
register pam_subobj_t * pam;
picodata_itemhead_t head;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
head.type = item[0];
head.info1 = item[1];
switch (head.type) {
/*commands that generate syllables/phonemes*/
case PICODATA_ITEM_SYLLPHON:
return FALSE; /*no queue needed*/
break;
case PICODATA_ITEM_BOUND:
if ((head.info1 == PICODATA_ITEMINFO1_BOUND_PHR3)
#ifdef PAM_PHR2_WITH_PR3
||(head.info1==PICODATA_ITEMINFO1_BOUND_PHR2)
#endif
|| (head.info1 == PICODATA_ITEMINFO1_BOUND_PHR0)) {
return FALSE; /*no queue needed*/
}
break;
default:
/*all other items has to be queued*/
break;
}
return TRUE; /*item has to be queued*/
} /*pam_hastobe_queued*/
/**
* queue item in local storage for later resynch
* @param this : pointer to current PU struct
* @param item : pointer to current item head
* @return TRUE : item queued
* @return FALSE : item not queued because of errors
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static pico_status_t pam_queue(register picodata_ProcessingUnit this,
const picoos_uint8 *item)
{
register pam_subobj_t * pam;
picodata_itemhead_t head;
picoos_uint8 nI;
pico_status_t sResult;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
sResult = TRUE; /*default : item queued*/
head.type = item[0];
head.info1 = item[1];
head.info2 = item[2];
head.len = item[3];
/*test condition on enough room to store current item in the "sSyllItems" area*/
if ((pam->nAttachedItemsSize + head.len + sizeof(picodata_itemhead_t))
>= PICOPAM_MAX_ITEM_SIZE_PER_SENT - 1) {
return FALSE; /*resource limit reached*/
}
/*store current offset*/
pam->sSyllItemOffs[pam->nLastAttachedItemId] = pam->nAttachedItemsSize;
/*store the item to the "sSyllItems" area*/
for (nI = 0; nI < (head.len + sizeof(picodata_itemhead_t)); nI++) {
pam->sSyllItems[pam->nAttachedItemsSize + nI] = item[nI];
}
/*increment the attached items area*/
pam->nAttachedItemsSize += nI;
/*increment id*/
pam->nLastAttachedItemId++;
/*set start(if not initialized) and end ids of queued items in sSyllFeats*/
if (pam->nCurrSyllable > -1) {
/*normal case : the item is attached to current syllable*/
if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] == 0) {
pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM]
= pam->nLastAttachedItemId;
}
pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]
= pam->nLastAttachedItemId;
} else {
/*special case : an item is requested to be queued even if no
syllables has been assigned to the sentence structure :
-->> use syll 0*/
if (pam->sSyllFeats[0].phoneV[ITM] == 0) {
pam->sSyllFeats[0].phoneV[ITM] = pam->nLastAttachedItemId;
}
pam->sSyllFeats[0].phoneV[itm] = pam->nLastAttachedItemId;
}
return TRUE; /*item queued successfully*/
} /*pam_queue*/
/**
* selects items to be dealth with by the PU processing
* @param item : pointer to current item head
* @return TRUE : item should be processed
* @return FALSE : item should not be processed (maybe it ontains commands or items for other PUs)
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static pico_status_t pam_deal_with(const picoos_uint8 *item)
{
picodata_itemhead_t head;
pico_status_t sResult;
sResult = FALSE;
head.type = item[0];
head.info1 = item[1];
head.info2 = item[2];
head.len = item[3];
switch (head.type) {
case PICODATA_ITEM_SYLLPHON:
case PICODATA_ITEM_BOUND:
sResult = TRUE;
break;
default:
break;
}
return sResult;
} /*pam_deal_with*/
/**
* returns true if more items has to be produced for current syllable
* @param this : Pam object pointer
* @return TRUE : item is to be produced
* @return FALSE : item is not to be produced
* @remarks item pointed to by *item should be already valid
* @callgraph
* @callergraph
*/
static picoos_uint8 pamHasToProcess(register picodata_ProcessingUnit this)
{
register pam_subobj_t * pam;
picoos_uint8 nCond1, nCond2, nCond3;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
/*conditions originating a "NOT to be processed" result */
nCond1 = pam->nCurrSyllable <= -1;
nCond2 = pam->nCurrSyllable >= pam->nTotalSyllables;
nCond3 = pam->nSyllPhoneme
>= pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3];
if ((nCond1) || (nCond2) || (nCond3))
return FALSE;
return TRUE;
} /*pamHasToProcess*/
/**
* modifies the process flags in order to point to next valid syllable phone or item to be produced
* @param this : Pam object pointer
* @return TRUE : item has to be produced
* @return FALSE : item has not to be produced
* @callgraph
* @callergraph
*/
static pico_status_t pamUpdateProcess(register picodata_ProcessingUnit this)
{
register pam_subobj_t * pam;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
if (pam->nCurrSyllable == -1) {
/*this to be able to manage sudden PU cleanup after FLUSH CMD*/
return PICO_OK;
}
/*check number of phonemes for current syllable*/
if (pam->nSyllPhoneme < pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] - 1) {
pam->nSyllPhoneme++;
return PICO_OK;
}
if (pam->nSyllPhoneme == pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] - 1) {
/*this helps in identifyng the end of syllable condition in PamHasToProcess*/
pam->nSyllPhoneme++;
}
/*previous syllable phonemes are complete: test if any items are tied to this syllable*/
if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] > 0) {
/*there are items tied to this syllable*/
if (pam->nCurrAttachedItem == 0) {
/*if it is the first item to be regenerated initialize it*/
pam->nCurrAttachedItem
= pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM];
return PICO_OK;
} else {
/*not the first item : check if more*/
if (pam->nCurrAttachedItem
< pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]) {
/*more tied items to be regenerated*/
pam->nCurrAttachedItem++;
return PICO_OK;
}
}
}
/*previous syllable phonemes and items are complete: switch to next syllable*/
if (pam->nCurrSyllable < pam->nTotalSyllables - 1) {
pam->nCurrSyllable++;
pam->nSyllPhoneme = 0;
pam->nCurrAttachedItem = 0;
return PICO_OK;
}
/*no more phonemes or items to be produced*/
pam->nCurrSyllable++;
pam->nSyllPhoneme = 0;
return PICO_ERR_OTHER;
} /*pamUpdateProcess*/
/**
* returns true if more items has to be popped for current syllable
* @param this : Pam object pointer
* @return TRUE : item has to be popped
* @return FALSE : item has not to be popped
* @callgraph
* @callergraph
*/
static picoos_uint8 pamHasToPop(register picodata_ProcessingUnit this)
{
register pam_subobj_t * pam;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
/*Preliminary condition : at least 1 syllable*/
if (pam->nCurrSyllable <= -1)
return FALSE;
/*Preliminary condition : not maximum number of syllables*/
if (pam->nCurrSyllable >= pam->nTotalSyllables)
return FALSE;
/*Preliminary condition : start and end offset in current item > 0 */
if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0)
|| (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0))
return FALSE;
/*Final condition : current popped item less or eq to maximum*/
if (pam->nCurrAttachedItem
> pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm])
return FALSE;
return TRUE;
} /*pamHasToPop*/
/**
* returns the address of an item to be popped from the current syllable queue
* @param this : Pam object pointer
* @return pop_address : item address
* @return NULL : item not poppable
* @callgraph
* @callergraph
*/
static picoos_uint8 *pamPopItem(register picodata_ProcessingUnit this)
{
register pam_subobj_t * pam;
picoos_uint8 nItem;
if (NULL == this || NULL == this->subObj) {
return NULL;
}
pam = (pam_subobj_t *) this->subObj;
/*Preliminary condition : at least 1 syllable*/
if (pam->nCurrSyllable <= -1)
return NULL;
/*Preliminary condition : not maximum number of syllables*/
if (pam->nCurrSyllable >= pam->nTotalSyllables)
return NULL;
/*Preliminary condition : start and end offset in current item > 0 */
if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0)
|| (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0))
return NULL;
/*Final condition : current popped item less than maximum*/
if (pam->nCurrAttachedItem
> pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm])
return NULL;
nItem = pam->nCurrAttachedItem;
/*please note : nItem-1 should match with actions performed in function "pam_queue(..)" */
return &(pam->sSyllItems[pam->sSyllItemOffs[nItem - 1]]);
} /*pamPopItem*/
/**
* returns the address of an item popped from the syllable 0 queue
* @param this : Pam object pointer
* @return pop_address : item address
* @return NULL : item not poppable
* @remarks the item is popped only if it has been inserted in the queue before the first
* @remarks item assigned to the syllable 0 i.e.
* @remarks AttachedItem<=pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]-1
* @callgraph
* @callergraph
*/
static picoos_uint8 *pamPopAttachedSy0(register picodata_ProcessingUnit this)
{
register pam_subobj_t * pam;
picoos_uint8 nItem;
if (NULL == this || NULL == this->subObj) {
return NULL;
}
pam = (pam_subobj_t *) this->subObj;
/*should be syllable 0*/
if (pam->nCurrSyllable != 0)
return NULL;
/*start and end offset in current item > 0 */
if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0)
|| (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0))
return NULL;
/*if current popped item is > 0 test end condition*/
if (pam->nCurrAttachedItem > 0) {
/*Other condition : current popped item less than maximum*/
if (pam->nCurrAttachedItem
> pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] - 1)
return NULL;
}
nItem = pam->nCurrAttachedItem;
return &(pam->sSyllItems[pam->sSyllItemOffs[nItem]]);
} /*pamPopAttachedSy0*/
/**
* pdf access for duration
* @param this : Pam object pointer
* @param durIndex : index of duration in the pdf
* @param phonDur : pointer to base of array where to store the duration values
* @param numFramesState : pointer to base of array where to store the number of frames per state
* @return PICO_OK : pdf retrieved
* @return PICO_ERR_OTHER : pdf not retrieved
* @remarks Modifies phonDur (the requested duration value)
* @remarks Modifies numFramesState (the requested number of frames per state (vector))
* @callgraph
* @callergraph
*/
static pico_status_t pam_get_duration(register picodata_ProcessingUnit this,
picoos_uint16 durIndex, picoos_uint16 *phonDur,
picoos_uint8 *numFramesState)
{
pam_subobj_t *pam;
picokpdf_PdfDUR pdf;
picoos_uint8 *durItem;
picoos_uint16 nFrameSize, nI;
picoos_single fValue;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pdf = pam->pdfdur;
/*make the index 0 based*/
if (durIndex > 0)
durIndex--;
/* check */
if (durIndex > pdf->numframes - 1) {
PICODBG_ERROR(("PAM durPdf access error, index overflow -> index: %d , numframes: %d", durIndex, pdf->numframes));
return PICO_ERR_OTHER;
}
/* base pointer */
durItem = &(pdf->content[durIndex * pdf->vecsize]);
if (durItem == NULL) {
PICODBG_ERROR(("PAM durPdf access error , frame pointer = NULL"));
return PICO_ERR_OTHER;
}
nFrameSize = pdf->sampperframe / 16;
*phonDur = ((pdf->phonquant[((*durItem) & 0xF0) >> 4]) * nFrameSize);
numFramesState[0] = pdf->statequant[((*durItem) & 0x0F)];
durItem++;
numFramesState[1] = pdf->statequant[((*durItem) & 0xF0) >> 4];
numFramesState[2] = pdf->statequant[((*durItem) & 0x0F)];
durItem++;
numFramesState[3] = pdf->statequant[((*durItem) & 0xF0) >> 4];
numFramesState[4] = pdf->statequant[((*durItem) & 0x0F)];
/*modification of the duration information based on the duration modifier*/
*phonDur = (picoos_uint16) (((picoos_single) * phonDur) * pam->dMod);
for (nI = 0; nI < 5; nI++) {
fValue = pam->dRest + (picoos_single) numFramesState[nI] * pam->dMod;
numFramesState[nI] = (picoos_uint8) (fValue);
pam->dRest = fValue - (picoos_single) numFramesState[nI];
}
return PICO_OK;
}/*pam_get_duration*/
/**
* pdf access for pitch
* @param this : Pam object pointer
* @param lf0Index : pointer to variable to receive index of pitch in the pdf
* @param nI : number of the phone's state
* @param phonF0 : pointer to variable to receive the pitch value
* @return PICO_OK : pdf retrieved
* @return PICO_ERR_OTHER : pdf not retrieved
* @remarks Modifies phonDur (the requested duration value)
* @remarks Modifies phonF0 (the requested pitch value (scalar))
* @callgraph
* @callergraph
*/
static pico_status_t pam_get_f0(register picodata_ProcessingUnit this,
picoos_uint16 *lf0Index, picoos_uint8 nI, picoos_single *phonF0)
{
pam_subobj_t *pam;
picoos_uint8 *lfItem, numstreams;
picoos_uint16 lf0IndexOffset, sTemp;
picoos_single lfum, lfivar, lfz;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
lf0IndexOffset = lf0Index[nI];
/*make the index 0 based*/
if (lf0IndexOffset > 0)
lf0IndexOffset--;
lf0IndexOffset += pam->pdflfz->stateoffset[nI];
if (lf0IndexOffset > pam->pdflfz->numframes - 1) {
PICODBG_ERROR(("PAM flfzPdf access error, index overflow -> index: %d , numframes: %d", lf0Index, pam->pdflfz->numframes));
return PICO_ERR_OTHER;
}
/* base pointer */
lf0IndexOffset *= pam->pdflfz->vecsize;
lfItem = &(pam->pdflfz->content[lf0IndexOffset]);
sTemp = (picoos_uint16) (((lfItem[1] << 8)) | lfItem[0]);
lfum = (picoos_single) (sTemp << (pam->pdflfz->meanpowUm[0]));
numstreams = 3;
lfivar = (picoos_single) (((picoos_uint16) lfItem[numstreams * 2])
<< pam->pdflfz->ivarpow[0]);
lfz = (picoos_single) lfum / (picoos_single) lfivar;
lfz = (picoos_single) exp((double) lfz);
phonF0[nI] = (picoos_single) lfz;
/*pitch modoification*/
phonF0[nI] *= pam->pMod;
return PICO_OK;
}/*pam_get_f0*/
/**
* elementary rounding function
* @param fIn : (real) input value
* @return the rounded value
* @callgraph
* @callergraph
*/
static picoos_single f_round(picoos_single fIn)
{
picoos_int32 iVal;
picoos_single fVal;
iVal = (picoos_int32) fIn;
fVal = (picoos_single) iVal;
if (fIn > (picoos_single) 0.0f) {
if ((fIn - fVal) < (picoos_single) 0.5f)
return fVal;
else
return fVal + (picoos_single) 1.0f;
} else {
if ((fVal - fIn) < (picoos_single) 0.5f)
return fVal;
else
return fVal - (picoos_single) 1.0f;
}
}/*f_round*/
/**
* updates the input vector for PAM
* @param this : Pam object pointer
* @return PICO_OK : update successful
* @return PICO_ERR_OTHER : errors on retrieving the PU pointer
* @remarks Modifies pam->sPhFeats[]
* @callgraph
* @callergraph
*/
static pico_status_t pam_update_vector(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
picoos_uint8 numstates, nI;
picoos_single fDur, f0avg, f0quant, minf0, maxf0, durquant1, durquant2,
mindur, maxdur1, maxdur2;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICO_ERR_OTHER;
}
/*default init*/
pam->sPhFeats[DUR] = 0;
pam->sPhFeats[F0] = 0;
/*
Hard coded parameters for quantization
*/
numstates = PICOPAM_NRSTPF;
f0quant = 30.0f;
minf0 = 90.0f;
maxf0 = 360.0f;
durquant1 = 20.0f;
durquant2 = 100.0f;
mindur = 40.0f;
maxdur1 = 160.0f;
maxdur2 = 600.0f;
f0avg = 0.0f;
for (nI = 0; nI < numstates; nI++)
f0avg += pam->phonF0[nI];
f0avg /= (picoos_single) numstates;
f0avg = f_round(f0avg / f0quant) * f0quant;
if (f0avg < minf0)
f0avg = minf0;
if (f0avg > maxf0)
f0avg = maxf0;
/*make initial silence of sentence shorter (see also pam_put_item)*/
if ((pam->nCurrSyllable == 0) && (pam->nSyllPhoneme == 0)) {
pam->phonDur = 2 * 4;
}
fDur = (picoos_single) pam->phonDur;
fDur = f_round(fDur / durquant1) * durquant1;
if (fDur < mindur)
fDur = mindur;
if (fDur > maxdur1) {
fDur = f_round(fDur / durquant2) * durquant2;
if (fDur > maxdur2)
fDur = maxdur2;
}
pam->sPhFeats[DUR] = (picoos_uint8) (fDur / (picoos_single) 10.0f);
pam->sPhFeats[F0] = (picoos_uint8) (f0avg / (picoos_single) 10.0f);
return PICO_OK;
}/*pam_update_vector*/
/**
* compress a single feature in the range 0..9
* @param inVal : the value to be compressed
* @return compVal : the compressed value
* @callgraph
* @callergraph
*/
static picoos_uint8 pamCompressComponent(picoos_uint8 inVal)
{
if (inVal <= 5)
return inVal;
if ((5 < inVal) && (inVal <= 10))
return 6;
if ((10 < inVal) && (inVal <= 20))
return 7;
if ((20 < inVal) && (inVal <= 30))
return 8;
return 9;
}/*pamCompressComponent*/
/**
* prepares the input vector for tree feeding
* @param this : Pam object pointer
* @return PICO_OK : vector expanded
* @return PICO_ERR_OTHER : errors on expansion or retrieving the PU pointer
* @remarks Modifies pam->sPhFeats[]
* @callgraph
* @callergraph
*/
static pico_status_t pam_expand_vector(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
picoos_uint8 *inVect, *phonVect, *outVect, nI;
picoos_int16 nOffs, nOffs1, nLen;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
inVect = &(pam->sSyllFeats[pam->nCurrSyllable].phoneV[0]);
phonVect = &(pam->sPhIds[0]);
outVect = &(pam->sPhFeats[0]);
/*just copy back*/
for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++)
outVect[nI] = inVect[nI];
/*now fill missing fields*/
picoos_mem_copy((void*) &(inVect[FID]), &nOffs, sizeof(nOffs));
/*offset to first phone of current syllable*/
nOffs = nOffs + pam->nSyllPhoneme; /*offset to current phone of current syllable*/
nLen = inVect[B3]; /*len of current syllable*/
if (pam->nSyllPhoneme >= nLen) {
/*error on addressing current phone*/
return PICO_ERR_OTHER;
}
/*previous of the previous phone*/
nOffs1 = nOffs - 2;
if (nOffs1 >= 0)
outVect[P1] = phonVect[nOffs1];
else
outVect[P1] = PICOPAM_PH_DONT_CARE_VAL;
/*previous phone*/
nOffs1 = nOffs - 1;
if (nOffs1 >= 0)
outVect[P2] = phonVect[nOffs1];
else
outVect[P2] = PICOPAM_PH_DONT_CARE_VAL;
/*^current phone*/
outVect[P3] = phonVect[nOffs];
/*next phone*/
nOffs1 = nOffs + 1;
if (nOffs1 < pam->nTotalPhonemes)
outVect[P4] = phonVect[nOffs1];
else
outVect[P4] = PICOPAM_PH_DONT_CARE_VAL;
/*next of the next phone*/
nOffs1 = nOffs + 2;
if (nOffs1 < pam->nTotalPhonemes)
outVect[P5] = phonVect[nOffs1];
else
outVect[P5] = PICOPAM_PH_DONT_CARE_VAL;
/*pos of curr phone with respect to left syllable boundary*/
outVect[P6] = pam->nSyllPhoneme + 1;
/*pos of curr phone with respect to right syllable boundary*/
outVect[P7] = nLen - pam->nSyllPhoneme;
/*is current phone in consonant syllable boundary? (1:yes)*/
if (pam->nSyllPhoneme < inVect[P8])
outVect[P8] = 1;
else
outVect[P8] = 0;
return PICO_OK;
}/*pam_expand_vector*/
/**
* compresses the input vector for PAM
* @param this : Pam object pointer
* @return PICO_OK : compression successful
* @return PICO_ERR_OTHER : errors on retrieving the PU pointer
* @remarks Modifies pam->sPhFeats[]
* @callgraph
* @callergraph
*/
static pico_status_t pamCompressVector(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
picoos_uint8 *outVect, nI;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
outVect = &(pam->sPhFeats[0]);
for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++) {
switch (nI) {
case P1:
case P2:
case P3:
case P4:
case P5:
case B1:
case B2:
case B16:
case E1:
case H5:
/*don't do any compression*/
break;
default:
/*do compression*/
if (outVect[nI] != PICOPAM_DONT_CARE_VALUE)
outVect[nI] = pamCompressComponent(outVect[nI]);
else
outVect[nI] = PICOPAM_DONT_CARE_VAL;
break;
}
}
return PICO_OK;
}/*pamCompressVector*/
/**
* reorganizes the input vector for PAM
* @param this : Pam object pointer
* @return PICO_OK : reorganization successful
* @return PICO_ERR_OTHER : errors on retrieving the PU pointer
* @remarks Modifies pam->sPhFeats[]
* @callgraph
* @callergraph
*/
static pico_status_t pamReorgVector(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
picoos_uint8 *outVect, inVect[60], nI;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
outVect = &(pam->sPhFeats[0]);
for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++) inVect[nI] = outVect[nI];
/*reorganize*/
for (nI = T_B1; nI <= T_H5; nI++) {
switch (nI) {
case T_B1:
outVect[T_B1] = inVect[B1];
break;
case T_B2:
outVect[T_B2] = inVect[B2];
break;
case T_B3:
outVect[T_B3] = inVect[B3];
break;
case T_B4:
outVect[T_B4] = inVect[B4];
break;
case T_B5:
outVect[T_B5] = inVect[B5];
break;
case T_B6:
outVect[T_B6] = inVect[B6];
break;
case T_B7:
outVect[T_B7] = inVect[B7];
break;
case T_B8:
outVect[T_B8] = inVect[B8];
break;
case T_B9:
outVect[T_B9] = inVect[B9];
break;
case T_B10:
outVect[T_B10] = inVect[B10];
break;
case T_B11:
outVect[T_B11] = inVect[B11];
break;
case T_B12:
outVect[T_B12] = inVect[B12];
break;
case T_B13:
outVect[T_B13] = inVect[B13];
break;
case T_B14:
outVect[T_B14] = inVect[B14];
break;
case T_B15:
outVect[T_B15] = inVect[B15];
break;
case T_B16:
outVect[T_B16] = inVect[B16];
break;
case T_B17:
outVect[T_B17] = inVect[B17];
break;
case T_B18:
outVect[T_B18] = inVect[B18];
break;
case T_B19:
outVect[T_B19] = inVect[B19];
break;
case T_B20:
outVect[T_B20] = inVect[B20];
break;
case T_B21:
outVect[T_B21] = inVect[B21];
break;
case T_E1:
outVect[T_E1] = inVect[E1];
break;
case T_E2:
outVect[T_E2] = inVect[E2];
break;
case T_E3:
outVect[T_E3] = inVect[E3];
break;
case T_E4:
outVect[T_E4] = inVect[E4];
break;
case T_E5:
outVect[T_E5] = inVect[E5];
break;
case T_E6:
outVect[T_E6] = inVect[E6];
break;
case T_E7:
outVect[T_E7] = inVect[E7];
break;
case T_E8:
outVect[T_E8] = inVect[E8];
break;
case T_E9:
outVect[T_E9] = inVect[E9];
break;
case T_E10:
outVect[T_E10] = inVect[E10];
break;
case T_E11:
outVect[T_E11] = inVect[E11];
break;
case T_E12:
outVect[T_E12] = inVect[E12];
break;
case T_E13:
outVect[T_E13] = inVect[E13];
break;
case T_A3:
outVect[T_A3] = inVect[A3];
break;
case T_C3:
outVect[T_C3] = inVect[C3];
break;
case T_D2:
outVect[T_D2] = inVect[D2];
break;
case T_F2:
outVect[T_F2] = inVect[F2];
break;
case T_G1:
outVect[T_G1] = inVect[G1];
break;
case T_I1:
outVect[T_I1] = inVect[I1];
break;
case T_G2:
outVect[T_G2] = inVect[G2];
break;
case T_I2:
outVect[T_I2] = inVect[I2];
break;
case T_H1:
outVect[T_H1] = inVect[H1];
break;
case T_H2:
outVect[T_H2] = inVect[H2];
break;
case T_H3:
outVect[T_H3] = inVect[H3];
break;
case T_H4:
outVect[T_H4] = inVect[H4];
break;
case T_H5:
outVect[T_H5] = inVect[H5];
break;
}
}
return PICO_OK;
}/*pamReorgVector*/
/**
* puts a PAM item into PU output buffer
* @param this : Pam object pointer
* @param outBuff : output buffer base pointer
* @param outWritePos : offset in output buffer
* @param *bytesWr : actual bytes written
* @return PICO_OK : put successful
* @return PICO_ERR_OTHER : errors on retrieving the PU pointer
* @callgraph
* @callergraph
*/
static pico_status_t pam_put_item(register picodata_ProcessingUnit this,
picoos_uint8 *outBuff, picoos_uint16 outWritePos, picoos_uint8 *bytesWr)
{
pam_subobj_t *pam;
picoos_uint8 *sDest, nI, nType, nIdx, fde;
picoos_uint32 pos, pos32;
picoos_int16 ft, dt;
picoos_uint16 uMinDur, uMaxDur;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
sDest = &(outBuff[outWritePos]);
sDest[0] = PICODATA_ITEM_PHONE; /*Item type*/
sDest[1] = pam->sPhFeats[P3]; /*phonetic id*/
sDest[2] = PICOPAM_NRSTPF; /*number of states per phone*/
sDest[3] = sizeof(picoos_uint16) * PICOPAM_NRSTPF * 3; /*size of the item*/
pos = 4;
/*make initial silence of sentence shorter (see also UpdateVector)*/
if ((pam->nCurrSyllable == 0) && (pam->nSyllPhoneme == 0)) {
for (nI = 0; nI < PICOPAM_NRSTPF - 1; nI++)
pam->numFramesState[nI] = 0;
pam->numFramesState[nI] = 2;
} else {
/*manage silence syllables with prescribed durations*/
pos32 = Min;
picoos_read_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV,
&pos32, &uMinDur);
pos32 = Max;
picoos_read_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV,
&pos32, &uMaxDur);
if (uMaxDur > 0) {
/* Select weights*/
nType = pam->sSyllFeats[pam->nCurrSyllable].phoneV[bnd];
switch (nType) {
case PICODATA_ITEMINFO1_BOUND_SBEG:
nIdx = PICOPAM_PWIDX_SBEG;
break;
case PICODATA_ITEMINFO1_BOUND_PHR1:
nIdx = PICOPAM_PWIDX_PHR1;
break;
case PICODATA_ITEMINFO1_BOUND_PHR2:
nIdx = PICOPAM_PWIDX_PHR2;
break;
case PICODATA_ITEMINFO1_BOUND_SEND:
case PICODATA_ITEMINFO1_BOUND_TERM:
nIdx = PICOPAM_PWIDX_SEND;
break;
default:
nIdx = PICOPAM_PWIDX_DEFA;
break;
}
fde = 2;
ft = 0;
dt = 0;
picodata_transformDurations(
fde, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */
PICOPAM_NRSTPF, /* number of states per phone */
&(pam->numFramesState[0]), /* estimated durations */
pam->sil_weights[nIdx], /* integer weights */
uMinDur, /* minimum target duration in ms */
uMaxDur, /* maximum target duration in ms */
ft, /* factor to be multiplied to get the target */
&dt /* in/out, rest in ms */
);
}
}
/*put data*/
for (nI = 0; nI < PICOPAM_NRSTPF; nI++) {
picoos_write_mem_pi_uint16(sDest, &pos,
(picoos_uint16) pam->numFramesState[nI]);
picoos_write_mem_pi_uint16(sDest, &pos,
(picoos_uint16) pam->lf0Index[nI]);
picoos_write_mem_pi_uint16(sDest, &pos,
(picoos_uint16) pam->mgcIndex[nI]);
}
*bytesWr = sizeof(picodata_itemhead_t) + sizeof(picoos_uint16)
* PICOPAM_NRSTPF * 3;
return PICO_OK;
}/*pam_put_item*/
/**
* puts a non PAM (queued) item into PU output buffer
* @param qItem : pointer to item to put
* @param outBuff : output buffer base pointer
* @param outWritePos : offset in output buffer
* @param *bytesWr : actual bytes written
* @return PICO_OK : put successful
* @return PICO_ERR_OTHER : errors on retrieving the PU pointer
* @callgraph
* @callergraph
*/
static pico_status_t pam_put_qItem(picoos_uint8 *qItem, picoos_uint8 *outBuff,
picoos_uint16 outWritePos, picoos_uint8 *bytesWr)
{
picoos_uint8 *sDest, nI;
sDest = &(outBuff[outWritePos]);
*bytesWr = sizeof(picodata_itemhead_t);
for (nI = 0; nI < (sizeof(picodata_itemhead_t) + qItem[3]); nI++) {
sDest[nI] = qItem[nI];
}
*bytesWr = nI;
return PICO_OK;
}/*pam_put_qItem*/
/**
* tells if an item is a PAM command (except play)
* @param qItem : input item to test
* @return TRUE : qItem is a PAM command (except play)
* @return FALSE : qItem not a PAM command
* @callgraph
* @callergraph
*/
static pico_status_t is_pam_command(const picoos_uint8 * qItem)
{
switch (qItem[0]) {
case PICODATA_ITEM_CMD:
switch (qItem[1]) {
case PICODATA_ITEMINFO1_CMD_FLUSH:
/* flush is for all PU's and as such it is also for PAM*/
case PICODATA_ITEMINFO1_CMD_PITCH:
case PICODATA_ITEMINFO1_CMD_SPEED:
return TRUE;
break;
default:
break;
}
}
return FALSE;
}/*is_pam_command*/
/**
* tells if an item is a PAM PLAY command
* @param qItem : input item to test
* @return TRUE : qItem is a PAM PLAY command
* @return FALSE : qItem not a PAM PLAY command
* @callgraph
* @callergraph
*/
static pico_status_t is_pam_play_command(picoos_uint8 *qItem)
{
switch (qItem[0]) {
case PICODATA_ITEM_CMD:
switch (qItem[1]) {
case PICODATA_ITEMINFO1_CMD_PLAY:
if (qItem[2] == PICODATA_ITEMINFO2_CMD_TO_PAM)
return TRUE;
break;
default:
break;
}
}
return FALSE;
}/*is_pam_play_command*/
/**
* command processor for PAM pu
* @param this : Pam item subobject
* @param qItem : input item pointer
* @return PICOPAM_FLUSH_RECEIVED : when a FLUSH is received
* @return PICOPAM_CONTINUE : normal command processing
* @return PICODATA_PU_ERROR : errors in accessing data
* @callgraph
* @callergraph
*/
static pico_status_t pamDoCommand(register picodata_ProcessingUnit this,
picoos_uint8 *qItem)
{
pam_subobj_t *pam;
picoos_single fValue;
picoos_uint16 nValue;
picoos_uint32 nPos;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
if (qItem[0] == PICODATA_ITEM_CMD) {
switch (qItem[1]) {
case PICODATA_ITEMINFO1_CMD_FLUSH:
/* flush is for all PU's and as such it is also for PAM : implement the flush!!*/
pam_reset_processors(this);
pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0;
pam->nAttachedItemsSize = 0;
return PICOPAM_FLUSH_RECEIVED;
break;
case PICODATA_ITEMINFO1_CMD_PITCH:
case PICODATA_ITEMINFO1_CMD_SPEED:
nPos = 4;
picoos_read_mem_pi_uint16(qItem, &nPos, &nValue);
if (qItem[2] == 'a') {
/*absloute modifier*/
fValue = (picoos_single) nValue / (picoos_single) 100.0f;
if (qItem[1] == PICODATA_ITEMINFO1_CMD_PITCH)
pam->pMod = fValue;
if (qItem[1] == PICODATA_ITEMINFO1_CMD_SPEED)
pam->dMod = (1.0f / fValue);
}
if (qItem[2] == 'r') {
/*relative modifier*/
fValue = (picoos_single) nValue / (picoos_single) 1000.0f;
if (qItem[1] == PICODATA_ITEMINFO1_CMD_PITCH)
pam->pMod *= (1.0f / fValue);
if (qItem[1] == PICODATA_ITEMINFO1_CMD_SPEED)
pam->dMod *= (1.0f / fValue);
}
return PICOPAM_CONTINUE;
break;
default:
break;
}/*end switch switch (qItem[1])*/
}/*end if (qItem[0]==PICODATA_ITEM_CMD)*/
return PICOPAM_CONTINUE;
}/*pamDoCommand*/
/**
* defines if an item has to be sent to following PUs
* @param qItem : input item pointer
* @return TRUE : item has to be transmitted to following PUs
* @return FALSE : item has to be consumed internallz on PAM
* @callgraph
* @callergraph
*/
static pico_status_t isItemToPut(picoos_uint8 *qItem)
{
switch (qItem[0]) {
case PICODATA_ITEM_CMD:
/* is a command*/
if (PICODATA_ITEMINFO1_CMD_SPEED == qItem[1]) {
/* SPEED consumed here*/
return FALSE;
}
break;
case PICODATA_ITEM_BOUND:
switch (qItem[1]) {
case PICODATA_ITEMINFO1_BOUND_SBEG:
case PICODATA_ITEMINFO1_BOUND_PHR0:
case PICODATA_ITEMINFO1_BOUND_PHR1:
case PICODATA_ITEMINFO1_BOUND_PHR2:
case PICODATA_ITEMINFO1_BOUND_PHR3:
/*boudary items consumed here except SEND,TERM*/
return FALSE;
break;
default:
break;
}
break;
default:
break;
}
/*all other items not explicitly mentioned here
are transmitted to next PUs*/
return TRUE;
}/*isItemToPut*/
/**
* pushes a boundary TERM item into some buffer
* @param outBuff : output buffer base pointer
* @param outWritePos : offset in output buffer
* @param *bytesWr : actual bytes written
* @return PICO_OK
* @remarks used while forcing TERM input items in forward processing
* @callgraph
* @callergraph
*/
static pico_status_t pam_put_term(picoos_uint8 *outBuff,
picoos_uint16 outWritePos, picoos_uint8 *bytesWr)
{
picoos_uint8 *sDest;
sDest = &(outBuff[outWritePos]);
sDest[0] = PICODATA_ITEM_BOUND; /*Item type*/
sDest[1] = PICODATA_ITEMINFO1_BOUND_TERM;
sDest[2] = PICODATA_ITEMINFO2_BOUNDTYPE_T;
sDest[3] = 0; /*item size*/
*bytesWr = 4;
return PICO_OK;
}/*pam_put_term*/
/**
* translates one full phone into a PHONE Item including DT Dur, F0 and CEP trees feature generation and traversal
* @param this : Pam item subobject pointer
* @return PICO_OK : processing successful
* @return PICODATA_PU_ERROR : error accessing PAM object
* @return !=PICO_OK : processing errors
* @callgraph
* @callergraph
*/
static pico_status_t pamPhoneProcess(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
pico_status_t sResult;
picokdt_classify_result_t dTreeResult;
picoos_uint8 nI, bWr;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
/*expands current phone in current syllable in the corresponding vector pam->sPhFeats[]*/
sResult = pam_expand_vector(this);
sResult = pamCompressVector(this);
sResult = pamReorgVector(this);
/*tree traversal for duration*/
if (!pam_do_tree(this, pam->dtdur, &(pam->sPhFeats[0]), PICOPAM_INVEC_SIZE,
&dTreeResult)) {
PICODBG_WARN(("problem using pam tree dtdur, using fallback value"));
dTreeResult.class = 0;
}
pam->durIndex = dTreeResult.class;
sResult = pam_get_duration(this, pam->durIndex, &(pam->phonDur),
&(pam->numFramesState[0]));
/*tree traversal for pitch*/
for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) {
if (!pam_do_tree(this, pam->dtlfz[nI], &(pam->sPhFeats[0]),
PICOPAM_INVEC_SIZE, &dTreeResult)) {
PICODBG_WARN(("problem using pam tree lf0Tree, using fallback value"));
dTreeResult.class = 0;
}
pam->lf0Index[nI] = dTreeResult.class;
}
/*pdf access for pitch*/
for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) {
sResult = pam_get_f0(this, &(pam->lf0Index[0]), nI, &(pam->phonF0[0]));
}
/*update vector with duration and pitch for cep tree traversal*/
sResult = pam_update_vector(this);
/*cep tree traversal*/
for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) {
if (!pam_do_tree(this, pam->dtmgc[nI], &(pam->sPhFeats[0]),
PICOPAM_INVEC_SIZE, &dTreeResult)) {
PICODBG_WARN(("problem using pam tree lf0Tree, using fallback value"));
dTreeResult.class = 0;
}
pam->mgcIndex[nI] = dTreeResult.class;
}
/*put item to output buffer*/
sResult = pam_put_item(this, pam->outBuf, pam->outWritePos, &bWr);
if (sResult == PICO_OK)
pam->outWritePos += bWr;
else
return sResult;
return PICO_OK;
}/*pamPhoneProcess*/
/**
* manages first syllable attached items when seen before SBEG
* @param this : Pam item subobject pointer
* @return PICO_OK (0) : default return code --> means no more items to be processed before 1st syllable
* @return PICOPAM_GOTO_FEED : go to feed state after this
* @return PICOPAM_GOTO_SCHEDULE : flush received
* @return PICODATA_PU_ERROR : errors
* @callgraph
* @callergraph
*/
static pico_status_t pamDoPreSyll(register picodata_ProcessingUnit this)
{
pam_subobj_t *pam;
pico_status_t sResult;
picoos_uint8 bWr, nRc;
picoos_uint8 *qItem;
nRc = PICOPAM_PRE_SYLL_ENDED;
pam = (pam_subobj_t *) this->subObj;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
/*regenerate initial items before the phonemes*/
if (((qItem = pamPopAttachedSy0(this)) != NULL) && !((qItem[0]
== PICODATA_ITEM_BOUND) && (qItem[1]
== PICODATA_ITEMINFO1_BOUND_SBEG))) {
if (isItemToPut(qItem)) {
pam_put_qItem(qItem, pam->outBuf, pam->outWritePos, &bWr);/*popped item has to be sent to next PU*/
pam->outWritePos += bWr;
nRc = PICOPAM_GOTO_FEED;
}
if (is_pam_command(qItem) == TRUE) {
nRc = pamDoCommand(this, qItem); /*popped item is a PAM command : do it NOW!!*/
if ((nRc == PICOPAM_FLUSH_RECEIVED) || (nRc == PICODATA_PU_ERROR)) {
/*FLUSH command RECEIVED or errors: stop ALL PROCESSING*/
return nRc;
}
}
pam->nCurrAttachedItem++;
if (nRc == 0)
return PICOPAM_CONTINUE;
else
return nRc;
}
/*SBEG item management*/
if ((qItem != NULL) && (qItem[0] == PICODATA_ITEM_BOUND) && (qItem[1]
== PICODATA_ITEMINFO1_BOUND_SBEG)) {
sResult = pam_put_qItem(qItem, pam->outBuf, pam->outWritePos, &bWr);
pam->outWritePos += bWr;
pam->nCurrAttachedItem++;
nRc = PICOPAM_GOTO_FEED;
}
return nRc;
}/*pamDoPreSyll*/
/**
* performs a step of the pam processing
* @param this : Pam item subobject pointer
* @param mode : mode for the PU
* @param *numBytesOutput : pointer to output number fo bytes produced
* @return PICODATA_PU_IDLE : nothing to do
* @return PICODATA_PU_BUSY : still tasks undergoing
* @return PICODATA_PU_ERROR : errors on processing
* @callgraph
* @callergraph
*/
static picodata_step_result_t pam_step(register picodata_ProcessingUnit this,
picoos_int16 mode, picoos_uint16 * numBytesOutput)
{
register pam_subobj_t * pam;
pico_status_t sResult;
picoos_uint16 blen, numinb, numoutb;
pico_status_t rv;
picoos_uint8 bWr;
picoos_uint8 bForcedItem[4];
picoos_uint8 *qItem;
numinb = 0;
numoutb = 0;
rv = PICO_OK;
if (NULL == this || NULL == this->subObj) {
return PICODATA_PU_ERROR;
}
pam = (pam_subobj_t *) this->subObj;
mode = mode; /* avoid warning "var not used in this function"*/
/*Init number of output bytes*/
*numBytesOutput = 0;
while (1) { /* exit via return */
PICODBG_DEBUG(("pam_step -- doing state %i",pam->procState));
switch (pam->procState) {
case PICOPAM_COLLECT:
/* *************** item collector ***********************************/
/*collecting items from the PU input buffer*/
sResult = picodata_cbGetItem(this->cbIn,
&(pam->inBuf[pam->inWritePos]), pam->inBufSize
- pam->inWritePos, &blen);
if (sResult != PICO_OK) {
if (sResult == PICO_EOF) {
/*no items available : remain in state 0 and return idle*/
return PICODATA_PU_IDLE;
} else {
/*errors : remain in state 0 and return error*/
PICODBG_DEBUG(("pam_step(PICOPAM_COLLECT) -- Errors on item buffer input, status: %d",sResult));
return PICODATA_PU_ERROR;
}
}
PICODBG_DEBUG(("pam_step -- got item, status: %d",sResult));
sResult = picodata_is_valid_item(
&(pam->inBuf[pam->inWritePos]), blen);
if (sResult != TRUE) {
/*input item is not valid : consume the input item and stay in COLLECT*/
pam->inWritePos += blen;
pam->inReadPos += blen;
if (pam->inReadPos >= pam->inWritePos) {
pam->inReadPos = 0;
pam->inWritePos = 0;
}PICODBG_DEBUG(("pam_step -- item is not valid, type: %d",pam->inBuf[pam->inWritePos]));
return PICODATA_PU_BUSY;
}
/*update input write pointer + move to "schedule" state*/
pam->inWritePos += blen;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
case PICOPAM_SCHEDULE:
/* check out if more items are available */
if (pam->inReadPos >= pam->inWritePos) {
/*no more items : back to collect state*/
pam->procState = PICOPAM_COLLECT;
return PICODATA_PU_BUSY;
}
/* we have one full valid item, with len>0 starting at
pam->inBuf[pam->inReadPos]; here we decide how to elaborate it */
/* PLAY management */
if (is_pam_play_command(&(pam->inBuf[pam->inReadPos])) == TRUE) {
/*consume the input item : it has been managed*/
pam->inReadPos += pam->inBuf[pam->inReadPos + 3]
+ sizeof(picodata_itemhead_t);
if (pam->inReadPos >= pam->inWritePos) {
pam->inReadPos = 0;
pam->inWritePos = 0;
}
/*stay in schedule*/
return PICODATA_PU_BUSY;
}
if (pam_check_immediate(this, &(pam->inBuf[pam->inReadPos]))) {
/* item has to be sent to next PU NOW : switch to "immediate" state */
pam->procState = PICOPAM_IMMEDIATE;
return PICODATA_PU_BUSY;
}
if (pamCheckResourceLimits(this, &(pam->inBuf[pam->inReadPos]))) {
/* item would not fit into local buffers -->> free some space -->>
switch to "force term" state */
pam->procState = PICOPAM_FORWARD_FORCE_TERM;
return PICODATA_PU_BUSY;
}
if (pam_deal_with(&(pam->inBuf[pam->inReadPos]))) {
/* item has to be managed by the "forward" state : switch to forward state*/
pam->procState = PICOPAM_FORWARD;
return PICODATA_PU_BUSY;
}
if (pam_hastobe_queued(this, &(pam->inBuf[pam->inReadPos]))) {
/* item is not for PAM so it has to be queued internally */
pam_queue(this, &(pam->inBuf[pam->inReadPos]));
/*consume the input item : it has been queued*/
pam->inReadPos += pam->inBuf[pam->inReadPos + 3]
+ sizeof(picodata_itemhead_t);
if (pam->inReadPos >= pam->inWritePos) {
pam->inReadPos = 0;
pam->inWritePos = 0;
}
return PICODATA_PU_BUSY;
}
/*if we get here something wrong happened. Being the the item valid,
switch to "immediate" state -> send it to next PU -> */
PICODBG_DEBUG(("pam_step (PICOPAM_SCHEDULE) -- unexpected item is sent to next PU !!"));
pam->procState = PICOPAM_IMMEDIATE;
return PICODATA_PU_BUSY;
break; /*PICOPAM_SCHEDULE*/
case PICOPAM_FORWARD:
/*we have one full valid item, with len>0 starting at pam->inBuf[pam->inReadPos].
furthermore this item should be in the set {BOUND,SYLL}.
No other items should arrive here*/
sResult = pam_adapter_forward_step(this,
&(pam->inBuf[pam->inReadPos]));
/*decide if this item has to be queued for later re-synchronization
normally this is only done for SEND/TERM items*/
if (pam_hastobe_queued(this, &(pam->inBuf[pam->inReadPos]))) {
/*item has to be queued iternally in local storage*/
pam_queue(this, &(pam->inBuf[pam->inReadPos]));
}
/*now assign next state according to Forward results*/
switch (sResult) {
case PICOPAM_READY:
pam->needMoreInput = FALSE;
/*consume the input item : it has already been stored*/
pam->inReadPos += pam->inBuf[pam->inReadPos + 3]
+ sizeof(picodata_itemhead_t);
if (pam->inReadPos >= pam->inWritePos) {
pam->inReadPos = 0;
pam->inWritePos = 0;
}
/*activate backward processing*/
sResult = pam_adapter_backward_step(this);
if (sResult == PICO_OK) {
pam->procState = PICOPAM_PROCESS;
return PICODATA_PU_BUSY;
} else {
PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD) -- wrong return from BackwardStep: %d -- Buffered sentence will be discarded",sResult));
pam_reset_processors(this);
pam->nLastAttachedItemId = pam->nCurrAttachedItem
= 0;
pam->nAttachedItemsSize = 0;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
}
break;
case PICOPAM_MORE:
pam->needMoreInput = TRUE;
/*consume the input item : it has already been stored*/
pam->inReadPos += pam->inBuf[pam->inReadPos + 3]
+ sizeof(picodata_itemhead_t);
if (pam->inReadPos >= pam->inWritePos) {
/*input is finished and PAM need more data :
clenaup input buffer + switch state back to "schedule state"
*/
pam->inReadPos = 0;
pam->inWritePos = 0;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_ATOMIC;
} else {
/*input is not finished and need more data :
remain in state "PICOPAM_FORWARD" */
return PICODATA_PU_ATOMIC;
}
break;
case PICOPAM_NA:
default:
/*this item has not been stored in internal buffers:
assign this item to the management of
"immediate" state*/
pam->procState = PICOPAM_IMMEDIATE;
return PICODATA_PU_BUSY;
break;
} /*end switch sResult*/
break; /*PICOPAM_FORWARD*/
case PICOPAM_FORWARD_FORCE_TERM:
/*we have one full valid item, with len>0
starting at pam->inBuf[pam->inReadPos] but we decided
to force a TERM item before, without losing the item in
inBuf[inReadPos] : --> generate a TERM item and do the
forward processing */
pam_put_term(bForcedItem, 0, &bWr);
sResult = pam_adapter_forward_step(this, &(bForcedItem[0]));
switch (sResult) {
case PICOPAM_READY:
pam_queue(this, &(bForcedItem[0]));
/*activate backward processing*/
sResult = pam_adapter_backward_step(this);
if (sResult == PICO_OK) {
pam->procState = PICOPAM_PROCESS;
return PICODATA_PU_BUSY;
} else {
PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD_FORCE_TERM) -- wrong return from BackwardStep: %d -- Buffered sentence will be discarded",sResult));
pam_reset_processors(this);
pam->nLastAttachedItemId = pam->nCurrAttachedItem
= 0;
pam->nAttachedItemsSize = 0;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
}
break;
default:
PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD_FORCE_TERM) -- Forced a TERM but processing do not appear to end -- Buffered sentence will be discarded",sResult));
pam_reset_processors(this);
pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0;
pam->nAttachedItemsSize = 0;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
break;
} /*end switch sResult*/
break; /*PICOPAM_FORWARD_FORCE_TERM*/
case PICOPAM_PROCESS:
if ((PICOPAM_FRAME_ITEM_SIZE + 4) > (pam->outBufSize
- pam->outWritePos)) {
/*WARNING (buffer overflow): leave status unchanged until output buffer free */
return PICODATA_PU_BUSY;
}
if (pam->nCurrSyllable == 0) {
sResult = pamDoPreSyll(this);
if (sResult == PICOPAM_GOTO_FEED) {
/*
items pushed to output buffer :
switch to "feed" but then back
to "process"
*/
pam->retState = PICOPAM_PROCESS;
pam->procState = PICOPAM_FEED;
return PICODATA_PU_BUSY;
}
if (sResult == PICOPAM_CONTINUE) {
/*
items processed (maybe commands) :
return (maybe we need to process other
items in pre_syll) and then back to "process"
*/
pam->retState = PICOPAM_PROCESS;
pam->procState = PICOPAM_PROCESS;
return PICODATA_PU_BUSY;
}
if ((sResult == PICOPAM_FLUSH_RECEIVED) || (sResult
== PICODATA_PU_ERROR)) {
/*
items processed were a flush or
problems found: switch to "schedule"
and abort all processing
*/
pam->retState = PICOPAM_SCHEDULE;
pam->procState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
}
if (sResult == PICOPAM_PRE_SYLL_ENDED) {
/*
we get here when pam->nCurrSyllable==0 and
no more items to be processed before the syllable
*/
sResult = sResult;
}
}
if (pamHasToProcess(this)) {
if (pamPhoneProcess(this) == PICO_OK) {
sResult = pamUpdateProcess(this);
pam->procState = PICOPAM_FEED; /*switch to feed*/
return PICODATA_PU_BUSY;
} else {
PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- NULL return from pamPhoneProcess"));
return PICODATA_PU_ERROR;
}
}
if (pamHasToPop(this) != FALSE) {
if ((qItem = pamPopItem(this)) == NULL) {
PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- NULL return from pamPopItem"));
return PICODATA_PU_ERROR;
}
if (isItemToPut(qItem)) {
/*popped item has to be sent to next PU*/
sResult = pam_put_qItem(qItem, pam->outBuf,
pam->outWritePos, &bWr);
if (sResult != PICO_OK) {
PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- Error on writing item to output buffer"));
return PICODATA_PU_ERROR;
}
pam->outWritePos += bWr; /*item write ok*/
pam->procState = PICOPAM_FEED; /*switch to feed*/
}
/*moved command processing here (after pam_put_qItem) because of FLUSH command could erase
* the syllable structure and make it impossible to transmit the flush to other PUs*/
if (is_pam_command(qItem) == TRUE) {
sResult = pamDoCommand(this, qItem); /*popped item is a PAM command : do it NOW!!*/
if ((sResult == PICOPAM_FLUSH_RECEIVED) || (sResult
== PICODATA_PU_ERROR)) {
pam->retState = PICOPAM_SCHEDULE;
pam->procState = PICOPAM_SCHEDULE; /*switch to schedule */
return PICODATA_PU_BUSY;
}
}
/*update PAM status: if more items attached to the current syllable
stay in current syllable, otherwise move to next syllable and switch
to processing phones */
sResult = pamUpdateProcess(this); /*both "doCommand" or "put" : update PAM status*/
return PICODATA_PU_BUSY;
} else {
pam->procState = PICOPAM_SCHEDULE; /*switch to schedule */
return PICODATA_PU_BUSY;
}
break; /*PICOPAM_PROCESS*/
case PICOPAM_IMMEDIATE:
/* *** item is output NOW!!! */
/*context: full valid item, with len> starting at pam->inBuf[pam->inReadPos]*/
numinb = PICODATA_ITEM_HEADSIZE
+ pam->inBuf[pam->inReadPos + 3];
sResult = picodata_copy_item(&(pam->inBuf[pam->inReadPos]),
numinb, &(pam->outBuf[pam->outWritePos]),
pam->outBufSize - pam->outWritePos, &numoutb);
if (sResult == PICO_OK) {
pam->inReadPos += numinb;
if (pam->inReadPos >= pam->inWritePos) {
pam->inReadPos = 0;
pam->inWritePos = 0;
pam->needMoreInput = FALSE;
}
pam->outWritePos += numoutb;
pam->procState = PICOPAM_FEED; /*switch to FEED state*/
pam->retState = PICOPAM_SCHEDULE; /*back to SCHEDULE after FEED*/
} else {
/*
PICO_EXC_BUF_IGNORE
PICO_EXC_BUF_UNDERFLOW
PICO_EXC_BUF_OVERFLOW
*/
PICODBG_DEBUG(("pam_step(PICOPAM_IMMEDIATE) --- wrong return from picodata_copy_item:%d",sResult));
return PICODATA_PU_ERROR;
}
return PICODATA_PU_BUSY;
break; /*PICOPAM_IMMEDIATE*/
case PICOPAM_FEED:
/* *************** item output/feeding ***********************************/
/*feeding items to PU output buffer*/
sResult = picodata_cbPutItem(this->cbOut,
&(pam->outBuf[pam->outReadPos]), pam->outWritePos
- pam->outReadPos, &numoutb);
PICODBG_DEBUG(("pam_step -- put item, status: %d",sResult));
if (PICO_OK == sResult) {
PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG],
(picoos_uint8 *)"pam: ",
pam->outBuf + pam->outReadPos, pam->outBufSize);
pam->outReadPos += numoutb;
*numBytesOutput = numoutb;
if (pam->outReadPos >= pam->outWritePos) {
/*reset the output pointers*/
pam->outReadPos = 0;
pam->outWritePos = 0;
/*switch to appropriate state*/
switch (pam->retState) {
case PICOPAM_IMMEDIATE:
pam->procState = PICOPAM_IMMEDIATE;
pam->retState = PICOPAM_SCHEDULE;
return PICODATA_PU_BUSY;
break;
case PICOPAM_PLAY:
pam->procState = PICOPAM_PLAY;
pam->retState = PICOPAM_SCHEDULE;