Currently I can record the microphone input using the Naudio .dll with this:
public void recordInput()
{
Console.WriteLine("Now recording...");
waveSource = new WaveIn();
waveSource.WaveFormat = new WaveFormat(16000, 1);
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
//string tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".wav");
string tempFile = Path.Combine(#"C:\Users\Nick\Desktop", "test.wav");
waveFile = new WaveFileWriter(tempFile, waveSource.WaveFormat);
waveSource.StartRecording();
myTimer.Interval = 5000;
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
}
Currently I used an eventhandler to wait for 5 seconds and then onTick I stop recording. However this is causing problems because I am having trouble waiting for the recording task to finish in the main part of the code where I call:
public string voiceToText()
{
recordInput();
//Somehow wait here until record is done then proceed.
convertToFlac();
return "done";
}
I've tried putting the Naudio in a thread and using a waitOne(); but waveSource.StartRecording(); is put in an eventhandler and thread an expection. I've also tried using a Thread.Sleep(5000) and stop recording after that thread finishes but the audio only records the first 500mS of audio for some reason.
I'm pretty new to c# and don't fully understand threading so any help or seperate approach is welcome.
I know this is an old topic, but here is some code that I made for one of my projects and that records audio for x seconds (it uses NAudio.Lame to convert the wave file to mp3):
public class Recorder
{
/// <summary>
/// Timer used to start/stop recording
/// </summary>
private Timer _timer;
private WaveInEvent _waveSource;
private WaveFileWriter _waveWriter;
private string _filename;
private string _tempFilename;
public event EventHandler RecordingFinished;
/// <summary>
/// Record from the mic
/// </summary>
/// <param name="seconds">Duration in seconds</param>
/// <param name="filename">Output file name</param>
public void RecordAudio(int seconds, string filename)
{
/*if the filename is empty, throw an exception*/
if (string.IsNullOrEmpty(filename))
throw new ArgumentNullException("The file name cannot be empty.");
/*if the recording duration is not > 0, throw an exception*/
if (seconds <= 0)
throw new ArgumentNullException("The recording duration must be a positive integer.");
_filename = filename;
_tempFilename = $"{Path.GetFileNameWithoutExtension(filename)}.wav";
_waveSource = new WaveInEvent
{
WaveFormat = new WaveFormat(44100, 1)
};
_waveSource.DataAvailable += DataAvailable;
_waveSource.RecordingStopped += RecordingStopped;
_waveWriter = new WaveFileWriter(_tempFilename, _waveSource.WaveFormat);
/*Start the timer that will mark the recording end*/
/*We multiply by 1000 because the Timer object works with milliseconds*/
_timer = new Timer(seconds * 1000);
/*if the timer elapses don't reset it, stop it instead*/
_timer.AutoReset = false;
/*Callback that will be executed once the recording duration has elapsed*/
_timer.Elapsed += StopRecording;
/*Start recording the audio*/
_waveSource.StartRecording();
/*Start the timer*/
_timer.Start();
}
/// <summary>
/// Callback that will be executed once the recording duration has elapsed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StopRecording(object sender, ElapsedEventArgs e)
{
/*Stop the timer*/
_timer?.Stop();
/*Destroy/Dispose of the timer to free memory*/
_timer?.Dispose();
/*Stop the audio recording*/
_waveSource.StopRecording();
}
/// <summary>
/// Callback executed when the recording is stopped
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RecordingStopped(object sender, StoppedEventArgs e)
{
_waveSource.DataAvailable -= DataAvailable;
_waveSource.RecordingStopped -= RecordingStopped;
_waveSource?.Dispose();
_waveWriter?.Dispose();
/*Convert the recorded file to MP3*/
ConvertWaveToMp3(_tempFilename, _filename);
/*Send notification that the recording is complete*/
RecordingFinished?.Invoke(this, null);
}
/// <summary>
/// Callback executed when new data is available
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataAvailable(object sender, WaveInEventArgs e)
{
if (_waveWriter != null)
{
_waveWriter.Write(e.Buffer, 0, e.BytesRecorded);
_waveWriter.Flush();
}
}
/// <summary>
/// Converts the recorded WAV file to MP3
/// </summary>
private void ConvertWaveToMp3(string source, string destination)
{
using (var waveStream = new WaveFileReader(source))
using(var fileWriter = new LameMP3FileWriter(destination, waveStream.WaveFormat, 128))
{
waveStream.CopyTo(fileWriter);
waveStream.Flush();
}
/*Delete the temporary WAV file*/
File.Delete(source);
}
}
And here is how to use it in your code:
var rec = new Recorder();
/*This line allows us to be notified when the recording is complete and the callback 'OnRecordingFinished' will be executed*/
rec.RecordingFinished += OnRecordingFinished;
rec.RecordAudio(seconds, recPath);
private void OnRecordingFinished(object sender, RecordingContentArgs e)
{
//Put your code here to process the audio file
}
If you aren't running in a Windows Forms or WPF application, then you should use WaveInEvent instead, so that a background thread is set up to handle the callbacks. The default constructor for WaveIn uses Windows messages.
Related
I am trying to write an application that saves depth and color streams of Kinect for Windows v2 as image files (like png or jpg). So, I used Kinect SDK v2 examples(since I have no prior experience with C# or Kinect API). I modified the ColorBasics-WPF sample code to achieve my goal. Here is the code that only convert color stream to png files(the only part I modified is Reader_ColorFrameArrived function):
//------------------------------------------------------------------------------
// <copyright file="MainWindow.xaml.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace Microsoft.Samples.Kinect.ColorBasics
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Kinect;
using System.Collections.Generic;
/// <summary>
/// Interaction logic for MainWindow
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
static int count = 0;
/// <summary>
/// Active Kinect sensor
/// </summary>
private KinectSensor kinectSensor = null;
/// <summary>
/// Reader for color frames
/// </summary>
private ColorFrameReader colorFrameReader = null;
/// <summary>
/// Bitmap to display
/// </summary>
private WriteableBitmap colorBitmap = null;
/// <summary>
/// Current status text to display
/// </summary>
private string statusText = null;
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// </summary>
public MainWindow()
{
// get the kinectSensor object
this.kinectSensor = KinectSensor.GetDefault();
// open the reader for the color frames
this.colorFrameReader = this.kinectSensor.ColorFrameSource.OpenReader();
// wire handler for frame arrival
this.colorFrameReader.FrameArrived += this.Reader_ColorFrameArrived;
// create the colorFrameDescription from the ColorFrameSource using Bgra format
FrameDescription colorFrameDescription = this.kinectSensor.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
// create the bitmap to display
this.colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
// set IsAvailableChanged event notifier
this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged;
// open the sensor
this.kinectSensor.Open();
// set the status text
this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText
: Properties.Resources.NoSensorStatusText;
// use the window object as the view model in this simple example
this.DataContext = this;
// initialize the components (controls) of the window
this.InitializeComponent();
}
/// <summary>
/// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets the bitmap to display
/// </summary>
public ImageSource ImageSource
{
get
{
return this.colorBitmap;
}
}
/// <summary>
/// Gets or sets the current status text to display
/// </summary>
public string StatusText
{
get
{
return this.statusText;
}
set
{
if (this.statusText != value)
{
this.statusText = value;
// notify any bound elements that the text has changed
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText"));
}
}
}
}
/// <summary>
/// Execute shutdown tasks
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
if (this.colorFrameReader != null)
{
// ColorFrameReder is IDisposable
this.colorFrameReader.Dispose();
this.colorFrameReader = null;
}
if (this.kinectSensor != null)
{
this.kinectSensor.Close();
this.kinectSensor = null;
}
}
/// <summary>
/// Handles the user clicking on the screenshot button
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void ScreenshotButton_Click(object sender, RoutedEventArgs e)
{
if (this.colorBitmap != null)
{
// create a png bitmap encoder which knows how to save a .png file
BitmapEncoder encoder = new PngBitmapEncoder();
// create frame from the writable bitmap and add to encoder
encoder.Frames.Add(BitmapFrame.Create(this.colorBitmap));
//bitmaps.Add(BitmapFrame.Create(this.colorBitmap.Clone()));
string time = count.ToString();
//string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string path = Path.Combine(myPhotos, "KinectScreenshot-Color-" + time + ".png");
count++;
// write the new file to disk
try
{
// FileStream is IDisposable
using (FileStream fs = new FileStream(path, FileMode.Create))
{
encoder.Save(fs);
}
this.StatusText = string.Format(Properties.Resources.SavedScreenshotStatusTextFormat, path);
}
catch (IOException)
{
this.StatusText = string.Format(Properties.Resources.FailedScreenshotStatusTextFormat, path);
}
}
}
/// <summary>
/// Handles the color frame data arriving from the sensor
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
// ColorFrame is IDisposable
using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
{
if (colorFrame != null)
{
FrameDescription colorFrameDescription = colorFrame.FrameDescription;
using (KinectBuffer colorBuffer = colorFrame.LockRawImageBuffer())
{
this.colorBitmap.Lock();
// verify data and write the new color frame data to the display bitmap
if ((colorFrameDescription.Width == this.colorBitmap.PixelWidth) && (colorFrameDescription.Height == this.colorBitmap.PixelHeight))
{
colorFrame.CopyConvertedFrameDataToIntPtr(
this.colorBitmap.BackBuffer,
(uint)(colorFrameDescription.Width * colorFrameDescription.Height * 4),
ColorImageFormat.Bgra);
this.colorBitmap.AddDirtyRect(new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight));
}
this.colorBitmap.Unlock();
}
}
// my modification : save current frame as png file.
if (this.colorBitmap != null)
{
// create a png bitmap encoder which knows how to save a .png file
BitmapEncoder encoder = new PngBitmapEncoder();
// create frame from the writable bitmap and add to encoder
encoder.Frames.Add(BitmapFrame.Create(this.colorBitmap));
string time = count.ToString();
//string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string path = Path.Combine(myPhotos, "KinectScreenshot-Color-" + time + ".png");
count++;
// write the new file to disk
try
{
// FileStream is IDisposable
using (FileStream fs = new FileStream(path, FileMode.Create))
{
encoder.Save(fs);
}
this.StatusText = string.Format(Properties.Resources.SavedScreenshotStatusTextFormat, path);
}
catch (IOException)
{
this.StatusText = string.Format(Properties.Resources.FailedScreenshotStatusTextFormat, path);
}
}
}
}
/// <summary>
/// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged).
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
{
// on failure, set the status text
this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText
: Properties.Resources.SensorNotAvailableStatusText;
}
}
}
The problem with this code is that it generates say 200 png files during the recording time but starting from say frame 90 to the end, all the frames are identical to each other(It starts recording as soon as I run it and it stops whenever I close it).
1) Would you help me understand why this happens? Why it doesn't record the rest of the frames and repeats a frame again and again?
2) Do you have any advice or pointer about how I can record depth and color streams as image files simultaneously in an efficient way and with a good frame rate(say 20-30 fps) using Kinect for Windows v2?
Writing simultaneously color and depth streams with the same fps without loosing frames is a little tricky. In order to check your problem with the identical frames I suggest you try to write color and depth images to separate buffers (you can keep its frame timestamp in a buffer too) and write them to the disk after the recording is over. I'll give you an example and you can ajust it to your problem.
Saving color frames to a buffer:
private void myKinectSensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame color = e.OpenColorImageFrame())
{
if (color != null)
{
colorbits = new byte[color.PixelDataLength];
color.CopyPixelDataTo(colorbits);
image1.Source = BitmapSource.Create(color.Width, color.Height, 96, 96, PixelFormats.Bgr32, null, colorbits, color.Width * color.BytesPerPixel);
if (StartSavingFrames)
{
SaveColorTimestamps.AddLast(DateTime.Now.ToString("hhmmssfff"));
SaveColorFrames.AddLast(colorbits);
}
}
}
}
Saving depth frames to another buffer:
private void myKinectSensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
using (DepthImageFrame depth = e.OpenDepthImageFrame())
{
depthPixels = new DepthImagePixel[myKinectSensor.DepthStream.FramePixelDataLength];
if (depth != null)
{
frame = new short[depth.PixelDataLength];
depth.CopyPixelDataTo(frame);
for (int i = 0; i < frame.Length; i++)
{
frame[i] = (short)(((ushort)frame[i]) >> 3);
}
image3.Source = BitmapSource.Create(depth.Width, depth.Height, 96, 96, PixelFormats.Gray16, null, frame, depth.Width * depth.BytesPerPixel);
if (StartSavingFrames)
{
SaveDepthTimestamps.AddLast(DateTime.Now.ToString("hhmmssfff"));
SaveDepthFrames.AddLast(frame);
}
}
}
}
Finally, loop in each buffer and write frames to disk:
e = SaveColorTimestamps.GetEnumerator();
foreach (byte[] node in SaveColorFrames)
{
e.MoveNext();
PngBitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(BitmapSource.Create(640, 480, 96, 96, PixelFormats.Bgr32, null, node, 640*4)));
string temppath = System.IO.Path.Combine(#"../output/kinect1/color/", e.Current + ".png");
using (FileStream fs = new FileStream(temppath, FileMode.Create))
{
enc.Save(fs);
fs.Close();
}
}
SaveColorTimestamps.Clear();
SaveColorFrames.Clear();
e.Dispose();
e = SaveDepthTimestamps.GetEnumerator();
foreach (short[] node in SaveDepthFrames)
{
e.MoveNext();
PngBitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(BitmapSource.Create(640, 480, 96, 96, PixelFormats.Gray16, null, node, 640 * 2)));
string temppath = System.IO.Path.Combine(#"../output/kinect1/depth/", e.Current + ".png");
using (FileStream fs = new FileStream(temppath, FileMode.Create))
{
enc.Save(fs);
fs.Close();
}
}
It is not the optimal way to do it, but it will help you understand how the frame-writing works and you will not have any drop-frames.
So i have been trying over and over with lots of trial and error and i cannot seem to get this to work, basically i want to unzip a zip file using the Ionic.DLL from http://dotnetzip.codeplex.com as you can see i have also made a thread about it here: Extract ZipFile Using C# With Progress Report so to basically sum up what i am after.
I have a form with:
3xbuttons: btnCancel, btnBrowse and btnStart,
1xbackground worker: backgroundworker1
1xlabel: label1
1xtextbox: textBox1
1xprogressbar
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Ionic.Zip;
namespace BackgroundWorkerSample
{
public partial class Form1 : Form
{
/// <summary>
/// The backgroundworker object on which the time consuming operation shall be executed
/// </summary>
BackgroundWorker m_oWorker;
public Form1()
{
InitializeComponent();
m_oWorker = new BackgroundWorker();
m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
}
/// <summary>
/// On completed do the appropriate task
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void m_oWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//If it was cancelled midway
if (e.Cancelled)
{
lblStatus.Text = "Task Cancelled.";
}
else if (e.Error != null)
{
lblStatus.Text = "Error while performing background operation.";
}
else
{
lblStatus.Text = "Task Completed...";
}
btnStartAsyncOperation.Enabled = true;
btnCancel.Enabled = false;
}
/// <summary>
/// Notification is performed here to the progress bar
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void m_oWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Here you play with the main UI thread
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";
}
/// <summary>
/// Time consuming operations go here </br>
/// i.e. Database operations,Reporting
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
//NOTE : Never play with the UI thread here...
//time consuming operation
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
m_oWorker.ReportProgress(i);
/////////////////////MINEEEEEEEEEEEEEEEEEEEEEEEEE
string INSTALL_LOCATION = "C:" + #"\" + "Program Files (x86)" + #"\" + "TEST_FOLDER" + #"\" + #"\" + "Burgos_Folder";
string DEFAULT_LOCATION = "C:" + #"\" + "Program Files (x86)" + #"\" + "TEST_FOLDER" + #"\" + "test.rar";
if (!Directory.Exists(INSTALL_LOCATION))
{
Directory.CreateDirectory(INSTALL_LOCATION);
}
//if the textbox directory exists
if (Directory.Exists(INSTALL_LOCATION))
{
using (ZipFile zip = ZipFile.Read(DEFAULT_LOCATION))
{
zip.ExtractAll(INSTALL_LOCATION, ExtractExistingFileAction.OverwriteSilently);
}
}
//If cancel button was pressed while the execution is in progress
//Change the state from cancellation ---> cancel'ed
if (m_oWorker.CancellationPending)
{
e.Cancel = true;
m_oWorker.ReportProgress(0);
return;
}
}
//Report 100% completion on operation completed
m_oWorker.ReportProgress(100);
}
private void btnStartAsyncOperation_Click(object sender, EventArgs e)
{
btnStartAsyncOperation.Enabled = false;
btnCancel.Enabled = true;
//Start the async operation here
m_oWorker.RunWorkerAsync();
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (m_oWorker.IsBusy)
{
//Stop/Cancel the async operation here
m_oWorker.CancelAsync();
}
}
}
}
What i would like my winforms to have is simply: browse for a folder, then click Start(btnStart) which starts the zip extraction process which is also shown on the ProgressBar(timewise), and the cancel(btnCancel) button cancels the unzipping processs, i have successfully done everything but i cannot work out how to cancel the unzipping process, it never seems to stop unless i actually close the .exe down. I decided to make a simpler example without the textbox and browse button, and that example is in my previous Asked Question(link above), but i don't see how to implement a way to cancel the unzipping process with the background worker, and i definantly need to use background worker so i can have a progress report on the current situation etc. Can anyone please adapt my examples or provide a example that does this?
I have found a solution, i have moved away from Ionic and added the existing references: System.IO.Compression and System.IO.Compression.FileSystem.
I am able to capture system audio which is generated by speaker with the help of WasapiLoopbackCapture (naudio). but the problem is it capture wav file and size of wav file very large (almost 10 to 15 MB/Min). I have to capture 2-3 hour audio and this will be too high.
I m looking for a solution that will convert wav stream which is capture by WasapiLoopbackCapture convert to MP3 and then save this to disk. I try a loat with LAME.exe or other solution but not get success. Any working code.
Here is My Code:
private void button1_Click(object sender, EventArgs e){
LoopbackRecorder obj = new LoopbackRecorder();
string a = textBox1.Text;
obj.StartRecording(#"e:\aman.mp3");
}
public class LoopbackRecorder
{
private IWaveIn _waveIn;
private Mp3WaveFormat _mp3format;
private WaveFormat _wavFormat;
private WaveFileWriter _writer;
private bool _isRecording = false;
/// <summary>
/// Constructor
/// </summary>
public LoopbackRecorder()
{
}
/// <summary>
/// Starts the recording.
/// </summary>
/// <param name="fileName"></param>
public void StartRecording(string fileName)
{
// If we are currently record then go ahead and exit out.
if (_isRecording == true)
{
return;
}
_fileName = fileName;
_waveIn = new WasapiLoopbackCapture();
// _waveIn.WaveFormat = new WaveFormat(16000, 16 , 2);
_writer = new WaveFileWriter(fileName, _waveIn.WaveFormat);
_waveIn.DataAvailable += OnDataAvailable;
// _waveIn.RecordingStopped += OnRecordingStopped;
_waveIn.StartRecording();
_isRecording = true;
}
private void OnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
if (_writer == null)
{
_writer = new WaveFileWriter(#"e:\aman.mp3", _waveIn.WaveFormat);
}
_writer.Write(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
byte[] by= Float32toInt16(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
private string _fileName = "";
/// <summary>
/// The name of the file that was set when StartRecording was called. E.g. the current file being written to.
/// </summary>
public string FileName
{
get
{
return _fileName;
}
}
}
Here's an example of using NAudio.Lame (in a console application) to capture data from sound card loopback and write direct to an MP3 file:
using System;
using NAudio.Lame;
using NAudio.Wave;
namespace MP3Rec
{
class Program
{
static LameMP3FileWriter wri;
static bool stopped = false;
static void Main(string[] args)
{
// Start recording from loopback
IWaveIn waveIn = new WasapiLoopbackCapture();
waveIn.DataAvailable += waveIn_DataAvailable;
waveIn.RecordingStopped += waveIn_RecordingStopped;
// Setup MP3 writer to output at 32kbit/sec (~2 minutes per MB)
wri = new LameMP3FileWriter( #"C:\temp\test_output.mp3", waveIn.WaveFormat, 32 );
waveIn.StartRecording();
stopped = false;
// Keep recording until Escape key pressed
while (!stopped)
{
if (Console.KeyAvailable)
{
var key = Console.ReadKey(true);
if (key != null && key.Key == ConsoleKey.Escape)
waveIn.StopRecording();
}
else
System.Threading.Thread.Sleep(50);
}
// flush output to finish MP3 file correctly
wri.Flush();
// Dispose of objects
waveIn.Dispose();
wri.Dispose();
}
static void waveIn_RecordingStopped(object sender, StoppedEventArgs e)
{
// signal that recording has finished
stopped = true;
}
static void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
// write recorded data to MP3 writer
if (wri != null)
wri.Write(e.Buffer, 0, e.BytesRecorded);
}
}
}
At the moment the NAudio.Lame package on NuGet is compiled for x86 only, so make sure your application is set to target that platform.
To convert the audio to MP3 on the fly, one of the easiest ways is to use the command line options that let you pass audio into LAME.exe via stdin. I describe how to do that in this article.
You may also be interested that Corey Murtagh has created a LAME package for NAudio. I haven't tried it myself, but it looks like it should also do the job. Documentation is here.
I am basically trying to take input as RGB Stream from Kinect for Windows using the same code as given in the SDK (ColorBasics Example).
The code of the Example in SDK is as follow
public partial class MainWindow : Window
{
/// <summary>
/// Active Kinect sensor
/// </summary>
private KinectSensor sensor;
/// <summary>
/// Bitmap that will hold color information
/// </summary>
private WriteableBitmap colorBitmap;
/// <summary>
/// Intermediate storage for the color data received from the camera
/// </summary>
private byte[] colorPixels;
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// </summary>
public MainWindow()
{
//InitializeComponent();
}
/// <summary>
/// Execute startup tasks
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// Look through all sensors and start the first connected one.
// This requires that a Kinect is connected at the time of app startup.
// To make your app robust against plug/unplug,
// it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit
foreach (var potentialSensor in KinectSensor.KinectSensors)
{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}
if (null != this.sensor)
{
// Turn on the color stream to receive color frames
this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
// Allocate space to put the pixels we'll receive
this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
// This is the bitmap we'll display on-screen
this.colorBitmap = new WriteableBitmap(this.sensor.ColorStream.FrameWidth, this.sensor.ColorStream.FrameHeight, 96.0, 96.0, PixelFormats.Bgr32, null);
// Set the image we display to point to the bitmap where we'll put the image data
this.Image.Source = this.colorBitmap;
// Add an event handler to be called whenever there is new color frame data
this.sensor.ColorFrameReady += this.SensorColorFrameReady;
// Start the sensor!
try
{
this.sensor.Start();
}
catch (IOException)
{
this.sensor = null;
}
}
if (null == this.sensor)
{
this.statusBarText.Text = Properties.Resources.NoKinectReady;
}
}
/// <summary>
/// Execute shutdown tasks
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (null != this.sensor)
{
this.sensor.Stop();
}
}
/// <summary>
/// Event handler for Kinect sensor's ColorFrameReady event
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame != null)
{
// Copy the pixel data from the image to a temporary array
colorFrame.CopyPixelDataTo(this.colorPixels);
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int),
0);
}
}
}
/// <summary>
/// Handles the user clicking on the screenshot button
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void ButtonScreenshotClick(object sender, RoutedEventArgs e)
{
if (null == this.sensor)
{
this.statusBarText.Text = Properties.Resources.ConnectDeviceFirst;
return;
}
// create a png bitmap encoder which knows how to save a .png file
BitmapEncoder encoder = new PngBitmapEncoder();
// create frame from the writable bitmap and add to encoder
encoder.Frames.Add(BitmapFrame.Create(this.colorBitmap));
string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string path = Path.Combine(myPhotos, "KinectSnapshot-" + time + ".png");
// write the new file to disk
try
{
using (FileStream fs = new FileStream(path, FileMode.Create))
{
encoder.Save(fs);
}
this.statusBarText.Text = string.Format("{0} {1}", Properties.Resources.ScreenshotWriteSuccess, path);
}
catch (IOException)
{
this.statusBarText.Text = string.Format("{0} {1}", Properties.Resources.ScreenshotWriteFailed, path);
}
}
}
}
And the code in my application is as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
namespace VideoKinect
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private KinectSensor sensor;
private WriteableBitmap colorBitmap;
private byte[] colorPixels;
public MainWindow()
{
//InitializeComponent();
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
foreach (var potentialSensor in KinectSensor.KinectSensors)
{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}
if (null != this.sensor)
{
// Turn on the color stream to receive color frames
this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
// Allocate space to put the pixels we'll receive
this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
// This is the bitmap we'll display on-screen
this.colorBitmap = new WriteableBitmap(this.sensor.ColorStream.FrameWidth, this.sensor.ColorStream.FrameHeight, 96.0, 96.0, PixelFormats.Bgr32, null);
// Set the image we display to point to the bitmap where we'll put the image data
this.ColorImage.Source = this.colorBitmap;
// Add an event handler to be called whenever there is new color frame data
this.sensor.ColorFrameReady += this.SensorColorFrameReady;
// Start the sensor!
//try
//{
this.sensor.Start();
// }
// catch (IOException)
//{
this.sensor = null;
// }
}
if (null == this.sensor)
{
MessageBox.Show("No Kinect Available");
}
}
private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame != null)
{
// Copy the pixel data from the image to a temporary array
colorFrame.CopyPixelDataTo(this.colorPixels);
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int),
0);
}
}
}
}
}
But I am getting the Error at "IOException" in my code and the Image "ColorImage" is not being detected even though I named the image in my xaml file as the same.
I was able to compile and execute your code above with the expected behaviour - the only change was uncommenting the InitializeComponent(); and adding <Image x:Name="ColorImage"/> to the MainWindow.xaml.
What exactly does the IOException say? Can you double check that you Kinect sensor is connected properly via at least a USB 2.0 bus - 1.1 has insufficient bandwidth? Are you also sure that the sensor has sufficient power as you will need the kinect power supply cable. You could always check to see if the SDK is installed properly, have a look at this post.
With regards to it not finding your ColorImage rebuilding the solution should resolve the issue, assuming there is not a spelling mistake on the x:Name of the Image in XAML.
You messed up when you commented out the try ... catch statement, you left sensor = null; in there, after you started it, meaning you had no sensor. You should have commented that out.
// What it should be:
// try
// {
this.sensor.Start();
// }
// catch (IOException)
// {
// this.sensor = null; <- What it should be
// }
// What it is:
// try
// {
this.sensor.Start();
// }
// catch (IOException)
// {
this.sensor = null; //turns sensor null, then SensorColorFrame
// never gets called, etc.
// }
That line will ultimately destroy any Kinect program you ever write. Hope this helps!
you left out a reference. you need to include:
using System.IO;
at the very top. Hope This helps!
I have a windows service which has a timer reading interval from configuration.
DipRedipServiceTimer_Elapsed event is called after 1000 miliseconds on first run of service. Code written in this method must be executed before running next cycle of this timer. however, i have seen DipRedipServiceTimer_Elapsed event firing even when the first cycle has not yet completed. this results is two threads working on same piece of code and some very horrible issues. How can i prevent this from happening ? Please suggest.
partial class DIPREDIPServiceHost : ServiceBase
{
#region Private Fields
/// <summary>
/// Timer for polling job pool on timely basis
/// </summary>
private Timer DipRedipServiceTimer;
#endregion
public DIPREDIPServiceHost()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
DipRedipServiceTimer = new Timer();
DipRedipServiceTimer.Enabled = true;
DipRedipServiceTimer.Interval = 1000;
DipRedipServiceTimer.AutoReset = false;
DipRedipServiceTimer.Elapsed += new ElapsedEventHandler(DipRedipServiceTimer_Elapsed);
}
protected override void OnStop()
{
if (DipRedipServiceTimer != null)
{
DipRedipServiceTimer.Enabled = false;
DipRedipServiceTimer.Stop();
DipRedipServiceTimer = null;
}
}
#region "Timer Elapsed Event"
/// <summary>
/// Handles the Elapsed event of the timer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Timers.ElapsedEventArgs"/> instance containing the event data.</param>
void DipRedipServiceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//disable timers as at a given time only one thread should process dip/redip.
DipRedipServiceTimer.Stop();
DipRedipServiceTimer.AutoReset = false;
DipRedipServiceTimer.Enabled = false;
try
{
IDipRedipController controller = new DipRedipController();
try
{
DipRedipConfiguration config = controller.GetDipRedipConfiguration();
// In case configuration has been retrieved, set timer defined.
if (config != null)
{
//set timer interval after reading from config file.
DipRedipServiceTimer.Interval = config.FileGenerationInterval * 60000;
controller.dipRedipConfiguration = config;
LoggingHelper.LogMessage(String.Format("Dip Service timer initialized at {0}", DateTime.UtcNow), Source.EDiscDIPREDIPService, LogCategory.Exception);
//Process Dip
bool dipSuccess = controller.ProcessDIP();
//Process Re-Dip
bool redipSuccess = controller.ProcessREDIP();
//Enable timers for next cycle
LoggingHelper.LogMessage(String.Format("Dip Service timer completed at {0}", DateTime.UtcNow), Source.EDiscDIPREDIPService, LogCategory.Exception);
}
// In case configuration is null, get the default timer defined in App.Config file.
else
{
int interval = 0;
int.TryParse(ConfigurationManager.AppSettings.Get("DefaultTimerValue"), out interval);
DipRedipServiceTimer.Interval = interval * 60000;
LoggingHelper.LogWarning("Configuration for Dip/Redip could not be fetched from database.", Source.FileImportService, LogCategory.Exception);
}
DipRedipServiceTimer.Enabled = true;
DipRedipServiceTimer.Start();
}
catch (FaultException ex)
{
LoggingHelper.LogException("Exception Occured in DipRedipServiceTimer_Elapsed method of Dip/Redip Window Service", ex, Source.EDiscDIPREDIPService);
}
}
catch (Exception ex)
{
LoggingHelper.LogException("Exception Occured in the DipRedip Service Host Window Service", ex, Source.EDiscDIPREDIPService);
}
}
#endregion
}
Following link
http://msdn.microsoft.com/en-us/library/system.timers.timer.interval.aspx
describes behaviour of setting the interval again. I was setting interval from config before doing any processing thereby causing timer to reset and fir elaspsed event as per the documentation.
Fix :- I am setting interval after processing is done. This resets the timer and elapsed event will fire after configured interval. Also following lines of code are no more needed
DipRedipServiceTimer.Stop();
DipRedipServiceTimer.AutoReset = false;
DipRedipServiceTimer.Enabled = false;
because autoreset is set to false while initializing the timer.
#region "Timer Elapsed Event"
/// <summary>
/// Handles the Elapsed event of the timer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Timers.ElapsedEventArgs"/> instance containing the event data.</param>
void DipRedipServiceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
IDipRedipController controller = new DipRedipController();
try
{
DipRedipConfiguration config = controller.GetDipRedipConfiguration();
if (config != null)
{
//set timer interval after reading from config file.
controller.dipRedipConfiguration = config;
LoggingHelper.LogMessage(String.Format("Dip Service timer initialized at {0}", DateTime.UtcNow), Source.EDiscDIPREDIPService, LogCategory.Exception);
//Process Dip
bool dipSuccess = controller.ProcessDIP();
//Process Re-Dip
bool redipSuccess = controller.ProcessREDIP();
// In case configuration has been retrieved, set timer defined.
DipRedipServiceTimer.Interval = config.FileGenerationInterval * 60000;
//Enable timers for next cycle
LoggingHelper.LogMessage(String.Format("Dip Service timer completed at {0}", DateTime.UtcNow), Source.EDiscDIPREDIPService, LogCategory.Exception);
}
// In case configuration is null, get the default timer defined in App.Config file.
else
{
int interval = 0;
int.TryParse(ConfigurationManager.AppSettings.Get("DefaultTimerValue"), out interval);
DipRedipServiceTimer.Interval = interval * 60000;
LoggingHelper.LogWarning("Configuration for Dip/Redip could not be fetched from database.", Source.EDiscDIPREDIPService, LogCategory.Exception);
}
DipRedipServiceTimer.Start();
}
catch (Exception ex)
{
LoggingHelper.LogException("Exception Occured in DipRedipServiceTimer_Elapsed method of Dip/Redip Window Service", ex, Source.EDiscDIPREDIPService);
}
}
catch (Exception ex)
{
LoggingHelper.LogException("Exception Occured in the DipRedip Service Host Window Service", ex, Source.EDiscDIPREDIPService);
}
}
#endregion