Recording audio with NAudio cuts me off - c#

I am recording an audio to send it to send it to Google speech to text but when I make the audio with naudio it records me only 5 seconds and from there it stops recording. I copy the code in C #, this is my first time using this API, but I don't know why it cuts me, if it should stop recording when I press the save button, the application is a simple form with 2 buttons, one for recording and the other for stop.
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private BufferedWaveProvider bwp;
WaveIn waveIn;
WaveOut waveOut;
WaveFileWriter writer;
WaveFileReader reader;
string output = "audio.raw";
public Form1()
{
InitializeComponent();
waveOut = new WaveOut();
waveIn = new WaveIn();
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
waveIn.WaveFormat = new NAudio.Wave.WaveFormat(16000, 1);
bwp = new BufferedWaveProvider(waveIn.WaveFormat);
bwp.DiscardOnBufferOverflow = true;
btnRecordVoice.Enabled = true;
btnSave.Enabled = false;
//btnSpeechInfo.Enabled = false;
}
private void btnRecordVoice_Click(object sender, EventArgs e)
{
if (NAudio.Wave.WaveIn.DeviceCount < 1)
{
Console.WriteLine("No se encuentra un microfono!");
return;
}
waveIn.StartRecording();
btnRecordVoice.Enabled = false;
btnSave.Enabled = true;
}
private void btnSave_Click(object sender, EventArgs e)
{
waveIn.StopRecording();
if (File.Exists("audio.raw"))
File.Delete("audio.raw");
writer = new WaveFileWriter(output, waveIn.WaveFormat);
btnRecordVoice.Enabled = false;
btnSave.Enabled = false;
byte[] buffer = new byte[bwp.BufferLength];
int offset = 0;
int count = bwp.BufferLength;
var read = bwp.Read(buffer, offset, count);
if (count > 0)
{
writer.Write(buffer, offset, read);
}
waveIn.Dispose();
waveIn = null;
writer.Close();
writer = null;
reader = new WaveFileReader("audio.raw"); // (new MemoryStream(bytes));
waveOut.Init(reader);
waveOut.PlaybackStopped += new EventHandler<StoppedEventArgs>(waveOut_PlaybackStopped);
waveOut.Play();
}
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
bwp.AddSamples(e.Buffer, 0, e.BytesRecorded);
}
private void waveOut_PlaybackStopped(object sender, StoppedEventArgs e)
{
waveOut.Stop();
reader.Close();
reader = null;
}
}
}

You get a 5-second audio clip not only because you do a one-time BufferLength read from the BufferedWaveProvider...
int count = bwp.BufferLength;
var read = bwp.Read(buffer, offset, count);
...and 5 seconds is the default value of that property, but because BufferedWaveProvider uses a circular buffer, so BufferLength is all the data it has available.
What worked for me was to skip the BufferedWaveProvider and write new data to the WaveFileWriter as soon as it becomes available...
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
writer.Write(e.Buffer, 0, e.BytesRecorded);
}
To support that change, the button event handlers get changed to the following...
private void btnRecordVoice_Click(object sender, EventArgs e)
{
if (NAudio.Wave.WaveIn.DeviceCount < 1)
{
Console.WriteLine("No se encuentra un microfono!");
return;
}
writer = new WaveFileWriter(output, waveIn.WaveFormat);
waveIn.StartRecording();
btnRecordVoice.Enabled = false;
btnSave.Enabled = true;
}
private void btnSave_Click(object sender, EventArgs e)
{
waveIn.StopRecording();
writer.Close();
writer = null;
btnRecordVoice.Enabled = false;
btnSave.Enabled = false;
reader = new WaveFileReader("audio.raw"); // (new MemoryStream(bytes));
waveOut.Init(reader);
waveOut.PlaybackStopped += new EventHandler<StoppedEventArgs>(waveOut_PlaybackStopped);
waveOut.Play();
}
This appears to be the same approach used in Recording a WAV file in a WinForms app with WaveIn.

Related

I want to record video and audio at the same time but i dont know how to?

