Прежде всего, позвольте мне сказать, что я читал другие подобные вопросы, но я не могу найти решение моей проблемы в них.
Я использую библиотеку «OpenAL» для воспроизведения файлов WAV, создав AudioBuffer, а затем AudioSource, но я думаю, что это не имеет значения.Я создал класс AudioBuffer, который имеет статический метод для получения всей информации, а затем возвращает указатель на объект, созданный внутри него.Что я пытаюсь сделать, это прочитать файл WAV.Для этого я сначала читаю заголовок, чтобы получить значения каждого поля, а затем строю буфер с «размером данных», который я прочитал ранее, и сохраняю в нем все поле данных.Проблема в том, что когда я пытаюсь загрузить WAV-файл, он просто не воспроизводится.Вот функция, которую я использую для загрузки файла WAV и чтения его полей:
typedef struct {
char chunk_id[4];
uint32_t chunk_size;
char format[4];
} wave_header;
typedef struct {
char id[4];
uint32_t size;
} riff_chunk_header;
typedef struct {
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
} wave_fmt_chunk;
AudioBuffer* AudioBuffer::load(const char* filename) {
wave_header w_header;
riff_chunk_header r_c_header;
wave_fmt_chunk w_f_chunk;
short extra_params_size = 0;
bool data = false;
char bloque[1];
int data_size = 0;
AudioBuffer *audiobuffer = new AudioBuffer(1);
std::ifstream in(filename, std::ios::binary);
if (in.is_open()) {
printf("Fichero abierto correctamente.\n");
in.read(w_header.chunk_id, 4);
if (strncmp(w_header.chunk_id, "RIFF", 4) != 0) {
printf("El fichero no es de tipo WAV.\n");
return nullptr;
}
else {
printf("Fichero WAV valido.\n");
}
in.read(reinterpret_cast<char *>(&w_header.chunk_size), 4);
in.read(w_header.format, 4);
in.read(r_c_header.id, 4);
in.read(reinterpret_cast<char *>(&r_c_header.size), 4); //FmtChunkSize
in.read(reinterpret_cast<char *>(&w_f_chunk.audio_format), 2);
in.read(reinterpret_cast<char *>(&w_f_chunk.num_channels), 2);
in.read(reinterpret_cast<char *>(&w_f_chunk.sample_rate), 4);
in.read(reinterpret_cast<char *>(&w_f_chunk.byte_rate), 4);
in.read(reinterpret_cast<char *>(&w_f_chunk.block_align), 2);
in.read(reinterpret_cast<char *>(&w_f_chunk.bits_per_sample), 2);
if (r_c_header.size > 16) {
in.read(reinterpret_cast<char *>(&extra_params_size), 2);
in.ignore(extra_params_size); //Ignoramos los bytes de parámetros adicionales.
}
while (!data) {
in.read(bloque, 1);
if (bloque[0] == 'd') {
in.read(bloque, 1);
if (bloque[0] == 'a') {
in.read(bloque, 1);
if (bloque[0] == 't') {
in.read(bloque, 1);
if (bloque[0] == 'a')
data = true; //Se ha encontrado "data".
}
}
}
}
//Una vez encontrado "data"
in.read(reinterpret_cast<char *>(&data_size), 4); //Leemos el tamaño del bloque data.
char *m_data = new char[data_size]; //Buffer con el tamaño de los datos.
in.read(m_data, data_size); //Rellenamos el buffer con los datos.
//Generamos el buffer de OpenAL.
alGenBuffers(1, audiobuffer->buffer);
if (w_f_chunk.bits_per_sample == 8) {
if (w_f_chunk.num_channels == 1) {
alBufferData(audiobuffer->buffer[0], AL_FORMAT_MONO8, m_data, data_size, w_f_chunk.sample_rate);
}
else {
alBufferData(audiobuffer->buffer[0], AL_FORMAT_STEREO8, m_data, data_size, w_f_chunk.sample_rate);
}
}
else if (w_f_chunk.bits_per_sample == 16) {
if (w_f_chunk.num_channels == 1) {
alBufferData(audiobuffer->buffer[0], AL_FORMAT_MONO16, m_data, data_size, w_f_chunk.sample_rate);
}
else {
alBufferData(audiobuffer->buffer[0], AL_FORMAT_STEREO16, m_data, data_size, w_f_chunk.sample_rate);
}
}
return audiobuffer;
}
else {
printf("El fichero no se pudo abrir. Ruta incorrecta.\n");
return nullptr;
}
}
Извините, если некоторые имена переменных и комментарии написаны на испанском языке, но я думаю, что это легко понять.
- Сначала я открываю файл, полученный функцией по параметру, и печатаю, если она была успешно открыта.
- Затем я ищу строку "RIFF", которая сообщает мне, является ли это действительный файл WAV.
- После этого я читаю значения для каждого поля.
Структура заголовка WAV, которой я следую, такова:
Я предполагаю, что последние 2 элемента появляются только в зависимости от значения поля «AudioFormat».Если он равен 1, эти элементы не появятся.В противном случае они могут появиться или не появиться.Для этого я сравниваю значение поля «FmtChunkSize»:
- Если оно равно 16, то последние 2 поля точно отсутствуют.
- Если этобольше 16, тогда я должен прочитать значение поля «ExtraParamsSize» и пропустить эти байты при чтении.
Затем я ищу строку «data».Когда я наконец нашел его, я читаю его размер (следующие 4 байта) и создаю буфер такого размера.Начиная с alGenBuffers(1, audiobuffer->buffer);
, я просто создаю буферы OpenAL (не в этом моя проблема).
Отладка Я обнаружил, что значение AudioFormat равно 1 (поэтому в нем не должно быть двух последних полей), НОFmtChunkSize больше 16 (поэтому он должен иметь последние два поля ... Вид конфликта ...) Поэтому я могу подумать, что моя проблема в том, что я не принимаю во внимание порядок байтов, но если это так, я не знаюкак правильно читать значения.
WAV-файл, который я загружаю, в порядке, потому что другие знакомые мне люди успешно воспроизвели его со своим кодом.
Извините, если я не объяснил себеочень хорошо, и извините за размер вопроса, но я подумал, что вам может быть полезно узнать, за какой структурой WAV-заголовка я следовал.
Любая помощь будет оценена, большое спасибо заранее.