/* * 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 picodata.c * * 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 "picorsrc.h" #include "picotrns.h" #include "picodata.h" #ifdef __cplusplus extern "C" { #endif #if 0 } #endif /* we output coefficients as fixed point values */ #define PICOCEP_OUT_DATA_FORMAT PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FIXED /* *************************************************************** * CharBuffer * *****************************************************************/ /* * method signatures */ typedef pico_status_t (* picodata_cbPutItemMethod) (register picodata_CharBuffer this, const picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen); typedef pico_status_t (* picodata_cbGetItemMethod) (register picodata_CharBuffer this, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen, const picoos_uint8 issd); typedef pico_status_t (* picodata_cbSubResetMethod) (register picodata_CharBuffer this); typedef pico_status_t (* picodata_cbSubDeallocateMethod) (register picodata_CharBuffer this, picoos_MemoryManager mm); typedef struct picodata_char_buffer { picoos_char *buf; picoos_uint16 rear; /* next free position to write */ picoos_uint16 front; /* next position to read */ picoos_uint16 len; /* empty: len = 0, full: len = size */ picoos_uint16 size; picoos_Common common; picodata_cbGetItemMethod getItem; picodata_cbPutItemMethod putItem; picodata_cbSubResetMethod subReset; picodata_cbSubDeallocateMethod subDeallocate; void * subObj; } char_buffer_t; static pico_status_t data_cbPutItem(register picodata_CharBuffer this, const picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen); static pico_status_t data_cbGetItem(register picodata_CharBuffer this, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen, const picoos_uint8 issd); pico_status_t picodata_cbReset(register picodata_CharBuffer this) { this->rear = 0; this->front = 0; this->len = 0; if (NULL != this->subObj) { return this->subReset(this); } else { return PICO_OK; } } /* CharBuffer constructor */ picodata_CharBuffer picodata_newCharBuffer(picoos_MemoryManager mm, picoos_Common common, picoos_objsize_t size) { picodata_CharBuffer this; this = (picodata_CharBuffer) picoos_allocate(mm, sizeof(*this)); PICODBG_DEBUG(("new character buffer, size=%i", size)); if (NULL == this) { return NULL; } this->buf = picoos_allocate(mm, size); if (NULL == this->buf) { picoos_deallocate(mm, (void*) &this); return NULL; } this->size = size; this->common = common; this->getItem = data_cbGetItem; this->putItem = data_cbPutItem; this->subReset = NULL; this->subDeallocate = NULL; this->subObj = NULL; picodata_cbReset(this); return this; } void picodata_disposeCharBuffer(picoos_MemoryManager mm, picodata_CharBuffer *this) { if (NULL != (*this)) { /* terminate */ if (NULL != (*this)->subObj) { (*this)->subDeallocate(*this,mm); } picoos_deallocate(mm,(void*)&(*this)->buf); picoos_deallocate(mm,(void*)this); } } pico_status_t picodata_cbPutCh(register picodata_CharBuffer this, picoos_char ch) { if (this->len < this->size) { this->buf[this->rear++] = ch; this->rear %= this->size; this->len++; return PICO_OK; } else { return PICO_EXC_BUF_OVERFLOW; } } picoos_int16 picodata_cbGetCh(register picodata_CharBuffer this) { picoos_char ch; if (this->len > 0) { ch = this->buf[this->front++]; this->front %= this->size; this->len--; return ch; } else { return PICO_EOF; } } /* *************************************************************** * items: CharBuffer functions * *****************************************************************/ static pico_status_t data_cbGetItem(register picodata_CharBuffer this, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen, const picoos_uint8 issd) { picoos_uint16 i; if (this->len < PICODATA_ITEM_HEADSIZE) { /* item not in cb? */ *blen = 0; if (this->len == 0) { /* is cb empty? */ PICODBG_DEBUG(("no item to get")); return PICO_EOF; } else { /* cb not empty, but not a valid item */ PICODBG_WARN(("problem getting item, incomplete head, underflow")); } return PICO_EXC_BUF_UNDERFLOW; } *blen = PICODATA_ITEM_HEADSIZE + (picoos_uint8)(this->buf[((this->front) + PICODATA_ITEMIND_LEN) % this->size]); /* if getting speech data in item */ if (issd) { /* check item type */ if (this->buf[this->front] != PICODATA_ITEM_FRAME) { PICODBG_WARN(("item type mismatch for speech data: %c", this->buf[this->front])); for (i=0; i<*blen; i++) { this->front++; this->front %= this->size; this->len--; } *blen = 0; return PICO_OK; } } if (*blen > this->len) { /* item in cb not complete? */ PICODBG_WARN(("problem getting item, incomplete content, underflow; " "blen=%d, len=%d", *blen, this->len)); *blen = 0; return PICO_EXC_BUF_UNDERFLOW; } if (blenmax < *blen) { /* buf not large enough? */ PICODBG_WARN(("problem getting item, overflow")); *blen = 0; return PICO_EXC_BUF_OVERFLOW; } /* if getting speech data in item */ if (issd) { /* skip item header */ for (i = 0; i < PICODATA_ITEM_HEADSIZE; i++) { this->front++; this->front %= this->size; this->len--; } *blen -= PICODATA_ITEM_HEADSIZE; } /* all ok, now get item (or speech data only) */ for (i = 0; i < *blen; i++) { buf[i] = (picoos_uint8)(this->buf[this->front++]); this->front %= this->size; this->len--; } #if defined(PICO_DEBUG) if (issd) { PICODBG_DEBUG(("got speech data: %d samples", *blen)); } else { PICODBG_DEBUG(("got item: %c|%d|%d|%d||", buf[PICODATA_ITEMIND_TYPE], buf[PICODATA_ITEMIND_INFO1], buf[PICODATA_ITEMIND_INFO2], buf[PICODATA_ITEMIND_LEN])); for (i=PICODATA_ITEM_HEADSIZE; i<*blen; i++) { if (buf[PICODATA_ITEMIND_TYPE] == PICODATA_ITEM_WORDGRAPH) { PICODBG_DEBUG(("%c", buf[i])); } else { PICODBG_DEBUG((" %d", buf[i])); } } } #endif return PICO_OK; } static pico_status_t data_cbPutItem(register picodata_CharBuffer this, const picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) { picoos_uint16 i; if (blenmax < PICODATA_ITEM_HEADSIZE) { /* itemlen not accessible? */ PICODBG_WARN(("problem putting item, underflow")); *blen = 0; return PICO_EXC_BUF_UNDERFLOW; } *blen = buf[PICODATA_ITEMIND_LEN] + PICODATA_ITEM_HEADSIZE; if (*blen > (this->size - this->len)) { /* cb not enough space? */ PICODBG_WARN(("problem putting item, overflow")); *blen = 0; return PICO_EXC_BUF_OVERFLOW; } if (*blen > blenmax) { /* item in buf not completely accessible? */ PICODBG_WARN(("problem putting item, underflow")); *blen = 0; return PICO_EXC_BUF_UNDERFLOW; } /* all ok, now put complete item */ #if defined(PICO_DEBUG) PICODBG_DEBUG(("putting item: %c|%d|%d|%d||", buf[PICODATA_ITEMIND_TYPE], buf[PICODATA_ITEMIND_INFO1], buf[PICODATA_ITEMIND_INFO2], buf[PICODATA_ITEMIND_LEN])); for (i=PICODATA_ITEM_HEADSIZE; i<*blen; i++) { if (buf[PICODATA_ITEMIND_TYPE] == PICODATA_ITEM_WORDGRAPH) { PICODBG_DEBUG(("%c", buf[i])); } else { PICODBG_DEBUG((" %d", buf[i])); } } #endif for (i = 0; i < *blen; i++) { /* put single byte */ this->buf[this->rear++] = (picoos_char)buf[i]; this->rear %= this->size; this->len++; } return PICO_OK; } /*---------------------------------------------------------- * Names : picodata_cbGetItem * picodata_cbGetSpeechData * Function: gets one item from 'this' and writes it on 'blenmax' sized 'buf'. * gets one item from 'this' and writes the speech data to * 'blenmax' sized 'buf'. * Returns : PICO_OK : one item was copied * PICO_EOF : 'this' is empty; no new items available * PICO_BUF_UNDERFLOW : 'this' doesn't contain a full/valid item * PICO_BUF_OVERFLOW : 'buf[blenmax]' too small to hold item * on return, '*blen' contains the number of bytes written to 'buf' * ---------------------------------------------------------*/ pico_status_t picodata_cbGetItem(register picodata_CharBuffer this, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) { return this->getItem(this, buf, blenmax, blen, FALSE); } pico_status_t picodata_cbGetSpeechData(register picodata_CharBuffer this, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) { return this->getItem(this, buf, blenmax, blen, TRUE); } pico_status_t picodata_cbPutItem(register picodata_CharBuffer this, const picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) { return this->putItem(this,buf,blenmax,blen); } /* unsafe, just for measuring purposes */ picoos_uint8 picodata_cbGetFrontItemType(register picodata_CharBuffer this) { return this->buf[this->front]; } /* *************************************************************** * items: support function * *****************************************************************/ picoos_uint8 is_valid_itemtype(const picoos_uint8 ch) { switch (ch) { case PICODATA_ITEM_WSEQ_GRAPH: case PICODATA_ITEM_TOKEN: case PICODATA_ITEM_WORDGRAPH: case PICODATA_ITEM_WORDINDEX: case PICODATA_ITEM_WORDPHON: case PICODATA_ITEM_SYLLPHON: case PICODATA_ITEM_BOUND: case PICODATA_ITEM_PUNC: case PICODATA_ITEM_CMD: case PICODATA_ITEM_PHONE: case PICODATA_ITEM_FRAME: case PICODATA_ITEM_FRAME_PAR: return TRUE; break; case PICODATA_ITEM_OTHER: default: break; } PICODBG_WARN(("item type problem: %c", ch)); return FALSE; } picoos_uint8 picodata_is_valid_itemhead(const picodata_itemhead_t *head) { if ((NULL != head) && is_valid_itemtype(head->type)) { return TRUE; } else { PICODBG_WARN(("item header problem")); return FALSE; } } /* ***************************************************/ pico_status_t picodata_get_itemparts_nowarn( const picoos_uint8 *buf, const picoos_uint16 blenmax, picodata_itemhead_t *head, picoos_uint8 *content, const picoos_uint16 clenmax, picoos_uint16 *clen) { if (blenmax >= PICODATA_ITEM_HEADSIZE) { head->type = buf[PICODATA_ITEMIND_TYPE]; head->info1 = buf[PICODATA_ITEMIND_INFO1]; head->info2 = buf[PICODATA_ITEMIND_INFO2]; head->len = buf[PICODATA_ITEMIND_LEN]; *clen = head->len; if (blenmax >= (*clen + PICODATA_ITEM_HEADSIZE)) { if (clenmax >= head->len) { picoos_uint16 i; for (i=0; ilen; i++) { content[i] = buf[PICODATA_ITEM_HEADSIZE+i]; } return PICO_OK; } *clen = 0; return PICO_EXC_BUF_OVERFLOW; } } *clen = 0; return PICO_EXC_BUF_UNDERFLOW; } pico_status_t picodata_get_itemparts( const picoos_uint8 *buf, const picoos_uint16 blenmax, picodata_itemhead_t *head, picoos_uint8 *content, const picoos_uint16 clenmax, picoos_uint16 *clen) { pico_status_t status = picodata_get_itemparts_nowarn(buf,blenmax,head,content,clenmax,clen); if (PICO_EXC_BUF_OVERFLOW == status) { PICODBG_WARN(("problem getting item, overflow")); } else if (PICO_EXC_BUF_UNDERFLOW == status) { PICODBG_WARN(("problem getting item, overflow")); } return status; } pico_status_t picodata_put_itemparts(const picodata_itemhead_t *head, const picoos_uint8 *content, const picoos_uint16 clenmax, picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) { *blen = head->len + PICODATA_ITEM_HEADSIZE; if (blenmax >= *blen) { if (clenmax >= head->len) { picoos_uint16 i; buf[PICODATA_ITEMIND_TYPE] = head->type; buf[PICODATA_ITEMIND_INFO1] = head->info1; buf[PICODATA_ITEMIND_INFO2] = head->info2; buf[PICODATA_ITEMIND_LEN] = head->len; for (i=0; ilen; i++) { buf[PICODATA_ITEM_HEADSIZE+i] = content[i]; } return PICO_OK; } PICODBG_WARN(("problem putting item, underflow")); *blen = 0; return PICO_EXC_BUF_UNDERFLOW; } PICODBG_WARN(("problem putting item, overflow")); *blen = 0; return PICO_EXC_BUF_OVERFLOW; } pico_status_t picodata_get_iteminfo( picoos_uint8 *buf, const picoos_uint16 blenmax, picodata_itemhead_t *head, picoos_uint8 **content) { if (blenmax >= PICODATA_ITEM_HEADSIZE) { head->type = buf[PICODATA_ITEMIND_TYPE]; head->info1 = buf[PICODATA_ITEMIND_INFO1]; head->info2 = buf[PICODATA_ITEMIND_INFO2]; head->len = buf[PICODATA_ITEMIND_LEN]; if (head->len == 0) { *content = NULL; } else { *content = &buf[PICODATA_ITEM_HEADSIZE]; } return PICO_OK; } return PICO_EXC_BUF_UNDERFLOW; } pico_status_t picodata_copy_item(const picoos_uint8 *inbuf, const picoos_uint16 inlenmax, picoos_uint8 *outbuf, const picoos_uint16 outlenmax, picoos_uint16 *numb) { if (picodata_is_valid_item(inbuf, inlenmax)) { *numb = PICODATA_ITEM_HEADSIZE + inbuf[PICODATA_ITEMIND_LEN]; } else { *numb = 0; } if (*numb > 0) { if (outlenmax >= inlenmax) { picoos_uint16 i; for (i=0; i<*numb; i++) { outbuf[i] = inbuf[i]; } return PICO_OK; } else { PICODBG_WARN(("buffer problem, out: %d > in: %d", outlenmax, inlenmax)); *numb = 0; return PICO_EXC_BUF_OVERFLOW; } } else { PICODBG_WARN(("item problem in inbuf")); return PICO_ERR_OTHER; } } pico_status_t picodata_set_iteminfo1(picoos_uint8 *buf, const picoos_uint16 blenmax, const picoos_uint8 info) { if (PICODATA_ITEMIND_INFO1 < blenmax) { buf[PICODATA_ITEMIND_INFO1] = info; return PICO_OK; } else return PICO_EXC_BUF_UNDERFLOW; } pico_status_t picodata_set_iteminfo2(picoos_uint8 *buf, const picoos_uint16 blenmax, const picoos_uint8 info) { if (PICODATA_ITEMIND_INFO2 < blenmax) { buf[PICODATA_ITEMIND_INFO2] = info; return PICO_OK; } else return PICO_EXC_BUF_UNDERFLOW; } /* sets the len field in the header contained in the item in buf; return values: PICO_OK <- all ok PICO_EXC_BUF_UNDERFLOW <- underflow in buf */ pico_status_t picodata_set_itemlen(picoos_uint8 *buf, const picoos_uint16 blenmax, const picoos_uint8 len) { if (PICODATA_ITEMIND_LEN < blenmax) { buf[PICODATA_ITEMIND_LEN] = len; return PICO_OK; } else return PICO_EXC_BUF_UNDERFLOW; } picoos_uint8 picodata_is_valid_item(const picoos_uint8 *item, const picoos_uint16 ilenmax) { if (ilenmax >= PICODATA_ITEM_HEADSIZE) { picodata_itemhead_t head; head.type = item[0]; head.info1 = item[1]; head.info2 = item[2]; head.len = item[3]; if ((ilenmax >= (head.len + PICODATA_ITEM_HEADSIZE)) && picodata_is_valid_itemhead(&head)) { return TRUE; } } return FALSE; } /* *************************************************************** * ProcessingUnit * *****************************************************************/ picoos_uint16 picodata_get_default_buf_size (picodata_putype_t puType) { return (PICODATA_PUTYPE_TEXT == puType) ? PICODATA_BUFSIZE_TEXT : (PICODATA_PUTYPE_TOK == puType) ? PICODATA_BUFSIZE_TOK : (PICODATA_PUTYPE_PR == puType) ? PICODATA_BUFSIZE_PR : (PICODATA_PUTYPE_PR == puType) ? PICODATA_BUFSIZE_PR : (PICODATA_PUTYPE_WA == puType) ? PICODATA_BUFSIZE_WA : (PICODATA_PUTYPE_SA == puType) ? PICODATA_BUFSIZE_SA : (PICODATA_PUTYPE_ACPH == puType) ? PICODATA_BUFSIZE_ACPH : (PICODATA_PUTYPE_SPHO == puType) ? PICODATA_BUFSIZE_SPHO : (PICODATA_PUTYPE_PAM == puType) ? PICODATA_BUFSIZE_PAM : (PICODATA_PUTYPE_CEP == puType) ? PICODATA_BUFSIZE_CEP : (PICODATA_PUTYPE_SIG == puType) ? PICODATA_BUFSIZE_SIG : (PICODATA_PUTYPE_SINK == puType) ? PICODATA_BUFSIZE_SINK : PICODATA_BUFSIZE_DEFAULT; } typedef struct simple_pu_data { picorsrc_Voice voice; } simple_pu_data_t; static pico_status_t puSimpleInitialize (register picodata_ProcessingUnit this, picoos_int32 resetMode) { return PICO_OK; } static pico_status_t puSimpleTerminate (register picodata_ProcessingUnit this) { return PICO_OK; } static picodata_step_result_t puSimpleStep (register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput) { picoos_int16 ch; picoos_int16 result = PICO_OK; mode = mode; /*PP 13.10.08 : fix warning "var not used in this function"*/ *numBytesOutput = 0; while ((result == PICO_OK) && (ch = picodata_cbGetCh(this->cbIn)) != PICO_EOF) { result = picodata_cbPutCh(this->cbOut,(picoos_char) ch); (*numBytesOutput)++; } if (PICO_OK != result) { (*numBytesOutput)--; } if (PICO_OK == result) { return PICODATA_PU_IDLE; } else { return PICODATA_PU_ERROR; } } picodata_ProcessingUnit picodata_newProcessingUnit( picoos_MemoryManager mm, picoos_Common common, picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, picorsrc_Voice voice) { picodata_ProcessingUnit this = (picodata_ProcessingUnit) picoos_allocate(mm, sizeof(*this)); if (this == NULL) { picoos_emRaiseException(common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); return NULL; } this->common = common; this->cbIn = cbIn; this->cbOut = cbOut; this->voice = voice; this->initialize = puSimpleInitialize; this->terminate = puSimpleTerminate; this->step = puSimpleStep; this->subDeallocate = NULL; this->subObj = NULL; return this; } void picodata_disposeProcessingUnit( picoos_MemoryManager mm, picodata_ProcessingUnit * this) { if (NULL != (*this)) { /* terminate */ if (NULL != (*this)->subObj) { (*this)->subDeallocate(*this,mm); } picoos_deallocate(mm,(void *)this); } } picodata_CharBuffer picodata_getCbIn(picodata_ProcessingUnit this) { if (NULL == this) { picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); return NULL; } else { return this->cbIn; } } picodata_CharBuffer picodata_getCbOut(picodata_ProcessingUnit this) { if (NULL == this) { picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); return NULL; } else { return this->cbOut; } } pico_status_t picodata_setCbIn(picodata_ProcessingUnit this, picodata_CharBuffer cbIn) { if (NULL == this) { picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); return PICO_ERR_OTHER; } else { this->cbIn = cbIn; return PICO_OK; } } pico_status_t picodata_setCbOut(picodata_ProcessingUnit this, picodata_CharBuffer cbOut) { if (NULL == this) { picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); return PICO_ERR_OTHER; } else { this->cbOut = cbOut; return PICO_OK; } } /* *************************************************************** * auxiliary functions * *****************************************************************/ static void transDurUniform( picoos_uint8 frame_duration_exp, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */ picoos_int8 array_length, picoos_uint8 * inout, picoos_int16 inputdur, /* input duration in ms */ picoos_int16 targetdur, /* target duration in ms */ picoos_int16 * restdur /* in/out, rest in ms */ ) { picoos_int8 i; picoos_int32 fact, rest; /* calculate rest and factor in number of frames (in PICODATA_PICODATA_PRECISION) */ rest = (*restdur) << (PICODATA_PRECISION - frame_duration_exp); fact = (targetdur << (PICODATA_PRECISION - frame_duration_exp)) / inputdur; for (i = 0; i < array_length; i++) { rest += fact * inout[i]; /* instead of rounding, we carry the rest to the next state */ inout[i] = rest >> PICODATA_PRECISION; rest -= inout[i] << PICODATA_PRECISION; } (*restdur) = rest >> (PICODATA_PRECISION - frame_duration_exp); } static void transDurWeighted( picoos_uint8 frame_duration_exp, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */ picoos_int8 array_length, picoos_uint8 * inout, const picoos_uint16 * weight, /* integer weights */ picoos_int16 inputdur, /* input duration in ms */ picoos_int16 targetdur, /* target duration in ms */ picoos_int16 * restdur /* in/out, rest in ms */ ) { picoos_int8 i; picoos_int32 fact, rest, out, weighted_sum; /* calculate rest and factor in number of frames (in PICODATA_PICODATA_PRECISION) */ rest = (*restdur) << (PICODATA_PRECISION - frame_duration_exp); weighted_sum = 0; for (i=0; i < array_length; i++) { weighted_sum += inout[i] * weight[i]; } if (0 == weighted_sum) { transDurUniform(frame_duration_exp,array_length,inout,inputdur,targetdur,restdur); return; } /* get the additive change factor in PICODATA_PRECISION: */ if (targetdur > inputdur) { fact = ((targetdur - inputdur) << (PICODATA_PRECISION-frame_duration_exp))/ weighted_sum; } else { fact = -((inputdur - targetdur) << (PICODATA_PRECISION-frame_duration_exp))/ weighted_sum; } /* input[i] * fact * weight[i] is the additive modification in PICODATA_PRECISION */ for (i=0; i < array_length; i++) { rest += fact * inout[i] * weight[i]; /* instead of rounding, we carry the rest to the next state */ out = inout[i] + (rest >> PICODATA_PRECISION); if (out < 0) { out = 0; } rest -= ((out-inout[i]) << PICODATA_PRECISION); inout[i] = out; } (*restdur) = rest >> (PICODATA_PRECISION - frame_duration_exp); } void picodata_transformDurations( picoos_uint8 frame_duration_exp, picoos_int8 array_length, picoos_uint8 * inout, const picoos_uint16 * weight, /* integer weights */ picoos_int16 mintarget, /* minimum target duration in ms */ picoos_int16 maxtarget, /* maximum target duration in ms */ picoos_int16 facttarget, /* factor to be multiplied with original length to get the target the factor is fixed-point with PICODATA_PRECISION PICODATA_PRECISION, i.e. the factor as float would be facttarget / PICODATA_PRECISION_FACT if factor is 0, only min/max are considered */ picoos_int16 * dur_rest /* in/out, rest in ms */ ) { picoos_int32 inputdur, targetdur; picoos_int8 i; /* find the original duration in ms */ inputdur = 0; for (i=0; i < array_length; i++) { inputdur += inout[i]; } PICODBG_TRACE(("######## transforming duration fact=%i, limits = [%i,%i] (input frames: %i)",facttarget,mintarget,maxtarget, inputdur)); inputdur <<= frame_duration_exp; /* find the target duration */ if (facttarget) { targetdur = (facttarget * inputdur + PICODATA_PREC_HALF) >> PICODATA_PRECISION; } else { targetdur = inputdur; } /* we need to modify input if there is an explicit factor or input is not in the target range */ if (facttarget || (targetdur < mintarget) || (maxtarget < targetdur)) { /* make sure we are in the limits */ if (targetdur < mintarget) { targetdur = mintarget; } else if (maxtarget < targetdur) { targetdur = maxtarget; } /* perform modification */ if (NULL == weight) { transDurUniform(frame_duration_exp,array_length,inout,inputdur,targetdur,dur_rest); } else { transDurWeighted(frame_duration_exp,array_length,inout,weight,inputdur,targetdur,dur_rest); } } } extern picoos_uint8 picodata_getPuTypeFromExtension(picoos_uchar * filename, picoos_bool input) { if (input) { if (picoos_has_extension(filename, PICODATA_PUTYPE_TOK_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_TOK; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_PR_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_PR; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_WA_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_WA; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SA_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SA; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_ACPH_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_ACPH; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SPHO_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SPHO; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_PAM_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_PAM; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_CEP_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_CEP; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SIG_INPUT_EXTENSION) || picoos_has_extension(filename, PICODATA_PUTYPE_WAV_INPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SIG; } else { return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; } } else { if (picoos_has_extension(filename, PICODATA_PUTYPE_TOK_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_TOK; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_PR_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_PR; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_WA_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_WA; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SA_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SA; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_ACPH_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_ACPH; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SPHO_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SPHO; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_PAM_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_PAM; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_CEP_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_CEP; } else if (picoos_has_extension(filename, PICODATA_PUTYPE_SIG_OUTPUT_EXTENSION) || picoos_has_extension(filename, PICODATA_PUTYPE_WAV_OUTPUT_EXTENSION)) { return PICODATA_ITEMINFO2_CMD_TO_SIG; } else { return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; } } return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; } /** * * @param transducer * @param common * @param xsampa_parser * @param svoxpa_parser * @param xsampa2svoxpa_mapper * @param inputPhones * @param alphabet * @param outputPhoneIds * @param maxOutputPhoneIds * @return */ pico_status_t picodata_mapPAStrToPAIds(picotrns_SimpleTransducer transducer, picoos_Common common, picokfst_FST xsampa_parser, picokfst_FST svoxpa_parser, picokfst_FST xsampa2svoxpa_mapper, picoos_uchar * inputPhones, picoos_uchar * alphabet, picoos_uint8 * outputPhoneIds, picoos_int32 maxOutputPhoneIds) { pico_status_t status = PICO_OK; if (picoos_strcmp(alphabet, PICODATA_XSAMPA) == 0) { if ((NULL != xsampa_parser) && (NULL != xsampa2svoxpa_mapper)) { picotrns_stInitialize(transducer); status = picotrns_stAddWithPlane(transducer, inputPhones, PICOKFST_PLANE_ASCII); if (PICO_OK != status) { picoos_emRaiseWarning(common->em, status, NULL, (picoos_char *) "phoneme sequence too long (%s)", inputPhones); } else { status = picotrns_stTransduce(transducer, xsampa_parser); if (PICO_OK != status) { picoos_emRaiseWarning(common->em, status, NULL, (picoos_char *) "not recognized as xsampa (%s)", inputPhones); } else { status = picotrns_stTransduce(transducer, xsampa2svoxpa_mapper); if (PICO_OK != status) { picoos_emRaiseWarning(common->em, status, NULL, (picoos_char *) "illeagal phoneme sequence (%s)", inputPhones); } else { status = picotrns_stGetSymSequence(transducer, outputPhoneIds, maxOutputPhoneIds); } } } return status; } } else if (picoos_strcmp(alphabet, PICODATA_SVOXPA) == 0) { if ((NULL != svoxpa_parser)) { picotrns_stInitialize(transducer); status = picotrns_stAddWithPlane(transducer, inputPhones, PICOKFST_PLANE_ASCII); if (PICO_OK == status) { status = picotrns_stTransduce(transducer, svoxpa_parser); } if (PICO_OK == status) { status = picotrns_stGetSymSequence(transducer, outputPhoneIds, maxOutputPhoneIds); } return status; } } picoos_strlcpy(outputPhoneIds, (picoos_char *) "", maxOutputPhoneIds); picoos_emRaiseWarning(common->em, PICO_EXC_NAME_ILLEGAL, NULL, (picoos_char *) "alphabet not supported (%s)", alphabet); return PICO_EXC_NAME_ILLEGAL; } #if defined (PICO_DEBUG) /* *************************************************************** * For Debugging only * *****************************************************************/ /* put string representation of 'itemtype' into 'str' (allocated size 'strsize') * return 'str' */ static picoos_char * data_itemtype_to_string(const picoos_uint8 itemtype, picoos_char * str, picoos_uint16 strsize) { picoos_char * tmpstr; switch (itemtype) { case PICODATA_ITEM_BOUND: tmpstr = (picoos_char *)"BOUND"; break; case PICODATA_ITEM_FRAME_PAR: tmpstr = (picoos_char *)"FRAME_PAR"; break; case PICODATA_ITEM_PHONE: tmpstr = (picoos_char *)"PHONE"; break; case PICODATA_ITEM_CMD: tmpstr = (picoos_char *)"CMD"; break; case PICODATA_ITEM_ERR: tmpstr = (picoos_char *)"ERR"; break; case PICODATA_ITEM_FRAME: tmpstr = (picoos_char *)"FRAME"; break; case PICODATA_ITEM_OTHER: tmpstr = (picoos_char *)"OTHER"; break; case PICODATA_ITEM_PUNC: tmpstr = (picoos_char *)"PUNC"; break; case PICODATA_ITEM_SYLLPHON: tmpstr = (picoos_char *)"SYLLPHON"; break; case PICODATA_ITEM_WORDGRAPH: tmpstr = (picoos_char *)"WORDGRAPH"; break; case PICODATA_ITEM_WORDINDEX: tmpstr = (picoos_char *)"WORDINDEX"; break; case PICODATA_ITEM_WORDPHON: tmpstr = (picoos_char *)"WORDPHON"; break; case PICODATA_ITEM_WSEQ_GRAPH: tmpstr = (picoos_char *)"WSEQ_GRAPH"; break; default: tmpstr = (picoos_char *)"UNKNOWN"; break; } picopal_slprintf((picopal_char *) str, strsize, (picopal_char *)"%s", tmpstr); return str; } picoos_char * picodata_head_to_string(const picodata_itemhead_t *head, picoos_char * str, picoos_uint16 strsize) { picoos_uint16 typelen; if (NULL == head) { picoos_strlcpy(str,(picoos_char *)"[head is NULL]",strsize); } else { data_itemtype_to_string(head->type, str, strsize); typelen = picoos_strlen(str); picopal_slprintf((picopal_char *) str+typelen, strsize-typelen, (picopal_char *)"|%c|%c|%i", head->info1, head->info2, head->len); } return str; } void picodata_info_item(const picoknow_KnowledgeBase kb, const picoos_uint8 *pref6ch, const picoos_uint8 *item, const picoos_uint16 itemlenmax, const picoos_char *filterfn) { #define SA_USE_PHST 1 picoos_uint16 i; picoos_uint8 ch; if ((itemlenmax < 4) || (item == NULL)) { PICODBG_INFO_MSG(("invalid item\n")); } /* first 6 char used for prefix */ PICODBG_INFO_MSG_F(filterfn, ("%6s(", pref6ch)); /* type */ ch = item[0]; if ((32 <= ch) && (ch < 127)) { PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); } else { PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); } /* info1 */ ch = item[1]; if ((32 <= ch) && (ch < 127)) switch (item[0]) { case PICODATA_ITEM_PUNC: case PICODATA_ITEM_BOUND: case PICODATA_ITEM_CMD: case PICODATA_ITEM_TOKEN: case PICODATA_ITEM_FRAME_PAR: PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); break; default: PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); } else PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); /* info2 */ ch = item[2]; if ((32 <= ch) && (ch < 127)) switch (item[0]) { case PICODATA_ITEM_PUNC: case PICODATA_ITEM_BOUND: case PICODATA_ITEM_CMD: case PICODATA_ITEM_WORDPHON: case PICODATA_ITEM_SYLLPHON: PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); break; default: PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); } else PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); /* len */ ch = item[3]; PICODBG_INFO_MSG_F(filterfn, ("%3d)", ch)); for (i = 0; i < ch; i++) { if ((item[0] == PICODATA_ITEM_WSEQ_GRAPH) || (item[0] == PICODATA_ITEM_TOKEN) || (item[0] == PICODATA_ITEM_WORDGRAPH) || ((item[0] == PICODATA_ITEM_CMD) && !((item[1] == PICODATA_ITEMINFO1_CMD_SPEED) || (item[1] == PICODATA_ITEMINFO1_CMD_PITCH) || (item[1] == PICODATA_ITEMINFO1_CMD_VOLUME) || (item[1] == PICODATA_ITEMINFO1_CMD_SPELL) || (item[1] == PICODATA_ITEMINFO1_CMD_SIL)))) { PICODBG_INFO_MSG_F(filterfn, ("%c", item[4 + i])); } else { PICODBG_INFO_MSG_F(filterfn, ("%4d", item[4 + i])); } } #if defined (SA_USE_PHST) { #include "picokdbg.h" picoos_uint8 j; picokdbg_Dbg kdbg; kdbg = picokdbg_getDbg(kb); if ((item[0] == PICODATA_ITEM_WORDPHON) || (item[0] == PICODATA_ITEM_SYLLPHON) || ((item[0] == PICODATA_ITEM_CMD) && (item[1] == PICODATA_ITEMINFO1_CMD_PHONEME))) { if (picokdbg_getPhoneSym(kdbg, item[4])) { PICODBG_INFO_MSG_F(filterfn, (" ")); for (j = 0; j < item[3]; j++) { PICODBG_INFO_MSG_F(filterfn, ("%s", picokdbg_getPhoneSym(kdbg, item[4 + j]))); } } } } #endif PICODBG_INFO_MSG_F(filterfn, ("\n")); } #endif /* PICO_DEBUG */ #ifdef __cplusplus } #endif /* picodata.c end */