Пример #1
0
        /// <summary>
        /// Initializes a new windower for the specified stream with the specified window and hop size.
        /// </summary>
        /// <param name="stream">the stream to read the audio data to process from</param>
        /// <param name="windowSize">the window size in the dimension of samples</param>
        /// <param name="hopSize">the hop size in the dimension of samples</param>
        /// <param name="windowType">the type of the window function to apply</param>
        public StreamWindower(IAudioStream stream, int windowSize, int hopSize, WindowType windowType)
        {
            this.stream         = stream;
            this.windowSize     = windowSize;
            this.hopSize        = hopSize;
            this.windowFunction = WindowUtil.GetFunction(windowType, WindowSize);

            Initialize();
        }
Пример #2
0
        /// <summary>
        /// Initializes a new windower for the specified stream with the specified window and hop size.
        /// </summary>
        /// <param name="stream">the stream to read the audio data to process from</param>
        /// <param name="windowSize">the window size in the dimension of samples</param>
        /// <param name="hopSize">the hop size in the dimension of samples</param>
        /// <param name="windowType">the type of the window function to apply</param>
        public StreamWindower(IAudioStream stream, int windowSize, int hopSize, WindowType windowType, int bufferSize = DEFAULT_STREAM_INPUT_BUFFER_SIZE)
        {
            this.stream         = stream;
            this.windowSize     = windowSize;
            this.hopSize        = hopSize;
            this.windowFunction = WindowUtil.GetFunction(windowType, WindowSize);
            this.bufferSize     = bufferSize;

            Initialize();
        }
Пример #3
0
 public InverseSTFT(IAudioWriterStream stream, int windowSize, int hopSize, int fftSize, WindowType windowType, float windowNormalizationFactor)
     : base(stream, windowSize, hopSize)
 {
     if (fftSize < windowSize)
     {
         throw new ArgumentOutOfRangeException("fftSize must be >= windowSize");
     }
     frameBuffer     = new float[fftSize];
     fft             = FFTFactory.CreateInstance(fftSize);
     synthesisWindow = WindowUtil.GetFunction(windowType, windowSize, windowNormalizationFactor);
 }
