diff options
Diffstat (limited to 'include/lc3_cpp.h')
-rw-r--r-- | include/lc3_cpp.h | 143 |
1 files changed, 85 insertions, 58 deletions
diff --git a/include/lc3_cpp.h b/include/lc3_cpp.h index acd3d0b..1949eb9 100644 --- a/include/lc3_cpp.h +++ b/include/lc3_cpp.h @@ -50,11 +50,12 @@ enum class PcmFormat { template <typename T> class Base { protected: - Base(int dt_us, int sr_hz, int sr_pcm_hz, size_t nchannels) + 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) { + nchannels_(nchannels), + hrmode_(hrmode) { states.reserve(nchannels_); } @@ -63,37 +64,50 @@ class Base { 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_frame_samples(dt_us_, sr_pcm_hz_); } + int GetFrameSamples() { + return lc3_hr_frame_samples(hrmode_, dt_us_, sr_pcm_hz_); } - // Return the size of frames, from bitrate - int GetFrameBytes(int bitrate) { return lc3_frame_bytes(dt_us_, bitrate); } + // 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 frames - int ResolveBitrate(int nbytes) { return lc3_resolve_bitrate(dt_us_, nbytes); } + // 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_delay_samples(dt_us_, sr_pcm_hz_); } + 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 frame_size, uint8_t *out) { + 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; - for (size_t ich = 0; ich < nchannels_; ich++) + 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 + ich * frame_size); + frame_size, out_ptr); + + out_ptr += frame_size; + } return ret; } @@ -101,21 +115,24 @@ class Encoder : public Base<struct lc3_encoder> { public: // Encoder construction / destruction // - // The frame duration `dt_us` is 7500 or 10000 us. - // The samplerate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. + // 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 samplerate of the encoded stream `sr_hz`. + // 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 - // samplerate `sr_hz`. + // sample rate `sr_hz`. - Encoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, size_t nchannels = 1) - : Base(dt_us, sr_hz, sr_pcm_hz, nchannels) { + 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_encoder_size(dt_us_, sr_pcm_hz_)), free); + auto s = state_ptr((lc3_encoder_t) + malloc(lc3_hr_encoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free); - if (lc3_setup_encoder(dt_us_, sr_hz_, sr_pcm_hz_, s.get())) + if (lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get())) states.push_back(std::move(s)); } } @@ -126,7 +143,7 @@ class Encoder : public Base<struct lc3_encoder> { void Reset() { for (auto &s : states) - lc3_setup_encoder(dt_us_, sr_hz_, sr_pcm_hz_, s.get()); + lc3_hr_setup_encoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()); } // Encode @@ -135,43 +152,43 @@ class Encoder : public Base<struct lc3_encoder> { // according the type of `pcm` input buffer, or by selecting a format. // // The PCM samples are read in interleaved way, and consecutive - // `nchannels` frames of size `frame_size` are output in `out` buffer. + // `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 frame_size, uint8_t *out) { - return EncodeImpl(PcmFormat::kS16, pcm, frame_size, out); + 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 frame_size, uint8_t *out) { - return EncodeImpl(PcmFormat::kS24, pcm, frame_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 frame_size, uint8_t *out) { - return EncodeImpl(PcmFormat::kF32, pcm, frame_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 frame_size, uint8_t *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), - frame_size, out); + block_size, out); case PcmFormat::kS24: assert(pcm_ptr % alignof(int32_t) == 0); return EncodeImpl(fmt, reinterpret_cast<const int32_t *>(pcm), - frame_size, out); + block_size, out); case PcmFormat::kS24In3Le: return EncodeImpl(fmt, reinterpret_cast<const int8_t(*)[3]>(pcm), - frame_size, out); + block_size, out); case PcmFormat::kF32: assert(pcm_ptr % alignof(float) == 0); - return EncodeImpl(fmt, reinterpret_cast<const float *>(pcm), frame_size, + return EncodeImpl(fmt, reinterpret_cast<const float *>(pcm), block_size, out); } @@ -183,37 +200,47 @@ class Encoder : public Base<struct lc3_encoder> { // Decoder Class class Decoder : public Base<struct lc3_decoder> { template <typename T> - int DecodeImpl(const uint8_t *in, int frame_size, PcmFormat fmt, T *pcm) { + 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; - for (size_t ich = 0; ich < nchannels_; ich++) - ret |= lc3_decode(states[ich].get(), in + ich * frame_size, frame_size, + 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 7500 or 10000 us. - // The samplerate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. + // 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 samplerate of the decoded stream `sr_hz`. + // 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 - // samplerate `sr_hz`. + // sample rate `sr_hz`. - Decoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, size_t nchannels = 1) - : Base(dt_us, sr_hz, sr_pcm_hz, nchannels) { + 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_decoder_size(dt_us_, sr_pcm_hz_)), free); + auto s = state_ptr((lc3_decoder_t) + malloc(lc3_hr_decoder_size(hrmode_, dt_us_, sr_pcm_hz_)), free); - if (lc3_setup_decoder(dt_us_, sr_hz_, sr_pcm_hz_, s.get())) + if (lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get())) states.push_back(std::move(s)); } } @@ -224,12 +251,12 @@ class Decoder : public Base<struct lc3_decoder> { void Reset() { for (auto &s : states) - lc3_setup_decoder(dt_us_, sr_hz_, sr_pcm_hz_, s.get()); + lc3_hr_setup_decoder(hrmode_, dt_us_, sr_hz_, sr_pcm_hz_, s.get()); } // Decode // - // Consecutive `nchannels` frames of size `frame_size` are decoded + // 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, @@ -238,39 +265,39 @@ class Decoder : public Base<struct lc3_decoder> { // The value returned is 0 on successs, 1 when PLC has been performed, // and -1 otherwise. - int Decode(const uint8_t *in, int frame_size, int16_t *pcm) { - return DecodeImpl(in, frame_size, PcmFormat::kS16, pcm); + 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 frame_size, int32_t *pcm) { - return DecodeImpl(in, frame_size, PcmFormat::kS24In3Le, 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 frame_size, float *pcm) { - return DecodeImpl(in, frame_size, PcmFormat::kF32, 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 frame_size, PcmFormat fmt, void *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, frame_size, fmt, + return DecodeImpl(in, block_size, fmt, reinterpret_cast<int16_t *>(pcm)); case PcmFormat::kS24: assert(pcm_ptr % alignof(int32_t) == 0); - return DecodeImpl(in, frame_size, fmt, + return DecodeImpl(in, block_size, fmt, reinterpret_cast<int32_t *>(pcm)); case PcmFormat::kS24In3Le: - return DecodeImpl(in, frame_size, fmt, + return DecodeImpl(in, block_size, fmt, reinterpret_cast<int8_t(*)[3]>(pcm)); case PcmFormat::kF32: assert(pcm_ptr % alignof(float) == 0); - return DecodeImpl(in, frame_size, fmt, reinterpret_cast<float *>(pcm)); + return DecodeImpl(in, block_size, fmt, reinterpret_cast<float *>(pcm)); } return -1; |