I'm using accord.net i record audio and video separatly but I want to do both at the same time because i will read the video with sound while its recorded in another app using sockets.
I read somewhere to use videofilewriter but i dont know how to use it with audio.
i'm running the recording in background because it make the form freeze.
public Form1()
{
InitializeComponent();
// back ground running
bg = new BackgroundWorker();
bg.WorkerSupportsCancellation = true;
bg.DoWork += Run;
audiostream = new MemoryStream();
audioencoder = new WaveEncoder(audiostream);
}
private void Form1_Load(object sender, EventArgs e)
{
VideoCaptureDevices = new
FilterInfoCollection(FilterCategory.VideoInputDevice);
captureDevice = new VideoCaptureDeviceForm();
}
private void source_NewFrame(object sender, Accord.Audio.NewFrameEventArgs eventArgs)
{
audioencoder.Encode(eventArgs.Signal);
}
void FinalVideo_NewFrame(object sender, Accord.Video.NewFrameEventArgs eventArgs)
{
video = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone(); ;
}
private void record_Click(object sender, EventArgs e)
{
source = new AudioCaptureDevice()
{
// Listen on 44.1 Hz, Cam Quality 1280x720
DesiredFrameSize = 4096,
SampleRate = 44100,
};
saveFileDialog2.Filter = "Wav Files (*.wav)|*.wav";
saveFileDialog2.InitialDirectory = #"C:\Users\dell\Desktop\Camrecord";
saveFileDialog1.Filter = "Avi Files (*.avi)|*.avi";
saveFileDialog1.InitialDirectory = #"C:\Users\dell\Desktop\Camrecord";
int h = captureDevice.VideoDevice.VideoResolution.FrameSize.Height;
int w = captureDevice.VideoDevice.VideoResolution.FrameSize.Width;
audiofilestream = new FileStream(saveFileDialog2.FileName,
FileMode.Create);
FileWriter.Open(saveFileDialog1.FileName, w, h, 155, VideoCodec.MPEG4,
3200000);
source.NewFrame += source_NewFrame;
source.Start();
bg.RunWorkerAsync();
}
private void Run(object sender, DoWorkEventArgs e)
{
audioencoder = new WaveEncoder(audiofilestream);
do
{
Runexecuted = true;
FileWriter.WriteVideoFrame(video);
} while (!Stopclicked);
FinalVideo = captureDevice.VideoDevice;
FinalVideo.NewFrame += new
NewFrameEventHandler(FinalVideo_NewFrame);
source.NewFrame += source_NewFrame;
source.Start();
FinalVideo.Start();
}
if you know how to merge them i can use it, pending the solution that would suit me. thanks to all of you.

How to move a function to a separate assembly from the interface [Error]

