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

why divide by 32768f

Jan 25, 2014 at 3:37 PM
Edited Jan 25, 2014 at 3:41 PM
I found this code online and I have been using it, but I do not know why you have to
divide by 32768f. and why do you have to make it a short ?
I want my to be a double to that is why I added
buffer1[tempint] = (double)sample32;
is there a better way of doing it ?
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
t sample = (short)((buffer[index + 1] << 8) |
                                        buffer[index + 0]);

                float sample32 = sample / 32768f;
                buffer1[tempint] = (double)sample32;
                tempint++;
}
and why do you have to divide by 32768f?
Jan 25, 2014 at 4:43 PM
To get an IEEE float sample from a 16bit PCM sample you need to divide it by 32768. That's just the way it is.

Have a look at the NAudio source, Wave16ToFloatProvider.cs show you how it's done.
Jan 25, 2014 at 4:55 PM
ok I change my code to this :

for (int index = 0; index < 32768; index += 2)
        {

            buffer1[tempint] = ((buffer[index + 1] << 8) |
                                    buffer[index + 0]);
            tempint++;

        }
because I want a double
that should work right ?
Jan 26, 2014 at 12:38 AM
What is buffer1 used for? I can't see why you would need a double for a sample, it should be either a 16bit int sample or a floating point sample.

16bit int sample ranges from -32768 to 32768
float sample ranges from about -1.0f to 1.0f

To turn a 16bit sample into a float you divide it by 32768. Casting it to a double just blows the sample range out of proportion, it will still be within the -1.0d to 1.0d range.

"for (int index = 0; index < 32768; index += 2)" means you are iterating through a total of 32768 samples. It should be "for (int index = 0; index < buffer1.Length; index += 2)"

The buffer would typically have 44100 samples per second per channel.
Jan 27, 2014 at 1:28 AM
buffer1 is a double array

I going send 32768 sample to my fft
because it has to be 2^n number of sample sent to the fft

I would told that double has more information than float and int
and my graphic class only takes in double

what do you mean by just blows the sample range out of proportion?
it have more useful information right?
for my FFT?
Jan 27, 2014 at 1:58 AM
Edited Jan 27, 2014 at 1:58 AM
It all makes sense now, casting to a double should work fine.

Using a Sample Collector/Aggregator may be the best solution. It's a much cleaner way of sending samples to an FFT visualizer.

Have a look at the AudioPlaybackDemo example app in the NAudio source. It should work fine with WaveIn.

AudioPlayback.cs
SampleAggregator.cs

Copy SampleAggregator.cs into your project, then have a look how AudioPlayback.cs interfaces with the SampleAggregator.

Specifically this function and the OnFftCalculated() function:
        private void OpenFile(string fileName)
        {
            try
            {
                var inputStream = new AudioFileReader(fileName);
                fileStream = inputStream;
                var aggregator = new SampleAggregator(inputStream);
                aggregator.NotificationCount = inputStream.WaveFormat.SampleRate / 100;
                aggregator.PerformFFT = true;
                aggregator.FftCalculated += (s, a) => OnFftCalculated(a);
                aggregator.MaximumCalculated += (s, a) => OnMaximumCalculated(a);
                playbackDevice.Init(aggregator);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Problem opening file");
                CloseFile();
            }
        }
Jan 27, 2014 at 9:14 PM
K24A3

I am a little lost here.

I was able to find AudioPlayback demo file but I was not able to find AudioPlayback.cs or
SampleAggregator.cs

http://naudio.codeplex.com/SourceControl/latest#NAudioDemo/AudioPlaybackDemo/AudioPlaybackPanel.cs
Jan 27, 2014 at 9:19 PM
Jan 27, 2014 at 9:53 PM
Edited Jan 27, 2014 at 9:54 PM
ok I got it ...

