Я понимаю, что данные PCM хранятся как [left][right][left][right]...
, Я пытаюсь преобразовать стерео PCM в моно Vorbis (* .ogg), что, как я понимаю, достижимо путем деления левого и правого каналов вдвое ((левый + правый) * 0,5). На самом деле я добился этого, внеся изменения в пример кодировщика в libvorbis SDK следующим образом:
#define READ 1024
signed char readbuffer[READ*4];
и данные PCM читаются таким образом
fread(readbuffer, 1, READ*4, stdin)
Затем я разделил пополам два канала,
buffer[0][i] = ((((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))/32768.f) + (((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))/32768.f)) * 0.5f;
Это сработало отлично, но я не понимаю, как они перемежают левый и правый канал от данных PCM (то есть все битовые сдвиги и «И» и «ИЛИ»).
Файл .wav обычно хранит свои данные PCM в немного порядковый номер формат, с 16 битами на выборку на канал. Для обычного подписанного 16-битного файла PCM это означает, что данные физически хранятся как
[LEFT LSB] [LEFT MSB] [RIGHT LSB] [RIGHT MSB] ...
так что каждая группа из 4 байтов составляет одну выборку стерео ИКМ. Следовательно, вы можете найти образец i
глядя на байты 4*i
через 4*i+3
включительно.
Чтобы декодировать одно 16-битное значение из двух байтов, вы делаете это:
(MSB << 8) | LSB
Потому что ваши значения буфера чтения хранятся как подписанный Вы должны быть немного осторожны, потому что оба MSB
а также LSB
будет продлен знак Это нежелательно для LSB; поэтому код использует
0xff & (int)LSB
чтобы получить беззнаковую версию младшего байта (технически это работает путем выгрузки до int и выбора младших 8 битов; альтернативной формулировкой будет просто записать (uint8_t)LSB
).
Обратите внимание, что MSB имеют индексы 1 и 3, а LSB имеют индексы 0 и 2. Итак,
((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))
а также
((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))
просто получают значения левого и правого каналов в виде 16-битных значений со знаком, используя некоторые битовые манипуляции для сборки байтов в числа.
Затем каждое из этих значений делится на 32768,0. Обратите внимание, что 16-разрядное значение со знаком имеет диапазон [-32768, 32767]
, Таким образом, деление на 32768 дает диапазон приблизительно [-1, 1]. Два разделенных значения добавляются, чтобы получить число в диапазоне [-2, 2], а затем все умножается на 0,5, чтобы получить среднее значение (значение с плавающей запятой в диапазоне [-1, 1]).