I am currently working on a file copying facility that allows me to select a source and a destination for the folders to be copied from and to. A progress bar is displayed after the user clicks on Copy.
The only issue is that All of my functions reside in one file which is form1.cs (as follows)
namespace CopyFacility
{
public partial class Form1 : Form
{
BackgroundWorker background = new BackgroundWorker();
FolderBrowserDialog folderBrowser = new FolderBrowserDialog();
OpenFileDialog openFile = new OpenFileDialog();
public Form1()
{
InitializeComponent();
background.WorkerSupportsCancellation = true;
background.WorkerReportsProgress = true;
background.DoWork += Background_DoWork;
background.RunWorkerCompleted += Background_RunWorkerCompleted;
background.ProgressChanged += Background_ProgressChanged;
}
string inputFile = null;
string outputFile = null;
private void CopyFile(string source, string destination, DoWorkEventArgs e)
{
FileStream fsOut = new FileStream(destination, FileMode.Create);
FileStream fsIn = new FileStream(source, FileMode.Open);
byte[] buffer = new byte[1048756];
int readBytes;
while((readBytes = fsIn.Read(buffer,0,buffer.Length)) > 0)
{
if(background.CancellationPending)
{
e.Cancel = true;
background.ReportProgress(0);
fsIn.Close();
fsOut.Close();
return;
}
else
{
fsOut.Write(buffer, 0, readBytes);
background.ReportProgress((int) (fsIn.Position * 100 / fsIn.Length));
}
fsOut.Write(buffer, 0, readBytes);
background.ReportProgress((int)(fsIn.Position * 100 / fsIn.Length));
}
fsIn.Close();
fsOut.Close();
}
private void Background_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
fileProgressBar.Value = e.ProgressPercentage;
}
private void Background_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled)
{
fileProgressBar.Visible = true;
lblMessage.Visible = true;
lblMessage.Text = "The process has been cancelled";
}
else
{
fileProgressBar.Visible = true;
lblMessage.Visible = true;
lblMessage.Text = "The process has been completed";
}
}
private void Background_DoWork(object sender, DoWorkEventArgs e)
{
CopyFile(inputFile, outputFile + #"\" + Path.GetFileName(inputFile),e);
}
private void btnCancel_Click(object sender, EventArgs e)
{
background.CancelAsync();
}
private void btnCopy_Click(object sender, EventArgs e)
{
if(background.IsBusy)
{
lblProgress.Visible = true;
}
else
{
fileProgressBar.Visible = true;
background.RunWorkerAsync();
}
}
private void btnSource_Click(object sender, EventArgs e)
{
if(openFile.ShowDialog() == DialogResult.OK )
{
inputFile = openFile.FileName;
btnSource.Text = inputFile;
}
}
private void btnDestination_Click(object sender, EventArgs e)
{
if (folderBrowser.ShowDialog() == DialogResult.OK)
{
outputFile = folderBrowser.SelectedPath;
btnDestination.Text = outputFile + #"\" + Path.GetFileName(inputFile);
}
}
}
}
I was wondering how I could go about putting the function "CopyFile" into it's own class that can be called whenever the button is clicked?
When I try creating a new class method and inserting the functions related to the copying function into a new class "CopyFunction.cs" , I get a following error from the code "InitializingComponent();" as follows
public CopyPresenter(BackgroundWorker background, FolderBrowserDialog folderBrwoser, OpenFileDialog openFile)
{
InitializeComponent();
background.WorkerSupportsCancellation = true;
background.WorkerReportsProgress = true;
background.DoWork += Background_DoWork;
background.RunWorkerCompleted += Background_RunWorkerCompleted;
background.ProgressChanged += Background_ProgressChanged;
}
The error says that the "InitializeComponent" doesn't exist in the current context.

How can i extract frames from video using directshowlib-2005?

