Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

FEAPIExamplePluginSpectral.cpp

Go to the documentation of this file.
00001 
00002 //     /*! \file FEAPIExamplePluginSpectral.cpp: \brief implementation of the CSpectralFeatures class. */
00003 //
00004 //        Copyright (c) 2005-2007, Alexander Lerch, zplane.development GbR
00005 //        All rights reserved.
00006 //
00007 //        Redistribution and use in source and binary forms, with or without 
00008 //        modification, are permitted provided that the following conditions 
00009 //        are met:
00010 //
00011 //        *   Redistributions of source code must retain the above copyright 
00012 //            notice, this list of conditions and the following disclaimer. 
00013 //        *   Redistributions in binary form must reproduce the above 
00014 //            copyright notice, this list of conditions and the following 
00015 //            disclaimer in the documentation and/or other materials 
00016 //            provided with the distribution. 
00017 //        *   Neither the name of the FEAPI development team nor the names 
00018 //            of its contributors may be used to endorse or promote products 
00019 //            derived from this software without specific prior written 
00020 //            permission. 
00021 //
00022 //        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00023 //        "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
00024 //        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
00025 //        FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
00026 //        COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
00027 //        INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
00028 //        BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
00029 //        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00030 //        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00031 //        LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
00032 //        ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
00033 //        POSSIBILITY OF SUCH DAMAGE.
00034 //
00036 
00037 
00038 #include <string>
00039 #include <iostream>
00040 #include <math.h>
00041 
00042 #include "zplVecLib.h"
00043 
00044 #include "FEAPI.h"
00045 #include "FEAPIExamplePluginSpectral.h"
00046 #include "FEAPIEntryPoints.h"
00047 
00048 #ifndef FLT_MAX
00049 #define FLT_MAX 3.402823466e+38F
00050 #endif
00051 
00052 #define kDefaultNumOfResults    8
00053 #define kDefaultRollOff         0.85F
00054 
00056 #define _MY_MAJOR_VERSION       0x00000000
00057 #define _MY_MINOR_VERSION       0x00000000
00058 #define _MY_SUB_VERSION         0x00000001
00059 
00060 
00061 // defines for plug in name etc.
00062 #define _MY_PLUGIN_NAME        "Spectral"
00063 #define _MY_PLUGIN_VENDOR      "zplane.development"
00064 #define _MY_PLUGIN_DESCRIPTION "This PlugIn calculates the spectral features Flux, Rolloff, Centroid and Spread."
00065 #define _MY_PLUGIN_COPYRIGHT   "(c) 2005 by zplane.development"
00066 #define _MY_PLUGIN_ID          "zplSpectral"
00067 
00068 
00069 // defines for description of result
00070 #define kFeatureName           "Relative number of Zero-Crossings"
00071 #define kFeatureUnit           "-"
00072 #define kFeatureDescription    "The number of zero crossings in the analysis block divided by the analysis block length"
00073 #define kFeatureRangeMin       0.0F
00074 #define kFeatureRangeMax       1.0F
00075 #define kFeatureIsQuantized    -1  // value is not quantized
00076 
00077 
00078 enum SpectralParameters_t
00079 {
00080     kParamBlockSize      = 0,
00081     kParamHopSize        = 1,
00082     kParamChannelMode    = 2,
00083     kParamWindowType     = 3,
00084     kParamLowFreqBound   = 4,
00085 
00086     kNumParameters
00087 };
00088 
00089 enum SpectralFeatures_t
00090 {
00091     kFeatureFlux         = 0,
00092     kFeatureRolloff      = 1,
00093     kFeatureCentroid     = 2,
00094     kFeatureSpread       = 3,
00095 
00096     kNumFeatures
00097 };
00098 
00099 static const FEAPI_ParameterDescription_t SpectralParameterDescription[kNumParameters] = 
00100 {
00101     //Name,                                     Unit,       Description,                                                                                                                    RangeMin,           RangeMax,               Default,    Quantized,      Realtime
00102     {"Analysis Block Length",                   "Frames",   "Length of analysis window for one result",                                                                                     4,                  (float)((1<<30)-1),     1024,       4,              false},
00103     {"Analysis Hop-Size",                       "ms",       "Distance between two analysis block beginnings",                                                                               1,                  (float)((1<<30)-1),     10,         -1,             false},
00104     {"Individual Channels or Sum Channel",      "",         "Determines wether the calculation should be done on the sum of all input channels ('0') or on each individual channel ('1')",  0,                  1,                      0,          1,              false},
00105     {"FFT Window",                              "",         "Window Type for FFT analysis (0: rectangular, 1: hanning, 2: hamming, 3: blackman)",                                           0,                  3,                      1,          1,              false},
00106     {"Low Frequency Cutoff",                    "Hz",       "Only take into account frequencies above this frequency",                                                                      0,                  (float)((1<<30)-1),     0,          -1,             true},
00107     
00108 };
00109 
00110 static const FEAPI_SignalDescription_t SpectralFeatureDescription[kNumFeatures] = 
00111 {
00112     //Name,                                     Unit,       Description,                                                                                                                                RangeMin,           RangeMax,               Quantized               SampleRate
00113     {"Spectral Flux",                           "",         "/sqrt{/sum_{/forall k}{(X(n)-X(n-1))^2}}, n = block index, k = frequency index, X = abs spectrum",                                                0,                  (float)((1<<30)-1),     -4,                     0},
00114     {"Spectral Rolloff",                        "",         "Defined as frequency f_K, given that 0.85/sum_{/forall k}{X_k} == /sum_0^K{X_k}, k = frequency index, X = abs spectrum",                   0,                  (float)((1<<30)-1),     -1,                     0},
00115     {"Spectral Centroid",                       "",         "C=/frac{/sum_{/forall k}{/log_2(0.001f_k}P}{/sum_{/forall k}{P}}, k = frequency index, P = power spectrum",                                -(float)((1<<30)-1),(float)((1<<30)-1),     -1,                     0},
00116     {"Spectrum Spread",                         "",         "/frac{/sum_{/forall k}{(/log_2(0.001f_k}-C)^2 P}{/sum_{/forall k}{P}}, k = frequency index, P = power spectrum, C = spectral centroid",    0,                  (float)((1<<30)-1),     -1,                     0},
00117     
00118 };
00119 
00120 static INLINE int sfRollOffIdx (const float *pfSpectrum, int iLength)
00121 {
00122     float   fSum        = 0,
00123             fOverallSum = 0;
00124     int     i;
00125 
00126     for (i = 0; i < iLength; i++)
00127         fOverallSum    += pfSpectrum[i];
00128  
00129     fOverallSum    *= kDefaultRollOff;
00130     i               = 0;
00131     while (fSum < fOverallSum)
00132     {
00133         fSum   += pfSpectrum[i];
00134         i++;
00135     }
00136 
00137     return i;
00138 }
00139 
00140 static INLINE float sfFlux (const float *pfSpectrum, float *pfOldSpectrum, int iStartIdx, int iLength)
00141 {
00142     float   fSum = 0;
00143     int     i;
00144 
00145     zplfRealSub_I (pfOldSpectrum, (float*)pfSpectrum, iLength);
00146     zplfRealMul_I (pfOldSpectrum, pfOldSpectrum, iLength);
00147     for (i = iStartIdx; i < iLength; i++)
00148         fSum   += pfOldSpectrum[i];
00149 
00150     return sqrtf (fSum);
00151 }
00152 
00153 static INLINE float sfCentroid (const float *pfSpectrum, float *pfLogFreqs, float fOverallSum, int iStartIdx, int iLength)
00154 {
00155     float   fSum = 0;
00156     int     i;
00157 
00158     if (fOverallSum < 1e-30)
00159         return 0;
00160 
00161     zplfRealMul_I (pfLogFreqs, (float*)pfSpectrum, iLength);
00162     for (i = iStartIdx; i < iLength; i++)
00163         fSum   += pfLogFreqs[i];
00164 
00165     return (fSum / fOverallSum);
00166 }
00167 
00168 static INLINE float sfSpread (const float *pfSpectrum, float *pfLogFreqs, float fCentroid, float fOverallSum, int iStartIdx, int iLength)
00169 {
00170     float   fSum = 0;
00171     int     i;
00172 
00173     if (fOverallSum < 1e-30)
00174         return 0;
00175 
00176     zplfRealAddC_I (pfLogFreqs, -fCentroid, iLength);
00177     zplfRealMul_I (pfLogFreqs, pfLogFreqs, iLength);
00178     zplfRealMul_I (pfLogFreqs, (float*)pfSpectrum, iLength);
00179     for (i = iStartIdx; i < iLength; i++)
00180         fSum   += pfLogFreqs[i];
00181 
00182     return sqrtf (fSum / fOverallSum);
00183 }
00184 
00185 CSpectralFeatures::CSpectralFeatures () : CFeatureExtractBase()
00186 {
00187 
00188     zplVecLibDispatcher ();
00189     
00190     m_ppCRingBuffer         = 0;
00191     m_ppResults             = 0;
00192     m_pfProcessBuffer       = 0;
00193     m_ptLocalTimeStamp      = 0;
00194     m_pfParameters          = 0;
00195     m_pFFTInstance          = 0;
00196     m_ppfFFTHistory         = 0;
00197     m_pfHelpBuffer          = 0;
00198     m_pfLogFreqs            = 0;
00199     m_iMPEG7SetZero         = 0;
00200 
00201     m_iSizeOfResultBuffer   = kDefaultNumOfResults;
00202 
00203     // set strings that will be returned by the default methods
00204     m_cPluginName           = _MY_PLUGIN_NAME;
00205     m_cPluginVendor         = _MY_PLUGIN_VENDOR;
00206     m_cPluginDescription    = _MY_PLUGIN_DESCRIPTION;
00207     m_cPluginId             = _MY_PLUGIN_ID;
00208     m_cPluginCopyRight      = _MY_PLUGIN_COPYRIGHT;
00209 
00210     // set plug in version info
00211     m_iMajorVersion         = _MY_MAJOR_VERSION;
00212     m_iMinorVersion         = _MY_MINOR_VERSION;
00213     m_iSubVersion           = _MY_SUB_VERSION;
00214 
00215     m_pfParameters          = new float [kNumParameters];
00216     for (int i = 0; i < kNumParameters; i++)
00217         m_pfParameters[i]     = SpectralParameterDescription[i].fDefaultValue;
00218 }
00219 
00220 
00221 CSpectralFeatures::~CSpectralFeatures ()
00222 {
00223     int iCh;
00224     if (m_ppCRingBuffer)
00225     {
00226         for (iCh = 0; iCh < this->GetPluginNumOfInputs (); iCh++)
00227         {
00228             if (m_ppCRingBuffer[iCh])
00229                 delete m_ppCRingBuffer[iCh];
00230             m_ppCRingBuffer[iCh]    = 0;
00231         }
00232         delete [] m_ppCRingBuffer;
00233         m_ppCRingBuffer     = 0;
00234     }
00235     if (m_ppResults)
00236     {
00237         for (iCh = 0; iCh < this->GetPluginNumOfResults (); iCh++)
00238         {
00239             if (m_ppResults[iCh])
00240                 delete [] m_ppResults[iCh];
00241             m_ppResults[iCh]        = 0;
00242         }
00243         delete [] m_ppResults;
00244         m_ppResults         = 0;
00245     }
00246     if (m_ptLocalTimeStamp)
00247         delete [] m_ptLocalTimeStamp;
00248     m_ptLocalTimeStamp  = 0;
00249 
00250     if (m_pfParameters)
00251         delete [] m_pfParameters;
00252     m_pfParameters      = 0;
00253 
00254     zplfFree (m_pfProcessBuffer);
00255     zplfFree (m_pfHelpBuffer);
00256     zplfFree (m_pfLogFreqs);
00257     if (m_ppfFFTHistory)
00258     {
00259         for (iCh = 0; iCh < this->GetPluginNumOfResults ()/kNumFeatures; iCh++)
00260             zplfFree (m_ppfFFTHistory[iCh]);
00261 
00262         delete [] m_ppfFFTHistory;
00263         m_ppfFFTHistory = 0;
00264     }
00265     zplfFFTDestroyInstance (m_pFFTInstance);
00266 }
00267 
00268 
00269 FEAPI_Error_t      CSpectralFeatures::InitializePlugin (float               fInputSampleRate, 
00270                                                         int                 iNumberOfAudioChannels,
00271                                                         int                 iHostApiMajorVersion,
00272                                                         FEAPI_UserData_t     *pstUserData)
00273 {
00274     FEAPI_Error_t   rErr;
00275     int             iCh;
00276 
00277     // free already allocated memory
00278     if (m_ppCRingBuffer)
00279     {
00280         for (iCh = 0; iCh < this->GetPluginNumOfInputs ()/kNumFeatures; iCh++)
00281         {
00282             if (m_ppCRingBuffer[iCh])
00283                 delete m_ppCRingBuffer[iCh];
00284             m_ppCRingBuffer[iCh]    = 0;
00285         }
00286         delete [] m_ppCRingBuffer;
00287         m_ppCRingBuffer     = 0;
00288     }
00289     if (m_ppResults)
00290     {
00291         for (iCh = 0; iCh < this->GetPluginNumOfResults (); iCh++)
00292         {
00293             if (m_ppResults[iCh])
00294                 delete [] m_ppResults[iCh];
00295             m_ppResults[iCh]        = 0;
00296         }
00297         delete [] m_ppResults;
00298         m_ppResults         = 0;
00299     }
00300     if (m_ptLocalTimeStamp)
00301         delete [] m_ptLocalTimeStamp;
00302     m_ptLocalTimeStamp  = 0;
00303     zplfFree (m_pfProcessBuffer);
00304     zplfFree (m_pfHelpBuffer);
00305     zplfFree (m_pfLogFreqs);
00306     if (m_ppfFFTHistory)
00307     {
00308         for (iCh = 0; iCh < this->GetPluginNumOfResults ()/kNumFeatures; iCh++)
00309             zplfFree (m_ppfFFTHistory[iCh]);
00310 
00311         delete [] m_ppfFFTHistory;
00312         m_ppfFFTHistory = 0;
00313     }
00314 
00315     rErr    = CFeatureExtractBase::InitializePlugin (   fInputSampleRate, 
00316                                                         iNumberOfAudioChannels,
00317                                                         iHostApiMajorVersion,
00318                                                         pstUserData);
00319 
00320     if (rErr != FEAPI_kNoError)
00321         return rErr;
00322 
00323     // Set information about the plugin inputs
00324     char acChannelStr[FEAPI_kMaxDescriptionLength];
00325     for (int h = 0; h < iNumberOfAudioChannels; ++h) 
00326     {
00327         sprintf(acChannelStr, "Channel: %d", h);
00328         SetPluginInputPinInfo(CPin::SetIndex(h)
00329             .SetName(acChannelStr)
00330             .SetUnit("")
00331             .SetDescription(acChannelStr)
00332             .SetRangeMin(-1.0f)
00333             .SetRangeMax(1.0f)
00334             .SetSampleRate(fInputSampleRate)
00335         );
00336     }
00337 
00338     // Setting information about the plugin parameters
00339     for (int i = 0; i < kNumParameters; ++i) 
00340     {
00341         SetPluginParameterPinInfo(CPin::SetIndex(i)
00342             .SetName(SpectralParameterDescription[i].acName)
00343             .SetUnit(SpectralParameterDescription[i].acUnit)
00344             .SetDescription(SpectralParameterDescription[i].acDescription)
00345             .SetRangeMin(SpectralParameterDescription[i].fRangeMin)
00346             .SetRangeMax(SpectralParameterDescription[i].fRangeMax)
00347             .SetDefaultValue(SpectralParameterDescription[i].fDefaultValue)
00348             .SetQuantizedTo(SpectralParameterDescription[i].fQuantizedTo)
00349             .SetIsChangeableInRealTime(SpectralParameterDescription[i].bIsChangeableInRealTime)
00350         );
00351     }
00352 
00353     // allocate ringbuffers and memory for results and temp memory for processing
00354     int iAllocLength    = (m_pfParameters[kParamBlockSize] > m_pfParameters[kParamHopSize]/1000*fInputSampleRate)?
00355         (int)(m_pfParameters[kParamBlockSize] + .5F) : (int)(m_pfParameters[kParamHopSize]/1000*fInputSampleRate + .5F);
00356     m_pfProcessBuffer   = zplfMalloc (iAllocLength);
00357     m_pfHelpBuffer      = zplfMalloc ((iAllocLength)>>1);
00358     m_pfLogFreqs        = zplfMalloc ((iAllocLength)>>1);
00359     m_ppCRingBuffer     = new CRingBuffer<float>*[iNumberOfAudioChannels];
00360     for (iCh = 0; iCh < iNumberOfAudioChannels; iCh++)
00361     {
00362         m_ppCRingBuffer[iCh]    = new CRingBuffer<float>(iAllocLength<<1);
00363     }
00364 
00365     // Setting information about the plugin results
00366     char acDescription[FEAPI_kMaxDescriptionLength];
00367     //int  iNumOfChannels =  (m_pfParameters[kParamChannelMode]  ==  0)  ?  1  :  iNumberOfAudioChannels;
00368     int iNumOfResults   = kNumFeatures * ((m_pfParameters[kParamChannelMode] == 0) ? 1 : iNumberOfAudioChannels);
00369     if (m_pfParameters[kParamChannelMode] == 0)
00370     {
00371         for (iCh = 0; iCh < iNumOfResults; ++iCh) 
00372         {
00373             sprintf(acDescription, "%s", SpectralFeatureDescription[iCh].acDescription);
00374             SetPluginResultPinInfo(CPin::SetIndex(iCh)
00375                 .SetName(SpectralFeatureDescription[iCh].acName)
00376                 .SetUnit(SpectralFeatureDescription[iCh].acUnit)
00377                 .SetDescription(acDescription)
00378                 .SetRangeMin(SpectralFeatureDescription[iCh].fRangeMin)
00379                 .SetRangeMax(SpectralFeatureDescription[iCh].fRangeMax)
00380                 .SetQuantizedTo(SpectralFeatureDescription[iCh].fQuantizedTo)
00381                 .SetSampleRate(1000.0F / m_pfParameters[kParamHopSize])
00382                 );
00383         }
00384     }
00385     else
00386     {
00387         for (iCh = 0; iCh < iNumOfResults; ++iCh) 
00388         {
00389             sprintf(acDescription, "Channel: %d;", iCh/iNumberOfAudioChannels);
00390             strcat(acDescription, SpectralFeatureDescription[iCh/iNumberOfAudioChannels].acDescription);
00391             SetPluginResultPinInfo(CPin::SetIndex(iCh)
00392                 .SetName(SpectralFeatureDescription[iCh/iNumberOfAudioChannels].acName)
00393                 .SetUnit(SpectralFeatureDescription[iCh/iNumberOfAudioChannels].acUnit)
00394                 .SetDescription(acDescription)
00395                 .SetRangeMin(SpectralFeatureDescription[iCh/iNumberOfAudioChannels].fRangeMin)
00396                 .SetRangeMax(SpectralFeatureDescription[iCh/iNumberOfAudioChannels].fRangeMax)
00397                 .SetQuantizedTo(SpectralFeatureDescription[iCh/iNumberOfAudioChannels].fQuantizedTo)
00398                 .SetSampleRate(1000.0F / m_pfParameters[kParamHopSize])
00399             );
00400         }
00401     }
00402     m_ppResults             = new InternalResults_t*[iNumOfResults];
00403     m_ppfFFTHistory         = new float*[iNumOfResults];
00404     m_ptLocalTimeStamp      = new FEAPI_TimeStamp_t [iNumOfResults];
00405     for (iCh = 0; iCh < iNumOfResults; iCh++)
00406     {
00407         m_ppResults[iCh]        = new InternalResults_t[m_iSizeOfResultBuffer];
00408         m_ppfFFTHistory[iCh]    = zplfMalloc (((int)(m_pfParameters[kParamBlockSize]+.1F))>>1);
00409         zplfSetZero (m_ppfFFTHistory[iCh], ((int)(m_pfParameters[kParamBlockSize]+.1F))>>1);
00410         memset (m_ppResults[iCh], 0, sizeof (InternalResults_t) * m_iSizeOfResultBuffer);
00411     }
00412     memset (m_ptLocalTimeStamp, 0, sizeof(FEAPI_TimeStamp_t)*iNumberOfAudioChannels);
00413 
00414     zplfFFTDestroyInstance (m_pFFTInstance);
00415     zplfFFTCreateInstance (m_pFFTInstance, (int)(m_pfParameters[kParamBlockSize] + .1F),1, CzplfFFT_If::_Fft_Windows_ ((int)(m_pfParameters[kParamWindowType] + .1F)));
00416 
00417     // init tables
00418     m_iMPEG7SetZero = this->CalcFreqTable ();
00419     
00420     return FEAPI_kNoError;
00421 }
00422 
00423 FEAPI_Error_t      CSpectralFeatures::SetPluginParameter (int iParameterIndex, float fValue)
00424 {
00425     if ((iParameterIndex >= this->GetPluginNumOfParameters ()) || (iParameterIndex < 0))
00426         return FEAPI_kUnspecifiedError;
00427 
00428     if ((fValue < SpectralParameterDescription[iParameterIndex].fRangeMin) || (fValue > SpectralParameterDescription[iParameterIndex].fRangeMax))
00429         return FEAPI_kUnspecifiedError;
00430 
00431     m_pfParameters[iParameterIndex] = fValue;
00432 
00433     if ((iParameterIndex == kParamBlockSize) && ((int)(fValue) != Int2PowTwo ((int)fValue)))
00434         return FEAPI_kUnspecifiedError;
00435 
00436     // since all other parameters are non-realtime parameters, we can call initialize here for simplicity
00437     if (iParameterIndex != kParamLowFreqBound)
00438         this->InitializePlugin (m_fSampleRate, this->GetPluginNumOfInputs (), 1, 0);
00439     
00440     return FEAPI_kNoError;
00441 }
00442 
00443 
00444 float       CSpectralFeatures::GetPluginParameter (int iParameterIndex)
00445 {
00446     if ((iParameterIndex >= this->GetPluginNumOfParameters ()) || (iParameterIndex < 0))
00447         return FEAPI_kUnspecifiedError;
00448 
00449     return m_pfParameters[iParameterIndex];
00450 }
00451 
00452 
00453 int         CSpectralFeatures::GetPluginResultLatency (int iResultIndex)
00454 {
00455     return (int)(m_pfParameters[kParamBlockSize]);
00456 }
00457 
00458 
00459 FEAPI_Error_t      CSpectralFeatures::ProcessPluginDone ()
00460 {
00461     int iNumProcessChannels = this->GetPluginNumOfResults ()/kNumFeatures, // either 1 or num of channels...
00462         iProcessBlockSize   = (int)(m_pfParameters[kParamBlockSize]),
00463         iProcessBufSize     = (m_pfParameters[kParamBlockSize] > m_pfParameters[kParamHopSize]/1000*m_fSampleRate)? (int)(m_pfParameters[kParamBlockSize] + .5F) : (int)(m_pfParameters[kParamHopSize]/1000*m_fSampleRate + .5F),
00464         iStartIdx           = (int)(m_pfParameters[kParamLowFreqBound] / m_fSampleRate * iProcessBlockSize),
00465         iSamplesInBuffer    = m_ppCRingBuffer[0]->GetSamplesInBuffer ();
00466 
00467     for (int iCh = 0; iCh < iNumProcessChannels; iCh++)
00468     {
00469         float   fSum  = 0,
00470                 fResult;
00471 
00472         // get data from ring bufffer and oncrement read pointer
00473         m_ppCRingBuffer[iCh]->GetPostInc (m_pfProcessBuffer, iSamplesInBuffer);
00474         memset (&m_pfProcessBuffer[iSamplesInBuffer], 0, sizeof(float)*(iProcessBufSize - iSamplesInBuffer));
00475     
00476         // adjust time stamp
00477         m_ptLocalTimeStamp[iCh]  = m_ptLocalTimeStamp[iCh] - iSamplesInBuffer/m_fSampleRate;
00478 
00479         // calc fft
00480         m_pFFTInstance->zplfFFT (m_pfProcessBuffer, m_pfProcessBuffer);
00481 
00482         // calc abs
00483         zplfCompAbs (m_pfProcessBuffer, m_pfProcessBuffer, iProcessBlockSize>>1);
00484 
00486         // calc rolloff
00487         fResult = sfRollOffIdx (&m_pfProcessBuffer[iStartIdx], (iProcessBlockSize>>1)-iStartIdx) * m_fSampleRate / iProcessBlockSize;
00488         this->WriteResult (kFeatureRolloff * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00489 
00490         // calc flux
00491         fResult = sfFlux (m_pfProcessBuffer, m_ppfFFTHistory[iCh], iStartIdx, iProcessBlockSize>>1);
00492         this->WriteResult (kFeatureFlux * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00493 
00494         // update history buffer for next frame
00495         memcpy (m_ppfFFTHistory[iCh], m_pfProcessBuffer, sizeof(float)*(iProcessBlockSize>>1));
00496 
00497         // calc power
00498         zplfRealMul_I (m_pfProcessBuffer, m_pfProcessBuffer, iProcessBlockSize>>1);
00499 
00500         // calc sum
00501         for (int j = iStartIdx; j < iProcessBlockSize>>1; j++)
00502             fSum    += m_pfProcessBuffer[j];
00503 
00504         // calc centroid
00505         memcpy (m_pfHelpBuffer, m_pfLogFreqs, sizeof(float)*(iProcessBlockSize>>1));
00506         fResult = sfCentroid (m_pfProcessBuffer, m_pfHelpBuffer, fSum, iStartIdx, iProcessBlockSize>>1);
00507         this->WriteResult (kFeatureCentroid * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00508 
00509         // calc spread
00510         memcpy (m_pfHelpBuffer, m_pfLogFreqs, sizeof(float)*(iProcessBlockSize>>1));
00511         fResult = sfSpread (m_pfProcessBuffer, m_pfHelpBuffer, fResult, fSum, iStartIdx, iProcessBlockSize>>1);
00512         this->WriteResult (kFeatureSpread * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00513     }
00514 
00515     return FEAPI_kNoError;
00516 }
00517 
00518 FEAPI_Error_t      CSpectralFeatures::ProcessPlugin (const float **ppfInputBuffer, const FEAPI_TimeStamp_t *ptTimeStamps, int iNumberOfFrames)
00519 {
00520     bool bDownmixToMono = (m_pfParameters[kParamChannelMode] == 0)? true : false;
00521     int iCh,
00522         iIdx,
00523         iProcessBlockSize   = (int)(m_pfParameters[kParamBlockSize]),
00524         iHopSize            = (int)(m_pfParameters[kParamHopSize]*0.001F * m_fSampleRate + .1F),
00525         iFramesRequired     = (m_pfParameters[kParamBlockSize] > iHopSize) ? (int)(m_pfParameters[kParamBlockSize]) : iHopSize,
00526         iStartIdx           = (int)(m_pfParameters[kParamLowFreqBound] / m_fSampleRate * iProcessBlockSize),
00527         iNumFramesLeft      = iNumberOfFrames,
00528         iNumInputChannels   = this->GetPluginNumOfInputs (),
00529         iNumProcessChannels = this->GetPluginNumOfResults ()/kNumFeatures, // either 1 or num of channels...,
00530         iSamplesInBuffer    = 0;
00531 
00532     if (!m_bIsInitialized)
00533         return FEAPI_kUnspecifiedError;
00534 
00535     // do time stamp handling, in both cases: no/defined time stamp
00536     if (ptTimeStamps)
00537     {
00538         for (iCh = 0; iCh < iNumInputChannels; iCh++)
00539             m_ptLocalTimeStamp[iCh] = ptTimeStamps[iCh] + iNumberOfFrames/m_fSampleRate;
00540     }
00541     else
00542     {
00543         for (iCh = 0; iCh < iNumInputChannels; iCh++)
00544             m_ptLocalTimeStamp[iCh]    += iNumberOfFrames/m_fSampleRate;
00545     }
00546 
00547     // if there are sufficient frames to process, do it!
00548     //while (m_ppCRingBuffer[0]->GetSamplesInBuffer () + iNumFramesLeft >= iProcessBlockSize)
00549     while (m_ppCRingBuffer[0]->GetSamplesInBuffer () + iNumFramesLeft >= iFramesRequired)
00550     {
00551         // check if we have to downmix to mono or not
00552         if (bDownmixToMono)
00553         {
00554             int iLength = (iHopSize < iNumFramesLeft) ? iHopSize : iNumFramesLeft;
00555             iNumProcessChannels = 1;
00556             // downmix and write to buffer, decr numframesleft
00557             memcpy (m_pfProcessBuffer, &ppfInputBuffer[0][iNumberOfFrames - iNumFramesLeft], sizeof(float) * iLength);
00558             for (iCh = 1; iCh < iNumInputChannels; iCh++)
00559             {
00560                 const float *pfBuffer = &ppfInputBuffer[iCh][iNumberOfFrames - iNumFramesLeft];
00561 
00562                 for (iIdx = 0; iIdx < iLength; iIdx++)
00563                     m_pfProcessBuffer[iIdx] += pfBuffer[iIdx];
00564             }
00565 
00566             // scale downmixed signal
00567             for (iIdx = 0; iIdx < iLength; iIdx++)
00568                 m_pfProcessBuffer[iIdx] *= 1.0F/iNumInputChannels;
00569 
00570             m_ppCRingBuffer[0]->PutPostInc (m_pfProcessBuffer, iLength);
00571         }
00572         else
00573         {
00574             for (iCh = 0; iCh < iNumInputChannels; iCh++)
00575                 m_ppCRingBuffer[iCh]->PutPostInc (&ppfInputBuffer[iCh][iNumberOfFrames - iNumFramesLeft], (iHopSize < iNumFramesLeft) ? iHopSize : iNumFramesLeft);
00576         }
00577 
00578         // decrement number of frames left in ppfInputBuffer
00579         iNumFramesLeft     -= (iHopSize < iNumFramesLeft) ? iHopSize : iNumFramesLeft;
00580 
00581         // get the current number of sample in ring buffer
00582         iSamplesInBuffer    = m_ppCRingBuffer[0]->GetSamplesInBuffer ();
00583 
00584         // if there are not enough sample in ring buffer, go on (note that this is not really possible...)
00585         if (iSamplesInBuffer < iProcessBlockSize)
00586             continue;
00587 
00588         // now do the processing
00589         for (iCh = 0; iCh < iNumProcessChannels; iCh++)
00590         {
00591             int     j;
00592             float   fSum  = 0,
00593                     fResult;
00594 
00595             // adjust time stamp
00596             m_ptLocalTimeStamp[iCh]  = ptTimeStamps[iCh] + iNumberOfFrames/m_fSampleRate - (iSamplesInBuffer+iNumFramesLeft)/m_fSampleRate;
00597     
00598             // get data from ring buffer and increment read pointer
00599             m_ppCRingBuffer[iCh]->GetOff (m_pfProcessBuffer, iProcessBlockSize, 0);
00600             m_ppCRingBuffer[iCh]->SetReadPos (m_ppCRingBuffer[iCh]->GetReadPos () + iHopSize);
00601 
00602             // calc fft
00603             m_pFFTInstance->zplfFFT (m_pfProcessBuffer, m_pfProcessBuffer);
00604 
00605             // calc abs
00606             zplfCompAbs (m_pfProcessBuffer, m_pfProcessBuffer, iProcessBlockSize>>1);
00607 
00608             // calc rolloff
00609             fResult = sfRollOffIdx (&m_pfProcessBuffer[iStartIdx], (iProcessBlockSize>>1)-iStartIdx) * m_fSampleRate / iProcessBlockSize;
00610             this->WriteResult (kFeatureRolloff * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00611 
00612             // calc flux
00613             fResult = sfFlux (m_pfProcessBuffer, m_ppfFFTHistory[iCh], iStartIdx, iProcessBlockSize>>1);
00614             this->WriteResult (kFeatureFlux * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00615 
00616             // update history buffer for next frame
00617             memcpy (m_ppfFFTHistory[iCh], m_pfProcessBuffer, sizeof(float)*(iProcessBlockSize>>1));
00618 
00619             // calc power
00620             zplfRealMul_I (m_pfProcessBuffer, m_pfProcessBuffer, (iProcessBlockSize>>1));
00621 
00622             // mpeg-7 specific low frequencies:
00623             for (j = 0; j < m_iMPEG7SetZero+1; j++)
00624                 fSum    += m_pfProcessBuffer[j];
00625             for (j = 0; j < m_iMPEG7SetZero; j++)
00626                 m_pfProcessBuffer[j]    = 0.0F;
00627             m_pfProcessBuffer[m_iMPEG7SetZero]  = fSum;
00628 
00629             // calc sum
00630             fSum = 0;
00631             for (j = iStartIdx; j < iProcessBlockSize>>1; j++)
00632                 fSum    += m_pfProcessBuffer[j];
00633             
00634             // calc centroid
00635             memcpy (m_pfHelpBuffer, m_pfLogFreqs, sizeof(float)*(iProcessBlockSize>>1));
00636             fResult = sfCentroid (m_pfProcessBuffer, m_pfHelpBuffer, fSum, iStartIdx, iProcessBlockSize>>1);
00637             this->WriteResult (kFeatureCentroid * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00638 
00639             // calc spread
00640             memcpy (m_pfHelpBuffer, m_pfLogFreqs, sizeof(float)*(iProcessBlockSize>>1));
00641             fResult = sfSpread (m_pfProcessBuffer, m_pfHelpBuffer, fResult, fSum, iStartIdx, iProcessBlockSize>>1);
00642             this->WriteResult (kFeatureSpread * iNumProcessChannels + iCh, fResult, m_ptLocalTimeStamp[iCh]); 
00643             
00644             // adjust time stamp
00645             m_ptLocalTimeStamp[iCh]  = m_ptLocalTimeStamp[iCh] + iHopSize/m_fSampleRate;
00646         }
00647     }
00648 
00649     // if there are frames left in ppfInputBuffer, handle them here
00650     if (iNumFramesLeft > 0)
00651     {
00652         // write remaining frames to ringbuffer (distinguish downmix or not..., decr numframesleft)
00653         if (bDownmixToMono)
00654         {
00655             // downmix and write to buffer
00656             memcpy (m_pfProcessBuffer, &ppfInputBuffer[0][iNumberOfFrames - iNumFramesLeft], sizeof(float) * iNumFramesLeft);
00657             for (iCh = 1; iCh < iNumInputChannels; iCh++)
00658             {
00659                 const float *pfBuffer = &ppfInputBuffer[iCh][iNumberOfFrames - iNumFramesLeft];
00660 
00661                 for (iIdx = 0; iIdx < iNumFramesLeft; iIdx++)
00662                     m_pfProcessBuffer[iIdx] += pfBuffer[iIdx];
00663             }
00664             // scale downmixed signal
00665             for (iIdx = 0; iIdx < iHopSize; iIdx++)
00666                 m_pfProcessBuffer[iIdx] *= 1.0F/iNumInputChannels;
00667 
00668             m_ppCRingBuffer[0]->PutPostInc (m_pfProcessBuffer, iNumFramesLeft);
00669         }
00670         else
00671         {
00672             for (iCh = 0; iCh < iNumInputChannels; iCh++)
00673                 m_ppCRingBuffer[iCh]->PutPostInc (&ppfInputBuffer[iCh][iNumberOfFrames - iNumFramesLeft], iNumFramesLeft);
00674         }
00675     }
00676 
00677     return FEAPI_kNoError;
00678 }
00679 
00680 int         CSpectralFeatures::GetPluginSizeOfResult (int iResultIndex)
00681 {
00682     if ((iResultIndex >= this->GetPluginNumOfResults ()) || (iResultIndex < 0))
00683         return -1;
00684 
00685     if (m_ppResults[iResultIndex][0].bHoldsResult == true)
00686         return 1;
00687     else
00688         return 0;
00689 }
00690 
00691 
00692 FEAPI_Error_t      CSpectralFeatures::GetPluginResult (int iResultIndex, float *pfResult, FEAPI_TimeStamp_t *ptTimeStamp)
00693 {
00694     if ((iResultIndex >= this->GetPluginNumOfResults ()) || (iResultIndex < 0))
00695         return FEAPI_kUnspecifiedError;
00696     
00697     if (m_ppResults[iResultIndex][0].bHoldsResult == false)
00698         return FEAPI_kUnspecifiedError;
00699 
00700     pfResult[0]     = m_ppResults[iResultIndex][0].fResult;
00701     ptTimeStamp[0]  = m_ppResults[iResultIndex][0].tTimeStamp;
00702 
00703     memmove (&m_ppResults[iResultIndex][0], &m_ppResults[iResultIndex][1], (m_iSizeOfResultBuffer - 1)*sizeof(InternalResults_t));
00704     m_ppResults[iResultIndex][m_iSizeOfResultBuffer-1].bHoldsResult = false;
00705 
00706     return FEAPI_kNoError;
00707 }
00708 
00709 
00710 FEAPI_Error_t      CSpectralFeatures::ResetPlugin ()
00711 {
00712     for (int iCh = 0; iCh < this->GetPluginNumOfInputs (); iCh++)
00713     {
00714         m_ppCRingBuffer[iCh]->Reset ();
00715         m_ptLocalTimeStamp[iCh] = 0;
00716     }
00717     return FEAPI_kNoError;
00718 }
00719 
00720 
00721 float        CSpectralFeatures::GetPluginProperty ( FEAPI_PluginProperty_t ePluginProperty)
00722 {
00723     switch (ePluginProperty)
00724     {
00725     case FEAPI_kMinSampleRate:
00726         {
00727             return 1;
00728         }
00729     case FEAPI_kMaxSampleRate:
00730         {
00731             return 1e38F;
00732         }
00733     case FEAPI_kMinChannels:
00734         {
00735             return 1;
00736         }
00737     case FEAPI_kMaxChannels:
00738         {
00739             return (float)((1<<30)-1);
00740         }
00741     case FEAPI_kMinFrameSize:
00742         {
00743             return 1;
00744         }
00745     case FEAPI_kMaxFrameSize:
00746         {
00747             return (float)((1<<30)-1);
00748         }
00749     case FEAPI_kOptFrameSize:
00750         {
00751             return floorf(m_pfParameters[kParamHopSize] * 0.001F * m_fSampleRate + .1F);
00752         }
00753     default:
00754         {
00755             // this shall never happen ...
00756             return -1;
00757         }
00758     }
00759     return -1;
00760 }
00761 
00762 void CSpectralFeatures::WriteResult (int iResultIdx, float fValue, FEAPI_TimeStamp_t tTimeStamp)
00763 {
00764     int     iCurrentIdx = 0;
00765 
00766     ZASSERT (!m_ppResults);
00767     
00768     for (iCurrentIdx = 0; iCurrentIdx < m_iSizeOfResultBuffer; iCurrentIdx++)
00769     {
00770         ZASSERT (!m_ppResults[iCurrentIdx]);
00771         if (m_ppResults[iResultIdx][iCurrentIdx].bHoldsResult == false)
00772             break;
00773     }
00774     if (iCurrentIdx == m_iSizeOfResultBuffer)
00775     {
00776         // alloc new memory
00777         m_iSizeOfResultBuffer   <<= 1;
00778         for (int i = 0; i < this->GetPluginNumOfResults (); i++)
00779         {
00780             InternalResults_t *pTmp = new InternalResults_t[m_iSizeOfResultBuffer];
00781             memcpy (pTmp, m_ppResults[i], (m_iSizeOfResultBuffer>>1) * sizeof(InternalResults_t));
00782             memset (&pTmp[(m_iSizeOfResultBuffer>>1)], 0, (m_iSizeOfResultBuffer>>1) * sizeof(InternalResults_t));
00783             delete [] m_ppResults[i];
00784             m_ppResults[i]          = 0;
00785             m_ppResults[i]          = pTmp;
00786         }
00787     }
00788 
00789     m_ppResults[iResultIdx][iCurrentIdx].bHoldsResult  = true;
00790     m_ppResults[iResultIdx][iCurrentIdx].fResult       = fValue;
00791     m_ppResults[iResultIdx][iCurrentIdx].tTimeStamp    = tTimeStamp;
00792 
00793     return;
00794 }
00795 
00796 int CSpectralFeatures::CalcFreqTable ()
00797 {
00798     // don't worry about the magic frequency values... these are from MPEG-7
00799     
00800     int i,
00801         iProcessBlockSize   =  (((int)(m_pfParameters[kParamBlockSize]+.1F))>>1),
00802         iStartIdx           = (int)floorf ( 62.5F * (iProcessBlockSize<<1) / m_fSampleRate)+1;
00803     float   fInvLog2        = 1.0F / logf(2.0F),
00804             fInvBlockSize   = 1.0F / (iProcessBlockSize<<1);
00805 
00806     for (i = 0; i < iStartIdx; i++)
00807         m_pfLogFreqs[i] = fInvLog2 * logf (31.25F*0.001F);
00808 
00809     for (i = iStartIdx; i < iProcessBlockSize; i++)
00810         m_pfLogFreqs[i] = fInvLog2 * logf (i * m_fSampleRate * 0.001F * fInvBlockSize);
00811 
00812     return iStartIdx-1;
00813 }
00814 
00816 // entry points
00817 #ifdef __cplusplus                                                      
00818 extern "C" {                                                            
00819 #endif                                                              
00820 
00821 FEAPI_ENTRY_POINTS(CSpectralFeatures)
00822 
00823 #ifdef __cplusplus                                                  
00824 }                                                               
00825 #endif
00826 
00827 

Generated on Fri Mar 23 10:28:54 2007 for FEAPI Plugin Documentation by  doxygen 1.3.9.1