This project has moved and is read-only. For the latest updates, please go here.

Problem with FFT calculation

Apr 5, 2013 at 10:58 AM
Edited Apr 5, 2013 at 11:01 AM
Hey,

A while ago I've posted on your blog (Sound Code), but I'm having a rather similar issue after having read one of your FFT articles.

Basically, what I need to do is calculate the frequency of the microphone input. I'm using IWaveProvider for this and its implemented Read(). The buffer always has a size of 8820 elements and something seems to be going wrong with the conversion from byte array to float array as well (the .FloatBuffer property part).

Here are some of the important bits...

This is where I start my recording:
private void InitializeSoundRecording()
        {
            WaveIn waveIn = new WaveIn();
            waveIn.DeviceNumber = 0;   
            waveIn.DataAvailable += (s, e) => this.waveIn_DataAvailable(s, e); 
            waveIn.RecordingStopped += (s, e) => this.waveIn_RecordingStopped(s, e);
            waveIn.WaveFormat = new WaveFormat(44100, 1);
            waveIn.StartRecording();
        }
When the DataAvailable event handler is called, the following is executed:
private void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            WaveBuffer wb = new WaveBuffer(e.Buffer.Length);

            IWaveProvider iWaveProvider = new PitchDetector(new WaveInProvider(sender as WaveIn), new WaveBuffer(e.Buffer));
            iWaveProvider.Read(wb, 0, e.Buffer.Length);

            PitchDetector pd = iWaveProvider as PitchDetector;
            
            this.ShowPitch(pd.Pitch);
        }
And lastly, this is the "actual" important bit:
private const int FLOAT_BUFFER_SIZE = 8820;
        private IWaveProvider source;
        private WaveBuffer waveBuffer;
        private int sampleRate;
        private float[] fftBuffer;
        private float[] prevBuffer;
        public float Pitch { get; private set; }

        public WaveFormat WaveFormat { get { return this.source.WaveFormat; } }

        internal PitchDetector(IWaveProvider waveProvider, WaveBuffer waveBuffer = null)
        {
            this.source = waveProvider;
            this.sampleRate = waveProvider.WaveFormat.SampleRate;
            this.waveBuffer = waveBuffer;
        }

        /// <summary>
        /// UNSAFE METHOD! Do not edit unless you know what to do
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private unsafe float[] ByteArrayToFloatArray(byte[] input)
        {
            float[] fb = new float[FLOAT_BUFFER_SIZE];
            unsafe
            {
                fixed (byte* ptrBuffer = input)
                {
                    float* ptrFloatBuffer = (float*)ptrBuffer;
                    for (int i = 0; i < FLOAT_BUFFER_SIZE; i++)
                    {
                        fb[i] = *ptrFloatBuffer;
                        ptrFloatBuffer++;
                    }
                }
            }
            return fb;
        }

        public int Read(byte[] buffer, int offset = 0, int count = 0)
        {
            if (this.waveBuffer == null || this.waveBuffer.MaxSize < count)
                this.waveBuffer = new WaveBuffer(count);

            int readBytes = this.source.Read(this.waveBuffer, 0, count);

            if (readBytes > 0) readBytes = count;

            int frames = readBytes / sizeof(float);

            this.Pitch = this.DeterminePitch(this.waveBuffer.FloatBuffer, frames);

            return frames * 4;
        }

Strangely enough, when it enters the constructor, waveBuffer contains some data (255, 1, 0, etc.), but when I check the "buffer" parameter of Read(), it's entirely 0. Every element.

Out of curiosity also, why does Read() have a buffer parameter, but isn't actually used in the method at all (I got that piece of code from one of your articles)?

Any help to resolve this issue would be greatly appreciated! I've been at this for quite a while already, but can make no sense out of it.


Thanks,
Alain