I am looking into graphing a waveform from the WaveIn function in nAudio. I have found an example online that achieves exactly what I am attempting to do, however it uses an external graphing library (Scottplot), and it is programmed in C# (I need VB). I have successfully got it go graph on the standard chart, and basically translated all of the code, and although it compiles, my stream is empty. I have tried to solve this for weeks with no luck.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NAudio.Wave;
using NAudio.CoreAudioApi;
using System.Numerics;
namespace microphone;
public partial class Form1 : Form
{
public WaveIn wi;
public BufferedWaveProvider bwp;
//public int envelopeMax;
private int RATE = 44100; // sample rate of the sound card
private int BUFFERSIZE = 1 << 13; // must be a multiple of 2
//private int BUFFERSIZE = 2048; // must be a multiple of 2
public Form1()
{
InitializeComponent();
WaveIn wi = new WaveIn();
wi.DeviceNumber = 0;
wi.WaveFormat = new NAudio.Wave.WaveFormat(RATE, 1);
bwp = new BufferedWaveProvider(wi.WaveFormat);
bwp.BufferLength = BUFFERSIZE * 2;
bwp.DiscardOnBufferOverflow = true;
wi.DataAvailable += (sender, e) => bwp.AddSamples(e.Buffer, 0, e.BytesRecorded);;
wi.StartRecording();
}
public void timer1_Tick(object sender, EventArgs e)
{
int frameSize = BUFFERSIZE;
byte[] frames = new byte[frameSize];
bwp.Read(frames, 0, frameSize);
if (frames.Length == 0)
return;
else if (frames[frameSize - 2] == 0)
{
label1.Text = "removed";
return;
}
else
label1.Text = "graphing";
// convert it to int32 manually (and a double for scottplot)
int SAMPLE_RESOLUTION = 16;
int BYTES_PER_POINT = SAMPLE_RESOLUTION / 8;
int[] vals = new int[frames.Length / BYTES_PER_POINT];
double[] Ys = new double[frames.Length / BYTES_PER_POINT];
double[] Xs = new double[frames.Length / BYTES_PER_POINT];
// double[] Ys2 = new double[frames.Length / BYTES_PER_POINT];
// double[] Xs2 = new double[frames.Length / BYTES_PER_POINT];
for (int i = 0; i < vals.Length; ++i)
{
// bit shift the byte buffer into the right variable format
byte hByte = frames[i * 2 + 1];
byte lByte = frames[i * 2 + 0];
vals[i] = (int)((hByte << 8) | lByte);
Xs[i] = i;
Ys[i] = vals[i];
// Xs2[i] = i * .001 * RATE / Ys.Length; // units are in kHz
}
chart1.ChartAreas[0].AxisX.Maximum = 400;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.Series[0].Points.DataBindXY(Xs, Ys);
/* Ys2 = FFT(Ys);
// update scottplot (FFT, frequency domain)
chart2.ChartAreas[0].AxisX.Maximum = 10;
chart2.ChartAreas[0].AxisX.Minimum = 0;
chart2.Series[0].Points.DataBindXY(Xs2.Take(Xs2.Length / 2).ToArray(), Ys2.Take(Ys2.Length / 2).ToArray());
// update the displays
Application.DoEvents();
*/
}
//public double[] FFT(double[] data)
//{
// double[] fft = new double[data.Length]; // this is where we will store the output (fft)
// Complex[] fftComplex = new Complex[data.Length]; // the FFT function requires complex format
//
// for (int i = 0; i < data.Length; ++i)
// fftComplex[i] = new(data[i], 0); // make it complex format (imaginary = 0)
//
// Accord.Math.FourierTransform.FFT(fftComplex, Accord.Math.FourierTransform.Direction.Forward);
//
// for (int i = 0; i < data.Length; ++i)
// {
// fft[i] = fftComplex[i].Magnitude; // back to double
// //fft[i] = Math.Log10(fft[i]); // convert to dB
// }
//
// return fft;
//}
public void chart1_Click(object sender, EventArgs e) { }
}
That was the original code I've modified, and got to work successfully, without the extra bits (commented out).
Imports NAudio
Imports NAudio.CoreAudioApi
Public Class Form1
Public WithEvents wi As New NAudio.Wave.WaveIn() 'Wave 'in Stream Generates 'by Naudio
Public WaveFormat As New NAudio.Wave.WaveFormat(44100, 1) 'Wave In format
'AddHandler wi.DataAvailable, AddressOf StreamWavein_DataAvailable
Public bwp As New NAudio.Wave.BufferedWaveProvider(wi.WaveFormat)
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'wi.DeviceNumber = 0
'Dim waveforamt As New NAudio.Wave.WaveFormat(44100, 1)
'AddHandler wi.DataAvailable, AddressOf StreamWavein_DataAvailable
'Dim bwp As New NAudio.Wave.BufferedWaveProvider(wi.WaveFormat)
bwp.BufferLength = 1 << 13
bwp.DiscardOnBufferOverflow = True
wi.StartRecording()
Chart1.ChartAreas(0).AxisX.Maximum = 400
Chart1.ChartAreas(0).AxisX.Minimum = 0
End Sub
Public Sub StreamWavein_DataAvailable(ByVal sender As Object, ByVal e As NAudio.Wave.WaveInEventArgs) Handles wi.DataAvailable
bwp.AddSamples(e.Buffer, 0, e.BytesRecorded)
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim frameSize As Integer = 1 << 13
Dim frames(frameSize) As Byte
bwp.Read(frames, 0, frameSize)
If frames.Length = 0 Then
Return
Else If frames(frameSize - 2) = 0 Then
Label1.Text = "removed"
Return
Else
Label1.Text = "graphing"
End If
Dim SAMPLE_RESOLUTION As Integer = 16
Dim BYTES_PER_POINT As Integer = SAMPLE_RESOLUTION / 8
Dim vals(frames.Length / BYTES_PER_POINT) As Integer
Dim Ys(frames.Length / BYTES_PER_POINT) As Double
Dim Xs(frames.Length / BYTES_PER_POINT) As Double
Dim i As Integer
For i = 0 To vals.Length Step 1
Dim hbyte As Byte = frames(i * 2 + 1)
Dim lbyte As Byte = frames(i * 2 + 0)
vals(i) = CInt(CShort((hbyte << 8) Or lbyte))
Xs(i) = i
Ys(i) = vals(i)
Next
Chart1.Series("Series1").Points.DataBindXY(Xs, Ys)
End Sub
End Class
I'm not sure where I went wrong, but any help would be greatly appreciated.