Changeset View
Changeset View
Standalone View
Standalone View
lib/virtual_oss/bt/sbc_encode.c
- This file was added.
| /*- | |||||
| * Copyright (c) 2015 Nathanial Sloss <nathanialsloss@yahoo.com.au> | |||||
| * | |||||
| * This software is dedicated to the memory of - | |||||
| * Baron James Anlezark (Barry) - 1 Jan 1949 - 13 May 2012. | |||||
| * | |||||
| * Barry was a man who loved his music. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in the | |||||
| * documentation and/or other materials provided with the distribution. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||||
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||||
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||||
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||||
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||||
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||||
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||||
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||||
| * POSSIBILITY OF SUCH DAMAGE. | |||||
| */ | |||||
| #include <sys/cdefs.h> | |||||
| #include <sys/types.h> | |||||
| #include <sys/param.h> | |||||
| #include <sys/endian.h> | |||||
| #include <sys/uio.h> | |||||
| #include <stdio.h> | |||||
| #include <errno.h> | |||||
| #include <stdbool.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <unistd.h> | |||||
| #include <math.h> | |||||
| #include "sbc_coeffs.h" | |||||
| #include "bt.h" | |||||
| #define SYNCWORD 0x9c | |||||
| #define ABS(x) (((x) < 0) ? -(x) : (x)) | |||||
| #define BIT30 (1U << 30) | |||||
| #define BM(x) ((1LL << (x)) - 1LL) | |||||
| /* Loudness offset allocations. */ | |||||
| static const int loudnessoffset8[4][8] = { | |||||
| {-2, 0, 0, 0, 0, 0, 0, 1}, | |||||
| {-3, 0, 0, 0, 0, 0, 1, 2}, | |||||
| {-4, 0, 0, 0, 0, 0, 1, 2}, | |||||
| {-4, 0, 0, 0, 0, 0, 1, 2}, | |||||
| }; | |||||
| static const int loudnessoffset4[4][4] = { | |||||
| {-1, 0, 0, 0}, | |||||
| {-2, 0, 0, 1}, | |||||
| {-2, 0, 0, 1}, | |||||
| {-2, 0, 0, 1}, | |||||
| }; | |||||
| static uint8_t | |||||
| calc_scalefactors_joint(struct sbc_encode *sbc) | |||||
| { | |||||
| float sb_j[16][2]; | |||||
| uint32_t x; | |||||
| uint32_t y; | |||||
| uint8_t block; | |||||
| uint8_t joint; | |||||
| uint8_t sb; | |||||
| uint8_t lz; | |||||
| joint = 0; | |||||
| for (sb = 0; sb != sbc->bands - 1; sb++) { | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| sb_j[block][0] = (sbc->samples[block][0][sb] + | |||||
| sbc->samples[block][1][sb]) / 2.0f; | |||||
| sb_j[block][1] = (sbc->samples[block][0][sb] - | |||||
| sbc->samples[block][1][sb]) / 2.0f; | |||||
| } | |||||
| x = 1 << 15; | |||||
| y = 1 << 15; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| x |= (uint32_t)ABS(sb_j[block][0]); | |||||
| y |= (uint32_t)ABS(sb_j[block][1]); | |||||
| } | |||||
| lz = 1; | |||||
| while (!(x & BIT30)) { | |||||
| lz++; | |||||
| x <<= 1; | |||||
| } | |||||
| x = 16 - lz; | |||||
| lz = 1; | |||||
| while (!(y & BIT30)) { | |||||
| lz++; | |||||
| y <<= 1; | |||||
| } | |||||
| y = 16 - lz; | |||||
| if ((sbc->scalefactor[0][sb] + sbc->scalefactor[1][sb]) > x + y) { | |||||
| joint |= 1 << (sbc->bands - sb - 1); | |||||
| sbc->scalefactor[0][sb] = x; | |||||
| sbc->scalefactor[1][sb] = y; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| sbc->samples[block][0][sb] = sb_j[block][0]; | |||||
| sbc->samples[block][1][sb] = sb_j[block][1]; | |||||
| } | |||||
| } | |||||
| } | |||||
| return (joint); | |||||
| } | |||||
| static void | |||||
| calc_scalefactors(struct sbc_encode *sbc) | |||||
| { | |||||
| uint8_t block; | |||||
| uint8_t ch; | |||||
| uint8_t sb; | |||||
| for (ch = 0; ch != sbc->channels; ch++) { | |||||
| for (sb = 0; sb != sbc->bands; sb++) { | |||||
| uint32_t x = 1 << 15; | |||||
| uint8_t lx = 1; | |||||
| for (block = 0; block != sbc->blocks; block++) | |||||
| x |= (uint32_t)ABS(sbc->samples[block][ch][sb]); | |||||
| while (!(x & BIT30)) { | |||||
| lx++; | |||||
| x <<= 1; | |||||
| } | |||||
| sbc->scalefactor[ch][sb] = 16 - lx; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void | |||||
| calc_bitneed(struct bt_config *cfg) | |||||
| { | |||||
| struct sbc_encode *sbc = cfg->handle.sbc_enc; | |||||
| int32_t bitneed[2][8]; | |||||
| int32_t max_bitneed, bitcount; | |||||
| int32_t slicecount, bitslice; | |||||
| int32_t loudness; | |||||
| int ch, sb, start_chan = 0; | |||||
| if (cfg->chmode == MODE_DUAL) | |||||
| sbc->channels = 1; | |||||
| next_chan: | |||||
| max_bitneed = 0; | |||||
| bitcount = 0; | |||||
| slicecount = 0; | |||||
| if (cfg->allocm == ALLOC_SNR) { | |||||
| for (ch = start_chan; ch < sbc->channels; ch++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| bitneed[ch][sb] = sbc->scalefactor[ch][sb]; | |||||
| if (bitneed[ch][sb] > max_bitneed) | |||||
| max_bitneed = bitneed[ch][sb]; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| for (ch = start_chan; ch < sbc->channels; ch++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->scalefactor[ch][sb] == 0) { | |||||
| bitneed[ch][sb] = -5; | |||||
| } else { | |||||
| if (sbc->bands == 8) { | |||||
| loudness = sbc->scalefactor[ch][sb] - | |||||
| loudnessoffset8[cfg->freq][sb]; | |||||
| } else { | |||||
| loudness = sbc->scalefactor[ch][sb] - | |||||
| loudnessoffset4[cfg->freq][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]; | |||||
| } | |||||
| } | |||||
| } | |||||
| slicecount = bitcount = 0; | |||||
| bitslice = max_bitneed + 1; | |||||
| do { | |||||
| bitslice--; | |||||
| bitcount += slicecount; | |||||
| slicecount = 0; | |||||
| for (ch = start_chan; ch < sbc->channels; ch++) { | |||||
| for (sb = 0; sb < sbc->bands; 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 < cfg->bitpool); | |||||
| /* check if exactly one more fits */ | |||||
| if (bitcount + slicecount == cfg->bitpool) { | |||||
| bitcount += slicecount; | |||||
| bitslice--; | |||||
| } | |||||
| for (ch = start_chan; ch < sbc->channels; ch++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (bitneed[ch][sb] < bitslice + 2) { | |||||
| sbc->bits[ch][sb] = 0; | |||||
| } else { | |||||
| sbc->bits[ch][sb] = bitneed[ch][sb] - bitslice; | |||||
| if (sbc->bits[ch][sb] > 16) | |||||
| sbc->bits[ch][sb] = 16; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (cfg->chmode == MODE_DUAL) | |||||
| ch = start_chan; | |||||
| else | |||||
| ch = 0; | |||||
| sb = 0; | |||||
| while (bitcount < cfg->bitpool && sb < sbc->bands) { | |||||
| if ((sbc->bits[ch][sb] >= 2) && (sbc->bits[ch][sb] < 16)) { | |||||
| sbc->bits[ch][sb]++; | |||||
| bitcount++; | |||||
| } else if ((bitneed[ch][sb] == bitslice + 1) && | |||||
| (cfg->bitpool > bitcount + 1)) { | |||||
| sbc->bits[ch][sb] = 2; | |||||
| bitcount += 2; | |||||
| } | |||||
| if (sbc->channels == 1 || start_chan == 1) | |||||
| sb++; | |||||
| else if (ch == 1) { | |||||
| ch = 0; | |||||
| sb++; | |||||
| } else | |||||
| ch = 1; | |||||
| } | |||||
| if (cfg->chmode == MODE_DUAL) | |||||
| ch = start_chan; | |||||
| else | |||||
| ch = 0; | |||||
| sb = 0; | |||||
| while (bitcount < cfg->bitpool && sb < sbc->bands) { | |||||
| if (sbc->bits[ch][sb] < 16) { | |||||
| sbc->bits[ch][sb]++; | |||||
| bitcount++; | |||||
| } | |||||
| if (sbc->channels == 1 || start_chan == 1) | |||||
| sb++; | |||||
| else if (ch == 1) { | |||||
| ch = 0; | |||||
| sb++; | |||||
| } else | |||||
| ch = 1; | |||||
| } | |||||
| if (cfg->chmode == MODE_DUAL && start_chan == 0) { | |||||
| start_chan = 1; | |||||
| sbc->channels = 2; | |||||
| goto next_chan; | |||||
| } | |||||
| } | |||||
| static void | |||||
| sbc_store_bits_crc(struct sbc_encode *sbc, uint32_t numbits, uint32_t value) | |||||
| { | |||||
| uint32_t off = sbc->bitoffset; | |||||
| while (numbits-- && off != sbc->maxoffset) { | |||||
| if (value & (1 << numbits)) { | |||||
| sbc->data[off / 8] |= 1 << ((7 - off) & 7); | |||||
| sbc->crc ^= 0x80; | |||||
| } | |||||
| sbc->crc *= 2; | |||||
| if (sbc->crc & 0x100) | |||||
| sbc->crc ^= 0x11d; /* CRC-8 polynomial */ | |||||
| off++; | |||||
| } | |||||
| sbc->bitoffset = off; | |||||
| } | |||||
| static int | |||||
| sbc_encode(struct bt_config *cfg) | |||||
| { | |||||
| struct sbc_encode *sbc = cfg->handle.sbc_enc; | |||||
| const int16_t *input = sbc->music_data; | |||||
| float delta[2][8]; | |||||
| float levels[2][8]; | |||||
| float mask[2][8]; | |||||
| float S; | |||||
| float *X; | |||||
| float Z[80]; | |||||
| float Y[80]; | |||||
| float audioout; | |||||
| int16_t left[8]; | |||||
| int16_t right[8]; | |||||
| int16_t *data; | |||||
| int numsamples; | |||||
| int i; | |||||
| int k; | |||||
| int block; | |||||
| int chan; | |||||
| int sb; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (i = 0; i < sbc->bands; i++) { | |||||
| left[i] = *input++; | |||||
| if (sbc->channels == 2) | |||||
| right[i] = *input++; | |||||
| } | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| /* select right or left channel */ | |||||
| if (chan == 0) { | |||||
| X = sbc->left; | |||||
| data = left; | |||||
| } else { | |||||
| X = sbc->right; | |||||
| data = right; | |||||
| } | |||||
| /* shift up old data */ | |||||
| for (i = (sbc->bands * 10) - 1; i > sbc->bands - 1; i--) | |||||
| X[i] = X[i - sbc->bands]; | |||||
| k = 0; | |||||
| for (i = sbc->bands - 1; i >= 0; i--) | |||||
| X[i] = data[k++]; | |||||
| for (i = 0; i < sbc->bands * 10; i++) { | |||||
| if (sbc->bands == 8) | |||||
| Z[i] = sbc_coeffs8[i] * X[i]; | |||||
| else | |||||
| Z[i] = sbc_coeffs4[i] * X[i]; | |||||
| } | |||||
| for (i = 0; i < sbc->bands * 2; i++) { | |||||
| Y[i] = 0; | |||||
| for (k = 0; k < 5; k++) | |||||
| Y[i] += Z[i + k * sbc->bands * 2]; | |||||
| } | |||||
| for (i = 0; i < sbc->bands; i++) { | |||||
| S = 0; | |||||
| for (k = 0; k < sbc->bands * 2; k++) { | |||||
| if (sbc->bands == 8) { | |||||
| S += cosdata8[i][k] * Y[k]; | |||||
| } else { | |||||
| S += cosdata4[i][k] * Y[k]; | |||||
| } | |||||
| } | |||||
| sbc->samples[block][chan][i] = S * (1 << 15); | |||||
| } | |||||
| } | |||||
| } | |||||
| calc_scalefactors(sbc); | |||||
| if (cfg->chmode == MODE_JOINT) | |||||
| sbc->join = calc_scalefactors_joint(sbc); | |||||
| else | |||||
| sbc->join = 0; | |||||
| calc_bitneed(cfg); | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->bits[chan][sb] == 0) | |||||
| continue; | |||||
| mask[chan][sb] = BM(sbc->bits[chan][sb]); | |||||
| levels[chan][sb] = mask[chan][sb] * | |||||
| (1LL << (15 - sbc->scalefactor[chan][sb])); | |||||
| delta[chan][sb] = | |||||
| (1LL << (sbc->scalefactor[chan][sb] + 16)); | |||||
| } | |||||
| } | |||||
| numsamples = 0; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->bits[chan][sb] == 0) | |||||
| continue; | |||||
| audioout = (levels[chan][sb] * | |||||
| (delta[chan][sb] + sbc->samples[block][chan][sb])); | |||||
| audioout /= (1LL << 32); | |||||
| audioout = roundf(audioout); | |||||
| /* range check */ | |||||
| if (audioout > mask[chan][sb]) | |||||
| audioout = mask[chan][sb]; | |||||
| sbc->output[numsamples++] = audioout; | |||||
| } | |||||
| } | |||||
| } | |||||
| return (numsamples); | |||||
| } | |||||
| static void | |||||
| sbc_decode(struct bt_config *cfg) | |||||
| { | |||||
| struct sbc_encode *sbc = cfg->handle.sbc_enc; | |||||
| float delta[2][8]; | |||||
| float levels[2][8]; | |||||
| float audioout; | |||||
| float *X; | |||||
| float *V; | |||||
| float left[160]; | |||||
| float right[160]; | |||||
| float U[160]; | |||||
| float W[160]; | |||||
| float S[8]; | |||||
| int position; | |||||
| int block; | |||||
| int chan; | |||||
| int sb; | |||||
| int i; | |||||
| int k; | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| levels[chan][sb] = (1 << sbc->bits[chan][sb]) - 1; | |||||
| delta[chan][sb] = (1 << sbc->scalefactor[chan][sb]); | |||||
| } | |||||
| } | |||||
| i = 0; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->bits[chan][sb] == 0) { | |||||
| audioout = 0; | |||||
| } else { | |||||
| audioout = | |||||
| ((((sbc->output[i] * 2.0f) + 1.0f) * delta[chan][sb]) / | |||||
| levels[chan][sb]) - delta[chan][sb]; | |||||
| } | |||||
| sbc->output[i++] = audioout; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (cfg->chmode == MODE_JOINT) { | |||||
| i = 0; | |||||
| while (i < (sbc->blocks * sbc->bands * sbc->channels)) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->join & (1 << (sbc->bands - sb - 1))) { | |||||
| audioout = sbc->output[i]; | |||||
| sbc->output[i] = (2.0f * sbc->output[i]) + | |||||
| (2.0f * sbc->output[i + sbc->bands]); | |||||
| sbc->output[i + sbc->bands] = | |||||
| (2.0f * audioout) - | |||||
| (2.0f * sbc->output[i + sbc->bands]); | |||||
| sbc->output[i] /= 2.0f; | |||||
| sbc->output[i + sbc->bands] /= 2.0f; | |||||
| } | |||||
| i++; | |||||
| } | |||||
| i += sbc->bands; | |||||
| } | |||||
| } | |||||
| position = 0; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| /* select right or left channel */ | |||||
| if (chan == 0) { | |||||
| X = left; | |||||
| V = sbc->left; | |||||
| } else { | |||||
| X = right; | |||||
| V = sbc->right; | |||||
| } | |||||
| for (i = 0; i < sbc->bands; i++) | |||||
| S[i] = sbc->output[position++]; | |||||
| for (i = (sbc->bands * 20) - 1; i >= (sbc->bands * 2); i--) | |||||
| V[i] = V[i - (sbc->bands * 2)]; | |||||
| for (k = 0; k < sbc->bands * 2; k++) { | |||||
| float vk = 0; | |||||
| for (i = 0; i < sbc->bands; i++) { | |||||
| if (sbc->bands == 8) { | |||||
| vk += cosdecdata8[i][k] * S[i]; | |||||
| } else { | |||||
| vk += cosdecdata4[i][k] * S[i]; | |||||
| } | |||||
| } | |||||
| V[k] = vk; | |||||
| } | |||||
| for (i = 0; i <= 4; i++) { | |||||
| for (k = 0; k < sbc->bands; k++) { | |||||
| U[(i * sbc->bands * 2) + k] = | |||||
| V[(i * sbc->bands * 4) + k]; | |||||
| U[(i * sbc->bands | |||||
| * 2) + sbc->bands + k] = | |||||
| V[(i * sbc->bands * 4) + | |||||
| (sbc->bands * 3) + k]; | |||||
| } | |||||
| } | |||||
| for (i = 0; i < sbc->bands * 10; i++) { | |||||
| if (sbc->bands == 4) { | |||||
| W[i] = U[i] * (sbc_coeffs4[i] * -4.0f); | |||||
| } else if (sbc->bands == 8) { | |||||
| W[i] = U[i] * (sbc_coeffs8[i] * -8.0f); | |||||
| } else { | |||||
| W[i] = 0; | |||||
| } | |||||
| } | |||||
| for (k = 0; k < sbc->bands; k++) { | |||||
| unsigned int offset = k + (block * sbc->bands); | |||||
| X[offset] = 0; | |||||
| for (i = 0; i < 10; i++) { | |||||
| X[offset] += W[k + (i * sbc->bands)]; | |||||
| } | |||||
| if (X[offset] > 32767.0) | |||||
| X[offset] = 32767.0; | |||||
| else if (X[offset] < -32767.0) | |||||
| X[offset] = -32767.0; | |||||
| } | |||||
| } | |||||
| } | |||||
| for (i = 0, k = 0; k != (sbc->blocks * sbc->bands); k++) { | |||||
| sbc->music_data[i++] = left[k]; | |||||
| if (sbc->channels == 2) | |||||
| sbc->music_data[i++] = right[k]; | |||||
| } | |||||
| } | |||||
| size_t | |||||
| sbc_encode_frame(struct bt_config *cfg) | |||||
| { | |||||
| struct sbc_encode *sbc = cfg->handle.sbc_enc; | |||||
| uint8_t config; | |||||
| uint8_t block; | |||||
| uint8_t chan; | |||||
| uint8_t sb; | |||||
| uint8_t j; | |||||
| uint8_t i; | |||||
| config = (cfg->freq << 6) | (cfg->blocks << 4) | | |||||
| (cfg->chmode << 2) | (cfg->allocm << 1) | cfg->bands; | |||||
| sbc_encode(cfg); | |||||
| /* set initial CRC */ | |||||
| sbc->crc = 0x5e; | |||||
| /* reset data position and size */ | |||||
| sbc->bitoffset = 0; | |||||
| sbc->maxoffset = sizeof(sbc->data) * 8; | |||||
| sbc_store_bits_crc(sbc, 8, SYNCWORD); | |||||
| sbc_store_bits_crc(sbc, 8, config); | |||||
| sbc_store_bits_crc(sbc, 8, cfg->bitpool); | |||||
| /* skip 8-bit CRC */ | |||||
| sbc->bitoffset += 8; | |||||
| if (cfg->chmode == MODE_JOINT) { | |||||
| if (sbc->bands == 8) | |||||
| sbc_store_bits_crc(sbc, 8, sbc->join); | |||||
| else if (sbc->bands == 4) | |||||
| sbc_store_bits_crc(sbc, 4, sbc->join); | |||||
| } | |||||
| for (i = 0; i < sbc->channels; i++) { | |||||
| for (j = 0; j < sbc->bands; j++) | |||||
| sbc_store_bits_crc(sbc, 4, sbc->scalefactor[i][j]); | |||||
| } | |||||
| /* store 8-bit CRC */ | |||||
| sbc->data[3] = (sbc->crc & 0xFF); | |||||
| i = 0; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->bits[chan][sb] == 0) | |||||
| continue; | |||||
| sbc_store_bits_crc(sbc, sbc->bits[chan][sb], sbc->output[i++]); | |||||
| } | |||||
| } | |||||
| } | |||||
| return ((sbc->bitoffset + 7) / 8); | |||||
| } | |||||
| static uint32_t | |||||
| sbc_load_bits_crc(struct sbc_encode *sbc, uint32_t numbits) | |||||
| { | |||||
| uint32_t off = sbc->bitoffset; | |||||
| uint32_t value = 0; | |||||
| while (numbits-- && off != sbc->maxoffset) { | |||||
| if (sbc->rem_data_ptr[off / 8] & (1 << ((7 - off) & 7))) { | |||||
| value |= (1 << numbits); | |||||
| sbc->crc ^= 0x80; | |||||
| } | |||||
| sbc->crc *= 2; | |||||
| if (sbc->crc & 0x100) | |||||
| sbc->crc ^= 0x11d; /* CRC-8 polynomial */ | |||||
| off++; | |||||
| } | |||||
| sbc->bitoffset = off; | |||||
| return (value); | |||||
| } | |||||
| size_t | |||||
| sbc_decode_frame(struct bt_config *cfg, int bits) | |||||
| { | |||||
| struct sbc_encode *sbc = cfg->handle.sbc_enc; | |||||
| uint8_t config; | |||||
| uint8_t block; | |||||
| uint8_t chan; | |||||
| uint8_t sb; | |||||
| uint8_t j; | |||||
| uint8_t i; | |||||
| sbc->rem_off = 0; | |||||
| sbc->rem_len = 0; | |||||
| config = (cfg->freq << 6) | (cfg->blocks << 4) | | |||||
| (cfg->chmode << 2) | (cfg->allocm << 1) | cfg->bands; | |||||
| /* set initial CRC */ | |||||
| sbc->crc = 0x5e; | |||||
| /* reset data position and size */ | |||||
| sbc->bitoffset = 0; | |||||
| sbc->maxoffset = bits; | |||||
| /* verify SBC header */ | |||||
| if (sbc->maxoffset < (8 * 4)) | |||||
| return (0); | |||||
| if (sbc_load_bits_crc(sbc, 8) != SYNCWORD) | |||||
| return (0); | |||||
| if (sbc_load_bits_crc(sbc, 8) != config) | |||||
| return (0); | |||||
| cfg->bitpool = sbc_load_bits_crc(sbc, 8); | |||||
| (void)sbc_load_bits_crc(sbc, 8);/* CRC */ | |||||
| if (cfg->chmode == MODE_JOINT) { | |||||
| if (sbc->bands == 8) | |||||
| sbc->join = sbc_load_bits_crc(sbc, 8); | |||||
| else if (sbc->bands == 4) | |||||
| sbc->join = sbc_load_bits_crc(sbc, 4); | |||||
| else | |||||
| sbc->join = 0; | |||||
| } else { | |||||
| sbc->join = 0; | |||||
| } | |||||
| for (i = 0; i < sbc->channels; i++) { | |||||
| for (j = 0; j < sbc->bands; j++) | |||||
| sbc->scalefactor[i][j] = sbc_load_bits_crc(sbc, 4); | |||||
| } | |||||
| calc_bitneed(cfg); | |||||
| i = 0; | |||||
| for (block = 0; block < sbc->blocks; block++) { | |||||
| for (chan = 0; chan < sbc->channels; chan++) { | |||||
| for (sb = 0; sb < sbc->bands; sb++) { | |||||
| if (sbc->bits[chan][sb] == 0) { | |||||
| i++; | |||||
| continue; | |||||
| } | |||||
| sbc->output[i++] = | |||||
| sbc_load_bits_crc(sbc, sbc->bits[chan][sb]); | |||||
| } | |||||
| } | |||||
| } | |||||
| sbc_decode(cfg); | |||||
| sbc->rem_off = 0; | |||||
| sbc->rem_len = sbc->blocks * sbc->channels * sbc->bands; | |||||
| return ((sbc->bitoffset + 7) / 8); | |||||
| } | |||||