private static Bin[] PitchShiftBins(float pitchShift, Bin[] bins)
        {
            return bins.Select(x => new Bin(x.Frequency*pitchShift, x.Magnitude)).ToArray();

            //var shiftedBins = new Bin[bins.Length];

            //for (var i = 0; i < shiftedBins.Length; i++)
            //{
            //    shiftedBins[i] = new Bin(0f, 0f);
            //}

            //for (var i = 0; i < bins.Length; i++)
            //{
            //    var index = (int)(i * pitchShift);

            //    if (index < bins.Length)
            //    {
            //        shiftedBins[i].Magnitude = bins[i].Magnitude;
            //        shiftedBins[i].Frequency = bins[i].Frequency * pitchShift;
            //    }
            //}

            //return shiftedBins;
        }
        private static Complex[] SynthesizeFft(float sampleRate, Bin[] bins)
        {
            const float expectedPhaseDifference = (float) (2*Math.PI);
            var fftBuffer = new Complex[bins.Length * 2];
            var frequencyPerBin = (sampleRate / (float)fftBuffer.Length);

            var phase = 0f;

            for (var i = 0; i < bins.Length; i++)
            {
                var tmp = bins[i].Frequency;

                tmp -= i*frequencyPerBin;

                tmp /= frequencyPerBin;

                tmp *= (float) (2*Math.PI);

                tmp += i*expectedPhaseDifference;

                phase += tmp;

                var real = (float)(bins[i].Magnitude * Math.Cos(phase));
                var imaginary = (float)(bins[i].Magnitude * Math.Sin(phase));

                fftBuffer[i] = new Complex(real, imaginary);
            }

            for (var i = bins.Length; i < fftBuffer.Length; i++)
            {
                fftBuffer[i] = new Complex(0f, 0f);
            }

            return fftBuffer;
        }
        private static Bin[] CalculateBins(int sampleRate, IList<Complex> fftBuffer)
        {
            const float expectedPhaseDifference = (float) (2*Math.PI);

            var frequencyPerBin = sampleRate / (float) fftBuffer.Count;
            var lastPhase = 0f;
            var bins = new Bin[fftBuffer.Count / 2];

            for (var i = 0; i < bins.Length; i++)
            {
                var magnitude = CalculateMagnitude(fftBuffer[i]);
                var phase = CalculatePhase(fftBuffer[i]);

                var tmp = phase - lastPhase;
                lastPhase = phase;

                tmp -= i*expectedPhaseDifference;

                var qpd = (long) (tmp/Math.PI);
                if (qpd >= 0) qpd += qpd & 1;
                else qpd -= qpd & 1;
                tmp -= (float) (Math.PI*qpd);

                tmp /= expectedPhaseDifference;

                tmp = i*frequencyPerBin + tmp*frequencyPerBin;

                bins[i] = new Bin(tmp, magnitude);
            }

            return bins;
        }