/*
 * 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 resetMode)
{
    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 (resetMode == 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), resetMode);
        /*-----------------------------------------------------------------
         * 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), resetMode);
    }


    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; nI<PICODSP_PHASEORDER; nI++) {
        phsVect[nI] = 0;
    }
    nFrame++;
    return PICO_OK;
}/*getPhsFromPdf*/

/**
 * processes one item with sig algo
 * @param    this : the PU object pointer
 * @param    inReadPos : read position in input buffer
 * @param    numinb : number of bytes in input buffer (including header)
 * @param    outWritePos : write position in output buffer
 * @param    numoutb : number of bytes produced in output buffer
 * @return  PICO_OK : processing successful and terminated
 * @return  PICO_STEP_BUSY : processing successful but still things to do
 * @return  PICO_ERR_OTHER : errors
 * @remarks processes a full input item
 * @remarks input data is one or more item, taken from local storage
 * @remarks output data is one or more item, written in local storage
 * @callgraph
 * @callergraph
 */
static pico_status_t sigProcess(register picodata_ProcessingUnit this,
        picoos_uint16 inReadPos, picoos_uint16 numinb,
        picoos_uint16 outWritePos, picoos_uint16 *numoutb)
{

    register sig_subobj_t * sig_subObj;
    picoos_int16 n_i;
    picoos_int16 n_frames, n_count;
    picoos_int16 *s_data, offset;
    picoos_int32 f_data, mlt, *t1, *tmp1, *tmp2;
    picoos_uint16 tmp_uint16;
    picopal_int16 tmp_int16;
    picoos_uint16 i, cnt;
    picoos_int16 hop_p_half;

    sig_subObj = (sig_subobj_t *) this->subObj;

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