Пример #4
0
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Title = Title + (Environment.Is64BitProcess ? " (x64)" : " (x86)");

            multiTrackViewer1.ItemsSource = trackList;

            // INIT COMMAND BINDINGS
            CommandBinding playBinding = new CommandBinding(MediaCommands.Play);

            CommandBindings.Add(playBinding);
            playBinding.CanExecute += new CanExecuteRoutedEventHandler(playCommandBinding_CanExecute);
            playBinding.Executed   += new ExecutedRoutedEventHandler(playCommandBinding_Executed);

            CommandBinding pauseBinding = new CommandBinding(MediaCommands.Pause);

            CommandBindings.Add(pauseBinding);
            pauseBinding.CanExecute += new CanExecuteRoutedEventHandler(pauseCommandBinding_CanExecute);
            pauseBinding.Executed   += new ExecutedRoutedEventHandler(pauseCommandBinding_Executed);

            CommandBinding playToggleBinding = new CommandBinding(Commands.PlayToggle);

            CommandBindings.Add(playToggleBinding);
            playToggleBinding.Executed += new ExecutedRoutedEventHandler(playToggleBinding_Executed);


            //// INIT TRACKLIST STUFF
            //trackList.PropertyChanged += delegate(object sender2, PropertyChangedEventArgs e2) {
            //    if (e2.PropertyName == "TotalLength") {
            //        multiTrackViewer1.VirtualViewportMaxWidth = trackList.TotalLength.Ticks;
            //    }
            //};


            // INIT PLAYER
            player = new MultitrackPlayer(trackList);
            player.VolumeAnnounced += Player_VolumeAnnounced_VolumeMeter;

            player.CurrentTimeChanged += new EventHandler <ValueEventArgs <TimeSpan> >(
                delegate(object sender2, ValueEventArgs <TimeSpan> e2) {
                multiTrackViewer1.Dispatcher.BeginInvoke((Action) delegate {
                    multiTrackViewer1.VirtualCaretOffset = e2.Value.Ticks;
                    // autoscroll
                    if (multiTrackViewer1.VirtualViewportInterval.To <= multiTrackViewer1.VirtualCaretOffset)
                    {
                        multiTrackViewer1.VirtualViewportOffset = multiTrackViewer1.VirtualCaretOffset;
                    }
                });
            });

            player.PlaybackStateChanged += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                multiTrackViewer1.Dispatcher.BeginInvoke((Action) delegate {
                    // CommandManager must be called on the GUI-thread, else it won't do anything
                    CommandManager.InvalidateRequerySuggested();
                });
            });

            volumeSlider.ValueChanged += new RoutedPropertyChangedEventHandler <double>(
                delegate(object sender2, RoutedPropertyChangedEventArgs <double> e2) {
                player.Volume = (float)e2.NewValue;
            });


            // INIT PROGRESSBAR
            progressBar1.IsEnabled = false;
            ProgressMonitor.GlobalInstance.ProcessingStarted += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.IsEnabled    = true;
                    progressBar1Label.Text    = ProgressMonitor.GlobalInstance.StatusMessage;
                    win7TaskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
                    win7TaskBar.ProgressValue = 0;
                });
            });

            ProgressMonitor.GlobalInstance.ProcessingProgressChanged += new EventHandler <ValueEventArgs <float> >(
                delegate(object sender2, ValueEventArgs <float> e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.Value        = e2.Value;
                    win7TaskBar.ProgressValue = e2.Value / 100;
                    progressBar1Label.Text    = ProgressMonitor.GlobalInstance.StatusMessage;
                });
            });

            ProgressMonitor.GlobalInstance.ProcessingFinished += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.Value        = 0;
                    progressBar1.IsEnabled    = false;
                    progressBar1Label.Text    = "";
                    win7TaskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
                });
            });


            // INIT RANDOM STUFF
            multiTrackViewer1.KeyUp += new KeyEventHandler(delegate(object sender2, KeyEventArgs e2) {
                if (e2.Key == Key.Delete)
                {
                    // create temporary list to avoid concurrent modification exception
                    var selectedAudioTracks = new List <AudioTrack>(multiTrackViewer1.SelectedItems.Cast <AudioTrack>());

                    // delete tracks
                    foreach (AudioTrack audioTrack in selectedAudioTracks)
                    {
                        if (audioTrack != null)
                        {
                            // 1. delete all related matches
                            List <Match> deleteList = new List <Match>();
                            // 1a find all related matches
                            foreach (Match m in multiTrackViewer1.Matches)
                            {
                                if (m.Track1 == audioTrack || m.Track2 == audioTrack)
                                {
                                    deleteList.Add(m);
                                }
                            }
                            // 1b delete
                            foreach (Match m in deleteList)
                            {
                                multiTrackViewer1.Matches.Remove(m);
                            }
                            // 2. delete track
                            trackList.Remove(audioTrack);
                        }
                    }
                    e2.Handled = true;
                }
            });


            // INIT FFT
            int    fftSize     = 1024;
            double correlation = 0;

            fftAnalyzer         = new FFTAnalyzer(fftSize);
            fftAnalyzerConsumer = 2;
            correlationConsumer = 1;
            WindowFunction fftWindow = WindowUtil.GetFunction(WindowType.BlackmanHarris, fftSize);

            fftAnalyzer.WindowFunction  = fftWindow;
            fftAnalyzer.WindowAnalyzed += FftAnalyzer_WindowAnalyzed_FrequencyGraph;
            fftAnalyzer.WindowAnalyzed += FftAnalyzer_WindowAnalyzed_Spectrogram;
            player.SamplesMonitored    += new EventHandler <StreamDataMonitorEventArgs>(delegate(object sender2, StreamDataMonitorEventArgs e2) {
                if (fftAnalyzerConsumer > 0 || correlationConsumer > 0)
                {
                    float[][] uninterleaved = AudioUtil.Uninterleave(e2.Properties, e2.Buffer, e2.Offset, e2.Length, true);
                    if (fftAnalyzerConsumer > 0)
                    {
                        fftAnalyzer.PutSamples(uninterleaved[0]); // put the summed up mono samples into the analyzer
                    }
                    if (correlationConsumer > 0)
                    {
                        correlation = CrossCorrelation.Correlate(uninterleaved[1], uninterleaved[2]);
                        Dispatcher.BeginInvoke((Action) delegate {
                            correlationMeter.Value = correlation;
                        });
                    }
                }
            });
            spectrogram.SpectrogramSize = fftSize / 2;
        }
