11-01-2010 02:09 PM
I am creating a program that reads in a WAV file and will eventually do some Advanced Analysis on it.
I have been successful in copying out 8 and 16 bit info since i can save these directly into a char and short int array respectfully. however, performing 24-bit has posed to be kind of tricky and i am NOT that great of a bit shifter. Can someone please explain which annotation of shifting I need to do to save 3 consecutive bytes ( a 24-bit number) into an integer32 space? Not sure if Wav file format knowledge is needed but here is a link: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Below is the exert from my code. I am unsure about the 24-bit memcpy. And i think i need to do a (data[i])&0x00FF)-127 to the 8 bit portion since its unsigned (but not sure if what I just typed is correct either).
THANKS IN ADVANCE
//ReadWavFile and save data into channel 1/2 array
#include <formatio.h>
#include <ansi_c.h>
#include <lowlvlio.h>
#include "WavFileIO.h"
int Snd_ReadWavFile(char *filePath, void *channel1, void *channel2, int bytesPerChannel)
{
// Information about the Wav file.
int samplesPerChannel;
int bitsPerSample;
int numberOfChannels;
int samplingFrequency;
int checkBytesPerChannel;
header *wavHeader;
int file;
int error;
int i;
unsigned char* data;
int fileSize;
// Get information about the file.
error = Snd_ReadWavFileInfo(filePath, &samplesPerChannel, &bitsPerSample, &numberOfChannels,
&samplingFrequency, &checkBytesPerChannel);
if(error < 0)
return -1; // ReadWavFileInfo error.
// Simple error check
if(checkBytesPerChannel != bytesPerChannel)
return -1; // Error: BytesPerChannel does not match file.
if(!channel1)
return -1; // channel1 is null
if(!channel2 && (numberOfChannels == 2))
return -1; // channel2 is null
// Open file for reading.
file = OpenFile (filePath, VAL_READ_ONLY, VAL_OPEN_AS_IS, VAL_BINARY);
if(file < 0)
{
return -1; // OpenFile error.
}
// Skip the header since we already have the info from it.
/*if(lseek (file, sizeof(header), SEEK_SET))
{
CloseFile(file);
return -1; // Seeking error.
}*/
wavHeader = malloc(sizeof(header));
ReadFile (file, (char *)wavHeader, sizeof(header));
free(wavHeader);
// Read the data
data = malloc((bitsPerSample/8)*samplesPerChannel*numberOfChannels);
if(!data)
{
CloseFile(file);
return -1; // Memory allocation error.
}
GetFileInfo (filePath, &fileSize);
data = malloc(fileSize-sizeof(header));
error = ReadFile (file, data, fileSize-sizeof(header));
//error = ReadFile (file, data, (bitsPerSample/8)*samplesPerChannel*numberOfChannels);
if(error < 0)
{
free(data);
CloseFile(file);
return -1; // ReadFile error.
}
// Process the data
// We have to treat data differently depending on how many bits per sample it has.
switch(bitsPerSample)
{
// 8 bit data.
case 8:
for(i = 0; i < samplesPerChannel; i++)
{
memcpy((void*)((char*)channel1+i), &data[i*numberOfChannels], 1);
if(numberOfChannels == 2)
{
memcpy((void*)((char*)channel2+i), &data[i*numberOfChannels+1], 1);
}
}
break;
// 16 bit data.
case 16:
for(i = 0;i < samplesPerChannel; i++)
{
memcpy((void*)((char*)channel1+i*2), &data[i*2*numberOfChannels], 2);
if(numberOfChannels == 2)
{
memcpy((void*)((char*)channel2+i*2), &data[i*2*numberOfChannels+2], 2);
}
}
break;
// 24 bit data.
case 24: //Must be saved into an integer size
for(i = 0;i < samplesPerChannel; i++)
{
memcpy((void*)((char*)channel1+i*4), &data[i*3*numberOfChannels], 3); //every 4 bytes so it in integer format
if(numberOfChannels == 2)
{
memcpy((void*)((char*)channel2+i*4), &data[i*3*numberOfChannels+3], 3);
}
}
break;
// Unsupported number of data bits.
default:
free(data);
CloseFile(file);
return -1; // Unsupported number of data bits.
break;
}
free(data);
error = CloseFile(file);
if(error < 0)
return -1; // Error while closing file.
return 0;
}
11-01-2010 04:49 PM - edited 11-01-2010 04:49 PM
Hi ngay,
you may find something similar to what you want in my Color-to-grayscale conversion example program: specifically ConvertFile () and ConvertBMP () functions handle 24-bit bitmaps casting image data into an array of integers. You may take them as a starting point to develop your own converting function.
11-05-2010 03:06 AM - edited 11-05-2010 03:13 AM
Hi,
i recomend to not use memcpy for copying 1..3 bytes there is too much overhead in function call.
i am not sure about waw but according to:
this can be somethink like(not tested)
24bit to 32bit:chanel1:((char*)channel1+i*4 +0)=data[0+i*4*numberOfChannels +0];
((char*)channel1+i*4 +1)=data[0+i*4*numberOfChannels +1];
((char*)channel1+i*4 +2)=data[0+i*4*numberOfChannels +2];((char*)channel1+i*4 +3)=data[0+i*4*numberOfChannels +3];//copy last byte form 24bit to 32bit
chanel2:((char*)channel2+i*4 +0)=data[4+i*4*numberOfChannels +0];
((char*)channel2+i*4 +1)=data[4+i*4*numberOfChannels +1];
((char*)channel2+i*4 +2)=data[4+i*4*numberOfChannels +2];
((char*)channel2+i*4 +3)=data[4+i*4*numberOfChannels +3];//copy last byte form 24bit to 32bit
copying last byte form 24bit to 32bit is for getting good min/max value
for example:
0x000000 ->0x00000000 //minimal value is minimal value
0xFFFFFF->0xFFFFFFFF //max value is max value
0x7F7F7F ->0x7F7F7F7F //Half value is max value
it is only optimization you ca set last byte to zero, if you like, or you can invent your own optimiyzation algorithm
also for example..
8bit:
chanel1:((char*)channel1+i)=data[0+i*numberOfChannels];
chanel2:((char*)channel2+i)=data[1+i*numberOfChannels+1];
16bit:
chanel1:((char*)channel1+i*2 +0)=data[0+i*2*numberOfChannels +0];
((char*)channel1+i*2 +1)=data[0+i*2*numberOfChannels +1];
chanel2:((char*)channel2+i*2 +0)=data[2+i*2*numberOfChannels +0];
((char*)channel2+i*2 +1)=data[2+i*2*numberOfChannels +1];
11-05-2010 03:22 AM
ia am sorry, in previous post i switch byte order for copy least signifcant byte in 24bit
there is corected version:
i recomend to not use memcpy for copying 1..3 bytes there is too much overhead in function call.
i am not sure about waw but according to:
this can be somethink like(not tested)
24bit to 32bit:chanel1:((char*)channel1+i*4 +0)=data[0+i*4*numberOfChannels +0];//copy
((char*)channel1+i*4 +1)=data[0+i*4*numberOfChannels +0];
((char*)channel1+i*4 +2)=data[0+i*4*numberOfChannels +1];((char*)channel1+i*4 +3)=data[0+i*4*numberOfChannels +2];
chanel2:((char*)channel2+i*4 +0)=data[4+i*4*numberOfChannels +0];//copy
((char*)channel2+i*4 +1)=data[4+i*4*numberOfChannels +0];
((char*)channel2+i*4 +2)=data[4+i*4*numberOfChannels +1];
((char*)channel2+i*4 +3)=data[4+i*4*numberOfChannels +2];
copying last byte form 24bit to 32bit is for getting good min/max value
for example:
0x000000 ->0x00000000 //minimal value is minimal value
0xFFFFFF->0xFFFFFFFF //max value is max value
0x7F7F7F ->0x7F7F7F7F //Half value is max value
it is only optimization you ca set last byte to zero, if you like, or you can invent your own optimiyzation algorithm
also for example..
8bit:
chanel1:((char*)channel1+i)=data[0+i*numberOfChannels];
chanel2:((char*)channel2+i)=data[1+i*numberOfChannels+1];
16bit:
chanel1:((char*)channel1+i*2 +0)=data[0+i*2*numberOfChannels +0];
((char*)channel1+i*2 +1)=data[0+i*2*numberOfChannels +1];
chanel2:((char*)channel2+i*2 +0)=data[2+i*2*numberOfChannels +0];
((char*)channel2+i*2 +1)=data[2+i*2*numberOfChannels +1];
11-09-2010 10:12 AM
I have yet to test it, but I made soem corrections below:
//memcpy((void*)((char*)channel1+i*4), &data[i*3*numberOfChannels], 3);
((char*)channel1+i*4+0)=data[i*3*numberOfChannels+0];//copy
((char*)channel1+i*4+1)=data[i*3*numberOfChannels+0];
((char*)channel1+i*4+2)=data[i*3*numberOfChannels+1];
((char*)channel1+i*4+3)=data[i*3*numberOfChannels+2];
if(numberOfChannels == 2)
{
//memcpy((void*)((char*)channel2+i*4), &data[i*3*numberOfChannels+3], 3);
((char*)channel2+i*4 +0)=data[3+i*3*numberOfChannels +0];//copy
((char*)channel2+i*4 +1)=data[3+i*3*numberOfChannels +0];
((char*)channel2+i*4 +2)=data[3+i*3*numberOfChannels +1];
((char*)channel2+i*4 +3)=data[3+i*3*numberOfChannels +2];
}
11-10-2010 01:05 AM
sorry, you has right. I made it from scratch, but you got the point. ![]()