bluez/sbc/sbc.c
Siarhei Siamashka 213aff750a sbc: faster 'sbc_calculate_bits' function
By using SBC_ALWAYS_INLINE trick, the implementation of 'sbc_calculate_bits'
function is split into two branches, each having 'subband' variable value
known at compile time. It helps the compiler to generate more optimal code
by saving at least one extra register, and also provides more obvious
opportunities for loops unrolling.

Benchmarked on ARM Cortex-A8:

== Before: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m3.989s
user    0m3.602s
sys     0m0.391s

samples  %        image name               symbol name
26057    32.6128  sbcenc                   sbc_pack_frame
20003    25.0357  sbcenc                   sbc_analyze_4b_8s_neon
14220    17.7977  sbcenc                   sbc_calculate_bits
8498     10.6361  no-vmlinux               /no-vmlinux
5300      6.6335  sbcenc                   sbc_calc_scalefactors_j_neon
3235      4.0489  sbcenc                   sbc_enc_process_input_8s_be_neon
2172      2.7185  sbcenc                   sbc_encode

== After: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m3.652s
user    0m3.195s
sys     0m0.445s

samples  %        image name               symbol name
26207    36.0095  sbcenc                   sbc_pack_frame
19820    27.2335  sbcenc                   sbc_analyze_4b_8s_neon
8629     11.8566  no-vmlinux               /no-vmlinux
6988      9.6018  sbcenc                   sbc_calculate_bits
5094      6.9994  sbcenc                   sbc_calc_scalefactors_j_neon
3351      4.6044  sbcenc                   sbc_enc_process_input_8s_be_neon
2182      2.9982  sbcenc                   sbc_encode
2010-07-02 16:02:10 -03:00

1229 lines
31 KiB
C

