/*! \brief Discrete Cepstrum Transform * * method for computing cepstrum aenalysis from a discrete * set of partial peaks (frequency and amplitude) * * This implementation is owed to the help of Jordi Janer (thanks!) from the MTG, * along with the following paper: * "Regularization Techniques for Discrete Cepstrum Estimation" * Olivier Cappe and Eric Moulines, IEEE Signal Processing Letters, Vol. 3 * No.4, April 1996 * * \todo add anchor point add at frequency = 0 with the same magnitude as the first * peak in pMag. This does not change the size of the cepstrum, only helps to smoothen it * at the very beginning. * * \param sizeCepstrum order+1 of the discrete cepstrum * \param pCepstrum pointer to output array of cepstrum coefficients * \param sizeFreq number of partials peaks (the size of pFreq should be the same as pMag * \param pFreq pointer to partial peak frequencies (hertz) * \param pMag pointer to partial peak magnitudes (linear) * \param fLambda regularization factor * \param iMaxFreq maximum frequency of cepstrum */ void sms_dCepstrum( int sizeCepstrum, sfloat *pCepstrum, int sizeFreq, sfloat *pFreq, sfloat *pMag, sfloat fLambda, int iMaxFreq) { int i, k; sfloat factor; sfloat fNorm = PI / (float)iMaxFreq; /* value to normalize frequencies to 0:0.5 */ //static sizeCepstrumStatic static CepstrumMatrices m; //printf("nPoints: %d, nCoeff: %d \n", m.nPoints, m.nCoeff); if(m.nPoints != sizeCepstrum || m.nCoeff != sizeFreq) AllocateDCepstrum(sizeFreq, sizeCepstrum, &m); int s; /* signum: "(-1)^n, where n is the number of interchanges in the permutation." */ /* compute matrix M (eq. 4)*/ for (i=0; i<sizeFreq; i++) { gsl_matrix_set (m.pM, i, 0, 1.); // first colum is all 1 for (k=1; k <sizeCepstrum; k++) gsl_matrix_set (m.pM, i, k , 2.*sms_sine(PI_2 + fNorm * k * pFreq[i]) ); } /* compute transpose of M */ gsl_matrix_transpose_memcpy (m.pMt, m.pM); /* compute R diagonal matrix (for eq. 7)*/ factor = COEF * (fLambda / (1.-fLambda)); /* \todo why is this divided like this again? */ for (k=0; k<sizeCepstrum; k++) gsl_matrix_set(m.pR, k, k, factor * powf((sfloat) k,2.)); /* MtM = Mt * M, later will add R */ gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1., m.pMt, m.pM, 0.0, m.pMtMR); /* add R to make MtMR */ gsl_matrix_add (m.pMtMR, m.pR); /* set pMag in X and multiply with Mt to get pMtXk */ for(k = 0; k <sizeFreq; k++) gsl_vector_set(m.pXk, k, log(pMag[k])); gsl_blas_dgemv (CblasNoTrans, 1., m.pMt, m.pXk, 0., m.pMtXk); /* solve x (the cepstrum) in Ax = b, where A=MtMR and b=pMtXk */ /* ==== the Cholesky Decomposition way ==== */ /* MtM is 'symmetric and positive definite?' */ //gsl_linalg_cholesky_decomp (m.pMtMR); //gsl_linalg_cholesky_solve (m.pMtMR, m.pMtXk, m.pC); /* ==== the LU decomposition way ==== */ gsl_linalg_LU_decomp (m.pMtMR, m.pPerm, &s); gsl_linalg_LU_solve (m.pMtMR, m.pPerm, m.pMtXk, m.pC); /* copy pC to pCepstrum */ for(i = 0; i < sizeCepstrum; i++) pCepstrum[i] = gsl_vector_get (m.pC, i); }
/*! \brief generate a sinusoid given two frames, current and last * * \param fFreq current frequency * \param fMag current magnitude * \param pLastFrame stucture with values from last frame * \param pFBuffer pointer to output waveform * \param sizeBuffer size of the synthesis buffer * \param iTrack current track */ static void SineSynth(sfloat fFreq, sfloat fMag, SMS_Data *pLastFrame, sfloat *pFBuffer, int sizeBuffer, int iTrack) { sfloat fMagIncr, fInstMag, fFreqIncr, fInstPhase, fInstFreq; int i; /* if no mag in last frame copy freq from current */ if(pLastFrame->pFSinAmp[iTrack] <= 0) { pLastFrame->pFSinFreq[iTrack] = fFreq; pLastFrame->pFSinPha[iTrack] = TWO_PI * sms_random(); } /* and the other way */ else if(fMag <= 0) fFreq = pLastFrame->pFSinFreq[iTrack]; /* calculate the instantaneous amplitude */ fMagIncr = (fMag - pLastFrame->pFSinAmp[iTrack]) / sizeBuffer; fInstMag = pLastFrame->pFSinAmp[iTrack]; /* calculate instantaneous frequency */ fFreqIncr = (fFreq - pLastFrame->pFSinFreq[iTrack]) / sizeBuffer; fInstFreq = pLastFrame->pFSinFreq[iTrack]; fInstPhase = pLastFrame->pFSinPha[iTrack]; /* generate all the samples */ for(i = 0; i < sizeBuffer; i++) { fInstMag += fMagIncr; fInstFreq += fFreqIncr; fInstPhase += fInstFreq; pFBuffer[i] += sms_dBToMag(fInstMag) * sms_sine(fInstPhase); } /* save current values into last values */ pLastFrame->pFSinFreq[iTrack] = fFreq; pLastFrame->pFSinAmp[iTrack] = fMag; pLastFrame->pFSinPha[iTrack] = fInstPhase - floor(fInstPhase / TWO_PI) * TWO_PI; }