Главная » Программирование звука » MPEG-кодирование стереозвука

0

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

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

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

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

B  MPEG  Layer  3  добавлен  еще  режим  MS-cmepeo  -промежуточный  вариант между  вышеописанными  методами.  По  сути,  при  использовании  этого  метода  отдельные левый и правый каналы преобразуются в средний канал (то есть в сумму исходных)  и  боковой  (их  разность).  При  декодировании  для  получения  значений левого  канала  к  среднему  каналу  прибавляется  боковой,  а  для  получения  значений  правого  канала  боковой  вычитается.  Преимущество  данной  схемы  заключается в том, что для записи бокового канала не требуется большой точности.

При  кодировании  MPEG  Layer  I  в  каждом  фрейме  записывается  12  групп  из

32 отсчетов поддиапазонов. Для записи каждого отсчета требуется от 2 до 15 бит.

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

Первый   уровень   предусматривает   хранение   распределения   и   коэффициентов усиления   в   абсолютной   форме.   Значения   распределения   записываются   в   виде последовательностей   4-битных   величин,   а   масштабные   коэффициенты     в   виде последовательностей 6-битных величин.

Листинг 14.19. Декодирование фрейма Layer 1

void DecompressMpeg::LayerlDecode() {

int allocation[2][32];          // Один  для каждого канала

// и  поддиапазона.

ResetBits();

int scaleFactor[2][32];        // Один  для каждого канала

// и  поддиапазона.

long sbSamples[2][32];          // Отсчеты.

for(int gr=0;gr<12;gr++) {     // Читаем  12 групп  отсчетов. if(_channels == 1) {

} else {                     // Стерео.

}

}

}

Хранение распределения в Layer 1

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

Чтобы   в   потоке   битов   не   появлялись   ложные   синхрогруппы,   распределение никогда   не   бывает   выражено   числом,   представляемым   последовательностью   одних единиц.

Листинг 14.20. Чтение значений распределения Layer 1

if(_channels == 1) {

// Для  монозаписи хранится  одно значение  распределения

// для  каждого

// поддиапазона.

for(int sb=0;sb<32;sb++)

allocation[0][sb] = GetBits(4);

} else { // Стереозапись слегка  сложнее.

// Получаем независимые  распределения для диапазона

// с  полной записью стерео. int sb;

for(sb=0;sb<_bound;sb++) { allocation[0][sb] = GetBits(4); allocation[1][sb] = GetBits(4);

}

// Получаем объединенное распределение  для диапазонов

// интенсивности стерео.

for(;sb<32;sb++) { allocation[0][sb] = GetBits(4); allocation[1][sb] = allocation[0][sb];

}

}

Масштабные коэффициенты в Layer 1

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

Листинг 14.21. Чтение масштабных коэффициентов Layer 1

{

for(int sb=0; sb<32; sb++)

for(int ch=0; ch<_channels; ch++)

if(allocation[ch][sb] != 0) {

scaleFactor[ch][sb] = GetBits(6);

}

}

Хранение отсчетов в Layer 1

После   получения   величины   распределения   и   масштабного   коэффициента,

сложностей с чтением отсчетов поддиапазона не возникнет. Величина распределения

показывает, сколько битов отведено на один отсчет. Нулевое распределение свидетельствует о том, что ни одного бита отсчета не записано. Распределение, величина которого лежит в диапазоне от 1 до 14, показывает, что для записи одного значения отводится от 2 до 15 бит. Распределение не может принимать значение 15, поскольку в противном случае не исключено появление ложных синхрогрупп.

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

После того как будет подготовлена группа из 32 отсчетов поддиапазона, необ-

ходимо провести синтез поддиапазона и воссоздать 32 отсчета ИКМ.

Листинг 14.22. Чтение и декодирование отсчетов поддиапазонов монозаписи Layer 1

for(int sb=0;sb<32;sb++)    // Считываем группу из  32 отсчетов. if(!allocation[0][sb])   // Отсутствуют  биты?

sbSamples[0][sb] = 0;

