Skip to content

Commit

Permalink
Adds 24-bit API for projection encoder/decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
jmvalin committed Oct 2, 2024
1 parent 03df13e commit acdc8db
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
75 changes: 75 additions & 0 deletions include/opus_projection.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,44 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode(
opus_int32 max_data_bytes
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);

/** Encodes a projection Opus frame.
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
* @param[in] pcm <tt>const opus_int32*</tt>: The input signal as interleaved
* samples representing (or slightly exceeding) 24-bit values.
* This must contain
* <code>frame_size*channels</code>
* samples.
* @param frame_size <tt>int</tt>: Number of samples per channel in the input
* signal.
* This must be an Opus frame size for the
* encoder's sampling rate.
* For example, at 48 kHz the permitted values
* are 120, 240, 480, 960, 1920, and 2880.
* Passing in a duration of less than 10 ms
* (480 samples at 48 kHz) will prevent the
* encoder from using the LPC or hybrid modes.
* @param[out] data <tt>unsigned char*</tt>: Output payload.
* This must contain storage for at
* least \a max_data_bytes.
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
* memory for the output
* payload. This may be
* used to impose an upper limit on
* the instant bitrate, but should
* not be used as the only bitrate
* control. Use #OPUS_SET_BITRATE to
* control the bitrate.
* @returns The length of the encoded packet (in bytes) on success or a
* negative error code (see @ref opus_errorcodes) on failure.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode24(
OpusProjectionEncoder *st,
const opus_int32 *pcm,
int frame_size,
unsigned char *data,
opus_int32 max_data_bytes
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);


/** Encodes a projection Opus frame from floating point input.
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
Expand Down Expand Up @@ -493,6 +531,43 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode(
int decode_fec
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);

/** Decode a projection Opus packet.
* @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
* @param[in] data <tt>const unsigned char*</tt>: Input payload.
* Use a <code>NULL</code>
* pointer to indicate packet
* loss.
* @param len <tt>opus_int32</tt>: Number of bytes in payload.
* @param[out] pcm <tt>opus_int32*</tt>: Output signal, with interleaved
* samples representing (or slightly exceeding) 24-bit values.
* This must contain room for
* <code>frame_size*channels</code>
* samples.
* @param frame_size <tt>int</tt>: The number of samples per channel of
* available space in \a pcm.
* If this is less than the maximum packet duration
* (120 ms; 5760 for 48kHz), this function will not be capable
* of decoding some packets. In the case of PLC (data==NULL)
* or FEC (decode_fec=1), then frame_size needs to be exactly
* the duration of audio that is missing, otherwise the
* decoder will not be in the optimal state to decode the
* next incoming packet. For the PLC and FEC cases, frame_size
* <b>must</b> be a multiple of 2.5 ms.
* @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
* forward error correction data be decoded.
* If no such data is available, the frame is
* decoded as if it were lost.
* @returns Number of samples decoded on success or a negative error code
* (see @ref opus_errorcodes) on failure.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode24(
OpusProjectionDecoder *st,
const unsigned char *data,
opus_int32 len,
opus_int32 *pcm,
int frame_size,
int decode_fec
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);

/** Decode a projection Opus packet with floating point output.
* @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
Expand Down
66 changes: 66 additions & 0 deletions src/mapping_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,72 @@ void mapping_matrix_multiply_channel_out_short(
}
}

void mapping_matrix_multiply_channel_in_int24(
const MappingMatrix *matrix,
const opus_int32 *input,
int input_rows,
opus_res *output,
int output_row,
int output_rows,
int frame_size)
{
/* Matrix data is ordered col-wise. */
opus_int16* matrix_data;
int i, col;

celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);

matrix_data = mapping_matrix_get_data(matrix);

for (i = 0; i < frame_size; i++)
{
opus_val64 tmp = 0;
for (col = 0; col < input_rows; col++)
{
tmp +=
matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
(opus_val64)input[MATRIX_INDEX(input_rows, col, i)];
}
#if defined(FIXED_POINT)
output[output_rows * i] = INT24TORES((tmp + 16384) >> 15);
#else
output[output_rows * i] = INT24TORES((1/(32768.f))*tmp);
#endif
}
}

