I'm using the naudio lib in C# and want to play a simple file. The problem is, the playback stops after 1 second. I cant figure out the reason why it does that.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAudio.Wave;
namespace NAudioTest
{
class Program
{
static IWavePlayer waveout;
static WaveStream outputStream;
static string filename = null;
static void Main(string[] args)
{
waveout = new WaveOut();
filename = "C:\\1.wav";
outputStream = CreateInputStream(filename);
try
{
waveout.Init(outputStream);
}
catch (Exception ex)
{
Console.WriteLine("Error while loading output");
Console.WriteLine("Details: " + ex.Message);
Console.ReadLine();
return;
}
Console.WriteLine("Press [Enter] to start playback");
Console.ReadLine();
waveout.Play(); //this stops after 1 sec. should it play until i hit enter cause of the next line?
Console.WriteLine("Press [Enter] to abort");
Console.ReadLine();
waveout.Dispose();
Console.ReadLine();
}
static WaveStream CreateInputStream(string name)
{
WaveChannel32 inputStream;
if (name.EndsWith(".wav"))
{
WaveStream readerStream = new WaveFileReader(name);
if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
{
readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
readerStream = new BlockAlignReductionStream(readerStream);
}
if (readerStream.WaveFormat.BitsPerSample != 16)
{
var format = new WaveFormat(readerStream.WaveFormat.SampleRate, 16, readerStream.WaveFormat.Channels);
readerStream = new WaveFormatConversionStream(format, readerStream);
}
inputStream = new WaveChannel32(readerStream);
}
else
{
throw new InvalidOperationException("Invalid extension");
}
return inputStream;
}
}
}
You need to make sure you are using function callbacks if you are trying to play audio from a console app, since the default for WaveOut is to use window callbacks.
new WaveOut(WaveCallbackInfo.FunctionCallback())
Update: With newer versions of NAudio I now recommend that you avoid function callbacks, as they can cause deadlocks with certain drivers. Instead, WaveOutEvent which uses event callbacks and a background thread is the preferred mechanism:
new WaveOutEvent()
Related
I am trying to send a Midi Note On message out to DAW software using NAudio, with a virtual port created by teVirtualMIDI. I am able to see the "device" created by teVirtualMIDI in Ableton Live 10, but have been unsuccessful in receiving any information in Live. My sound is turned up, and I never see Live's Midi meter move. The Code is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NAudio.Midi;
using TobiasErichsen.teVirtualMIDI;
namespace BDBConsole_1_0
{
public class BDBMidiClient
{
public static ConsoleKeyInfo cKi;
public static TeVirtualMIDI port;
static MidiOut midiOut;
int midiOutIndex;
//public static List<MidiEvent> noteEvent;
static void Main(string[] args)
{
CreateMidiPort();
}
public static void CreateMidiPort()
{
TeVirtualMIDI.logging(TeVirtualMIDI.TE_VM_LOGGING_MISC | TeVirtualMIDI.TE_VM_LOGGING_RX | TeVirtualMIDI.TE_VM_LOGGING_TX);
string portName = "BDB Client";
//port = new TeVirtualMIDI(portName, 65535, TeVirtualMIDI.TE_VM_FLAGS_INSTANTIATE_BOTH);
port = new TeVirtualMIDI(portName);
Console.WriteLine("New Midi Port Opened...");
Console.ReadKey();
EnumerateMidiOutDevices();
Thread thread = new Thread(new ThreadStart(SendNextMidiOutMessage));
thread.Start();
//SendNextMidiOutMessage();
}
public static void EnumerateMidiOutDevices()
{
int noOutDevices = MidiOut.NumberOfDevices;
Console.WriteLine("No. of Midi Out Devices..." + noOutDevices);
Console.ReadKey();
string deviceOutOne = MidiOut.DeviceInfo(1).ProductName;
Console.WriteLine("Device One..." + deviceOutOne);
Console.ReadKey();
}
public static void SendNextMidiOutMessage()
{
midiOut = new MidiOut(deviceNo: 0);
//events = new List<MidiEvent>();
int channel = 1;
int note = 64;
var noteOnEvent = new NoteOnEvent(0, channel, note, 127, 1000);
try
{
//while (true) loop here before
do
{
Console.WriteLine("Send Midi Note...");
cKi = Console.ReadKey();
midiOut.Send(noteOnEvent.GetAsShortMessage());
Console.WriteLine("Note Sent...");
cKi = Console.ReadKey();
} while (cKi.Key != ConsoleKey.Escape);
port.shutdown();
Console.WriteLine("Midi Port Closed...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine("thread aborting: " + ex.Message);
}
}
}
}
Any Help with this would be greatly appreciated!
I swear this code used to work .....
I'm using code from this sample:
https://www.codeproject.com/Articles/871746/Implementing-pub-sub-using-MSMQ-in-minutes
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Messaging;
using System.Threading;
namespace MSMQPublisher
{
class Publisher
{
static void Main(string[] args)
{
try
{
string MSMQMulticastAddress = "FormatName:MULTICAST=234.1.1.1:8001";
var messageQueue = MessageQueue.Create(MSMQMulticastAddress, true);
var stopWatch = new Stopwatch();
stopWatch.Start();
for (var i = 0; i < 10; i++)
{
Message msg = new Message(string.Format($"{DateTime.UtcNow.Ticks}: msg:{i} hello world "));
msg.UseDeadLetterQueue = true;
msg.TimeToBeReceived = new TimeSpan(0, 0, 1, 0);
messageQueue.Send(msg);
Console.WriteLine("[MSMQ] Sent");
Thread.Sleep(10);
}
stopWatch.Stop();
Console.WriteLine("====================================================");
Console.WriteLine("[MSMQ] done sending messages in " + stopWatch.ElapsedMilliseconds);
Console.WriteLine("[MSMQ] Sending reset counter to consumers.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTION: " + ex.Message);
Console.Read();
}
}
}
}
Which throws the exception :
"Cannot create a queue with the path FormatName:MULTICAST=234.1.1.1:8001."} System.Exception
{System.ArgumentException}
I've tried this on several Windows 10 Machines.
I tried setting [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSMQ\Parameters]
"MulticastBindIP"
Can anyone suggest a possible resolution or point out what stupid thing I'm doing?
Thanks
To reproduce the issue, I created a console project and below is the code in my Program.cs file:
using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;
namespace TestSavingTwoBigFiles
{
public class Program
{
private static string folderPath = #"C:\FOLDERPATH\";
private static string fileName1 = folderPath + "FILENAME1.xlsm";
private static string fileName2 = folderPath + "FILENAME2.xlsm";
public static void StartThread(string ordinal, string fileName)
{
Console.WriteLine("Creating {0} file...", ordinal);
var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
try
{
using (wb)
{
using (var ms = new MemoryStream())
{
Console.WriteLine("Saving {0} file...", ordinal);
wb.SaveAs(ms);
}
}
Console.WriteLine("{0} file saved successfully", ordinal);
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
public static void Main(string[] args)
{
var thread1 = new Thread(() => StartThread("first", fileName1));
Console.WriteLine("Starting first thread");
thread1.Start();
var thread2 = new Thread(() => StartThread("second", fileName2));
Console.WriteLine("Starting second thread");
thread2.Start();
}
}
}
[Thanks #EmilyLin for the cleaner version]
When I run the above program with two `.xlsm files, one is ~2MB and the other one is ~7MB, the program completes successfully. However, when I run it with two ~7MB files, the program will be stuck at the saving statements and does not progress without throwing an exception. The console will stay as the following image shows and does not change.
One workaround we used was placing a lock on the SaveAs method. Is there a better way?
Thanks!
Placing a lock on the SaveAs method is probably the best way. In the source code for XLWorkbook.cs, both SaveAs functions use FileStream and/or MemoryStream. Neither streams are thread-safe, so your code may not work if run simultaneously with multiple threads, so you should make sure that only one thread can access the MemoryStream at the same time.
Here is an example:
using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;
namespace Whatever
{
class Class1
{
private static readonly object lockObject = new object();
public static void StartThread(string ordinal, string fileName)
{
Console.WriteLine(string.Format("creating {0} file...", ordinal));
var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
try
{
using (wb)
using (var ms = new MemoryStream())
{
lock (lockObject)
{
Console.WriteLine(string.Format("saving {0} file...", ordinal));
wb.SaveAs(ms);
}
}
Console.WriteLine(string.Format("{0} file saved successfully", ordinal));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public static void Main(string[] args)
{
var thread1 = new Thread(() => StartThread("first", "a.xlsm"));
thread1.Start();
var thread2 = new Thread(() => StartThread("second", "b.xlsm"));
thread2.Start();
}
}
}
my code runs and creates a test.wav but this file dosent contain aything. i am trying to run this code in a console application. please help
using System;
using System.Media;
using NAudio;
using NAudio.Wave;
class sound
{
public static void Main()
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(0);
Console.WriteLine("Now recording...");
WaveInEvent waveSource = new WaveInEvent();
waveSource.DeviceNumber = 0;
waveSource.WaveFormat = new WaveFormat(16000, deviceInfo.Channels);
//waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
string tempFile = (#"C:\Users\user\Desktop\test1.wav");
WaveFileWriter waveFile = new WaveFileWriter(tempFile, waveSource.WaveFormat);
waveSource.StartRecording();
}
//void waveInStream_DataAvailable(object sender, WaveInEventArgs e)
//{
// wavefile.WriteData(e.Buffer, 0, e.BytesRecorded);
//}
}
and can someone please explain what do the lines which are commented mean. i am a beginner in programming.
when i compile the program it gives 2 errors:
Error 1: An object reference is required for the non-static field, method, or property 'sound.waveSource_DataAvailable(object, NAudio.Wave.WaveInEventArgs)' C:\Users\user\Documents\Visual Studio 2008\Projects\sound\sound\Program.cs 18 49 sound
Error 2 The name 'wavefile' does not exist in the current context C:\Users\user\Documents\Visual Studio 2008\Projects\sound\sound\Program.cs 28 21 sound
Apparently the StartRecording methods start some capture loops that periodically raises the DataAvailable event to allow the user collecting the recorded data. In your example code the event handle properly append the recorded data to the file tempFile. Both the function waveInStream_DataAvailable and the waveFile must be declared as static.
Try this:
using System;
using System.Media;
using NAudio;
using NAudio.Wave;
class sound
{
static WaveFileWriter waveFile;
public static void Main()
{
//WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(0);
Console.WriteLine("Now recording...");
WaveInEvent waveSource = new WaveInEvent();
//waveSource.DeviceNumber = 0;
waveSource.WaveFormat = new WaveFormat(44100, 1);
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
string tempFile = (#"C:\Users\user\Desktop\test1.wav");
waveFile = new WaveFileWriter(tempFile, waveSource.WaveFormat);
waveSource.StartRecording();
Console.WriteLine("Press enter to stop");
Console.ReadLine();
waveSource.StopRecording();
waveFile.Dispose();
}
static void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
waveFile.WriteData(e.Buffer, 0, e.BytesRecorded);
}
}
I have a big problem, but probably it's only big for me :). "terminal.Bind(client);" this line causes my program to hang if IP is bad. I want to stop this program after 5s working because if IP is wrong after 10s all program is hang.. :(
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rebex.TerminalEmulation;
using Rebex.Security;
using Rebex.Net;
namespace Routers_info_v._1
{
class Program
{
static void Main(string[] args)
{
Telnet client = new Telnet("192.168.1.1");
VirtualTerminal terminal = new VirtualTerminal(80, 25);
terminal.Bind(client);
terminal.SendToServer("pass\r");
terminal.SendToServer("sys ver\r");
TerminalState state;
do
{
state = terminal.Process(2000);
} while (state == TerminalState.DataReceived);
terminal.Save("terminal.txt", TerminalCaptureFormat.Text, TerminalCaptureOptions.DoNotHideCursor);
terminal.Unbind();
terminal.Dispose();
}
}
}
Try to wrap the call in a try catch (assuming some exception is thrown):
try
{
terminal.Bind(client);
}
catch(Exception ex)
{
return;
}
You could kick off the Bind in a thread, and start a timer, if the thread takes X seconds too long to complete, you could kill the thread, or your application, whichever you choose.
You can use Task.Wait. Here is little simulation for an operation which will take 10 sec and you are waiting it for 5 sec to finish :)
using System;
using System.Linq;
using System.Data.Linq;
using System.Data;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class VirtualTerminal
{
public VirtualTerminal(int a, int b) { }
public bool Bind() { System.Threading.Thread.Sleep(10000); return true; }
}
class Program
{
static void Main(string[] args)
{
VirtualTerminal terminal = new VirtualTerminal(80, 25);
Func<bool> func = () => terminal.Bind() ;
Task<bool> task = new Task<bool>(func);
task.Start();
if (task.Wait(5*1000))
{
// you got connected
}
else
{
//failed to connect
}
Console.ReadLine();
}
}
}
I would suggest to put the network stuff into a second thread, which then may be aborted by the main thread.
class Program {
static void Main(string[] args) {
Thread thread = new Thread(threadFunc);
thread.Start();
Stopwatch watch = new Stopwatch();
watch.Start();
while (watch.ElapsedMilliseconds < 5000 && thread.IsAlive)
;
if (!thread.IsAlive) {
thread.Abort();
Console.WriteLine("Unable to connect");
}
}
private static void threadFunc() {
Telnet client = new Telnet("192.168.1.1");
VirtualTerminal terminal = new VirtualTerminal(80, 25);
terminal.Bind(client);
// ...
terminal.Dispose();
}
}