Audio file reading for FFT - c#

first time asking though i have been visiting for some time.
Here's the problem:
I'm currently trying to isolate the base frequenciy of a signal contained in a WAVE data file with these properties:
PCM Audio Format i.e Liner Quantization
8000 Hz Sample Rate
16 Bits Per Sample
16000 Byte Rate
One Channel only there is no interleaving.
Getting the byte value:
System.IO.FileStream WaveFile = System.IO.File.OpenRead(#"c:\tet\fft.wav");
byte[] data = new byte[WaveFile.Length];
WaveFile.Read(data,0,Convert.ToInt32(WaveFile.Length));
Converting it to an Array of Doubles:
for (int i = 0; i < 32768; i++)//this is only for a relatively small chunk of the file
{
InReal[i] =BitConverter.ToDouble(data, (i + 1) * 8 + 44);
}
and finanly passing it to a Transform Function.
FFT FftObject = new FFT();
FftObject.Transform(InReal, InImg, 0, 32768, out outReal, out outImg, false);
Now the first question, as i understand the PCM values of the wav file should be in the boundaries of
-1 and 1, but when converting to Double i get this values:
2.65855908666825E-235
2.84104982662944E-285
-1.58613492930337E+235
-1.25617351166869E+264
1.58370933499389E-242
6.19284549187335E-245
-2.92969500042228E+254
-5.90042665390976E+226
3.11954507295188E-273
3.06831908609091E-217
NaN
2.77113146323761E-302
6.76597919848376E-306
-1.55843653898344E+291
These are the firs few of the array in those limits is the rest of array too.
My conclusion of this is that i have some sort of code malfunction but i can seem to be able to find it.
Any help would be appreciated.
And the second question, because i'm only providing real data to the FFT algorithm in the response vector should i expect only Real part data too??
Thank you very much.

I was finally able to find out what was going wrong it seems that i didn't accounted for the pulse code modulation of the signal in the data representation, and because i found many unanswered questions here on wave file preparing for Fourier transformation here is the code in a function that prepares the wave file.
public static Double[] prepare(String wavePath, out int SampleRate)
{
Double[] data;
byte[] wave;
byte[] sR= new byte[4];
System.IO.FileStream WaveFile = System.IO.File.OpenRead(wavePath);
wave = new byte[WaveFile.Length];
data = new Double[(wave.Length - 44) / 4];//shifting the headers out of the PCM data;
WaveFile.Read(wave,0,Convert.ToInt32(WaveFile.Length));//read the wave file into the wave variable
/***********Converting and PCM accounting***************/
for (int i = 0; i < data.Length - i * 4; i++)
{
data[i] = (BitConverter.ToInt32(wave, (1 + i) * 4)) / 65536.0;
//65536.0.0=2^n, n=bits per sample;
}
/**************assigning sample rate**********************/
for (int i = 24; i < 28; i++)
{
sR[i-24]= wave[i];
}
SampleRate = BitConverter.ToInt32(sR,0);
return data;
}
all you need to do now is to send the sample rate and the returned result to your FFT algorithm.
The code is not handled so do your own handling as needed.
I has been tested for phone recordings, of busy, ringing and speech, it functions correctly.

Related

Why is the last byte of a WasapiLoopbackCapture sample always 3B,3C,3D,3E,BC,BC or BE

I am writing a program to display audio samples on a time/amplitude graph.
I want to use the real-time audio playing on the computer and am using WasapiLoopbackCapture from the CSCore library, but the data shows on my graph always seems erroneous.
when I try to read the audio stream buffer with a bit depth of 32, the last byte of the array written to debug in
Debug.WriteLine(BitConverter.ToString(_sample));
is always 3B,3C,3D,3E,BC,BC or BE
I also found that reading the buffer as 32 bit (capture.WaveFormat.BitsPerSample returns 32) appears to show completely erroneous amplitudes on the graph whereas manually setting a bit depth
of 16 and reading the byte array with ReadInt16BigEndian appears to represent each sample somewhat accurately.
capture = new WasapiLoopbackCapture();
_bitDepth = capture.WaveFormat.BitsPerSample;
_byteDepth = bitDepth / 8;
Debug.WriteLine(bitDepth);
capture.DataAvailable += (s, a) =>
{
//for loop where i steps through each sample (each sample is multiple bytes)
for(int i = 0; i < a.Buffer.Length; i += _byteDepth)
{
//creates new byte array with 4 bytes / 32 bits
var _sample = new byte[_byteDepth];
//copies 1 sample from the buffer into the _sample byte array
Buffer.BlockCopy(a.Buffer, i, _sample,0,_byteDepth);
Debug.WriteLine(BitConverter.ToString(_sample));
//reads the byte array to an int
var _intSample = BinaryPrimitives.ReadInt32BigEndian(_sample);
currentData.Add(_intSample);
}
};
WASAPI uses 32 bit floating point (float) as a sample format. It's not a 32 bit integer.

How to read file bytes from byte offset?

If I am given a .cmp file and a byte offset 0x598, how can I read a file from this offset?
I can ofcourse read file bytes like this
byte[] fileBytes = File.ReadAllBytes("upgradefile.cmp");
But how can I read it from byte offset 0x598
To explain a bit more, actually from this offset the actual data starts that I have to read and before this byte offset it is just header data, so basically I have to read file from that offset till end.
Try code like this:
using (BinaryReader reader = new BinaryReader(File.Open("upgradefile.cmp", FileMode.Open)))
{
long offset = 0x598;
if (reader.BaseStream.Length > offset)
{
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
byte[]fileBytes = reader.ReadBytes((int) (reader.BaseStream.Length - offset));
}
}
If you are not familiar with Streams, Linq, or whatever, I have simplest solution for you:
Read entire file into memory (I hope you deal with small files):
byte[] fileBytes = File.ReadAllBytes("upgradefile.cmp");
Calculate how many bytes are present in array after given offset:
long startOffset = 0x598; // this is just hexadecimal representation for human, it can be decimal or whatever
long howManyBytesToRead = fileBytes.Length - startOffset;
Then just copy data to new array:
byte[] newArray = new byte[howManyBytesToRead];
long pos = 0;
for (int i = startOffset; i < fileBytes.Length; i++)
{
newArray[pos] = fileBytes[i];
pos = pos + 1;
}
If you understand how it works you can look at Array.Copy method in Microsoft documentation.
By not using ReadAllBytes.
Get a stream, move to potition, read rest of files.
You basically complain that a convenience method made to allow a one line read of a whole file is not what you want - ignoring that it is just that, a convenience method. The normal way to deal with files is opening them and using a Stream.

Quick normalizer for wav files not working as intended

I wrote a quick wave file normalizer in c# using naudio.
Currently it locks the thread and creates 1 KB files. sm is the highest peak of the file
using (WaveFileReader reader = new WaveFileReader(aktuellerPfad))
{
using (WaveFileWriter writer = new WaveFileWriter("temp.wav", reader.WaveFormat))
{
byte[] bytesBuffer = new byte[reader.Length];
int read = reader.Read(bytesBuffer, 0, bytesBuffer.Length);
writer.WriteSample(read *32768/sm);
}
}
You need to do mathematical operation in audio buffer to normalise the signal. The normalising steps would be:
a. Read audio buffer as you are doing. (Although, I would prefer reading in chunks).
byte[] bytesBuffer = new byte[reader.Length];
reader.Read( bytesBuffer, 0, bytesBuffer.Length );
b. Calculate multiplier value. There are different ways to calculate the value. I don't know how you are calculating but it looks the value is 32768/sm. I would denote multiplier as "mul".
c. Now iterate through the buffer and multiply the value with the multiplier.
for ( int i = 0; i < bytesBuffer.Length; i++ )
{
bytesBuffer[i] = bytesBuffer[i] * mul;
}
d. Finally, write samples to file.
writer.WriteSamples( bytesBuffer, 0, bytesBuffer.Length );

Writing multiple wav files from NAudio asioOut

I'm trying to record 3-4 streams of audio and write them to separate wav files. I'm using NAudio's asioOut to capture the audio. At first I was just writing a 3 or 4 channel wav file. So I searched questions here and thought I founded an answer, but I still can't figure it out. Now I can write the separate wav files but they have multiple channels in each file.
channel_1.wav --------> has channel 1 and 2
channel_2.wav --------> has channel 1 and 3
channel_3.wav --------> has channel 2 and 3
I think there is a problem when I try to parse the GetAsInterleavedSamples().
This is my asioOut_AudioAvailable()
void asioOut_AudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
float[] samples = new float[2 * 44100 * GetUserSpecifiedChannelCount()];
samples = e.GetAsInterleavedSamples();
int offset = 0;
while (offset < samples.Length)
{
for (int n = 0; n < this.writers.Length; n++)
{
this.writers[n].WriteSamples(samples, offset, 2);
offset += 2;
}
}
}
I'm new at this so I'm just learning as a go, any help would be greatly appreciated.
Thanks.
If I understand you correctly, you only want to write one sample to each writer, so the third parameter for WriteSamples should be 1, and offset should be incremented by 1. You've probably copied the +=2 from an example that is dealing with 16 bit audio in a byte array.

