【问题标题】:Processing large files with libsndfile使用 libsndfile 处理大文件
【发布时间】:2013-10-23 01:31:52
【问题描述】:

目前,我已经基于“libsndfile”的可用示例代码编写了一个程序(在 Visual Studio C++ 中),其中我刚刚添加了一个减法函数来用另一个减去一个(一个通道的)WAV 文件.

该程序非常适合具有 4 个通道限制的文件。

问题是,一旦我上传了多达 5 个或更多频道的文件,程序就会拒绝执行该功能。这与帧大小无关,因为我设法处理了比我使用的某些 5/6 通道文件大很多倍的 4 通道文件。

以前有没有人遇到过这个或类似的问题?如果需要,我会提供源代码。

对于糟糕的结构,我深表歉意,在我完成整个交易之前,我不会真正优化。

代码:

#include <sndfile.hh>
#include <tinyxml2.h>
#include <iostream>
#include <fstream>

#define BLOCK_SIZE 32

using TiXmlDocument = tinyxml2::XMLDocument;
using CStdStringA = std::string;

int main(int argc, char* argv[])

{
    SNDFILE *infile  = NULL;
    SNDFILE *infile2 = NULL;
    SNDFILE *outfile = NULL;
    SF_INFO    sfinfo;
    SF_INFO    sfinfo2;
    SF_INFO    sfinfoOut;
    sf_count_t readcount;
    //int filetype = SF_FORMAT_WAV | SF_FORMAT_PCM_24;                  // 24-bit Wav-Files
    TiXmlDocument iDoc;                                               // Init tinyXML
    int i;                                                            // Iteration-var;
    short BufferIn[BLOCK_SIZE];                                       // Buffer1
    short BufferIn2[BLOCK_SIZE];                                      // Buffer2
    short BufferOut[BLOCK_SIZE];
    CStdStringA FileLoc, FileName, FileLocWav, FileLocTxt,FileLocRaw; // OutputFile locationstring
    CStdStringA WavName, WavName2, FileIn, FileIn2;
    FileLoc = "C:\\Testfiles\\";
    //TextTitle(FileLoc);                                             // Print console-header
    printf("Name Wavefile 1:\n");
    std::cin >> WavName;
    FileIn = FileLoc + WavName + ".wav";
    if((infile = sf_open(FileIn.c_str(),SFM_READ,&sfinfo)) == NULL)   // Open Wav-file 2 instance
    {
        printf("Not able to open input file 1\n");
        printf("\n\nPress any key to exit.");                         // Exit-text if file not present
        puts(sf_strerror(NULL)) ;
        return 1;
    }
    std::cout << "Wav file 1 succesfully opened." <<  std::endl;
    std::cout << "\nChannels: " << sfinfo.channels << "\nFrames: " << sfinfo.frames << std::endl; // Print Channels & Frames
    std::cout << "Samplerate: " << sfinfo.samplerate << "\n\n" <<  std::endl;// Print Samplerate
    printf("Name Wavefile 2:\n");
    std::cin >> WavName2;
    FileIn2 = FileLoc + WavName2 + ".wav";
    if((infile2 = sf_open(FileIn2.c_str(),SFM_READ,&sfinfo2)) == NULL) // Open Wav-file 2 instance
    {
        printf("Not able to open input file 2\n");
        printf("\n\nPress any key to exit.");                          // Exit-text if file not present
        puts(sf_strerror(NULL)) ;
        return 1;
    }
    std::cout << "Wav file 2 succesfully opened." <<  std::endl;
    std::cout << "\nChannels: " << sfinfo2.channels << "\nFrames: " << sfinfo2.frames  << std::endl; // Print Channels & Frames
    std::cout << "Samplerate: " << sfinfo2.samplerate << "\n\n" <<  std::endl;// Print Samplerate
//{
    //std::cout << "Format differs from eachother, abort program.";
    //printf("\n\nPress any key to exit.");                     // Exit-text
    //return 1;
//}
    if(sfinfo.channels != sfinfo2.channels)                                // Abort if channels not the same
    {
        std::cout << "Channelammount differs from eachother, abort program.";
        printf("\n\nPress any key to exit.");                     // Exit-text
        return 1;
    }
    if(sfinfo.samplerate != sfinfo2.samplerate)                   // Abort if samplerate not the same
    {
        std::cout << "Samplerate differs from eachother, abort program.";
        printf("\n\nPress any key to exit.");                     // Exit-text
        return 1;
    }
    std::cout << "Give a filename for Txt- & Wav-file: ";
    std::cin >> FileName;
    FileLoc += FileName;                                          // Fuse Filelocation with given name
    FileLocTxt = FileLoc + ".txt";
    FileLocWav = FileLoc + ".wav";
    FileLocRaw = FileLoc + "Raw.txt";
    sfinfoOut.channels = sfinfo.channels;
    sfinfoOut.format = sfinfo.format;
    sfinfoOut.samplerate = sfinfo.samplerate;
    if((outfile = sf_open(FileLocWav.c_str(),SFM_WRITE,&sfinfoOut)) == NULL)      // Open Wav-file 2 instance
    {
        printf("Not able to create output file \n");
        printf("\n\nPress any key to exit.");                      // Exit-text if file not present
        puts(sf_strerror(NULL)) ;
        return 1;
    }
    std::ofstream myfile;
    myfile.open(FileLocTxt.c_str(),std::ios::app);
    std::ofstream myfileRaw;
    myfileRaw.open(FileLocRaw.c_str(),std::ios::app);
    while((readcount = sf_read_short(infile, BufferIn, BLOCK_SIZE)))     // While there are still frames to be processed
    {
        //process_data (data, readcount, sfinfo.channels) ;
        auto readcount2 = sf_read_short(infile2, BufferIn2, BLOCK_SIZE);
        for(i = 0; i < BLOCK_SIZE; i++)                                  // BLOCK_SIZE decides the chunk-size
        {
            BufferOut[i] = BufferIn[i] - BufferIn2[i];
            myfileRaw << BufferOut[i];
        }
        sf_write_short(outfile, BufferOut, BLOCK_SIZE) ;                 // Write the data to a new file
    }
    sf_close(infile);                                                    // Close Wav-file handlers
    sf_close(infile2);
    sf_close(outfile);
    myfile.close();                                                      // Close text-file handlers
    printf("\n\nPress any key to exit.");                                // Exit-text
    return 0;
}

