C++;里夫波读取器慢得令人痛苦 我以前从来没有真正使用二进制文件,我对C++是新手。我想读取一个wav文件并将其数据部分输出到一个txt(用逗号分隔每个样本的值)。我还设法读入了header部分,但是这段代码在这里并不重要,所以我将不包括它

C++;里夫波读取器慢得令人痛苦 我以前从来没有真正使用二进制文件,我对C++是新手。我想读取一个wav文件并将其数据部分输出到一个txt(用逗号分隔每个样本的值)。我还设法读入了header部分,但是这段代码在这里并不重要,所以我将不包括它,c++,audio,wav,binaryfiles,C++,Audio,Wav,Binaryfiles,我的wav文件以32 bps的速度存储IEEE 754标准(浮点数)中的数据。我首先将整个wav文件读入一个字符向量,然后尝试使用它。程序的输出是我所期望的,我可以通过读取txt来播放Python中的声音,而不会出现问题。这个程序的速度非常慢(一个只有几秒钟长的wav文件需要几分钟) 这是wavReader.cpp: #include "stdafx.h" #include "wavFile.h" #include <fstream> #include <iostream>

我的wav文件以32 bps的速度存储IEEE 754标准(浮点数)中的数据。我首先将整个wav文件读入一个字符向量,然后尝试使用它。程序的输出是我所期望的,我可以通过读取txt来播放Python中的声音,而不会出现问题。这个程序的速度非常慢(一个只有几秒钟长的wav文件需要几分钟)

这是
wavReader.cpp

#include "stdafx.h"
#include "wavFile.h"
#include <fstream>
#include <iostream>
#include <vector>

int main()
{
    std::ifstream file("file.wav", std::ios::binary);
    std::vector<char> buffer((
        std::istreambuf_iterator<char>(file)),
        (std::istreambuf_iterator<char>()));
    std::cout << "Loading complete!\n";

    WavFile wavFile = setWavFile(buffer);

    return 0;
}
#include "stdafx.h"
#include "WavFile.h"
#include <fstream>

WavFile setWavFile(std::vector<char> buffer) {

    WavFile wavFile;
    std::vector<char>::iterator it = buffer.begin();

    // Beginning of data chunk is marked with "data"
    it += 4;
    while (*(it - 4) != 'd' ||
        *(it - 3) != 'a' ||
        *(it - 2) != 't' ||
        *(it - 1) != 'a')
        it++;

    wavFile.dataSize = getUint32(buffer, it), it += 4;
    std::ofstream output("data.txt");

    while (it != buffer.end())
    {
        char outputChar[4];
        for (int i = 0; i < 4; (i++, it++))
            outputChar[i] = *it;
        char* outputStr = outputChar;
        char** outputStrPtr = &outputStr;
        float** outputPtr = reinterpret_cast<float**>(outputStrPtr);
        output << **outputPtr << ", ";
        std::cout << static_cast<double>(std::distance(buffer.begin(), it)) * 100 / wavFile.dataSize << "\%\n";
    }

    return wavFile;
}

uint32_t getUint32(std::vector<char> buffer, std::vector<char>::iterator it)
{
    char outputChar[4];
    for (int i = 0; i < 4; (i++, it++))
        outputChar[i] = *it;
    char* outputStr = outputChar;
    char** outputStrPtr = &outputStr;
    uint32_t** outputPtr = reinterpret_cast<uint32_t**>(outputStrPtr);
    return **outputPtr;
}
这是
wavFile.cpp

#include "stdafx.h"
#include "wavFile.h"
#include <fstream>
#include <iostream>
#include <vector>

int main()
{
    std::ifstream file("file.wav", std::ios::binary);
    std::vector<char> buffer((
        std::istreambuf_iterator<char>(file)),
        (std::istreambuf_iterator<char>()));
    std::cout << "Loading complete!\n";

    WavFile wavFile = setWavFile(buffer);

    return 0;
}
#include "stdafx.h"
#include "WavFile.h"
#include <fstream>

WavFile setWavFile(std::vector<char> buffer) {

    WavFile wavFile;
    std::vector<char>::iterator it = buffer.begin();

    // Beginning of data chunk is marked with "data"
    it += 4;
    while (*(it - 4) != 'd' ||
        *(it - 3) != 'a' ||
        *(it - 2) != 't' ||
        *(it - 1) != 'a')
        it++;

    wavFile.dataSize = getUint32(buffer, it), it += 4;
    std::ofstream output("data.txt");

    while (it != buffer.end())
    {
        char outputChar[4];
        for (int i = 0; i < 4; (i++, it++))
            outputChar[i] = *it;
        char* outputStr = outputChar;
        char** outputStrPtr = &outputStr;
        float** outputPtr = reinterpret_cast<float**>(outputStrPtr);
        output << **outputPtr << ", ";
        std::cout << static_cast<double>(std::distance(buffer.begin(), it)) * 100 / wavFile.dataSize << "\%\n";
    }

    return wavFile;
}

