Swap endian in pcm audio - c++

I've made simply program to swap endian in PCM audio (2 channels, 48kHz, 24 bit), but only one channel is swapped correctly, second one is still little Endian (i've checked generated output in CoolEdit 2000). Could anybody give me some guidance what's wrong in my code?
inline int endian_swap(unsigned int x)
{
unsigned char c1, c2, c3, c4;
c1 = x & 255;
c2 = (x >> 8) & 255;
c3 = (x >> 16) & 255;
c4 = (x >> 24) & 255;
return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;
}
int main()
{
FILE *fpIn, *fpOut;
short x;
fpIn = fopen("audio.pcm", "rb");
fpOut = fopen("out.pcm", "wb");
int test = sizeof(short);
int count = 0;
int swaped = 0;
while( fread(&x, sizeof(int), 1, fpIn) == 1 )
{
swaped = endian_swap(x);
fwrite(&swaped, sizeof(int), 1, fpOut);
}
system("pause");
return 0;
}
Best regards!

You are reading in the file one int at a time. But an int is probably either 16-bit or 32-bit. You say you have 24-bit audio.
You should modify your code to read three char at a time, into a char [3] array. You will then too modify your swap_endian function to operate on a char [3] (this is easy; just swap the contents of the first and last elements of the array!)

You declared short x. Try declaring unsigned int x.

Related

Split an integer into bytes and combine back into the integers results into error

Toy program to split an integer into 4 bytes and later combine these bytes to get back the input value results into error. However the program works for positive integers. I am interested in signed integers. Need help.
Expected Output: -12345
Actual Output: -57
int main()
{
int j,i = -12345;
char b[4];
b[0] = (i >> 24) & 0xFF;
b[1] = (i >> 16) & 0xFF;
b[2] = (i >> 8) & 0xFF;
b[3] = (i >> 0) & 0xFF;
j = (int)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0));
std::cout << j;
return 0;
}
There are actually two problems that leads to your "error".
The first is that the result of e.g. b[0] << 24 will be an int. When you cast that to a char (and assuming that char is an 8-bit type) then you cut off the top 24 bits of the value, truncating it.
The second problem is that char could be unsigned (it's implementation-defined if char is signed or unsigned). If char is unsigned then the value -1 (0xffffffff) will become 255 (0x000000ff).
When you then bring all that together it will almost certainly result in wrong values.
In general, whenever you feel the need to do a C-style cast (like in (char)(b[0] << 24)) when programming in C++, you should take that as a sign that you're doing something wrong.
One possible way to solve your problem, always work with explicit unsigned data-types.
First you need to copy the original int value to an unsigned int:
unsigned ui;
memcpy(&ui, &i, sizeof ui);
Then use ui instead of i when doing the "split". And explicitly use unsigned char:
unsigned char b[sizeof(unsigned)] = { 0 };
b[0] = (ui >> 24) & 0xFF;
b[1] = (ui >> 16) & 0xFF;
b[2] = (ui >> 8) & 0xFF;
b[3] = (ui >> 0) & 0xFF;
Then to put it all back, again use an explicit unsigned type, and copy it to the resulting variable:
unsigned uj = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);
memcpy(&j, &uj, sizeof j);
I suggest using unsigned data types here to avoid possible problems that can come from sign-extension during conversion.
Your code works only for possessive numbers! "i" is negative and by shifting it to to right b[0] becomes positive! and finally desensitization results error!
try
int main()
{
int j, i = -12345;
const char* bytes = reinterpret_cast<const char*>(&i);
j = *reinterpret_cast<const int*>(bytes);
std::cout << j;
return 0;
}

C++ - Converting char vector elements to single uint64

