Convert memorystream to double-array? - c#

I've got a pcm-stream of raw music data from a wave-file and would like to convert it to a double-array (to apply a fft afterwards).
The result I got now contains very high or low double-numbers (1.0E-200 and 1.0E+300) and I'm not sure whether these can be correct.
This is the code I'm using right now:
WaveStream pcm = WaveFormatConversionStream.CreatePcmStream(mp3);
double[] real = new double[pcm.Length];
byte[] buffer = new byte[8];
int count = 0;
while ((read = pcm.Read(buffer, 0, buffer.Length)) > 0)
{
real[count] = BitConverter.ToDouble(buffer, 0);
count++;
}

Your PCM stream is almost certainly 16 bit. So instead of BitConverter.ToDouble use ToInt16 instead. Then divide by 32768.0 to get into the the range +/- 1.0

I realize that this question is old; however, I thought I might offer this alternative approach to calling BitConverter.ToDouble.
public static double[] ToDoubleArray(this byte[] bytes)
{
Debug.Assert(bytes.Length % sizeof(double) == 0, "byte array must be aligned on the size of a double.");
double[] doubles = new double[bytes.Length / sizeof(double)];
GCHandle pinnedDoubles = GCHandle.Alloc(doubles, GCHandleType.Pinned);
Marshal.Copy(bytes, 0, pinnedDoubles.AddrOfPinnedObject(), bytes.Length);
pinnedDoubles.Free();
return doubles;
}
public static double[] ToDoubleArray(this MemoryStream stream)
{
return stream.ToArray().ToDoubleArray();
}

Related

Get PCM byte array from MediaFoundationResampler, Naudio

I'm working on a method to resample a wav file, here's the method:
internal byte[] ResampleWav(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
byte[] pcmData;
using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
{
RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, new WaveFormat(newFrequency, bits, channels)))
{
// Here should go the code to get the array of bytes with the resampled PCM data
}
}
return pcmData;
}
The problem here is that there isn't any property in the MediaFoundationResampler that returns the size of the buffer. The method should return an array of bytes with the resampled PCM data only.
Thanks in advance!
--Edit
After some time working, I could get this:
internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
byte[] pcmData;
using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
{
RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, newFrequency))
{
//Start reading PCM data
using (MemoryStream wavData = new MemoryStream())
{
byte[] readBuffer = new byte[1024];
while ((conversionStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
{
wavData.Write(readBuffer, 0, readBuffer.Length);
}
pcmData = wavData.ToArray();
}
}
}
return pcmData;
}
"Seems" to work fine, but there's another problem, seems that the PCM data byte array is greater than expected. Here's one of the tests I've tested with the method:
Input settings:
44100Hz
16 Bits
01 Channel
1846324 Bytes of PCM data
Expected (when I resample the same wav file with Audition, Audacity and WaveFormatConversionStream I get this):
22050Hz
16 Bits
01 Channel
923162 Bytes
MediaFoundationResampler result:
22050Hz
16 Bits
01 Channel
923648 Bytes
And the size changes drastically if I change the size of the readBuffer array.
The main problem is that MediaFoundationResampler doesn't have the property Length to know the real size of the resampled PCM data buffer. Using WaveFormatConversionStream the code would be this, but the quality is not very good:
internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
byte[] pcmData;
using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
{
RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
using (WaveFormatConversionStream wavResampler = new WaveFormatConversionStream(new WaveFormat(newFrequency, bits, channels), Original))
{
pcmData = new byte[wavResampler.Length];
wavResampler.Read(pcmData, 0, pcmData.Length);
}
}
return pcmData;
}
What should I do to get the expected PCM data array, using the MediaFoundationResampler?
Disclaimer
I'm not familiar with the NAudio Library, so there might be a more proper way of doing this.
EDIT
Still not a good answer, seems still off by a few bytes...
Some corrections to the code, using Mark Heath (NAudio creator) comment on this answer: https://stackoverflow.com/a/14481756/9658671
I keep the answer here for now, as it might help for finding a real answer, but I'll edit or remove it if necessary.
/EDIT
The difference in length between the file produced by Audition and your code is 923648 - 923162 = 486 bytes, which is less than your 1024 buffer.
It can be explained by the following mechanism:
At the very last call to the Read method, the remaining byte count is inferior to your buffer size. So instead of getting 1024 bytes, you get less.
But your code still adds a full 1024 byte group, instead of a smaller number. That explains the 486 bytes difference and the fact that this number will change if you choose another buffer size.
Fixing this should be easy.
From NAudio documentation:
https://github.com/naudio/NAudio/blob/fb35ce8367f30b8bc5ea84e7d2529e172cf4c381/Docs/WaveProviders.md
The Read method returns the number for bytes that were read. This
should never be more than numBytes and can only be less if the end of
the audio stream is reached. NAudio playback devices will stop playing
when Read returns 0.
So instead of pushing always 1024 bytes at each iteration, just push the number returned by the Read method.
Also, from Mark Heath comment:
the buffer size should be configurable to be an exact multiple of the
block align of the WaveStream
So instead of choosing a "random" buffer size, use a multiple of the block align.
internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency, int BlockAlign)
{
byte[] pcmData;
var BufferSize = BlockAlign * 1024;
using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
{
RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, newFrequency))
{
//Start reading PCM data
using (MemoryStream wavData = new MemoryStream())
{
var ByteCount = 0;
var readBuffer = new byte[BufferSize];
while ((ByteCount = conversionStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
{
wavData.Write(readBuffer, 0, ByteCount);
}
pcmData = wavData.ToArray();
}
}
}
return pcmData;
}

