예제 #1
0
        public void TestAdaptiveSpectrogram()
        {
            // test variables
            var audioSystem = BassProxy.Instance;

            // 0. Get Audio Data
            float[] audioSamples = BassProxy.ReadMonoFromFile(WAVE_INPUT_FILEPATH, SAMPLING_RATE);

            var aspec = new AdaptiveSpectrogram(SAMPLING_RATE);

            int blockSize = aspec.GetPreferredBlockSize();              // 2048
            int stepSize  = aspec.GetPreferredStepSize();               // 1024 = 50% overlap

            // print out a normal spectrogram for comparison
            double[][] spec1  = FFTUtils.CreateSpectrogramLomont(audioSamples, blockSize, stepSize);
            var        spec1M = new Matrix(spec1).Transpose();

            spec1M.DrawMatrixImage("spec1_normal.png", -1, -1, true, true);

            // split the signal into chunks to feed the AdaptiveSpectrogram
            var chunks = MathUtils.Split(audioSamples, stepSize, false);

            int chunkLength = chunks.Count();

            Console.WriteLine("Chunk count: {0}", chunkLength);

            int count = 1;
            IEnumerable <double[]> spec = new double[0][];

            float[] lastChunk = null;
            foreach (var chunk in chunks)
            {
                Console.Write("Processing chunk: {0}   \r", count);

                if (lastChunk != null)
                {
                    // add two chunks together, because adaptive spectrogram expects 50% overlap
                    var z = new float[lastChunk.Length + chunk.Count()];
                    lastChunk.CopyTo(z, 0);
                    chunk.ToArray().CopyTo(z, chunk.Count());

                    // process two last chunks as one (e.g. 50% overlap)
                    var chunkData = aspec.Process(z);

                    // store in spectrogram
                    spec = spec.Concat(chunkData);

                    //var chunkM = new Matrix(chunkData);
                    //chunkM.WriteCSV("chunkData_" + count + ".csv");
                }

                lastChunk = chunk.ToArray();
                count++;
            }

            var specM = new Matrix(spec.ToArray()).Transpose();

            //specM.WriteCSV("spec_all.csv");
            specM.DrawMatrixImage("spec_adaptive.png", -1, -1, true, true);
        }
예제 #2
0
        public static Complex[] padded_FFT(ref double[] @in)
        {
            Debug.Assert(@in.Length > 0);
            int n = @in.Length;

            int padded = n > 256 ? Util.NextLowPrimes(n) : n;

            Array.Resize <double>(ref @in, padded);

            // 4096 real numbers on input processed by FFTW dft_r2c_1d transform gives
            // 4096/2+1 = 2049 complex numbers at output
            // prepare the input arrays
            var fftwInput = new FFTW.DoubleArray(@in);

            int complexSize = (padded >> 1) + 1;             // this is the same as (padded / 2 + 1);
            var fftwOutput  = new FFTW.ComplexArray(complexSize);

            FFTW.ForwardTransform(fftwInput, fftwOutput);

            Array.Resize <double>(ref @in, n);

            // free up memory
            GC.Collect();

            return(FFTUtils.ComplexDoubleToComplex(fftwOutput.ComplexValues));
        }
예제 #3
0
    public static Complex[] padded_FFT(double[] signal)
    {
        int N = MathUtils.NextPowerOfTwo(signal.Length);

        signal = zeros(signal, N);

        double[]  signal_fft    = FFTUtils.FFT(signal);
        Complex[] complexSignal = FFTUtils.DoubleToComplex(signal_fft);

        return(complexSignal);
    }
예제 #4
0
    public static double[] padded_IFFT(double[] signal)
    {
        int N = signal.Length;

        Complex[] complexSignal = FFTUtils.DoubleToComplex(signal);
        Fourier.FFT(complexSignal, N, FourierDirection.Backward);

        // get the result
        double[] fft_real = new double[N];
        for (int j = 0; j < N; j++)
        {
            fft_real[j] = complexSignal[j].Re;
        }
        return(fft_real);
    }
