Introduction

As I already mentioned in my article A low-level audio player in C#, there are no built-in classes in the .NET framework for dealing with sound. This holds true not only for audio playback, but also for audio capture.

It should be noted, though, that the Managed DirectX 9 SDK does include classes for high-level and low-level audio manipulation. However, sometimes you don’t want your application to depend on the full DX 9 runtime, just to do basic sound playback and capture, and there are also some areas where Managed DirectSound doesn’t help at all (for example, multi-channel sound playback and capture).

Nevertheless, I strongly recommend you to use Managed DirectSound for sound playback and capture unless you have a good reason for not doing so.

This article describes a sample application that uses the waveIn and waveOut APIs in C# through P/Invoke to capture an audio signal from the sound card’s input, and play it back (almost) at the same time.

Using the code

The sample code reuses the WaveOutPlayer class from my article A low-level audio player in C#. The new classes in this sample are WaveInRecorder and FifoStream.

The FifoStream class extends System.IO.Stream to implement a FIFO (first-in first-out) of bytes. The overridden Write method adds data to the FIFO’s tail, and the Read method peeks and removes data from the FIFO’s head. The Length property returns the amount of buffered data at any time. Calling Flush will clear all pending data.

The WaveInRecorder class is analogous to the WaveOutPlayer class. In fact, if you look at the source files, you’ll notice that the implementations of these classes are very similar. As with WaveOutPlayer, the interface of this class has been reduced to the strict minimum.

Creating an instance of WaveInRecorder will cause the system to start recording immediately. Here’s the code that creates the WaveOutPlayer and WaveInRecorder instances.

The WaveInRecorder constructor takes five parameters. Except for the last parameter, their meaning is the same as in WaveOutPlayer.

The first parameter is the ID of the wave input device that you want to use. The value -1 represents the default system device, but if your system has more than one sound card, then you can pass any number from 0 to the number of installed sound cards minus one, to select a particular device.

The second parameter is the format of the audio samples.

The third and forth parameters are the size of the internal wave buffers and the number of buffers to allocate. You should set these to reasonable values. Smaller buffers will give you less latency, but the captured audio may have gaps on it if your computer is not fast enough.

The fifth and last parameter is a delegate that will be called periodically as internal audio buffers are full of captured data. In the sample application we just write the captured data to the FIFO, like this:

Conclusion

This sample demonstrates how to combine the waveIn and waveOut APIs in C#. As an exercise, you may want to combine this code with the audio effect framework in the article Programming Audio Effects in C#, to apply effects to a live audio input in real-time, although latency may be an issue for certain applications.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Ianier Munoz lives in France and works as a senior consultant and analyst for an international consulting firm. His specialty is in multimedia applications, and he has authored some popular software, such as American DJ's Pro-Mix, Chronotron and Adapt-X.

i am developing an app for my Client to save skype audio calls communication ,i have recorded the voice of sender and reciever or u may call as caller and callee but they saved separately.i want to combine in such a way that they sound like normal communication between caller n callee ,what i have done i concat the two voices ,but it seems to have useless idea.so kindly help me in this regard.

I first tried your suggestions, after digging into too many definitions it seemed to work OK but then I discovered naudio which works great on both x86 and x64 builds. You can check it @ http://naudio.codeplex.com/

The above example showing the waveInOpen API may be slightly in error. The uDeviceID value is defined as uint in the MSDN definition of WaveInOpen, not UINT_PTR.

In the case of waveInOpen the uDeviceID should be left as int (or uint) rather than UINT_PTR.

Note the reason int is frequently used for uDeviceID rather than uint is because the default device (WAVEMAPPER) value is -1. If int is used the default input device can be directly specified as -1. If the theoretically correct uint type is used WAVEMAPPER becomes harder to define. For example:

I have try this code, on two usb-souncards, and it works, but it will put more and more delay on the sound from the capture device to the play device, I have try to count up the numbers of "Data_arrived" and "Filler" events. Ex. when i have recived 917 "Data_arrived" events i have only recived 910 "Filler" events?? how can i solve this problem???

Hii'm a beginner that want to give an analog signal to soundcard line in and get the digitized data and process itthe important point is that i should process the digitized data exactly as it is digitized not to get all digitized data and then process it.

I am making an editor for the engine that will run both for Windows and xBox 360, I am using the XNA technology for the engine as it is the best for this stuff. However, the editor does not require the use of the XNA technology. How do I load sound in the form, have a button that plays the sound, stop the sound and then save the sound in my own .bin file?

Let us say the sound.bin have two sound files stored in them, not just a little c:\location\sound.wav string that directs it to the sound, but the actual two sounds are stored in the file. How do you do that? And Using the reverse method of saving these sounds to load them and store them in the array, array[0]=holds sound 1, array[1]=holds sound 2, then using the function I would be able to play that sound, how do I do that?

1) Click on the Add Sound button, a windows dialog box comes up. I select the .wav file I want to add.2) When I select the file it stores it in an array and puts in the listbox: sound 03) I click Add Sound button again, a window dialog box comes up. I select the .wav file I want to add.4) When I select the file it stores it in an array and puts in the listbox: sound 15) When I select the item in the listbox.selectIndex = 0, and press the Play button it plays the sound 0 from the Array[0] index.6) When I select the item in the listbox.selectindex =1, and press the Play button it plays the sound 1 from the Array[1] index.7) When I press the OK button in the Window, before the Window performs the action this.Close();, it saves the information in the Array in a file called test.bin.8) The information that is stored in the Array is the actual sound, which is sound 0 and sound 1.9) When the form loads, it executes the LoadSound() function I make and what it does it looks at the test.bin file and fills the Array[0] and Array[1] with Sound 0 and Sound 1

So what happens is that I toke an actual normal file0.wav and file1.wav and saved them both as a single file called test.bin. The test.bin holds sound0 and sound 1 or whatever sound name you called it with the actual file0.wav and file1.wav. When you open test.bin you see gibberish because it is two .wav files saved together as test.bin. The test.bin can hold as many .wav files you want. So let us say the first file0.wav is 12 KB and the second file1.wav is 12 KB, the test.bin should be 24 KB plus whatever bytes or KBs extra about the information of the sound. Can anyone help to the right direction how to achieve this? Thanks in advance.

Hi IanIt's such a nice article.I implement your code in my video and audio conferencing project.The code is so easy to use for anyone.But i have a problem regarding to audio channels.I want to listen left channel or right channel in both channels (in both ear) of the speaker or headphone. is it possible to duplicate channels ,if yes then how ? Any type of help will be appreciated.Thanks in advance ............

tyvm, this is a great example code!! it loaded and converted fine for the vs 2010 edition and worked excellent (had a warning on first build and test, but the warning actually dissappeared on second build)the program does not seem to save a recorded file ing the /record dir i have created but that is not something i am seeking at this time.

no questions here, just a thanks to the author for sharing the knowledge, and cudos to you!