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