Files
MontaukOS/kernel/src/Drivers/USB/Bluetooth/Sbc.hpp
T

98 lines
3.3 KiB
C++

/*
* Sbc.hpp
* SBC (Sub-Band Codec) encoder for Bluetooth A2DP
* Fixed-point implementation (no FPU/SSE required)
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
namespace Drivers::USB::Bluetooth::Sbc {
// =========================================================================
// SBC configuration
// =========================================================================
// Standard SBC parameters for A2DP
constexpr int SBC_SUBBANDS = 8;
constexpr int SBC_BLOCKS = 16;
constexpr int SBC_CHANNELS = 2; // Stereo
constexpr int SBC_BITPOOL = 53; // Standard quality
// Allocation method
constexpr uint8_t ALLOC_SNR = 0;
constexpr uint8_t ALLOC_LOUDNESS = 1;
// Channel mode
constexpr uint8_t MODE_MONO = 0;
constexpr uint8_t MODE_DUAL_CHANNEL = 1;
constexpr uint8_t MODE_STEREO = 2;
constexpr uint8_t MODE_JOINT_STEREO = 3;
// Sampling frequency
constexpr uint8_t FREQ_16000 = 0;
constexpr uint8_t FREQ_32000 = 1;
constexpr uint8_t FREQ_44100 = 2;
constexpr uint8_t FREQ_48000 = 3;
// SBC frame header
struct SbcHeader {
uint8_t SyncWord; // 0x9C
uint8_t Config; // freq(2) | blocks(2) | mode(2) | alloc(1) | subbands(1)
uint8_t Bitpool;
uint8_t Crc;
} __attribute__((packed));
// =========================================================================
// Encoder state
// =========================================================================
struct SbcEncoder {
uint8_t Frequency;
uint8_t Blocks;
uint8_t ChannelMode;
uint8_t AllocMethod;
uint8_t Subbands;
uint8_t Bitpool;
uint8_t Channels;
// Analysis filter state (per-channel windowed buffer; X[0] = newest
// sample, shifted down by Subbands each block)
int32_t X[SBC_CHANNELS][SBC_SUBBANDS * 10];
// Computed frame size in bytes
uint32_t FrameSize;
// Samples per frame
uint32_t SamplesPerFrame; // blocks * subbands
};
// =========================================================================
// Public API
// =========================================================================
// Initialize encoder with given parameters
void Init(SbcEncoder* enc, uint32_t sampleRate, uint8_t channels, uint8_t bitsPerSample);
// Override the encoder's SBC parameters from the negotiated AVDTP capability
// octets (octet0 = SamplingFreq[7:4]|ChannelMode[3:0], octet1 =
// BlockLength[7:4]|Subbands[3:2]|Alloc[1:0]) + the chosen bitpool, so the
// emitted frame headers match exactly what the sink agreed to. Call after
// Init.
void Configure(SbcEncoder* enc, uint8_t octet0, uint8_t octet1, uint8_t bitpool);
// Encode one SBC frame from PCM data
// pcm: interleaved 16-bit signed PCM, length = blocks * subbands * channels
// out: output buffer for SBC frame
// Returns number of bytes written to out
uint32_t Encode(SbcEncoder* enc, const int16_t* pcm, uint8_t* out);
// Get the frame size in bytes for the current configuration
uint32_t GetFrameSize(const SbcEncoder* enc);
// Get the number of PCM samples consumed per frame (per channel)
uint32_t GetSamplesPerFrame(const SbcEncoder* enc);
}