Convert Hex string to Image

I am using FormsConnect an App for the iPad to export signatures to XML.
The output from the App is as follows:
0x1828023f020000001d1100000018000000e02f01000000000000000000000000a888223f010000005259414ca0a37e00000000000000000000000000000000000000000000000000000000000000000010b9611100000000000000000000000000000000308e660e00000000c021070030a46c0e00000000000000000000000044b0fb3e00beb0000100000001000000107b6111000030420000584200000000000000000000000000000000000080bf00000000000000000100000000000000000000000000000000000000000000001cb0fb3e0100000000000000000000000000000000000000000000000047864aa0860100a086010000c05411000070110047864a0000000000000000010000000000000000000000000000000000000018884d3f801200010900000101000000000000000000020074a54e3fb0b6690ec0b6690e00000000000000000000000044b0fb3e0038a9000100000001000000f0e4c008000030420000304200000000000000000000000000000000000080bf00000000000000000100000000000000000000000000000000000000000000001cb0fb3e0100000000000000000000000000000000000000000000000047864aa0860100a08601000020761100407c110047864a0000000000000000010000000000000000000000000000000000000018884d3f801200010900000101000000000000000000020074a54e3f20b6690e30b6690e000000000000000000000000a888223f010000005259414c808b730c00000000000000000000000000000000000000000000000000000000000000000cc0fb3e0000000000000000000000000400000000000000000000000000000000000000000000000000000000000000a888223f010000005259414ce06ebe0a00000000000000000000000000000000000000000000000000000000000000009ceefb3ea08c61110000000000000000000000000000000000000000000000000000000000000000280001c10400000000000000b017640000000000000000000000000000000000000000000000000000000000000020415846fc3ed08c6111000000000000000000000000000000000000000000000000000000000000003f000000004014630000887a0670c89b0c40146300000000000000000000000000000000000000000000000000100000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e44200000000000000000000000000000000408d6111f08e61110000584200003042000000000000000000000000a888223f010000005259414c4040050d00000000000000000000000000000000000000000000000000000000000000002cd7fb3e108d61110000000000000000a08e6111d033120000000000000000000000000000000000200000c10000000000000000000000000000000000000000a888223f010000005259414c304d050d0000000000000000000000000000000000000000000000000000000000000000ccc8fb3eb08d611100000000d08c611100000000908b6111000000000000000000000000000000000000000000000000000000000150000000000000f08d611101000000000000000000e03f0000204100000000000000000000000000000000108e611104000000000000000000000084854d3f01000000110000000300000002000000e08d61110000000000000000f0c7fb3e908b61112952d53200000000d08d6111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000094c9fb3e0100000000000000608e611100000000000000000000000000000000000000000000000000003442000000000000e83f000000606666d63f808e6111408d6111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000084854d3f0000000001000000030000000100000000000000000000000000000084854d3f01000000110000000300000002000000c08e61110000000000000000408d6111000000000000000000000000d088223fe003fe07020000000800000002000000000000000000000000000000b4effb3e308f6111000000000000000000000000b0906111000000000000000000000000f0496300200000c100000000608f6111000080bf0200000000000000a888223f010000005259414cf04a050d000000000000000000000000000000000000000000000000000000000000000054a0fb3ed08f6111000000000000000000000000d0331200000000000000000000000000f0496300330000c100000000000000000000000020887a06201c630000000000e0a762001032d805000000000000803f0000000000000000010000000000c841000000000416000000000000a888223f010000005259414c9047050d0000000000000000000000000000000000000000000000000000000000000000d088223fc00bfe070100000008000000010000000000000000000000000000003ca9fb3e00000000b7b6363f9796163ffffefe3e0000803f304277060000000084854d3f01000000110000000300000007000000609061110000000000000000c0b96f0e000000000000000000000000a8894d3f800501012412010050596100000000000000000000000000040000009f9e9e3ea9a8a83eb3b2b23e0000803f00c66d0e00000000000000000000000084854d3f01000000110000000300000002000000c06e6d0e00000000000000009ceefb3ee09161110000000000000000000000000000000000000000000000000000000000000000280001c10400000000000000b017640000000000000000000000000000000000000000000000000000000000000020415846fc3e10926111000000000000000000000000000000000000000000000000000000000000003f000000004014630020629b0c10629a0c40146300000000000000000000000000000000000000000000000000100000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4420000000000000000000000000000000080926111309461110000584200003042000000000000000000000000a888223f010000005259414c1043050d00000000000000000000000000000000000000000000000000000000000000002cd7fb3e509261110000000000000000e0936111d033120000000000000000000000000000000000200000c10000000000000000000000000000000000000000a888223f010000005259414c804b050d0000000000000000000000000000000000000000000000000000000000000000ccc8fb3ef0926111000000001092611100000000d09061110000000000000000000000000000000000000000000000000000000001500000000000003093611101000000000000000000e03f00002041000000000000000000000000000000005093611104000000000000000000000084854d3f01000000110000000300000002000000209361110000000000000000f0c7fb3ed09061112952d5320000000010936111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000094c9fb3e0100000000000000a093611100000000000000000000000000000000000000000000000000003442000000000000e83f000000606666d63fc093611180926111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000084854d3f0000000001000000030000000100000000000000000000000000000084854d3f0100000011000000030000000200000000946111000000000000000080926111000000000000000000000000d088223f6007fe07020000000800000002000000000000000000000000000000b4effb3e7094611100000000000000000000000030976111000000000000000000000000f0496300200000c100000000a0946111000080bf0200000000000000a888223f010000005259414c0047050d000000000000000000000000000000000000000000000000000000000000000054a0fb3e10956111000000000000000000000000d0331200000000000000000000000000f0496300330000c100000000000000000000000040629b0c201c630000000000e0a762001032d805000000000000803f0000000000000000010000000000c841000000000416000000000000a888223f010000005259414c8042050d0000000000000000000000000000000000000000000000000000000000000000d088223fc00ffe07010000000800000001000000000000000000000000000000907c6211000000000000000000000000a0946111000000000000000000000000a8894d3f8006010200000000504f6c0e00100000000000000000000000000000000000000000000045f41836397925360000000000000000000000005854554d000000006028000000000000000000000000000000000000d09561110000000000000000d4956111000000000010ea0d0000000000000000000000000000000000000000000000000000000000000000a8894d3f8005010132e100005059610000000000000000000000000004000000e3e2e23ef1f0f03e8180003f0000803fa888223f010000005259414c5045050d0000000000000000000000000000000000000000000000000000000000000000a888223f010000005259414cc044050d000000000000000000000000000000000000000000000000000000000000000054a0fb3e202fc508000000000000000000000000d0331200000000000000000000000000f0496300330000c10000000000000000000000008054990c201c630000000000e0a762001032d805000000000000803f0000000000000000010000000000c841000000000416000000000000a0966111000000000000000000000000087c070000000000000000000000000084854d3f010000001100000003000000020000007095611100000000000000009ceefb3e409661110000000000000000000000000000000000000000000000000000000000000000280001c10400000000000000b017640000000000000000000000000000000000000000000000000000000000000020415846fc3e60986111000000000000000000000000000000000000000000000000000000000000003f0000000040146300402a930c20a5990c40146300000000000000000000000000000000000000000000000000100000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e44200000000000000000000000000000000a0986111509a611100005842000030420000000000000000000000002cd7fb3e709661110000000000000000009a6111d033120000000000000000000000000000000000200000c10000000000000000000000000000000000000000ccc8fb3e10996111000000006098611100000000509761110000000000000000000000000000000000000000000000000000000001500000000000005099611101000000000000000000e03f00002041000000000000000000000000000000007099611104000000000000000000000084854d3f01000000110000000300000002000000409961110000000000000000f0c7fb3e509761112952d5320000000030996111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000094c9fb3e0100000000000000c099611100000000000000000000000000000000000000000000000000003442000000000000e83f000000606666d63fe0996111a0986111000000000000000000000000c08a4d3f8011000101000000000000000000000000000100c8c94e3f0000000084854d3f00000000010000000300000001000000000000000000000000
Now I'm trying to convert this Hex string back into an image using this code:
Bitmap newImage = new Bitmap(new MemoryStream(StringToByteArray(hex)));
public static byte[] StringToByteArray(string hex)
{
hex = hex.Substring(2, hex.Length - 2);
if (hex.Length % 2 != 0)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hex));
}
byte[] HexAsBytes = new byte[hex.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hex.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return HexAsBytes;
}
But I keep getting Parameter is not valid, when attempting to Load the stream into a Bitmap. I posed the question to the developer of the App, and here is his response:
Dear Alex
The data is stored in binary, hex format. Here are the instructions on how to read the binary data and write it back out as a jpg.
byteData[i] = (digit [i * 2] shl 4) + (digit [i * 2 + 1])
The above assumes that the digits are already converted to numbers from 0 to 15. If you’re trying to optimize your script by writing to memory in larger chunks (integers, for instance) you need to take endianness into account. All major CPU architectures are little-endian which means the numbers are stored with their bytes arranged in the opposite order from their actual value (ie, 0x1234 is stored as 0x3412 in memory).
Below are two different scripts for extracting blob data from the form:
1. Python Script:
iterate over each photo attached to image field in FormConnect xml file
data = R[i]
to strip '0x' off front of each blob
a = data[2:]
iterate over each byte, write as binary int to array
for i in range(len(a)/2):
b = (int(bin(int(a[i*2],16)),2)<<4) + int(bin(int(a[i*2+1],16)),2)
data.append(b)
write array to binary file
F = file(outFile,'wb')
data.tofile(F)
F.close()
PHP Script:
$pic = "";
$field = substr($field,2);
header("Content-Type: image/jpeg");
$pic = pack("H*", $field);
echo $pic;
If anyone can help me on this, I would be very grateful.
Kind regards,
Alex
Your problem isn't the hex conversion routine, it's that the original data isn't encoded properly. Based on all the zeroes within it, I'd say it's just a raw bitmap! My guess is that the author of the program that generated that data forgot to encode the bitmap into a specific file format before outputting it.

Categories