NAudio streaming to mp3 file throught yeti lame wrapper - c#

I have the following code to record audio in and out
using System;
using System.Diagnostics;
using System.IO;
using NAudio.Wave;
using Yeti.MMedia.Mp3;
namespace SoundRecording
{
public class SoundManager
{
private WaveInEvent _waveIn;
private WaveFileWriter _waveInFile;
private WasapiLoopbackCapture _waveOut;
private WaveFileWriter _waveOutFile;
private Process _lameProcess;
public void StartRecording()
{
InitLame();
DateTime dtNow = DateTime.Now;
try
{
InitAudioOut(dtNow);
}
catch
{
}
try
{
InitAudioIn(dtNow);
}
catch
{
}
}
private void InitLame()
{
string outputFileName = #"c:\Rec\test.mp3";
_lameProcess = new Process();
_lameProcess.StartInfo.FileName = #"lame.exe";
_lameProcess.StartInfo.UseShellExecute = false;
_lameProcess.StartInfo.RedirectStandardInput = true;
_lameProcess.StartInfo.Arguments = "-r -s 44.1 -h -b 256 --bitwidth 32 - \"" + outputFileName + "\"";
_lameProcess.StartInfo.CreateNoWindow = true;
_lameProcess.Start();
}
private void InitAudioIn(DateTime dtNow)
{
string pathIn = #"C:\Rec\(" + dtNow.ToString("HH-mm-ss") + " " + dtNow.ToString("dd-MM-yyyy") + " IN).wav";
_waveIn = new WaveInEvent();
_waveIn.WaveFormat = new WaveFormat(8000, 1);
_waveIn.DataAvailable += WaveInDataAvailable;
_waveIn.RecordingStopped += WaveInRecordStopped;
_waveInFile = new WaveFileWriter(pathIn, _waveIn.WaveFormat);
_waveIn.StartRecording();
}
private void InitAudioOut(DateTime recordMarker)
{
string pathOut = #"C:\Rec\(" + recordMarker.ToString("HH-mm-ss") + " " + recordMarker.ToString("dd-MM-yyyy") + " OUT).mp3";
_waveOut = new WasapiLoopbackCapture();
//_waveOut.WaveFormat = new WaveFormat(44100, 1);
_waveOut.DataAvailable += WaveOutDataAvailable;
_waveOut.RecordingStopped += WaveOutRecordStopped;
_waveOutFile = new WaveFileWriter(pathOut, new Mp3WaveFormat(_waveOut.WaveFormat.SampleRate, _waveOut.WaveFormat.Channels, 0, 128));
_waveOut.StartRecording();
}
private void WaveInDataAvailable(object sender, WaveInEventArgs e)
{
if (_waveInFile != null)
{
_waveInFile.Write(e.Buffer, 0, e.BytesRecorded);
_waveInFile.Flush();
}
}
private void WaveOutDataAvailable(object sender, WaveInEventArgs e)
{
if (_waveInFile != null)
{
using (var memStream = new MemoryStream(e.Buffer))
{
using (WaveStream wStream = new RawSourceWaveStream(memStream, _waveOut.WaveFormat))
{
var format = new WaveFormat(_waveOut.WaveFormat.SampleRate, _waveOut.WaveFormat.Channels);
var transcodedStream = new ResamplerDmoStream(wStream, format);
var read = (int)transcodedStream.Length;
var bytes = new byte[read];
transcodedStream.Read(bytes, 0, read);
var fmt = new WaveLib.WaveFormat(transcodedStream.WaveFormat.SampleRate, transcodedStream.WaveFormat.BitsPerSample, transcodedStream.WaveFormat.Channels);
var beconf = new Yeti.Lame.BE_CONFIG(fmt, 128);
// Encode WAV to MP3
byte[] mp3Data;
using (var mp3Stream = new MemoryStream())
{
using (var mp3Writer = new Mp3Writer(mp3Stream, fmt, beconf))
{
int blen = transcodedStream.WaveFormat.AverageBytesPerSecond;
mp3Writer.Write(bytes, 0, read);
mp3Data = mp3Stream.ToArray();
}
}
_waveOutFile.Write(mp3Data, 0, mp3Data.Length);
_waveOutFile.Flush();
}
}
}
}
private byte[] WavBytesToMp3Bytes(IWaveProvider waveStream, uint bitrate = 128)
{
// Setup encoder configuration
var fmt = new WaveLib.WaveFormat(waveStream.WaveFormat.SampleRate, waveStream.WaveFormat.BitsPerSample, waveStream.WaveFormat.Channels);
var beconf = new Yeti.Lame.BE_CONFIG(fmt, bitrate);
// Encode WAV to MP3
int blen = waveStream.WaveFormat.AverageBytesPerSecond;
var buffer = new byte[blen];
byte[] mp3Data = null;
using (var mp3Stream = new MemoryStream())
{
using (var mp3Writer = new Mp3Writer(mp3Stream, fmt, beconf))
{
int readCount;
while ((readCount = waveStream.Read(buffer, 0, blen)) > 0)
{
mp3Writer.Write(buffer, 0, readCount);
}
mp3Data = mp3Stream.ToArray();
}
}
return mp3Data;
}
private void WaveInRecordStopped(object sender, StoppedEventArgs e)
{
if (_waveIn != null)
{
_waveIn.Dispose();
_waveIn = null;
}
if (_waveInFile != null)
{
_waveInFile.Dispose();
_waveInFile = null;
}
_lameProcess.StandardInput.BaseStream.Close();
_lameProcess.StandardInput.BaseStream.Dispose();
_lameProcess.Close();
_lameProcess.Dispose();
}
private void WaveOutRecordStopped(object sender, StoppedEventArgs e)
{
if (_waveOutFile != null)
{
_waveOutFile.Close();
_waveOutFile = null;
}
_waveOut = null;
}
public void StopRecording()
{
try
{
_waveIn.StopRecording();
}
catch
{
}
try
{
_waveOut.StopRecording();
}
catch
{
}
}
}
}
I'm using NAudio to capture audio in/out and yetis' lame wrapper to convert it to mp3 file on the fly, the problem is that the resulting audio out file is corrupted and unreadable, probably, missing mp3 headers or something other that i've missed...