else {

int width = allocation[0][sb]+1;

long s = GetBits(width);

// Передискретизация

// и  масштабирование этого  отсчета. sbSamples[0][sb] = Layer1Requant(s, width,

scaleFactor[0][sb]);

} Layerl2Synthesis(_V[0],sbSamples[0],32,_pcmSamples[0]);

_pcmSamples[0] += 32;

_samplesRemaining += 32;

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

Листинг 14.23. Чтение и декодирование отсчетов поддиапазонов стереозаписи Layer 1

{ // Получаем отсчеты  для  поддиапазонов с  полной записью  стерео. for(int sb=0;sb<_bound;sb++)

for(int ch=0;ch<2;ch++)

if(!allocation[ch][sb])

sbSamples[ch][sb] = 0;

else {

int width = allocation[ch][sb]+l;

long s = GetBits(width);

// Передискретизация и  масштабирование

// полученных  значений.

sbSamples[ch][sb] = Layer1Requant(s, width, scaleFactor[ch][sb]);

}

}

{           // Получаем  общие   отсчеты для поддиапазонов,

// использующих  интенсивность  стерео. for(int sb=0;sb<_bound;sb++) {

if( !allocation[0] [sb])

sbSamples[0][sb] = 0;

else {

int width = allocation[0][sb]+l;

long s = GetBits(width);

// Передискретизация и  масштабирование  отсчета

// для  каждого канала.

sbSamples[0][sb] = LayerlRequant(s, width, scaleFactor[0][sb]);

sbSamples[1][sb] = LayerlRequant(s, width, scaleFactor[1][sb]);

// A теперь  реконструируем каждый   из каналов.

for(int ch=0;ch<_channels;ch++) { Layer12Synthesis(_V[ch],sbSamples[ch],32,_pcmSamples[ch]);

_pcmSamples[ch] += 32;

}

_samplesRemaining += 32;

}

}

}

Передискретизация и масштабирование в Layer 1

Передискретизацией   называется   процесс   преобразования   коротких   (занимающих  от  2  до  15  бит)  отсчетов  в  значение  одного  вида.  Приведенная  ниже  программа преобразует отсчеты к 16-битным значениям со знаком.

Операция   передискретизации   отображает   всевозможные   n-битные   коды   отсчетов в набор расположенных на равных расстояниях друг от друга чисел, лежащих в диапазоне от -1 до +1. Например, в трех битах может быть записано 7 кодов  (коды,  полностью  составленные  из  единиц,  использовать  нельзя,  чтобы  не вызвать  появление  ложной  синхрогруппы).  Коды  от  0  до  6  отображены,  соответственно, на -6/7, -4/7, -2/7, 0, 2/7, 4/7 и 6/7.

Листинг 14.24. Функция передискретизации Layer 1

static long *layerlScaleFactors = 0;

// Беззнаковое  число с  фиксированной

// точкой  формата 1.15.

// Возвращаем значение  в  формате 2.16,

// полученное после передискретизации

// и  масштабирования.

inline long LayerlRequant(long sample, int width, int scaleIndex)

{

long levels = (1<<width)-1;

return (layerlScaleFactors[scaleIndex] * (((sample+sample+1 levels)<<15)/levels)

)>>14;

}

Значения масштабных коэффициентов соответствуют экспоненциальной функции.

Листинг 14.13. Инициализация общих переменных Layer 1 и Layer2 (продолжение)

if(!layerlScaleFactors) { layerlScaleFactors = new long[63]; for(int i = 0; i<63;i++) {

layerlScaleFactors[i] = static_cast<long>

(32767.0 * pow(2.0, 1.0 i/3.0));

}

}

Листинг 14.14. Очистка ресурсов MPEG (продолжение)

delete layerlScaleFactors;

layerlScaleFactors = 0;

Концептуально  MPEG  Layer  2  ничем  не  отличается  от  MPEG  Layer  1.  Тем  не менее   формат   Layer   2   позволяет   воспользоваться   дополнительными   возможностями, чтобы уменьшить в итоге число битов:

? в  формате  Layer  2  задействовано  меньше  поддиапазонов  с  малыми  скоростями   передачи   битов.   Это   позволяет   снизить   объем   требуемой   информации о распределении;

? в  отдельном  фрейме  Layer  2  хранятся  три  группы  по  12  отсчетов  и  разре-