With this code i can play video files from my hard disk and show the video in pictureBox1. But i wonder how can i save all the frames of the video to images files on the hard disk ? While playing the video or without playing i need somehow to extract the frames and save them.
This is my used code so far:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
IGraphBuilder m_graphBuilder = null;
IMediaControl m_mediaCtrl = null;
IMediaEventEx m_mediaEvt = null;
IMediaPosition m_mediaPos = null;
IMediaSeeking m_mediaSeeking = null;
public Form1()
{
InitializeComponent();
}
void InitInterfaces()
{
try
{
m_graphBuilder = (IGraphBuilder)new FilterGraph();
m_mediaCtrl = (IMediaControl)m_graphBuilder;
m_mediaEvt = (IMediaEventEx)m_graphBuilder;
m_mediaPos = (IMediaPosition)m_graphBuilder;
m_mediaSeeking = (IMediaSeeking)m_graphBuilder;
}
catch (Exception)
{
MessageBox.Show("Couldn't start directshow graph");
}
}
void CloseInterfaces()
{
if (m_mediaCtrl != null)
{
m_mediaCtrl.StopWhenReady();
}
m_mediaCtrl = null;
m_mediaEvt = null;
m_mediaPos = null;
m_mediaSeeking = null;
if (m_graphBuilder != null)
Marshal.ReleaseComObject(this.m_graphBuilder);
m_graphBuilder = null;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void SetuupVideoRenderer()
{
IBaseFilter vmrFilter = null;
vmrFilter = (IBaseFilter)new VideoMixingRenderer();
m_graphBuilder.AddFilter(vmrFilter, "Video Renderer");
IVMRFilterConfig FilterConfig = (IVMRFilterConfig)vmrFilter;
FilterConfig.SetRenderingMode(VMRMode.Windowless);
IVMRWindowlessControl windowlessCtrl = (IVMRWindowlessControl)vmrFilter;
windowlessCtrl.SetVideoClippingWindow(this.pictureBox1.Handle);
windowlessCtrl.SetVideoPosition(null, DsRect.FromRectangle(pictureBox1.ClientRectangle));
windowlessCtrl.SetAspectRatioMode(VMRAspectRatioMode.LetterBox);
}
private void buttonLoad_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "All Files (*.*)|*.*|mp4 (*.mp4)|*.mp4|mov (*.mov)|*.mov||";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
CloseInterfaces();
InitInterfaces();
SetuupVideoRenderer();
m_graphBuilder.RenderFile(openFileDialog1.FileName, null);
textBoxDur.Text = ( getDuration() * 0.0000001).ToString();
m_mediaCtrl.Run();
timer1.Enabled = true;
}
}
private void GetPosition(out long CurrentPos,out long StopPos)
{
m_mediaSeeking.GetPositions(out CurrentPos, out StopPos);
}
private long getDuration()
{
long duration;
m_mediaSeeking.GetDuration(out duration);
return duration;
}
private void SetPos(double fPos)
{
DsLong startPosition = (DsLong)(10000000 * fPos);
m_mediaSeeking.SetPositions(startPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);
}
private void buttonPause_Click(object sender, EventArgs e)
{
m_mediaCtrl.Pause();
}
private void buttonPlay_Click(object sender, EventArgs e)
{
m_mediaCtrl.Run();
}
private void OnVideoCompleted()
{
MessageBox.Show("Video Playback Completed");
}
private void timer1_Tick(object sender, EventArgs e)
{
long iCurPos, iStopPos;
GetPosition(out iCurPos, out iStopPos);
if (iCurPos >= iStopPos)
{
timer1.Enabled = false;
OnVideoCompleted();
return;
}
textBoxCurPos.Text = (iCurPos * 0.0000001 ).ToString();
}
private void buttonGo_Click(object sender, EventArgs e)
{
SetPos(Convert.ToDouble(textBoxNewPos.Text));
timer1.Enabled = true;
}
}
}
I think this is excatly what you are looking for:
extract frames of a video
Have a look as well at this SO question and the links provided on this webpage.
The easiest way to do it is indeed using an FFMPEG, since its alredy includes some of the most common codecs (if you dont mind extra 30+Mb added to your app). As for wrappers, i used AForge wrapper in the past and really liked it, because of how simple it is to work with. Here is an example from its docs:
// create instance of video reader
VideoFileReader reader = new VideoFileReader();
// open video file
reader.Open( "test.avi");
// read 100 video frames out of it
for ( int i = 0; i < 100; i++)
{
Bitmap videoFrame = reader.ReadVideoFrame();
videoFrame.Save(i + ".bmp")
// dispose the frame when it is no longer required
videoFrame.Dispose( );
}
reader.Close();

automatic speech detection and recording

I am new to coding in c#. I am building an application to detect the speech and automatically record it. All the information available is based on windows speech recognition engine but my requirement is, the program should detect the speech and record it.
after recording that file is used for processing using hidden markov model(HMM).
namespace Application
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_1_Click(object sender, EventArgs e)
{
List<NAudio.Wave.WaveInCapabilities> sources = new List<NAudio.Wave.WaveInCapabilities>();
for (int i = 0; i < NAudio.Wave.WaveIn.DeviceCount; i++)
{
sources.Add(NAudio.Wave.WaveIn.GetCapabilities(i));
}
sourceList.Items.Clear();
foreach (var source in sources)
{
ListViewItem item = new ListViewItem(source.ProductName);
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, source.Channels.ToString()));
sourceList.Items.Add(item);
}
}
NAudio.Wave.WaveIn sourceStream = null;
NAudio.Wave.DirectSoundOut waveOut = null;
NAudio.Wave.WaveFileWriter waveWriter = null;
private void button_2_click(object sender, MouseEventArgs e)
{
if (sourceList.SelectedItems.Count == 0) return;
int deviceNumber = sourceList.SelectedItems[0].Index;
sourceStream = new NAudio.Wave.WaveIn();
sourceStream.DeviceNumber = deviceNumber;
sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(16000, NAudio.Wave.WaveIn.GetCapabilities(deviceNumber).Channels);
sourceStream.DataAvailable += new EventHandler<NAudio.Wave.WaveInEventArgs>(sourceStream_DataAvailable);
waveWriter = new NAudio.Wave.WaveFileWriter("test.wav", sourceStream.WaveFormat);
sourceStream.StartRecording();
}
private void sourceStream_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
{
if (waveWriter == null) return;
waveWriter.WriteData(e.Buffer, 0, e.BytesRecorded);
waveWriter.Flush();
}
private void button_3_click(object sender, EventArgs e)
{
if (waveOut != null)
{
waveOut.Stop();
waveOut.Dispose();
waveOut = null;
}
if (sourceStream != null)
{
sourceStream.StopRecording();
sourceStream.Dispose();
sourceStream = null;
}
if (waveWriter != null)
{
waveWriter.Dispose();
waveWriter = null;
}
speechprocessing.Model_test.speech();
}
private void button4_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
this suits my requirement but it has two button to initiate and terminate the recording process which is not under my requirement..
the program should be running and when the speech is detected it must be recorded and further processed. the words which it should detect is also not too much only a few set of words for which we have made the models using hidden markov model..
so please help me out from this problem.

