Ejemplo n.º 1
0
    /**
     * Constructor, sets the {@link Decoder}, the sample window size and the
     * hop size for the spectra returned. Say the sample window size is 1024
     * samples. To get an overlapp of 50% you specify a hop size of 512 samples,
     * for 25% overlap you specify a hopsize of 256 and so on. Hop sizes are of
     * course not limited to powers of 2.
     *
     * @param decoder The decoder to get the samples from.
     * @param sampleWindowSize The sample window size.
     * @param hopSize The hop size.
     * @param useHamming Wheter to use hamming smoothing or not.
     */
    public SpectrumProvider( DecoderInterface decoder, int sampleWindowSize, int hopSize, bool useHamming )
    {
        if( decoder == null )
            throw new ArgumentException( "Decoder must be != null" );

        if( sampleWindowSize <= 0 )
            throw new ArgumentException( "Sample window size must be > 0" );
        if( hopSize <= 0 )
            throw new ArgumentException( "Hop size must be > 0" );

        if( sampleWindowSize < hopSize )
            throw new ArgumentException( "Hop size must be <= sampleSize" );

        this.sampleWindowSize = sampleWindowSize;

        this.decoder = decoder;
        this.samples = new float[sampleWindowSize];
        this.nextSamples = new float[sampleWindowSize];
        this.tempSamples = new float[sampleWindowSize];
        this.hopSize = hopSize;
        fft = new FFT( sampleWindowSize, AudioManager.frequency );
        if( useHamming )
            fft.window(FFT.HAMMING);

        decoder.readSamples( ref samples );
        decoder.readSamples( ref nextSamples );
    }