but I am not reading from a file.
I am reading from a microphone
void Voice()
        {
            //Byte[] buffer = new Byte[10];
            // sound from the Mic

            int deviceNumber = 0;
            waveIn = new WaveIn();
            waveIn.BufferMilliseconds = 250;
            waveIn.DeviceNumber = deviceNumber;
            waveIn.DataAvailable += waveIn_DataAvailable;
            waveIn.WaveFormat = new WaveFormat(44100, NAudio.Wave.WaveIn.GetCapabilities(deviceNumber).Channels);
            waveIn.StartRecording();
        }
SampleAggregator() take in a AudioFileReader

also what does this do ?
 aggregator.FftCalculated += (s, a) => OnFftCalculated(a);
                aggregator.MaximumCalculated += (s, a) => OnMaximumCalculated(a);
are they two events?
why is int fftLength = 1024? that is a small sample ... it is enough to do a fft on a live sample system ?
Jan 27, 2014 at 9:58 PM
what is with all the
this. ?
 public SampleAggregator(ISampleProvider source, int fftLength = 1024)
        {
            channels = source.WaveFormat.Channels;
            if (!IsPowerOfTwo(fftLength))
            {
                throw new ArgumentException("FFT Length must be a power of two");
            }
            this.m = (int)Math.Log(fftLength, 2.0);
            this.fftLength = fftLength;
            this.fftBuffer = new Complex[fftLength];
            this.fftArgs = new FftEventArgs(fftBuffer);
            this.source = source;
        }
you use this. when you are working with more that one thread right ?

but you are only reading from one file, so why would you need it ?
Jan 27, 2014 at 10:01 PM
why are you doing this ?
 aggregator.NotificationCount = inputStream.WaveFormat.SampleRate / 100;
why are you dividing my 100?
also are you using the default Sample rate?
Jan 27, 2014 at 10:09 PM
Edited Jan 27, 2014 at 10:09 PM
also in SampleAggregator.cs
the Read function calls Add function and the Add function calls the FFT function .
but where is the Read function called to start all of this off?
Jan 28, 2014 at 12:48 AM
Try SampleAggregator(wavein). I cant check if it works at the moment.

This is the event using Linq
aggregator.FftCalculated += (s, a) => OnFftCalculated(a);

This is how many times a second aggregator will send the FFT data to your OnFftCalculated function.
aggregator.NotificationCount = inputStream.WaveFormat.SampleRate / 100; // Your FFT visualizer will update 10 times a second

OnFftCalculated will be called 10 times a second and will send 1024 FFT data (not 1024 samples). FFT data is a range of peak frequencies detected in all the samples that were sent to the aggregator within that 1/10th of a second. The aggregator doesn't care how many samples it receives, it keeps on calculating the volume peaks, sends the current data, and resets 10 times a second.
Jan 28, 2014 at 1:17 AM
wait before I do all of that...
i just learned that my program is kind of working ...
I am using this site for testing now
http://onlinetonegenerator.com/?freq=5000
and not that youtube video ...

I always get half the right Frequency

I also did 3000Hz from that same site
and the highest point I get is 1499.249

I did 5000Hz
and I got 2500Hz