void mapping_matrix_multiply_channel_out_int24(
const MappingMatrix *matrix,
const opus_res *input,
int input_row,
int input_rows,
opus_int32 *output,
int output_rows,
int frame_size)
{
/* Matrix data is ordered col-wise. */
opus_int16* matrix_data;
int i, row;
opus_int32 input_sample;

celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);

matrix_data = mapping_matrix_get_data(matrix);

for (i = 0; i < frame_size; i++)
{
input_sample = RES2INT24(input[input_rows * i]);
for (row = 0; row < output_rows; row++)
{
opus_int64 tmp =
(opus_int64)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] *
input_sample;
output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15;
}
}
}


const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 };
const opus_int16 mapping_matrix_foa_mixing_data[36] = {
16384, 0, -16384, 23170, 0, 0, 16384, 23170,
Expand Down
20 changes: 20 additions & 0 deletions src/mapping_matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ void mapping_matrix_multiply_channel_out_short(
int frame_size
);


void mapping_matrix_multiply_channel_in_int24(
const MappingMatrix *matrix,
const opus_int32 *input,
int input_rows,
opus_res *output,
int output_row,
int output_rows,
int frame_size
);

void mapping_matrix_multiply_channel_out_int24(
const MappingMatrix *matrix,
const opus_res *input,
int input_row,
int input_rows,
opus_int32 *output,
int output_rows,
int frame_size
);
/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics.
* foa: first-order ambisonics
* soa: second-order ambisonics
Expand Down
30 changes: 30 additions & 0 deletions src/opus_projection_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ static void opus_projection_copy_channel_out_short(
src_stride, short_dst, dst_stride, frame_size);
}

static void opus_projection_copy_channel_out_int24(
void *dst,
int dst_stride,
int dst_channel,
const opus_res *src,
int src_stride,
int frame_size,
void *user_data)
{
opus_int32 *short_dst;
const MappingMatrix *matrix;
short_dst = (opus_int32 *)dst;
matrix = (const MappingMatrix *)user_data;
if (dst_channel == 0)
OPUS_CLEAR(short_dst, frame_size * dst_stride);

if (src != NULL)
mapping_matrix_multiply_channel_out_int24(matrix, src, dst_channel,
src_stride, short_dst, dst_stride, frame_size);
}

static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st)
{
/* void* cast avoids clang -Wcast-align warning */
Expand Down Expand Up @@ -224,6 +245,15 @@ int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
get_dec_demixing_matrix(st));
}

int opus_projection_decode24(OpusProjectionDecoder *st, const unsigned char *data,
opus_int32 len, opus_int32 *pcm, int frame_size,
int decode_fec)
{
return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
pcm, opus_projection_copy_channel_out_int24, frame_size, decode_fec, 0,
get_dec_demixing_matrix(st));
}

#ifndef DISABLE_FLOAT_API
int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data,
opus_int32 len, float *pcm, int frame_size, int decode_fec)
Expand Down
23 changes: 23 additions & 0 deletions src/opus_projection_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ static void opus_projection_copy_channel_in_short(
(const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size);
}

static void opus_projection_copy_channel_in_int24(
opus_res *dst,
int dst_stride,
const void *src,
int src_stride,
int src_channel,
int frame_size,
void *user_data
)
{
mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data,
(const opus_int32*)src, src_stride, dst, src_channel, dst_stride, frame_size);
}

static int get_order_plus_one_from_channels(int channels, int *order_plus_one)
{
int order_plus_one_;
Expand Down Expand Up @@ -392,6 +406,15 @@ int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm,
max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st));
}

int opus_projection_encode24(OpusProjectionEncoder *st, const opus_int32 *pcm,
int frame_size, unsigned char *data,
opus_int32 max_data_bytes)
{
return opus_multistream_encode_native(get_multistream_encoder(st),
opus_projection_copy_channel_in_int24, pcm, frame_size, data,
max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st));
}

#ifndef DISABLE_FLOAT_API
int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm,
int frame_size, unsigned char *data,
Expand Down

0 comments on commit acdc8db

Please sign in to comment.