представлять 2 выборки sint16s как одну выборку uint32

Мой вопрос связан с этим вопросом, но наоборот.

Разделите UInt32 (аудиокадр) на два SInt16 (левый и верно)?

В приведенной выше ссылке оператор хотел разделить 32-битный кадр на 2 16-битных образца (левый и правый).

У меня есть 2 16-битных образца, и я хотел бы выразить их как один 32-битный чередующийся кадр.

То, что я пробовал до сих пор, выглядит так.

UInt32* ar = malloc(totalFramesInFile * sizeof (ar));

for (int b=0; b < totalFramesInFile; b++)
{
  UInt32 l = soundStructArray[audioFile].audioDataLeft[b];
  UInt32 r = soundStructArray[audioFile].audioDataRight[b];

  UInt32 t = (UInt32) l + r;

  ar[b] = t;
}
soundStructArray[audioFile].audioData = ar;

Это законно и правильно? Я не уверен из-за своей неопытности. Мой аудиовыход звучит немного странно, и я пытаюсь методом исключения определить, что происходит не так.

Было бы полезно, если бы кто-нибудь мог либо подтвердить, что то, что я делаю, - это правильный способ выразить 2 16-битных выборки в виде 32-битного кадра, либо предложить правильный способ.

У меня есть ощущение, что то, что я сделал, неправильно. Я думаю, это потому, что первые 16 бит 32-битного кадра должны быть левыми, а вторые 16 бит — правыми. Все это не должно быть суммой двух..... Я думаю.


person dubbeat    schedule 26.11.2010    source источник
comment
Может быть, ваши образцы l и r должны иметь тип const UInt16?   -  person unwind    schedule 26.11.2010


Ответы (2)


Вам нужно изменить::

UInt32 t = (UInt32) l + r;

to:

UInt32 t = (l << 16) | (r & 0xffff);

Это помещает l в старшие 16 бит t и r в младшие 16 бит.

Подробное объяснение

Если у вас есть два 16-битных семпла, l и r, которые в двоичном виде выглядят так:

l: LLLLLLLLLLLLLLLL
r: RRRRRRRRRRRRRRRR

давайте сначала расширим их до 32 бит:

l: 0000000000000000LLLLLLLLLLLLLLLL
r: 0000000000000000RRRRRRRRRRRRRRRR

Теперь сдвинем l влево на 16 бит (l << 16)

l: LLLLLLLLLLLLLLLL0000000000000000
r: 0000000000000000RRRRRRRRRRRRRRRR

Теперь давайте ИЛИ (|) их вместе:

t: LLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRR

Вуаля! Теперь у вас есть l и r, объединенные в 32-битное значение, из которого их можно легко снова извлечь позже.

person Paul R    schedule 26.11.2010
comment
Это работает, только если у вас есть два беззнаковых 16-битных образца. Отрицательные 16-битные образцы со знаком будут преобразованы в беззнаковые 32-битные числа со всеми старшими 16 битами, равными 1. - person caf; 27.11.2010
comment
@caf: правда - я не использовал маскировку, чтобы сделать пример простым, но, думаю, мне следует добавить его - ответ обновлен сейчас. - person Paul R; 27.11.2010

Я рассмотрю это как дополнение к ответу Пола Р., но это было слишком долго, чтобы комментировать.

Альтернативным решением, которое может быть более «очевидным», является явная установка верхнего или нижнего 16-битного значения в 32-битном значении. Вы можете сделать это с помощью союза, т.е.

typedef union {
    struct {
        SInt16 high;
        SInt16 low;
    } parts;
    UInt32 word;
} IntConverter;

Использование:

IntConverter * ar = malloc(totalFramesInFile * sizeof (IntConverter));

for (int b=0; b < totalFramesInFile; b++)
{
    ar[b].parts.high = soundStructArray[audioFile].audioDataLeft[b];
    ar[b].parts.low = soundStructArray[audioFile].audioDataRight[b];
}
soundStructArray[audioFile].audioData = (UInt32 *) ar;

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

person Christoffer    schedule 26.11.2010
comment
это довольно полезно. Союз для меня новый. Я только когда-либо видел структуру раньше - person dubbeat; 26.11.2010