шается    использовать    общие    коэффициенты    масштабирования    для    трех групп значений (в Layer 1 содержится только одна группа из 12 отсчетов);

? вместо   независимого   хранения   двоичного   кода   для   каждого   из   отсчетов

поддиапазонов   часть   отсчетов   может   быть   сгруппирована   в   единый   дво-

ичный код.

Структура декодера Layer 2 не похожа на структуру декодера Layer 1. Основное отличие  заключается  в  том,  что  обрабатывается  36  наборов  отсчетов  поддиапазонов. Эти наборы делятся на 3 группы (по 12 штук в каждой), в которых могут быть

различные  масштабные  коэффициенты.  Каждая  группа  из  12  значений  поделена на 4 группы по 3 элемента. Ha рис. 14.1 показано, как наборы отсчетов поддиапазонов собираются в группы по 3 (с целью комбинирования сходных отсчетов) и по 12 (это позволяет им совместно использовать один набор масштабных коэффициентов).

Листинг 14.25. Layer 2: декодирование фрейма

void DecompressMpeg::Layer2Decode() {

int allocation[2][32];   // По  одному для каждого канала

// и  поддиапазона.

ResetBits();

int scaleFactor[3][2][32];// По  одному для каждого канала

// и  поддиапазона.

long sbSamples[3][2][32];       // Три  набора отсчетов

// поддиапазонов.

for(int sf=0;sf<3;sf++) {       // Различные  масштабные

// коэффициенты  для

// каждой  трети.

for(int gr=0;gr<4;gr++) {   // 4 группы отсчетов

// в  каждой трети.

}

}

}

Хранение распределения в Layer 2

Для   хранения   колебаний   в   низкочастотных   поддиапазонах   требуется   большее разрешение,    чем    при    записи    высокочастотных    поддиапазонов    звука.    Поэтому в  формате  Layer  2  обеспечиваются  более  тесные  рамки  распределения  памяти  для высокочастотных   поддиапазонов.   Основываясь   на   информации   о   скорости   передачи   битов   и   частоте   дискретизации   звука,   алгоритмы   Layer   2   определяют   конкретную стратегию хранения информации о распределении памяти.

Например,   при   скорости   передачи   32000   бит   в   секунду   и   частоте   дискретизации   32000   отсчетов   в   секунду   алгоритмы   Layer   2   используют   таблицы   LayerAllocationB2d.   Они   были   взяты   из   таблицы   под   названием   B.2d,   приведенной в   спецификациях   ISO;   подробнее   мы   поговорим   о   них   чуть   позже.   B   соответствии   с   определенной   стратегией   4   бита   используются   с   целью   указания   распределения   для   каждого   из   расположенных   ниже   двух   поддиапазонов,   3   бита     для каждого   из  следующих  десяти,  а  20  старших   поддиапазонов  не  хранятся  вообще. Таким  образом,  для  описания  информации  о  распределении  памяти  в  файле  с  монозапись’ю  понадобилось  бы  всего  38  бит  против  128,  которые  были  бы  нужны,  если бы файл относился к формату Layer 1.

Кроме   того,   значение,   хранящееся   в   качестве   величины   распределения,     не число   битов,   затрачиваемое   для   хранения   каждого   отсчета.   Ha   самом   деле   это ссылка  на  ячейку  в  таблице.  Содержимое  ячеек  упомянутой  таблицы   это  указатели   на   классы   квантования,   о   которых   я   расскажу   ниже.   Важно   отметить,   что, основывая   выбор   стратегии   распределения   памяти   на   скорости   передачи   битов и  используя  ссылки  на  таблицы  вместо  прямых  значений,  компрессор  Layer  2  обладает      большими      возможностями      для      точной     корректировки      потребностей в памяти.

Листинг 14.26. Layer2: таблицы распределения битов

Layer2QuantClass *l2allocationA[] = {0,&l2qc3,&l2qc7,&l2qc15,

&l2qc31,&l2qc63,&l2qcl27,&l2qc255,&l2qc511,&l2qcl023,&l2qc2047,

&l2qc4095,&l2qc8191,&l2qc16383,&l2qc32767,&l2qc65535}; Layer2QuantClass *12allocationB[] =

