Почему мой ADPCM-декодер колеблется?

Я пишу код для встроенного процессора (ARM Cortex-M4)

Целью этого кода является декодирование 4-битного ADPCM в формате Intel/DVI (также называемый форматом IMA). Я закодировал образец прямоугольной волны ADPCM, используя Python audioop модуль. Затем я успешно расшифровал этот образец, используя тот же audioop модуль, и это хорошо подходит для ввода.

Однако я не могу правильно декодировать входные данные на моем встроенном процессоре. valpred Значение, которое представляет выход, кажется, убегает и колеблется между большим положительным и большим отрицательным значением. Это, кажется, обусловлено поведением sign значение. Проблема, которую я имею, состоит в том, что этот код фактически является точной копией кода реализации C audioop, с удаленными частями Python. Алгоритм, насколько я могу судить, идентичен. И все же он, похоже, переходит в колебательное состояние практически для каждого значения входных данных. Это явно обусловлено sign листать vpdiff значение, но я не вижу, как этого избежать, учитывая, что шаг квантования очень высок (обычно на максимальном шаге 88), и данные, кажется, имеют чередующиеся знаки.

Это реализация, с которой я сейчас работаю. adpcm_step_size массив содержит шаги квантования (например, 7, 8, 9 ... 29794, 32767), тогда как adpcm_step_size_adapt содержит шаг приращения (-1, -1, -1, -1, 2, 4, 6, 8, дублирован).

void audio_adpcm_play(uint8_t *sample_data, uint16_t sample_size)
{
    int sign, delta, step, vpdiff, valpred, index, half;
    uint32_t debug_data;
    uint32_t result;
    uint8_t data = 0x00;

    // Initial state
    half = 0;
    valpred = 0;
    index = 0;
    step = adpcm_step_size[index];

    while(sample_size > 0) {
        // Extract the appropriate word
        if(half) {
            delta = data & 0x0f;
        } else {
            data = *sample_data++;
            delta = (data >> 4) & 0x0f;
            sample_size--;
        }

        half = !half;
        debug_data = delta;

        // Find new index value
        index += adpcm_step_size_adapt[delta];
        if(index < 0)
            index = 0;
        if(index > 88)
            index = 88;

        // Separate sign and magnitude
        sign = delta & 8;
        delta = delta & 7;

        // Compute difference and the new predicted value
        vpdiff = step >> 3;

        if(delta & 4)
            vpdiff += step;
        if(delta & 2)
            vpdiff += step >> 1;
        if(delta & 1)
            vpdiff += step >> 2;

        if(sign)
            valpred -= vpdiff;
        else
            valpred += vpdiff;

        // Clamp values that exceed the valid range
        if(valpred > 32767)
            valpred = 32767;
        else if(valpred < -32768)
            valpred = -32768;

        step = adpcm_step_size[index];

        result = (valpred + 32767) >> AUDIO_CODE_SHIFT;
        uart_printf(DBG_LVL_INFO, \
                "data=%02x,  source_byte=%02x,  samples_rem=%5d,  valpred=%7d,  vpdiff=%5d,  sign=%02x,  delta=%02x,  index=%3d,  step=%3d,  adapt=%3d,  res=%5d/%5d\r\n", \
                debug_data, data, sample_size, valpred, vpdiff, sign, delta, index, step, \
                adpcm_step_size_adapt[delta], result, AUDIO_CODE_DUTY_MAX);
    }
}

Вот результат ввода прямоугольных входных данных; как можно видеть, valpred быстро колеблется между двумя значениями, когда он должен достичь определенного значения.