NAudio conversion artifacts

I'm capturing IEEE, 48khz, 32 bit audio and attempting to convert it to PCM, 44.1khz, 16 bit audio. I hear a small pop many times a second in the PCM encoded result.
I've listened to playback of the original audio (the 48khz format.) It doesn't have artifacts, sounds good.
That leaves the resampling. Could someone tell me what I'm doing wrong here?
Here's my conversion code:
byte[] buffer = new byte[1024 * 10];
//wave format is IEEE 48khz, 32 bit
public byte[] Convert(byte[] input, int length, WaveFormat format)
{
if (length == 0)
return new byte[0];
using (var memStream = new MemoryStream(input, 0, length))
{
using (var inputStream = new RawSourceWaveStream(memStream, format))
{
//convert bytes to floats for operations.
WaveToSampleProvider sampleStream = new WaveToSampleProvider(inputStream);
//resample to 44.1khz
var resamplingProvider = new WdlResamplingSampleProvider(sampleStream, 44100);
//convert float stream to PCM 16 bit.
var ieeeToPCM = new SampleToWaveProvider16(resamplingProvider);
return readStream(ieeeToPCM);
}
}
}
private byte[] readStream(IWaveProvider waveStream)
{
using (var stream = new MemoryStream())
{
int read;
while ((read = waveStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, read);
}
return stream.ToArray();
}
}

Converting a two dimensional int array to a byte array

I want to convert a two dimensional int array to a byte array. what is the most simple way to do so? Example:
int[,] array = new int[2, 2] { { 2, 1 }, { 0, 1 } };
How can i convert array to a byte[]? On your answer, please include also the reverse function to that. (if there is a function to convert an int[,] to a byte[] please show me also how to convert a byte[] to an int[,] )
If you're asking yourself why do i need to do it: i need to send a int[,] over a TCP client to a server, then send a response to the client
PS: I thought about making a [Serializeable] class, which will contain the int[,], then serialize the class into a file and send that file, on the server side i will deserialize that file and get the array from there. but i thought that it would take a lot more resrouces to do that then just converting it to a byte[].
Thank you for your help! :)
Short answer: Buffer.BlockCopy.
public static byte[] ToBytes<T>(this T[,] array) where T : struct
{
var buffer = new byte[array.GetLength(0) * array.GetLength(1) * System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))];
Buffer.BlockCopy(array, 0, buffer, 0, buffer.Length);
return buffer;
}
public static void FromBytes<T>(this T[,] array, byte[] buffer) where T : struct
{
var len = Math.Min(array.GetLength(0) * array.GetLength(1) * System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer.Length);
Buffer.BlockCopy(buffer, 0, array, 0, len);
}
If you aren't afraid of using unsafe code it's really simple:
int[,] array = new int[2, 2];
//Do whatever to fill the array
byte[] buffer = new byte[array.GetLength(0) * array.GetLength(1) * sizeof(int)];
fixed (void* pArray = &array[0,0])
{
byte* pData = (byte*)pArray;
for (int buc = 0; buc < buffer.Length; buc++)
buffer[buc] = *(pData + buc);
}