I did 261.625565Hz
and I got 131.890Hz
so why is that ?
Jan 28, 2014 at 1:21 AM
someone else told me that
the samples might actually be 8-bit samples, not 16-bit
if that is so then I am cutting my in coming samples in half
            PointPairList list = new PointPairList();
            PointPairList list2 = new PointPairList();
            byte[] buffer = e.Buffer;
            int bytesRecorded = e.BytesRecorded;
            points = new RollingPointPairList(32768 / 2);
            buffer1 = new double[(32768 / 2)];
            int tempint = 0;
            for (int index = 0; index < 32768; index += 2)
            {

                buffer1[tempint] = ((buffer[index + 1] << 8) |
                                        buffer[index + 0]);

                //float sample32 = sample / 32768f;
               // buffer1[tempint] = (double)sample32;
                tempint++;

            }

            DSP = new DSPclass(buffer1, 44100);
            DSP.FFT1();
            double[] F = new double[bytesRecorded];
            double[] C = new double[bytesRecorded];
            int temp = DSP.frequencies(F, C);
            
             LineItem myCurve;
            if (temp1 == true)
            {
                temp1 = false;
                for (int i = 0; i < buffer1.Length; i++)
                {
                    points.Add(counter, (double)buffer1[i]);
                    counter++;

                }
                myCurve = myPane.AddCurve("", points, System.Drawing.Color.Blue, SymbolType.Circle);
                if (counter >= 10)
                {
                    myPane.XAxis.Scale.Max = points[points.Count - 1].X;
                    myPane.XAxis.Scale.Min = myPane.XAxis.Scale.Max - 20;
                    zedGraphControl1.AxisChange();
                    zedGraphControl1.Invalidate();
                    zedGraphControl1.Refresh();
                }
                else
                {

                    zedGraphControl1.AxisChange();
                    zedGraphControl1.Invalidate();
                    zedGraphControl1.Refresh();
                }

                for (int u = 0; u < temp; u++)
                {
                    list2.Add((double)F[u], (double)C[u]);
                  //  richTextBox1.Text = richTextBox1.Text + " " + Convert.ToString(F[u]);
                }
               LineItem myCurve2 = myPane2.AddCurve("", list2, System.Drawing.Color.Blue, SymbolType.Circle);
                zedGraphControl2.AxisChange();
                zedGraphControl2.Invalidate();
                zedGraphControl2.Refresh();
            }
Jan 28, 2014 at 2:06 AM
Edited Jan 28, 2014 at 2:16 AM
If you can get it working then that's fine. I'd use SampleAggregator personally since it is done and tested.

i dont think it matters what the bitspersample is. max volume should still be about 1.0f
Jan 28, 2014 at 5:00 AM
I think it does...
it is it 8 bit samples that i am losing have my samples
but is it 16 bit then I am doing it right
so which is it ?
Jan 28, 2014 at 5:10 AM
Edited Jan 28, 2014 at 5:16 AM
so I just tried this :
  for (int index = 0; index < 32768; index++)
            {
                buffer1[tempint] = buffer[index]; 
                tempint++;
            }
and the fft is off
so maybe it really is 16bits

do anyone know anything that might help me?
Jan 28, 2014 at 5:43 AM
Not sure but here is the code to get SampleAggregator working

init()
{
        WaveIn wavein = new WaveIn();
        waveIn.BufferMilliseconds = 250;
        waveIn.DeviceNumber = 0;
        //waveIn.DataAvailable += waveIn_DataAvailable;
        waveIn.WaveFormat = new WaveFormat(44100, NAudio.Wave.WaveIn.GetCapabilities(deviceNumber).Channels);
        
        SampleAggregator aggregator = new SampleAggregator(wavein);
        aggregator.NotificationCount = inputStream.WaveFormat.SampleRate / 100;
        aggregator.PerformFFT = true;
        aggregator.FftCalculated += OnFftCalculated; // for spectrum analyzer
        //aggregator.MaximumCalculated += (s, a) => OnMaximumCalculated(a); // for volume peaks
        
        waveIn.StartRecording();    
}

        void audioGraph_FftCalculated(object sender, FftEventArgs e)
        {
            if (yourControl != null)
            {
                yourControl .OnFftCalculated(e.Result); // The float array, 0 to 1023 is the frequency peaks from 20hz to 20000hz (or there abouts)
            }
        }
Jan 28, 2014 at 6:32 AM
can anyone tell me if I am read in the sample right?
from the microphone ?

I know my fft works... because I compared it to mat lab...
I just need to know more about reading in for the microphone
Jan 28, 2014 at 8:01 AM
if you construct a signal chain (say WaveIn -> BufferedWaveProvider -> ToSampleProvider -> SampleAggregator), then you will still need something to "pull" data out the other end. Normally this is the soundcard, or a WaveFileWriter. In your case, you would have to call Read on the SampleAggregator and pull out the number of samples you knew had been put in.

So in your case, with nothing playing the data, I'd just pull out the code from within SampleAggregator and use that to build up buffers full of samples. When you've got the required number (e.g. 1024 or 2048), then you can run your FFT on it.