Record live audio from mic input and save simultanously

I was trying to develop a Voice recorder in C#. I have tried many ways, like NAudio, DirectX, Microsoft.Xna.Framework.Audio, etc.
Everything gives the same result. After we stop the recording, the output file mp3/wav get saved.
The mp3/wav file get created at the beginning itself (without and content - 0 bytes)
I am trying to create an application which can save audio live/simultaneously.
private void StartRecording() {
this.WaveSource = new WaveInEvent { WaveFormat = new WaveFormat(44100, 1) };
this.WaveSource.DataAvailable += this.WaveSourceDataAvailable;
this.WaveSource.RecordingStopped += this.WaveSourceRecordingStopped;
this.WaveFile = new WaveFileWriter(#"C:\Sample.wav", this.WaveSource.WaveFormat);
this.WaveSource.StartRecording();
}
private void StopRecording() {
this.WaveSource.StopRecording();
}
void WaveSourceDataAvailable(object sender, WaveInEventArgs e) {
if (this.WaveFile != null) {
this.WaveFile.Write(e.Buffer, 0, e.BytesRecorded);
this.WaveFile.Flush();
}
}
void WaveSourceRecordingStopped(object sender, StoppedEventArgs e) {
if (this.WaveSource != null) {
this.WaveSource.Dispose();
this.WaveSource = null;
}
if (this.WaveFile != null) {
this.WaveFile.Dispose();
this.WaveFile = null;
}
}
I have solved the problem with NAudio library itself.
Few modification to the existing code.
public class Recorder {
WaveIn sourceStream;
WaveFileWriter waveWriter;
readonly String FilePath;
readonly String FileName;
readonly int InputDeviceIndex;
public Recorder(int inputDeviceIndex, String filePath, String fileName) {
InitializeComponent();
this.InputDeviceIndex = inputDeviceIndex;
this.FileName = fileName;
this.FilePath = filePath;
}
public void StartRecording(object sender, EventArgs e) {
sourceStream = new WaveIn {
DeviceNumber = this.InputDeviceIndex,
WaveFormat =
new WaveFormat(44100, WaveIn.GetCapabilities(this.InputDeviceIndex).Channels)
};
sourceStream.DataAvailable += this.SourceStreamDataAvailable;
if (!Directory.Exists(FilePath)) {
Directory.CreateDirectory(FilePath);
}
waveWriter = new WaveFileWriter(FilePath + FileName, sourceStream.WaveFormat);
sourceStream.StartRecording();
}
public void SourceStreamDataAvailable(object sender, WaveInEventArgs e) {
if (waveWriter == null) return;
waveWriter.Write(e.Buffer, 0, e.BytesRecorded);
waveWriter.Flush();
}
private void RecordEnd(object sender, EventArgs e) {
if (sourceStream != null) {
sourceStream.StopRecording();
sourceStream.Dispose();
sourceStream = null;
}
if (this.waveWriter == null) {
return;
}
this.waveWriter.Dispose();
this.waveWriter = null;
recordEndButton.Enabled = false;
Application.Exit();
Environment.Exit(0);
}
}
You can do this with DirectShow.
Take a look at Microsoft's documentation and the project's code samples to learn the best way to configure it according to your needs.
Wanna try to BASS NET?
There is a complete code for you task How to record sound and encode it to mp3? (C#!)

Categories