Example #1
0
// [[Rcpp::export]]
IntegerVector bootPerm(const int n) {
    RNGScope scope;
    NumericVector unRound(runif(n, 0, n));
    NumericVector rounded(floor(unRound));
    IntegerVector out = Rcpp::as< IntegerVector >(rounded);
    return out;
}
bool AFTimeHistoryAnalyzer::AnalyzeTrack(const int nCh)
{
   // Code by A.Farina
   
   // ********************* If requested, remove DC component ********************
   if(m_bRemoveDC)
	   m_paSignalTracks->Item(nCh).RemoveMean();
   
   // *************************** Apply selected filter ***************************
   m_paSignalTracks->Item(nCh).Filter();

   double dbRate = m_paSignalTracks->Item(nCh).GetSamplerate();

   AFSampleCount smpcTrackLength = m_paSignalTracks->Item(nCh).GetTrackLength(),
                 smpcStepLength  = AFSampleCount(dbRate/1000.0),                 // N. di campioni che fanno circa 1ms
                 smpcStepsCount  = smpcTrackLength/smpcStepLength;               // Numero di step

   if((smpcStepsCount*smpcStepLength) > smpcTrackLength)
	   smpcStepsCount -= 1;  // It prevents overflow
       
   const double dbStepDuration = smpcStepLength/dbRate;  // Lunghezza esatta di uno step, in s

   TITUFactors ituA( exp(-1.0/(0.03 * dbRate)),                            // Ag (cost. tempo ITU P56  dTau = 30 ms)
                     exp(-dbStepDuration/2.0/0.125) *dbStepDuration/0.125, // Fattore A per Fast = 0.125 s
                     exp(-dbStepDuration/2.0/1.0)   *dbStepDuration/1.0,   // Fattore A per Slow = 1 s
                     exp(-dbStepDuration/2.0/0.035) *dbStepDuration/0.035, // Fattore A per Impulse crescente
                     exp(-dbStepDuration/2.0/1.5)   *dbStepDuration/1.5 ); // Fattore A per Impulse decrescente

   TITUFactors ituB( 1.0 - ituA.m_dbG,
                     1.0 - ituA.m_dbFast,
                     1.0 - ituA.m_dbSlow,
                     1.0 - ituA.m_dbImpRaising,
                     1.0 - ituA.m_dbImpFalling );
   TITULevels ituL;

   long   iFast=0;
   
   AFSampleCount j;
   
   // preparazione vettori per ITU P56
   double adbLevelThresholds         [30]; //soglie di livello
   size_t aunSamplesOverThreshold    [30], //numero di campioni oltre la soglia
          aunLastSampleOverThreshold [30]; //memoria dall'ultimo campione sopra soglia
   
   const size_t unHangoverLength = unRound(0.2 / dbStepDuration); //hangover time in samples, rounded (H = 0.2)

   adbLevelThresholds        [0] = 1.0/M_SQRT2;
   aunSamplesOverThreshold   [0] = 0;
   aunLastSampleOverThreshold[0] = unHangoverLength;
   
   for(j = 1; j < 30; j++)    //scendo a passi di circa 3 dB
   {    
      adbLevelThresholds        [j] = adbLevelThresholds[j-1]/M_SQRT2;
      aunSamplesOverThreshold   [j] = 0;
      aunLastSampleOverThreshold[j] = unHangoverLength;
   }

   // ******************************** Parte 1 ********************************
   
   // inizializzo a zero il progress meter
#if defined __ITUP56_SINGLE_FRAME__ || !defined __WXGTK__
   SetProgressMeterMessage(wxString::Format(wxT("Analyzing channel %d Time History..."), nCh+1));
#endif
   
   AFSample* pTrack = m_paSignalTracks->Item(nCh).GetFilteredTrack();

   AFSampleCount smpcStep = 0, un = 0;
   double dbRmsOn1ms = 0.0, dbLocalMax = 0.0,
          dbMax      = 0.0,
          dbSample   = 0.0, dbSqrSample = 0.0,
          dbLeq      = 0.0,
          dbTotalSum = 0.0;

   double dbPi=0.0, dbEnvp=0.0;

   double** aadbBuffers = m_aResults[nCh].m_aadbBuffers; // Just for better readability...

   for(smpcStep=0; smpcStep < smpcStepsCount; smpcStep++)       // inizio il ciclo con smpcStep 1ms, parto da 0
   {
      dbRmsOn1ms = 0.0;
      dbLocalMax = 0.0;
      for(un=0; un < smpcStepLength; un++)   //ciclo interno sul blocchetto di 1ms
      {
         dbSample     = pTrack[un + smpcStep*smpcStepLength]; // campione corrente
         dbSqrSample  = dbSample*dbSample;                    // campione al quadrato
         dbRmsOn1ms  += dbSqrSample;                          // somma dei quadrati

         if(dbSqrSample > dbMax)
        	 dbMax = dbSqrSample; // ricerca del max peak istantaneo

         if(dbSqrSample > dbLocalMax)
        	 dbLocalMax = dbSqrSample; // ricerca del max peak istantaneo locale

         dbPi   = ituA.m_dbG * dbPi   + ituB.m_dbG * fabs(dbSample);  // valore intermedio
         dbEnvp = ituA.m_dbG * dbEnvp + ituB.m_dbG * fabs(dbPi);      // Envelope secondo ITU P56
      }
      // WARNING: In the original code the following lines are swapped!!!
      dbTotalSum += dbRmsOn1ms;     // Accumulo il totale generale per il Leq
      dbRmsOn1ms /= smpcStepLength; // Valore short-Leq di 1ms

      // Ciclo ricerca threshold ITU P56
      for(j = 1; j < 30; j++)
      {
          if(dbEnvp < adbLevelThresholds[j])
          {
             if(aunLastSampleOverThreshold[j] < unHangoverLength)
             {
                 aunSamplesOverThreshold   [j] += 1;
                 aunLastSampleOverThreshold[j] += 1;
             }
          }
          else
          {
             aunSamplesOverThreshold   [j] += 1;
             aunLastSampleOverThreshold[j]  = 0;
          }
      }
      // aunSamplesOverThreshold[j] è ora uguale al numero di campioni sopra il threshold j-esimo

      ituL.m_dbRunFast = ituA.m_dbFast * dbRmsOn1ms + ituB.m_dbFast * ituL.m_dbRunFast;
      ituL.m_dbRunSlow = ituA.m_dbFast * dbRmsOn1ms + ituB.m_dbSlow * ituL.m_dbRunSlow;

      // Costante di tempo Impulse (nuova versione), 
      ituL.m_dbRun35ms = ituA.m_dbImpRaising * dbRmsOn1ms + ituB.m_dbImpRaising * ituL.m_dbRun35ms; // questo è l'RMS 35ms corrente
      ituL.m_dbRunImp  = (ituL.m_dbRun35ms > ituL.m_dbRunImp) ? ituL.m_dbRun35ms
    		                                                  : ituL.m_dbRunImp * ituB.m_dbImpFalling;
 
      // memorizzo i valori max Fast, Slow, Impulse
      if (ituL.m_dbRunFast > ituL.m_dbMaxFast) { ituL.m_dbMaxFast = ituL.m_dbRunFast;
                                                 iFast = smpcStep; }
      if (ituL.m_dbRunSlow > ituL.m_dbMaxSlow)   ituL.m_dbMaxSlow = ituL.m_dbRunSlow;
      if (ituL.m_dbRunImp  > ituL.m_dbMaxImp)    ituL.m_dbMaxImp  = ituL.m_dbRunImp;
      if (dbRmsOn1ms       > ituL.m_dbMax1ms)    ituL.m_dbMax1ms  = dbRmsOn1ms;

      // dbAggiungo ai 5 buffers i valori RMS correnti, già in dB
      aadbBuffers[TC_PEAK][smpcStep] = dB(dbLocalMax);    // memorizzo per il grafico il Peak  corrente
      aadbBuffers[TC_RMS] [smpcStep] = dB(dbRmsOn1ms);    // memorizzo per il grafico il valore istantaneo
      aadbBuffers[TC_ITU] [smpcStep] = dB(dbEnvp*dbEnvp); // memorizzo per il grafico il valore Envelope ITU
      aadbBuffers[TC_FAST][smpcStep] = dB(ituL.m_dbRunFast);     // memorizzo per il grafico il Fast corrente
      aadbBuffers[TC_SLOW][smpcStep] = dB(ituL.m_dbRunSlow);     // memorizzo per il grafico il Slow corrente
      aadbBuffers[TC_IMP] [smpcStep] = dB(ituL.m_dbRunImp);      // memorizzo per il grafico il Imp  corrente

      // aggiorno il progress meter
#if defined __ITUP56_SINGLE_FRAME__ || !defined __WXGTK__
      if((smpcStep % 100) == 0)   // to speedup not update at every step
         if(!UpdateProgressMeter((nCh+1)*smpcStep, m_nChnlsCount*smpcStepsCount))
            return false;
#endif

    }
        
    // ******************************** Parte 2 ********************************    
        
    // Converto tutti i risultati in dB
    dbMax            = dB(dbMax);
    ituL.m_dbMaxFast = dB(ituL.m_dbMaxFast);
    ituL.m_dbMaxSlow = dB(ituL.m_dbMaxSlow);
    ituL.m_dbMaxImp  = dB(ituL.m_dbMaxImp);
    ituL.m_dbMax1ms  = dB(ituL.m_dbMax1ms);
    dbLeq            = dB(dbTotalSum/smpcTrackLength); // divido per il n. di blocchetti, ed ho l'energia media

    bool   bIsImpulsive = false;
    double dbPulseDuration = 0.0;
    AFSampleCount smpcLeftBound  = 0,
    		      smpcRightBound = 0;
    
    // Verifica componente impulsiva (ituL, iFast, smpcStepsCount) -> dbPulseDuration
    // Prima condizione: Lmax,imp - Lmax,slow >= 6 dB
    if((ituL.m_dbMaxImp - ituL.m_dbMaxSlow) >= 6.0)
    {        
        // Seconda condizione: dbPulseDuration < 1s
        for(smpcStep = iFast; smpcStep > 0; smpcStep--)          // inizio il ciclo con step 1ms
        {
        	if(aadbBuffers[TC_FAST][smpcStep] < (ituL.m_dbMaxFast - 10.0))
            {
            	smpcLeftBound = smpcStep;
                break;
            }
        }
        
        for(smpcStep = iFast; smpcStep < smpcStepsCount; smpcStep++)          // inizio il ciclo con step 1ms
        {
            if (aadbBuffers[TC_FAST][smpcStep] < (ituL.m_dbMaxFast - 10.0))
            {
            	smpcRightBound = smpcStep;
                break;
            }
        }
            
        if((smpcLeftBound > 0) && (smpcRightBound > 0))
            dbPulseDuration = dbStepDuration * (smpcRightBound - smpcLeftBound - 1);
        
        if(dbPulseDuration < 1.0)
            bIsImpulsive = true;
    }

    // ******************************** Parte 3 ********************************

    // Calcolo Active Speech level        TODO  ActiveSpeechLevel(dbTotalSum, a, c) => (Afin)
    const double M = 15.9; //Threshold standard secondo ITU P56
    double Aj,Cj;
    double Afin = 0, Jfin = 0;
    double Deltaj;
    double Deltajm1 = 50.0;     //tutta l'energia impaccata in un unico campione
    
    for(j=29; j>0; j--)         // inizio il ciclo sui 50 possibili valori di Threshold
    {
        if(aunSamplesOverThreshold[j] == 0)
        	aunSamplesOverThreshold[j] = 1;

        Aj = dB(dbTotalSum/aunSamplesOverThreshold[j]);
        Cj = dB20(adbLevelThresholds[j]);
        Deltaj = Aj-Cj;
        if(Deltaj <= M) 
        {
            Jfin = j + (M-Deltaj)/(Deltajm1-Deltaj);
            Afin = dB(dbTotalSum/aunSamplesOverThreshold[j]) + (Jfin-j) * (dB(dbTotalSum/aunSamplesOverThreshold[j+1]) - dB(dbTotalSum/aunSamplesOverThreshold[j]));
            break; // ho trovato la soluzione, esco dal ciclo.
        }
        Deltajm1 = Deltaj;
    }
    
    // ******************************** Parte 4 ********************************
    // Salvataggio Risultati
    double* adbParameters = m_aResults[nCh].m_adbParameters;

    double dbFullScale = m_paSignalTracks->Item(nCh).GetFullScale(),
    	   dbLeqFs     = dbLeq + dbFullScale; // Leq scaled

    adbParameters[THA_FSL] = dbFullScale;                          // Full Scale level
    adbParameters[THA_AVG] = dbLeqFs;                              // Average level
    adbParameters[THA_SEL] = dbLeqFs + dB(smpcTrackLength/dbRate); // Single Event level
    adbParameters[THA_TDU] = smpcTrackLength/dbRate;               // Total Duration
    adbParameters[THA_ASL] = Afin +  dbFullScale;                  // Active Speech level
    adbParameters[THA_THS] = Afin +  dbFullScale - M;              // Threshold level
    adbParameters[THA_ACT] = undB(dbLeq-Afin) * 100;               // Activity factor (%)
    adbParameters[THA_MPK] = dbMax + dbFullScale;                  // Max Peak level
    adbParameters[THA_MIM] = ituL.m_dbMaxImp  + dbFullScale;       // MaxSPL Impulse
    adbParameters[THA_MFS] = ituL.m_dbMaxFast + dbFullScale;       // MaxSPL Fast
    adbParameters[THA_MSL] = ituL.m_dbMaxSlow + dbFullScale;       // MaxSPL Slow
    adbParameters[THA_DUR] = dbPulseDuration;                      // Duration of the impulsive event
    adbParameters[THA_IMP] = (bIsImpulsive) ? 1.0 : 0.0;           // Impulsive event??
    
   // ritorno ok
   return true;
}