Пример #5
0
        public static double FrequencyDistribution(byte[] x, byte[] y)
        {
            if (x.Length != y.Length)
            {
                throw new ArgumentException("interval lengths do not match");
            }

            int samples = x.Length / 4;

            float[] xF = new float[samples];
            float[] yF = new float[samples];

            Buffer.BlockCopy(x, 0, xF, 0, x.Length);
            Buffer.BlockCopy(y, 0, yF, 0, y.Length);

            int fftSize = 2048; // max FFT size

            // if there are less samples to analyze, find a fitting FFT size
            while (fftSize > samples)
            {
                fftSize /= 2;
            }
            int hopSize = fftSize / 8;

            if (fftSize < 64)
            {
                throw new Exception("FFT might be too small to get a meaningful result");
            }

            double[] xSum   = new double[fftSize / 2];
            double[] ySum   = new double[fftSize / 2];
            float[]  buffer = new float[fftSize];

            if (windowFunction == null || windowFunction.Size != fftSize)
            {
                windowFunction = WindowUtil.GetFunction(WindowType.Hann, fftSize);
            }

            var fft = new PFFFT.PFFFT(fftSize, PFFFT.Transform.Real);

            int blocks = (samples - fftSize) / hopSize;

            for (int block = 0; block < blocks; block++)
            {
                Array.Copy(xF, block * hopSize, buffer, 0, buffer.Length);
                FrequencyDistributionBlockProcess(buffer, xSum, fft);

                Array.Copy(yF, block * hopSize, buffer, 0, buffer.Length);
                FrequencyDistributionBlockProcess(buffer, ySum, fft);
            }

            fft.Dispose();

            // remove DC offset
            xSum[0] = 0;
            ySum[0] = 0;

            double xScalarSum = xSum.Sum();
            double yScalarSum = ySum.Sum();

            double result = 0;

            for (int i = 0; i < fftSize / 2; i++)
            {
                result += Math.Abs(xSum[i] / xScalarSum - ySum[i] / yScalarSum);
            }

            return(1 - result);
        }
