I'm quite new to c# and I've been trying to write a program that would record sound, display it's wave, modify it and play it in real-time. Drawing graph works good because I used some examples from the internet for it, but I can't get the playback right. I've been trying to use "WaveOut" with double array converted to byte but it gives me some terrible noise but I think I can hear some things from my input. Thanks in advance!
Here are most important parts of code:
(Ys2 is array of doubles with samples)
static byte[] GetBytesAlt(double[] values)
{
var result = new byte[values.Length * sizeof(double)];
Buffer.BlockCopy(values, 0, result, 0, result.Length);
return result;
}
public void UpdateAudioGraph()
{
[.....]
WaveOut wo = new WaveOut();
byte[] Ys3 = GetBytesAlt(Ys2);
IWaveProvider provider = new RawSourceWaveStream(
new MemoryStream(Ys3), new WaveFormat());
wo.Init(provider);
wo.Play();
[.....]
}
private void timer1_Tick(object sender, EventArgs e)
{
UpdateAudioGraph();
}
*EDIT
I managed to do that. There's still some echo but it works good. Here's the result:
public partial class Form1 : Form
{
static WaveFormat waveFormat;
static int bufferMilliseconds;
static int x = 0;
public WaveIn wi;
public BufferedWaveProvider bwp;
public BufferedWaveProvider provider;
public Int32 envelopeMax;
public IWavePlayer wo;
double cutoff = 10000;
private int RATE = 44100; // sample rate of the sound card
private int BUFFERSIZE = (int)Math.Pow(2, 16); // must be a multiple of 2
//private int BUFFERSIZE = 44100;
public byte[] frames;
public Form1()
{
InitializeComponent();
// see what audio devices are available
int devcount = WaveIn.DeviceCount;
Console.Out.WriteLine("Device Count: {0}.", devcount);
//waveFormat = new NAudio.Wave.WaveFormat.(RATE, 1);
waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(RATE, 1);
bufferMilliseconds = (int)((double)BUFFERSIZE / (double)RATE * 1000.0);
// get the WaveIn class started
WaveIn wi = new WaveIn();
wi.DeviceNumber = 0;
wi.WaveFormat = waveFormat;
wi.BufferMilliseconds = bufferMilliseconds;
// create a wave buffer and start the recording
wo = new DirectSoundOut();
wi.DataAvailable += new EventHandler<WaveInEventArgs>(wi_DataAvailable);
bwp = new BufferedWaveProvider(waveFormat);
bwp.BufferLength = BUFFERSIZE * 8;
bwp.DiscardOnBufferOverflow = true;
wi.StartRecording();
wo.Init(bwp);
wo.Play();
}
// adds data to the audio recording buffer
void wi_DataAvailable(object sender, WaveInEventArgs e)
{
int size = e.BytesRecorded;
label3.Text = size.ToString();
frames = new byte[size];
e.Buffer.CopyTo(frames, 0);
float[] values = new float[size / 4];
for (int i = 0; i < values.Length; i++)
{
values[i] = BitConverter.ToSingle(frames, i * 4);
}
double[] doubleArray = Array.ConvertAll(values, x => (double)x);
doubleArray = Butterworth(doubleArray,cutoff);
values = Array.ConvertAll(doubleArray, y => (float)y);
frames = values.SelectMany(value => BitConverter.GetBytes(value)).ToArray();
x++;
label2.Text = x.ToString();
label1.Text = timer2.Interval.ToString();
bwp.AddSamples(frames, 0, size);
}
You are providing audio in doubles (presumably mono), but the playback code is expecting 16 bit stereo audio. If you can provide the audio as float
then you can use WaveFormat.CreateIeeeFloatWaveFormat(44100,1)
(with the correct sample rate and channel count for your audio) in the constructor to RawSourceWaveStream