{0,&l2qc3,&l2qc5,&l2qc7,&l2qc9,

&l2qc15,&l2qc31,&l2qc63,&l2qc127,&l2qc255,&l2qc511,&l2qcl023,&l2qc2047,

&l2qc4095,&l2qc8191,&l2qc65535};

Layer2QuantClass *12allocationC[] = {0,&l2qc3,&l2qc5,&l2qc7,

&l2qc9,&l2qc15,&l2qc31,&l2qc65535};

Layer2QuantClass *l2allocationD[] = {0,&l2qc3,&l2qc5,&l2qc65535}; Layer2QuantClass *l2allocationE[] = {0,&l2qc3,&l2qc5,&l2qc9,

&l2qc15,&l2qc31,&l2qc63,&l2qc127,&l2qc255,&l2qc511,&l2qc1023,&l2qc2047,

&l2qc4095,&l2qc8191,&l2qc16383,&l2qc32767}; Layer2QuantClass *l2allocationF[] =

{0,&l2qc3,&l2qc5,&l2qc7,&l2qc9,

&l2qc15,&l2qc31,&l2qc63,&l2qc127,&l2qc255,&l2qc511,&l2qc1023,&l2qc2047,

&l2qc4095,&l2qc8191,&l2qc16383};

struct Layer2BitAllocationTableEntry {

char _numberBits;

Layer2QuantClass **_quantClasses;

};

// 27 активных  поддиапазонов.

// Для  моно   требуется 88 бит  для  записи  таблицы распределения. Layer2BitAllocationTableEntry Layer2AllocationB2a[32] = {

{ 4, l2allocationA }, { 4, l2allocationA }, { 4, l2allocationA },

{ 4, l2allocationB }, { 4, l2allocationB }, { 4, l2allocationB },

{ 4, l2allocationB }, { 4, l2allocationB }, { 4, l2allocationB },

{ 4, l2allocationB }, { 4, l2allocationB }, { 3, l2allocationC },

{ 3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{ 3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{ 3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{ 3, l2allocationC }, { 3, l2allocationC }, { 2, l2allocationD },

{ 2, l2allocationD }, { 2, l2allocationD }, { 2, l2allocationD },

{ 0,0},  { 0,0},   { 0,0}, { 0,0},    { 0,0}

};

// 30 активных  поддиапазонов.

// Для  моно   требуется 94 бита  для  записи  таблицы распределения.

// Использованы  при   самых   высоких скоростях  передачи. Layer2BitAllocationTableEntry Layer2AllocationB2b[32] = {

{4, l2allocationA }, { 4, l2allocationA }, { 4, l2allocationA },

{4, l2allocationB }, { 4, l2allocationB }, { 4, l2allocationB },

{4, l2allocationB }, { 4, l2allocationB }, { 4, l2allocationB },

{4, l2allocationB }, { 4, l2allocationB }, { 3, l2allocationC },

{3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{3, l2allocationC }, { 3, l2allocationC }, { 3, l2allocationC },

{3, l2allocationC }, { 3, l2allocationC }, { 2, l2allocationD },

{2, l2allocationD }, { 2, l2allocationD }, { 2, l2allocationD ),

{2, l2allocationD }, { 2, l2allocationD }, { 2, l2allocationD },

{ 0,0},  { 0,0}

};

// 7 активных  поддиапазонов.

// Для  моно   требуется 26 бит  для  записи  таблицы распределения.

// Использованы  при   самых   низких скоростях  передачи. Layer2BitAllocationTableEntry Layer2AllocationB2c[32] = {

{ 4, l2allocationE }, { 4, l2allocationE },   { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE },   { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE },

{0,0},{0,0},{0,0},{0,0} , {0,0} , {0,0} , {0,0} , {0,0} ,

{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0} , {0,0} ,

{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},

};

// 11 активных  поддиапазонов.

// Для  моно   требуется 38 бит  для  записи  таблицы распределения.

// Использованы  при   самых   низких скоростях  передачи. Layer2BitAllocationTableEntry Layer2AllocationB2d[32] = {

{ 4, l2allocationE }, { 4, l2allocationE }, { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE }, { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE }, { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE }, { 3, l2allocationE },

{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},

{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},

};

