Сжатие звука в IMA ADPCM

Есть такой аудиокодек — IMA ADPCM. Сжимает аудио в 4 бита на сэмпл (250 кбит/с при частоте дискретизации 32 кГц, стерео), после чего, достаточно достоверно восстанавливает. А главное, очень быстро. Около 100 тактов на сэмпл на ядре AVR.

Как это работает?

Возьмём обычный файл звук.wav, закодированный в самом распространённом формате — PCM, 16 бит на сэмпл. Амплитуда каждого сэмпла представлена в нём числом от -32768 до 32767. Возьмём и заменим каждый сэмпл на разницу (дельта) между ним и предыдущим сэмлом. Получим формат DPCM — Differential PCM. Но тут мы ничего не выиграли, полученная дельта уже и в 16 бит не влезает. Получается число от -65535 до 65535.

Но что, если уменьшить разрядность дельты? Если сигнал нарастает или убывает незначительно, всё будет хорошо. Но на крутых подъёмах и спусках изменение будет превышать разрядность дельты, возникнут искажения.

А если вместо дельты использовать дельту, умноженную на некоторый шаг? Например, если шаг равен 16, при изменении амплитуды сигнала на 64, дельта будет равна 4. Теперь, если сигнал изменяется значительно, процент искажений будет незначительным, однако при небольших изменениях сигнала, опять же, возникнут искажения, небольшие изменения могут просто пропасть.

Но что, если сделать шаг изменяемым. При небольших изменениях сигнала — маленький, при значительных — большой. Учитывая, что амплитуда сигнала — не случайная величина, а более-менее гладкая функция, мы сможем корректно изменять шаг, и минимизировать искажения.

Данный формат называется ADPCM — Adaptive Differential PCM. Осталось решить как рассчитывать изменение шага. Существует несколько алгоритмов. Здесь мы поговорим о IMA ADPCM. Это быстрый и простой алгоритм, оптимизированный для музыки.

Шаг берётся из специальной таблицы (ima_step_table), заполненной волшебными числами. Номер (step_index) шага в этой таблице изменяется после кодирования каждого сэмпла, в зависимости от скорости нарастания или убывания сигнала, по другой таблице (ima_index_table). Сжатый сэмпл занимает 4 бита (nibble) — 1 бит для знака и 3 для абсолютного значения (т.о. сжатый сэмпл может принимать значения от -7 до 7).

Сжатие:

step = step_table[step_index]
diff = sample - prev_sample
nibble = diff / step
step_index = step_index + index_table[nibble]

Восстановление:

step = step_table[step_index]
diff = nibble * step
sample = prev_sample + diff
step_index = step_index + index_table[nibble]

При сжатии и восстановлении обязательно нужно учитывать возможные переполнения sample и step_index. Они случаются достаточно редко, но если случаются, то могут привести к плачевным последствиям. sample должен быть ограничен пределами от -32768 до 32767, step_index — от 0 до 88.

Кстати, этот кодек — отличный пример, показывающий превосходства программирования на ассемблере. Взять те же переполнения. При программировании на языке высокого уровня информация о переполнениях теряется, приходится использовать более длинный тип данных, и делать медленные сравнения. Что ужасно сказывается на производительности.

Ладно, вот моя реализация декодера.


/* -------------------------------------------------------------------------- */

#pragma once

/* -------------------------------------------------------------------------- */

typedef struct ima_state {
    int16_t sample;
    int8_t index;
} ima_state;

/* -------------------------------------------------------------------------- */

void imadec(ima_state *state, uint8_t value);

/* -------------------------------------------------------------------------- */



;------------------------------------------------------------------------------

    .global imadec

; ------------------------------------------------------------------------------

#define XL        R26
#define XH        R27
#define ZL        R30
#define ZH        R31

; ------------------------------------------------------------------------------

/*
    R0    *
    R1    zero

    R18    sample
    R19    sample

    R20    step
    R21    step

    R22    value
    R23    index

    R24    state
    R25    state

    R26    XL
    R27    XH
    R30    ZL
    R31    ZH
*/

;------------------------------------------------------------------------------

imadec:

    movw        XL,R24 ; state
    
    ld            R18,X+    ; sample
    ld            R19,X+
    ld            R23,X    ; index

    ; load step
    ldi            ZL,lo8(step_table)
    ldi            ZH,hi8(step_table)

    mov            XL,R23
    lsl            XL
    add            ZL,XL
    adc            ZH,R1

    lpm            R20,Z+            ; step = step_table[index]
    lpm            R21,Z

    ; diff = (value + 0.5) * step / 4
    clr            XL                ; diff = 0
    clr            XH

    sbrs        R22,2            ; if(value & 4) diff += step
    rjmp        __1
    add            XL,R20
    adc            XH,R21
