Born Dead #0G
31 марта 2000
  Звук  

Coding своими руками - Алгоритм сжатия звука ADPCM.

════════════════════════════════════════════════════════════════
ЇЄ╒▐╟░░╟▐╒ЄєЇCODING СВОИМИ РУКАМИ ЇєЄ╒▐╟░░╟▐╒ЄєЇ
════════════════════════════════════════════════════════════════

(c) MoNz7eR^Sa9e

   Итак,  ADPCM:  сжатие  с  потерями,  но  если  сжимать  16bit
оригинал (вся фишка в том, что чем качественней оригинал, имею в
виду   разрядность,   тем   качественней   полученный  архив)  и
использовать  4bit  для  архива,  то это звучит даже на PC очень
сильно (чуть  хуже  MP3),  а  если  2bit на выборку юзать, то на
спеке  с MCC методом тоже солидно звучит (я имею в виду выходной
сигнал 8-7bit!)

   Тема  такая,  за  основу  взят  простейший  дельта  паковщик,
разрядностью 1bit. (рис.1)

                ^       ,-. o
                |      ;  o\  o
                |     ; o   \   o
                |   ,'o     ::    o
                o-o-o--------(------o---------->
                |             \       o     _,o
                |              ~.       o_-~o
                |                ~-____-' o
                |
                            [рис.1]

   Он стремится догнать изменяющийся сигнал с помощью одинаковых
смещений по X. Типа

             если INсигнал > PACсигнал, то bit = 1, а
             если INсигнал < PACсигнал, то bit = 0.

   ADPCM  адаптирует  смещения  с  помощью  таблицы  и с помощью
умножения.  Не  буду  описывать  общий метод, объясню на примере
2bit'ного сжатия.

   В сжатом 2bit'ном виде хранится:

                   [  S  ]      [  k0  ]   ...
                 sign - знак   коэффициент
                 "+" или "-"    умножения

   При распаковке получаем формулу:

          X = X + (-1) * S * (TAB(i) * k0 + TAB(i)/2)

(при большей разрядности
          ... + k1*TAB(i)/2 + k2*TAB(i)/4 + TAB(i)/8
и т.д.)

   Причём  если  2bit = 0 или 2, то i = i - 1, если  1 или 3, то
i = i + 2. (i - смещение  по табличке приращений по X.)  В итоге
пакуемый сигнал быстро адаптируется под оригинал. (см. рис.2)

                ^
                |        o
            max + - - - - -o- - - - - - - - - -
                |      o,-.
                |      ;   \ °
                |     °     \
                |   o'      :: o
                o-°----------(---------------o->
                |             \            o_,-
                |              ~.o       o-~
                |                ~-____-'
                |                  o   °
                + - - - - - - - - - -o- - - - - и т.д.

                            [рис.2]

   Есть  у  меня  оригинал  таблички  приращений,  выдранный  из
PC'шного  Encoder'а,  так, что файлы, спакованные с этой таблой,
играются  где  угодно (если  заголовок правильный у файла). Одна
проблема  на  спеке,  подобрать  амплитуду  сигнала  так,  чтобы
быстрый распаковщик (есть исходник, играет по MCC примерно 20кГц
с распаковкой из 2bit!!!) после сложений не выпрыгнул за пределы
(не  перешёл  через ноль и не сменил знак), а так метод - просто
рульный!

   В  итоге  для паковки каждую выборку (а точнее, разницу между
выборками  из  оригинала  и  из  компаратора - из  запакованного
сигнала)  анализируют  так:  в  начале сохраняем первое значение
оригинала [pac(0) = in(0)]. Потом:

let bit1 = 0 : let bit0 = 0 : let d(n) = in(n) - pac(n)
if d(n) < 0 then bit1 = 1 : let d(n) = ABS d(n)
if d(n) > tabl(i) then bit0 = 1 : let i = i + 2 else i = i - 1

(для  многобитного  сжатия  вместо -1  и +2 используем таблицу с
кучей значений)

if i < 0 then i = 0
pac(n+1) = pac(n) + (-1)*bit1 + bit0*tabl(i) + tabl(i)/2

   и всё... весь принцип, конечно, без tabl(i) это не сработает,
кстати для эксперимента можете сгенерить её сами, начинается она
с   числа   7,  далее   Xn+1 = Xn * 1,1   (получается   примерно
похоже).  Почему  сразу  с  такого  большого  числа?  Потому что
сжимать  надо  как  минимум  16it сигнал, или пересэмплированный
8bit'ный  сигнал  с  отфильтрованной частотой среза (1/2 частоты
дискретизации).

   А для распаковки имеем:      
                                                                
OUT(0) = сохр. первая выборка сигнала                           
OUT(n+1) = OUT(n) + (-1)*bit1 + bit0*tabl(i) + tabl(i)/2        
if bit0 = 1 then i = i + 2 else i = i - 1              (i>=0!!!)
                                                                
   Вроде, совсем всё...                                         
                                                                
   Кстати,  ADPCM  расшифровывается  как  Adaptive  Differencial
Pulse Code Modulation!     




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Intro - Werewolves вернулся...
Открытые письма Nemo №5.8
Веселуха - Жизнь простого сисадмина И печальна и тосклива если рядом нету пива: Сисадмину посвящается.

В этот день...   24 сентября