2010-11-26 1 views
1

Вопрос, связанный с этим вопросом, но он обратный.представляют 2 образца sint16s в качестве одного образца uint32

Split UInt32 (audio frame) into two SInt16s (left and right)?

В ссылке выше оп хотел разделить 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 бит должны быть правыми. Все это не должно быть суммой двух ... я думаю.

+0

Возможно, ваши образцы l и r должны иметь тип const UInt16? – unwind 2010-11-26 08:57:31

ответ

4

Вы должны изменить ::

UInt32 t = (UInt32) l + r; 

к:

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: LLLLLLLLLLLLLLLL0000000000000000 
r: 0000000000000000RRRRRRRRRRRRRRRR 

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

t: LLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRR 

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

+1

отличное объяснение! – dubbeat 2010-11-26 09:03:16

+0

Это работает только при наличии двух * неподписанных * 16-разрядных образцов. Отрицательные, подписанные 16-битные сэмплы будут конвертировать в беззнаковые 32-разрядные номера со всеми верхними 16 битами, равными `1`. – caf 2010-11-27 07:36:20

2

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

Альтернативное решение, которое может быть более «очевидным», явно устанавливает верхние или нижние 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; 

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