__1:

    lsr            R21                ; step >>= 1
    ror            R20
    
    sbrs        R22,1            ; if(value & 2) diff += step
    rjmp        __2
    add            XL,R20
    adc            XH,R21        
__2:

    lsr            R21                ; step >>= 1
    ror            R20

    sbrs        R22,0            ; if(value & 1) diff += step
    rjmp        __3
    add            XL,R20
    adc            XH,R21
__3:

    lsr            R21                ; step >>= 1
    ror            R20
    
    add            XL,R20            ; diff += step
    adc            XH,R21

    ; update sample
    ldi            R21,0x80

    add            R19,R21            ; sample += 0x8000

    sbrs        R22,3            ; if(value & 7)
    rjmp        __4

    sub            R18,XL            ;         sample -= diff
    sbc            R19,XH
    brcc        __5
    
    clr            R18                ;         if(sample < 0) sample = 0
    clr            R19
    rjmp        __5

__4:                            ; else
    add            R18,XL            ;        sample += diff
    adc            R19,XH
    brcc        __5

    ser            R18                ;        if(sample > 0xffff) sample = 0xffff
    ser            R19

__5:
    sub            R19,R21            ; sample -= 0x8000

    ; update index
    ldi            ZL, lo8(index_table)
    ldi            ZH, hi8(index_table)

    andi        R22,7            ; value &= 7
    add            ZL,R22
    adc            ZH,R1

    lpm            R20,Z
    add            R23,R20            ; index += index_table[value]

    brpl        __6                ; if(index < 0)
    clr            R23                ;     index = 0
    rjmp        __7

__6:
    cpi            R23,89            ; if(index >= 89)
    brlo        __7
    ldi            R23,88            ;     index = 88

__7:
    movw        XL,R24
    st            X+,R18
    st            X+,R19
    st            X,R23

    ret

; ------------------------------------------------------------------------------

index_table:
    .byte        -1, -1, -1, -1, 2, 4, 6, 8

; ------------------------------------------------------------------------------

step_table:
    .word        7,     8,     9,    10,    11,    12,    13,    14
    .word       16,    17,    19,    21,    23,    25,    28,    31
    .word       34,    37,    41,    45,    50,    55,    60,    66
    .word       73,    80,    88,    97,   107,   118,   130,   143
    .word      157,   173,   190,   209,   230,   253,   279,   307
    .word      337,   371,   408,   449,   494,   544,   598,   658
    .word      724,   796,   876,   963,  1060,  1166,  1282,  1411
    .word     1552,  1707,  1878,  2066,  2272,  2499,  2749,  3024
    .word     3327,  3660,  4026,  4428,  4871,  5358,  5894,  6484
    .word     7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899
    .word    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794
    .word    32767

; ------------------------------------------------------------------------------


А вот пример использования

void playima(char *name)
{
    uint8_t buff[512];
    WORD cb;
    uint16_t n;
    ima_state state[2];
    uint8_t data;

    if(!pf_open(name))
    {
        snd_freq(44100);

        state[0].sample = 0;
        state[0].index = 0;
        state[1].sample = 0;
        state[1].index = 0;

        while(!pf_read(buff, sizeof(buff), &cb))
        {
            for(n = 0; n < cb; ++n)
            {
                data = buff[n];

                imadec(state+0, data);
                imadec(state+1, data>>4);

                snd_out( (state[0].sample>>8)+0x80, (state[1].sample>>8)+0x80 );
            }
            if(cb != sizeof(buff))
                break;
        }
    }
}


snd_freq устанавливает частоту загрузки данных из кольцевого буфера в регистр PWM
snd_out ложит данные в кольцевой буфер

А здесь можно скачать прогу для перекодировария WAV файлов в IMA и пример прошивки, воспроизводящей файл, сжатый IMA с SD-карточки.

