I am trying to record audio in C# using NAudio. After looking at the NAudio Chat Demo, I used some code from there to record.
Here is the code:
using System;
using NAudio.Wave;
public class FOO
{
static WaveIn s_WaveIn;
static void Main(string[] args)
{
init();
while (true) /* Yeah, this is bad, but just for testing.... */
System.Threading.Thread.Sleep(3000);
}
public static void init()
{
s_WaveIn = new WaveIn();
s_WaveIn.WaveFormat = new WaveFormat(44100, 2);
s_WaveIn.BufferMilliseconds = 1000;
s_WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(SendCaptureSamples);
s_WaveIn.StartRecording();
}
static void SendCaptureSamples(object sender, WaveInEventArgs e)
{
Console.WriteLine("Bytes recorded: {0}", e.BytesRecorded);
}
}
However, the eventHandler is not being called. I am using .NET version 'v2.0.50727' and compiling it as:
csc file_name.cs /reference:Naudio.dll /platform:x86
If this is your whole code, then you are missing a message loop. All the eventHandler specific events requires a message loop. You can add a reference to Application or Form as per your need.
Here is an example by using Form:
using System;
using System.Windows.Forms;
using System.Threading;
using NAudio.Wave;
public class FOO
{
static WaveIn s_WaveIn;
[STAThread]
static void Main(string[] args)
{
Thread thread = new Thread(delegate() {
init();
Application.Run();
});
thread.Start();
Application.Run();
}
public static void init()
{
s_WaveIn = new WaveIn();
s_WaveIn.WaveFormat = new WaveFormat(44100, 2);
s_WaveIn.BufferMilliseconds = 1000;
s_WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(SendCaptureSamples);
s_WaveIn.StartRecording();
}
static void SendCaptureSamples(object sender, WaveInEventArgs e)
{
Console.WriteLine("Bytes recorded: {0}", e.BytesRecorded);
}
}
Just use WaveInEvent instead of WaveIn and the code will work. Then the handling happens on a separate thread instead of in a window message loop, which isn't available in a console application.
Further reading:
https://github.com/naudio/NAudio/wiki/Understanding-Output-Devices#waveout-and-waveoutevent
(The feature was added in 2012, so at the time of the question it wasn't available)
Related
I am unable to trace the cause of the problem here. The program starts a service that runs continuously. While this runs I need to run another piece of code every 30 seconds that I can do it either by using a background worker or using a timer.
I tried using both timer and async background worker. However every time there is a callback after 30 seconds the program exits. The code is given below,
using log4net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "logger.xml", Watch = true)]
namespace Service.Envelope
{
static class Program
{
private static readonly System.Timers.Timer Timer;
private static readonly ILog LOGGER = LogManager.GetLogger(typeof(Program));
private static Dictionary<int, int[]> MainCpseIdNodeIdDict = new Dictionary<int, int[]>();
private static int[] NodeIds;
private static int[] MainCpseIds;
private static EnvelopeMainService envelopeMainService;
private static void InitializeDict()
{
MainCpseIdNodeIdDict.Add(7, new int[] { 23476, 2276, 23472, 24498 });
//MainCpseIdNodeIdDict.Add(9, new int[] { 23476, 2276, 23472, 24498 });
MainCpseIds = new List<int>(MainCpseIdNodeIdDict.Keys).ToArray();
NodeIds = new List<int>(MainCpseIdNodeIdDict.Values.SelectMany(x => x)).ToArray();
}
private static void StartBackgroundWorker()
{
LOGGER.Fatal("Starting bg worker..");
BackgroundWorker work = new BackgroundWorker();
work.DoWork += new DoWorkEventHandler(work_DoWork);
work.RunWorkerAsync();
}
private static void work_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
System.Threading.Thread.Sleep(30 * 1000);
EnvelopeMainService.EnvelopeSwitch(false);
Console.WriteLine("Generating data ..");
envelopeMainService.GenerateBaseDataForGoodPart(); // program exits here
System.Threading.Thread.Sleep(30 * 1000);
}
}
static void Main()
{
InitializeDict();
LOGGER.MBLog("Start LOGGING");
StartBackgroundWorker();
EnvelopeMainService.SetUpTables();
EnvelopeMainService envelopeMainService = new EnvelopeMainService(NodeIds, MainCpseIds);
envelopeMainService.InitiateLiveEnvelope(MainCpseIdNodeIdDict);
}
}
}
The program exits at envelopeMainService.GenerateBaseDataForGoodPart(). This function calls a SQL function that loads the data to a datatable.
The timer version is given below. In both the versions the program exits at the same spot.
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Xml;
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "logger.xml", Watch = true)]
namespace Service.Envelope
{
static class Program
{
private static System.Timers.Timer Timer;
private static readonly ILog LOGGER = LogManager.GetLogger(typeof(Program));
private static Dictionary<int, int[]> MainCpseIdNodeIdDict = new Dictionary<int, int[]>();
private static int[] NodeIds;
private static int[] MainCpseIds;
private static EnvelopeMainService envelopeMainService;
private static void TimeIt()
{
Timer = new System.Timers.Timer(30000);
Timer.AutoReset = false;
Timer.Elapsed += OnTimedEvent;
Timer.Start();
}
private static void InitializeDict()
{
MainCpseIdNodeIdDict.Add(7, new int[] { 23476, 2276, 23472, 24498 2276 });
MainCpseIds = new List<int>(MainCpseIdNodeIdDict.Keys).ToArray();
NodeIds = new List<int>(MainCpseIdNodeIdDict.Values.SelectMany(x => x)).ToArray();
}
private static void StartService()
{
EnvelopeMainService.SetUpTables();
envelopeMainService = new EnvelopeMainService(NodeIds, MainCpseIds);
envelopeMainService.InitiateLiveEnvelope(MainCpseIdNodeIdDict);
}
static void Main()
{
TimeIt();
InitializeDict();
LOGGER.MBLog("Start LOGGING");
StartService();
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Timer.Enabled = false;
Timer.Stop();
EnvelopeMainService.EnvelopeSwitch(false);
Console.WriteLine("Generating data ..");
envelopeMainService.GenerateBaseDataForGoodPart(); // program exits here
Console.WriteLine($"Data generated\n Starting live envelope");
EnvelopeMainService.EnvelopeSwitch(true);
Timer.Enabled = true;
Timer.Start();
}
}
}
This program spawns a thread and the two threads communicate.It works fine and I would like to see how it appears in Windows Task Manager so I can understand it better. When I look in Task Manager I see this:
Should there be two entries somewhere in Task Manager because there are two threads? Is it all happening in .Net so there's nothing else to see in Task Manager?
using System;
using System.Threading;
namespace SensorNamespace {
class Sensor {
private ISensorInterface sensorInterface;
public Sensor(ISensorInterface sensorInterface) {
this.sensorInterface = sensorInterface;
}
private void ThreadStart() {
while (true) {
// The sensor reads a value from the real world and converts it to a double.
// We would need the unit of measure from the sensor manufacturer.
float value = (float)(new Random()).NextDouble();
sensorInterface.Update(value);
Thread.Sleep(500); // A nice pause because analog sensors are slow.
}
}
public void Start() {
Thread thread = new Thread(new ThreadStart(this.ThreadStart));
thread.Start();
}
}
}
using System;
using SensorNamespace;
using System.Threading;
namespace MultithreadedSensorInterfaceCSharp {
class Demo : SensorNamespace.ISensorInterface {
private static float sensorValue;
private static Sensor temperatureSensor;
static void Main(string[] args) {
Demo demo = new MultithreadedSensorInterfaceCSharp.Demo();
SensorNamespace.Sensor sensor = new SensorNamespace.Sensor(demo);
temperatureSensor = new SensorNamespace.Sensor(demo);
temperatureSensor.Start();
while (true) {
Console.WriteLine(sensorValue);
Thread.Sleep(5000);
}
}
void ISensorInterface.Update(float value) {
sensorValue = value;
}
}
}
namespace SensorNamespace {
interface ISensorInterface {
void Update(float value);
}
}
The entire project is here: https://github.com/nicomp42/MultithreadedSensorInterfaceCSharp
I made a simple C# app some time ago (as a console app), now I'm making a new version as a Windows Application in Sharpdevelop. I'm pretty new to C# and graphical applications and I got this confusing error.
What I want to do: on the UI, I have a button which checks if COM3 serial port is opened and if not, open it, if it's open, close it and write a message about it on a listbox. The problem is that wherever I put the serial handling part, I get errors about it not being in the current context, or get an "Object reference not set to an instance of an object" error.
I created the app with Sharpdevelop's template, so I have code in several files:
Program.cs:
using System;
using System.Windows.Forms;
namespace SerialClient_v2
{
class Program
{
[STAThread]
void Main(string[] args)
{
SerialHandle SH=new SerialHandle();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm(SH));
}
}
}
Mainform.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO.Ports;
namespace SerialClient_v2
{
public partial class MainForm : Form
{
private SerialHandle _sh;
public MainForm(SerialHandle sh)
{
InitializeComponent();
_sh = sh;
}
void ConnectBtnClick(object sender, EventArgs e)
{
try{
if(_sh._serialPort.IsOpen){
listBox1.Items.Add(DictionaryClass.strDisconnecting);
//Program._serialPort.Close();
}
else{
//Program._serialPort.Open();
listBox1.Items.Add(DictionaryClass.strConnecting);
}
}
catch (Exception ex)
{
listBox1.Items.Add("Error opening/writing to serial port :: " + ex.Message);
}
}
}
}
SerialHandle.cs: (this is my file, the stuff which used to be in the Main function in the console app comes here. DictionaryClass is just a translation helping class to easily switch between two languages)
using System;
using System.IO.Ports;
namespace SerialClient_v2
{
public class SerialHandle
{
bool SerialComm;
public SerialPort _serialPort;
public SerialHandle()
{
SerialPort _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.None;
_serialPort.ReadTimeout = 1000;
_serialPort.Open();
}
}
public static class DictionaryClass{
//DICTIONARY:
public static string strConnecting="Initializing serial communication!";
public static string strDisconnecting="Closing serial port";
}
}
The problem is that SH._serialPort.IsOpen can't be checked as it's not in the context. SH is created in the Main function, so I don't get why it's not seen. Sorry for the beginner question.
The simplest solution is to pass the SH object instance to the main form:
In SerialHandle.cs (use _sh._serialPort.IsOpen):
private SerialHandle _sh;
public MainForm(SerialHandle sh)
{
_sh = sh;
}
In Program.cs:
Application.Run(new MainForm(SH));
Simply move the initialization statement SerialHandle SH=new SerialHandle(); into MainForm.cs class
I'm new at C# programming and i'm lost with a thing that could be simple.
Executing a console application, at a moment i need to call a Windows Form that will show statics of the execution but when i call the form1.ShowDialog(); this stop the console runtime.
How do i keep my console execution alive while i show a Windows form screen ?
class Program
{
static Form1 form = new Form1();
public static bool run = true;
static void Main(string[] args)
{
work();
}
public static void work()
{
form.Show();
while (run)
{
Console.WriteLine("Console still running");
}
}
}
try this it work on me
using System.Windows.Forms;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public static bool run = true;
static void Main(string[] args)
{
Startthread();
Application.Run(new Form1());
Console.ReadLine();
}
private static void Startthread()
{
var thread = new Thread(() =>
{
while (run)
{
Console.WriteLine("console is running...");
Thread.Sleep(1000);
}
});
thread.Start();
}
}
}
Threading is like "process inside a process" in my own understanding.
See this question. You have to use Form1.Show() because Form1.ShowDialog() pauses execution until the form is closed.
Update This seems to be working (with Application.Run):-
public static Form1 form = new Form1();
public static bool run = true;
[MTAThread]
static void Main(string[] args)
{
new Thread(() => Application.Run(form)).Start();
new Thread(work).Start();
}
public static void work()
{
while (run)
{
Console.WriteLine("Console Running");
}
}
I'm somewhat new to C# on the whole and I'm developing a small program to render my backlog of CAD stuff when I'm idle. I'm using the MouseKeyboardActivityMonitor library found here: https://globalmousekeyhook.codeplex.com/ but having major problems such as input frozen upon the launch of my program and from there out no user input is detected by the hooks. I am using Windows 8.1 x64 and compiling both the DLL and my own executable towards .NET 4.0
Note: I am using Version 3 of the project
This is my code (just a small test of the hooks):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MouseKeyboardActivityMonitor;
using MouseKeyboardActivityMonitor.WinApi;
using System.Windows.Forms;
namespace HookTest1
{
class Program
{
static MouseHookListener mouseListener;
static KeyboardHookListener keyListener;
static void Main(string[] args)
{
Activate();
while (true)
{
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
private static void OnUserActivity()
{
Console.Write("UserAct");
}
private static void Activate()
{
mouseListener = new MouseHookListener(new GlobalHooker());
mouseListener.Enabled = true;
mouseListener.MouseDown += OnMouseActivity;
mouseListener.MouseMove += OnMouseActivity;
mouseListener.MouseWheel += OnMouseActivity;
keyListener = new KeyboardHookListener(new GlobalHooker());
mouseListener.Enabled = true;
keyListener.KeyDown += OnKeyActivity;
}
private static void OnMouseActivity(Object sender, System.Windows.Forms.MouseEventArgs e)
{
OnUserActivity();
}
private static void OnKeyActivity(Object sender, System.Windows.Forms.KeyEventArgs e)
{
OnUserActivity();
}
}
}
Thanks for any and all help!
You may have added this somewhere and just removed it in your sample... but have you called
Application.Run();
in Main()? As I understand it, you're attempting to hook window events without a message loop going. Application.Run will get it running.