我正在尝试围绕OpenAL实现一些简单的函数包装器。
当尝试逐个加载文件以通过多个缓冲区流式传输文件时,我莫名其妙地读取了eof。
#include <iostream>
#include <type_traits>
#include <cstring>
#include <fstream>
int32_t convert_to_int(char* buffer, std::size_t len, const std::endian endianess)
{
int32_t a = 0;
if(endianess == std::endian::little)
std::memcpy(&a, buffer, len);
else
for(std::size_t i = 0; i < len; ++i)
reinterpret_cast<char*>(&a)[3 - i] = buffer[i];
return a;
}
bool load_wav_file_header(std::ifstream& file, uint8_t& channels, int32_t& sampleRate, uint8_t& bitsPerSample, int32_t& size)
{
char buffer[4];
if(!file.is_open())
return false;
// the RIFF
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read RIFF" << std::endl;
return false;
}
if(std::strncmp(buffer, "RIFF", 4) != 0)
{
std::cerr << "ERROR: file is not a valid WAVE file (header doesn't begin with RIFF)" << std::endl;
return false;
}
// the size of the file
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read size of file" << std::endl;
return false;
}
// the WAVE
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read WAVE" << std::endl;
return false;
}
if(std::strncmp(buffer, "WAVE", 4) != 0)
{
std::cerr << "ERROR: file is not a valid WAVE file (header doesn't contain WAVE)" << std::endl;
return false;
}
// "fmt/0"
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read fmt/0" << std::endl;
return false;
}
// this is always 16, the size of the fmt data chunk
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read the 16" << std::endl;
return false;
}
// PCM should be 1?
if(!file.read(buffer, 2))
{
std::cerr << "ERROR: could not read PCM" << std::endl;
return false;
}
// the number of channels
if(!file.read(buffer, 2))
{
std::cerr << "ERROR: could not read number of channels" << std::endl;
return false;
}
channels = convert_to_int(buffer, 2, std::endian::little);
// sample rate
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read sample rate" << std::endl;
return false;
}
sampleRate = convert_to_int(buffer, 4, std::endian::little);
// (sampleRate * bitsPerSample * channels) / 8
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read (sampleRate * bitsPerSample * channels) / 8" << std::endl;
return false;
}
// ?? dafaq
if(!file.read(buffer, 2))
{
std::cerr << "ERROR: could not read dafaq" << std::endl;
return false;
}
// bitsPerSample
if(!file.read(buffer, 2))
{
std::cerr << "ERROR: could not read bits per sample" << std::endl;
return false;
}
bitsPerSample = convert_to_int(buffer, 2, std::endian::little);
// data chunk header "data"
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read data chunk header" << std::endl;
return false;
}
if(std::strncmp(buffer, "data", 4) != 0)
{
std::cerr << "ERROR: file is not a valid WAVE file (doesn't have 'data' tag)" << std::endl;
return false;
}
// size of data
if(!file.read(buffer, 4))
{
std::cerr << "ERROR: could not read data size" << std::endl;
return false;
}
size = convert_to_int(buffer, 4, std::endian::little);
/* cannot be at the end of file */
if(file.eof())
{
std::cerr << "ERROR: reached EOF on the file" << std::endl;
return false;
}
if(file.fail())
{
std::cerr << "ERROR: fail state set on the file" << std::endl;
return false;
}
return true;
}
const int32_t BUFFER_SIZE = 320000;
const int32_t NUM_BUFFERS = 4;
int main()
{
std::string filename = "Assets/session.wav";
std::ifstream file;
file.open(filename);
if(!file.is_open())
{
std::cerr << "ERROR: could not open file \"" << filename << "\"" << std::endl;
return false;
}
uint8_t channels;
int32_t sampleRate;
uint8_t bitsPerSample;
int32_t size;
if(!load_wav_file_header(file,channels,sampleRate,bitsPerSample,size))
{
std::cerr << "ERROR: could not open wav header of \"" << filename << "\"" << std::endl;
return false;
}
char* data = new char[size];
if(!file.read(data, size))
{
if(file.eof())
std::cerr << "ERROR: reached end of file trying to read "
<< size << " bytes. Actually read " << file.gcount() << std::endl;
else if(file.fail())
std::cerr << "ERROR: fail state" << std::endl;
else if(file.bad())
perror(("error while reading file " + filename).c_str());
return 0;
}
return 0;
}
程序的输出为:
ERROR: reached end of file trying to read 7035488 bytes. Actually read 554
根据cppreference,当您到达eof时,read
会发生这种情况,它基于gcount()
,看起来像我。问题在于该文件的总数为6,871 KB
,否则.WAV文件中报告的大小大于它声称保留在其中的554。