зы. Данный кодек я очень люблю, и юзаю как в девайсах на МК, так и в прогах для компа, для передачи звука по сети (в этом случае можно сверху ещё deflate'ом прижать).

Комментарии (31)

RSS свернуть / развернуть
Класс! Давно хотел что то подобное реализовать, но все как то руки не доходили. А теперь еще и готовый код есть. Спасибо :)
0
Забавно.
Но зачем по сети-то в нем передавать? Есть же куда более эффективные алгоритмы, хотя и более тяжелые — но для компа это уже несущественно.
P.S. snd_out ложит данные в кольцевой буфер
0
  • avatar
  • Vga
  • 16 марта 2011, 13:51
IMHO, «пример прошивки, воспроизводящей файл, сжатый IMA с SD-карточки» можно было бы в отдельную статейку с подробным описанием
0
и фотками конструкции. Кроме того, я заметил там Petit FatFs Module — внятное описание ее применения это было бы суперски!
0
Спасибо! Пример работы с SD-карточками был бы очень полезен.
0
Огромное спасибо за алгоритм!
Щас замутим на STM8 и PIC18
0
полезно-полезно, спасибо!
Лично я в реализациях для PC сижу на тяжеленном speex :) Для передачи узкополосных сигналов без искажения пакетов он хорош
0
+
а как IMA относится отдельно к повреждениям и полным потерям пакетов? Насколько велики искажения?
0
Если есть потери, стоит порезать поток на фреймы. В начале каждого фрейма записать индекс и текущее значение сэмпла. Каждый фрейм — в отдельный пакет. Потеряной инфы, конечно, не восстановишь, но искажений не будет. Насчёт помех — не знаю, но явно результат будет хуже, чем тупо PCM. Потом, IMA лучше прижать zlib'ом, так то он для передачи по сети в чистом виде не оч подходит. А вот zlib искажений не терпит.
А где ты нашёл канал с помехами? Юзаешь UDP без проверки контрольной суммы?
0
нет, канал с помехами — это радиоканал ;) а с потерями, но без искажения — udp/tcp. Лично я много и часто использую передачу речи по сети, и для этого выбрал speex. Но подобные, легкие для контроллеров, алгоритмы меня интересовали уже давно. Пока что нашел melp, но он несколько сложен… :) А в IMA можно быстро перекодировать на лету, и это очень хорошо!
0
декодер/кодер:
#include "ul_audio.h"

