How to start a process that is a resource? - c#

I add my test.bat as a resource via resx. I then try
proc.StartInfo.FileName = myNamespace.Properties.Resources.test;
but it says
System.ComponentModel.Win32Exception: The system cannot find the file specified.'
How can I fix this?
Here is my full code:
public async void button_A_Click(object sender, EventArgs e)
{
button_A.Enabled = false;
await Task.Run(() => {
var proc = new Process();
proc.StartInfo.FileName = LOS_Installer.Properties.Resources.test;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.Arguments = path;
if (proc.Start())
{
void outputCallback(string data)
{
textBoxLog.AppendText(data);
textBoxLog.AppendText(Environment.NewLine);
}
proc.OutputDataReceived += (_, e) => Invoke(outputCallback, e.Data);
proc.ErrorDataReceived += (_, e) => Invoke(outputCallback, e.Data);
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
proc.WaitForExit();
});
button_A.Enabled = true;
}
Minor question: it seems that the resource manager doesn't care about file's extension. So what if I have 2 files with the same name yet different extensions?

If embedded test.bat contains this text:
#echo off
title Testing...
echo Lorem ipsum is placeholder text commonly used in
echo the graphic, print, and publishing industries for
echo previewing layouts and visual mockups.
pause
and the objective is to run it programmatically...
... from an embedded resource:
Then here's one way to copy it to a tmp file and run it (see explanation in the comments).
public MainForm()
{
InitializeComponent();
buttonRunBatch.Click += runFromEmbedded;
}
private void runFromEmbedded(object sender, EventArgs e)
{
var asm = GetType().Assembly;
// Obtain the full resource path (different from a file path).
var res =
asm
.GetManifestResourceNames()
.Where(_ => _.Contains("Scripts.test.bat"))
.FirstOrDefault();
// Make path for a temporary file
var tmp = Path.Combine(Path.GetTempPath(), "tmp.bat");
// Get the byte stream for the embedded resource...
byte[] bytes;
using (var stream = asm.GetManifestResourceStream(res))
{
bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
}
// ... and write it to the tmp file
using (FileStream fileStream = new FileStream(tmp, FileMode.Create))
{
try
{
fileStream.Lock(0, bytes.Length);
fileStream.Write(bytes, 0, bytes.Length);
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
finally
{
fileStream.Unlock(0, bytes.Length);
}
}
// RUN the bat file.
var process = Process.Start(fileName: tmp);
SetForegroundWindow(process.MainWindowHandle);
process.WaitForExit();
// Clean up.
File.Delete(tmp);
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);

Related

Process has exited, so the requested information is not available

public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{ try
{
Print();
}
catch(Exception ex)
{
File.AppendAllText(#"C:\fold1\Log.txt", ex.ToString());
}
}
public static void Print()
{
//Print & Move the files after printing
DirectoryInfo sourceinfo = new DirectoryInfo(#"C:\fold");
DirectoryInfo target = new DirectoryInfo(#"C:\fold1");
foreach (FileInfo fi in sourceinfo.GetFiles())
{
if (fi.Length != 0)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.Refresh();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.Verb = "print";
process.StartInfo.FileName = fi.FullName;
process.StartInfo.UseShellExecute = true;
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.Start();
process.WaitForInputIdle();
System.Threading.Thread.Sleep(18000);
if (!process.CloseMainWindow())
process.Kill();
MoveFile(fi.FullName);
}
}
}
public static void MoveFile(string Filename)
{
string SourcePath = #"C:\fold";
string targetpath = #"C:\fold1";
if (!Directory.Exists(targetpath))
{
Directory.CreateDirectory(targetpath);
}
string[] sourceFiles = Directory.GetFiles(SourcePath);
foreach (string sourcefile in sourceFiles)
{
string mfilename = Path.GetFullPath(sourcefile);
string mname = Path.GetFileName(sourcefile);
if (mfilename == Filename)
{
string distnition = Path.Combine(targetpath, mname);
File.Move(mfilename, distnition);
}
}
}
protected override void OnStop()
{
File.AppendAllText(#"C:\fold1\stop.txt", "Stop method");
}
}
I created a windows service that prints all the pdf(which means i need to use adobe reader or some other pdf reader) files in a directory but when I run it , it does nothing , I wrote my code so that any error is edited into a file and this is what it gives me "Process has exited, so the requested information is not available".
You are trying to close the process after it has exited with Process.CloseMainWindow (see the docs - InvalidOperationException). Change the code to kill the process only, if the process if still active. Also, in a non-user-interactive environment like a window service, the printing process wouldn't have a MainWindow, so CloseMainWindow won't close it.
if (fi.Length != 0)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.Verb = "print";
process.StartInfo.FileName = fi.FullName;
process.StartInfo.UseShellExecute = true;
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.Start();
if (!process.WaitForExit(180000))
process.Kill();
MoveFile(fi.FullName);
}
You don't print the empty files but you also don't move them. Consider moving them out of your watched folder, otherwise it could get filled up with 0 length files that would never be printed. So move the line MoveFile(fi.FullName); after the if-block, if this fits the requirements.

C# WPF application capture python script console output

I have been trying for hours to figure out how to do this but I have a python script that was made into an exe so it acts a console application I'm trying to write a GUI wrapper for it using WPF I have it set up to where it does execute the exe with the command arguments but I want to capture the output from the console and display it in a text box and i can not figure it out. I have tried multiple code snippets but it either does nothing, Outputs after the python exe has finished, or locks up the GUI until the python exe finishes then dumps the completed output to the textbox.
Would someone be able to take a look and see if they can help me with this?
public partial class MainWindow : Window
{
//string output = string.Empty;
private static StringBuilder output = new StringBuilder();
private object syncGate = new object();
private Process process;
private bool outputChanged;
public MainWindow()
{
InitializeComponent();
}
private void RB_Mii_Checked(object sender, RoutedEventArgs e)
{
}
//If we click the button we copy the bin file to the work directory
private void btn_SelMiiQR_Click(object sender, RoutedEventArgs e)
{
//Copy the encrypted.bin file to the working directory
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Input.bin (*.bin)|*.bin|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (openFileDialog.ShowDialog() == true)
{
var fileName = openFileDialog.FileName;
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
//If the file exists delete the existing file and copy the newone.
if (System.IO.File.Exists(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName)))
{
System.IO.File.Delete(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
System.IO.File.Copy(fileName, System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
}
//If the button was clicked use the input.bin file and attempt to brute force the movable_sedpart1.bin
private void BTN_MIIBF_Click(object sender, RoutedEventArgs e)
{
//If the mfg has input year or no input use it
if (TB_MFGYR.Text.Length == 0 || TB_MFGYR.Text.Length == 4)
{
string DStype = null;
string MFGYR = null;
//Grab the Year if it has value
if (TB_MFGYR.Text.Length == 4)
{
MFGYR = TB_MFGYR.Text;
}
else
{
MFGYR = null;
}
if (RB_N3ds.IsChecked == true)
{
DStype = "new";
}
else if (RB_O3DS.IsChecked == true)
{
DStype = "old";
}
//Execute Command with Arguments
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
string dir = System.IO.Path.GetDirectoryName(exePath)+"\\App\\";
//Start the process and export thr console output to the textbox
CreateProcess(dir + "seedminer_launcher.exe", "Mii " + DStype + " " + MFGYR, dir);
}
//Else display Error Message WIP
else
{
tb_outputtext.Text = null;
tb_outputtext.Text = "MFG Year must have 4 characters or none";
}
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
private void ReadData()
{
var input = process.StandardOutput;
int nextChar;
while ((nextChar = input.Read()) >= 0)
{
lock (syncGate)
{
output.Append((char)nextChar);
if (!outputChanged)
{
outputChanged = true;
var dispatcher = Application.Current.MainWindow.Dispatcher;
Dispatcher.BeginInvoke(new Action(OnOutputChanged));
}
}
}
lock (syncGate)
{
process.Dispose();
process = null;
}
}
private void OnOutputChanged()
{
lock (syncGate)
{
tb_outputtext.AppendText(output.ToString());
outputChanged = false;
}
}
}
If I understand you correctly then you want your WPF app to continously update the content ot the TextBox while your python executable is running?
I have stripped down your code and used the Windows command ping -t 127.0.0.1 -w 10000 which generates a new line every second to test your code. On my machine your code works as expected: the output in the WPF textbox is updated every second.
What happens if you replace the ping command with your python executable in the code below? Does your python script output a newline character after each line (as mentioned in Process.OutputDataReceived Event)?
MainWindow.xaml.cs
using System;
using System.Diagnostics;
using System.Windows;
namespace SO_Continous_Process_Output
{
public partial class MainWindow : Window
{
private Process process;
public MainWindow()
{
InitializeComponent();
CreateProcess("ping", "-t 127.0.0.1 -w 1000", "");
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
}
}
MainWindow.xaml
<Window x:Class="SO_Continous_Process_Output.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="tb_outputtext" Text="{Binding ProcessOutput}"></TextBox>
</Grid>
</Window>
Update
Python script
I wrote a python script to test if the output works and I had to set flush=True in order to make it work.
import time
while True:
print('hi!', flush=True)
time.sleep(1)

How to run process in background? c#

I am using wkhtmltopdf for reporting purpose in my application. However it works great as expected.
Problem-
In below method for I am converting strings source to pdf and writing bytes.
Note-
I am starting process before reading all bytes and trying to run a process.
The main problem is background ability of running this process. I don't get this process to run in background.
Currently what happens is until pdf is not generated the whole application goes in halt mode.This is something to do with background process is not working.
How do I modify this process so it works in background without halting my application?
I have read about task factory and multiple threads but I didn't get the clue.
Method for pdf conversion-
public byte[] ConverToPdf(string source, string commandLocation)
{
string HtmlToPdfExePath = Server.MapPath("~/wkhtmltopdf.exe");
Process p;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(commandLocation, HtmlToPdfExePath);
psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
string args = "-q -n ";
args += "--enable-javascript ";
args += "--enable-plugins ";
args += "--disable-smart-shrinking ";
args += "--margin-bottom 20 ";
args += "--margin-left 20 ";
args += "--margin-right 20 ";
args += "--margin-top 20 ";
args += "--orientation Landscape ";
args += "--outline-depth 0 ";
args += "--page-size A4 ";
args += "--encoding utf-8";
args += " - -";
psi.Arguments = args;
p = Process.Start(psi);
try
{
using (StreamWriter stdin = new StreamWriter(p.StandardInput.BaseStream, Encoding.UTF8))
{
stdin.AutoFlush = true;
stdin.Write(source);
}
byte[] buffer = new byte[32768];
byte[] file;
using (var ms = new MemoryStream())
{
while (true)
{
int read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
ms.Write(buffer, 0, read);
}
file = ms.ToArray();
}
p.StandardOutput.Close();
p.WaitForExit(60000);
int returnCode = p.ExitCode;
p.Close();
if (returnCode == 0)
return file;
else
return file;
}
catch (Exception ex)
{
ModelState.AddModelError("Could not create PDF", ex);
}
finally
{
p.Close();
p.Dispose();
}
return null;
}
Update-
I was actually trying to find a way of background worker to do its job and return bytes from above method.
My main purpose of calling this method with background worker is Communicating back to from where it was called with results.
public ActionResult DuesPDF()
{
var relativePath = "~/Views/Shared/_TestView.cshtml";
string content;
var view = ViewEngines.Engines.FindView(ControllerContext, relativePath, null);
using (var writer = new StringWriter())
{
TempData["req"] = "DuesAndOverDuesChart";
var context = new ViewContext(ControllerContext, view.View, ViewData, TempData, writer);
view.View.Render(context, writer);
writer.Flush();
content = writer.ToString();
byte[] pdfBuf = ConverToPdf(content, Server.MapPath("~/PDF/"));
if (pdfBuf == null)
return null;
return File(pdfBuf, "application/pdf");
}
}
Here is in this method I am calling pdf method- ConverToPdf(content, Server.MapPath("~/PDF/"))
Note-
I am asking for communication from ConverToPdf method above with background worker.
Use Thread Class it will run your method in background thread other than the main thread.
More over you are returning null in your method so its better to make the return type void and do not return null.
Thread threadObj = new Thread(new ThreadStart(()=>ConverToPdf("a","b")));
threadObj.Start();
Update : I am assuming you are using windows form. As per your updates you can easily see that your main method need the response to execute further. now for this i would suggest you to show some progress bar in background thread so that i would not halt the application. and when the converttoPDF method finishes it process stop the progress bar. in this case your application would not stuck and you will get the response as you need.
private void Button1_Click(object sender, EventArgs e)
{
bgworker.RunWorkerAsync();
}
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
ConverToPdf(source, commandLocation);
}

How can I feed commands to cmd.exe process via an input stream manually?

The question sounds a bit, dense. Here is a slightly longer version:
I need to have the main loop wait for user input and also have a process running and waiting for input from a stream to which the user input is to be sent.
Full story: I'm building a Cmd emulator and at first everything looked fine: The user enters a command, it gets echoed to the output area, processed and StdOut and StdErrOut are captured and also added to the output TextBox.
The only problem was, that, as the cmd process was created and started separately for each command, no state was kept. Neither variables nor codepage nor working directory etc..
So I decided to invent a little hack: Entering an opening or closing parenthesis starts and stops collecting the commands instead of executing them. After the closing parenthesis the list of commands ('batch') is used in the processBatch method to feed them all to the cmd process vie its redirected input. Worked fine.
The only problem was, obviously, now I got state but lost immediate response, so any errors wouldn't pop up until the batch was run.
So I decided to combine the good parts and, well, I knew I was heading for trouble when I realized, that to keep two loops working & waiting I have to use threading. Which I haven't done in years..
In the layout I chose the main() loop waits for user input and startCMDtask() runs startCMD() in a task. Here the input stream is scanned until is has data and then the cmd process is to process them..
But it doesn't work.
List<string> batch = new List<string>();
public volatile string output = "+";
public volatile string outputErr = "-";
Process CMD;
Task cmdTask;
volatile Queue<string> cmdQueue = new Queue<string>();
volatile public bool CMDrunning = false;
Tthis works just fine
private void processBatch()
{
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
foreach(string line in batch) sw.WriteLine(line);
}
output = "^"; outputErr = "~";
try { output = p.StandardOutput.ReadToEnd(); } catch { }
try { outputErr = p.StandardError.ReadToEnd(); } catch { }
try { p.WaitForExit(); } catch { }
tb_output.AppendText(output + "\r\n" + outputErr + "\r\n");
}
These don't quite, but almost..
private void setupCMD()
{
CMD = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
// info.Arguments = "/K"; // doesn't make a difference
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
CMD.StartInfo = info;
}
private void startCMDtask()
{
var task = Task.Factory.StartNew(() => startCMD());
cmdTask = task;
}
private void startCMD()
{
try { CMD.Start(); CMDrunning = true; }
catch { output = "Error starting cmd process.\r\n"; CMDrunning = false; }
using (StreamWriter sw = CMD.StandardInput)
{
if (sw.BaseStream.CanWrite)
do {
try
{
string cmd = cmdQueue.Dequeue();
if (cmd != null & cmd !="")
{
sw.WriteLine(cmd);
processOutputStreams();
}
}
catch {}
} while (CMDrunning);
}
private void processOutputStreams()
{
string newOutput = ""; string newOutputErr = "";
while (CMD.StandardOutput.Peek() > 0)
newOutput += (char)(CMD.StandardOutput.Read());
newOutput += "!?"; // at this point stdout is correctly captured (1)
try {
while (CMD.StandardError.Peek() > 0) // from here execution jumps away (2)
{ newOutputErr += (char)(CMD.StandardError.Read()); }
} catch {
newOutputErr = "?"; // never comes here
}
lock (output) // no noticable difference
lock (outputErr) //
{ // if I jump here (3) from (1) the result is displayed
// but not if i comment out the 2nd while loop (2)
if (newOutput != null & newOutput != "") output += newOutput + "\r\n";
if (newOutputErr != null & newOutputErr != "") outputErr += newOutputErr + "\r\n";
}
}
This is the call from the input processor in the main thread:
lock (cmdQueue) cmdQueue.Enqueue(cmd);
I have no idea which part is the problem: the process, the cmd shell, the input stream, the output stream, the threading, the locks or all of it in turns..??
I finally got it working. The reason for the erratic behaviour I described in the code samples was that the 3 streams were not accessed in an async'ed manner.
To rectify I discarded the processOutput function and replaced it by two calls that the process itself triggers. MS documetation gives a fine example here
I also made the StreamWriter sync, that feeds the process and the whole task it runs in as well.
Here is the new code:
private void startCMDtask()
{
var task = Task.Factory.StartNew(() => startCMD());
cmdTask = task;
}
private async void startCMD()
{
try { CMD.Start(); CMDrunning = true; }
catch { cmdErrOutput.Append("\r\nError starting cmd process.");
CMDrunning = false; }
CMD.BeginOutputReadLine();
CMD.BeginErrorReadLine();
using (StreamWriter sw = CMD.StandardInput)
{
if (sw.BaseStream.CanWrite)
do {
try
{
string cmd = cmdQueue.Dequeue();
if (cmd != null & cmd !="") await sw.WriteLineAsync(cmd);
}
catch { }
} while (CMDrunning);
try { CMD.WaitForExit(); }
catch { cmdErrOutput.Append("WaitForExit Error.\r\n"); }
}
}
This is how the process is set up now:
private void setupCMD()
{
CMD = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
CMD.OutputDataReceived += new DataReceivedEventHandler(cmdOutputDataHandler);
CMD.ErrorDataReceived += new DataReceivedEventHandler(cmdErrorDataHandler);
cmdOutput = new StringBuilder();
cmdErrOutput = new StringBuilder();
CMD.StartInfo = info;
}
And here are the output handlers:
private static void cmdOutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{ // Add the text to the collected output.
cmdOutput.Append(Environment.NewLine + outLine.Data);
}
}
private static void cmdErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{ // Add the text to the collected error output.
cmdErrOutput.Append(Environment.NewLine + outLine.Data);
}
}
At the end of the user input porcessing this is how the input queue is ged and the output fetched:
cmdUnDoStack.Push(cmd);
Application.DoEvents();
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => updateOutputArea(uiScheduler));
Using this little routine:
private void updateOutputArea(TaskScheduler uiScheduler)
{
Task.Factory.StartNew(() =>
{
tb_output.AppendText(cmdOutput + "\r\n" + cmdErrOutput + "\r\n");
cmdOutput.Clear();
cmdErrOutput.Clear();
}, System.Threading.CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}
And now for the special treament some of the good old commands like CLS or COLOR need.. ;-)

How to amplify, increase bitrate and Fadin- fadout the recorded audio in Windows Phone 7?

I am facing the following problem regarding to the voice (Audio) recording in windows phone 7.
I am recording the sound using Microphone class available in Microsoft.Xna.Framework.Audio namespace. here is the code -
Variable declaration:
private Microphone mic = Microphone.Default;
private MemoryStream stream;
private const string FILE_NAME = "recording.mp3";
byte[] buffer;
Recording Button click code-
mic.BufferDuration = TimeSpan.FromSeconds(1);
buffer = new byte[mic.GetSampleSizeInBytes(mic.BufferDuration)];
// Create the event handler. I could have done an anonymous
// delegate here if I had so desired.
mic.BufferReady += new EventHandler<EventArgs>(mic_BufferReady);
stream = new MemoryStream();
mic.Start();
Buffer Ready Event code ----------
void mic_BufferReady(object sender, EventArgs e)
{
mic.GetData(buffer);
// Write buffer to stream
stream.Write(buffer, 0, buffer.Length);
}
Button stop code -
private void btnStop_Click(object sender, RoutedEventArgs e)
{
dt.Stop();
btnStop.IsEnabled = false;
btnPlayRecording.IsEnabled = true;
mic.Stop();
//Writing stream into Storage
writeFile(stream);
}
private void writeFile(MemoryStream s, string name)
{
try
{
using (var userStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (userStore.FileExists(name))
{
userStore.DeleteFile(name);
}
using (var file = userStore.OpenFile(name, FileMode.CreateNew))
{
s.WriteTo(file);
}
}
}
catch (Exception ee)
{
}
}
Once I save the stream into isolated storage and play it back, the volume is very low and the quality is also not good.
So
Can we amplify the Volume ?
can we increase the bitrate ?
Can we do Fadin-Fadout ?
If all these three is not possible in windows phone 7, then is there any third party API available to perform all these operations?
Thanks in advance
Amplification in .NET is not trivial. The best approach I found was to make an external process call to "SoX, the Swiss Army knife of sound processing programs." (http://sox.sourceforge.net/)
I don't have a Windows 7 phone -- so I don't know for sure that SOX runs there.
The format would be SOX -V volume_parameter inputFileName outputFileName for amplification, so:
"sox.exe -v 3.0 myNormalFile.wav myAmpedFile.wav"
would give you an amplification of 300%. Sox also allows for bitrate change... not sure of Fadein/Fadeout.
I don't have anything specifically for Windows 7 phone, but in straight .NET/C# Code:
string finalFileName = "myAmplifiedFile.WAV";
string tmpFileName = "tmpHoldingFile.WAV";
string soxEXE = #"C:\SOX\sox.exe";
string soxArgs = "-v 3.0 ";
/// OTHER STUFF HERE
/*-----------------------------------------------------------
* Call the SOX utility to amplify it so it is 3 times as loud.
*-----------------------------------------------------------*/
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = new System.Diagnostics.ProcessStartInfo();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = soxEXE;
process.StartInfo.Arguments = string.Format("{0} {1} {2}",
soxArgs, tmpFileName, finalFileName);
process.Start();
process.WaitForExit();
int exitCode = process.ExitCode;
}
catch (Exception ex)
{
string err = ex.Message;
return false;
}
/*-------------------------------------------------------------
* OK, now we play it using SoundPlayer
*-------------------------------------------------------------*/
try
{
SoundPlayer simpleSound = new SoundPlayer(#finalFileName);
simpleSound.PlaySync();
FileInfo readFile = new FileInfo(finalFileName);
string finalDestination = finalDirectory + "/" + readFile.Name;
readFile.MoveTo(finalDestination);
}
catch (Exception e)
{
string errmsg = e.Message;
return false;
}
finalFileName = "";
tmpFileName = "";
spVoice = null;

Categories

Resources