0 Comments
Suppose you want to not just play back some audio, but record what you are playing to a WAV file. This can be achieved in NAudio by creating an IWaveProvider whose read method reads from another IWaveProvider but also writes to disk as it goes. This is very easy to implement, and the WaveRecorder class I present here will be added to NAudio shortly. Our WaveRecorder also needs to be disposable, as we will want to close the WAV file when we are finished.
/// <summary>
/// Utility class to intercept audio from an IWaveProvider and
/// save it to disk
/// </summary>
public class WaveRecorder : IWaveProvider, IDisposable
{
    private WaveFileWriter writer;
    private IWaveProvider source;
 
    /// <summary>
    /// Constructs a new WaveRecorder
    /// </summary>
    /// <param name="destination">The location to write the WAV file to</param>
    /// <param name="source">The source Wave Provider</param>
    public WaveRecorder(IWaveProvider source, string destination)
    {
        this.source = source;
        this.writer = new WaveFileWriter(destination, source.WaveFormat);
    }
     
    /// <summary>
    /// Read simply returns what the source returns, but writes to disk along the way
    /// </summary>
    public int Read(byte[] buffer, int offset, int count)
    {
        int bytesRead = source.Read(buffer, offset, count);
        writer.WriteData(buffer, offset, bytesRead);
        return bytesRead;
    }
 
    /// <summary>
    /// The WaveFormat
    /// </summary>
    public WaveFormat WaveFormat
    {
        get { return source.WaveFormat; }
    }
 
    /// <summary>
    /// Closes the WAV file
    /// </summary>
    public void Dispose()
    {
        if (writer != null)
        {
            writer.Dispose();
            writer = null;
        }
    }
}

Now we have our WaveRecorder, we can insert it anywhere in the chain we like. The most obvious place is right at the end of the chain. So we wrap the WaveStream or WaveProvider we would normally pass to the Init method of our IWavePlayer with the WaveRecorder class. To demonstrate, I will extend the sine wave generating code I created recently, to save the sine wave you are playing to disk. Only three extra lines of code are required:
IWavePlayer waveOut;
WaveRecorder recorder; 

private void button1_Click(object sender, EventArgs e)
{
    StartStopSineWave();
}

void StartStopSineWave()
{
    if (waveOut == null)
    {
        var sineWaveProvider = new SineWaveProvider16();
        sineWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
        sineWaveProvider.Frequency = 500;
        sineWaveProvider.Amplitude = 0.1f;
        recorder = new WaveRecorder(sineWaveProvider, @"C:\Users\Mark\Documents\sine.wav");
        waveOut = new WaveOut();
        waveOut.Init(recorder);
        waveOut.Play();
    }
    else
    {
        waveOut.Stop();
        waveOut.Dispose();
        waveOut = null;
        recorder.Dispose();
        recorder = null;                
    }
}
Want to get up to speed with the the fundamentals principles of digital audio and how to got about writing audio applications with NAudio? Be sure to check out my Pluralsight courses, Digital Audio Fundamentals, and Audio Programming with NAudio.
Vote on HN

Comments

Comment by Mark H

hi n20,
have you got the very latest NAudio source code out from Codeplex?

Comment by Mark H

This comment has been removed by the author.

Comment by n2o

Version that I tried I downloaded today from Codeplex.

Comment by Mark H

You need to go to the source code tab and download the latest and build it. NAudio 1.3 has not yet been released yet.

Here's the code for the latest IWaveProvider:
naudio.codeplex.com/.../28979

Comment by Jelle

Hi Mark,

I would like to record only the audio from one single application that plays music. is that possible with the NAUDIO lib ?

thanks!

Jelle

Comment by n2o

This comment has been removed by the author.

Comment by n2o

BTW I am using XP, seems that newest NAudio Demo has that function but as exeption said "This functionality is only supported on Windows Vista or newer."

One more question about recorder buffer, it contais bytes, so each audio sample is 8bit or divided into several array elements?

Comment by Mark H

hi n2o, you can't use WASAPI capture on XP. Use WaveIn instead. See my voice recorder article on the Coding4Fun website to learn more about recording audio in NAudio.

blogs.msdn.com/.../9905168.aspx

Comment by JC

Hi Mark! I'm on Windows 7 and am struggling to get NAudio to record the stereo mix - is this possible, maybe using WASAPI as opposed to WaveIn? I'm not sure how to do this with NAudio if it is.