I have a vector which holds byte data (chars) received from a socket. This data holds different datatypes i want to extract. E.g. the first 8 elements (8 Bytes) of the vector are an uint64_t. Now I want to convert these first 8 Bytes to a single uint64.
A workaround I've found is:
// recv_buffer is the vector containing the received Bytes
std::vector<uint64_t> frame_number(recv_buffer.begin(), recv_buffer.begin() + sizeof(uint64_t));
uint64_t frame_num = frame.number.at(0);
Is there a way to extract the data without creating a new vector?
This is an effective method:
C/C++:
uint64_t hexToUint64(char *data, int32_t offset){
uint64_t num = 0;
for (int32_t i = offset; i < offset + 8; i++) {
num = (num << 8) + (data[i] & 0xFF);
}
return num;
}
Java:
long hexToUint64(byte[] data, int offset){
return
((long)data[offset++] << 56 & 0xFF00000000000000L) |
((long)data[offset++] << 48 & 0xFF000000000000L) |
((long)data[offset++] << 40 & 0xFF0000000000L) |
((long)data[offset++] << 32 & 0xFF00000000L) |
((long)data[offset++] << 24 & 0xFF000000L) |
((long)data[offset++] << 16 & 0xFF0000L) |
((long)data[offset++] << 8 & 0xFF00L) |
((long)data[offset++] & 0xFFL);
}
JavaScript:
function hexToUint64(data, offset) {
let num = 0;
let multiple = 0x100000000000000;
for (let i = offset; i < offset + 8; i++ , multiple /= 0x100) {
num += (data[i] & 0xFF) * multiple;
}
return num;
}
One normally uses memcpy or similar to a properly aligned structure, and then ntohl to convert a number from network byte order to computer byte order. ntohl is not part of the C++ specification, but exists in Linux and Windows and others regardless.
uint64_t frame_num;
std::copy(recv_buffer.begin(), recv_buffer.begin() + sizeof(uint64_t), static_cast<char*>(&fame_num);
//or memcpy(&frame_num, recv_buffer.data(), sizeof(frame_num));
frame_num = ntohl(ntohl);
It is tempting to do this for a struct that represents an entire network header, but since C++ compilers can inject padding bytes into structs, and it's undefined to write to the padding, it's better to do this one primitive at a time.
You could perform the conversion byte by byte like this:
int main()
{
unsigned char bytesArray[8];
bytesArray[0] = 0x05;
bytesArray[1] = 0x00;
bytesArray[2] = 0x00;
bytesArray[3] = 0x00;
bytesArray[4] = 0x00;
bytesArray[5] = 0x00;
bytesArray[6] = 0x00;
bytesArray[7] = 0x00;
uint64_t intVal = 0;
intVal = (intVal << 8) + bytesArray[7];
intVal = (intVal << 8) + bytesArray[6];
intVal = (intVal << 8) + bytesArray[5];
intVal = (intVal << 8) + bytesArray[4];
intVal = (intVal << 8) + bytesArray[3];
intVal = (intVal << 8) + bytesArray[2];
intVal = (intVal << 8) + bytesArray[1];
intVal = (intVal << 8) + bytesArray[0];
cout<<intVal;
return 0;
}
I suggest doing the following:
uint64_t frame_num = *((uint64_t*)recv_buffer.data());
You should of course first verify that the amount of data you have in recv_buffer is at least sizeof(frame_num) bytes.

C++ write a number on two bytes

I am new to the low level c++, and I find it a bit hard to understand how to manipulate bits. I am trying to do the following to use in a compression algorithm I am trying to make:
unsigned int num = ...;//we want to store this number
unsigned int num_size = 3;//this is the maximum size of the number in bits, and
//can be anything from 1 bit to 32
unsigned int pos = 7;//the starting pos on the 1st bit.
//this can be anything from 1 to 8
char a;
char b;
if the num_size is 3 and pos is 7 for example, we must store num, on the 7th and 8th bit of a and on the 1st bit of b.
How about just?
a = num << (pos-1);
b = ((num << (pos-1)) & 0xFF00) >> 8;
To read num back just
num = ((unsigned int)a + ((unsigned int b) << 8)) >> (pos - 1);
Note, this doesn't do any sanity checks, such as whether all the relevant bits fit in a and b, you'll have to do that yourself.
For this specific test case, the highest number that fits into 2 unsigned char is actually 65535.
#include <iostream>
unsigned char high(int input)
{
return (input >> 8) & 0xFF;
}
unsigned char low(int input)
{
return input & 0xFF;
}
int value(unsigned char low, unsigned char high)
{
return low | (high << 8);
}
int main()
{
int num = 65535;
unsigned char l = low(num);
unsigned char h = high(num);
int val = value(l, h);
std::cout<<"l: "<<l<<" h: "<<h<<" val: "<<val;
}

How to read pixels from MNIST digit database and create the iplimage

sorry this may be somewhat duplication, but i am not able to fix it. i am involved with handwritten OCR application. I use MNIST digit database for training process here. I use following codehere for read pixels from the database and re-create the image. programs doesnt give any error but it gives meaningless image(totally black and unclear pixel patterns) as output. can someone explain the reason for that? plz help
here is my code
int reverseInt(int i) {
unsigned char c1, c2, c3, c4;
c1 = i & 255;
c2 = (i >> 8) & 255;
c3 = (i >> 16) & 255;
c4 = (i >> 24) & 255;
return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;
}
void create_image(CvSize size, int channels, unsigned char* data[28][28], int imagenumber) {
string imgname; ostringstream imgstrm;string fullpath;
imgstrm << imagenumber;
imgname=imgstrm.str();
fullpath="D:\\"+imgname+".jpg";
IplImage *imghead=cvCreateImageHeader(size, IPL_DEPTH_16S, channels);
imghead->imageData=(char *)data;
cvSaveImage(fullpath.c_str(),imghead);
}
int main(){
ifstream file ("D:\\train-images.idx3-ubyte",ios::binary);
if (file.is_open())
{
int magic_number=0; int number_of_images=0;int r; int c;
int n_rows=0; int n_cols=0;CvSize size;unsigned char temp=0;
file.read((char*)&magic_number,sizeof(magic_number));
magic_number= reverseInt(magic_number);
file.read((char*)&number_of_images,sizeof(number_of_images));
number_of_images= reverseInt(number_of_images);
file.read((char*)&n_rows,sizeof(n_rows));
n_rows= reverseInt(n_rows);
file.read((char*)&n_cols,sizeof(n_cols));
n_cols= reverseInt(n_cols);
unsigned char *arr[28][28];
for(int i=0;i<number_of_images;++i)
{
for(r=0;r<n_rows;++r)
{
for(c=0;c<n_cols;++c)
{
file.read((char*)&temp,sizeof(temp));
arr[r][c]= &temp;
}
}
size.height=r;size.width=c;
create_image(size,1, arr, i);
}
}
return 0;
}
You have:
unsigned char temp=0;
...
file.read((char*)&temp,sizeof(temp));
With that you are reading a byte into a single char, and overwriting it with each subsequent byte in the file.
When you do this:
create_image(size,3, &temp, i);
temp is only one character long and just contains the last byte in the file, so your image ends up being just whatever happens to be in memeory after temp.
You need to allocate an array to hold the image data and increment a pointer into it as you fill it with data.
Also you are creating a 3 channel image, but the MNIST data is only single channel, right?
Also,
imghead->imageData=(char *)data;
should be
cvSetData(imghead, data, size.width)
and
unsigned char *arr[28][28];
should be
unsigned char arr[28][28];
I also wanted to use MNIST with OpenCV and this question was the closest i got.
I thought I post a "copy&paste->be happy" version based on cv::Mat instead of iplimage, since this is easier to work with. Also, cv::Mat is preferred since OpenCV 2.x.
This method get you a vector of pairs of cv::Mat images and labels as ints. Have fun.
std::vector<std::pair<cv::Mat,int>> loadBinary(const std::string &datapath, const std::string &labelpath){
std::vector<std::pair<cv::Mat,int>> dataset;
std::ifstream datas(datapath,std::ios::binary);
std::ifstream labels(labelpath,std::ios::binary);
if (!datas.is_open() || !labels.is_open())
throw std::runtime_error("binary files could not be loaded");
int magic_number=0; int number_of_images=0;int r; int c;
int n_rows=0; int n_cols=0; unsigned char temp=0;
// parse data header
datas.read((char*)&magic_number,sizeof(magic_number));
magic_number=reverseInt(magic_number);
datas.read((char*)&number_of_images,sizeof(number_of_images));
number_of_images=reverseInt(number_of_images);
datas.read((char*)&n_rows,sizeof(n_rows));
n_rows=reverseInt(n_rows);
datas.read((char*)&n_cols,sizeof(n_cols));
n_cols=reverseInt(n_cols);
// parse label header - ignore
int dummy;
labels.read((char*)&dummy,sizeof(dummy));
labels.read((char*)&dummy,sizeof(dummy));
for(int i=0;i<number_of_images;++i){
cv::Mat img(n_rows,n_cols,CV_32FC1);
for(r=0;r<n_rows;++r){
for(c=0;c<n_cols;++c){
datas.read((char*)&temp,sizeof(temp));
img.at<float>(r,c) = 1.0-((float)temp)/255.0; // inverse 0.255 values
}
}
labels.read((char*)&temp,sizeof(temp));
dataset.push_back(std::make_pair(img,(int)temp));
}
return dataset;
}
just the same as above:
int reverseInt(int i) {
unsigned char c1, c2, c3, c4;
c1 = i & 255; c2 = (i >> 8) & 255; c3 = (i >> 16) & 255; c4 = (i >> 24) & 255;
return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;
}

Given 2 16-bit ints, can I interleave those bits to form a single 32 bit int?

Whats the proper way about going about this? Lets say I have ABCD and abcd and the output bits should be something like AaBbCcDd.
unsigned int JoinBits(unsigned short a, unsigned short b) { }
#include <stdint.h>
uint32_t JoinBits(uint16_t a, uint16_t b) {
uint32_t result = 0;
for(int8_t ii = 15; ii >= 0; ii--){
result |= (a >> ii) & 1;
result <<= 1;
result |= (b >> ii) & 1;
if(ii != 0){
result <<= 1;
}
}
return result;
}
also tested on ideone here: http://ideone.com/lXTqB.
First, spread your bits:
unsigned int Spread(unsigned short x)
{
unsigned int result=0;
for (unsigned int i=0; i<15; ++i)
result |= ((x>>i)&1)<<(i*2);
return result;
}
Then merge the two with an offset in your function like this:
Spread(a) | (Spread(b)<<1);
If you want true bitwise interleaving, the simplest and elegant way might be this:
unsigned int JoinBits(unsigned short a, unsigned short b)
{
unsigned int r = 0;
for (int i = 0; i < 16; i++)
r |= ((a & (1 << i)) << i) | ((b & (1 << i)) << (i + 1));
return r;
}
Without any math trick to exploit, my first naive solution would be to use a BitSet like data structure to compute the output number bit by bit. This would take looping over lg(a) + lg(b) bits which would give you the complexity.
Quite possible with some bit manipulation, but the exact code depends on the byte order of the platform. Assuming little-endian (which is the most common), you could do:
unsigned int JoinBits(unsigned short x, unsigned short y) {
// x := AB-CD
// y := ab-cd
char bytes[4];
/* Dd */ bytes[0] = ((x & 0x000F) << 4) | (y & 0x000F);
/* Cc */ bytes[1] = (x & 0x00F0) | ((y & 0x00F0) >> 4);
/* Bb */ bytes[2] = ((x & 0x0F00) >> 4) | ((y & 0x0F00) >> 8);
/* Aa */ bytes[3] = ((x & 0xF000) >> 8) | ((y & 0xF000) >> 12);
return *reinterpret_cast<unsigned int *>(bytes);
}
From Sean Anderson's website :
static const unsigned short MortonTable256[256] =
{
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
};
unsigned short x; // Interleave bits of x and y, so that all of the
unsigned short y; // bits of x are in the even positions and y in the odd;
unsigned int z; // z gets the resulting 32-bit Morton Number.
z = MortonTable256[y >> 8] << 17 |
MortonTable256[x >> 8] << 16 |
MortonTable256[y & 0xFF] << 1 |
MortonTable256[x & 0xFF];