// 30 активных поддиапазонов.

// Для  моно   требуется 7 5 бит  для  записи  таблицы распределения.

// Использованы для  формата MPEG-2 при   низких частотах дискретизации.

Layer2BitAllocationTableEntry Layer2AllocationB1[32] = {

{ 4, l2allocationF }, { 4, l2allocationF }, { 4, l2allocationF },

{ 4, l2allocationF }, { 3, l2allocationE }, { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE }, { 3, l2allocationE },

{ 3, l2allocationE }, { 3, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{ 2, l2allocationE }, { 2, l2allocationE }, { 2, l2allocationE },

{0,0},{0,0}

};

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

Листинг 14.27. Layer 2: считывание величины распределения

// Определяем, какую  карту  распределения использовать. Layer2BitAllocationTableEntry *allocationMap;

long bitRatePerChannel = _bitRate/_charmels;

if(_id==0) // Используем карту  распределения  MPEG-2 allocationMap = Layer2AllocationB1;

else if(bitRatePerChannel <= 48000) {

if(_samplingRate == 32000) allocationMap = Layer2AllocationB2d;

else allocationMap = Layer2AllocationB2c;

} else if (bitRatePerChannel < 96000)

allocationMap = Layer2AllocationB2a;

else if (_samplingRate == 48000)

allocationMap = Layer2AllocationB2a;

else

allocationMap = Layer2AllocationB2b;

// Замечание: заголовок  фрейма устанавливает

// _bound в 0 для  одноканальных записей, поэтому

// предлагаемая  программа корректно  работает

// и  для моно, и  для стерео.

int sblimit=0; // Увеличенный  на   1 номер старшего поддиапазона

// с  непустым распределением.

{              // Получаем отдельные  распределения  для  полных

// стереоподдиапазонов. for(int sb=0;sb<_bound;sb++) {

if(allocationMap[sb]._numberBits) {

allocation[0][sb] = GetBits(allocationMap[sb]._numberBits);

allocation[1][sb] = GetBits(allocationMap[sb]._numberBits);

if( (allocation[0][sb] || allocation[1][sb])

&&(sb >= sblimit) )

sblimit=sb+1;

} else {

allocation[0][sb] = 0;

allocation[1][sb] = 0;

}

}

}

{              // Получаем общее распределение  для  поддиапазонов

// с интенсивностью  стерео. for(int sb=_bound;sb<32;sb++) {

if(allocationMap[sb]._numberBits) {

allocation[0][sb] = GetBits(allocationMap[sb]._numberBits);

if(allocation[0][sb] && (sb >= sblimit))

sblimit=sb+1;

} else

allocation[0][sb] = 0;

allocation[1][sb] = allocation[0][sb];

}

}

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

Масштабные коэффициенты в Layer 2

Layer  1  подразумевает  хранение  одного  набора  масштабных  коэффициентов для каждого фрейма из 384 отсчетов. Поскольку в формате Layer 2 отсчетов втрое больше,  в  нем  используется  ряд  приемов  для  более  экономного  хранения  масштабных коэффициентов.

Один фрейм Layer 2 содержит 36 наборов отсчетов поддиапазона. Иначе говоря, для каждого поддиапазона один фрейм содержит 36 отсчетов. Bo фрейме 1 Layer один  масштабный  коэффициент  применяется  ко  всем  отсчетам  одного  поддиапазона. Так как отсчетов у нас втрое больше, то для Layer 2 предусмотрен вариант сохранения  трех  масштабных  коэффициентов  (одного  для  каждой  группы  по  12), благодаря чему экономится место.

Чтобы  считать  масштабные  коэффициенты,  сначала  извлекается  информация по  их  выбору.  Эти  2-битные  значения  показывают,  как  хранятся  масштабные коэффициенты.  Затем  для  каждого  поддиапазона  вы  считываете  либо  один  масштабный  коэффициент  (который  применяется  ко  всем  36  отсчетам),  либо  два (один применяется к 12, другой к 24 отсчетам), либо три (один на каждую группупо 12).

