I have 2 alaw streams that i'm trying to convert to a stereo wav file.
The result sounds bad, I can hear the content but there is an annoying squicking sound that doesn't exist in the original files.
The code I'm doing:
For the wav header:
public static byte[] GetHeader(int fileLength, int bitsPerSample, int numberOfChannels, int sampleRate) // bitsPerSample = 8, numberOfChannels= 1 or 2 (mono or stereo) , sampleRate = 8000
{
MemoryStream memStream = new MemoryStream(WAVE_HEADER_SIZE);
BinaryWriter writer = new BinaryWriter(memStream);
writer.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4); //4 bytes of RIFF description
writer.Write((fileLength - 8) / 2);
writer.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);
writer.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
writer.Write(16); //Chunk size
writer.Write((short)6); //wFormatTag (1 == uncompressed PCM, 6 = A law compression)
writer.Write((short)numberOfChannels); //nChannels
writer.Write(sampleRate); //nSamplesPerSec
int blockAllign = bitsPerSample / 8 * numberOfChannels;
writer.Write(sampleRate * blockAllign); //nAvgBytesPerSec
writer.Write((short)blockAllign); //nBlockAlign
writer.Write((short)bitsPerSample); //wBitsPerSample
writer.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
writer.Write(fileLength / 2 - WAVE_HEADER_SIZE); //data length
writer.Flush();
byte[] buffer = new byte[memStream.Length];
memStream.Position = 0;
memStream.Read(buffer, 0, buffer.Length);
writer.Close();
return buffer;
}
The data (the original streams are read from alaw files):
do
{
if (channels == 2)
{
if (dlRead == 0)
{
dlRead = dlStream.Read (dlBuffer, 0, dlBuffer.Length);
}
if (ulRead == 0)
{
ulRead =ulStream.Read (ulBuffer, 0, ulBuffer.Length);
}
if ((dlRead != 0) && (ulRead != 0))
{
//Create the stero wave buffer
Array.Clear(waveBuffer, 0, waveBuffer.Length);
for (int i = 0; i < dlRead / 2; ++i)
{
waveBuffer[i * 4 + 0] = dlBuffer[i * 2];
waveBuffer[i * 4 + 1] = dlBuffer[i * 2 + 1];
}
for (int i = 0; i < ulRead / 2; ++i)
{
waveBuffer[i * 4 + 2] = ulBuffer[i * 2];
waveBuffer[i * 4 + 3] = ulBuffer[i * 2 + 1];
}
bytesToWrite = Math.Max(ulRead * 2, dlRead * 2);
dlRead = 0;
ulRead = 0;
}
else
bytesToWrite = 0;
}
else
{
//Create the mono wave buffer
if (metadata.ULExists)
{
bytesToWrite = ulStream.Read(ulBuffer, 0, ulBuffer.Length);
Buffer.BlockCopy(ulBuffer, 0, waveBuffer, 0, ulBuffer.Length);
}
else if (metadata.DLExists)
{
bytesToWrite = dlStream.Read(dlBuffer, 0, dlBuffer.Length);
Buffer.BlockCopy(dlBuffer, 0, waveBuffer, 0, dlBuffer.Length);
}
else
{
bytesToWrite = 0;
}
}
if (bytesToWrite > 0)
fileStream.Write(waveBuffer, 0, bytesToWrite);
} while (bytesToWrite > 0);
What am I doing wrong? Any ideas?
Related
I have the following c# code which reads a wave file into a byte array and then writes it into another array, creating a new wave file. I found it online and dont have much knowledge about it.
I want to change the values being written into the new array so that my amplitude is increased by let's say a value 'x' for the new wave file being generated.. Where and what should be the changes made?
private void ReadWavfiles(string fileName)
{
byte[] fa = File.ReadAllBytes(fileName);
int startByte = 0;
// look for data header
for (var x = 0; x < fa.Length; x++)
if (fa[x] == 'd' && fa[x + 1] == 'a' && fa[x + 2] == 't' && fa[x + 3] == 'a')
{
startByte = x + 8;
break;
}
var buff = new byte[fa.Length / 2];
var y = 0;
var length = fa.Length;
for (int s = startByte; s < length; s = s + 2)
buff[y++] = (byte)(fa[s + 1] * 0x100 + fa[s]);
write(buff, "D:\\as1.wav", "D:\\us1.wav");
WaveOut obj = new WaveOut();
obj.Init(new WaveFileReader("D:\\as1.wav"));
obj.Play();
}
private void write(byte[] buffer, string fileOut, string fileIn)
{
WaveFileReader reader = new WaveFileReader(fileIn);
int numChannels = reader.WaveFormat.Channels, sampleRate = reader.WaveFormat.SampleRate;
int BUFFER_SIZE = 1024 * 16;
using (WaveFileWriter writer = new WaveFileWriter(fileOut, new WaveFormat(sampleRate, 16, numChannels)))
{
int bytesRead;
while (true)
{
bytesRead = reader.Read(buffer, 0, BUFFER_SIZE);
if (bytesRead != 0)
writer.Write(buffer, 0, bytesRead);
else break;
}
writer.Close();
}
}
I'm trying to implement a Feistel Cipher, I have the following code:
public static byte[] Encode(byte[] bytes) {
byte[] s = (byte[])bytes.Clone();
int half = s.Length / 2;
if (s.Length % 2 != 0)
throw new Exception("Unbalanced code");
byte[] left = new byte[half];
byte[] right = new byte[half];
Array.Copy(s, left, half);
Array.Copy(s, half, right, 0, half);
for (var k = 0; k < ROUNDS; k++) {
left = XOR(left,f(right));
var temp = left; left = right; right = temp;
}
byte[] toReturn = new byte[s.Length];
Array.Copy(left, 0, toReturn, half, half);
Array.Copy(right, 0, toReturn, 0, half);
return toReturn;
}
In this sample, ROUNDS is 21 and f is a function that rearranges the bytes in an array of bytes.
Unfortunately, while bytes should be equal to Encode(Encode(bytes)), it's not. And I have no idea what I'm doing wrong.
Any advice?
Edit: The code for f()
public static byte[] f(byte[] s) {
byte[] toReturn = (byte[])s.Clone();
byte temp = s[0];
for (var k = 1; k < s.Length; k++) {
s[k-1] = s[k];
s[k - 1] = (byte)(s[k - 1] ^ 45);
}
s[s.Length - 1] = temp;
s[s.Length - 1] = (byte)(s[s.Length - 1] ^ 45);
return toReturn;
}
CodesInChaos is correct, the problem was the variable being mutated.
I'm trying to read from two alaw/pcm files in the following way:
byte[] dlBuffer = null;
if (dlStream != null)
{
dlStream.Position = 0;
dlBuffer = new byte[dlStream.Length+1];
int readDL = dlStream.Read(dlBuffer, 0, dlBuffer.Length);
}
byte[] ulBuffer = null;
if (ulStream != null)
{
ulStream.Position = 0;
ulBuffer = new byte[ulStream.Length+1];
int readUL = ulStream.Read(ulBuffer, 0, ulBuffer.Length);
}
And then to save the buffers to one wav file:
private const int WAVE_HEADER_SIZE = 44;
private const int WAVE_BUFFER_SIZE = 2 * 1024 * 1024; // = 2,097,152
private bool SaveBufferToWave(string wavFileName, VoiceMetadata metadata,byte[] dlBuffer,byte[] ulBuffer)
{
if ((wavFileName == null) || (wavFileName.Length == 0) || (metadata == null))
return false;
FileStream fileStream = null;
bool success = true;
try
{
byte[] waveBuffer = new byte[WAVE_BUFFER_SIZE];
int bytesToWrite = 0;
int dlRead = 0, ulRead = 0;
//If we have DL & UL write stereo wav, else write mono wave
int channels = (metadata.DLExists && metadata.ULExists) ? 2 : 1;
int samples = (int)metadata.TotalTimeMS * (VoiceMetadata.SAMPLES_PER_SECOND / 1000);
fileStream = new FileStream(wavFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
BinaryWriter wrt = new BinaryWriter(fileStream);
wrt.Write(GetHeader(
WAVE_HEADER_SIZE + (samples) * (channels) * sizeof(short), sizeof(short) * 8,
channels,
8000));
if (channels == 2)
{
if (dlRead == 0)
{
dlRead = dlBuffer.Length;
}
if (ulRead == 0)
{
ulRead = ulBuffer.Length;
}
if ((dlRead != 0) && (ulRead != 0))
{
//Create the stero wave buffer
Array.Clear(waveBuffer, 0, waveBuffer.Length);
for (int i = 0; i < dlRead / 2; ++i)
{
waveBuffer[i * 4 + 0] = dlBuffer[i * 2];
waveBuffer[i * 4 + 1] = dlBuffer[i * 2 + 1];
}
for (int i = 0; i < ulRead / 2; ++i)
{
waveBuffer[i * 4 + 2] = ulBuffer[i * 2];
waveBuffer[i * 4 + 3] = ulBuffer[i * 2 + 1];
}
bytesToWrite = Math.Max(ulRead * 2, dlRead * 2);
dlRead = 0;
ulRead = 0;
}
else
bytesToWrite = 0;
}
else
{
//Create the mono wave buffer
if (metadata.ULExists)
{
Buffer.BlockCopy(ulBuffer, 0, waveBuffer, 0, ulBuffer.Length);
bytesToWrite = ulBuffer.Length;
}
else if (metadata.DLExists)
{
Buffer.BlockCopy(dlBuffer, 0, waveBuffer, 0, dlBuffer.Length);
bytesToWrite = dlBuffer.Length;
}
else
{
bytesToWrite = 0;
}
}
if (bytesToWrite > 0)
fileStream.Write(waveBuffer, 0, bytesToWrite);
Logger.Debug("File {0} was saved successfully in wav format.", wavFileName);
}
catch (Exception e)
{
Logger.Error("Failed saving file {0} in wav format, Exception: {1}.", wavFileName, e);
success = false;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
return success;
}
Most of the times it works fine, but sometimes I get one of this two exceptions:
Failed saving file c:\Samples\WAV\24112014-095948.283.wav in wav format, Exception: System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
Failed saving file c:\Samples\WAV\24112014-100742.409.wav in wav format, Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
What can be the problem?
I have the following method which collects PCM data from the IMediaSample into floats for the FFT:
public int PCMDataCB(IntPtr Buffer, int Length, ref TDSStream Stream, out float[] singleChannel)
{
int numSamples = Length / (Stream.Bits / 8);
int samplesPerChannel = numSamples / Stream.Channels;
float[] samples = new float[numSamples];
if (Stream.Bits == 32 && Stream.Float) {
// this seems to work for 32 bit floating point
byte[] buffer32f = new byte[numSamples * 4];
Marshal.Copy(Buffer, buffer32f, 0, numSamples);
for (int j = 0; j < buffer32f.Length; j+=4)
{
samples[j / 4] = System.BitConverter.ToSingle(new byte[] { buffer32f[j + 0], buffer32f[j + 1], buffer32f[j + 2], buffer32f[j + 3]}, 0);
}
}
else if (Stream.Bits == 24)
{
// I need this code
}
// compress result into one mono channel
float[] result = new float[samplesPerChannel];
for (int i = 0; i < numSamples; i += Stream.Channels)
{
float tmp = 0;
for (int j = 0; j < Stream.Channels; j++)
tmp += samples[i + j] / Stream.Channels;
result[i / Stream.Channels] = tmp;
}
// mono output to be used for visualizations
singleChannel = result;
return 0;
}
Seems to work for 32b float, because I get sensible data in the spectrum analyzer (although it seems too shifted(or compressed?) to the lower frequencies).
I also seem to manage to make it work for 8, 16 and 32 non float, but I can only read garbage when the bits are 24.
How can I adapt this to work with 24 bit PCM coming into Buffer?
Buffer comes from an IMediaSample.
Another thing I am wondering is if the method I use to add all channels to one by summing and dividing by the number of channels is ok...
I figured it out:
byte[] buffer24 = new byte[numSamples * 3];
Marshal.Copy(Buffer, buffer24, 0, numSamples * 3);
var window = (float)(255 << 16 | 255 << 8 | 255);
for (int j = 0; j < buffer24.Length; j+=3)
{
samples[j / 3] = (buffer24[j] << 16 | buffer24[j + 1] << 8 | buffer24[j + 2]) / window;
}
Creates a integer from the three bytes and then scales it into the range 1/-1 by dividing with the max value of three bytes.
Have you tried
byte[] buffer24f = new byte[numSamples * 3];
Marshal.Copy(Buffer, buffer24f, 0, numSamples);
for (int j = 0; j < buffer24f.Length; j+=3)
{
samples[j / 3] = System.BitConverter.ToSingle(
new byte[] {
0,
buffer24f[j + 0],
buffer24f[j + 1],
buffer24f[j + 2]
}, 0);
}
I have this class that worked for 8 bpp bitmaps to pcx, but I am having trouble making it work for 1 bpp.
The image starts off like this:
But the resulting PCX is black after line 27, as seen in IrfanView:
Can anyone help me spot the glaring error?
Usage by the way is Pcx.SavePCX("AOut.pcx", new Bitmap("A.bmp"));
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace Imaging
{
public sealed class Pcx
{
private static void WriteWord(Stream stream, int data)
{
stream.WriteByte((byte) (data & 0xFF));
stream.WriteByte((byte) ((data >> 8) & 0xFF));
}
public static void SavePCX(Stream pcxStream, Bitmap bmp)
{
if (bmp.PixelFormat != PixelFormat.Format1bppIndexed)
{
throw new Exception("Can only PCX bitmaps that are 1bpp indexed");
}
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
try
{
{
//header
pcxStream.WriteByte(10); // char manufacturer;
pcxStream.WriteByte(5); //char version;
pcxStream.WriteByte(1); //char encoding;
pcxStream.WriteByte(1); // char bpp;
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char xmin[2];
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char ymin[2];
WriteWord(pcxStream, bmp.Width - 1); // char xmax[2];
WriteWord(pcxStream, bmp.Height - 1); //char ymax[2];
WriteWord(pcxStream, 72); //word(pcx->hdpi, 72);
WriteWord(pcxStream, 72); // word(pcx->vdpi, 72);
for (var i = 0; i < 16*3; i++) //4bpp palette
{
pcxStream.WriteByte(0);
}
pcxStream.WriteByte(0); // pcx->res = 0;
pcxStream.WriteByte(1); // pcx->nplanes = 1;
WriteWord(pcxStream, bmp.Width); // word(pcx->bytesperline, width / 2);
WriteWord(pcxStream, 0); //word(pcx->palletteinfo, 0);
WriteWord(pcxStream, 0); //word(pcx->hscrn, 0);
WriteWord(pcxStream, 0); //word(pcx->vscrn, 0);
for (var i = 0; i < 54; i++) //memset(pcx->filler, 0, 54);
{
pcxStream.WriteByte(0);
}
} //end of header
{
//read all bytes to an array
var baseLine = data.Scan0;
// Declare an array to hold the bytes of the bitmap.
var byteLength = bmp.Width*bmp.Height;
var bytes = new byte[byteLength];
// Copy the RGB values into the array.
for (var y = 0; y < data.Height; y++)
{
var lineOffset = y*data.Stride;
Debug.WriteLine("Y={0}, Offset={1}", y, lineOffset);
for (var x = 0; x < data.Width; x++)
{
bytes[y*bmp.Width + x] = Marshal.ReadByte(baseLine, lineOffset + x);
}
}
var baseIdx = 0;
var end = byteLength;
var run = 0;
var ldata = -1;
byte ld;
while (baseIdx < end)
{
//if it matches, increase the run by 1 up to max of 63
if ((bytes[baseIdx] == ldata) && (run < 63)) run++;
else
{
//write data
if (run != 0) //not first run
{
ld = (byte) ldata;
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
run = 1;
}
ldata = bytes[baseIdx];
baseIdx++;
}
ld = (byte) ((ldata >> 4) | (ldata << 4));
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
}
finally
{
bmp.UnlockBits(data);
}
}
public static void SavePCX(string fileName, Bitmap bbp1Bmp)
{
using (var fstest = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
SavePCX(fstest, bbp1Bmp);
}
}
}
}
Solved it by using data.Stride for the bytes per line, and reading in the bytes from the 1bpp using stride as the width, not width.
public static void SavePCX(Stream pcxStream, Bitmap bmp)
{
if (bmp.PixelFormat != PixelFormat.Format1bppIndexed)
{
throw new Exception("Can only PCX bitmaps that are 1bpp indexed");
}
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
try
{
{
//header
pcxStream.WriteByte(10); // char manufacturer;
pcxStream.WriteByte(5); //char version;
pcxStream.WriteByte(1); //char encoding;
pcxStream.WriteByte(1); // char bpp;
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char xmin[2];
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char ymin[2];
WriteWord(pcxStream, bmp.Width - 1); // char xmax[2];
WriteWord(pcxStream, bmp.Height - 1); //char ymax[2];
WriteWord(pcxStream, 72); //word(pcx->hdpi, 72);
WriteWord(pcxStream, 72); // word(pcx->vdpi, 72);
for (var i = 0; i < 16*3; i++) //4bpp palette
{
pcxStream.WriteByte(0);
}
pcxStream.WriteByte(0); // pcx->res = 0;
pcxStream.WriteByte(1); // pcx->nplanes = 1;
WriteWord(pcxStream, data.Stride); // word(pcx->bytesperline, width / 2);
WriteWord(pcxStream, 0); //word(pcx->palletteinfo, 0);
WriteWord(pcxStream, 0); //word(pcx->hscrn, 0);
WriteWord(pcxStream, 0); //word(pcx->vscrn, 0);
for (var i = 0; i < 54; i++) //memset(pcx->filler, 0, 54);
{
pcxStream.WriteByte(0);
}
} //end of header
{
//read all bytes to an array
var baseLine = data.Scan0;
// Declare an array to hold the bytes of the bitmap.
var byteLength = data.Stride*data.Height;
var bytes = new byte[byteLength];
// Copy the RGB values into the array.
for (var y = 0; y < data.Height; y++)
{
var lineOffset = y*data.Stride;
Debug.WriteLine("Y={0}, Offset={1}", y, lineOffset);
for (var x = 0; x < data.Stride; x++)
{
bytes[y*data.Stride + x] = Marshal.ReadByte(baseLine, lineOffset + x);
}
}
var baseIdx = 0;
var end = byteLength;
var run = 0;
var ldata = -1;
byte ld;
while (baseIdx < end)
{
//if it matches, increase the run by 1 up to max of 63
if ((bytes[baseIdx] == ldata) && (run < 63)) run++;
else
{
//write data
if (run != 0) //not first run
{
ld = (byte) ldata;
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
run = 1;
}
ldata = bytes[baseIdx];
baseIdx++;
}
ld = (byte) ((ldata >> 4) | (ldata << 4));
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
}
finally
{
bmp.UnlockBits(data);
}
}