The problem is that you're getting batches of data from the loopback capture interface in the default format (ie: PCM), then writing that to a wave file with a format block that claims that the data is in ALAW format. At no point do you actually do a conversion from the PCM data to ALAW data, resulting in a garbage file.
The WaveFileWriter class doesn't do any form of recoding or resampling for you. It uses the format specifier to build a format block for the WAV file, and assumes that you are providing it with data in that format.
Your two options are:
Convert the incoming data from PCM-44100-Stereo (or whatever the default is) to ALAW-8000-Mono before writing to the WaveFileWriter instance.
Initialize _waveOutFile with _waveOut.WaveFormat to match the data formats.
Updated 26-Sep...
So after much messing around, I finally have a working solution to the original problem of correctly converting the wave format from the loopback capture into something that can be compressed.
Here's the code for the first stage of the conversion:
[StructLayout(LayoutKind.Explicit)]
internal struct UnionStruct
{
[FieldOffset(0)]
public byte[] bytes;
[FieldOffset(0)]
public float[] floats;
}
public static byte[] Float32toInt16(byte[] data, int offset, int length)
{
UnionStruct u = new UnionStruct();
int nSamples = length / 4;
if (offset == 0)
u.bytes = data;
else
{
u.bytes = new byte[nSamples * 4];
Buffer.BlockCopy(data, offset, u.bytes, 0, nSamples * 4);
}
byte[] res = new byte[nSamples * 2];
for (i = 0, o = 0; i < nSamples; i++, o+= 2)
{
short val = (short)(u.floats[i] * short.MaxValue);
res[o] = (byte)(val & 0xFF);
res[o + 1] = (byte)((val >> 8) & 0xFF);
}
u.bytes = null;
return res;
}
That will convert the 32-bit floating point samples to 16-bit signed integer samples that can be handled by most audio code. Fortunately, this includes the Yeti MP3 code.
To encode on-the-fly and ensure that the MP3 output is valid, create the Mp3Writer and its output Stream (a FileStream to write directly to disk for instance) at the same time and just keep feeding it data (run through the converter above) as it comes in from the loopback interface. Close the Mp3Writer and the Stream in the waveInStopRecording event handler.
Stream _mp3Output;
Mp3Writer _mp3Writer;
private void InitAudioOut(DateTime recordMarker)
{
string pathOut = string.Format(#"C:\Rec\({0:HH-mm-ss dd-MM-yyyy} OUT).mp3", recordMarker);
_waveOut = new WasapiLoopbackCapture();
_waveOut.DataAvailable += WaveOutDataAvailable;
_waveOut.RecordingStopped += WaveOutRecordStopped;
_mp3Output = File.Create(pathIn);
var fmt = new WaveLib.WaveFormat(_waveOut.WaveFormat.SampleRate, 16, _waveOut.Channels);
var beconf = new Yeti.Lame.BE_CONFIG(fmt, 128);
_mp3Writer = new Mp3Writer(_mp3Stream, fmt, beconf);
_waveOut.StartRecording();
}
private void WaveOutDataAvailable(object sender, WaveInEventArgs e)
{
if (_mp3Writer != null)
{
byte[] data = Float32toInt16(e.Buffer, 0, e.BytesRecorded);
_mp3Writer.Write(data, 0, data.Length);
}
}
private void WaveOutRecordStopped(object sender, StoppedEventArgs e)
{
if (InvokeRequired)
BeginInvoke(new MethodInvoker(WaveOutStop));
else
WaveOutStop();
}
private void WaveOutStop()
{
if (_mp3Writer != null)
{
_mp3Writer.Close();
_mp3Writer.Dispose();
_mp3Writer = null;
}
if (_mp3Stream != null)
{
_mp3Stream.Dispose();
_mp3Stream = null;
}
_waveOut.Dispose();
_waveOut = null;
}
Incidentally, the Mp3Writer class is all you need for this. Throw out the other Lame code you've got there. It will just get in your way.

WasapiLoopbackCapture will likely be capturing audio at 32 bit floating point, 44.1kHz, stereo. WaveFormatConversionStream will not convert that into a-law 8kHz mono in one step. You need to do this conversion in multiple steps.
First get to 16 bit PCM (I tend to do this manually)
Then get to mono (mix or discard one channel - it's up to you) (Again I'd do this manually)
Then resample down to 8kHz (WaveFormatConversionStream can do this)
Then encode to a-law (use a second instance of WaveFormatConversionStream)

Related

Input a command from a Sensor to get data through an IP Address in C#

I have an instrument called Picarro G2401 where I need to see data from it. In order to see the data the Instrument have its own command which is (_Meas_GetConc). When I do it in putty and input the command it shows the data. See the image below.
I don't know where to put this command in order to make it work.
Below find the an image where it says that it is connected but no data is given.
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private PicarroG2401 sensor = new PicarroG2401(new IPAddress(new byte[] {10, 71, 3, 4}));
private void MainForm_Load(object sender, EventArgs e)
{
this.sensor.Connected += Sensor_Connected;
this.sensor.Disconnected += Sensor_Disconnected;
this.sensor.DataReceived += Sensor_DataReceived;
this.sensor.Startup();
}
private void Sensor_DataReceived(object sender, DataReading reading)
{
this.data.AppendText(reading.ToString() + Environment.NewLine);
}
private void Sensor_Disconnected(object sender, TCPSensor sensor)
{
this.data.AppendText("Disconnected" + Environment.NewLine);
}
private void Sensor_Connected(object sender, TCPSensor sensor)
{
this.data.AppendText("Connected" + Environment.NewLine);
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
this.sensor.Shutdown();
}
}
PicarroG2401 - Class
namespace SensorDriverLibrary.Instruments
{
[Serializable]
public class PicarroG2401 : TCPSensor
{
public PicarroG2401(IPAddress ip) : base(ip, 51020)
{
}
public override SensorTypes GetSensorType()
{
return SensorTypes.PicarroG2401;
}
protected override DataReading processData()
{
base.processData();
if (this.tcpClient != null && this.tcpClient.Connected && this.tcpClient.Available > 0)
{
StreamReader reader = new StreamReader(this.tcpClient.GetStream());
string line = reader.ReadLine();
PicarroG2401_DataReading reading = new PicarroG2401_DataReading(line);
this.lastRead = DateTime.Now;
this.OnDataReceived(reading);
return reading;
}
return null;
}
}
}
PicarroG2401_DataReading
namespace SensorDriverLibrary.Instruments
{
[Serializable]
public class PicarroG2401_DataReading : DataReading
{
public PicarroG2401_DataReading() : base()
{ }
public PicarroG2401_DataReading(string data) : base()
{
//409.541;1.940;0.123;1.301
//012345678901234567890123456789
//0 1 2
//CO2 CH4 CO H2O
data = data.Substring(29);
string[] elements = data.Replace("\n\r", "").Split(';');
this.CO2 = float.Parse(elements[0]);
this.CH4 = float.Parse(elements[1]);
this.CO = float.Parse(elements[2]);
this.H2O = float.Parse(elements[3]);
}
public override void ReadFromFile(FileStream file)
{
byte[] bytes = new byte[8];
file.Read(bytes, 0, 8);
this.Timestamp = new DateTime(BitConverter.ToInt64(bytes, 0));
file.Read(bytes, 0, 4);
this.co2 = BitConverter.ToSingle(bytes, 0);
file.Read(bytes, 0, 4);
this.ch4 = BitConverter.ToSingle(bytes, 0);
file.Read(bytes, 0, 4);
this.co = BitConverter.ToSingle(bytes, 0);
file.Read(bytes, 0, 4);
this.h2o = BitConverter.ToSingle(bytes, 0);
}
public override void WriteToFile(FileStream file)
{
byte[] bytes = BitConverter.GetBytes(this.Timestamp.Ticks);
file.Write(bytes, 0, bytes.Length);
bytes = BitConverter.GetBytes(this.co2);
file.Write(bytes, 0, bytes.Length);
bytes = BitConverter.GetBytes(this.ch4);
file.Write(bytes, 0, bytes.Length);
bytes = BitConverter.GetBytes(this.co);
file.Write(bytes, 0, bytes.Length);
bytes = BitConverter.GetBytes(this.h2o);
}
public override string ToString()
{
return base.ToString() +
this.CO2.ToString("0.000") + " " +
this.CH4.ToString("0.000") + " " +
this.CO.ToString("0.000") + " " +
this.H2O.ToString("0.000");
}
public override string GetHTMLTable()
{
string table = "<table>";
table += "<tr><td>CO2</td><td>" + this.CO2.ToString("0.000") + " ppm" + "</td></tr>";
table += "<tr><td>CH4</td><td>" + this.CH4.ToString("0.000") + " ppm" + "</td></tr>";
table += "<tr><td>CO</td><td>" + this.CO.ToString("0.000") + " ppm" + "</td></tr>";
table += "<tr><td>H2O</td><td>" + this.H2O.ToString("0.000") + " %" + "</td></tr>";
table += "</table>";
return table;
}
private float co2 = 0; //ppm
public float CO2
{
get
{
return this.co2;
}
set
{
this.co2 = value;
}
}
private float ch4 = 0; //ppm
public float CH4
{
get
{
return this.ch4;
}
set
{
this.ch4 = value;
}
}
private float co = 0; //ppm
public float CO
{
get
{
return this.co;
}
set
{
this.co = value;
}
}
private float h2o = 0; // %
public float H2O
{
get
{
return this.h2o;
}
set
{
this.h2o = value;
}
}
}
Disclaimer: I don't have enough info to verify this answer, but this is too much for a oomment.
In PicarroG2401.processData(), you'll need to send the command string to the sensor before attempting to read the result. Something like this:
StreamWriter writer = new StreamWriter(this.tcpClient.GetStream());
StreamReader reader = new StreamReader(this.tcpClient.GetStream());
writer.WriteLine("_Meas_GetConc");
writer.Flush();
string line = reader.ReadLine();
I think you will want to remove the condition this.tcpClient.Available > 0, as the sensor will not have sent any data until it receives the command.
Now, this assumes that the line ending chosen by StreamWriter and StreamReader match the line ending required/sent by the sensor. If it doesn't, you may have additional work to do.
I managed to do it work the code below was the issue -
protected override DataReading processData()
{
base.processData();
if (this.tcpClient != null && this.tcpClient.Connected)
{
StreamWriter writer = new StreamWriter(tcpClient.GetStream());
writer.WriteLine("_Meas_GetConc\n\r");
writer.Flush();
StreamReader reader = new StreamReader(tcpClient.GetStream());
string line = reader.ReadLine();
PicarroG2401_DataReading reading = new PicarroG2401_DataReading(line);
lastRead = DateTime.Now;
OnDataReceived(reading);
return reading;
}
return null;
}

circle buffer for serial port in c#

I want to creating circle buffer in c#.
i have Arduino board that sending a lot of data
when discard buffer in serial port command some of data will be lost.
at this situation I need circle buffer for my data to ricived them .
InputData = ComPort.ReadByte();
object firstByte = InputData;
if (ComPort.IsOpen==true)
{
s = Convert.ToString(Convert.ToChar(firstByte));
temp1 += s;
lock (firstByte) {
if (Convert.ToInt32( firstByte)== 13)
{
temp = temp1;
temp1 = "";
LstGetInfo.BeginInvoke(new Action(()=>
{
if (temp !=null)
{
LstGetInfo.Items.Add(temp);
if (LstGetInfo.Items.Count >= 100)
{
LstGetInfo.Items.Clear();
// ComPort.DiscardInBuffer();
//ComPort.DiscardOutBuffer();
}
FileStream fs = new FileStream(filename, FileMode.Append);
var data = System.Text.Encoding.UTF8.GetBytes(String.Format("{0} {1}", temp, DateTime.Now.ToString("hh mm ss")) +"\r\n");
fs.Write(data, 0, data.Length);
fs.Close();
}
}));
LstGetInfo.BeginInvoke(new Action(() =>
{
LstGetInfo.TopIndex = LstGetInfo.Items.Count - 1;
}));
}
}
any solution for this problem ?
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication72
{
class Program
{
static string buffer = "";
static void Main(string[] args)
{
}
static void AddToBuffer(byte[] rxData)
{
buffer += Encoding.UTF8.GetString(rxData);
}
static string ReadLine()
{
int returnIndex = buffer.IndexOf("\n");
if (returnIndex >= 0)
{
string line = buffer.Substring(0, returnIndex);
buffer = buffer.Remove(0, returnIndex + 1);
return line;
}
else
{
return "";
}
}
}
}

stm32f4 discovery sample of using USB to communicate with pc or read/write pendrive using net micro framework

I cannot find any sample of using USB port of STM32F4 Discovery board in .NET Micro Framework. I'm trying to learn how to use USB port to send or write data. Where can I find such examples?
I've tried to make sample application based on https://guruce.com/blogpost/communicating-with-your-microframework-application-over-usb but it doesn't work.
This is part of my code sample:
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Hardware.UsbClient;
using System;
using System.Text;
using System.Threading;
namespace MFConsoleApplication1
{
public class Program
{
private const int WRITE_EP = 1;
private const int READ_EP = 2;
private static bool ConfigureUSBController(UsbController usbController)
{
bool bRet = false;
// Create the device descriptor
Configuration.DeviceDescriptor device = new Configuration.DeviceDescriptor(0xDEAD, 0x0001, 0x0100);
device.bcdUSB = 0x110;
device.bDeviceClass = 0xFF; // Vendor defined class
device.bDeviceSubClass = 0xFF; // Vendor defined subclass
device.bDeviceProtocol = 0;
device.bMaxPacketSize0 = 8; // Maximum packet size of EP0
device.iManufacturer = 1; // String #1 is manufacturer name (see string descriptors below)
device.iProduct = 2; // String #2 is product name
device.iSerialNumber = 3; // String #3 is the serial number
// Create the endpoints
Configuration.Endpoint writeEP = new Configuration.Endpoint(WRITE_EP, Configuration.Endpoint.ATTRIB_Bulk | Configuration.Endpoint.ATTRIB_Write);
writeEP.wMaxPacketSize = 64;
writeEP.bInterval = 0;
Configuration.Endpoint readEP = new Configuration.Endpoint(READ_EP, Configuration.Endpoint.ATTRIB_Bulk | Configuration.Endpoint.ATTRIB_Read);
readEP.wMaxPacketSize = 64;
readEP.bInterval = 0;
Configuration.Endpoint[] usbEndpoints = new Configuration.Endpoint[] { writeEP, readEP };
// Set up the USB interface
Configuration.UsbInterface usbInterface = new Configuration.UsbInterface(0, usbEndpoints);
usbInterface.bInterfaceClass = 0xFF; // Vendor defined class
usbInterface.bInterfaceSubClass = 0xFF; // Vendor defined subclass
usbInterface.bInterfaceProtocol = 0;
// Create array of USB interfaces
Configuration.UsbInterface[] usbInterfaces = new Configuration.UsbInterface[] { usbInterface };
// Create configuration descriptor
Configuration.ConfigurationDescriptor config = new Configuration.ConfigurationDescriptor(500, usbInterfaces);
// Create the string descriptors
Configuration.StringDescriptor manufacturerName = new Configuration.StringDescriptor(1, Consts.MANUFACTURER);
Configuration.StringDescriptor productName = new Configuration.StringDescriptor(2, Consts.PRODUCT_NAME);
Configuration.StringDescriptor serialNumber = new Configuration.StringDescriptor(3, Consts.SERIAL_NO);
Configuration.StringDescriptor displayName = new Configuration.StringDescriptor(4, Consts.DISPLAYED_NAME);
Configuration.StringDescriptor friendlyName = new Configuration.StringDescriptor(5, Consts.FRENDLY_NAME);
// Create the final configuration
Configuration configuration = new Configuration();
configuration.descriptors = new Configuration.Descriptor[]
{
device,
config,
manufacturerName,
productName,
serialNumber,
displayName,
friendlyName
};
try
{
// Set the configuration
usbController.Configuration = configuration;
if (UsbController.ConfigError.ConfigOK != usbController.ConfigurationError)
throw new ArgumentException();
// If all ok, start the USB controller.
bRet = usbController.Start();
}
catch (ArgumentException)
{
Debug.Print(Consts.CONFIG_ERR + usbController.ConfigurationError.ToString());
}
return bRet;
}
private static string GetCommand(byte[] data)
{
return new string(Encoding.UTF8.GetChars(data));
}
private static byte[] GetDataToSend(Reading data, JsonSerializer serializer)
{
return Encoding.UTF8.GetBytes(serializer.Serialize(data));
}
private static void UsbMainLoop(UsbStream usbStream, AnalogInput supplyInput, AnalogInput dataInput, OutputPort recievingDataIndicator, OutputPort seindingDataIndicator, JsonSerializer dataSerializer)
{
byte[] readData = new byte[100];
for (;;)
{
recievingDataIndicator.Write(true);
int bytesRead = usbStream.Read(readData, 0, readData.Length);
recievingDataIndicator.Write(false);
if (bytesRead > 0)
{
string command = GetCommand(readData);
switch (command)
{
case "READ":
seindingDataIndicator.Write(true);
byte[] dataToSend = GetDataToSend(Reading.GetReading(supplyInput, dataInput), dataSerializer);
usbStream.Write(dataToSend, 0, dataToSend.Length);
seindingDataIndicator.Write(false);
break;
}
}
}
}
private static UsbController CheckSupportAndAccessibility(UsbController[] usbControllers, out string message)
{
UsbController usbController = null;
if (0 == usbControllers.Length)
{
message = Consts.USB_NOT_SUPPORTED;
}
else
{
bool foundedFreeUsb = false;
foreach (UsbController controller in usbControllers)
{
if (UsbController.PortState.Stopped == controller.Status)
{
usbController = controller;
foundedFreeUsb = true;
break;
}
}
if (foundedFreeUsb)
{
message = string.Empty;
}
else
{
message = Consts.NO_FREE_USB;
}
}
return usbController;
}
private static void OtherMainProgramLoop()
{
AnalogInput temperature0 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
AnalogInput supply0 = new AnalogInput(Cpu.AnalogChannel.ANALOG_1);
double t0, r0, z0;
while (true)
{
z0 = supply0.Read() * 3;
r0 = Reading.GetRt(z0, temperature0.Read() * z0);
t0 = Reading.GetTemp(r0);
Debug.Print("Supply:" + z0.ToString() + "[V]");
Debug.Print("Rt:" + r0.ToString() + "[Ohm]");
Debug.Print("Temperature:" + t0.ToString() + "[^C]");
Thread.Sleep(1000);
}
}
public static void Main()
{
UsbController[] controllers = UsbController.GetControllers();
string msg;
UsbController usbController = CheckSupportAndAccessibility(controllers, out msg);
if (null == usbController)
{
Debug.Print(msg);
OtherMainProgramLoop();
//return;
}
else
{
UsbStream usbStream = null;
try
{
if (ConfigureUSBController(usbController))
usbStream = usbController.CreateUsbStream(WRITE_EP, READ_EP);
else
throw new Exception();
}
catch (Exception)
{
Debug.Print(Consts.USB_CREATE_STREAM_ERR + usbController.ConfigurationError.ToString());
OtherMainProgramLoop();
//return;
}
AnalogInput temperatureSource = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
AnalogInput supplySource = new AnalogInput(Cpu.AnalogChannel.ANALOG_1);
OutputPort ledGreen = new OutputPort((Cpu.Pin)60, false);
OutputPort ledYellow = new OutputPort((Cpu.Pin)61, false);
UsbMainLoop(usbStream, supplySource, temperatureSource, ledYellow, ledGreen, new JsonSerializer());
usbStream.Close();
}
}
}
}
Thanks for any help.

Dropped zip file causes e.Data.GetData("FileContents") to throw an exception

I'm trying to implement a handler in my WPF application for files dragged from a zip archive. The handler should get the file content for further processing.
My environment: Windows7, 7-zip installed, Visual Studio 2012 Express, .Net 4.5
Here is the code of a simple MainWindow app to demonstrate the problem:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AllowDrop= true;
Drop += onDrop;
}
private void onDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("FileContents"))
{
var fileContents = e.Data.GetData("FileContents");
//get file contents...
}
}
}
When I drag a file contained in a zip archive to my Window the call to e.Data.GetData("FileContents") throws a System.ArgumentException ("Argument out of Range") with the following callstack:
System.Windows.DataObject.OleConverter.GetDataInner(formatetc, medium)
System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(format, aspect, index)
System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(format, aspect, index)
System.Windows.DataObject.OleConverter.GetData(format, autoConvert, aspect, index)
System.Windows.DataObject.OleConverter.GetData(format, autoConvert)
System.Windows.DataObject.GetData(format, autoConvert)
System.Windows.DataObject.GetData(format)
TestZip.MainWindow.onDrop(sender, e) Zeile 34 C#
I've looked up the source code of this OleConverter (http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3#5#1/Dotnetfx_Win7_3#5#1/3#5#1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Core/CSharp/System/Windows/dataobject#cs/1/dataobject#cs) but the GetDataInner() method is implemented like
private void GetDataInner(ref FORMATETC formatetc, out STGMEDIUM medium)
{
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); // BlessedAssert
try
{
_innerData.GetData(ref formatetc, out medium);
}
finally
{
SecurityPermission.RevertAssert();
}
}
So this does also not provide further info of what's wrong here.
I also tried with uninstalled 7-zip and with different zip archives, but no change.
My question: Does any one have a clue what's going wrong here? What do I need to do in order to get the content of a file from a zip-archive dropped onto my window?
Old question but I needed to do this today so....
Using statements:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
Reference PresentationCore
https://msdn.microsoft.com/en-us/library/system.windows.idataobject(v=vs.110).aspx
First you need to get the "FileDescriptor" contents, here's a class which reads them.
/// <summary>
/// Specifies which fields are valid in a FileDescriptor Structure
/// </summary>
[Flags]
enum FileDescriptorFlags : uint
{
ClsId = 0x00000001,
SizePoint = 0x00000002,
Attributes = 0x00000004,
CreateTime = 0x00000008,
AccessTime = 0x00000010,
WritesTime = 0x00000020,
FileSize = 0x00000040,
ProgressUI = 0x00004000,
LinkUI = 0x00008000,
Unicode = 0x80000000,
}
internal static class FileDescriptorReader
{
internal sealed class FileDescriptor
{
public FileDescriptorFlags Flags{get;set;}
public Guid ClassId{get;set;}
public Size Size{get;set;}
public Point Point{get;set;}
public FileAttributes FileAttributes{get;set;}
public DateTime CreationTime{get;set;}
public DateTime LastAccessTime{get;set;}
public DateTime LastWriteTime{get;set;}
public Int64 FileSize{get;set;}
public string FileName{get;set;}
public FileDescriptor(BinaryReader reader)
{
//Flags
Flags = (FileDescriptorFlags)reader.ReadUInt32();
//ClassID
ClassId = new Guid(reader.ReadBytes(16));
//Size
Size = new Size(reader.ReadInt32(), reader.ReadInt32());
//Point
Point = new Point(reader.ReadInt32(), reader.ReadInt32());
//FileAttributes
FileAttributes = (FileAttributes)reader.ReadUInt32();
//CreationTime
CreationTime = new DateTime(1601,1,1).AddTicks(reader.ReadInt64());
//LastAccessTime
LastAccessTime = new DateTime(1601,1,1).AddTicks(reader.ReadInt64());
//LastWriteTime
LastWriteTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64());
//FileSize
FileSize = reader.ReadInt64();
//FileName
byte[] nameBytes = reader.ReadBytes(520);
int i = 0;
while(i < nameBytes.Length)
{
if (nameBytes[i] == 0 && nameBytes[i + 1] == 0)
break;
i++;
i++;
}
FileName = UnicodeEncoding.Unicode.GetString(nameBytes, 0, i);
}
}
public static IEnumerable<FileDescriptor> Read(Stream fileDescriptorStream)
{
BinaryReader reader = new BinaryReader(fileDescriptorStream);
var count = reader.ReadUInt32();
while (count > 0)
{
FileDescriptor descriptor = new FileDescriptor(reader);
yield return descriptor;
count--;
}
}
public static IEnumerable<string> ReadFileNames(Stream fileDescriptorStream)
{
BinaryReader reader = new BinaryReader(fileDescriptorStream);
var count = reader.ReadUInt32();
while(count > 0)
{
FileDescriptor descriptor = new FileDescriptor(reader);
yield return descriptor.FileName;
count--;
}
}
}
Now using that you can get the matching file content for each file:
static class ClipboardHelper
{
internal static MemoryStream GetFileContents(System.Windows.IDataObject dataObject, int index)
{
//cast the default IDataObject to a com IDataObject
IDataObject comDataObject;
comDataObject = (IDataObject)dataObject;
System.Windows.DataFormat Format = System.Windows.DataFormats.GetDataFormat("FileContents");
if (Format == null)
return null;
FORMATETC formatetc = new FORMATETC();
formatetc.cfFormat = (short)Format.Id;
formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
formatetc.lindex = index;
formatetc.tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL;
//create STGMEDIUM to output request results into
STGMEDIUM medium = new STGMEDIUM();
//using the com IDataObject interface get the data using the defined FORMATETC
comDataObject.GetData(ref formatetc, out medium);
switch (medium.tymed)
{
case TYMED.TYMED_ISTREAM: return GetIStream(medium);
default: throw new NotSupportedException();
}
}
private static MemoryStream GetIStream(STGMEDIUM medium)
{
//marshal the returned pointer to a IStream object
IStream iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember);
Marshal.Release(medium.unionmember);
//get the STATSTG of the IStream to determine how many bytes are in it
var iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG();
iStream.Stat(out iStreamStat, 0);
int iStreamSize = (int)iStreamStat.cbSize;
//read the data from the IStream into a managed byte array
byte[] iStreamContent = new byte[iStreamSize];
iStream.Read(iStreamContent, iStreamContent.Length, IntPtr.Zero);
//wrapped the managed byte array into a memory stream
return new MemoryStream(iStreamContent);
}
}
Now you can enumerate the streams in the file contents:
var fileDescriptor = (MemoryStream)Clipboard.GetDataObject().GetData("FileGroupDescriptorW");
var files = FileDescriptorReader.Read(fileDescriptor);
var fileIndex = 0;
foreach (var fileContentFile in files)
{
if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0)
{
//Do something with directories?
//Note that directories do not have FileContents
//And will throw if we try to read them
}
else
{
var fileData = ClipboardHelper.GetFileContents(Clipboard.GetDataObject(), FileIndex);
fileData.Position = 0;
//Do something with the fileContent Stream
}
fileIndex++;
}