Possible ways to persist a string array to a stream without using serialization?

What are possible ways to save string arrays to a stream without using serialization?
I'm particularly interested in strings since their lengths may vary. I also should be able to restore the array from stream.
And, more importantly, I would like to be able to read only slices of an array without reading full array into memory, because potentially my arrays can be huge.
P.S. I know that there exist databases, that I shouldn't reinvent the wheel, etc, but I have my reasons to opt for hand made solution.
Thank you.
Well, saving data to a stream is serialization; the real trick is: what kind. For example, I assume you're talking about things like XmlSerializer or BinaryFormatter that require you to deserialize the whole thing, but that isn't always necessary.
By writing each string with a length-prefix, you should be able to seek past items you don't want pretty easily. The other option is to write (separately) an index of offsets, but that is sometimes overkill.
As a basic example, s here is "jkl", without it reading the entire stream or deserializing the unwanted strings; note that it could be optimized by (for example) using a variable-length encoding for the int (length), which would also fix the current assumption that endianness is the same between reader and writer:
static void Main()
{
byte[] raw;
using (MemoryStream ms = new MemoryStream())
{
// serialize all
List<string> data = new List<string> {
"abc", "def", "ghi", "jkl", "mno", "pqr" };
foreach (string s in data)
{
byte[] buffer = Encoding.UTF8.GetBytes(s);
byte[] lenBuffer = BitConverter.GetBytes(buffer.Length);
ms.Write(lenBuffer, 0, lenBuffer.Length);
ms.Write(buffer, 0, buffer.Length);
}
raw = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream(raw))
{
int offset = 3, len;
byte[] buffer = new byte[128];
while (offset-- > 0)
{
Read(ms, ref buffer, 4);
len = BitConverter.ToInt32(buffer, 0);
ms.Seek(len, SeekOrigin.Current); // assume seekable, but
// easy to read past if not
}
Read(ms, ref buffer, 4);
len = BitConverter.ToInt32(buffer, 0);
Read(ms, ref buffer, len);
string s = Encoding.UTF8.GetString(buffer, 0, len);
}
}
static void Read(Stream stream, ref byte[] buffer, int count)
{
if (buffer.Length < count) buffer = new byte[count];
int offset = 0;
while (count > 0)
{
int bytes = stream.Read(buffer, offset, count);
if (bytes <= 0) throw new EndOfStreamException();
offset += bytes;
count -= bytes;
}
}

How do I convert a Stream into a byte[] in C#? [duplicate]