Пример #6
0
        private void Generate(FFTLibrary fftLib)
        {
            // FFT resources:
            // http://www.mathworks.de/support/tech-notes/1700/1702.html
            // http://stackoverflow.com/questions/6627288/audio-spectrum-analysis-using-fft-algorithm-in-java
            // http://stackoverflow.com/questions/1270018/explain-the-fft-to-me
            // http://stackoverflow.com/questions/6666807/how-to-scale-fft-output-of-wave-file

            /*
             * FFT max value test:
             * 16Hz, 1024 samplerate, 512 samples, rectangle window
             * -> input min/max: -1/1
             * -> FFT max: 256
             * -> FFT result max: ~1
             * -> FFT dB result max: ~1
             *
             * source: "Windowing Functions Improve FFT Results, Part I"
             * => kann zum Normalisieren für Fensterfunktionen verwendet werden
             */

            float frequency       = float.Parse(frequencyTextBox.Text);
            int   ws              = (int)windowSize.Value;
            float frequencyFactor = ws / frequency;
            int   sampleRate      = int.Parse(sampleRateTextBox.Text);

            SineGeneratorStream sine = new SineGeneratorStream(sampleRate, frequency, new TimeSpan(0, 0, 1));

            float[] input = new float[ws];
            sine.Read(input, 0, ws);

            //// add second frequency
            //SineGeneratorStream sine2 = new SineGeneratorStream(44100, 700, new TimeSpan(0, 0, 1));
            //float[] input2 = new float[ws];
            //sine2.Read(input2, 0, ws);
            //for (int x = 0; x < input.Length; x++) {
            //    input[x] += input2[x];
            //    input[x] /= 2;
            //}

            //// add dc offset
            //for (int x = 0; x < input.Length; x++) {
            //    input[x] += 0.5f;
            //}

            inputGraph.Values = input;

            WindowFunction wf = WindowUtil.GetFunction((WindowType)windowTypes.SelectedValue, ws);

            float[] window = (float[])input.Clone();
            wf.Apply(window);

            input2Graph.Values = window;

            float[] fftIO = (float[])window.Clone();

            if (fftLib == FFTLibrary.ExocortexDSP)
            {
                // This function call indirection is needed to allow this method execute even when the
                // Exocortex FFT assembly is missing.
                ApplyExocortexDSP(fftIO);
            }
            else if (fftLib == FFTLibrary.FFTW)
            {
                FFTW.FFTW fftw = new FFTW.FFTW(fftIO.Length);
                fftw.Execute(fftIO);
            }
            else if (fftLib == FFTLibrary.PFFFT)
            {
                PFFFT.PFFFT pffft = new PFFFT.PFFFT(fftIO.Length, PFFFT.Transform.Real);
                pffft.Forward(fftIO, fftIO);
            }

            //// convert real input to complex input with im part set to zero
            //float[] fftIO = new float[ws * 2];
            //int i = 0;
            //for (int j = 0; j < window.Length; j++) {
            //    fftIO[i] = window[j];
            //    i += 2;
            //}
            //Fourier.FFT(fftIO, fftIO.Length / 2, FourierDirection.Forward);

            fftOutputGraph.Values = fftIO;


            float[] fftResult = new float[ws / 2];
            //FFTUtil.Results(fftIO, fftResult);

            // transform complex output to magnitudes
            float sum = 0;
            int   y   = 0;

            for (int x = 0; x < fftIO.Length; x += 2)   //  / 2
            {
                fftResult[y] = FFTUtil.CalculateMagnitude(fftIO[x], fftIO[x + 1]) / ws * 2;
                sum         += fftResult[y++];
            }
            //FFTUtil.Results(fftIO, fftResult);

            //// adjust values for the sum to become 1
            //float sum2 = 0;
            //for (int x = 0; x < fftResult.Length; x++) {
            //    fftResult[x] /= sum;
            //    sum2 += fftResult[x];
            //}
            //Debug.WriteLine("sum / sum2: {0} / {1}", sum, sum2);

            fftNormalizedOutputGraph.Values = fftResult;

            // convert magnitudes to decibel
            float[] fftResultdB = new float[fftResult.Length];
            //for (int x = 0; x < fftResult.Length; x++) {
            //    fftResultdB[x] = (float)VolumeUtil.LinearToDecibel(fftResult[x]);
            //}
            FFTUtil.Results(fftIO, fftResultdB);
            fftdBOutputGraph.Values = fftResultdB;

            summary.Text = String.Format(
                "input min/max: {0}/{1} -> window min/max: {2}/{3} -> fft min/max: {4}/{5} -> result min/max/bins/sum: {6}/{7}/{8}/{9} -> dB min/max: {10:0.000000}/{11:0.000000}",
                input.Min(), input.Max(),
                window.Min(), window.Max(),
                fftIO.Min(), fftIO.Max(),
                fftResult.Min(), fftResult.Max(), fftResult.Length, sum,
                fftResultdB.Min(), fftResultdB.Max());
        }