mirror of
https://github.com/google/liblc3.git
synced 2026-04-21 23:24:50 +00:00
tools & cpp: Add support of asymetric frame sizes of a stereo stream
This commit is contained in:
@@ -279,14 +279,29 @@ int lc3_hr_frame_bytes(bool hrmode, int dt_us, int sr_hz, int bitrate);
|
|||||||
|
|
||||||
int lc3_frame_bytes(int dt_us, int bitrate);
|
int lc3_frame_bytes(int dt_us, int bitrate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the size of frame blocks, from bitrate
|
||||||
|
* A frame block contains the frame data from all channels.
|
||||||
|
* hrmode Enable High-Resolution mode (48000 and 96000 sample rates)
|
||||||
|
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
|
||||||
|
* sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000
|
||||||
|
* nchannels The number of channels (or frames) in the block (<= 8)
|
||||||
|
* bitrate Target bitrate in bit per second, 0 or `INT_MAX` returns
|
||||||
|
* respectively the minimum and maximum allowed size.
|
||||||
|
* return The floor size in bytes of the frames, -1 on bad parameters
|
||||||
|
*/
|
||||||
|
int lc3_hr_frame_block_bytes(bool hrmode,
|
||||||
|
int dt_us, int sr_hz, int nchannels, int bitrate);
|
||||||
|
|
||||||
|
int lc3_frame_block_bytes(int dt_us, int nframes, int bitrate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the bitrate, from the size of frames
|
* Resolve the bitrate, from the size of frames
|
||||||
* hrmode Enable High-Resolution mode (48000 and 96000 sample rates)
|
* hrmode Enable High-Resolution mode (48000 and 96000 sample rates)
|
||||||
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
|
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
|
||||||
* sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000
|
* sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000
|
||||||
* nbytes Size in bytes of the frames, 0 or `INT_MAX` returns
|
* nbytes Size in bytes of the frames or frame blocks
|
||||||
* respectively the minimum and maximum allowed bitrate.
|
* return The ceiled bitrate in bps, -1 on bad parameters
|
||||||
* return The according bitrate in bps, -1 on bad parameters
|
|
||||||
*/
|
*/
|
||||||
int lc3_hr_resolve_bitrate(bool hrmode, int dt_us, int sr_hz, int nbytes);
|
int lc3_hr_resolve_bitrate(bool hrmode, int dt_us, int sr_hz, int nbytes);
|
||||||
|
|
||||||
|
|||||||
@@ -72,15 +72,20 @@ class Base {
|
|||||||
public:
|
public:
|
||||||
// Return the number of PCM samples in a frame
|
// Return the number of PCM samples in a frame
|
||||||
int GetFrameSamples() {
|
int GetFrameSamples() {
|
||||||
return lc3_hr_frame_samples(hrmode_, dt_us_, sr_pcm_hz_); }
|
return lc3_hr_frame_samples(hrmode_, dt_us_, sr_pcm_hz_); }
|
||||||
|
|
||||||
// Return the size of frames, from bitrate
|
// Return the size of frames, from bitrate
|
||||||
int GetFrameBytes(int bitrate) {
|
int GetFrameBytes(int bitrate) {
|
||||||
return lc3_hr_frame_bytes(hrmode_, dt_us_, sr_hz_, bitrate); }
|
return lc3_hr_frame_bytes(hrmode_, dt_us_, sr_hz_, bitrate); }
|
||||||
|
|
||||||
// Resolve the bitrate, from the size of frames
|
// Return the size of a frame block, from bitrate
|
||||||
|
int GetFrameBlockBytes(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) {
|
int ResolveBitrate(int nbytes) {
|
||||||
return lc3_hr_resolve_bitrate(hrmode_, dt_us_, sr_hz_, nbytes); }
|
return lc3_hr_resolve_bitrate(hrmode_, dt_us_, sr_hz_, nbytes); }
|
||||||
|
|
||||||
// Return algorithmic delay, as a number of samples
|
// Return algorithmic delay, as a number of samples
|
||||||
int GetDelaySamples() {
|
int GetDelaySamples() {
|
||||||
@@ -91,15 +96,22 @@ class Base {
|
|||||||
// Encoder Class
|
// Encoder Class
|
||||||
class Encoder : public Base<struct lc3_encoder> {
|
class Encoder : public Base<struct lc3_encoder> {
|
||||||
template <typename T>
|
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;
|
if (states.size() != nchannels_) return -1;
|
||||||
|
|
||||||
enum lc3_pcm_format cfmt = static_cast<lc3_pcm_format>(fmt);
|
enum lc3_pcm_format cfmt = static_cast<lc3_pcm_format>(fmt);
|
||||||
int ret = 0;
|
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_,
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -144,43 +156,43 @@ class Encoder : public Base<struct lc3_encoder> {
|
|||||||
// according the type of `pcm` input buffer, or by selecting a format.
|
// according the type of `pcm` input buffer, or by selecting a format.
|
||||||
//
|
//
|
||||||
// The PCM samples are read in interleaved way, and consecutive
|
// 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.
|
// The value returned is 0 on successs, -1 otherwise.
|
||||||
|
|
||||||
int Encode(const int16_t *pcm, int frame_size, uint8_t *out) {
|
int Encode(const int16_t *pcm, int block_size, uint8_t *out) {
|
||||||
return EncodeImpl(PcmFormat::kS16, pcm, frame_size, out);
|
return EncodeImpl(PcmFormat::kS16, pcm, block_size, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Encode(const int32_t *pcm, int frame_size, uint8_t *out) {
|
int Encode(const int32_t *pcm, int block_size, uint8_t *out) {
|
||||||
return EncodeImpl(PcmFormat::kS24, pcm, frame_size, out);
|
return EncodeImpl(PcmFormat::kS24, pcm, block_size, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Encode(const float *pcm, int frame_size, uint8_t *out) {
|
int Encode(const float *pcm, int block_size, uint8_t *out) {
|
||||||
return EncodeImpl(PcmFormat::kF32, pcm, frame_size, 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);
|
uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm);
|
||||||
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case PcmFormat::kS16:
|
case PcmFormat::kS16:
|
||||||
assert(pcm_ptr % alignof(int16_t) == 0);
|
assert(pcm_ptr % alignof(int16_t) == 0);
|
||||||
return EncodeImpl(fmt, reinterpret_cast<const int16_t *>(pcm),
|
return EncodeImpl(fmt, reinterpret_cast<const int16_t *>(pcm),
|
||||||
frame_size, out);
|
block_size, out);
|
||||||
|
|
||||||
case PcmFormat::kS24:
|
case PcmFormat::kS24:
|
||||||
assert(pcm_ptr % alignof(int32_t) == 0);
|
assert(pcm_ptr % alignof(int32_t) == 0);
|
||||||
return EncodeImpl(fmt, reinterpret_cast<const int32_t *>(pcm),
|
return EncodeImpl(fmt, reinterpret_cast<const int32_t *>(pcm),
|
||||||
frame_size, out);
|
block_size, out);
|
||||||
|
|
||||||
case PcmFormat::kS24In3Le:
|
case PcmFormat::kS24In3Le:
|
||||||
return EncodeImpl(fmt, reinterpret_cast<const int8_t(*)[3]>(pcm),
|
return EncodeImpl(fmt, reinterpret_cast<const int8_t(*)[3]>(pcm),
|
||||||
frame_size, out);
|
block_size, out);
|
||||||
|
|
||||||
case PcmFormat::kF32:
|
case PcmFormat::kF32:
|
||||||
assert(pcm_ptr % alignof(float) == 0);
|
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);
|
out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,16 +204,23 @@ class Encoder : public Base<struct lc3_encoder> {
|
|||||||
// Decoder Class
|
// Decoder Class
|
||||||
class Decoder : public Base<struct lc3_decoder> {
|
class Decoder : public Base<struct lc3_decoder> {
|
||||||
template <typename T>
|
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;
|
if (states.size() != nchannels_) return -1;
|
||||||
|
|
||||||
enum lc3_pcm_format cfmt = static_cast<enum lc3_pcm_format>(fmt);
|
enum lc3_pcm_format cfmt = static_cast<enum lc3_pcm_format>(fmt);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
for (size_t ich = 0; ich < nchannels_; ich++)
|
const uint8_t *in_ptr = in;
|
||||||
ret |= lc3_decode(states[ich].get(), in + ich * frame_size, frame_size,
|
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_);
|
cfmt, pcm + ich, nchannels_);
|
||||||
|
|
||||||
|
in_ptr += frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +260,7 @@ class Decoder : public Base<struct lc3_decoder> {
|
|||||||
|
|
||||||
// Decode
|
// 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.
|
// in the `pcm` buffer in interleaved way.
|
||||||
//
|
//
|
||||||
// The PCM samples are output in signed 16 bits, 24 bits, float,
|
// The PCM samples are output in signed 16 bits, 24 bits, float,
|
||||||
@@ -250,39 +269,39 @@ class Decoder : public Base<struct lc3_decoder> {
|
|||||||
// The value returned is 0 on successs, 1 when PLC has been performed,
|
// The value returned is 0 on successs, 1 when PLC has been performed,
|
||||||
// and -1 otherwise.
|
// and -1 otherwise.
|
||||||
|
|
||||||
int Decode(const uint8_t *in, int frame_size, int16_t *pcm) {
|
int Decode(const uint8_t *in, int block_size, int16_t *pcm) {
|
||||||
return DecodeImpl(in, frame_size, PcmFormat::kS16, pcm);
|
return DecodeImpl(in, block_size, PcmFormat::kS16, pcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Decode(const uint8_t *in, int frame_size, int32_t *pcm) {
|
int Decode(const uint8_t *in, int block_size, int32_t *pcm) {
|
||||||
return DecodeImpl(in, frame_size, PcmFormat::kS24In3Le, pcm);
|
return DecodeImpl(in, block_size, PcmFormat::kS24In3Le, pcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Decode(const uint8_t *in, int frame_size, float *pcm) {
|
int Decode(const uint8_t *in, int block_size, float *pcm) {
|
||||||
return DecodeImpl(in, frame_size, PcmFormat::kF32, 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);
|
uintptr_t pcm_ptr = reinterpret_cast<uintptr_t>(pcm);
|
||||||
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case PcmFormat::kS16:
|
case PcmFormat::kS16:
|
||||||
assert(pcm_ptr % alignof(int16_t) == 0);
|
assert(pcm_ptr % alignof(int16_t) == 0);
|
||||||
return DecodeImpl(in, frame_size, fmt,
|
return DecodeImpl(in, block_size, fmt,
|
||||||
reinterpret_cast<int16_t *>(pcm));
|
reinterpret_cast<int16_t *>(pcm));
|
||||||
|
|
||||||
case PcmFormat::kS24:
|
case PcmFormat::kS24:
|
||||||
assert(pcm_ptr % alignof(int32_t) == 0);
|
assert(pcm_ptr % alignof(int32_t) == 0);
|
||||||
return DecodeImpl(in, frame_size, fmt,
|
return DecodeImpl(in, block_size, fmt,
|
||||||
reinterpret_cast<int32_t *>(pcm));
|
reinterpret_cast<int32_t *>(pcm));
|
||||||
|
|
||||||
case PcmFormat::kS24In3Le:
|
case PcmFormat::kS24In3Le:
|
||||||
return DecodeImpl(in, frame_size, fmt,
|
return DecodeImpl(in, block_size, fmt,
|
||||||
reinterpret_cast<int8_t(*)[3]>(pcm));
|
reinterpret_cast<int8_t(*)[3]>(pcm));
|
||||||
|
|
||||||
case PcmFormat::kF32:
|
case PcmFormat::kF32:
|
||||||
assert(pcm_ptr % alignof(float) == 0);
|
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;
|
return -1;
|
||||||
|
|||||||
36
src/lc3.c
36
src/lc3.c
@@ -103,21 +103,33 @@ int lc3_frame_samples(int dt_us, int sr_hz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the size of frames, from bitrate
|
* Return the size of frames or frame blocks, from bitrate
|
||||||
*/
|
*/
|
||||||
int lc3_hr_frame_bytes(bool hrmode, int dt_us, int sr_hz, int bitrate)
|
int lc3_hr_frame_block_bytes(bool hrmode,
|
||||||
|
int dt_us, int sr_hz, int nchannels, int bitrate)
|
||||||
{
|
{
|
||||||
enum lc3_dt dt = resolve_dt(dt_us, hrmode);
|
enum lc3_dt dt = resolve_dt(dt_us, hrmode);
|
||||||
enum lc3_srate sr = resolve_srate(sr_hz, hrmode);
|
enum lc3_srate sr = resolve_srate(sr_hz, hrmode);
|
||||||
|
|
||||||
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE)
|
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE
|
||||||
|
|| nchannels < 1 || nchannels > 8 || bitrate < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
bitrate = LC3_CLIP(bitrate,
|
bitrate = LC3_CLIP(bitrate, 0, 8*LC3_HR_MAX_BITRATE);
|
||||||
lc3_hr_resolve_bitrate(hrmode, dt_us, sr_hz, 0),
|
|
||||||
lc3_hr_resolve_bitrate(hrmode, dt_us, sr_hz, INT_MAX));
|
|
||||||
|
|
||||||
return (bitrate * (1 + dt)) / 3200;
|
return LC3_CLIP((bitrate * (1 + dt)) / 3200,
|
||||||
|
nchannels * lc3_min_frame_bytes(dt, sr),
|
||||||
|
nchannels * lc3_max_frame_bytes(dt, sr) );
|
||||||
|
}
|
||||||
|
|
||||||
|
int lc3_frame_bock_bytes(int dt_us, int nchannels, int bitrate)
|
||||||
|
{
|
||||||
|
return lc3_hr_frame_block_bytes(false, dt_us, 8000, nchannels, bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lc3_hr_frame_bytes(bool hrmode, int dt_us, int sr_hz, int bitrate)
|
||||||
|
{
|
||||||
|
return lc3_hr_frame_block_bytes(hrmode, dt_us, sr_hz, 1, bitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lc3_frame_bytes(int dt_us, int bitrate)
|
int lc3_frame_bytes(int dt_us, int bitrate)
|
||||||
@@ -126,21 +138,17 @@ int lc3_frame_bytes(int dt_us, int bitrate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the bitrate, from the size of frames
|
* Resolve the bitrate, from the size of frames or frame blocks
|
||||||
*/
|
*/
|
||||||
int lc3_hr_resolve_bitrate(bool hrmode, int dt_us, int sr_hz, int nbytes)
|
int lc3_hr_resolve_bitrate(bool hrmode, int dt_us, int sr_hz, int nbytes)
|
||||||
{
|
{
|
||||||
enum lc3_dt dt = resolve_dt(dt_us, hrmode);
|
enum lc3_dt dt = resolve_dt(dt_us, hrmode);
|
||||||
enum lc3_srate sr = resolve_srate(sr_hz, hrmode);
|
enum lc3_srate sr = resolve_srate(sr_hz, hrmode);
|
||||||
|
|
||||||
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE)
|
if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE || nbytes < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
nbytes = LC3_CLIP(nbytes,
|
return LC3_MIN(((int64_t)nbytes * 3200 + dt) / (1 + dt), INT_MAX);
|
||||||
lc3_min_frame_bytes(dt, sr),
|
|
||||||
lc3_max_frame_bytes(dt, sr));
|
|
||||||
|
|
||||||
return (nbytes * 3200) / (1 + dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lc3_resolve_bitrate(int dt_us, int nbytes)
|
int lc3_resolve_bitrate(int dt_us, int nbytes)
|
||||||
|
|||||||
47
tools/dlc3.c
47
tools/dlc3.c
@@ -31,6 +31,8 @@
|
|||||||
#include "lc3bin.h"
|
#include "lc3bin.h"
|
||||||
#include "wave.h"
|
#include "wave.h"
|
||||||
|
|
||||||
|
#define MAX_CHANNELS 2
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
|
#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
|
||||||
#endif
|
#endif
|
||||||
@@ -158,15 +160,15 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* --- Check parameters --- */
|
/* --- Check parameters --- */
|
||||||
|
|
||||||
int frame_us, srate_hz, nch, nsamples;
|
int frame_us, srate_hz, nchannels, nsamples;
|
||||||
bool hrmode;
|
bool hrmode;
|
||||||
|
|
||||||
if (lc3bin_read_header(fp_in,
|
if (lc3bin_read_header(fp_in,
|
||||||
&frame_us, &srate_hz, &hrmode, &nch, &nsamples) < 0)
|
&frame_us, &srate_hz, &hrmode, &nchannels, &nsamples) < 0)
|
||||||
error(EINVAL, "LC3 binary input file");
|
error(EINVAL, "LC3 binary input file");
|
||||||
|
|
||||||
if (nch < 1 || nch > 2)
|
if (nchannels < 1 || nchannels > MAX_CHANNELS)
|
||||||
error(EINVAL, "Number of channels %d", nch);
|
error(EINVAL, "Number of channels %d", nchannels);
|
||||||
|
|
||||||
if (!LC3_CHECK_DT_US(frame_us))
|
if (!LC3_CHECK_DT_US(frame_us))
|
||||||
error(EINVAL, "Frame duration");
|
error(EINVAL, "Frame duration");
|
||||||
@@ -186,7 +188,7 @@ int main(int argc, char *argv[])
|
|||||||
((int64_t)nsamples * pcm_srate_hz) / srate_hz;
|
((int64_t)nsamples * pcm_srate_hz) / srate_hz;
|
||||||
|
|
||||||
wave_write_header(fp_out,
|
wave_write_header(fp_out,
|
||||||
pcm_sbits, pcm_sbytes, pcm_srate_hz, nch, pcm_samples);
|
pcm_sbits, pcm_sbytes, pcm_srate_hz, nchannels, pcm_samples);
|
||||||
|
|
||||||
/* --- Setup decoding --- */
|
/* --- Setup decoding --- */
|
||||||
|
|
||||||
@@ -200,7 +202,7 @@ int main(int argc, char *argv[])
|
|||||||
enum lc3_pcm_format pcm_fmt =
|
enum lc3_pcm_format pcm_fmt =
|
||||||
pcm_sbits == 24 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
pcm_sbits == 24 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
||||||
|
|
||||||
for (int ich = 0; ich < nch; ich++) {
|
for (int ich = 0; ich < nchannels; ich++) {
|
||||||
dec[ich] = lc3_hr_setup_decoder(
|
dec[ich] = lc3_hr_setup_decoder(
|
||||||
hrmode, frame_us, srate_hz, p.srate_hz,
|
hrmode, frame_us, srate_hz, p.srate_hz,
|
||||||
malloc(lc3_hr_decoder_size(hrmode, frame_us, pcm_srate_hz)));
|
malloc(lc3_hr_decoder_size(hrmode, frame_us, pcm_srate_hz)));
|
||||||
@@ -214,11 +216,12 @@ int main(int argc, char *argv[])
|
|||||||
static const char *dash_line = "========================================";
|
static const char *dash_line = "========================================";
|
||||||
|
|
||||||
int nsec = 0;
|
int nsec = 0;
|
||||||
|
int nerr = 0;
|
||||||
unsigned t0 = clock_us();
|
unsigned t0 = clock_us();
|
||||||
|
|
||||||
for (int i = 0; i * frame_samples < encode_samples; i++) {
|
for (int i = 0; i * frame_samples < encode_samples; i++) {
|
||||||
|
|
||||||
int frame_bytes = lc3bin_read_data(fp_in, nch, in);
|
int block_bytes = lc3bin_read_data(fp_in, nchannels, in);
|
||||||
|
|
||||||
if (floorf(i * frame_us * 1e-6) > nsec) {
|
if (floorf(i * frame_us * 1e-6) > nsec) {
|
||||||
|
|
||||||
@@ -231,19 +234,28 @@ int main(int argc, char *argv[])
|
|||||||
nsec = rint(i * frame_us * 1e-6);
|
nsec = rint(i * frame_us * 1e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_bytes <= 0)
|
if (block_bytes <= 0)
|
||||||
memset(pcm, 0, nch * frame_samples * pcm_sbytes);
|
memset(pcm, 0, nchannels * frame_samples * pcm_sbytes);
|
||||||
else
|
else {
|
||||||
for (int ich = 0; ich < nch; ich++)
|
const uint8_t *in_ptr = in;
|
||||||
lc3_decode(dec[ich],
|
for (int ich = 0; ich < nchannels; ich++) {
|
||||||
in + ich * frame_bytes, frame_bytes,
|
int frame_bytes = block_bytes / nchannels
|
||||||
pcm_fmt, pcm + ich * pcm_sbytes, nch);
|
+ (ich < block_bytes % nchannels);
|
||||||
|
|
||||||
|
int res = lc3_decode(dec[ich], in_ptr, frame_bytes,
|
||||||
|
pcm_fmt, pcm + ich * pcm_sbytes, nchannels);
|
||||||
|
|
||||||
|
nerr += (res != 0);
|
||||||
|
in_ptr += frame_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int pcm_offset = i > 0 ? 0 : encode_samples - pcm_samples;
|
int pcm_offset = i > 0 ? 0 : encode_samples - pcm_samples;
|
||||||
int pcm_nwrite = MIN(frame_samples - pcm_offset,
|
int pcm_nwrite = MIN(frame_samples - pcm_offset,
|
||||||
encode_samples - i*frame_samples);
|
encode_samples - i*frame_samples);
|
||||||
|
|
||||||
wave_write_pcm(fp_out, pcm_sbytes, pcm, nch, pcm_offset, pcm_nwrite);
|
wave_write_pcm(fp_out,
|
||||||
|
pcm_sbytes, pcm, nchannels, pcm_offset, pcm_nwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned t = (clock_us() - t0) / 1000;
|
unsigned t = (clock_us() - t0) / 1000;
|
||||||
@@ -252,9 +264,12 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n",
|
fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n",
|
||||||
nsec / 60, nsec % 60, t / 1000, t % 1000, "");
|
nsec / 60, nsec % 60, t / 1000, t % 1000, "");
|
||||||
|
|
||||||
|
if (nerr)
|
||||||
|
fprintf(stderr, "Warning: Decoding of %d frames failed!\n", nerr);
|
||||||
|
|
||||||
/* --- Cleanup --- */
|
/* --- Cleanup --- */
|
||||||
|
|
||||||
for (int ich = 0; ich < nch; ich++)
|
for (int ich = 0; ich < nchannels; ich++)
|
||||||
free(dec[ich]);
|
free(dec[ich]);
|
||||||
|
|
||||||
if (fp_in != stdin)
|
if (fp_in != stdin)
|
||||||
|
|||||||
50
tools/elc3.c
50
tools/elc3.c
@@ -31,6 +31,8 @@
|
|||||||
#include "lc3bin.h"
|
#include "lc3bin.h"
|
||||||
#include "wave.h"
|
#include "wave.h"
|
||||||
|
|
||||||
|
#define MAX_CHANNELS 2
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error handling
|
* Error handling
|
||||||
@@ -158,11 +160,11 @@ int main(int argc, char *argv[])
|
|||||||
/* --- Check parameters --- */
|
/* --- Check parameters --- */
|
||||||
|
|
||||||
int frame_us = p.frame_ms * 1000;
|
int frame_us = p.frame_ms * 1000;
|
||||||
int srate_hz, nch, nsamples;
|
int srate_hz, nchannels, nsamples;
|
||||||
int pcm_sbits, pcm_sbytes;
|
int pcm_sbits, pcm_sbytes;
|
||||||
|
|
||||||
if (wave_read_header(fp_in,
|
if (wave_read_header(fp_in,
|
||||||
&pcm_sbits, &pcm_sbytes, &srate_hz, &nch, &nsamples) < 0)
|
&pcm_sbits, &pcm_sbytes, &srate_hz, &nchannels, &nsamples) < 0)
|
||||||
error(EINVAL, "Bad or unsupported WAVE input file");
|
error(EINVAL, "Bad or unsupported WAVE input file");
|
||||||
|
|
||||||
if (p.bitrate <= 0)
|
if (p.bitrate <= 0)
|
||||||
@@ -181,8 +183,8 @@ int main(int argc, char *argv[])
|
|||||||
(pcm_sbits == 24 && pcm_sbytes != 24/8 && pcm_sbytes != 32/8))
|
(pcm_sbits == 24 && pcm_sbytes != 24/8 && pcm_sbytes != 32/8))
|
||||||
error(EINVAL, "Sample storage on %d bytes", pcm_sbytes);
|
error(EINVAL, "Sample storage on %d bytes", pcm_sbytes);
|
||||||
|
|
||||||
if (nch < 1 || nch > 2)
|
if (nchannels < 1 || nchannels > MAX_CHANNELS)
|
||||||
error(EINVAL, "Number of channels %d", nch);
|
error(EINVAL, "Number of channels %d", nchannels);
|
||||||
|
|
||||||
if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(p.hrmode, p.srate_hz) ||
|
if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(p.hrmode, p.srate_hz) ||
|
||||||
p.srate_hz > srate_hz ))
|
p.srate_hz > srate_hz ))
|
||||||
@@ -192,9 +194,18 @@ int main(int argc, char *argv[])
|
|||||||
int enc_samples = !p.srate_hz ? nsamples :
|
int enc_samples = !p.srate_hz ? nsamples :
|
||||||
((int64_t)nsamples * enc_srate_hz) / srate_hz;
|
((int64_t)nsamples * enc_srate_hz) / srate_hz;
|
||||||
|
|
||||||
|
int block_bytes = lc3_hr_frame_block_bytes(
|
||||||
|
p.hrmode, frame_us, srate_hz, nchannels, p.bitrate);
|
||||||
|
|
||||||
|
int bitrate = lc3_hr_resolve_bitrate(
|
||||||
|
p.hrmode, frame_us, srate_hz, block_bytes);
|
||||||
|
|
||||||
|
if (bitrate != p.bitrate)
|
||||||
|
fprintf(stderr, "Bitrate adjusted to %d bps\n", bitrate);
|
||||||
|
|
||||||
lc3bin_write_header(fp_out,
|
lc3bin_write_header(fp_out,
|
||||||
frame_us, enc_srate_hz, p.hrmode,
|
frame_us, enc_srate_hz, p.hrmode,
|
||||||
p.bitrate, nch, enc_samples);
|
bitrate, nchannels, enc_samples);
|
||||||
|
|
||||||
/* --- Setup encoding --- */
|
/* --- Setup encoding --- */
|
||||||
|
|
||||||
@@ -202,8 +213,6 @@ int main(int argc, char *argv[])
|
|||||||
uint8_t out[2 * LC3_HR_MAX_FRAME_BYTES];
|
uint8_t out[2 * LC3_HR_MAX_FRAME_BYTES];
|
||||||
lc3_encoder_t enc[2];
|
lc3_encoder_t enc[2];
|
||||||
|
|
||||||
int frame_bytes = lc3_hr_frame_bytes(
|
|
||||||
p.hrmode, frame_us, srate_hz, p.bitrate / nch);
|
|
||||||
int frame_samples = lc3_hr_frame_samples(
|
int frame_samples = lc3_hr_frame_samples(
|
||||||
p.hrmode, frame_us, srate_hz);
|
p.hrmode, frame_us, srate_hz);
|
||||||
int encode_samples = nsamples + lc3_hr_delay_samples(
|
int encode_samples = nsamples + lc3_hr_delay_samples(
|
||||||
@@ -212,7 +221,7 @@ int main(int argc, char *argv[])
|
|||||||
pcm_sbytes == 32/8 ? LC3_PCM_FORMAT_S24 :
|
pcm_sbytes == 32/8 ? LC3_PCM_FORMAT_S24 :
|
||||||
pcm_sbytes == 24/8 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
pcm_sbytes == 24/8 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
||||||
|
|
||||||
for (int ich = 0; ich < nch; ich++) {
|
for (int ich = 0; ich < nchannels; ich++) {
|
||||||
enc[ich] = lc3_hr_setup_encoder(
|
enc[ich] = lc3_hr_setup_encoder(
|
||||||
p.hrmode, frame_us, enc_srate_hz, srate_hz,
|
p.hrmode, frame_us, enc_srate_hz, srate_hz,
|
||||||
malloc(lc3_hr_encoder_size(p.hrmode, frame_us, srate_hz)));
|
malloc(lc3_hr_encoder_size(p.hrmode, frame_us, srate_hz)));
|
||||||
@@ -230,10 +239,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
for (int i = 0; i * frame_samples < encode_samples; i++) {
|
for (int i = 0; i * frame_samples < encode_samples; i++) {
|
||||||
|
|
||||||
int nread = wave_read_pcm(fp_in, pcm_sbytes, nch, frame_samples, pcm);
|
int nread = wave_read_pcm(fp_in, pcm_sbytes, nchannels, frame_samples, pcm);
|
||||||
|
|
||||||
memset(pcm + nread * nch * pcm_sbytes, 0,
|
memset(pcm + nread * nchannels * pcm_sbytes, 0,
|
||||||
nch * (frame_samples - nread) * pcm_sbytes);
|
nchannels * (frame_samples - nread) * pcm_sbytes);
|
||||||
|
|
||||||
if (floorf(i * frame_us * 1e-6) > nsec) {
|
if (floorf(i * frame_us * 1e-6) > nsec) {
|
||||||
float progress = fminf(
|
float progress = fminf(
|
||||||
@@ -246,12 +255,19 @@ int main(int argc, char *argv[])
|
|||||||
nsec = (int)(i * frame_us * 1e-6);
|
nsec = (int)(i * frame_us * 1e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ich = 0; ich < nch; ich++)
|
uint8_t *out_ptr = out;
|
||||||
lc3_encode(enc[ich],
|
for (int ich = 0; ich < nchannels; ich++) {
|
||||||
pcm_fmt, pcm + ich * pcm_sbytes, nch,
|
int frame_bytes = block_bytes / nchannels
|
||||||
frame_bytes, out + ich * frame_bytes);
|
+ (ich < block_bytes % nchannels);
|
||||||
|
|
||||||
lc3bin_write_data(fp_out, out, nch, frame_bytes);
|
lc3_encode(enc[ich],
|
||||||
|
pcm_fmt, pcm + ich * pcm_sbytes, nchannels,
|
||||||
|
frame_bytes, out_ptr);
|
||||||
|
|
||||||
|
out_ptr += frame_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc3bin_write_data(fp_out, out, block_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned t = (clock_us() - t0) / 1000;
|
unsigned t = (clock_us() - t0) / 1000;
|
||||||
@@ -262,7 +278,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* --- Cleanup --- */
|
/* --- Cleanup --- */
|
||||||
|
|
||||||
for (int ich = 0; ich < nch; ich++)
|
for (int ich = 0; ich < nchannels; ich++)
|
||||||
free(enc[ich]);
|
free(enc[ich]);
|
||||||
|
|
||||||
if (fp_in != stdin)
|
if (fp_in != stdin)
|
||||||
|
|||||||
@@ -80,12 +80,11 @@ int lc3bin_read_data(FILE *fp, int nchannels, void *buffer)
|
|||||||
uint16_t nbytes;
|
uint16_t nbytes;
|
||||||
|
|
||||||
if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1
|
if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1
|
||||||
|| nbytes > nchannels * LC3_MAX_FRAME_BYTES
|
|| nbytes > nchannels * LC3_HR_MAX_FRAME_BYTES
|
||||||
|| nbytes % nchannels
|
|
||||||
|| fread(buffer, nbytes, 1, fp) < 1)
|
|| fread(buffer, nbytes, 1, fp) < 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return nbytes / nchannels;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,11 +117,10 @@ void lc3bin_write_header(FILE *fp,
|
|||||||
/**
|
/**
|
||||||
* Write LC3 block of data
|
* Write LC3 block of data
|
||||||
*/
|
*/
|
||||||
void lc3bin_write_data(FILE *fp,
|
void lc3bin_write_data(FILE *fp, const void *data, int nbytes)
|
||||||
const void *data, int nchannels, int frame_bytes)
|
|
||||||
{
|
{
|
||||||
uint16_t nbytes = nchannels * frame_bytes;
|
uint16_t hdr_nbytes = nbytes;
|
||||||
fwrite(&nbytes, sizeof(nbytes), 1, fp);
|
fwrite(&hdr_nbytes, sizeof(hdr_nbytes), 1, fp);
|
||||||
|
|
||||||
fwrite(data, 1, nbytes, fp);
|
fwrite(data, 1, nbytes, fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ int lc3bin_read_header(FILE *fp,
|
|||||||
* Read LC3 block of data
|
* Read LC3 block of data
|
||||||
* fp Opened file
|
* fp Opened file
|
||||||
* nchannels Number of channels
|
* nchannels Number of channels
|
||||||
* buffer Output buffer of `nchannels * LC3_MAX_FRAME_BYTES`
|
* buffer Output buffer of `nchannels * LC3_HR_MAX_FRAME_BYTES`
|
||||||
* return Size of each 'nchannels` frames, -1 on error
|
* return Size of the frames block, -1 on error
|
||||||
*/
|
*/
|
||||||
int lc3bin_read_data(FILE *fp, int nchannels, void *buffer);
|
int lc3bin_read_data(FILE *fp, int nchannels, void *buffer);
|
||||||
|
|
||||||
@@ -65,11 +65,9 @@ void lc3bin_write_header(FILE *fp,
|
|||||||
* Write LC3 block of data
|
* Write LC3 block of data
|
||||||
* fp Opened file
|
* fp Opened file
|
||||||
* data The frames data
|
* data The frames data
|
||||||
* nchannels Number of channels
|
* nbytes Size of the frames block
|
||||||
* frame_bytes Size of each `nchannels` frames
|
|
||||||
*/
|
*/
|
||||||
void lc3bin_write_data(FILE *fp,
|
void lc3bin_write_data(FILE *fp, const void *data, int nbytes);
|
||||||
const void *data, int nchannels, int frame_bytes);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LC3BIN_H */
|
#endif /* __LC3BIN_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user