blob: 244e4b6ec19b1fb61dc14d5c4264a8ce61f87e45 [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 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; i<head->len; 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; i<head->len; 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) {
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 */