Tools: C# Speech Recording: A Detailed Guide to Implementing Voice Recording with the NAudio Library

Tools: C# Speech Recording: A Detailed Guide to Implementing Voice Recording with the NAudio Library

Source: Dev.to

Key Code Analysis ## Namespace and Class Definition ## Fields and Constructor ## Device and Volume Settings ## Starting and Stopping Recording ## Audio Data Processing and Recording End Handling ## Practical Application and Expansion In the field of audio processing, C# provides developers with powerful development tools thanks to its robust ecosystem and rich class libraries. The NAudio library is an excellent open-source library for audio processing that supports various audio formats and audio device operations. Today, we will conduct an in-depth analysis of a piece of C# code based on the NAudio library to implement voice recording functionality, guiding you through the technical details behind speech recording. This code defines a class named SpeechRecorder, which is responsible for the core functions of voice recording, including device searching, volume setting, starting and stopping recording, and writing recorded audio data to a file. Additionally, this class provides a RecordingStopped event to notify external code when the recording stops. At the beginning of the code, namespaces such as NAudio.CoreAudioApi and NAudio.Wave are imported. These namespaces contain key classes in the NAudio library for audio device management and audio stream processing. The SpeechRecorder class serves as the core carrier of the entire voice recording functionality. The RecordingStopped event is used to trigger when the recording stops, allowing external code to execute related operations by subscribing to this event. The fileName field is used to store the path of the recorded audio file. The constructor receives this path as a parameter, facilitating the subsequent writing of recorded audio data to the specified file. The FindDevices method uses the MMDeviceEnumerator class to enumerate all active audio capture devices (usually microphones). The SetMicrophoneVolume method obtains the device list by calling FindDevices and then sets the volume for each device. The volume range is from 0 to 100, and it is set through the MasterVolumeLevelScalar property. Since this property value is a floating-point number between 0 and 1, the passed volume value is divided by 100 for conversion. The Existed method is used to determine whether there are available audio capture devices. The Start method is the entry point for initiating the recording function. It first calls SetMicrophoneVolume to set the microphone volume to 100, then creates a WaveIn object and sets its audio format to a sampling rate of 16000Hz, 16-bit quantization, and mono. Then, it binds handling methods for the DataAvailable and RecordingStopped events of the WaveIn object, creates a WaveFileWriter object to write the recorded audio data to the specified file, and finally calls the StartRecording method to start recording. The Stop method is used to stop recording, implemented by calling the StopRecording method of the WaveIn object. The WaveSourceDataAvailable method is triggered when there is audio data available in the WaveIn object. It writes the received audio data to the WaveFileWriter object and calls the Flush method to ensure the data is written to the file in a timely manner. The WaveSourceRecordingStopped method is triggered when the recording stops. It is responsible for releasing the resources occupied by the WaveIn and WaveFileWriter objects and calls the OnRecordingStopped method to trigger the RecordingStopped event. The OnRecordingStopped method is the actual execution method for triggering the RecordingStopped event. This code provides a basic framework for voice recording functionality. In practical applications, it can be expanded according to requirements. For example, adding more audio format support can be achieved by modifying the WaveFormat parameters; or adding recording duration limits, real-time audio visualization, and other functions. Meanwhile, when handling audio devices and file operations, attention should be paid to exception handling to ensure the stability and robustness of the program. Through the analysis of this code, you should have a deeper understanding of implementing voice recording functionality in C# using the NAudio library. I hope this blog post can provide assistance for your audio processing development work. If you encounter problems in practical applications, feel free to discuss them in the comments section! The above blog post provides a detailed analysis of the voice recording code. If you feel that certain parts need supplementation or want to add code analysis for other functions, please feel free to let me know at any time. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: using NAudio.CoreAudioApi; using NAudio.Wave; using System; using System.Collections.Generic; using System.Linq; public class SpeechRecorder { // Code omitted } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: using NAudio.CoreAudioApi; using NAudio.Wave; using System; using System.Collections.Generic; using System.Linq; public class SpeechRecorder { // Code omitted } CODE_BLOCK: using NAudio.CoreAudioApi; using NAudio.Wave; using System; using System.Collections.Generic; using System.Linq; public class SpeechRecorder { // Code omitted } COMMAND_BLOCK: public event EventHandler<StoppedEventArgs> RecordingStopped; private readonly string fileName; public SpeechRecorder(string fileName) { this.fileName = fileName; } Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: public event EventHandler<StoppedEventArgs> RecordingStopped; private readonly string fileName; public SpeechRecorder(string fileName) { this.fileName = fileName; } COMMAND_BLOCK: public event EventHandler<StoppedEventArgs> RecordingStopped; private readonly string fileName; public SpeechRecorder(string fileName) { this.fileName = fileName; } COMMAND_BLOCK: private void SetMicrophoneVolume(int volume) { var devices = FindDevices(); foreach (var device in devices) { device.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f; } } public static IEnumerable<MMDevice> FindDevices() { return new MMDeviceEnumerator() .EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active); } public static bool Existed() { var devices = FindDevices(); return devices.Any(); } Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: private void SetMicrophoneVolume(int volume) { var devices = FindDevices(); foreach (var device in devices) { device.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f; } } public static IEnumerable<MMDevice> FindDevices() { return new MMDeviceEnumerator() .EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active); } public static bool Existed() { var devices = FindDevices(); return devices.Any(); } COMMAND_BLOCK: private void SetMicrophoneVolume(int volume) { var devices = FindDevices(); foreach (var device in devices) { device.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f; } } public static IEnumerable<MMDevice> FindDevices() { return new MMDeviceEnumerator() .EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active); } public static bool Existed() { var devices = FindDevices(); return devices.Any(); } CODE_BLOCK: public void Start() { this.SetMicrophoneVolume(100); this.source = new WaveIn { WaveFormat = new WaveFormat(16000, 16, 1) }; this.source.DataAvailable += WaveSourceDataAvailable; this.source.RecordingStopped += WaveSourceRecordingStopped; this.writer = new WaveFileWriter(fileName, source.WaveFormat); this.source.StartRecording(); } public void Stop() { this.source?.StopRecording(); } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: public void Start() { this.SetMicrophoneVolume(100); this.source = new WaveIn { WaveFormat = new WaveFormat(16000, 16, 1) }; this.source.DataAvailable += WaveSourceDataAvailable; this.source.RecordingStopped += WaveSourceRecordingStopped; this.writer = new WaveFileWriter(fileName, source.WaveFormat); this.source.StartRecording(); } public void Stop() { this.source?.StopRecording(); } CODE_BLOCK: public void Start() { this.SetMicrophoneVolume(100); this.source = new WaveIn { WaveFormat = new WaveFormat(16000, 16, 1) }; this.source.DataAvailable += WaveSourceDataAvailable; this.source.RecordingStopped += WaveSourceRecordingStopped; this.writer = new WaveFileWriter(fileName, source.WaveFormat); this.source.StartRecording(); } public void Stop() { this.source?.StopRecording(); } CODE_BLOCK: private void WaveSourceDataAvailable(object sender, WaveInEventArgs e) { if (writer != null) { writer.Write(e.Buffer, 0, e.BytesRecorded); writer.Flush(); } } private void WaveSourceRecordingStopped(object sender, StoppedEventArgs e) { if (source != null) { source.Dispose(); source = null; } if (writer != null) { writer.Close(); writer.Dispose(); writer = null; } this.OnRecordingStopped(sender, e); } protected void OnRecordingStopped(object sender, StoppedEventArgs e) { this.RecordingStopped?.Invoke(sender, e); } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: private void WaveSourceDataAvailable(object sender, WaveInEventArgs e) { if (writer != null) { writer.Write(e.Buffer, 0, e.BytesRecorded); writer.Flush(); } } private void WaveSourceRecordingStopped(object sender, StoppedEventArgs e) { if (source != null) { source.Dispose(); source = null; } if (writer != null) { writer.Close(); writer.Dispose(); writer = null; } this.OnRecordingStopped(sender, e); } protected void OnRecordingStopped(object sender, StoppedEventArgs e) { this.RecordingStopped?.Invoke(sender, e); } CODE_BLOCK: private void WaveSourceDataAvailable(object sender, WaveInEventArgs e) { if (writer != null) { writer.Write(e.Buffer, 0, e.BytesRecorded); writer.Flush(); } } private void WaveSourceRecordingStopped(object sender, StoppedEventArgs e) { if (source != null) { source.Dispose(); source = null; } if (writer != null) { writer.Close(); writer.Dispose(); writer = null; } this.OnRecordingStopped(sender, e); } protected void OnRecordingStopped(object sender, StoppedEventArgs e) { this.RecordingStopped?.Invoke(sender, e); }