Листинг 14.28. Layer2: считывание коэффициенты умножения

int scaleFactorSelection[2][32];

{     // Считываем  информацию о  расположении  масштабных

// коэффициентов.

for(int sb=0; sb<sblimit; sb++)

for(int ch=0; ch<_channels; ch++)

if(allocation[ch][sb] != 0)

scaleFactorSelection[ch][sb] = GetBits(2);

}

{

//

Считываем  масштабные  коэффициенты. Массив

//

scaleFactorSelection используется  для того,

//

чтобы определить, какой  коэффициент относится  более  чем

//

к  одной  группе.

for(int sb=0; sb<sblimit; sb++)

for(int ch=0; ch<_channels; ch++)

if(allocation[ch][sb] != 0) {

switch(scaleFactorSelection[ch][sb]) {

case 0: // Три  масштабных  коэффициента.

scaleFactor[0][ch][sb] = GetBits(6); scaleFactor[1][ch][sb] = GetBits(6); scaleFactor[2][ch][sb] = GetBits(6);

break;

case 1: // Один  для  первых двух  частей,

// третий для последней.

scaleFactor[0][ch][sb] = GetBits(6); scaleFactor[1][ch][sb] = scaleFactor[0][ch][sb]; scaleFactor[2][ch][sb] = GetBits(6);

break;

case 2: // Один  для всех  трех.

scaleFactor[0][ch][sb] = GetBits(6); scaleFactor[1][ch][sb] = scaleFactor[0][ch][sb]; scaleFactor[2][ch][sb] = scaleFactor[0][ch][sb]; break;

case 3: // Один  для  первой части,

// один  для  оставшихся двух.

scaleFactor[0][ch][sb] = GetBits(6); scaleFactor[1][ch][sb] = GetBits(6); scaleFactor[2][ch][sb] = scaleFactor[1][ch][sb]; break;

}

}

}

Чтение выборок в Layer 2

Помимо  разбиения  36  наборов  отсчетов  на  тройки  в  целях  выделения  масштабных  коэффициентов  в  формате  Layer  2  также  предусмотрено  объединение  отсчетов в наборы по три. Вместо чтения одного набора из 32 отсчетов поддиапазонов за один раз, как сделано в Layer I, в Layer 2 хранятся три отсчета для каждого поддиапазона. Основная экономия здесь идет за счет группирования.

При  группировании  три  отдельных  отсчета  записываются  в  единое  битовое поле. Например, если вы хотите сохранить три значения в диапазоне от 0 до 4… вместо использования трех бит на каждое значение (в сумме это дает 9 бит) можно    применить    пятеричную    арифметику    для    комбинирования    их    в    одном

7-битном поле.

Если три значения это а, b, и с, то мы сохраняем  значение 25a+5b+c. Для выделения   этих   сгруппированных   величин   необходимо   произвести   последовательное вычисление остатков.

Листинг 14.29. Layer 2: считывание и декодирование отсчетов поддиапазонов