예제 #5
0
        public void TestMelFrequencyFiltering()
        {
            var audio = BassProxy.Instance;

            //const string fileName = @"Tests\Passacaglia, Handel-Saw-86bmp.wav";
            const string fileName = @"Tests\Passacaglia, Handel-Sine-86bmp.wav";

            const int  sampleRate     = 44100;
            const int  fftWindowsSize = 2048;
            const int  fftOverlap     = 1024;
            const bool colorize       = true;
            const int  melFilters     = 120;

            var monoSignal = BassProxy.ReadMonoFromFile(fileName, sampleRate);

            double[][] specNormal    = FFTUtils.CreateSpectrogramLomont(monoSignal, fftWindowsSize, fftOverlap);
            var        specNormalMat = new Matrix(specNormal).Transpose();

            specNormalMat.DrawMatrixImage("spec_normal.png", -1, -1, colorize, true);

            // Mel Scale Filterbank
            // Mel-frequency is proportional to the logarithm of the linear frequency,
            // reflecting similar effects in the human's subjective aural perception)
            var melFilter = new MelFilter(fftWindowsSize, sampleRate, melFilters, 0);

            var specNormalMelMat = melFilter.FilterWeights * specNormalMat;

            specNormalMelMat.DrawMatrixImage("spec_normal_mel.png", -1, -1, colorize, true);

            melFilter.FilterWeights.WriteCSV("melfilter_orig.csv");
            melFilter.FilterWeights.DrawMatrixGraph("melfilter_orig.png");

            var melFilterBank    = new MelFilterBank(0, sampleRate / 2, melFilters, fftOverlap, sampleRate);
            var melFilterBankMat = melFilterBank.Matrix;

            melFilterBankMat.WriteCSV("melfilter_new.csv");
            melFilterBankMat.DrawMatrixGraph("melfilter_new.png");

            var specNormalMelMatNew = melFilterBankMat * specNormalMat;

            specNormalMelMatNew.DrawMatrixImage("spec_normal_mel_new.png", -1, -1, colorize, true);
        }
예제 #6
0
        public static double[] padded_IFFT(ref Complex[] @in, bool doProperScaling = false)
        {
            Debug.Assert(@in.Length > 1);

            int originalLength = @in.Length;
            int n = (@in.Length - 1) * 2;

            int padded = n > 256 ? Util.NextLowPrimes(n) : n;

            Array.Resize <Complex>(ref @in, padded / 2 + 1);

            // prepare the input arrays
            var complexDouble      = FFTUtils.ComplexToComplexDouble(@in);
            var fftwBackwardInput  = new FFTW.ComplexArray(complexDouble);
            var fftwBackwardOutput = new FFTW.DoubleArray(padded);

            // this method needs that the backwards transform uses the output.length as it's N
            // i.e. FFTW.dft_c2r_1d(output.Length, input.Handle, output.Handle, Flags.Estimate);
            FFTW.BackwardTransform(fftwBackwardInput, fftwBackwardOutput);

            double[] @out = null;
            if (doProperScaling)
            {
                @out = fftwBackwardOutput.ValuesDivedByN;
            }
            else
            {
                // in the original method it wasn't scaled correctly (meaning ValuesDivedByN)
                @out = fftwBackwardOutput.Values;
            }

            Array.Resize <Complex>(ref @in, n / 2 + 1);

            // free up memory
            GC.Collect();

            return(@out);
        }
