如何正确读取C ++一个WAV头?

问题描述 投票:0回答:1

首先,让我说,我一直在读另一个类似的问题,但我不能找到我在他们问题的解决方案。

我使用了“OpenAL的”库通过创建AudioBuffer,然后一对的AudioSource播放WAV文件,但我认为这并不重要。我创建了一个名为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头结构是这样的:enter image description here

我假设的最后2个元素仅仅依靠“的AudioFormat”字段值出现。如果它等于1,这些元素将不会出现。否则,他们可能会或可能不会出现。为了知道这一点,我比较“FmtChunkSize”字段的值:

  • 如果它等于16,那么最后2场是绝对不存在的。
  • 如果大于16,那么我要读“ExtraParamsSize”字段的值,并跳过读取时的字节。

然后,我在寻找的“数据”字符串。当我终于找到了,我看它的大小(在接下来的4个字节),并创建一个大小的缓冲区。从我刚刚创建的OpenAL缓冲区alGenBuffers(1, audiobuffer->buffer);(这是不是在我的问题)。

调试我发现AudioFormat的值是1(所以它不应该有最后两个字段)但FmtChunkSize大于16(所以它应该有最后两个字段...互相矛盾的一种...)所以,我可能认为我的问题是,我没有考虑到的存储方式,但即便如此我don0t知道如何读出的值正确即可。

我加载WAV文件是可以的,因为其他人,我知道已经成功与他们的代码发挥它。

对不起,如果我没有解释自己很好,遗憾的问题大小,但我却认为它可能是有帮助的,你知道我是以下哪个WAV头结构。

任何帮助,将不胜感激,非常感谢你提前。

c++ audio wav
1个回答
0
投票

WAV文件的作用有点不同于你的想法。

你有数据块,每次都必须一起阅读。他们都遵循相同的模式:4个字符,4个字节和可能的附加数据的大小。

第一个块应该是固定的,这就是文件类型,与那么文件的大小(字节-8,所以这是该文件的剩余大小)和文件格式。

然后,有通常的(可能)的块。您有一个类型(4个字符),则块的大小(-8字节)和相关数据。

在你的情况下,第二块似乎是“格式化”。您应该只关心这个数据块大小要知道,如果你有超过16个字节的信息或没有。这就是决定的事情。

然后,你有“数据”块。相同的图案,4个字符,则声音数据的大小和数据本身。

但是,你可以得到其他块,像“bext”,所以你需要阅读所有其他块,不只是“数据”。

正如我已经说过,他们遵循同样的模式。 4个字符,4个字节用于大小,然后附加到该块的一些字节(大小size的)。如果你遵守规则,那么你将能够阅读您的文件。

© www.soinside.com 2019 - 2024. All rights reserved.