for(int sb=0;sb<sblimit;sb++) {   // Считываем  3 набора из  32

// отсчетов поддиапазонов.

for(int ch=0;ch<_channels;ch++) {

// Если   обрабатывается  поддиапазон интенсивности стерео,

// то  копируем отсчеты. if((sb>=_bound) && (ch == 1)) {

sbSamples[0][1][sb] = sbSamples[0][0][sb]; sbSamples[1][1][sb] = sbSamples[1][0][sb]; sbSamples[2][1][sb] = sbSamples[2][0][sb]; continue;

}

Layer2QuantClass *quantClass

= allocationMap[sb]._quantClasses ?

allocationMap[sb]._quantClasses[

allocation[ch][sb] ]

: 0 ;

if(!allocation[ch][sb]) {   // Отсутствие битов, записываем

// 0 для  каждого значения. sbSamples[0][ch][sb] = 0;

sbSamples[1][ch][sb] = 0;

sbSamples[2][ch][sb] = 0;

} else if (quantClass->_grouping) {    // Сгруппированные

// отсчеты.

long s = GetBits(quantClass->_bits); // Считываем  группы.

// Выделяем

// значения,

// последовательно

// вычисляя  остатки.

sbSamples[0][ch][sb]

= Layer2Requant(s % quantClass->_levels,quantClass, scaleFactor[sf][ch][sb]);

s /= quantClass->_levels;

sbSamples[1][ch][sb]

= Layer2Requant(s % quantClass->_levels,quantClass, scaleFactor[sf][ch][sb]);

s /= quantClass->_levels;

sbSamples[2][ch][sb]

= Layer2Requant(s % quantClass->_levels,quantClass, scaleFactor[sf][ch][sb]);

} else {                    // Несгруппированные  значения.

int width = quantClass->_bits;

long s = GetBits(width); // Первое  значение. sbSamples[0][ch][sb]

= Layer2Requant(s,quantClass,scaleFactor[sf][ch][sb]);

s = GetBits(width);      // Второе  значение.

sbSamples[1][ch][sb]

=

Layer2Requant(s,quantClass,scaleFactor[sf][ch][sb]); s = GetBits(width);     // Третье  значение. sbSamples[2][ch][sb]

=

Layer2Requant(s,quantClass,scaleFactor[sf][ch][sb]);

}

}

}

// A теперь  передаем три набора

// отсчетов  поддиапазонов

// в  модуль синтеза.

for(int ch=0;ch < _channels;ch++) { Layerl2Synthesis(_V[ch],sbSamples[0][ch],sblimit,_pcmSamples[ch]);

_pcmSamples[ch] += 32; Layerl2Synthesis(_V[ch],sbSamples[1][ch],sblimit,_pcmSamples[ch]);

_pcmSamples[ch] += 32; Layerl2Synthesis(_V[ch],sbSamples[2][ch],sblimit,_pcmSamples[ch]);

_pcmSamples[ch] += 32;

}

_samplesRemaining += 96;

Передискретизация в Layer 2

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

Листинг 14.30. Layer 2: таблицы класса квантования

struct Layer2QuantClass {

long _levels;       // Количество  уровней.

char _bits;         // Сколько   битов  надо  прочитать.

bool _grouping;     // Да  -> нужно   разложить на   три выборки.

};

Класс квантования также используется функцией Layer2Requant для передискретизации  каждой  выборки.  Формула  аналогична  той,  которая  применяется функцией Layer1Requant.

Листинг 14.30. Layer 2: таблицы класса квантования (продолжение)

// Возвращает передискретизированное  и  отмасштабированное

// значение  в  формате 2.16.

inline long Layer2Requant(long sample, Layer2QuantClass *quantClass, int scaleIndex) {

long levels = quantClass->_levels;

return (layerlScaleFactors[scaleIndex] * (((sample+sample+1 levels)<<15)/levels)

) >> 14;

}

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

Листинг 14.30. Layer2: таблицы класса квантования (продолжение)

static Layer2QuantClass l2qc3 = {3,5,true}; static Layer2QuantClass l2qc5 = {5,7,true}; static Layer2QuantClass l2qc7 = {7,3,false}; static Layer2QuantClass l2qc9 = {9,10,true}; static Layer2QuantClass l2qcl5 = {15,4,false}; static Layer2QuantClass l2qc31 = {31,5,false}; static Layer2QuantClass l2qc63 = {63,6,false}; static Layer2QuantClass l2qcl27 = {127,7,false}; static Layer2QuantClass l2qc255 = {255,8,false}; static Layer2QuantClass l2qc511 = {511,9,false};

static Layer2QuantClass l2qcl023 = {1023,10,false};

static Layer2QuantClass l2qc2047 = {2047,ll,false}; static Layer2QuantClass l2qc4095 = {4095,12,false}; static Layer2QuantClass l2qc8191 = {8191,13,false}; static Layer2QuantClass l2qcl6383 = {16383,14,false}; static Layer2QuantClass l2qc32767 = {32767,15,false}; static Layer2QuantClass l2qc65535 = {65535,16,false};

Уровень Layer 3

B сравнении с Layer 2 компрессия Layer 3 гораздо сложнее:

?  Layer 3 позволяет варьировать размер фрейма данных. Хотя заголовки всегда расположены на равных расстояниях, связанные с ними данные не обязательно должны находиться только между двумя заголовками. Это способствует тому, что компрессор Layer 3 варьирует размер фрейма в зависимости от подлежащих сжатию данных;

?  Layer 3 использует более сложный способ хранения масштабных коэффи-

циентов: биты выбора масштабного коэффициента могут применяться

к группам масштабных коэффициентов; коды масштабных коэффициентов имеют различную длину для разных поддиапазонов частот;

?  отсчеты сохраняются с использованием кодов Хаффмана (Huffman), что по-

зволяет для записи чаще встречающихся значений использовать меньше би-

тов, чем для записи реже встречающихся;

?  при синтезе звука, записанного в формате Layer 3, используются два  этапа: каждый поддиапазон Layer 2 дополнительно подразделяется на 18 частотных пределов,  отсчеты  могут  группироваться  по-разному  для  разных  поддиапазонов частот.

B  силу  этих  нововведений  декомпрессоры  Layer  3  намного  сложнее  декомпрессоров Layer 2. Поскольку формат Layer 3 достаточно высокоорганизован, очень мало  программ-кодировщиков  в  полной  мере  использует  все  его  преимущества. B  частности,  возможность  варьировать  количество  данных  для  каждого  фрейма требует  оптимизации  требований  к  компрессии  для  нескольких  фреймов  одновременно.

Листинг 14.31. Переменные для декомпрессии Layer 3

private:

void Layer3Decode();

Листинг 14.32. Декодирование фрейма Layer 3

void DecompressMpeg::Layer3Decode() {

// Декомпрессия  MPEG Layer 3 не   поддерживается.

cerr << "I don’t support MPEG Layer 3 decompression.\n";

exit(1);

}

Программа чтения файлов MPEG

Аудиофайлы  MPEG  обычно  состоят  из  аудиопотока  MPEG,  хотя  и  многие другие  форматы  (включая  WAVE)  могут  содержать  данные  MPEG  Чтобы  прочитать  файл,  нам  понадобится,  во-первых,  функция,  способная  проверять  тип  файла, а во-вторых, аудиокласс, конструктор которого работает с istream.

Листинг 14.33. Класс для чтения файла MPEG

bool IsMpegFile(istream &file);

class MpegRead: public AudioAbstract {

private:

istream &_stream; AbstractDecompressor *_decoder;

public:

MpegRead(istream &input = cin);

~MpegRead();

size_t GetSamples(AudioSample *buffer, size_t numSamples);

size_t ReadBytes(AudioByte *buffer, size_t length);

void MinMaxSamplingRate(long *min, long *max, long

*preferred);

void MinMaxChannels(int *min, int *max, int *preferred);

};

MpegRead  это  простой  пример  класса  формата  файлов.  Конструктор  работает  с  потоком  C++  istream,  метод  GetSamples перенаправляет  запросы  к  объeктy _decoder, a ReadBytes извлекает данные из файла.

Листинг 14.3. Программа mpeg.cpp (продолжение)

bool IsMpegFile(istream &file) { file.seekg(0); // B начало файла. long magic = ReadIntMsb(file,2);

if ((magic & 0xFFF0) == 0xFFF0) return true;

else return false;

}

MpegRead::MpegRead(istream &input):AudioAbstract(),_stream(input)

{

// Формат   файла: MPEG

cerr << "File Format: MPEG\n";

_decoder = new DecompressMpeg(*this);

}

MpegRead::~MpegRead() {

if (_decoder) delete _decoder;

}

size_t MpegRead::GetSamples(AudioSample *buffer, size_t numSamples) {

return _decoder->GetSamples(buffer,numSamples);

}

size_t MpegRead::ReadBytes(AudioByte *buffer, size_t length) {

_stream.read(reinterpret_cast<char *>(buffer),length);

return _stream.gcount();

}

void MpegRead::MinMaxChannels(int *min, int *max, int *preferred)

{

_decoder->MinMaxChannels(min, max, preferred);

}

void MpegRead::MinMaxSamplingRate(long *min, long *max, long

*preferred) {

_decoder->MinMaxSamplingRate(min, max, preferred);

}

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

По теме:

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