1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
|
/******************************************************************************
*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* Low Complexity Communication Codec (LC3) - C++ interface
*/
#ifndef __LC3_CPP_H
#define __LC3_CPP_H
#include <cassert>
#include <memory>
#include <vector>
#include <stdlib.h>
#include "lc3.h"
namespace lc3 {
// PCM Sample Format
// - Signed 16 bits, in 16 bits words (int16_t)
// - Signed 24 bits, using low three bytes of 32 bits words (int32_t)
// The high byte sign extends (bits 31..24 set to b23)
// - Signed 24 bits packed in 3 bytes little endian
// - Floating point 32 bits (float type), in range -1 to 1
enum class PcmFormat {
kS16 = LC3_PCM_FORMAT_S16,
kS24 = LC3_PCM_FORMAT_S24,
kS24In3Le = LC3_PCM_FORMAT_S24_3LE,
kF32 = LC3_PCM_FORMAT_FLOAT
};
// Base Encoder/Decoder Class
template <typename T>
class Base {
protected:
Base(int dt_us, int sr_hz, int sr_pcm_hz, size_t nchannels, bool hrmode)
: dt_us_(dt_us),
sr_hz_(sr_hz),
sr_pcm_hz_(sr_pcm_hz == 0 ? sr_hz : sr_pcm_hz),
nchannels_(nchannels),
hrmode_(hrmode) {
states.reserve(nchannels_);
}
virtual ~Base() = default;
int dt_us_, sr_hz_;
int sr_pcm_hz_;
size_t nchannels_;
bool hrmode_;
using state_ptr = std::unique_ptr<T, decltype(&free)>;
std::vector<state_ptr> states;
public:
// Return the number of PCM samples in a frame
int GetFrameSamples() {
return lc3_hr_frame_samples(hrmode_, dt_us_, sr_pcm_hz_); }
// Return the size of a frame block, from bitrate
int GetFrameBytes(int bitrate) {
return lc3_hr_frame_block_bytes(
hrmode_, dt_us_, sr_hz_, nchannels_, bitrate); }
// Resolve the bitrate, from the size of frame blocks
int ResolveBitrate(int nbytes) {
return lc3_hr_resolve_bitrate(hrmode_, dt_us_, sr_hz_, nbytes); }
// Return algorithmic delay, as a number of samples
int GetDelaySamples() {
return lc3_hr_delay_samples(hrmode_, dt_us_, sr_pcm_hz_); }
}; // class Base
// Encoder Class
class Encoder : public Base<struct lc3_encoder> {
template <typename T>
int EncodeImpl(PcmFormat fmt, const T *pcm, int block_size, uint8_t *out) {
if (states.size() != nchannels_) return -1;
enum lc3_pcm_format cfmt = static_cast<lc3_pcm_format>(fmt);
int ret = 0;
uint8_t *out_ptr = out;
for (size_t ich = 0; ich < nchannels_; ich++) {
int frame_size = block_size / nchannels_
+ (ich < block_size % nchannels_);
ret |= lc3_encode(states[ich].get(), cfmt, pcm + ich, nchannels_,
frame_size, out_ptr);
out_ptr += frame_size;
}
return ret;
}
public:
// Encoder construction / destruction
//
// The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us.
// The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz.
// The `hrmode` flag enables the high-resolution mode, in which case
// the sample rate is 48000 or 96000 Hz.
//
// The `sr_pcm_hz` parameter is a downsampling option of PCM input,
// the value 0 fallback to the sample rate of the encoded stream `sr_hz`.
// When used, `sr_pcm_hz` is intended to be higher or equal to the encoder
// sample rate `sr_hz`.
Encoder(int dt_us, int sr_hz, int sr_pcm_hz = 0,
size_t nchannels = 1, bool hrmode = false)
: Base(dt_us, sr_hz, sr_pcm_hz, nchannels, hrmode) {
for (size_t ich = 0; ich < nchannels_; ich++) {
auto s = state_ptr((lc3_encoder_t)
malloc(lc3_hr_encoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free);
if (lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()))
states.push_back(std::move(s));
}
}
~Encoder() override = default;
// Reset encoder state
void Reset() {
for (auto &s : states)
lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get());
}
// Encode
//
// The input PCM samples are given in signed 16 bits, 24 bits, float,
// according the type of `pcm` input buffer, or by selecting a format.
//
// The PCM samples are read in interleaved way, and consecutive
// `nchannels` frames, are output in `out` buffer, of size `buffer_size`.
//
// The value returned is 0 on successs, -1 otherwise.
int Encode(const int16_t *pcm, int block_size, uint8_t *out) {
return EncodeImpl(PcmFormat::kS16, pcm, block_size, out);
}
int Encode(const int32_t *pcm, int block_size, uint8_t *out) {
return EncodeImpl(PcmFormat::kS24, pcm, block_size, out);
}
int Encode(const float *pcm, int block_size, uint8_t *out) {
return EncodeImpl(PcmFormat::kF32, pcm, block_size, out);
}
int Encode(PcmFormat fmt, const void *pcm, int block_size, uint8_t *out) {
uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm);
switch (fmt) {
case PcmFormat::kS16:
assert(pcm_ptr % alignof(int16_t) == 0);
return EncodeImpl(fmt, reinterpret_cast<const int16_t *>(pcm),
block_size, out);
case PcmFormat::kS24:
assert(pcm_ptr % alignof(int32_t) == 0);
return EncodeImpl(fmt, reinterpret_cast<const int32_t *>(pcm),
block_size, out);
case PcmFormat::kS24In3Le:
return EncodeImpl(fmt, reinterpret_cast<const int8_t(*)[3]>(pcm),
block_size, out);
case PcmFormat::kF32:
assert(pcm_ptr % alignof(float) == 0);
return EncodeImpl(fmt, reinterpret_cast<const float *>(pcm), block_size,
out);
}
return -1;
}
}; // class Encoder
// Decoder Class
class Decoder : public Base<struct lc3_decoder> {
template <typename T>
int DecodeImpl(const uint8_t *in, int block_size, PcmFormat fmt, T *pcm) {
if (states.size() != nchannels_) return -1;
enum lc3_pcm_format cfmt = static_cast<enum lc3_pcm_format>(fmt);
int ret = 0;
const uint8_t *in_ptr = in;
for (size_t ich = 0; ich < nchannels_; ich++) {
int frame_size = block_size / nchannels_
+ (ich < block_size % nchannels_);
ret |= lc3_decode(states[ich].get(), in_ptr, frame_size,
cfmt, pcm + ich, nchannels_);
in_ptr += frame_size;
}
return ret;
}
public:
// Decoder construction / destruction
//
// The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us.
// The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz.
// The `hrmode` flag enables the high-resolution mode, in which case
// the sample rate is 48000 or 96000 Hz.
//
// The `sr_pcm_hz` parameter is an downsampling option of PCM output,
// the value 0 fallback to the sample rate of the decoded stream `sr_hz`.
// When used, `sr_pcm_hz` is intended to be higher or equal to the decoder
// sample rate `sr_hz`.
Decoder(int dt_us, int sr_hz, int sr_pcm_hz = 0,
size_t nchannels = 1, bool hrmode = false)
: Base(dt_us, sr_hz, sr_pcm_hz, nchannels, hrmode) {
for (size_t i = 0; i < nchannels_; i++) {
auto s = state_ptr((lc3_decoder_t)
malloc(lc3_hr_decoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free);
if (lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()))
states.push_back(std::move(s));
}
}
~Decoder() override = default;
// Reset decoder state
void Reset() {
for (auto &s : states)
lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get());
}
// Decode
//
// Decode a frame block of size `block_size`,
// in the `pcm` buffer in interleaved way.
//
// The PCM samples are output in signed 16 bits, 24 bits, float,
// according the type of `pcm` output buffer, or by selecting a format.
//
// The value returned is 0 on successs, 1 when PLC has been performed,
// and -1 otherwise.
int Decode(const uint8_t *in, int block_size, int16_t *pcm) {
return DecodeImpl(in, block_size, PcmFormat::kS16, pcm);
}
int Decode(const uint8_t *in, int block_size, int32_t *pcm) {
return DecodeImpl(in, block_size, PcmFormat::kS24In3Le, pcm);
}
int Decode(const uint8_t *in, int block_size, float *pcm) {
return DecodeImpl(in, block_size, PcmFormat::kF32, pcm);
}
int Decode(const uint8_t *in, int block_size, PcmFormat fmt, void *pcm) {
uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm);
switch (fmt) {
case PcmFormat::kS16:
assert(pcm_ptr % alignof(int16_t) == 0);
return DecodeImpl(in, block_size, fmt,
reinterpret_cast<int16_t *>(pcm));
case PcmFormat::kS24:
assert(pcm_ptr % alignof(int32_t) == 0);
return DecodeImpl(in, block_size, fmt,
reinterpret_cast<int32_t *>(pcm));
case PcmFormat::kS24In3Le:
return DecodeImpl(in, block_size, fmt,
reinterpret_cast<int8_t(*)[3]>(pcm));
case PcmFormat::kF32:
assert(pcm_ptr % alignof(float) == 0);
return DecodeImpl(in, block_size, fmt, reinterpret_cast<float *>(pcm));
}
return -1;
}
}; // class Decoder
} // namespace lc3
#endif /* __LC3_CPP_H */
|