예제 #7
0
        public static void TestSpectrograms()
        {
            const int fftWindowSize = 4096;
            const int overlap       = 2048;

            var data = AudioUtilsNAudio.GenerateAudioTestData(44100, 10);

            double[][] spec1  = FFTUtils.CreateSpectrogramLomont(data, fftWindowSize, overlap);
            var        spec1M = new Matrix(spec1);

            spec1M.WriteCSV("spec_lomont.csv");

            double[][] spec2  = FFTUtils.CreateSpectrogramExocortex(data, fftWindowSize, overlap);
            var        spec2M = new Matrix(spec2);

            spec2M.WriteCSV("spec_exocortex.csv");
            Assert.That(spec2, Is.EqualTo(spec1).AsCollection.Within(0.001), "fail at [0]");

            double[][] spec3  = FFTUtils.CreateSpectrogramFFTW(data, fftWindowSize, overlap);
            var        spec3M = new Matrix(spec3);

            spec3M.WriteCSV("spec_fftw.csv");
            //Assert.That(spec3, Is.EqualTo(spec1).AsCollection.Within(0.001), "fail at [0]");

            double[][] spec4  = FFTUtils.CreateSpectrogramFFTWLIB(data, fftWindowSize, overlap);
            var        spec4M = new Matrix(spec4);

            spec4M.WriteCSV("spec_fftwlib.csv");
            //Assert.That(spec4, Is.EqualTo(spec1).AsCollection.Within(0.001), "fail at [0]");

            double[][] spec5  = FFTUtils.CreateSpectrogramFFTWLIB_INPLACE(data, fftWindowSize, overlap);
            var        spec5M = new Matrix(spec5);

            spec5M.WriteCSV("spec_fftwlib_inplace.csv");
            //Assert.That(spec5, Is.EqualTo(spec1).AsCollection.Within(0.001), "fail at [0]");
        }
예제 #8
0
        public void TestFFTAudioMatrixMethod()
        {
            // harmor_HQ.bmp = 1645 (width) x 511 (height) 32 bit

            // test variables
            const string outputDirectoryFilePath = "test";
            var          audioSystem             = BassProxy.Instance;

            // 0. Get Audio Data
            float[] audioSamples = BassProxy.ReadMonoFromFile(WAVE_INPUT_FILEPATH, SAMPLING_RATE);

            int width = 1645;
            //int width = (audioSamples.Length - WINDOW_SIZE)/ OVERLAP;
            int OVERLAP = (int)((double)(audioSamples.Length - WINDOW_SIZE) / (double)width);

            // 1. Explode samples to the range of 16 bit shorts (–32,768 to 32,767)
            // Matlab multiplies with 2^15 (32768)
            // e.g. if( max(abs(speech))<=1 ), speech = speech * 2^15; end;
            MathUtils.Multiply(ref audioSamples, AUDIO_MULTIPLIER);

            // zero pad if the audio file is too short to perform a fft
            if (audioSamples.Length < (WINDOW_SIZE + OVERLAP))
            {
                int lenNew = WINDOW_SIZE + OVERLAP;
                Array.Resize <float>(ref audioSamples, lenNew);
            }

            // 2. Windowing
            // 3. FFT
            #region Windowing and FFT
            var stft     = new STFT(FFTWindowType.HANNING, WINDOW_SIZE, OVERLAP);
            var stftdata = stft.Apply(audioSamples);

            // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024);
            stftdata.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram.png", true, false, -1, -1, false);

            var spect2    = FFTUtils.CreateSpectrogramFFTW(audioSamples, WINDOW_SIZE, OVERLAP);
            var stftdata2 = new Matrix(spect2).Transpose();

            // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024);
            stftdata2.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram2.png", true, false, -1, -1, false);

            var spect3    = FFTUtils.CreateSpectrogramLomont(audioSamples, WINDOW_SIZE, OVERLAP);
            var stftdata3 = new Matrix(spect3).Transpose();

            // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024);
            stftdata3.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram3.png", true, false, -1, -1, false);
            #endregion

            // the matrix are too different so comparing them always fails!
            //Assert.That(stftdata2, Is.EqualTo(stftdata3).AsCollection.Within(0.001), "fail at [0]");

            #region Inverse FFT
            // Perform inverse stft as well
            double[] audiodata_inverse_stft = stft.InverseStft(stftdata);

            // divide or normalize
            //MathUtils.Divide(ref audiodata_inverse_stft, AUDIO_MULTIPLIER);
            MathUtils.Normalize(ref audiodata_inverse_stft);

            Export.DrawGraph(audiodata_inverse_stft, outputDirectoryFilePath + "_audiodata_inverse_stft.png");

            float[] audiodata_inverse_float = MathUtils.DoubleToFloat(audiodata_inverse_stft);
            BassProxy.SaveFile(audiodata_inverse_float, outputDirectoryFilePath + "_inverse_stft.wav", 1, SAMPLING_RATE, 32);
            #endregion

            Assert.Pass("This test was succesful.");
        }