/* * 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 picosig.c * * Signal Generation PU - Implementation * * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland * All rights reserved. * * History: * - 2009-04-20 -- initial version * */ #include "picoos.h" #include "picodsp.h" #include "picosig2.h" #include "picodata.h" #include "picosig.h" #include "picodbg.h" #include "picokpdf.h" #ifdef __cplusplus extern "C" { #endif #if 0 } #endif #define PICOSIG_IN_BUFF_SIZE PICODATA_BUFSIZE_SIG /*input buffer size for SIG */ #define PICOSIG_OUT_BUFF_SIZE PICODATA_BUFSIZE_SIG /*output buffer size for SIG*/ #define PICOSIG_COLLECT 0 #define PICOSIG_SCHEDULE 1 #define PICOSIG_PLAY 2 #define PICOSIG_PROCESS 3 #define PICOSIG_FEED 4 /*---------------------------------------------------------- // Internal function declarations //---------------------------------------------------------*/ static picodata_step_result_t sigStep(register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput); /*---------------------------------------------------------- // Name : sig_subobj // Function: subobject definition for the sig processing // Shortcut: sig //---------------------------------------------------------*/ typedef struct sig_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 return after next processing step */ picoos_uint8 needMoreInput; /* more data necessary to start processing */ /*----------------------PU input management------------------------------*/ picoos_uint8 inBuf[PICOSIG_IN_BUFF_SIZE]; /* internal input buffer */ picoos_uint16 inBufSize;/* actually allocated size */ picoos_uint16 inReadPos, inWritePos; /* next pos to read/write from/to inBuf*/ /*Input audio file management*/ picoos_char sInSDFileName[255]; picoos_SDFile sInSDFile; picoos_uint32 sInSDFilePos; /*----------------------PU output management-----------------------------*/ picoos_uint8 outBuf[PICOSIG_OUT_BUFF_SIZE]; /* internal output buffer */ picoos_uint16 outBufSize; /* actually allocated size */ picoos_uint16 outReadPos, outWritePos; /* next pos to read/write from/to outBuf*/ picoos_bool outSwitch; /* output destination switch 0:buffer, 1:file*/ picoos_char sOutSDFileName[255]; /* output file name */ picoos_SDFile sOutSDFile; /* output file handle */ picoos_single fSampNorm; /* running normalization factor */ picoos_uint32 nNumFrame; /* running count for frame number in output items */ /*---------------------- other working variables ---------------------------*/ picoos_uint8 innerProcState; /*where to take up work at next processing step*/ /*-----------------------Definition of the local storage for this PU--------*/ sig_innerobj_t sig_inner; picoos_single pMod; /*pitch modifier*/ picoos_single vMod; /*Volume modifier*/ picoos_single sMod; /*speaker modifier*/ /*knowledge bases */ picokpdf_PdfMUL pdflfz, pdfmgc; picoos_uint32 scmeanpowLFZ, scmeanpowMGC; picoos_uint32 scmeanLFZ, scmeanMGC; picokpdf_PdfPHS pdfphs; } sig_subobj_t; /* ****************************************************************************** * generic PU management ********************************************************************************/ /** * initialization of the PU (processing unit) * @param this : sig PU object * @return PICO_OK : init ok * @return PICO_ERR_OTHER : init failed * @callgraph * @callergraph */ static pico_status_t sigInitialize(register picodata_ProcessingUnit this, picoos_int32 r_mode) { sig_subobj_t *sig_subObj; if (NULL == this || NULL == this->subObj) { return PICO_ERR_OTHER; } sig_subObj = (sig_subobj_t *) this->subObj; sig_subObj->inBufSize = PICOSIG_IN_BUFF_SIZE; sig_subObj->outBufSize = PICOSIG_OUT_BUFF_SIZE; sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; sig_subObj->outReadPos = 0; sig_subObj->outWritePos = 0; sig_subObj->needMoreInput = 0; sig_subObj->procState = PICOSIG_COLLECT; sig_subObj->retState = PICOSIG_COLLECT; sig_subObj->innerProcState = 0; sig_subObj->nNumFrame = 0; /*----------------------------------------------------------------- * MANAGE Item I/O control management ------------------------------------------------------------------*/ sig_subObj->sInSDFile = NULL; sig_subObj->sInSDFilePos = 0; sig_subObj->sInSDFileName[0] = '\0'; sig_subObj->outSwitch = 0; /*PU sends output to buffer (nextPU)*/ sig_subObj->sOutSDFile = NULL; sig_subObj->sOutSDFileName[0] = '\0'; sig_subObj->nNumFrame = 0; /*----------------------------------------------------------------- * MANAGE LINGWARE INITIALIZATION IF NEEDED ------------------------------------------------------------------*/ if (r_mode == PICO_RESET_FULL) { /*not done when resetting SOFT*/ sig_subObj->pdfmgc = picokpdf_getPdfMUL( this->voice->kbArray[PICOKNOW_KBID_PDF_MGC]); sig_subObj->pdflfz = picokpdf_getPdfMUL( this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]); sig_subObj->pdfphs = picokpdf_getPdfPHS( this->voice->kbArray[PICOKNOW_KBID_PDF_PHS]); sig_subObj->scmeanpowLFZ = sig_subObj->pdflfz->bigpow - sig_subObj->pdflfz->meanpow; sig_subObj->scmeanpowMGC = sig_subObj->pdfmgc->bigpow - sig_subObj->pdfmgc->meanpow; sig_subObj->scmeanLFZ = (1 << (picoos_uint32) sig_subObj->scmeanpowLFZ); sig_subObj->scmeanMGC = (1 << (picoos_uint32) sig_subObj->scmeanpowMGC); sig_subObj->fSampNorm = PICOSIG_NORM1 * sig_subObj->pdfmgc->amplif; /*----------------------------------------------------------------- * Initialize memory for DSP * ------------------------------------------------------------------*/ sigDspInitialize(&(sig_subObj->sig_inner), r_mode); /*----------------------------------------------------------------- * Initialize modifiers * ------------------------------------------------------------------*/ /*pitch , volume , speaker modifiers*/ sig_subObj->pMod = 1.0f; sig_subObj->vMod = 1.0f; sig_subObj->sMod = 1.0f; } else { /*----------------------------------------------------------------- * Initialize memory for DSP * ------------------------------------------------------------------*/ sigDspInitialize(&(sig_subObj->sig_inner), r_mode); } return PICO_OK; }/*sigInitialize*/ /** * terminates the PU (processing unit) * @param this : sig PU object * @return PICO_OK : termination ok * @return PICO_ERR_OTHER : termination failed * @callgraph * @callergraph */ static pico_status_t sigTerminate(register picodata_ProcessingUnit this) { sig_subobj_t *sig_subObj; if (NULL == this || NULL == this->subObj) { return PICO_ERR_OTHER; } sig_subObj = (sig_subobj_t *) this->subObj; return PICO_OK; }/*sigTerminate*/ /** * deallocates the PU (processing unit) sub object * @param this : sig PU object * @param mm : the engine memory manager * @return PICO_OK : deallocation ok * @return PICO_ERR_OTHER : deallocation failed * @callgraph * @callergraph */ static pico_status_t sigSubObjDeallocate(register picodata_ProcessingUnit this, picoos_MemoryManager mm) { sig_subobj_t *sig_subObj; if ((NULL == this) || ((this)->subObj == NULL)) { return PICO_ERR_OTHER; } sig_subObj = (sig_subobj_t *) (this)->subObj; if (sig_subObj->sInSDFile != NULL) { picoos_sdfCloseIn(this->common, &(sig_subObj->sInSDFile)); sig_subObj->sInSDFile = NULL; sig_subObj->sInSDFileName[0] = '\0'; } if (sig_subObj->sOutSDFile != NULL) { picoos_sdfCloseOut(this->common, &(sig_subObj->sOutSDFile)); sig_subObj->sOutSDFile = NULL; sig_subObj->sOutSDFileName[0] = '\0'; } sigDeallocate(mm, &(sig_subObj->sig_inner)); picoos_deallocate(this->common->mm, (void *) &this->subObj); return PICO_OK; }/*sigSubObjDeallocate*/ /** * creates a new sig processing unit * @param mm : the engine memory manager * @param common : the engine common object * @param cbIn : the PU input buffer * @param cbOut : the PU output buffer * @param voice : the voice descriptor object * @return a valid PU handle if creation is OK * @return NULL if creation is !=OK * @callgraph * @callergraph */ picodata_ProcessingUnit picosig_newSigUnit(picoos_MemoryManager mm, picoos_Common common, picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, picorsrc_Voice voice) { sig_subobj_t *sig_subObj; picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); if (NULL == this) { return NULL; } this->initialize = sigInitialize; PICODBG_DEBUG(("picosig_newSigUnit -- creating SIG PU")); /*Init function pointers*/ this->step = sigStep; this->terminate = sigTerminate; this->subDeallocate = sigSubObjDeallocate; /*sub obj allocation*/ this->subObj = picoos_allocate(mm, sizeof(sig_subobj_t)); if (NULL == this->subObj) { PICODBG_ERROR(("Error in Sig Object allocation")); picoos_deallocate(mm, (void *) &this); return NULL; } sig_subObj = (sig_subobj_t *) this->subObj; /*----------------------------------------------------------------- * Allocate memory for DSP inner algorithms * ------------------------------------------------------------------*/ if (sigAllocate(mm, &(sig_subObj->sig_inner)) != 0) { PICODBG_ERROR(("Error in Sig Sub Object Allocation")); picoos_deallocate(mm, (void *) &this); return NULL; } /*----------------------------------------------------------------- * Initialize memory for DSP (this may be re-used elsewhere, e.g.Reset) * ------------------------------------------------------------------*/ if (PICO_OK != sigInitialize(this, PICO_RESET_FULL)) { PICODBG_ERROR(("Error in iSig Sub Object initialization")); sigDeallocate(mm, &(sig_subObj->sig_inner)); picoos_deallocate(mm, (void *) &this); return NULL; }PICODBG_DEBUG(("SIG PU creation succeded!!")); return this; }/*picosig_newSigUnit*/ /** * pdf access for phase * @param this : sig object pointer * @param phsIndex : index of phase vectot in the pdf * @param phsVect : pointer to base of array where to store the phase values * @param numComponents : pointer to the variable to store the number of components * @return PICO_OK : pdf retrieved * @return PICO_ERR_OTHER : pdf not retrieved * @callgraph * @callergraph */ static pico_status_t getPhsFromPdf(register picodata_ProcessingUnit this, picoos_uint16 phsIndex, picoos_int32 *phsVect, picoos_int16 *numComponents) { sig_subobj_t *sig_subObj; picokpdf_PdfPHS pdf; static int nFrame = 0; picoos_uint32 nIndexValue; picoos_uint8 *nCurrIndexOffset, *nContent; picoos_uint16 nI; if (NULL == this || NULL == this->subObj) { return PICODATA_PU_ERROR; } sig_subObj = (sig_subobj_t *) this->subObj; pdf = sig_subObj->pdfphs; /*check incoming index*/ if (phsIndex >= pdf->numvectors) { return PICODATA_PU_ERROR; } nCurrIndexOffset = ((picoos_uint8*) pdf->indexBase) + phsIndex * sizeof(picoos_uint32); nIndexValue = (0xFF000000 & ((*(nCurrIndexOffset+3)) << 24)) | (0x00FF0000 & ((*(nCurrIndexOffset+2)) << 16)) | (0x0000FF00 & ((*(nCurrIndexOffset+1)) << 8)) | (0x000000FF & ((*nCurrIndexOffset))); nContent = pdf->contentBase; nContent += nIndexValue; *numComponents = (picoos_int16) *nContent++; if (*numComponents>PICODSP_PHASEORDER) { PICODBG_DEBUG(("WARNING : Frame %d -- Phase vector[%d] Components = %d --> too big\n", nFrame, phsIndex, *numComponents)); *numComponents = PICODSP_PHASEORDER; } for (nI=0; nI<*numComponents; nI++) { phsVect[nI] = (picoos_int32) *nContent++; } for (nI=*numComponents; nIsubObj; numinb = numinb; /* avoid warning "var not used in this function"*/ /*defaults to 0 for output bytes*/ *numoutb = 0; /*Input buffer contains an item FRAME_PAR*/ switch (sig_subObj->innerProcState) { case 0: /*--------------------------------------------- Shifting old values ---------------------------------------------*/ for (n_count = 0; n_count < CEPST_BUFF_SIZE-1; n_count++) { sig_subObj->sig_inner.F0Buff[n_count]=sig_subObj->sig_inner.F0Buff[n_count+1]; sig_subObj->sig_inner.PhIdBuff[n_count]=sig_subObj->sig_inner.PhIdBuff[n_count+1]; sig_subObj->sig_inner.VoicingBuff[n_count]=sig_subObj->sig_inner.VoicingBuff[n_count+1]; sig_subObj->sig_inner.FuVBuff[n_count]=sig_subObj->sig_inner.FuVBuff[n_count+1]; } for (n_count = 0; n_count < PHASE_BUFF_SIZE-1; n_count++) { sig_subObj->sig_inner.VoxBndBuff[n_count]=sig_subObj->sig_inner.VoxBndBuff[n_count+1]; } tmp1 = sig_subObj->sig_inner.CepBuff[0]; for (n_count = 0; n_count < CEPST_BUFF_SIZE-1; n_count++) { sig_subObj->sig_inner.CepBuff[n_count]=sig_subObj->sig_inner.CepBuff[n_count+1]; } sig_subObj->sig_inner.CepBuff[CEPST_BUFF_SIZE-1]=tmp1; tmp1 = sig_subObj->sig_inner.PhsBuff[0]; for (n_count = 0; n_count < PHASE_BUFF_SIZE-1; n_count++) { sig_subObj->sig_inner.PhsBuff[n_count]=sig_subObj->sig_inner.PhsBuff[n_count+1]; } sig_subObj->sig_inner.PhsBuff[PHASE_BUFF_SIZE-1]=tmp1; /*--------------------------------------------- Frame related initializations ---------------------------------------------*/ sig_subObj->sig_inner.prevVoiced_p = sig_subObj->sig_inner.voiced_p; /*--------------------------------------------- Get input data from PU buffer in internal buffers -------------------------------------------------*/ /*load the phonetic id code*/ picoos_mem_copy((void *) &sig_subObj->inBuf[inReadPos + sizeof(picodata_itemhead_t)], /*src*/ (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ sig_subObj->sig_inner.PhIdBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16; /*store into newest*/ tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.PhIdBuff[0]; /*assign oldest*/ sig_subObj->sig_inner.phId_p = (picoos_int16) tmp_uint16; /*assign oldest*/ /*load pitch values*/ for (i = 0; i < sig_subObj->pdflfz->ceporder; i++) { picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 * i * sizeof(tmp_uint16)]), /*src*/ (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ sig_subObj->sig_inner.F0Buff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.F0Buff[0]; /*assign oldest*/ /*convert in float*/ sig_subObj->sig_inner.F0_p = (tmp_uint16 ? ((picoos_single) tmp_uint16 / sig_subObj->scmeanLFZ) : (picoos_single) 0.0); if (sig_subObj->sig_inner.F0_p != (picoos_single) 0.0f) { sig_subObj->sig_inner.F0_p = (picoos_single) exp( (picoos_single) sig_subObj->sig_inner.F0_p); } /* voicing */ picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 * i * sizeof(tmp_uint16) + sizeof(tmp_uint16)]),/*src*/ (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ sig_subObj->sig_inner.VoicingBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.VoicingBuff[0]; /*assign oldest*/ sig_subObj->sig_inner.voicing = (picoos_single) ((tmp_uint16 & 0x01) * 8 + (tmp_uint16 & 0x0e) / 2) / (picoos_single) 15.0f; /* unrectified f0 */ picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 * i * sizeof(tmp_uint16) + 2 * sizeof(tmp_uint16)]),/*src*/ (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ sig_subObj->sig_inner.FuVBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.FuVBuff[0]; /*assign oldest*/ sig_subObj->sig_inner.Fuv_p = (picoos_single) tmp_uint16 / sig_subObj->scmeanLFZ; sig_subObj->sig_inner.Fuv_p = (picoos_single) EXP((double)sig_subObj->sig_inner.Fuv_p); } /*load cep values*/ offset = inReadPos + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 * sig_subObj->pdflfz->ceporder * sizeof(tmp_int16); tmp1 = sig_subObj->sig_inner.CepBuff[CEPST_BUFF_SIZE-1]; /*store into CURR */ tmp2 = sig_subObj->sig_inner.CepBuff[0]; /*assign oldest*/ for (i = 0; i < sig_subObj->pdfmgc->ceporder; i++) { picoos_mem_copy((void *) &(sig_subObj->inBuf[offset + i * sizeof(tmp_int16)]), /*src*/ (void *) &tmp_int16, sizeof(tmp_int16)); /*dest+size*/ tmp1 [i] = (picoos_int32) tmp_int16; sig_subObj->sig_inner.wcep_pI[i] = (picoos_int32) tmp2[i]; } if (sig_subObj->inBuf[inReadPos+ 3] > sig_subObj->inBuf[inReadPos+ 2]*2 + 8) { /*load phase values*/ /*get the index*/ picoos_mem_copy((void *) &(sig_subObj->inBuf[offset + sig_subObj->pdfmgc->ceporder * sizeof(tmp_int16)]), /*src*/ (void *) &tmp_int16, sizeof(tmp_int16)); /*dest+size*/ /*store into buffers*/ tmp1 = sig_subObj->sig_inner.PhsBuff[PHASE_BUFF_SIZE-1]; /*retrieve values from pdf*/ getPhsFromPdf(this, tmp_int16, tmp1, &(sig_subObj->sig_inner.VoxBndBuff[PHASE_BUFF_SIZE-1])); } else { /* no support for phase found */ sig_subObj->sig_inner.VoxBndBuff[PHASE_BUFF_SIZE-1] = 0; } /*pitch modifier*/ sig_subObj->sig_inner.F0_p *= sig_subObj->pMod; sig_subObj->sig_inner.Fuv_p *= sig_subObj->pMod; if (sig_subObj->sig_inner.F0_p > 0.0f) { sig_subObj->sig_inner.voiced_p = 1; } else { sig_subObj->sig_inner.voiced_p = 0; } sig_subObj->sig_inner.n_available++; if (sig_subObj->sig_inner.n_available>3) sig_subObj->sig_inner.n_available = 3; if (sig_subObj->sig_inner.n_available < 3) { return PICO_STEP_BUSY; } sig_subObj->innerProcState = 3; return PICO_STEP_BUSY; case 3: /*Convert from mfcc to power spectrum*/ save_transition_frame(&(sig_subObj->sig_inner)); mel_2_lin_lookup(&(sig_subObj->sig_inner), sig_subObj->scmeanpowMGC); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 4: /*Reconstruct PHASE SPECTRUM */ phase_spec2(&(sig_subObj->sig_inner)); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 5: /*Prepare Envelope spectrum for inverse FFT*/ env_spec(&(sig_subObj->sig_inner)); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 6: /*Generate the impulse response of the vocal tract */ impulse_response(&(sig_subObj->sig_inner)); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 7: /*Sum up N impulse responses according to excitation */ td_psola2(&(sig_subObj->sig_inner)); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 8: /*Ovladd */ overlap_add(&(sig_subObj->sig_inner)); sig_subObj->innerProcState += 1; return PICO_STEP_BUSY; case 9: /*----------------------------------------- Save the output FRAME item (0:hop-1) swap remaining buffer ---------------------------------------------*/ n_frames = 2; *numoutb = 0; hop_p_half = (sig_subObj->sig_inner.hop_p) / 2; for (n_count = 0; n_count < n_frames; n_count++) { sig_subObj->outBuf[outWritePos] = (picoos_uint8) PICODATA_ITEM_FRAME; sig_subObj->outBuf[outWritePos + 1] = (picoos_uint8) (hop_p_half); sig_subObj->outBuf[outWritePos + 2] = (picoos_uint8) (sig_subObj->nNumFrame % ((hop_p_half))); sig_subObj->outBuf[outWritePos + 3] = (picoos_uint8) sig_subObj->sig_inner.hop_p; s_data = (picoos_int16 *) &(sig_subObj->outBuf[outWritePos + 4]); /*range control and clipping*/ mlt = (picoos_int32) ((sig_subObj->fSampNorm * sig_subObj->vMod) * PICODSP_END_FLOAT_NORM); t1 = &(sig_subObj->sig_inner.WavBuff_p[n_count * (hop_p_half)]); for (n_i = 0; n_i < hop_p_half; n_i++) { /*Normalization*/ f_data = *t1++ * mlt; if (f_data >= 0) f_data >>= 14; else f_data = -(-f_data >> 14); if (f_data > PICOSIG_MAXAMP) f_data = PICOSIG_MAXAMP; if (f_data < PICOSIG_MINAMP) f_data = PICOSIG_MINAMP; *s_data = (picoos_int16) (f_data); s_data++; } sig_subObj->nNumFrame = sig_subObj->nNumFrame + 1; *numoutb += ((picoos_int16) n_i * sizeof(picoos_int16)) + 4; outWritePos += *numoutb; }/*end for n_count*/ /*Swap remaining buffer*/ cnt = sig_subObj->sig_inner.m2_p - sig_subObj->sig_inner.hop_p; tmp1 = sig_subObj->sig_inner.WavBuff_p; tmp2 = &(sig_subObj->sig_inner.WavBuff_p[sig_subObj->sig_inner.hop_p]); FAST_DEVICE(cnt,*(tmp1++)=*(tmp2++);) ; cnt = sig_subObj->sig_inner.m2_p - (sig_subObj->sig_inner.m2_p - sig_subObj->sig_inner.hop_p); FAST_DEVICE(cnt,*(tmp1++)=0;) ; sig_subObj->innerProcState = 0; /*reset to step 0*/ sig_subObj->nNumFrame += 2; return PICO_OK; default: return PICO_ERR_OTHER; } return PICO_ERR_OTHER; }/*sigProcess*/ /** * selects items to be dealth with by this PU * @param item : pointer to current item head * @return TRUE : item should be managed * @return FALSE : item should be passed on next PU * @remarks item pointed to by *item should be already valid * @callgraph * @callergraph */ static pico_status_t sig_deal_with(const picoos_uint8 *item) { picodata_itemhead_t head; pico_status_t s_result; s_result = FALSE; head.type = item[0]; head.info1 = item[1]; head.info2 = item[2]; head.len = item[3]; switch (head.type) { case PICODATA_ITEM_FRAME_PAR: /*the only item that is managed by sig, so far, is "FRAME_PAR"*/ s_result = TRUE; break; case PICODATA_ITEM_CMD: if ((head.info1 == PICODATA_ITEMINFO1_CMD_PLAY) || (head.info1 == PICODATA_ITEMINFO1_CMD_SAVE) || (head.info1 == PICODATA_ITEMINFO1_CMD_UNSAVE)) { if (head.info2 == PICODATA_ITEMINFO2_CMD_TO_SIG) { return TRUE; } } if ((head.info1 == PICODATA_ITEMINFO1_CMD_PITCH) || (head.info1 == PICODATA_ITEMINFO1_CMD_VOLUME) || (head.info1 == PICODATA_ITEMINFO1_CMD_SPEAKER)) { return TRUE; } break; default: break; } return s_result; } /*sig_deal_with*/ /** * selects items to be managed as commands by this PU * @param item : pointer to current item head * @return TRUE : item should be managed as a command * @return FALSE : item is not a PU command * @remarks item pointed to by *item should be already valid * @callgraph * @callergraph */ static pico_status_t sig_is_command(const picoos_uint8 *item) { picodata_itemhead_t head; head.type = item[0]; head.info1 = item[1]; head.info2 = item[2]; head.len = item[3]; switch (head.type) { case PICODATA_ITEM_CMD: if ((head.info1 == PICODATA_ITEMINFO1_CMD_PLAY) || (head.info1 == PICODATA_ITEMINFO1_CMD_SAVE) || (head.info1 == PICODATA_ITEMINFO1_CMD_UNSAVE)) { if (head.info2 == PICODATA_ITEMINFO2_CMD_TO_SIG) { return TRUE; } } if ((head.info1 == PICODATA_ITEMINFO1_CMD_PITCH) || (head.info1 == PICODATA_ITEMINFO1_CMD_VOLUME) || (head.info1 == PICODATA_ITEMINFO1_CMD_SPEAKER)) { return TRUE; } break; default: break; } return FALSE; } /*sig_is_command*/ /** * performs a step of the sig processing * @param this : pointer to current PU (Control Unit) * @param mode : mode for the PU * @param numBytesOutput : pointer to number of bytes produced (output) * @param this : pointer to current PU (Control Unit) * @return one of the "picodata_step_result_t" values * @callgraph * @callergraph */ static picodata_step_result_t sigStep(register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput) { register sig_subobj_t * sig_subObj; pico_status_t s_result; picoos_bool b_res; pico_status_t s_deal_with; picoos_uint16 blen; picoos_uint16 numinb, numoutb; pico_status_t rv; picoos_int16 *s_data; picoos_int16 hop_p_half; picoos_uint32 n_samp, n_i; picoos_char s_temp_file_name[255]; picoos_uint32 n_start, n_fram, n_bytes; picoos_single f_value; picoos_uint16 n_value; picoos_uint32 n_pos; /*wav file play volume control*/ picoos_int16 *s_t1; picoos_int32 sf_data, sf_mlt; picoos_uint32 sf; picoos_encoding_t enc; picoos_uint32 numSamples; numinb = 0; numoutb = 0; rv = PICO_OK; s_result = PICO_OK; if (NULL == this || NULL == this->subObj) { return PICODATA_PU_ERROR; } sig_subObj = (sig_subobj_t *) this->subObj; /*Init number of output bytes*/ *numBytesOutput = 0; mode = mode; /* avoid warning "var not used in this function" */ while (1) { /* exit via return */ PICODBG_DEBUG(("picosig.sigStep -- doing state %i",sig_subObj->procState)); switch (sig_subObj->procState) { case PICOSIG_COLLECT: /* ************** item collector ***********************************/ /*collecting items from the PU input buffer*/ s_result = picodata_cbGetItem(this->cbIn, &(sig_subObj->inBuf[sig_subObj->inWritePos]), sig_subObj->inBufSize - sig_subObj->inWritePos, &blen); PICODBG_DEBUG(("picosig.sigStep -- got item, status: %d",rv)); if (s_result == PICO_EOF) { /*no items available : remain in state 0 and return idle*/ return PICODATA_PU_IDLE; } if ((PICO_OK == s_result) && (blen > 0)) { /* we now have one item : CHECK IT */ s_result = picodata_is_valid_item( &(sig_subObj->inBuf[sig_subObj->inWritePos]), blen); if (s_result != TRUE) { PICODBG_DEBUG(("picosig.sigStep -- item is not valid: discard")); /*Item not valid : remain in state PICOSIG_COLLECT*/ return PICODATA_PU_BUSY; } /*item ok: it could be sent to schedule state*/ sig_subObj->inWritePos += blen; sig_subObj->needMoreInput = FALSE; sig_subObj->procState = PICOSIG_SCHEDULE; /* uncomment next to split into two steps */ return PICODATA_PU_ATOMIC; } /*no EOF, no OK --> errors : remain in state PICOSIG_COLLECT and return error*/ return PICODATA_PU_ERROR; break; case PICOSIG_SCHEDULE: /* *************** item processing ***********************************/ numinb = PICODATA_ITEM_HEADSIZE + sig_subObj->inBuf[sig_subObj->inReadPos + 3]; /*verify that current item has to be dealth with by this PU*/ s_deal_with = sig_deal_with( &(sig_subObj->inBuf[sig_subObj->inReadPos])); switch (s_deal_with) { case TRUE: /* we have to manage this item */ if (FALSE == sig_is_command( &(sig_subObj->inBuf[sig_subObj->inReadPos]))) { /*no commands, item to deal with : switch to process state*/ sig_subObj->procState = PICOSIG_PROCESS; sig_subObj->retState = PICOSIG_COLLECT; return PICODATA_PU_BUSY; /*data still to process or to feed*/ } else { /*we need to manage this item as a SIG command-item*/ switch (sig_subObj->inBuf[sig_subObj->inReadPos + 1]) { case PICODATA_ITEMINFO1_CMD_PLAY: /*CMD recognized : consume the command */ sig_subObj->inReadPos += numinb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; } /*default next state setting*/ sig_subObj->procState = sig_subObj->retState = PICOSIG_COLLECT; /*--------- wav file play management --------------*/ if (sig_subObj->sInSDFile != NULL) { /*input wav file is already open : return*/ return PICODATA_PU_BUSY; } /*get temp file name*/ picoos_strlcpy( (picoos_char*) s_temp_file_name, (picoos_char*) &(sig_subObj->inBuf[sig_subObj->inReadPos + 4]), sig_subObj->inBuf[sig_subObj->inReadPos + 3] + 1); /*avoid input/output file name clashes*/ if (sig_subObj->sOutSDFile != NULL) { if (picoos_strncmp( (picoos_char*) s_temp_file_name, (picoos_char*) sig_subObj->sOutSDFileName, picoos_strlen( (picoos_char*) s_temp_file_name)) == 0) { PICODBG_WARN(("input and output files has the same name!\n")); return PICODATA_PU_BUSY; } } /*actual sampled data file open*/ b_res = picoos_sdfOpenIn(this->common, &(sig_subObj->sInSDFile), s_temp_file_name, &sf, &enc, &numSamples); if (b_res != TRUE) { PICODBG_DEBUG(("Error on opening file %s\n", s_temp_file_name)); sig_subObj->sInSDFile = NULL; sig_subObj->sInSDFileName[0] = '\0'; return PICODATA_PU_BUSY; } /*input file handle is now valid : store filename*/ picoos_strlcpy( (picoos_char*) sig_subObj->sInSDFileName, (picoos_char*) s_temp_file_name, sig_subObj->inBuf[sig_subObj->inReadPos + 3] + 1); sig_subObj->sInSDFilePos = 0; /*switch to state PLAY and return*/ sig_subObj->procState = sig_subObj->retState = PICOSIG_PLAY; return PICODATA_PU_BUSY; break; case PICODATA_ITEMINFO1_CMD_SAVE: /*CMD recognized : consume the command */ sig_subObj->inReadPos += numinb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; } /*prepare return state*/ sig_subObj->procState = PICOSIG_COLLECT; sig_subObj->retState = PICOSIG_COLLECT; /*check about output file*/ if ((sig_subObj->sOutSDFile != NULL) || (sig_subObj->outSwitch == 1)) { /*output sig file is already active : return*/ return PICODATA_PU_BUSY; } /*get temp file name*/ picoos_strlcpy( (picoos_char*) s_temp_file_name, (picoos_char*) &(sig_subObj->inBuf[sig_subObj->inReadPos + 4]), sig_subObj->inBuf[sig_subObj->inReadPos + 3] + 1); /*check extension*/ if (picoos_has_extension(s_temp_file_name, PICODATA_PUTYPE_WAV_OUTPUT_EXTENSION) == FALSE){ /*extension unsupported : return*/ return PICODATA_PU_BUSY; } /*avoid input/output file name clashes*/ if (sig_subObj->sInSDFile != NULL) { if (picoos_strncmp( (picoos_char*) sig_subObj->sInSDFileName, (picoos_char*) s_temp_file_name, picoos_strlen( (picoos_char*) sig_subObj->sInSDFileName)) == 0) { /*input and output files has the same name : do not allow opening for writing*/ PICODBG_WARN(("input and output files has the same name!\n")); return PICODATA_PU_BUSY; } } /*try to open*/ picoos_sdfOpenOut(this->common, &(sig_subObj->sOutSDFile), s_temp_file_name, SAMPLE_FREQ_16KHZ, PICOOS_ENC_LIN); if (sig_subObj->sOutSDFile == NULL) { PICODBG_DEBUG(("Error on opening file %s\n", sig_subObj->sOutSDFileName)); sig_subObj->outSwitch = 0; sig_subObj->sOutSDFileName[0] = '\0'; } else { /*open OK*/ sig_subObj->outSwitch = 1; /*store output filename*/ picoos_strlcpy( (picoos_char*) sig_subObj->sOutSDFileName, (picoos_char*) s_temp_file_name, sig_subObj->inBuf[sig_subObj->inReadPos + 3] + 1); } return PICODATA_PU_BUSY; break; case PICODATA_ITEMINFO1_CMD_UNSAVE: /*CMD recognized : consume the command */ sig_subObj->inReadPos += numinb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; } /*prepare return state*/ sig_subObj->procState = PICOSIG_COLLECT; sig_subObj->retState = PICOSIG_COLLECT; /*close the output file if any*/ if ((sig_subObj->sOutSDFile == NULL) || (sig_subObj->outSwitch == 0)) { /*output sig file is not active : return*/ PICODBG_DEBUG(("Error on requesting a binary samples file output closing : no file output handle exist\n")); return PICODATA_PU_BUSY; } picoos_sdfCloseOut(this->common, &(sig_subObj->sOutSDFile)); sig_subObj->outSwitch = 0; sig_subObj->sOutSDFile = NULL; sig_subObj->sOutSDFileName[0] = '\0'; return PICODATA_PU_BUSY; break; case PICODATA_ITEMINFO1_CMD_PITCH: case PICODATA_ITEMINFO1_CMD_VOLUME: case PICODATA_ITEMINFO1_CMD_SPEAKER: n_pos = 4; picoos_read_mem_pi_uint16( &(sig_subObj->inBuf[sig_subObj->inReadPos]), &n_pos, &n_value); b_res = FALSE; switch (sig_subObj->inBuf[sig_subObj->inReadPos + 2]) { case 'a' : /*absloute modifier*/ f_value = (picoos_single) n_value / (picoos_single) 100.0f; b_res = TRUE; break; case 'r' : /*relative modifier*/ f_value = (picoos_single) n_value / (picoos_single) 1000.0f; b_res = TRUE; break; default : f_value = (picoos_single)0; /*avoid warnings*/ break; } if (b_res) { switch (sig_subObj->inBuf[sig_subObj->inReadPos + 1]) { case PICODATA_ITEMINFO1_CMD_PITCH : sig_subObj->pMod = f_value; break; case PICODATA_ITEMINFO1_CMD_VOLUME : sig_subObj->vMod = f_value; break; case PICODATA_ITEMINFO1_CMD_SPEAKER : sig_subObj->sMod = f_value; sig_subObj->sig_inner.sMod_p = sig_subObj->sMod; /*call the function needed to initialize the speaker factor*/ mel_2_lin_init( &(sig_subObj->sig_inner)); break; default : break; } } /*CMD recognized : consume the command */ sig_subObj->inReadPos += numinb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; } /*prepare proc state*/ sig_subObj->procState = PICOSIG_COLLECT; sig_subObj->retState = PICOSIG_COLLECT; return PICODATA_PU_BUSY; break; default: break; }/*switch command type*/ } /*end if is command*/ break; case FALSE: /*we DO NOT have to deal with this item on this PU. * Normally these are still alive boundary or flush items*/ /*copy item from PU input to PU output buffer, * i.e. make it ready to FEED*/ s_result = picodata_copy_item( &(sig_subObj->inBuf[sig_subObj->inReadPos]), numinb, &(sig_subObj->outBuf[sig_subObj->outWritePos]), sig_subObj->outBufSize - sig_subObj->outWritePos, &numoutb); if (s_result != PICO_OK) { /*item not prepared properly to be sent to next PU : * do not change state and retry next time*/ sig_subObj->procState = PICOSIG_SCHEDULE; sig_subObj->retState = PICOSIG_COLLECT; return PICODATA_PU_BUSY; /*data still to process or to feed*/ } /*if end of sentence reset number of frames(only needed for debugging purposes)*/ if ((sig_subObj->inBuf[sig_subObj->inReadPos] == PICODATA_ITEM_BOUND) && ((sig_subObj->inBuf[sig_subObj->inReadPos + 1] == PICODATA_ITEMINFO1_BOUND_SEND) || (sig_subObj->inBuf[sig_subObj->inReadPos + 1] == PICODATA_ITEMINFO1_BOUND_TERM))) { PICODBG_INFO(("End of sentence - Processed frames : %d", sig_subObj->nNumFrame)); sig_subObj->nNumFrame = 0; } /*item processed and put in oputput buffer : consume the item*/ sig_subObj->inReadPos += numinb; sig_subObj->outWritePos += numoutb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { /* inBuf exhausted */ sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; sig_subObj->needMoreInput = FALSE; } sig_subObj->procState = PICOSIG_FEED; sig_subObj->retState = PICOSIG_COLLECT; return PICODATA_PU_BUSY; /*data still to process or to feed*/ break; default: break; }/*end switch s_deal_with*/ break; /*end case sig_schedule*/ case PICOSIG_PROCESS: /* *************** item processing ***********************************/ numinb = PICODATA_ITEM_HEADSIZE + sig_subObj->inBuf[sig_subObj->inReadPos + 3]; /*Process a full item*/ s_result = sigProcess(this, sig_subObj->inReadPos, numinb, sig_subObj->outWritePos, &numoutb); if (s_result == PICO_OK) { sig_subObj->inReadPos += numinb; if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { sig_subObj->inReadPos = 0; sig_subObj->inWritePos = 0; sig_subObj->needMoreInput = FALSE; } sig_subObj->outWritePos += numoutb; sig_subObj->procState = PICOSIG_FEED; sig_subObj->retState = PICOSIG_COLLECT; PICODBG_DEBUG(("picosig.sigStep -- leaving PICO_PROC, inReadPos = %i, outWritePos = %i",sig_subObj->inReadPos, sig_subObj->outWritePos)); return PICODATA_PU_BUSY; /*data to feed*/ } return PICODATA_PU_BUSY; /*data still to process : remain in PROCESS STATE*/ break; case PICOSIG_PLAY: /*management of wav file play*/ s_data = (picoos_int16 *) &(sig_subObj->outBuf[sig_subObj->outWritePos + 4]); hop_p_half = sig_subObj->sig_inner.hop_p / 2; /*read directly into PU output buffer*/ n_samp = hop_p_half; b_res = picoos_sdfGetSamples(sig_subObj->sInSDFile, sig_subObj->sInSDFilePos, &n_samp, s_data); sig_subObj->sInSDFilePos += n_samp; if ((FALSE == b_res) || (0 == n_samp)) { /*file play is complete or file read error*/ picoos_sdfCloseIn(this->common, &(sig_subObj->sInSDFile)); sig_subObj->sInSDFile = NULL; sig_subObj->sInSDFileName[0] = '\0'; sig_subObj->procState = PICOSIG_COLLECT; sig_subObj->retState = PICOSIG_COLLECT; return PICODATA_PU_BUSY; /*check if data in input buffer*/ } /*-----------------------------------*/ /*Volume control of wav file playback*/ /* (code borrowed from sigProcess)*/ /*Volume mod and clipping control */ /* directly into PU output buffer*/ /*-----------------------------------*/ sf_mlt = (picoos_int32) ((sig_subObj->vMod) * 16.0f); s_t1 = &(s_data[0]); for (n_i = 0; n_i < n_samp; n_i++) { if (*s_t1 != 0) { sf_data = (picoos_int32) (*s_t1) * sf_mlt; sf_data >>= 4; if (sf_data > PICOSIG_MAXAMP) { sf_data = PICOSIG_MAXAMP; } else if (sf_data < PICOSIG_MINAMP) { sf_data = PICOSIG_MINAMP; } *s_t1 = (picoos_int16) (sf_data); } s_t1++; } /*Add header info*/ sig_subObj->outBuf[sig_subObj->outWritePos] = (picoos_uint8) PICODATA_ITEM_FRAME; sig_subObj->outBuf[sig_subObj->outWritePos + 1] = (picoos_uint8) n_samp; sig_subObj->outBuf[sig_subObj->outWritePos + 2] = (picoos_uint8) (sig_subObj->nNumFrame % (hop_p_half)); /*number of frame % 64*/ sig_subObj->outBuf[sig_subObj->outWritePos + 3] = (picoos_uint8) n_samp * 2; /*Item content*/ sig_subObj->outWritePos += (n_samp * sizeof(picoos_int16)) + 4; /*including header*/ sig_subObj->procState = PICOSIG_FEED; sig_subObj->retState = PICOSIG_PLAY; break; case PICOSIG_FEED: /* ************** item output/feeding ***********************************/ switch (sig_subObj->outSwitch) { case 0: /*feeding items to PU output buffer*/ s_result = picodata_cbPutItem(this->cbOut, &(sig_subObj->outBuf[sig_subObj->outReadPos]), sig_subObj->outWritePos - sig_subObj->outReadPos, &numoutb); break; case 1: /*feeding items to file*/ if (sig_subObj->outBuf[sig_subObj->outReadPos] == PICODATA_ITEM_FRAME) { if ((sig_subObj->sOutSDFile) != NULL) { n_start = (picoos_uint32) (sig_subObj->outReadPos) + PICODATA_ITEM_HEADSIZE; n_bytes = (picoos_uint32) sig_subObj->outBuf[(sig_subObj->outReadPos) + PICODATA_ITEMIND_LEN]; n_fram = (picoos_uint32) sig_subObj->outBuf[(sig_subObj->outReadPos) + PICODATA_ITEMIND_INFO2]; if (picoos_sdfPutSamples( sig_subObj->sOutSDFile, n_bytes / 2, (picoos_int16*) &(sig_subObj->outBuf[n_start]))) { PICODBG_DEBUG(("Nframe:%d - Nbytes %d\n", n_fram, n_bytes)); numoutb = n_bytes + 4; s_result = PICO_OK; /* also feed item to next PU */ s_result = picodata_cbPutItem( this->cbOut, &(sig_subObj->outBuf[sig_subObj->outReadPos]), sig_subObj->outWritePos - sig_subObj->outReadPos, &numoutb); } else { /*write error : close file + cleanup handles*/ if (sig_subObj->sOutSDFile != NULL) { picoos_sdfCloseOut(this->common, &(sig_subObj->sOutSDFile)); sig_subObj->sOutSDFile = NULL; } sig_subObj->sOutSDFileName[0] = '\0'; sig_subObj->outSwitch = 0; PICODBG_DEBUG(("Error in writing :%d bytes to output file %s\n", numoutb, &(sig_subObj->sOutSDFileName[0]))); s_result = PICO_ERR_OTHER; } } } else { /*continue to feed following PU with items != FRAME */ s_result = picodata_cbPutItem( this->cbOut, &(sig_subObj->outBuf[sig_subObj->outReadPos]), sig_subObj->outWritePos - sig_subObj->outReadPos, &numoutb); } break; default: s_result = PICO_ERR_OTHER; break; } PICODBG_DEBUG(("picosig.sigStep -- put item, status: %d",s_result)); if (PICO_OK == s_result) { sig_subObj->outReadPos += numoutb; *numBytesOutput = numoutb; /*-------------------------*/ /*reset the output pointers*/ /*-------------------------*/ if (sig_subObj->outReadPos >= sig_subObj->outWritePos) { sig_subObj->outReadPos = 0; sig_subObj->outWritePos = 0; sig_subObj->procState = sig_subObj->retState; } return PICODATA_PU_BUSY; } else if (PICO_EXC_BUF_OVERFLOW == s_result) { PICODBG_DEBUG(("picosig.sigStep ** feeding, overflow, PICODATA_PU_OUT_FULL")); return PICODATA_PU_OUT_FULL; } else if ((PICO_EXC_BUF_UNDERFLOW == s_result) || (PICO_ERR_OTHER == s_result)) { PICODBG_DEBUG(("picosig.sigStep ** feeding problem, discarding item")); sig_subObj->outReadPos = 0; sig_subObj->outWritePos = 0; sig_subObj->procState = sig_subObj->retState; return PICODATA_PU_ERROR; } break; default: /*NOT feeding items*/ s_result = PICO_EXC_BUF_IGNORE; break; }/*end switch*/ return PICODATA_PU_BUSY; /*check if there is more data to process after feeding*/ }/*end while*/ return PICODATA_PU_IDLE; }/*sigStep*/ #ifdef __cplusplus } #endif /* Picosig.c end */