data=07,  source_byte=f7,  samples_rem= 7999,  valpred=     19,  vpdiff=   30,  sign=00,  delta=07,  index= 16,  step= 34,  adapt=  8,  res=  128/  256
data=0f,  source_byte=f7,  samples_rem= 7998,  valpred=    -44,  vpdiff=   63,  sign=08,  delta=07,  index= 24,  step= 73,  adapt=  8,  res=  127/  256
data=07,  source_byte=f7,  samples_rem= 7998,  valpred=     92,  vpdiff=  136,  sign=00,  delta=07,  index= 32,  step=157,  adapt=  8,  res=  128/  256
data=0f,  source_byte=f7,  samples_rem= 7997,  valpred=   -201,  vpdiff=  293,  sign=08,  delta=07,  index= 40,  step=337,  adapt=  8,  res=  127/  256
data=07,  source_byte=f7,  samples_rem= 7997,  valpred=    430,  vpdiff=  631,  sign=00,  delta=07,  index= 48,  step=724,  adapt=  8,  res=  129/  256
data=0f,  source_byte=f7,  samples_rem= 7996,  valpred=   -927,  vpdiff= 1357,  sign=08,  delta=07,  index= 56,  step=1552,  adapt=  8,  res=  124/  256
data=07,  source_byte=f7,  samples_rem= 7996,  valpred=   1983,  vpdiff= 2910,  sign=00,  delta=07,  index= 64,  step=3327,  adapt=  8,  res=  135/  256
data=0f,  source_byte=f7,  samples_rem= 7995,  valpred=  -4253,  vpdiff= 6236,  sign=08,  delta=07,  index= 72,  step=7132,  adapt=  8,  res=  111/  256
data=07,  source_byte=f7,  samples_rem= 7995,  valpred=   9119,  vpdiff=13372,  sign=00,  delta=07,  index= 80,  step=15289,  adapt=  8,  res=  163/  256
data=0d,  source_byte=d5,  samples_rem= 7994,  valpred= -11903,  vpdiff=21022,  sign=08,  delta=05,  index= 84,  step=22385,  adapt=  4,  res=   81/  256
data=05,  source_byte=d5,  samples_rem= 7994,  valpred=  18876,  vpdiff=30779,  sign=00,  delta=05,  index= 88,  step=32767,  adapt=  4,  res=  201/  256
data=0b,  source_byte=b3,  samples_rem= 7993,  valpred=  -9793,  vpdiff=28669,  sign=08,  delta=03,  index= 87,  step=29794,  adapt= -1,  res=   89/  256
data=03,  source_byte=b3,  samples_rem= 7993,  valpred=  16276,  vpdiff=26069,  sign=00,  delta=03,  index= 86,  step=27086,  adapt= -1,  res=  191/  256
data=0c,  source_byte=c4,  samples_rem= 7992,  valpred= -14195,  vpdiff=30471,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7992,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=09,  source_byte=9c,  samples_rem= 7991,  valpred=  10381,  vpdiff=12286,  sign=08,  delta=01,  index= 87,  step=29794,  adapt= -1,  res=  168/  256
data=0c,  source_byte=9c,  samples_rem= 7991,  valpred= -23137,  vpdiff=33518,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7990,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7990,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7989,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7989,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7988,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7988,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7987,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7987,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7986,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7986,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7985,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7985,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7984,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256
data=0c,  source_byte=4c,  samples_rem= 7984,  valpred= -23137,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=01,  source_byte=14,  samples_rem= 7983,  valpred= -10851,  vpdiff=12286,  sign=00,  delta=01,  index= 87,  step=29794,  adapt= -1,  res=   85/  256
data=04,  source_byte=14,  samples_rem= 7983,  valpred=  22667,  vpdiff=33518,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7982,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7982,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7981,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7981,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7980,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7980,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7979,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7979,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7978,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7978,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7977,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7977,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=0c,  source_byte=c4,  samples_rem= 7976,  valpred= -14195,  vpdiff=36862,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   72/  256
data=04,  source_byte=c4,  samples_rem= 7976,  valpred=  22667,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  216/  256
data=09,  source_byte=9c,  samples_rem= 7975,  valpred=  10381,  vpdiff=12286,  sign=08,  delta=01,  index= 87,  step=29794,  adapt= -1,  res=  168/  256
data=0c,  source_byte=9c,  samples_rem= 7975,  valpred= -23137,  vpdiff=33518,  sign=08,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=   37/  256
data=04,  source_byte=4c,  samples_rem= 7974,  valpred=  13725,  vpdiff=36862,  sign=00,  delta=04,  index= 88,  step=32767,  adapt=  2,  res=  181/  256

Если я беру только каждую вторую выборку, она почти приемлемо работает для прямоугольных волн, но возникают проблемы для других форм волны. Это все еще не приемлемое решение, но, возможно, это ключ к пониманию причины проблемы.

Если у кого-то есть идеи, я буду признателен. Я рвал на себе волосы в течение нескольких дней.

Изменить: Источник для audioop Модуль можно найти здесь https://github.com/python/cpython/blob/master/Modules/audioop.c, декодер ADPCM audioop_adpcm2lin_impl,

1 ответ

Решение

Мне удалось исправить эту проблему. Это было вызвано глупой ошибкой: считывание 16-битных входных данных по одному байту за раз, а затем распаковка данных с использованием той же ошибки приводило к правильному результату в Python. Но это, очевидно, не принесло пользы для C-реализации декодера.

Оглядываясь назад, я не уверен, почему я не заметил, что аудиофайл был в два раза больше, чем должен был быть.

Другие вопросы по тегам