uint32_t getUint32(std::vector<char> buffer, std::vector<char>::iterator it)
{
    char outputChar[4];
    for (int i = 0; i < 4; (i++, it++))
        outputChar[i] = *it;
    char* outputStr = outputChar;
    char** outputStrPtr = &outputStr;
    uint32_t** outputPtr = reinterpret_cast<uint32_t**>(outputStrPtr);
    return **outputPtr;
}
#包括“stdafx.h”
#包括“WavFile.h”
#包括
WavFile setWavFile(标准::向量缓冲区){
WavFile;
std::vector::iterator it=buffer.begin();
//数据块的开头标记为“数据”
it+=4;
而(*(it-4)!='d'||
*(it-3)!=“a”||
*(it-2)!=“t”||
*(it-1)!=“a”)
it++;
wavFile.dataSize=getUint32(缓冲区,it),it+=4;
std::流输出(“data.txt”);
while(it!=buffer.end())
{
字符输出字符[4];
对于(int i=0;i<4;(i++,it++)
outputChar[i]=*它;
char*outputStr=outputChar;
字符**outputstrpt=&outputStr;
浮动**outputPtr=重新解释强制转换(outputstrprprtr);

输出您的阅读方式完全错误。Wave文件具有RIFF格式。每个文件由RIFF文件头和一系列块组成

#include <Windows.h> // for DWORD
#include <MMReg.h> // for PCMWAVEFORMATPCMWAVEFORMAT and FORCC

struct t_RiffFileHeader
{
    ::FOURCC m_riff;      // must be 'R', 'I', 'F', 'F'
    ::DWORD  m_file_size; // should be less than or equal to the total file zize
    ::FOURCC m_formtype;  // must be 'W', 'A', 'V', 'E'
};
static_assert(12 == sizeof(t_RiffFileHeader), "");
您先读取块头,然后根据块id读取
m\u chunk\u content\u size
字节的数据:

  • 'f'、'm'、't'、''
    块通常位于第一位,并且应包含描述wav数据的
    PCMWAVEFORMAT
    结构
  • “d”、“a”、“t”、“a”区块包含音频数据
  • 可以跳过其他块

如果您已完成读取最后一个数据块,但尚未到达文件结尾,则很可能附加了另一个RIFF文件。由于32位长度限制,大型文件是通过连接几个较小的RIFF文件来构建的。

可能打印进度会减慢?您打印了很多。可能您只能在百分比的整数值变化如下:

int lastPercent = -1;

loop {
  ...
  float percent = ...;
  int integralPercent = (int)percent;
  if (integralPercent!=lastPercent) {
    lastPercent = integralPercent;
    // print percent here
  }
}

我知道这一点。如问题中所述,我设法读取了标题信息(我还意味着我能够读取fmt块)。这就是我从中得到的信息,我的声音文件有一个通道,32bps,并且在IEEE 754标准中存储数据。我只是没有在这里包含此代码,因为这不是我所担心的。在我的示例代码中,我只是直接跳到数据块并开始读取数据。现在我只想知道为什么程序这么慢。@Keno And这实际上是错误的,因为您不能简单地通过查找
数据开始搜索数据块,因为它可以出现在数据块之前的自定义块中。至于速度问题,您不应该在读取每个样本后写入
std::cout
。每10000个样本或类似的内容编写一次报告。谢谢,程序s栏实际上是问题所在。关于数据块-如何在不查找“数据”的情况下找出它的起始位置?其他块位于fmt块和数据块之间。假设我读取了fmt块中的所有信息,现在我想继续数据块(忽略中间不必要的内容).如果有传统的“数据”,我该怎么做写在fmt块的结尾和数据块的开头之间?@Keno你从块头中一个接一个地读取块的大小。啊,好吧!任何块都以4个字符开头,后跟一个32位的块大小?我只需要读入这两个字符,跳过我不感兴趣的块的大小?哦,这就是embarassing。我添加进度条是因为程序开始时速度很慢,我想知道需要多长时间。现在我意识到,在添加进度条时我仍然使用调试版本,当时我使用了一个更大的wave文件。完全删除进度条并切换到发布版本解决了问题…谢谢!你是e欢迎:)只是一个额外的提示:你的
reinterpret_cast
代码不太好。改用
memcpy
。如果你的向量中有
char*ptr
,那么
float value;memcpy(&value,ptr,4)
做得更好。实际上,为什么不用python阅读呢?将音频值转换为文本,然后再转换为值似乎有些过分。@VTT这不是为了一些实际用途,而是为了理解WAVE文件的文件结构,以及如何在ge中将二进制文件转换为人类可读的文件,我给自己做的一个练习内尔。
int lastPercent = -1;

loop {
  ...
  float percent = ...;
  int integralPercent = (int)percent;
  if (integralPercent!=lastPercent) {
    lastPercent = integralPercent;
    // print percent here
  }
}