我正在研究从 nAudio 中的 WaveIn 函数绘制波形。我在网上找到了一个示例,它完全实现了我正在尝试做的事情,但是它使用了一个外部图形库(Scottplot),并且它是用 C# 编程的(我需要 VB)。我已经成功地将它放在标准图表上,并且基本上翻译了所有代码,虽然它编译了,但我的流是空的。我已经尝试解决这个问题好几个星期了,但没有运气。
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; // installed with nuget
using NAudio.CoreAudioApi;
using System.Numerics;
namespace microphone
{
public partial class Form1 : Form
{
public WaveIn wi;
public BufferedWaveProvider bwp;
//public Int32 envelopeMax;
private int RATE = 44100; // sample rate of the sound card
private int BUFFERSIZE = (int) Math.Pow(2,13); // must be a multiple of 2
//private int BUFFERSIZE = 2048; // must be a multiple of 2
public Form1()
{
InitializeComponent();
// see what audio devices are available
int devcount = WaveIn.DeviceCount;
Console.Out.WriteLine("Device Count: {0}.", devcount);
// get the WaveIn class started
WaveIn wi = new WaveIn();
wi.DeviceNumber = 0;
wi.WaveFormat = new NAudio.Wave.WaveFormat(RATE, 1);
// create a wave buffer and start the recording
wi.DataAvailable += new EventHandler<WaveInEventArgs>(wi_DataAvailable);
bwp = new BufferedWaveProvider(wi.WaveFormat);
bwp.BufferLength = BUFFERSIZE * 2;
bwp.DiscardOnBufferOverflow = true;
wi.StartRecording();
}
// adds data to the audio recording buffer
void wi_DataAvailable(object sender, WaveInEventArgs e)
{
bwp.AddSamples(e.Buffer, 0, e.BytesRecorded);
}
public void timer1_Tick(object sender, EventArgs e)
{
// read the bytes from the stream
int frameSize = BUFFERSIZE;
var frames = new byte[frameSize];
bwp.Read(frames, 0, frameSize);
if (frames.Length == 0) return;
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;
Int32[] vals = new Int32[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)(short)((hByte << 8) | lByte);
Xs[i] = i;
Ys[i] = vals[i];
// Xs2[i] = (double)i/Ys.Length*RATE/1000.0; // units are in kHz
}
chart1.ChartAreas[0].AxisX.Maximum = 400;
chart1.ChartAreas[0].AxisX.Minimum= 0;
chart1.Series[0].Points.DataBindXY(Xs, Ys);
//update scottplot (FFT, frequency domain)
/* Ys2 = FFT(Ys);
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 Complex(data[i], 0.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;
// //todo: this could be much faster by reusing variables
//}
public void chart1_Click(object sender, EventArgs e) { }
}
}
那是我修改过的原始代码,并且可以成功运行,没有多余的位(注释掉)。
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 wi As NAudio.Wave.WaveIn()
'Public bwp
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Dim wi As New NAudio.Wave.WaveIn()
'wi.DeviceNumber = 0
'Dim waveforamt As New NAudio.Wave.WaveFormat(44100, 1)
''wi.DataAvailable += New EventHandler < WaveInEventArgs > (wi_DataAvailable)\
'AddHandler wi.DataAvailable, AddressOf StreamWavein_DataAvailable
'Dim bwp As New NAudio.Wave.BufferedWaveProvider(wi.WaveFormat)
bwp.BufferLength = ((Math.Pow(2, 13)) * 2)
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
frameSize = Math.Pow(2, 13)
Dim frames(frameSize) As Byte
bwp.Read(frames, 0, frameSize)
If frames.Length = 0 Then
Return
End If
If frames(frameSize - 2) = 0 Then
Label1.Text = "removed"
Return
Else
Label1.Text = "graphing"
End If
Dim SAMPLE_RESOLUTION As Integer
SAMPLE_RESOLUTION = 16
Dim BYTES_PER_POINT As Integer
BYTES_PER_POINT = SAMPLE_RESOLUTION / 8
Dim vals(frames.Length / BYTES_PER_POINT) As Int32
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
Dim lbyte As Byte
hbyte = frames(i * 2 + 1)
lbyte = 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
我不确定我哪里出错了,但任何帮助将不胜感激。