I've used the tutorial example 5 from Codeplex and clicked the "Record all output from my soundcard" button, but it only records what is coming in from the microphone. Any pointers would be greatly appreciated!! Many thanks.

Comment by Mark H

hi JC, it probably depends on your sound-card drivers whether any of the WaveIn options can do this programatically. You might need to get the windows mixer up to select your recording source to make it work.

Comment by JIbin

HI,
Now i am able to capture sound and at the same time i send it over network like this



private void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
byte[] buffer = e.Buffer;

byte[] dataToWrite = ALawEncoder.ALawEncode(buffer);

if (socket_Audio != null)
socket_Audio.SendTo(dataToWrite, new IPEndPoint(IPAddress.Parse(RemoteIpv6), SoundPort));

}



Now the problem that i am facing is how to get back this audio at receiving end and and send it to the speaker of the system

I am just starting a new thread for rxving data from network

myAudioThread = new Thread(new ThreadStart(AudioListener));
myAudioThread.Start();

And in the AudioListener() i use the following code

#region for Audio socket Its rxving audio always

try
{

socket_Audio = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

socket_Audio.Bind(new IPEndPoint(IPAddress.IPv6Any, SoundPort));
IPEndPoint remoteEP = new IPEndPoint(IPAddress.IPv6Any, SoundPort);
//Receive data.

byte[] byteData;
while (true)
{

byteData = new byte[2048];
//Receive data.
socket_Audio.Receive(byteData);

//G711 compresses the data by 50%, so we allocate a buffer of double
//the size to store the decompressed data.
byte[] byteDecodedData = new byte[byteData.Length * 2];

//Decompress data using the proper vocoder.

ALawDecoder.ALawDecode(byteData, out byteDecodedData);



}

Now the decoded audio is in the byte array byteDecodedData.How i send it to speaker of that system.

I found only waveOut.Play() and

public override int Read(byte[] buffer, int offset, int count)
{

//code to process data

}

in the examples

Pls guide me to the next step....Pls let me know if i am in wrong path.

Thanks

JIbin

jibin.mn@hotmail.com

JIbin
Comment by Mark H

@Jlbin - have a look at the BufferedWaveProvider in the latest code. This can be used to buffer up your data read from the network and can be used to feed the soundcard

Comment by Seingalt

Hi Mark,

Great lib by the way.

I just want to ask if you have any ideas about recording conversations?

Is it possible to capture it using WASAPI or, in my case since I'm using win XP, WaveIn? Or do you know any alternatives to that?

seemenomore1987@gmail.com

Comment by Mark H

@Seingalt what do you mean by conversations? conversations on what program? if you mean skype, then you could look into using the Skype4Com object

Comment by Seingalt

Hi Mark,

I'd take a look at skype4com objects.

Basically, I have a web application that should allow the user to call (for example a Call Center Rep.) from that page and record that conversation.

I have done some research on skype4com already but somehow I'm still having a hard time on how I could use it on my application.

If you know or have any articles about it just post it here. Like "Using skype4com objects in your web application for biginners"

Thanks!

Comment by Anonymous

Thanks for the great example. I already noticed it at NAudio but since it was not actually used in tehir code, the sample was very helpful.

One question: I would like to use the WaveRecorder combined with the ASIO4All. The NADIO Asio only has AsioOut.cs. Is there a sample of how the Wave Recorder is used for ASIO?

Thanks
HM

Anonymous
Comment by Mark H

sadly NAudio ASIO support is very basic and doesn't work with all soundcards at the moment

Comment by Anonymous

Thanks Mark. I'm still hopefull, and struggeling with adding the ASIO-in interface by myself. I'm trying to figure out where to fit the WaveRecorder class.
Since WaveRecorder is actually an IWaveProvider, I plan to add AsioIn.cs which has "recordStream" of class WaveRecord (similar to AsioOut). I'm jyust confused wehther or not I need to add IWaveRecorder, similar to IWavePlayer.

Thanks you very much!
HM

Anonymous
Comment by Mark H

@HM, an AsioIn class should implement IWaveIn

Comment by Anonymous

Can I use that source code on windows mobile? Or do you have a code that record a wave file format on windows mobile? (records in a wave file format ..)

Anonymous
Comment by Anonymous

I want to change the frequency of this sinus wave without interrupting it and quite quickly . You said in your previous posts that I need to do it smoothly , how can I do that ? Sorry but I'm a beginner

Anonymous
comments powered by Disqus