// 4->16 bit IMA ADPCM tables of index changes and quantizer step size lookup
#ifdef __AVR
    S8  PROGMEM adpcmima_0416_index_tab[16] = {-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
    U16 PROGMEM adpcmima_0416_stepsize_tab[89] = {
             7,     8,     9,    10,    11,    12,    13,    14,    16,    17,
            19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
            50,    55,    60,    66,    73,    80,    88,    97,   107,   118,
           130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
           337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
           876,   963,  1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
          2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
          5894,  6484,  7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899,
         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
    };
#else
    S8  adpcmima_0416_index_tab[16] = {-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
    U16 adpcmima_0416_stepsize_tab[89] = {
             7,     8,     9,    10,    11,    12,    13,    14,    16,    17,
            19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
            50,    55,    60,    66,    73,    80,    88,    97,   107,   118,
           130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
           337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
           876,   963,  1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
          2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
          5894,  6484,  7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899,
         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
    };
#endif

U16 adpcmima_0416_dec(U8 sample_in, U16 sample_prev, U8 *index_prev) {
    U16 diffq, step;
    S8 index;

    sample_prev += 32768; /*convert to unsigned*/
    index = *index_prev;

    /* Find quantizer step size from lookup table using index */
    #ifdef __AVR
        step = pgm_read_word(&adpcmima_0416_stepsize_tab[index]);
    #else
        step = adpcmima_0416_stepsize_tab[index];
    #endif

    /* Inverse quantize the ADPCM code into a difference using the quantizer step size */
    if (sample_in & 4) diffq = step; else diffq = 0; step >>= 1;
    if (sample_in & 2) diffq += step; step >>= 1;
    if (sample_in & 1) diffq += step; step >>= 1;
    diffq += step;

    /* Add the difference to the predicted sample */
    if (sample_in & 8) {
        if (sample_prev > diffq) sample_prev -= diffq;
        else sample_prev = 0;
    } else {
        if ((0xffff - sample_prev) > diffq) sample_prev += diffq;
        else sample_prev = 0xffff;
    }
    sample_prev -= 32768;

    /* Find new quantizer step size by adding the old index and a table lookup using the ADPCM code */
    #ifdef __AVR
        index += pgm_read_byte(&adpcmima_0416_index_tab[sample_in & 0xf]);
    #else
        index += adpcmima_0416_index_tab[sample_in & 0xf];
    #endif

    /* Check for overflow of the new quantizer step size index */
    if (index < 0) index = 0;
        else if (index > 88) index = 88;
    *index_prev = index;
    
    return(sample_prev);
}

U8 adpcmima_0416_enc(U16 sample_in, U16 *sample_prev, S8 *index_prev) {
    S32 diff;        /* Difference between sample and the predicted sample */
    U16 step;        /* Quantizer step size */
    S16 sample_pred; /* Output of ADPCM predictor */
    S32 diffq;       /* Dequantized predicted difference */
    S8  index;       /* Index into step size table */
    U8 sample_out;   /* Result of encoding */

    /*restore previous values of predicted sample and quantizer step size index*/
    sample_pred = *sample_prev; /*convert predicted sample to unsigned format*/
    index = *index_prev;

    #ifdef __AVR
        step = pgm_read_word(&adpcmima_0416_stepsize_tab[index]);
    #else
        step = adpcmima_0416_stepsize_tab[index];
    #endif

    /*compute the difference between the input sample (sample_in) and the the predicted sample (sample_pred)*/
    diff = (S32)sample_in - (S32)sample_pred;
    if (diff >= 0) sample_out = 0; else {sample_out = 8; diff = -diff;}

    /* Quantize the difference into the 4-bit ADPCM code using the the quantizer step size	*/
    /* Inverse quantize the ADPCM code into a predicted difference using the quantizer step size */
    diffq = 0;
    if (diff >= step) {sample_out |= 4; diff -= step; diffq += step;}
    step >>= 1;
    if (diff >= step) {sample_out |= 2; diff -= step; diffq += step;}
    step >>= 1;
    if (diff >= step) {sample_out |= 1; diffq += step;}
    step >>= 1;
    diffq += step;

    /* Fixed predictor computes new predicted sample by adding the old predicted sample to predicted difference */
    if (sample_out & 8) sample_pred -= diffq; else sample_pred += diffq;

    /* Check for overflow of the new predicted sample */
    if (sample_pred > 32767) sample_pred = 32767; else if (sample_pred < -32767) sample_pred = -32767;

    /* Find new quantizer stepsize index by adding the old index to a table lookup using the ADPCM code */
    #ifdef __AVR
        index += pgm_read_byte(&adpcmima_0416_index_tab[sample_out]);
    #else
        index += adpcmima_0416_index_tab[sample_out];
    #endif

    /* Check for overflow of the new quantizer step size index */
    if (index < 0) index = 0; else if (index > 88) index = 88;

    /* Save the predicted sample and quantizer step size index for next iteration */
    *sample_prev = sample_pred;
    *index_prev = index;

    return(sample_out);
}
0
И? Быстрее работает, чем на асме?
0
не знаю, наверно нет.
с нехваткой скорости не сталкивался, поэтому с оптимизацией не заморачивался.
0
Я сталкивался. Без оптимизации не получается воспроизводить 44,1 кГц x 2.
0
да, возможно.
у меня максимум получился моно uLaw 32кГц на 10МГц Mega8.
ADPCM не устроил качеством.
0
Где взять ul_audio.h? Мой AVRGCC ругается, гугление ничего не дало
0
он не нужен, строку можно удалить
0
Всё равно вот что выдаёт: http://pastebin.com/pYCMCFXr
Что у вас за среда? Скорее всего, у меня в GCC нет заголовочных файлов каких-то…
0
U8,S8,U16,U32 определить не забыли?
#include <stdint.h>
#define U8 uint8_t
#define S8 int8_t
#define U16 uint16_t
#define S16 int16_t
#define S32 int32_t
0
Да, у меня для этого заголовочный есть из CodeVision, вроде. А поначалу ругалось. Всё равно — тот же вывод из копилятора с руганью. Даже не знаю, куда рыть, я только третий день изучаю Си для AVR
0
проверил обычным GCC — скомпилилось без проблем.
0
Можете показать Makefile или команды, через которые компилируете?
0
исходник: codetidy.com/paste/raw/4250
компилирую: gcc 1.c
0
Разобрался, получилось. Нужно добавить #include <avr/pgmspace.h> и два массива PROGMEM объявлять константами. Ну и int main(void){} добавить :)
К сожалению, не совсем понял, как поступать дальше — как «скармливать» поток ADPCM?
0
скармливайте 4 мл.бита sample_in,
sample_prev — предыдущий семпл,
index_prev — служебная переменная.
0
для коллекции uLaw:

// uLaw encoder sample bias value
#define ULAW_0816_BIAS 0x84
// uLaw encoder sample clipping value
#define ULAW_0816_CLIP 32635

#ifdef __AVR
    U16 PROGMEM ulaw_0816_expdec[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764};
    U8  PROGMEM ulaw_0816_expenc[] = {
        0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
        4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
	};
#else
    const U16 ulaw_0816_expdec[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764};
    const U8  ulaw_0816_expenc[] = {
        0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
        4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
    };
#endif
// uLaw decoder (8->16 bit)
U16 ulaw_0816_dec(U8 sample_in) {
    U8  exponent;
    U16 sample_out;
    sample_in = ~sample_in;
    exponent = (sample_in >> 4) & 7;
#ifdef __AVR
	sample_out = pgm_read_word(&ulaw_0816_expdec[exponent]);
#else
    sample_out = ulaw_0816_expdec[exponent];
#endif
    sample_out += (((U16)((sample_in) & 0xf)) << (exponent + 3));
    if (sample_in & 0x80) sample_out = -((S16)sample_out);
    return sample_out;
}

// uLaw encoder (16->8 bit)
U8 ulaw_0816_enc(U16 sample_in) {
    U8 sign, exponent, mantissa, sample_out;
    if ((S16)sample_in < 0) {
        sign = 0x80;
        sample_in = -(S16)sample_in;
    } else sign = 0;
    if (sample_in > ulaw_0816_clip) sample_in = ulaw_0816_clip;
    sample_in += ulaw_0816_bias;
#ifdef __AVR
	exponent = pgm_read_word(&ulaw_0816_expenc[((U16)sample_in >> 7) & 0xff]);
#else
    exponent = ulaw_0816_expenc[((U16)sample_in >> 7) & 0xff];
#endif
    mantissa = (sample_in >> (exponent + 3)) & 0xf;
    sample_out = (sign | (exponent << 4) | mantissa);
    if (sample_out == 0) sample_out = 2;
    return sample_out;
}
0
реализации 2- и 3- битного ADPCM не встречали?
0
Есть аппноут у атмела.
www.atmel.com/Images/doc2572.pdf
www.atmel.com/Images/AVR336.zip
0
Добрый день! Нет ли у кого кодека для сжатия 8-битных звуковых семплов до 2-х или 4-х бит?
0
Добрый день!
Я разбираю формат карт для автомагнитол MITSUBISHI
Столкнулся с файлами, которые отвечают за голосовые фразы
С помщью программы Audacity — расжал код фразы, но все равно не то.
Прошу вашей помощи/консультации:
— понять какой алгоритм расжатия/сжатия звука
— или если у Вас есть готовый кодек под мой вариант:
— подскажите: с какими параметрами и как мне получить хорошее качество звучания фраз с поомощью Вашего кодека
Вот пример:
— исходный сжатый код (RAW)data_30_0. Это, первая фраза, что находится в файле voice001.me. Звучит так «расчет маршрута завершен»
— Если его не расжимать а в нем тупо сделать шапку для Wav => 11_00_8_30_0_dec.wav то фразу слышно, но много шумов.
— если этот RAW data_30_0 пропустить через Audacity -> import->звуковой файл без загловка: с параметрами=>
— кодировка: Signed 8 bit PCM
— порядок байт: litle-endian
— каналов: 1
— весь файл (100%)
— частота дискредитации: 11025
То получим более четкую фразу, но все равно с шумами
Когда я этот файл (11_00_8_30_2_dec.wav) уже из под Audacity сохраняю, то получаю:
— исходный расжатый код (RAW) data_30_2 -> размер увеличился в 2 раз
— чатота дискредитации: 11025
— Количество байт, переданных за секунду воспроизведения, byteRate: 22050
— формат PCM (код =1)
— глубина звука: моно (1), 16 бит (Hambit)
Файлы можно скачать отсюда solk.org.ua/voice.rar
Заранее благодарен за помощь, просьба не пинать сильно, если что-то не грамотно описал. Я с этим раньше вообще не работал
0
  • avatar
  • AS21
  • 01 марта 2015, 11:17
Всем спасибо, вроде разобрались
модифицированный стандарт CD-I ADPCM level C
У кого-то есть обратный алгооритм, т.е. сжатие по стандарт CD-I ADPCM level C?
0
  • avatar
  • AS21
  • 05 марта 2015, 22:11
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.