Главная » Программирование звука » Два вида ДИКМ-кодирования

0

Сложная  и  увлекательная  задача,  возникающая  в  процессе  разработки  качественной  ДИКМ-технологии,  представляет   собой  балансирование   между  двумя требованиями.  Чтобы  ваш  алгоритм  сохранял  звуки  максимально  точно,  необходимо  иметь  возможность  точно  записывать  каждое  из  приращений,  в  особенности,  небольшие.  Однако,  поскольку  потенциально  возможные  величины  занимают больший  диапазон,  вам,  вероятно,  понадобится  сохранять  иногда  встречающиеся большие  приращения.  Обычно  это  означает,  что  такое  приращение  само  по  себе закодировано. B табл. 12.1. в качестве примера приведены коды, используемые

двумя  методами  компрессии,  разработанными  для  компьютера  Amiga.  Каждая  из этих   схем   позволяет   перейти   от   записи   8-битных   моментальных   значений к записи 4-битных кодированных приращений.

Таблица 12.1. Кодированные приращения для алгоритмов компрессии IFF/8SVX

типа 1 и типа 2

Значение кода

-8

-7

-6

-5

-4

-3

-2

-1

0

1

2

3

4

5

6

7

Фибоначчи

-34

-21

-13

-8

-5

-3

-2

-1

0

1

2

3

5

8

13

21

Экспоненциальное

-128

-64

-32

-16

-8

-4

-2

-1

0

1

2

4

8

16

32

64

Обратите   внимание,   что   при   задействовании   обеих   кодировок   получается множество  маленьких  значений  (в  целом,  небольшие  приращения  встречаются  гораздо чаще) и отдельные большие значения.

B  частности,  отметим,  что  показанное  в  этой  таблице  экспоненциальное  кодирование   (использующее   степени   числа   2),   по   своей   концепции   аналогично шаговой   таблице   в   более   изощренном   алгоритме   кодирования   IMA   ADPCM (в   котором   применяются   степени   числа   1.1;   подробнее   о   нем   рассказывается в главе 13).

Листинг 12.1. Программа dpcm.h

#ifndef DPCM_H_INCLUDED

#define DPCM_H_INCLUDED

#include "audio.h"

#include "compress.h"

class DecompressDpcmFibonacci: public AbstractDecompressor {

private:

AudioSample _previousValue;

public:

DecompressDpcmFibonacci(AudioAbstract &a): AbstractDecompressor(a) {

// Кодировка: ДИКМ  Фибоначчи.

cerr << "Encoding: Fibonacci Dpcm\n";

_previousValue = 0;

};

size_t GetSamples(AudioSample * buffer, size_t length);

};

class DecompressDpcmExponential: public AbstractDecompressor {

private:

AudioSample _previousValue;

public:

DecompressDpcmExponential(AudioAbstract &a): AbstractDecompressor(a) {

// Кодировка: экспоненциальная  ДИКМ.

cerr << "Encoding: Exponential Dpcm\n";

_previousValue = 0;

};

size_t GetSamples(AudioSample * buffer, size_t length);

};

#endif

Листинг 12.2. Программа dpcm.cpp

#include "audio.h"

#include "compress.h"

#include "dpcm.h"

static const signed char fibonacci[] = {

-34, 21, 13, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,

13, 21

};

static const signed char exponential[] = {

-128, 64, 32, 16, 8, 4, 2, 1, 0, 1, 2, 4, 8, 16,

32, 64

};

Процесс  непосредственно  декомпрессии  прост.  Для  каждого  полубайта  мы  находим  декодированный  инкремент  в  таблице  и  добавляем  его  к  _previousValue, что дает нам очередной отсчет. C целью оптимизации этой процедуры считывание сжатых данных производится в конец предусмотренного буфера, после чего осуществляется преобразование данных на месте. Сжатые данные необходимо считывать в конец буфера, чтобы они не затирались ходе конвертации. Кроме того, отметим, что поскольку  аппаратное  обеспечение  компьютеров  Amiga  может  обрабатывать  только 8-битные отсчеты, все процедуры компрессии для этого формата настроены на работу с 8-битными величинами. Перед сложением мне пришлось сдвигать приращения в область старшего байта.

Листинг 12.3. Метод GetSamples для ДИКМ с кодировкой Фибоначчи

size_t DecompressDpcmFibonacci::GetSamples(AudioSample * buffer, size_t length) {

AudioByte *byteBuffer =

reinterpret_cast<AudioByte *>(buffer)

+ length * sizeof(AudioSample) // Длина   буфера.

length / 2 ;            // Необходимое  для  хранения

// кодированных  данных место.

AudioSample *sampleBuffer = buffer;

// Считываем закодированные  данные в  буфер.

size_t bytesRead = ReadBytes(byteBuffer,length/2);

for(size_t i=0; i<bytesRead; i++) {

// Декодируем  младший   полубайт.

int nybble = (static_cast<int>(*byteBuffer>>4)+8)&0xF;

_previousValue +=

static_cast<AudioSample>(fibonacci[nybble])

<< ((sizeof(AudioSample)-1)*8);

*sampleBuffer++ = _previousValue;

// Декодируем  старший  полубайт.

nybble = (static_cast<int>(*byteBuffer)+8)&0xF;

_previousValue +=

static_cast<AudioSample>(fibonacci[nybble])

<< ((sizeof(AudioSample)-1)*8);

*sampleBuffer++ = _previousValue;

}

return bytesRead * 2;

}

Декодер   для   экспоненциальной   ДИКМ   идентичен   рассмотренному   ранее,   за

исключением того, что он использует другую таблицу.

Листинг 12.4. Метод GetSamples для ДИКМ с экспоненциальной кодировкой

size_t DecompressDpcmExponential::GetSamples(AudioSample *

buffer,

size_t length) { AudioByte *byteBuffer =

reinterpret_cast<AudioByte *>(buffer)

+ length * sizeof(AudioSample) // Длина   буфера.

length / 2 ;                 // Необходимое место  для

// закодированных  данных.

AudioSample *sampleBuffer = buffer;

// Считываем закодированные  данные в  буфер.

size_t bytesRead = ReadBytes(byteBuffer,length/2);

for(size_t i=0; i<bytesRead; i++) {

// Декодируем  младший   полубайт.

int nybble = (static_cast<int>(*byteBuffer>>4)+8)&0xF;

_previousValue +=

static_cast<AudioSample>(exponential[nybble])

<< ((sizeof(AudioSample)-1)*8);

*sampleBuffer++ = _previousValue;

// Декодируем  старший  полубайт.

nybble = (static_cast<int>(*byteBuffer)+8)&0xF;

_previousValue +=

static_cast<AudioSample>(exponential[nybble])

<< ((sizeof(AudioSample)-1)*8);

*sampleBuffer++ = _previousValue;

}

return bytesRead * 2;

}

Источник: Кинтцель Т.  Руководство программиста по работе со звуком = A Programmer’s Guide to Sound: Пер. с англ. М.: ДМК Пресс, 2000. 432 с, ил. (Серия «Для программистов»).

По теме:

  • Комментарии