代码之家  ›  专栏  ›  技术社区  ›  Egor Lakomkin

使用libSox链接多个效果并读取输出数据的正确方法

  •  3
  • Egor Lakomkin  · 技术社区  · 6 年前

    我正在尝试用libSox程序化地应用一些效果,但我目前无法理解我是否做得对。例如,我需要应用速度和增益效果,并在缓冲区中读取结果音频以进行进一步处理。文件真的很稀少,谷歌搜索也没有成功。

    sox_format_t* input = sox_open_read("<file.wav>", NULL, NULL, NULL);
    //sox_format_t* out;
    
    sox_format_t* output = sox_open_memstream_write(&buffer, &buffer_size,
                                                 &input->signal, &input->encoding, "raw", NULL);
    //assert(output = sox_open_write("/home/egor/hello_processed.wav", &input->signal, NULL, NULL, NULL, NULL));
    sox_effects_chain_t* chain = sox_create_effects_chain(&input->encoding, &output->encoding);
    
    char* sox_args[10];
    //input effect
    
    sox_effect_t* e = sox_create_effect(sox_find_effect("input"));
    sox_args[0] = (char*)input;
    assert(sox_effect_options(e, 1, sox_args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &input->signal, &input->signal) ==
           SOX_SUCCESS);
    free(e);
    
    e = sox_create_effect(sox_find_effect("tempo"));
    std::string tempo_str = "1.01";
    sox_args[0] = (char*)tempo_str.c_str();
    assert(sox_effect_options(e, 1, sox_args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &input->signal,&input->signal) ==
           SOX_SUCCESS);
    free(e);
    
    
    e = sox_create_effect(sox_find_effect("output"));
    sox_args[0] = (char*)output;
    assert(sox_effect_options(e, 1, sox_args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &input->signal, &input->signal) ==
           SOX_SUCCESS);
    free(e);
    sox_flow_effects(chain, NULL, NULL);
    
    
    static const size_t maxSamples=4096;
    sox_sample_t samples[maxSamples];
    
    std::vector<sox_sample_t> audio_buffer;
    for (size_t r; 0 != (r=sox_read(output,samples,maxSamples));)
        for(int i=0;i<r ;i++)
            audio_buffer.push_back(samples[i]);
    
    std::cout << audio_buffer.size() << std::endl;
    

    我的问题是:

    1. 我是否正确设置了效果链?

    2. 如果我使用tempo values<1,我会从输出中获得正确数量的样本(在音频缓冲区中),但是如果我将其更改为1.2,我会突然得到非常少量的样本,如果使用1.0的值,则会得到0。我想知道我的链配置或从输出读取数据时是否有错误?这是我第一次使用libsox,我试着用一些例子,但是我被困在这里了。

    提前感谢您的帮助!

    谢谢您!

    1 回复  |  直到 6 年前
        1
  •  0
  •   SergeyLebedev    6 年前
    1. 您的效果链正常,您可以将其写入文件来检查它是否提供了正确的输出缓冲区-只需替换代码中的这一行:

    sox_format_t* output = sox_open_memstream_write(&buffer, &buffer_size, &input->signal, &input->encoding, "raw", NULL);

    对于这个:

    sox_format_t* output = sox_open_write("2.wav", &input->signal, &input->encoding, "raw", NULL, NULL);

    1. 关于内存输出缓冲区问题-我研究过 libsox 代码中,似乎有一个错误在其内存缓冲区处理。作为解决办法,我建议您添加 output->olength = 0; 阅读前 output

    所以,您的代码将如下所示:

    ...
    if (std::stof(tempo_str) >= 1.0) { // use workaround only if tempo >= 1.0
        output->olength = 0;
    }
    
    std::vector<sox_sample_t> audio_buffer;
    for (size_t r; 0 != (r=sox_read(output,samples,maxSamples));)
        for(int i=0;i<r ;i++)
            audio_buffer.push_back(samples[i]);
    ...
    

    UPD:仅当 tempo >= 1.0