xref: /btstack/3rd-party/lc3-google/include/lc3_cpp.h (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
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