Ejemplo n.º 2
0
    // { 0, 500, 500, 2000, 2000, 4000, 4000, 8000, 8000, 16000, 16000, 22000 };
    public static void analyse(DecoderInterface decoder)
    {
        loadingProgress = 0;
        abortAnalysis = false;
        // For finding the volume levels
        List<int> volumeLevelList = new List<int> ();
        float rollingAverage = 0.01f;
        float alpha = 0.15f;
        int activePart = -1;
        int sampleCounter = 0;
        float totalMax = -1;

        // Get spectral flux
        SpectrumProvider spectrumProvider = new SpectrumProvider (decoder, BUFFER_SIZE, HOP_SIZE, true);
        float[] spectrum = spectrumProvider.nextSpectrum ();
        float[] lastSpectrum = new float[spectrum.Length];
        List<List<float>> spectralFlux = new List<List<float>> ();
        for (int i = 0; i < bands.Length / 2; i++)
            spectralFlux.Add (new List<float> ());

        int bufferCounter = 0;

        do {

            if(abortAnalysis) return;

            #region SPECTRAL ANALYSIS
            for (int i = 0; i < bands.Length; i+=2) {
                int startFreq = spectrumProvider.getFFT ().freqToIndex (bands [i]);
                int endFreq = spectrumProvider.getFFT ().freqToIndex (bands [i + 1]);
                float flux = 0;
                for (int j = startFreq; j <= endFreq; j++) {
                    float value = (spectrum [j] - lastSpectrum [j]);
                    value = (value + Mathf.Abs (value)) / 2;
                    flux += value;
                }
                (spectralFlux [i / 2]).Add (flux);
            }

            System.Array.Copy (spectrum, 0, lastSpectrum, 0, spectrum.Length);
            #endregion

            #region GET MAX SAMPLE
            foreach (float sample in spectrumProvider.getCurrentSamples()) {
                if (sample > totalMax)
                    totalMax = sample;
            }
            #endregion

            bufferCounter++;
            loadingProgress = 0.75f*(((bufferCounter*BUFFER_SIZE)/(float)AudioManager.frequency)/AudioManager.audioLength);

        } while( (spectrum = spectrumProvider.nextSpectrum() ) != null );

        #region VOLUME CLASSIFICATION
        DecoderInterface dec = spectrumProvider.getDecoder ();
        dec.reset ();

        float [] samples = new float[spectrumProvider.getWinSize ()];
        float factor = 1f / totalMax;
        List<float> decibelLevels = new List<float>();
        float avgDecibels = 0;

        float oldProgress = loadingProgress;

        while (dec.readSamples(ref samples) !=0) {

            if(abortAnalysis) return;

            float max = -1;

            /* Normalize the volume using the previously calculated factor */
            for (int i =0; i < samples.Length; i++) {
                samples [i] = Mathf.Abs (samples[i] * factor);
                if (samples [i] > max)
                    max = samples [i];
            }

            float db = Mathf.Abs(20*Mathf.Log10(max));
            if(max != 0) decibelLevels.Add(db);
            avgDecibels += db;

            rollingAverage = (alpha * max) + ((1 - alpha) * rollingAverage);

            // Have we found a part which classifies as extremely loud?
            if (rollingAverage > 0.82f) { //0.8

                // Are we already in that part?
                if (activePart != 5) {
                    activePart = 5; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as damn loud?
            } else if (rollingAverage > 0.7f) { //0.6

                // Are we already in that part?
                if (activePart != 4) {
                    activePart = 4; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty loud?
            } else if (rollingAverage > 0.4f) { //0.2

                // Are we already in that part?
                if (activePart != 3) {
                    activePart = 3; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty normal?
            } else if (rollingAverage > 0.1f) { //0.0716

                // Are we already in that part?
                if (activePart != 2) {
                    activePart = 2; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as pretty quiet?
            } else if (rollingAverage > 0.0016f) { //0.0016

                // Are we already in that part?
                if (activePart != 1) {
                    activePart = 1; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }

                // Have we found a part which classifies as very quiet?
                // Below 40db (== below 0.06f amplitude)
            } else {

                // Are we already in that part?
                if (activePart != 0) {
                    activePart = 0; // Set flag that we are now in that part
                    volumeLevelList.Add (sampleCounter * spectrumProvider.getCurrentSamples ().Length);
                    volumeLevelList.Add (activePart);
                }
            }
            sampleCounter++;
            loadingProgress = oldProgress + 0.25f*(((sampleCounter*BUFFER_SIZE)/(float)AudioManager.frequency)/AudioManager.audioLength);
        }
        #endregion

        if(abortAnalysis) return;

        // Store volumelevels
        volumeLevels = volumeLevelList.ToArray ();
        volumeLevelList.Clear();
        volumeLevelList = null;

        #region SPECTRAL FLUX ANALYSIS
        // Convert spectral flux arraylist to array
        float[][] spectralFluxArray = new float[spectralFlux.Count][];
        for (int i = 0; i < spectralFluxArray.Length; i++) {
            spectralFluxArray [i] = spectralFlux [i].ToArray ();
        }
        spectralFlux.Clear ();
        spectralFlux = null;

        if(abortAnalysis) return;

        // Get thresholds
        float[][] thresholds = new float[bands.Length / 2][];
        float[][] prunnedSpectralFlux = new float[bands.Length / 2][];
        for (int i = 0; i < bands.Length / 2; i++) {
            float[] threshold = new ThresholdFunction (HISTORY_SIZE, multipliers [i]).calculate (spectralFluxArray [i]);
            thresholds [i] = threshold;

            float[] tempPSF = new float[spectralFluxArray [i].Length];
            for (int j = 0; j < spectralFluxArray[i].Length; j++) {
                if (threshold [j] <= spectralFluxArray [i] [j])
                    tempPSF [j] = spectralFluxArray [i] [j] - threshold [j];
                else
                    tempPSF [j] = 0;
            }
            prunnedSpectralFlux [i] = tempPSF;
        }
        thresholds = null;

        if(abortAnalysis) return;

        // Get Peaks
        List<int[]> peaksList = new List<int[]> ();
        float[] peakAvgs = new float[prunnedSpectralFlux.Length];
        float[] minPeaks = new float[prunnedSpectralFlux.Length];
        for (int i = 0; i < prunnedSpectralFlux.Length; i++) {

            List<int> tempPeaks = new List<int> ();
            minPeaks [i] = float.MaxValue;

            for (int j = 0; j < prunnedSpectralFlux[i].Length -1; j++) {
                if (prunnedSpectralFlux [i] [j] > prunnedSpectralFlux [i] [j + 1]) {
                    tempPeaks.Add (j);
                    peakAvgs [i] += prunnedSpectralFlux [i] [j];
                    if (prunnedSpectralFlux [i] [j] != 0 && prunnedSpectralFlux [i] [j] < minPeaks [i])
                        minPeaks [i] = prunnedSpectralFlux [i] [j];
                }
            }
            peaksList.Add (tempPeaks.ToArray ());
            peakAvgs [i] /= tempPeaks.Count;
        }

        if(abortAnalysis) return;

        // Save current peaks & reset list
        peaks = peaksList.ToArray ();
        peaksList.Clear ();

        // Lowpass filter the peaks
        for (int i = 0; i < peaks.Length; i++) {
            List<int> tempPeaks = new List<int> ();
            for (int j = 0; j < peaks[i].Length; j++) {
                if (prunnedSpectralFlux [i] [peaks [i] [j]] > minPeaks [i] + 0.7f * (peakAvgs [i] - minPeaks [i])) {
                    tempPeaks.Add (peaks [i] [j]);
                    tempPeaks.Add (Mathf.RoundToInt(prunnedSpectralFlux[i][peaks[i][j]]));
                }
            }
            peaksList.Add (tempPeaks.ToArray ());
        }
        peaks = peaksList.ToArray ();
        #endregion

        if(abortAnalysis) return;

        #region NORMALIZE PEAK INTENSITIES
        for(int i = 0; i < peaks.Length; i++) {
            float max = -1;
            for(int j = 1;j < peaks[i].Length; j+=2) {
                if(peaks[i][j] > max) max = peaks[i][j];
            }
            for(int j = 1;j < peaks[i].Length; j+=2) {
                peaks[i][j] = Mathf.RoundToInt(100f*(peaks[i][j]/max));
            }
        }
        #endregion

        if(abortAnalysis) return;

        #region VARIATION FACTOR
        float[] dbLvls = decibelLevels.ToArray();
        decibelLevels.Clear();
        decibelLevels = null;

        avgDecibels /= (float)dbLvls.Length;

        float stDev = 0;
        for (int i = 0; i < dbLvls.Length; i++) {
            stDev += (dbLvls[i] - avgDecibels) * (dbLvls[i] - avgDecibels);
        }

        stDev = Mathf.Sqrt (stDev / (float)dbLvls.Length);

        if(stDev > 25f) stDev = 25f;
        else if (stDev < 5f) stDev = 5f;

        stDev /= 25f;
        variationFactor = stDev;
        #endregion

        isAnalyzing = false;
    }