Измените высоту звукового файла без изменения темпа с помощью libsox - PullRequest
2 голосов
/ 16 апреля 2020

Я разработал простое приложение, которое изменяет высоту звукового файла с помощью libsox (используя этот пример ). Вот мой код. Он работает с 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 для правильной работы этого эффекта?

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

Эффект pitch в libsox изменит частоту дискретизации звука. Если вы заметите частоту дискретизации после «подачи», вы обнаружите, что она была изменена. Чтобы сохранить аудиофайл с той же частотой дискретизации, вам нужно добавить эффект «rate» после эффекта «pitch». Например:

#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;
}

При желании вы можете добавить эффект «дизеринга» после «скорости», чтобы получить лучший результат.

0 голосов
/ 24 апреля 2020

После поиска, спасибо this . Я обнаружил, что для поддержания темпа звука необходимо добавить коэффициент скорости *1004* в цепочку эффектов после эффекта высоты тона .

...