This question already has answers here:
Creating a byte array from a stream
(18 answers)
Closed 6 years ago.
Is there a simple way or method to convert a Stream into a byte[] in C#?
The shortest solution I know:
using(var memoryStream = new MemoryStream())
{
sourceStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
Call next function like
byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);
Function:
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;
if(stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if(stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}
I use this extension class:
public static class StreamExtensions
{
public static byte[] ReadAllBytes(this Stream instream)
{
if (instream is MemoryStream)
return ((MemoryStream) instream).ToArray();
using (var memoryStream = new MemoryStream())
{
instream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
Just copy the class to your solution and you can use it on every stream:
byte[] bytes = myStream.ReadAllBytes()
Works great for all my streams and saves a lot of code!
Of course you can modify this method to use some of the other approaches here to improve performance if needed, but I like to keep it simple.
In .NET Framework 4 and later, the Stream class has a built-in CopyTo method that you can use.
For earlier versions of the framework, the handy helper function to have is:
public static void CopyStream(Stream input, Stream output)
{
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0)
output.Write(b, 0, r);
}
Then use one of the above methods to copy to a MemoryStream and call GetBuffer on it:
var file = new FileStream("c:\\foo.txt", FileMode.Open);
var mem = new MemoryStream();
// If using .NET 4 or later:
file.CopyTo(mem);
// Otherwise:
CopyStream(file, mem);
// getting the internal buffer (no additional copying)
byte[] buffer = mem.GetBuffer();
long length = mem.Length; // the actual length of the data
// (the array may be longer)
// if you need the array to be exactly as long as the data
byte[] truncated = mem.ToArray(); // makes another copy
Edit: originally I suggested using Jason's answer for a Stream that supports the Length property. But it had a flaw because it assumed that the Stream would return all its contents in a single Read, which is not necessarily true (not for a Socket, for example.) I don't know if there is an example of a Stream implementation in the BCL that does support Length but might return the data in shorter chunks than you request, but as anyone can inherit Stream this could easily be the case.
It's probably simpler for most cases to use the above general solution, but supposing you did want to read directly into an array that is bigEnough:
byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
offset += r;
That is, repeatedly call Read and move the position you will be storing the data at.
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
byte[] buf; // byte array
Stream stream=Page.Request.InputStream; //initialise new stream
buf = new byte[stream.Length]; //declare arraysize
stream.Read(buf, 0, buf.Length); // read from stream to byte array
Ok, maybe I'm missing something here, but this is the way I do it:
public static Byte[] ToByteArray(this Stream stream) {
Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
Byte[] buffer = new Byte[length];
stream.Read(buffer, 0, length);
return buffer;
}
if you post a file from mobile device or other
byte[] fileData = null;
using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
{
fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
}
Stream s;
int len = (int)s.Length;
byte[] b = new byte[len];
int pos = 0;
while((r = s.Read(b, pos, len - pos)) > 0) {
pos += r;
}
A slightly more complicated solution is necesary is s.Length exceeds Int32.MaxValue. But if you need to read a stream that large into memory, you might want to think about a different approach to your problem.
Edit: If your stream does not support the Length property, modify using Earwicker's workaround.
public static class StreamExtensions {
// Credit to Earwicker
public static void CopyStream(this Stream input, Stream output) {
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0) {
output.Write(b, 0, r);
}
}
}
[...]
Stream s;
MemoryStream ms = new MemoryStream();
s.CopyStream(ms);
byte[] b = ms.GetBuffer();
"bigEnough" array is a bit of a stretch. Sure, buffer needs to be "big ebough" but proper design of an application should include transactions and delimiters. In this configuration each transaction would have a preset length thus your array would anticipate certain number of bytes and insert it into correctly sized buffer. Delimiters would ensure transaction integrity and would be supplied within each transaction. To make your application even better, you could use 2 channels (2 sockets). One would communicate fixed length control message transactions that would include information about size and sequence number of data transaction to be transferred using data channel. Receiver would acknowledge buffer creation and only then data would be sent.
If you have no control over stream sender than you need multidimensional array as a buffer. Component arrays would be small enough to be manageable and big enough to be practical based on your estimate of expected data. Process logic would seek known start delimiters and then ending delimiter in subsequent element arrays. Once ending delimiter is found, new buffer would be created to store relevant data between delimiters and initial buffer would have to be restructured to allow data disposal.
As far as a code to convert stream into byte array is one below.
Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);
Quick and dirty technique:
static byte[] StreamToByteArray(Stream inputStream)
{
if (!inputStream.CanRead)
{
throw new ArgumentException();
}
// This is optional
if (inputStream.CanSeek)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
byte[] output = new byte[inputStream.Length];
int bytesRead = inputStream.Read(output, 0, output.Length);
Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
return output;
}
Test:
static void Main(string[] args)
{
byte[] data;
string path = #"C:\Windows\System32\notepad.exe";
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
{
data = StreamToByteArray(fs);
}
Debug.Assert(data.Length > 0);
Debug.Assert(new FileInfo(path).Length == data.Length);
}
I would ask, why do you want to read a stream into a byte[], if you are wishing to copy the contents of a stream, may I suggest using MemoryStream and writing your input stream into a memory stream.
You could also try just reading in parts at a time and expanding the byte array being returned:
public byte[] StreamToByteArray(string fileName)
{
byte[] total_stream = new byte[0];
using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read))
{
byte[] stream_array = new byte[0];
// Setup whatever read size you want (small here for testing)
byte[] buffer = new byte[32];// * 1024];
int read = 0;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
stream_array = new byte[total_stream.Length + read];
total_stream.CopyTo(stream_array, 0);
Array.Copy(buffer, 0, stream_array, total_stream.Length, read);
total_stream = stream_array;
}
}
return total_stream;
}

Categories