Reputation: 1850
I am writing code to read in a wave file.
I am using this document as my guideline.
It specifies that byte 22 of the header is the number of channels of the wave files, and byte 24 of the header is the sample rate.
I am using a test file that was output by Ableton as 2 channel 16 bit 44100hz. I have confirmed that the format of the test wave file is audacity to be sure it is indeed 44100hz samplerate.
When I read in the wave file, I get a sample rate value of -21436. I am quite certain that my code that reads in a little endian integer is correct. And I am certain that my test wavfile is correct. So now I am out of idea's as to why the read samplerate is incorrect....
my int reading code is as follows.
int ReadInt(char* bytes , int start) { return (bytes[start+3] << 24) + (bytes[start+2] << 16) + (bytes[start+1] << 8) + bytes[start]; }
The function that reads the wave file is as follows...
WavFile::WavFile(std::string filename)
{
std::ifstream ifs;
ifs.open( filename, std::ios::binary | std::ios::in );
LogStream(LOG_DEBUG) << "WavFile::WavFile - - - - BEGIN READING WAV - - - -";
if(ifs.fail())
throw std::invalid_argument("WavFile::WavFile : Failed to open wavFile "+filename);
char hbytes[HEADER_SIZE];
ifs.read(hbytes , HEADER_SIZE);
// check that this is actually a wave file
bool valid_riff = hbytes[0]=='R' && hbytes[1]=='I' && hbytes[2]=='F' && hbytes[3]=='F';
bool valid_wave = hbytes[8]=='W' && hbytes[9]=='A' && hbytes[10]=='V' && hbytes[11]=='E';
bool valid_ftm = (hbytes[12]=='f' && hbytes[13]=='m' && hbytes[14]=='t' && hbytes[15]==' ');
bool valid_data = (hbytes[36]=='d' && hbytes[37]=='a' && hbytes[38]=='t' && hbytes[39]=='a');
LogStream(LOG_DEBUG) << "WavFile::WavFile - valid_riff="<<valid_riff<<" valid_wave="<<valid_wave<<" valid_ftm="<<valid_ftm<<" valid_data="<<valid_data;
if(!(valid_data && valid_ftm && valid_riff))
throw std::invalid_argument("WavFile::WavFile : Invalid argument - unable to open wavfile "+filename);
int audioFormat = ReadShort(hbytes , 20);
int SubChunk1Size = ReadInt(hbytes , 16);
if(audioFormat != 1 || SubChunk1Size != 16)
throw std::invalid_argument("WavFile::WavFile : Only uncompressed PCM wave format supported."+filename);
int subChunk2size = ReadInt(hbytes , 40);
m_header.num_channels = ReadShort(hbytes , 22);
m_header.sample_rate = ReadInt(hbytes , 24);
m_header.bits_per_sample = ReadShort(hbytes , 34);
LogStream(LOG_DEBUG) << "WavFile::WavFile num_channels="<<m_header.num_channels << " sample_rate="<<m_header.sample_rate<<" bits_per_sample="<<m_header.bits_per_sample;
m_pcm_data.resize( subChunk2size / sizeof(int16_t) );
LogStream(LOG_DEBUG) << "WavFile::WavFile - subChunk2size = "<<subChunk2size;
LogStream(LOG_DEBUG) << "WavFile::WavFile - m_pcm_data.size() = "<<m_pcm_data.size();
ifs.read((char*)m_pcm_data.data() , subChunk2size);
LogStream(LOG_DEBUG) << "WavFile: ifstream failbit="<<ifs.fail()<<" badbit="<<ifs.bad()<<" goodbit="<<ifs.good();
ifs.close();
LogStream(LOG_DEBUG) << "WavFile::WavFile - - - - END READING WAV - - - -\n";
LogStream(LOG_DEBUG) << "WavFile::WavFile";
}
Upvotes: 0
Views: 833
Reputation: 2323
44100 has hex value 44ac (unsigned int16) and -21436 also has hex value 44ac (signed int16) - the problem is with the way the compiler is implicitly casting each signed char to a signed integer before shifting. You can avoid that either by casting as follows (which outputs 44100):
int main()
{
char bytes[4] = { 0x44, 0xac, 0x00, 0x00 };
printf("%i\n", (((unsigned char)bytes[3]) << 24) | (((unsigned char)bytes[2]) << 16) | (((unsigned char)bytes[1]) << 8) | ((unsigned char)bytes[0]));
return 0;
}
or simply reading as unsigned bytes - this will avoid the same problem for other fields:
int main()
{
unsigned char bytes[4] = { 0x44, 0xac, 0x00, 0x00 };
printf("%i\n", (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]);
return 0;
}
Upvotes: 1