【问题讨论】:

  • 使用g++ -std=c++0x -Wall -pedantic -g -O0 test.cpp -o test -lsndfile -ltinyxml2使其独立并在linux/gcc上编译
  • 只是在快速阅读文档后猜测:sf_read_short(infile, BufferIn, BLOCK_SIZE) 开始似乎有问题:sf_read_short 将读取 BLOCK_SIZE * #channels,因此您正在写入超出数组范围。在 BufferIn 之后的堆栈上有一些东西,所以可能你可以通过 4 个通道逃脱,因为你很幸运,然后 UB 真的开始了。(旁注:声明变量尽可能接近你的位置'将使用它们。它更有意义,它使代码更易于阅读。这不是 C。)
  • 对,确实有道理。问题是我天生就为微控制器应用程序编写 C,这对我来说是一个全新的环境。有没有办法给缓冲区数组一个动态大小?其中大小代表 BLOCK_SIZE * # 个频道?
  • 使用std::vector&lt; short &gt;,它提供与普通数组相同语义的连续存储。它的大小可以在构造函数中设置,也可以通过resize() 方法设置。它有一个成员函数data(),它给你一个指向序列开头的指针,这就是你要传递给 sf_read/sf_write
  • @stijn 我不相信你对文档的阅读是准确的,不应该有超限。

标签: c++ wav libsndfile


【解决方案1】:

documentation states:

文件读取函数(项)

sf_count_t  sf_read_short   (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t  sf_read_int     (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t  sf_read_float   (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t  sf_read_double  (SNDFILE *sndfile, double *ptr, sf_count_t items) ;

文件读取项目函数用请求的项目数填充 ptr 指向的数组。 items参数必须是通道数的整数乘积,否则会报错

这是你的问题,因为 BLOCK_SIZE 1、2、4 的倍数,但不是 3 和 5 的倍数 - 所以这会失败。

关于程序完成的问题好像已经发生了计算:添加适当的错误处理。

【讨论】:

    猜你喜欢
    • 2014-04-27
    • 2010-09-30
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    相关资源
    最近更新 更多