I am receiving packets of binary data encoding audio samples as 24bit unsigned integers. These need to be converted to 32bit signed (2's complement) integers for output.
However, due to the way the data is chunked, it is possible that a 24bit word be split across a packet boundary. I am therefore buffering each byte as an 8bit unsigned integer, ready to be recast in groups of 3 (+ 1byte of zero-padding) when all packets have been received.
I have written the following function to do this, where input
is a 1x3 array of type uint8
:
% This function takes 3 8-bit decimal values as input and converts them to
% a single, signed, 32 bit decimal number.
% NOTE - little endianness is assumed
function output = convert24bitTo32bit(input)
sign = bitget(input(3), 8); % get sign bit
bytes(3) = bitset(input(3), 8, 0); % zero sign bit
value = typecast([bytes, uint8(0)], 'int32') - logical(sign)*(2^23);
end
An example can be run using the below snippets:
% Test 255: 11111111 00000000 00000000
input = uint8([255 0 0]);
output = convert24bitTo32bit(input);
fprintf('\n In: 255 \t Out: %d', output)
% Test -2: 01111111 11111111 11111111
input = uint8([254 255 255]);
output = convert24bitTo32bit(input);
fprintf('\n In: -2 \t Out: %d', output)
This function does the job, but is the slowest process in my processing by several orders of magnitude.
Is there a more efficient way to achieve the same result? Or a built-in Matlab function that can handle more esoteric data type conversions?
Thanks
I would work as follows:
Fill your uint8
buffer with as many contiguous 3-byte values as you can:
data = uint8([255 0 0 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3]);
Reshape the matrix into a 3xN matrix (note no data copy happens):
data = reshape(data,3,[]);
Add the zero bytes (this is where a copy happens):
data = [data;zeros(1,size(data,2),'uint8')];
Cast the matrix to int32
:
data = typecast(data(:),'int32');
You seem to do some additional tweaking with the sign bit. I think that what you need to do there is pad not with a zero byte, but with a 0 or 255 byte, depending on the sign of the third byte. Step 3 then becomes:
sign = bitget(data(3:3:end),8);
sign = uint8(sign*255);
data = [data;sign,'uint8')];
[Note I have not actually run the code above, please let me know if I made a typo somewhere!]