/*
*
* Bluetooth low-complexity, subband codec (SBC) library
*
* Copyright (C) 2008-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
* Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/* todo items:
use a log2 table for byte integer scale factors calculation (sum log2 results
for high and low bytes) fill bitpool by 16 bits instead of one at a time in
bits allocation/bitpool generation port to the dsp
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <limits.h>
#include "sbc_math.h"
#include "sbc_tables.h"
#include "sbc.h"
#include "sbc_primitives.h"
#define SBC_SYNCWORD 0x9C
/* This structure contains an unpacked SBC frame.
Yes, there is probably quite some unused space herein */
struct sbc_frame {
uint8_t frequency;
uint8_t block_mode;
uint8_t blocks;
enum {
MONO = SBC_MODE_MONO,
DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL,
STEREO = SBC_MODE_STEREO,
JOINT_STEREO = SBC_MODE_JOINT_STEREO
} mode;
uint8_t channels;
enum {
LOUDNESS = SBC_AM_LOUDNESS,
SNR = SBC_AM_SNR
} allocation;
uint8_t subband_mode;
uint8_t subbands;
uint8_t bitpool;
uint16_t codesize;
uint8_t length;
/* bit number x set means joint stereo has been used in subband x */
uint8_t joint;
/* only the lower 4 bits of every element are to be used */
uint32_t SBC_ALIGNED scale_factor[2][8];
/* raw integer subband samples in the frame */
int32_t SBC_ALIGNED sb_sample_f[16][2][8];
/* modified subband samples */
int32_t SBC_ALIGNED sb_sample[16][2][8];
/* original pcm audio samples */
int16_t SBC_ALIGNED pcm_sample[2][16*8];
};
struct sbc_decoder_state {
int subbands;
int32_t V[2][170];
int offset[2][16];
};
/*
* Calculates the CRC-8 of the first len bits in data
*/
static const uint8_t crc_table[256] = {
0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
};
static uint8_t sbc_crc8(const uint8_t *data, size_t len)
{
uint8_t crc = 0x0f;
size_t i;
uint8_t octet;
for (i = 0; i < len / 8; i++)
crc = crc_table[crc ^ data[i]];
octet = data[i];
for (i = 0; i < len % 8; i++) {
char bit = ((octet ^ crc) & 0x80) >> 7;
crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
octet = octet << 1;
}
return crc;
}
/*
* Code straight from the spec to calculate the bits array
* Takes a pointer to the frame in question, a pointer to the bits array and
* the sampling frequency (as 2 bit integer)
*/
static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
const struct sbc_frame *frame, int (*bits)[8], int subbands)
{
uint8_t sf = frame->frequency;
if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
int ch, sb;
for (ch = 0; ch < frame->channels; ch++) {
max_bitneed = 0;
if (frame->allocation == SNR) {
for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
} else {
for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
if (loudness > 0)
bitneed[ch][sb] = loudness / 2;
else
bitneed[ch][sb] = loudness;
}
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
}
bitcount = 0;
slicecount = 0;
bitslice = max_bitneed + 1;
do {
bitslice--;
bitcount += slicecount;
slicecount = 0;
for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
slicecount += 2;
}
} while (bitcount + slicecount < frame->bitpool);
if (bitcount + slicecount == frame->bitpool) {
bitcount += slicecount;
bitslice--;
}
for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2)
bits[ch][sb] = 0;
else {
bits[ch][sb] = bitneed[ch][sb] - bitslice;
if (bits[ch][sb] > 16)
bits[ch][sb] = 16;
}
}
for (sb = 0; bitcount < frame->bitpool &&
sb < subbands; sb++) {
if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
bits[ch][sb]++;
bitcount++;
} else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
bits[ch][sb] = 2;
bitcount += 2;
}
}
for (sb = 0; bitcount < frame->bitpool &&
sb < subbands; sb++) {
if (bits[ch][sb] < 16) {
bits[ch][sb]++;
bitcount++;
}
}
}
} else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
int ch, sb;
max_bitneed = 0;
if (frame->allocation == SNR) {
for (ch = 0; ch < 2; ch++) {
for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
}
} else {
for (ch = 0; ch < 2; ch++) {
for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
if (loudness > 0)
bitneed[ch][sb] = loudness / 2;
else
bitneed[ch][sb] = loudness;
}
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
}
}
bitcount = 0;
slicecount = 0;
bitslice = max_bitneed + 1;
do {
bitslice--;
bitcount += slicecount;
slicecount = 0;
for (ch = 0; ch < 2; ch++) {
for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
slicecount += 2;
}
}
} while (bitcount + slicecount < frame->bitpool);
if (bitcount + slicecount == frame->bitpool) {
bitcount += slicecount;
bitslice--;
}
for (ch = 0; ch < 2; ch++) {
for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2) {
bits[ch][sb] = 0;
} else {
bits[ch][sb] = bitneed[ch][sb] - bitslice;
if (bits[ch][sb] > 16)
bits[ch][sb] = 16;
}
}
}
ch = 0;
sb = 0;
while (bitcount < frame->bitpool) {
if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
bits[ch][sb]++;
bitcount++;
} else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
bits[ch][sb] = 2;
bitcount += 2;
}
if (ch == 1) {
ch = 0;
sb++;
if (sb >= subbands)
break;
} else
ch = 1;
}
ch = 0;
sb = 0;
while (bitcount < frame->bitpool) {
if (bits[ch][sb] < 16) {
bits[ch][sb]++;
bitcount++;
}
if (ch == 1) {
ch = 0;
sb++;
if (sb >= subbands)
break;
} else
ch = 1;
}
}
}
static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
{
if (frame->subbands == 4)
sbc_calculate_bits_internal(frame, bits, 4);
else
sbc_calculate_bits_internal(frame, bits, 8);
}
/*
* Unpacks a SBC frame at the beginning of the stream in data,
* which has at most len bytes into frame.
* Returns the length in bytes of the packed frame, or a negative
* value on error. The error codes are:
*
* -1 Data stream too short
* -2 Sync byte incorrect
* -3 CRC8 incorrect
* -4 Bitpool value out of bounds
*/
static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
size_t len)
{
unsigned int consumed;
/* Will copy the parts of the header that are relevant to crc
* calculation here */
uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int crc_pos = 0;
int32_t temp;
int audio_sample;
int ch, sb, blk, bit; /* channel, subband, block and bit standard
counters */
int bits[2][8]; /* bits distribution */
uint32_t levels[2][8]; /* levels derived from that */
if (len < 4)
return -1;
if (data[0] != SBC_SYNCWORD)
return -2;
frame->frequency = (data[1] >> 6) & 0x03;
frame->block_mode = (data[1] >> 4) & 0x03;
switch (frame->block_mode) {
case SBC_BLK_4:
frame->blocks = 4;
break;
case SBC_BLK_8:
frame->blocks = 8;
break;
case SBC_BLK_12:
frame->blocks = 12;
break;
case SBC_BLK_16:
frame->blocks = 16;
break;
}
frame->mode = (data[1] >> 2) & 0x03;
switch (frame->mode) {
case MONO:
frame->channels = 1;
break;
case DUAL_CHANNEL: /* fall-through */
case STEREO:
case JOINT_STEREO:
frame->channels = 2;
break;
}
frame->allocation = (data[1] >> 1) & 0x01;
frame->subband_mode = (data[1] & 0x01);
frame->subbands = frame->subband_mode ? 8 : 4;
frame->bitpool = data[2];
if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
frame->bitpool > 16 * frame->subbands)
return -4;
if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
frame->bitpool > 32 * frame->subbands)
return -4;
/* data[3] is crc, we're checking it later */
consumed = 32;
crc_header[0] = data[1];
crc_header[1] = data[2];
crc_pos = 16;
if (frame->mode == JOINT_STEREO) {
if (len * 8 < consumed + frame->subbands)
return -1;
frame->joint = 0x00;
for (sb = 0; sb < frame->subbands - 1; sb++)
frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb;
if (frame->subbands == 4)
crc_header[crc_pos / 8] = data[4] & 0xf0;
else
crc_header[crc_pos / 8] = data[4];
consumed += frame->subbands;
crc_pos += frame->subbands;
}
if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
return -1;
for (ch = 0; ch < frame->channels; ch++) {
for (sb = 0; sb < frame->subbands; sb++) {
/* FIXME assert(consumed % 4 == 0); */
frame->scale_factor[ch][sb] =
(data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
crc_header[crc_pos >> 3] |=
frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
consumed += 4;
crc_pos += 4;
}
}
if (data[3] != sbc_crc8(crc_header, crc_pos))
return -3;
sbc_calculate_bits(frame, bits);
for (ch = 0; ch < frame->channels; ch++) {
for (sb = 0; sb < frame->subbands; sb++)
levels[ch][sb] = (1 << bits[ch][sb]) - 1;
}
for (blk = 0; blk < frame->blocks; blk++) {
for (ch = 0; ch < frame->channels; ch++) {
for (sb = 0; sb < frame->subbands; sb++) {
if (levels[ch][sb] > 0) {
audio_sample = 0;
for (bit = 0; bit < bits[ch][sb]; bit++) {
if (consumed > len * 8)
return -1;
if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
audio_sample |= 1 << (bits[ch][sb] - bit - 1);
consumed++;
}
frame->sb_sample[blk][ch][sb] =
(((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
} else
frame->sb_sample[blk][ch][sb] = 0;
}
}
}
if (frame->mode == JOINT_STEREO) {
for (blk = 0; blk < frame->blocks; blk++) {
for (sb = 0; sb < frame->subbands; sb++) {
if (frame->joint & (0x01 << sb)) {
temp = frame->sb_sample[blk][0][sb] +
frame->sb_sample[blk][1][sb];
frame->sb_sample[blk][1][sb] =
frame->sb_sample[blk][0][sb] -
frame->sb_sample[blk][1][sb];
frame->sb_sample[blk][0][sb] = temp;
}
}
}
}
if ((consumed & 0x7) != 0)
consumed += 8 - (consumed & 0x7);
return consumed >> 3;
}
static void sbc_decoder_init(struct sbc_decoder_state *state,
const struct sbc_frame *frame)
{
int i, ch;
memset(state->V, 0, sizeof(state->V));
state->subbands = frame->subbands;
for (ch = 0; ch < 2; ch++)
for (i = 0; i < frame->subbands * 2; i++)
state->offset[ch][i] = (10 * i + 10);
}
static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
{
if (s > 0x7FFF)
return 0x7FFF;
else if (s < -0x8000)
return -0x8000;
else
return s;
}
static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
struct sbc_frame *frame, int ch, int blk)
{
int i, k, idx;
int32_t *v = state->V[ch];
int *offset = state->offset[ch];
for (i = 0; i < 8; i++) {
/* Shifting */
offset[i]--;
if (offset[i] < 0) {
offset[i] = 79;
memcpy(v + 80, v, 9 * sizeof(*v));
}
/* Distribute the new matrix value to the shifted position */
v[offset[i]] = SCALE4_STAGED1(
MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
}
/* Compute the samples */
for (idx = 0, i = 0; i < 4; i++, idx += 5) {
k = (i + 4) & 0xf;
/* Store in output, Q0 */
frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
}
}
static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
struct sbc_frame *frame, int ch, int blk)
{
int i, j, k, idx;
int *offset = state->offset[ch];
for (i = 0; i < 16; i++) {
/* Shifting */
offset[i]--;
if (offset[i] < 0) {
offset[i] = 159;
for (j = 0; j < 9; j++)
state->V[ch][j + 160] = state->V[ch][j];
}
/* Distribute the new matrix value to the shifted position */
state->V[ch][offset[i]] = SCALE8_STAGED1(
MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
}
/* Compute the samples */
for (idx = 0, i = 0; i < 8; i++, idx += 5) {
k = (i + 8) & 0xf;
/* Store in output, Q0 */
frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
}
}
static int sbc_synthesize_audio(struct sbc_decoder_state *state,
struct sbc_frame *frame)
{
int ch, blk;
switch (frame->subbands) {
case 4:
for (ch = 0; ch < frame->channels; ch++) {
for (blk = 0; blk < frame->blocks; blk++)
sbc_synthesize_four(state, frame, ch, blk);
}
return frame->blocks * 4;
case 8:
for (ch = 0; ch < frame->channels; ch++) {
for (blk = 0; blk < frame->blocks; blk++)
sbc_synthesize_eight(state, frame, ch, blk);
}
return frame->blocks * 8;
default:
return -EIO;
}
}
static int sbc_analyze_audio(struct sbc_encoder_state *state,
struct sbc_frame *frame)
{
int ch, blk;
int16_t *x;
switch (frame->subbands) {
case 4:
for (ch = 0; ch < frame->channels; ch++) {
x = &state->X[ch][state->position - 16 +
frame->blocks * 4];
for (blk = 0; blk < frame->blocks; blk += 4) {
state->sbc_analyze_4b_4s(
x,
frame->sb_sample_f[blk][ch],
frame->sb_sample_f[blk + 1][ch] -
frame->sb_sample_f[blk][ch]);
x -= 16;
}
}
return frame->blocks * 4;
case 8:
for (ch = 0; ch < frame->channels; ch++) {
x = &state->X[ch][state->position - 32 +
frame->blocks * 8];
for (blk = 0; blk < frame->blocks; blk += 4) {
state->sbc_analyze_4b_8s(
x,
frame->sb_sample_f[blk][ch],
frame->sb_sample_f[blk + 1][ch] -
frame->sb_sample_f[blk][ch]);
x -= 32;
}
}
return frame->blocks * 8;
default:
return -EIO;
}
}
/* Supplementary bitstream writing macros for 'sbc_pack_frame' */
#define PUT_BITS(data_ptr, bits_cache, bits_count, v, n) \
do { \
bits_cache = (v) | (bits_cache << (n)); \
bits_count += (n); \
if (bits_count >= 16) { \
bits_count -= 8; \
*data_ptr++ = (uint8_t) \
(bits_cache >> bits_count); \
bits_count -= 8; \
*data_ptr++ = (uint8_t) \
(bits_cache >> bits_count); \
} \
} while (0)
#define FLUSH_BITS(data_ptr, bits_cache, bits_count) \
do { \
while (bits_count >= 8) { \
bits_count -= 8; \
*data_ptr++ = (uint8_t) \
(bits_cache >> bits_count); \
} \
if (bits_count > 0) \
*data_ptr++ = (uint8_t) \
(bits_cache << (8 - bits_count)); \
} while (0)
/*
* Packs the SBC frame from frame into the memory at data. At most len
* bytes will be used, should more memory be needed an appropriate
* error code will be returned. Returns the length of the packed frame
* on success or a negative value on error.
*
* The error codes are:
* -1 Not enough memory reserved
* -2 Unsupported sampling rate
* -3 Unsupported number of blocks
* -4 Unsupported number of subbands
* -5 Bitpool value out of bounds
* -99 not implemented
*/
static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
struct sbc_frame *frame, size_t len,
int frame_subbands, int frame_channels,
int joint)
{
/* Bitstream writer starts from the fourth byte */
uint8_t *data_ptr = data + 4;
uint32_t bits_cache = 0;
uint32_t bits_count = 0;
/* Will copy the header parts for CRC-8 calculation here */
uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int crc_pos = 0;
uint32_t audio_sample;
int ch, sb, blk; /* channel, subband, block and bit counters */
int bits[2][8]; /* bits distribution */
uint32_t levels[2][8]; /* levels are derived from that */
uint32_t sb_sample_delta[2][8];
data[0] = SBC_SYNCWORD;
data[1] = (frame->frequency & 0x03) << 6;
data[1] |= (frame->block_mode & 0x03) << 4;
data[1] |= (frame->mode & 0x03) << 2;
data[1] |= (frame->allocation & 0x01) << 1;
switch (frame_subbands) {
case 4:
/* Nothing to do */
break;
case 8:
data[1] |= 0x01;
break;
default:
return -4;
break;
}
data[2] = frame->bitpool;
if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
frame->bitpool > frame_subbands << 4)
return -5;
if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
frame->bitpool > frame_subbands << 5)
return -5;
/* Can't fill in crc yet */
crc_header[0] = data[1];
crc_header[1] = data[2];
crc_pos = 16;
if (frame->mode == JOINT_STEREO) {
PUT_BITS(data_ptr, bits_cache, bits_count,
joint, frame_subbands);
crc_header[crc_pos >> 3] = joint;
crc_pos += frame_subbands;
}
for (ch = 0; ch < frame_channels; ch++) {
for (sb = 0; sb < frame_subbands; sb++) {
PUT_BITS(data_ptr, bits_cache, bits_count,
frame->scale_factor[ch][sb] & 0x0F, 4);
crc_header[crc_pos >> 3] <<= 4;
crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
crc_pos += 4;
}
}
/* align the last crc byte */
if (crc_pos % 8)
crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
data[3] = sbc_crc8(crc_header, crc_pos);
sbc_calculate_bits(frame, bits);
for (ch = 0; ch < frame_channels; ch++) {
for (sb = 0; sb < frame_subbands; sb++) {
levels[ch][sb] = ((1 << bits[ch][sb]) - 1) <<
(32 - (frame->scale_factor[ch][sb] +
SCALE_OUT_BITS + 2));
sb_sample_delta[ch][sb] = (uint32_t) 1 <<
(frame->scale_factor[ch][sb] +
SCALE_OUT_BITS + 1);
}
}
for (blk = 0; blk < frame->blocks; blk++) {
for (ch = 0; ch < frame_channels; ch++) {
for (sb = 0; sb < frame_subbands; sb++) {
if (bits[ch][sb] == 0)
continue;
audio_sample = ((uint64_t) levels[ch][sb] *
(sb_sample_delta[ch][sb] +
frame->sb_sample_f[blk][ch][sb])) >> 32;
PUT_BITS(data_ptr, bits_cache, bits_count,
audio_sample, bits[ch][sb]);
}
}
}
FLUSH_BITS(data_ptr, bits_cache, bits_count);
return data_ptr - data;
}
static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
int joint)
{
if (frame->subbands == 4) {
if (frame->channels == 1)
return sbc_pack_frame_internal(
data, frame, len, 4, 1, joint);
else
return sbc_pack_frame_internal(
data, frame, len, 4, 2, joint);
} else {
if (frame->channels == 1)
return sbc_pack_frame_internal(
data, frame, len, 8, 1, joint);
else
return sbc_pack_frame_internal(
data, frame, len, 8, 2, joint);
}
}
static void sbc_encoder_init(struct sbc_encoder_state *state,
const struct sbc_frame *frame)
{
memset(&state->X, 0, sizeof(state->X));
state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
sbc_init_primitives(state);
}
struct sbc_priv {
int init;
struct SBC_ALIGNED sbc_frame frame;
struct SBC_ALIGNED sbc_decoder_state dec_state;
struct SBC_ALIGNED sbc_encoder_state enc_state;
};
static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
{
sbc->frequency = SBC_FREQ_44100;
sbc->mode = SBC_MODE_STEREO;
sbc->subbands = SBC_SB_8;
sbc->blocks = SBC_BLK_16;
sbc->bitpool = 32;
#if __BYTE_ORDER == __LITTLE_ENDIAN
sbc->endian = SBC_LE;
#elif __BYTE_ORDER == __BIG_ENDIAN
sbc->endian = SBC_BE;
#else
#error "Unknown byte order"
#endif
}
int sbc_init(sbc_t *sbc, unsigned long flags)
{
if (!sbc)
return -EIO;
memset(sbc, 0, sizeof(sbc_t));
sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
if (!sbc->priv_alloc_base)
return -ENOMEM;
sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
memset(sbc->priv, 0, sizeof(struct sbc_priv));
sbc_set_defaults(sbc, flags);
return 0;
}
ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
{
return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
}
ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, size_t *written)
{
struct sbc_priv *priv;
char *ptr;
int i, ch, framelen, samples;
if (!sbc || !input)
return -EIO;
priv = sbc->priv;
framelen = sbc_unpack_frame(input, &priv->frame, input_len);
if (!priv->init) {
sbc_decoder_init(&priv->dec_state, &priv->frame);
priv->init = 1;
sbc->frequency = priv->frame.frequency;
sbc->mode = priv->frame.mode;
sbc->subbands = priv->frame.subband_mode;
sbc->blocks = priv->frame.block_mode;
sbc->allocation = priv->frame.allocation;
sbc->bitpool = priv->frame.bitpool;
priv->frame.codesize = sbc_get_codesize(sbc);
priv->frame.length = framelen;
}
if (!output)
return framelen;
if (written)
*written = 0;
if (framelen <= 0)
return framelen;
samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
ptr = output;
if (output_len < (size_t) (samples * priv->frame.channels * 2))
samples = output_len / (priv->frame.channels * 2);
for (i = 0; i < samples; i++) {
for (ch = 0; ch < priv->frame.channels; ch++) {
int16_t s;
s = priv->frame.pcm_sample[ch][i];
if (sbc->endian == SBC_BE) {
*ptr++ = (s & 0xff00) >> 8;
*ptr++ = (s & 0x00ff);
} else {
*ptr++ = (s & 0x00ff);
*ptr++ = (s & 0xff00) >> 8;
}
}
}
if (written)
*written = samples * priv->frame.channels * 2;
return framelen;
}
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, ssize_t *written)
{
struct sbc_priv *priv;
int samples;
ssize_t framelen;
int (*sbc_enc_process_input)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
if (!sbc || !input)
return -EIO;
priv = sbc->priv;
if (written)
*written = 0;
if (!priv->init) {
priv->frame.frequency = sbc->frequency;
priv->frame.mode = sbc->mode;
priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
priv->frame.allocation = sbc->allocation;
priv->frame.subband_mode = sbc->subbands;
priv->frame.subbands = sbc->subbands ? 8 : 4;
priv->frame.block_mode = sbc->blocks;
priv->frame.blocks = 4 + (sbc->blocks * 4);
priv->frame.bitpool = sbc->bitpool;
priv->frame.codesize = sbc_get_codesize(sbc);
priv->frame.length = sbc_get_frame_length(sbc);
sbc_encoder_init(&priv->enc_state, &priv->frame);
priv->init = 1;
}
/* input must be large enough to encode a complete frame */
if (input_len < priv->frame.codesize)
return 0;
/* output must be large enough to receive the encoded frame */
if (!output || output_len < priv->frame.length)
return -ENOSPC;
/* Select the needed input data processing function and call it */
if (priv->frame.subbands == 8) {
if (sbc->endian == SBC_BE)
sbc_enc_process_input =
priv->enc_state.sbc_enc_process_input_8s_be;
else
sbc_enc_process_input =
priv->enc_state.sbc_enc_process_input_8s_le;
} else {
if (sbc->endian == SBC_BE)
sbc_enc_process_input =
priv->enc_state.sbc_enc_process_input_4s_be;
else
sbc_enc_process_input =
priv->enc_state.sbc_enc_process_input_4s_le;
}
priv->enc_state.position = sbc_enc_process_input(
priv->enc_state.position, (const uint8_t *) input,
priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
priv->frame.channels);
samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
if (priv->frame.mode == JOINT_STEREO) {
int j = priv->enc_state.sbc_calc_scalefactors_j(
priv->frame.sb_sample_f, priv->frame.scale_factor,
priv->frame.blocks, priv->frame.subbands);
framelen = sbc_pack_frame(output, &priv->frame, output_len, j);
} else {
priv->enc_state.sbc_calc_scalefactors(
priv->frame.sb_sample_f, priv->frame.scale_factor,
priv->frame.blocks, priv->frame.channels,
priv->frame.subbands);
framelen = sbc_pack_frame(output, &priv->frame, output_len, 0);
}
if (written)
*written = framelen;
return samples * priv->frame.channels * 2;
}
void sbc_finish(sbc_t *sbc)
{
if (!sbc)
return;
free(sbc->priv_alloc_base);
memset(sbc, 0, sizeof(sbc_t));
}
size_t sbc_get_frame_length(sbc_t *sbc)
{
int ret;
uint8_t subbands, channels, blocks, joint, bitpool;
struct sbc_priv *priv;
priv = sbc->priv;
if (priv->init)
return priv->frame.length;
subbands = sbc->subbands ? 8 : 4;
blocks = 4 + (sbc->blocks * 4);
channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
bitpool = sbc->bitpool;
ret = 4 + (4 * subbands * channels) / 8;
/* This term is not always evenly divide so we round it up */
if (channels == 1)
ret += ((blocks * channels * bitpool) + 7) / 8;
else
ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8;
return ret;
}
unsigned sbc_get_frame_duration(sbc_t *sbc)
{
uint8_t subbands, blocks;
uint16_t frequency;
struct sbc_priv *priv;
priv = sbc->priv;
if (!priv->init) {
subbands = sbc->subbands ? 8 : 4;
blocks = 4 + (sbc->blocks * 4);
} else {
subbands = priv->frame.subbands;
blocks = priv->frame.blocks;
}
switch (sbc->frequency) {
case SBC_FREQ_16000:
frequency = 16000;
break;
case SBC_FREQ_32000:
frequency = 32000;
break;
case SBC_FREQ_44100:
frequency = 44100;
break;
case SBC_FREQ_48000:
frequency = 48000;
break;
default:
return 0;
}
return (1000000 * blocks * subbands) / frequency;
}
size_t sbc_get_codesize(sbc_t *sbc)
{
uint16_t subbands, channels, blocks;
struct sbc_priv *priv;
priv = sbc->priv;
if (!priv->init) {
subbands = sbc->subbands ? 8 : 4;
blocks = 4 + (sbc->blocks * 4);
channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
} else {
subbands = priv->frame.subbands;
blocks = priv->frame.blocks;
channels = priv->frame.channels;
}
return subbands * blocks * channels * 2;
}
const char *sbc_get_implementation_info(sbc_t *sbc)
{
struct sbc_priv *priv;
if (!sbc)
return NULL;
priv = sbc->priv;
if (!priv)
return NULL;
return priv->enc_state.implementation_info;
}
int sbc_reinit(sbc_t *sbc, unsigned long flags)
{
struct sbc_priv *priv;
if (!sbc || !sbc->priv)
return -EIO;
priv = sbc->priv;
if (priv->init == 1)
memset(sbc->priv, 0, sizeof(struct sbc_priv));
sbc_set_defaults(sbc, flags);
return 0;
}