In a C# console app, how could I generate a Google Charts API request and save the result as an image?

Is it possible to make a call to the Google Charts API in a console app and save the result as a JPEG or PNG file? I can do it easily in a web app, just not quite sure how to do it in C#.
Many thanks-
https://chart.googleapis.com/chart
You could use the googlechartsharp wrapper for the Charts API to get a URL at which you can view the chart.
Using the HttpWebRequest and HttpWebResponse classes (or the WebClient class as per Joey's answer), you could capture the response stream as a byte array (the image) and write that to a file with the proper extension (a *.png file). Something like:
string chartUrl = chart.GetUrl();
byte[] chartBytes = null;
WebClient client = new WebClient();
chartBytes = client.DownloadData(chartUrl);
using (var memStream = new MemoryStream())
{
memStream.Write(chartBytes, 0, chartBytes.Length);
}
File.WriteAllBytes("C:\temp\myChart.png", chartBytes);
Use the WebClient class and its DownloadData or DownloadFile methods. Constructing the URL to retrieve is up to you.
I added my Chart generator class (working perfectly). Just call it (as seen below) add your own event method to catch the chart once it is generated and save it to the HDD.
Calling the class and generating the chart:
ChartGenerator charBartGen = new ChartGenerator();
charBartGen.ChartCreated += new ChartCreatedEventHandler(charBartGen_ChartCreated);
charBartGen.CreateBarChart(pictureBox2.Height, pictureBox2.Width,
stats.MaxChecks,
"Past 7 days",
stats.Last7DayChecks1, stats.Last7DayChecks2);
The actual class:
public class ChartGenerator
{
public event ChartCreatedEventHandler ChartCreated;
public string CreatePieChartUrl(int pHeight, int pWidth,
string[] pSeries, string pTitle, int[] pData)
{
string st = String.Format(Misc.EnUk,
#"http://chart.apis.google.com/chart?chs={0}x{1}&cht=p3&chd=t:", pWidth, pHeight);
for (int i = 0; i < pData.Length; i++)
{
st += pData[i].ToString(Misc.EnUk) + ",";
}
st = st.TrimEnd(',');
st += "&chdl=";
for (int i = 0; i < pData.Length; i++)
{
st += pSeries[i].Replace(" ", "+") + "|";
}
st = st.TrimEnd('|');
st += "&chtt=";
st += pTitle.Replace(" ", "+") + "|";
return st;
}
public void CreatePieChart(int pHeight, int pWidth,
string[] pSeries, string pTitle, int[] pData)
{
string url = CreatePieChartUrl(pHeight, pWidth,
pSeries, pTitle, pData);
Thread th = new Thread(new ParameterizedThreadStart(CreateChartAsync));
th.Start(url);
}
public string CreateBarChartUrl(int pHeight, int pWidth, int pMax,
string pTitle, int[] pData1, int[] pData2)
{
string st = String.Format(Misc.EnUk,
#"http://chart.apis.google.com/chart?chxr=0,0,{0}&chxt=y&chbh=a&chs={1}x{2}&cht=bvs&chco=4D89F9,C6D9FD&chds=0,{0},0,{0}&chd=t:",
pMax, pWidth, pHeight);
for (int i = 0; i < pData1.Length; i++)
{
st += pData1[i].ToString(Misc.EnUk) + ",";
}
st = st.TrimEnd(',');
st += "|";
for (int i = 0; i < pData2.Length; i++)
{
st += pData2[i].ToString(Misc.EnUk) + ",";
}
st = st.TrimEnd(',');
st += "&chtt=";
st += pTitle.Replace(" ", "+");
return st;
}
public void CreateBarChart(int pHeight, int pWidth,int pMax,
string pTitle, int[] pData1,int[] pData2)
{
string url = CreateBarChartUrl(pHeight, pWidth, pMax,
pTitle, pData1, pData2);
Thread th = new Thread(new ParameterizedThreadStart(CreateChartAsync));
th.Start(url);
}
private void CreateChartAsync(object pUrl)
{
string url = pUrl as string;
try
{
if (url != null)
{
using (Stream stream = GetPageContentStream(url, false))
{
Image img = Image.FromStream(stream);
if (img != null)
{
if (ChartCreated != null)
{
ChartCreated(this, new ChartCreatedEventArgs(img));
}
}
}
}
}
catch (Exception err)
{
Debug.Fail(err.Message);
}
}
/// <summary>
/// Gets the stream of the given url
/// </summary>
/// <param name="url">The url</param>
/// <param name="file">Whether this is a web file stream or a HttpWebRequest</param>
/// <returns></returns>
public static Stream GetPageContentStream(string url, bool file)
{
try
{
WebRequest wreq;
WebResponse wres;
if (file)
{
wreq = System.Net.FileWebRequest.Create(url);
}
else
{
wreq = HttpWebRequest.Create(url);
HttpWebRequest httpwrqst = wreq as HttpWebRequest;
if (httpwrqst != null)
{
httpwrqst.AllowAutoRedirect = false;
httpwrqst.Timeout = 10000;
}
}
wres = wreq.GetResponse();
return wres.GetResponseStream();
}
catch(Exception err)
{
Debug.Fail(err.Message);
Logger.AppLogger.Instance.LogError("GetPageContentStream", err);
return null;
}
}
}
public delegate void ChartCreatedEventHandler(object sender,ChartCreatedEventArgs e);
[Serializable]
public class ChartCreatedEventArgs : EventArgs
{
private readonly Image mImage;
public ChartCreatedEventArgs()
{
}
public ChartCreatedEventArgs(Image pImage)
{
mImage = pImage;
}
public Image Image
{
get
{
return mImage;
}
}
}

Categories

Resources