【问题标题】:Change audio file pitch without changing tempo using libsox使用 libsox 更改音频文件音高而不更改速度
【发布时间】:2020-04-16 03:00:16
【问题描述】:

我开发了一个简单的应用程序,它使用 libsox 更改音频文件的音高(使用 this example)。 这是我的代码。它适用于 2 个输入参数 - 输入文件路径和输出文件路径:

#include <sox.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

int main(int argc, char * argv[])
{
    static sox_format_t * in, * out; /* input and output files */
    sox_effects_chain_t * chain;
    sox_effect_t * e;
    char * args[10];
    sox_signalinfo_t interm_signal; /* @ intermediate points in the chain. */
    sox_encodinginfo_t out_encoding = {
        SOX_ENCODING_SIGN2,
        16,
        0,
        sox_option_default,
        sox_option_default,
        sox_option_default,
        sox_false
    };
    sox_signalinfo_t out_signal = {
        16000,
        1,
        0,
        0,
        NULL
    };

assert(argc == 3);
assert(sox_init() == SOX_SUCCESS);
assert(in = sox_open_read(argv[1], NULL, NULL, NULL));
assert(out = sox_open_write(argv[2], &out_signal, &out_encoding, NULL, NULL, NULL));

chain = sox_create_effects_chain(&in->encoding, &out->encoding);

interm_signal = in->signal; /* NB: deep copy */

e = sox_create_effect(sox_find_effect("input"));
args[0] = (char *)in; 
assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS);
free(e);

e = sox_create_effect(sox_find_effect("pitch"));
args[0] = "1000";
assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);

e = sox_create_effect(sox_find_effect("output"));
args[0] = (char *)out;
assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);

sox_flow_effects(chain, NULL, NULL);

sox_delete_effects_chain(chain);
sox_close(out);
sox_close(in);
sox_quit();

return 0;
}

但是我从上面的代码得到的结果是一个改变了速度的文件。 以下是输入和输出的详细信息:

Input File     : 'input.wav'
Channels       : 1
Sample Rate    : 16000
Precision      : 16-bit
Duration       : 00:00:11.87 = 189921 samples ~ 890.255 CDDA sectors

Input File     : 'output.wav'
Channels       : 1
Sample Rate    : 16000
Precision      : 16-bit
Duration       : 00:00:21.15 = 338401 samples ~ 1586.25 CDDA sectors

另外,sox 应用运行良好。

sox input.wav output_app.wav pitch 1000

它会生成一个与输入持续时间相同的文件:

Input File     : 'output_app.wav'
Channels       : 1
Sample Rate    : 16000
Precision      : 16-bit
Duration       : 00:00:11.87 = 189921 samples ~ 890.255 CDDA sectors

这里有人遇到同样的问题吗?还是我必须向 sox_effect 提供任何其他选项才能使此效果正常工作?

【问题讨论】:

  • 那些带有逗号运算符的asserts 是怎么回事,请忘记 :D 看起来真的很难阅读!你也在滥用断言。 assert 应该永远不会失败,它会声明不变量,所以你已经说过“没有人会调用这个程序而不给它正好 2 个命令行参数” 和 “sox 将始终成功打开第一个参数给它的文件”。除此之外,我相信这是一个很好的问题,对未来的读者有用:D
  • 关于:它会生成一个与输入持续时间相同的文件: 也许我遗漏了一些关键细节,但00:00:11.87 看起来不像00:00:21.15跨度>
  • 关于assert(argc == 3); 在检查命令行参数时(它们不存在),最好告诉用户调用程序的正确方法。类似于:fprintf( stderr, "USAGE: %s &lt;InputFileName&gt; &lt;OutputFileName&gt;\n", argv[0] );assert() 的其他调用也存在类似的考虑
  • 改变音高,声音的持续时间,采样的数量,不应该改变。只有样本的内容。此外,采样率远远超出奈奎斯特频率,因此音高的修改不应使声音失真
  • @user3629249 我只是从示例中复制代码并更改效果以查看它是否按预期工作。 “它生成一个与输入持续时间相同的文件”的语句是关于从终端运行 sox 应用程序。它生成了一个 11.87s 的文件(output_app.wav)文件。

标签: c sox libsox


【解决方案1】:

libsox 的“音高”效果会改变音频采样率。 如果您注意到“音高”之后的采样率,您会发现它已更改。 为了以相同的采样率保存音频文件,您需要在“音高”效果之后添加“速率”效果。 像这样:

#include <sox.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

int main(int argc, char * argv[])
{
    static sox_format_t * in, * out; /* input and output files */
    sox_effects_chain_t * chain;
    sox_effect_t * e;
    char * args[10];
    sox_signalinfo_t interm_signal; /* @ intermediate points in the chain. */
    sox_encodinginfo_t out_encoding = {
        SOX_ENCODING_SIGN2,
        16,
        0,
        sox_option_default,
        sox_option_default,
        sox_option_default,
        sox_false
    };
    sox_signalinfo_t out_signal = {
        16000,
        1,
        0,
        0,
        NULL
    };

    assert(argc == 3);
    assert(sox_init() == SOX_SUCCESS);
    assert(in = sox_open_read(argv[1], NULL, NULL, NULL));
    assert(out = sox_open_write(argv[2], &out_signal, &out_encoding, NULL, NULL, NULL));

    chain = sox_create_effects_chain(&in->encoding, &out->encoding);

    interm_signal = in->signal; /* NB: deep copy */

    e = sox_create_effect(sox_find_effect("input"));
    args[0] = (char *)in; 
    assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS);
    free(e);

    e = sox_create_effect(sox_find_effect("pitch"));
    args[0] = "1000";
    assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
    free(e);

    // Note: interm_signal.rate changed now, we need to rate it back

    e = sox_create_effect(sox_find_effect("rate"));
    args[0] = "-m";
    assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
    free(e);

    e = sox_create_effect(sox_find_effect("output"));
    args[0] = (char *)out;
    assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
    assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
    free(e);

    sox_flow_effects(chain, NULL, NULL);

    sox_delete_effects_chain(chain);
    sox_close(out);
    sox_close(in);
    sox_quit();

    return 0;
}

或者,您可以在“rate”之后添加“dither”效果以获得更好的结果。

【讨论】:

    【解决方案2】:

    搜索了一会,感谢this。我发现为了保持音频节奏,必须在音高效果之后将速率效果添加到效果链中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-30
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 2013-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多