private void AnalyzeWaveform(AudioSampleData[] data, double sampleTime)
        {
            double lVal = 0, rVal = 0;

            double[][] dataWaveform = new double[2][];
            dataWaveform[0] = new double[data.Length];
            dataWaveform[1] = new double[data.Length];

            int i = 0;

            for (i = 0; i < data.Length; i++)
            {
                double absL = Math.Abs(data[i].LVOL);
                double absR = Math.Abs(data[i].RVOL);

                if (lVal < absL)
                {
                    lVal = absL;
                }
                if (rVal < absR)
                {
                    rVal = absR;
                }

                dataWaveform[0][i] = data[i].LVOL;
                dataWaveform[1][i] = data[i].RVOL;

                if (i % 32 == 0)
                {
                    lock (_vuLock)
                    {
                        _vuMeterData = new AudioSampleData(
                            lVal / _maxLevel,
                            rVal / _maxLevel);
                    }

                    lVal = rVal = 0;
                }
            }

            lock (_waveformLock)
            {
                _waveformData = dataWaveform;
            }
        }
        void _tmrUpdate_Tick(object sender, EventArgs e)
        {
            try
            {
                _tmrUpdate.Stop();

                if (ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.VUMeter))
                {
                    AudioSampleData vuData = MediaRenderer.DefaultInstance.VuMeterData;
                    if (vuData != null)
                    {
                        vuLeft.Value  = 0.5 * (vuLeft.Value + vuLeft.Maximum * vuData.LVOL);
                        vuRight.Value = 0.5 * (vuRight.Value + vuRight.Maximum * vuData.RVOL);
                    }
                    else
                    {
                        vuLeft.Value  = 0;
                        vuRight.Value = 0;
                    }
                }

                if (ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.Waveform))
                {
                    gpWaveform.Reset(false);

                    double[][] waveformData = MediaRenderer.DefaultInstance.WaveformData;
                    if (waveformData != null && waveformData[0].Length > 0)
                    {
                        if (_prevWaveform == null)
                        {
                            _prevWaveform = new double[waveformData[0].Length];
                        }

                        for (int k = 0; k < _prevWaveform.Length; k++)
                        {
                            _prevWaveform[k] = 0.5 * (_prevWaveform[k] + waveformData[0][k]);
                        }

                        gpWaveform.MinVal = -1 * MediaRenderer.DefaultInstance.MaxLevel;
                        gpWaveform.MaxVal = MediaRenderer.DefaultInstance.MaxLevel;
                        gpWaveform.AddDataRange(_prevWaveform, ThemeManager.GradientGaugeColor1);
                    }
                    else
                    {
                        gpWaveform.Reset(true);
                    }
                }

                if (ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.Spectrogram))
                {
                    double maxFftLevel = SpectrogramTransferFunction(MediaRenderer.DefaultInstance.MaxFFTLevel);

                    spSpectrogram.Reset(false);
                    spSpectrogram.MinVal = maxFftLevel / 2; // Min level = -6 dBM
                    spSpectrogram.MaxVal = maxFftLevel;     // Max level = 0 dBM

                    double[] spectrogramData = MediaRenderer.DefaultInstance.SpectrogramData;
                    if (spectrogramData != null && spectrogramData.Length > 0)
                    {
                        double[] spectrogramData2 = new double[spectrogramData.Length];
                        Array.Clear(spectrogramData2, 0, spectrogramData.Length);

                        double[] bands = new double[BandCount];
                        Array.Clear(bands, 0, BandCount);

                        int jBand = 0;

                        int div = spectrogramData.Length / (BandCount);

                        try
                        {
                            int maxSize = (int)Math.Min(BandCount, spectrogramData.Length);
                            for (int i = 0; i < maxSize; i++)
                            {
                                bands[i]  = Math.Max(0, Math.Min(maxFftLevel, SpectrogramTransferFunction(spectrogramData[i])));
                                _bands[i] = 0.5 * (_bands[i] + bands[i]);
                            }

                            spSpectrogram.AddDataRange(_bands, Color.Transparent);
                        }
                        catch (Exception ex)
                        {
                            string s = ex.Message;
                            spSpectrogram.Reset(true);
                            Array.Clear(_bands, 0, _bands.Length);
                        }
                    }
                    else
                    {
                        spSpectrogram.Reset(true);
                        Array.Clear(_bands, 0, _bands.Length);
                    }
                }
            }
            finally
            {
                _tmrUpdate.Start();
            }
        }
        private void AnalyzeFFT(AudioSampleData[] data)
        {
            if (data.Length == _fftWindowSize)
            {
                double[] dataIn = new double[data.Length];
                double[] dataOut = new double[data.Length];
                
                for (int i = 0; i < data.Length; i++)
                    dataIn[i] = data[i].RmsLevel;

                FFT.Forward(dataIn, dataOut);

                lock (_spectrogramLock)
                {
                    _spectrogramData = dataOut
                        .Skip(1 /* First band represents the 'total energy' of the signal */ )
                        .Take(_fftWindowSize / 2 /* The spectrum is 'mirrored' horizontally around the sample rate / 2 according to Nyquist theorem */ )
                        .ToArray();
                }
            }
        }
        private void AnalyzeWaveform(AudioSampleData[] data, double sampleTime)
        {
            double lVal = 0, rVal = 0;
            double[] dataWaveform = new double[data.Length];

            int i = 0;
            for (i = 0; i < data.Length; i++)
            {
                double absL = Math.Abs(data[i].LVOL);
                double absR = Math.Abs(data[i].RVOL);

                if (lVal < absL)
                    lVal = absL;
                if (rVal < absR)
                    rVal = absR;

                dataWaveform[i] = data[i].AvgLevel;

                if (i % 32 == 0)
                {
                    lock (_vuLock)
                    {
                        _vuMeterData = new AudioSampleData(
                            lVal / _maxLevel,
                            rVal / _maxLevel);
                    }

                    lVal = rVal = 0;
                }
            }

            lock (_waveformLock)
            {
                _waveformData = dataWaveform;
            }
        }
        private void ExtractSamples(AudioSample smp)
        {
            if (smp == null || _actualAudioFormat == null || mediaPosition == null)
            {
                return;
            }

            double mediaTime = 0;

            mediaPosition.get_CurrentPosition(out mediaTime);

            double delay    = smp.SampleTime - mediaTime;
            double absDelay = Math.Abs(delay);

            // Discard samples too far in time from current media time
            if (absDelay > 1)
            {
                return;
            }

            //CalculateAverageDelay(delay * 1000);

            if (delay > 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(delay));
            }

            FilterState ms = GetFilterState();

            if (smp.RawSamples.Length <= 0 || ms != FilterState.Running || _actualAudioFormat == null)
            {
                return;
            }

            int bytesPerChannel      = _actualAudioFormat.wBitsPerSample / 8;
            int totalChannels        = _actualAudioFormat.nChannels;
            int totalChannelsInArray = Math.Min(2, totalChannels);

            int i = 0;

            while (i < smp.RawSamples.Length)
            {
                double[] channels = new double[totalChannelsInArray];
                Array.Clear(channels, 0, totalChannelsInArray);

                int j = 0;
                while (j < totalChannelsInArray)
                {
                    int k = 0;
                    while (k < bytesPerChannel)
                    {
                        if (bytesPerChannel <= 2)
                        {
                            channels[j] += (short)(smp.RawSamples[i] << (8 * k));
                        }
                        else
                        {
                            channels[j] += (int)(smp.RawSamples[i] << (8 * k));
                        }

                        i++;
                        k++;
                    }

                    j++;
                }

                if (channels.Length >= 2)
                {
                    _sampleData.Enqueue(new AudioSampleData((double)channels[0], (double)channels[1]));
                }
                else
                {
                    _sampleData.Enqueue(new AudioSampleData((double)channels[0], 0));
                }

                _gatheredSamples++;
                if (_gatheredSamples % _waveformWindowSize == 0)
                {
                    if (ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.VUMeter) ||
                        ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.Waveform) ||
                        ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.WCFInterface))
                    {
                        AnalyzeWaveform(_sampleData.Skip(_sampleData.Count - _waveformWindowSize).Take(_waveformWindowSize).ToArray(),
                                        smp.SampleTime);
                    }
                }

                Thread.Yield();
            }

            AudioSampleData lostSample = null;

            while (_sampleData.Count > _fftWindowSize)
            {
                _sampleData.TryDequeue(out lostSample);
            }

            if (ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.Spectrogram) ||
                ProTONEConfig.SignalAnalisysFunctionActive(SignalAnalisysFunction.WCFInterface))
            {
                AnalyzeFFT(_sampleData.ToArray());
            }

            Thread.Yield();
        }