tools & cpp: Add support of asymetric frame sizes of a stereo stream
diff --git a/include/lc3.h b/include/lc3.h
index 614a58a..9745d64 100644
--- a/include/lc3.h
+++ b/include/lc3.h
@@ -280,13 +280,28 @@
 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
  * 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
- * nbytes          Size in bytes of the frames, 0 or `INT_MAX` returns
- *                 respectively the minimum and maximum allowed bitrate.
- * return          The according bitrate in bps, -1 on bad parameters
+ * nbytes          Size in bytes of the frames or frame blocks
+ * return          The ceiled bitrate in bps, -1 on bad parameters
  */
 int lc3_hr_resolve_bitrate(bool hrmode, int dt_us, int sr_hz, int nbytes);
 
diff --git a/include/lc3_cpp.h b/include/lc3_cpp.h
index 3900b9b..bd16711 100644
--- a/include/lc3_cpp.h
+++ b/include/lc3_cpp.h
@@ -72,15 +72,20 @@
  public:
   // Return the number of PCM samples in a frame
   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
   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) {
-      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
   int GetDelaySamples() {
@@ -91,15 +96,22 @@
 // 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;
   }
@@ -144,43 +156,43 @@
   // 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);
     }
 
@@ -192,16 +204,23 @@
 // 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;
   }
 
@@ -241,7 +260,7 @@
 
   // 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,
@@ -250,39 +269,39 @@
   // 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;
diff --git a/src/lc3.c b/src/lc3.c
index dc7ebe7..56cdc14 100644
--- a/src/lc3.c
+++ b/src/lc3.c
@@ -103,21 +103,33 @@
 }
 
 /**
- * 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_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;
 
-    bitrate = LC3_CLIP(bitrate,
-        lc3_hr_resolve_bitrate(hrmode, dt_us, sr_hz, 0),
-        lc3_hr_resolve_bitrate(hrmode, dt_us, sr_hz, INT_MAX));
+    bitrate = LC3_CLIP(bitrate, 0, 8*LC3_HR_MAX_BITRATE);
 
-    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)
@@ -126,21 +138,17 @@
 }
 
 /**
- * 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)
 {
     enum lc3_dt dt = resolve_dt(dt_us, 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;
 
-    nbytes = LC3_CLIP(nbytes,
-        lc3_min_frame_bytes(dt, sr),
-        lc3_max_frame_bytes(dt, sr));
-
-    return (nbytes * 3200) / (1 + dt);
+    return LC3_MIN(((int64_t)nbytes * 3200 + dt) / (1 + dt), INT_MAX);
 }
 
 int lc3_resolve_bitrate(int dt_us, int nbytes)
diff --git a/tools/dlc3.c b/tools/dlc3.c
index d351324..2259000 100644
--- a/tools/dlc3.c
+++ b/tools/dlc3.c
@@ -31,6 +31,8 @@
 #include "lc3bin.h"
 #include "wave.h"
 
+#define MAX_CHANNELS 2
+
 #ifndef MIN
 #define MIN(a, b)  ( (a) < (b) ? (a) : (b) )
 #endif
@@ -158,15 +160,15 @@
 
     /* --- Check parameters --- */
 
-    int frame_us, srate_hz, nch, nsamples;
+    int frame_us, srate_hz, nchannels, nsamples;
     bool hrmode;
 
     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");
 
-    if (nch  < 1 || nch  > 2)
-        error(EINVAL, "Number of channels %d", nch);
+    if (nchannels < 1 || nchannels > MAX_CHANNELS)
+        error(EINVAL, "Number of channels %d", nchannels);
 
     if (!LC3_CHECK_DT_US(frame_us))
         error(EINVAL, "Frame duration");
@@ -186,7 +188,7 @@
         ((int64_t)nsamples * pcm_srate_hz) / srate_hz;
 
     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 --- */
 
@@ -200,7 +202,7 @@
     enum lc3_pcm_format pcm_fmt =
         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(
             hrmode, frame_us, srate_hz, p.srate_hz,
             malloc(lc3_hr_decoder_size(hrmode, frame_us, pcm_srate_hz)));
@@ -214,11 +216,12 @@
     static const char *dash_line = "========================================";
 
     int nsec = 0;
+    int nerr = 0;
     unsigned t0 = clock_us();
 
     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) {
 
@@ -231,19 +234,28 @@
             nsec = rint(i * frame_us * 1e-6);
         }
 
-        if (frame_bytes <= 0)
-            memset(pcm, 0, nch * frame_samples * pcm_sbytes);
-        else
-            for (int ich = 0; ich < nch; ich++)
-                lc3_decode(dec[ich],
-                    in + ich * frame_bytes, frame_bytes,
-                    pcm_fmt, pcm + ich * pcm_sbytes, nch);
+        if (block_bytes <= 0)
+            memset(pcm, 0, nchannels * frame_samples * pcm_sbytes);
+        else {
+            const uint8_t *in_ptr = in;
+            for (int ich = 0; ich < nchannels; ich++) {
+                int frame_bytes = block_bytes / nchannels
+                    + (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_nwrite = MIN(frame_samples - pcm_offset,
             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;
@@ -252,9 +264,12 @@
     fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n",
         nsec / 60, nsec % 60, t / 1000, t % 1000, "");
 
+    if (nerr)
+        fprintf(stderr, "Warning: Decoding of %d frames failed!\n", nerr);
+
     /* --- Cleanup --- */
 
-    for (int ich = 0; ich < nch; ich++)
+    for (int ich = 0; ich < nchannels; ich++)
         free(dec[ich]);
 
     if (fp_in != stdin)
diff --git a/tools/elc3.c b/tools/elc3.c
index 4d7b010..dec8bb0 100644
--- a/tools/elc3.c
+++ b/tools/elc3.c
@@ -31,6 +31,8 @@
 #include "lc3bin.h"
 #include "wave.h"
 
+#define MAX_CHANNELS 2
+
 
 /**
  * Error handling
@@ -158,11 +160,11 @@
     /* --- Check parameters --- */
 
     int frame_us = p.frame_ms * 1000;
-    int srate_hz, nch, nsamples;
+    int srate_hz, nchannels, nsamples;
     int pcm_sbits, pcm_sbytes;
 
     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");
 
     if (p.bitrate <= 0)
@@ -181,8 +183,8 @@
         (pcm_sbits == 24 && pcm_sbytes != 24/8 && pcm_sbytes != 32/8))
         error(EINVAL, "Sample storage on %d bytes", pcm_sbytes);
 
-    if (nch  < 1 || nch  > 2)
-        error(EINVAL, "Number of channels %d", nch);
+    if (nchannels < 1 || nchannels > MAX_CHANNELS)
+        error(EINVAL, "Number of channels %d", nchannels);
 
     if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(p.hrmode, p.srate_hz) ||
                        p.srate_hz > srate_hz                       ))
@@ -192,9 +194,18 @@
     int enc_samples = !p.srate_hz ? nsamples :
         ((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,
         frame_us, enc_srate_hz, p.hrmode,
-        p.bitrate, nch, enc_samples);
+        bitrate, nchannels, enc_samples);
 
     /* --- Setup encoding --- */
 
@@ -202,8 +213,6 @@
     uint8_t out[2 * LC3_HR_MAX_FRAME_BYTES];
     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(
         p.hrmode, frame_us, srate_hz);
     int encode_samples = nsamples + lc3_hr_delay_samples(
@@ -212,7 +221,7 @@
         pcm_sbytes == 32/8 ? LC3_PCM_FORMAT_S24 :
         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(
             p.hrmode, frame_us, enc_srate_hz, srate_hz,
             malloc(lc3_hr_encoder_size(p.hrmode, frame_us, srate_hz)));
@@ -230,10 +239,10 @@
 
     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,
-            nch * (frame_samples - nread) * pcm_sbytes);
+        memset(pcm + nread * nchannels * pcm_sbytes, 0,
+            nchannels * (frame_samples - nread) * pcm_sbytes);
 
         if (floorf(i * frame_us * 1e-6) > nsec) {
             float progress = fminf(
@@ -246,12 +255,19 @@
             nsec = (int)(i * frame_us * 1e-6);
         }
 
-        for (int ich = 0; ich < nch; ich++)
-            lc3_encode(enc[ich],
-                pcm_fmt, pcm + ich * pcm_sbytes, nch,
-                frame_bytes, out + ich * frame_bytes);
+        uint8_t *out_ptr = out;
+        for (int ich = 0; ich < nchannels; ich++) {
+            int frame_bytes = block_bytes / nchannels
+                + (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;
@@ -262,7 +278,7 @@
 
     /* --- Cleanup --- */
 
-    for (int ich = 0; ich < nch; ich++)
+    for (int ich = 0; ich < nchannels; ich++)
         free(enc[ich]);
 
     if (fp_in != stdin)
diff --git a/tools/lc3bin.c b/tools/lc3bin.c
index 576cab5..97ae82b 100644
--- a/tools/lc3bin.c
+++ b/tools/lc3bin.c
@@ -80,12 +80,11 @@
     uint16_t nbytes;
 
     if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1
-            || nbytes > nchannels * LC3_MAX_FRAME_BYTES
-            || nbytes % nchannels
+            || nbytes > nchannels * LC3_HR_MAX_FRAME_BYTES
             || fread(buffer, nbytes, 1, fp) < 1)
         return -1;
 
-    return nbytes / nchannels;
+    return nbytes;
 }
 
 /**
@@ -118,11 +117,10 @@
 /**
  * Write LC3 block of data
  */
-void lc3bin_write_data(FILE *fp,
-    const void *data, int nchannels, int frame_bytes)
+void lc3bin_write_data(FILE *fp, const void *data, int nbytes)
 {
-    uint16_t nbytes = nchannels * frame_bytes;
-    fwrite(&nbytes, sizeof(nbytes), 1, fp);
+    uint16_t hdr_nbytes = nbytes;
+    fwrite(&hdr_nbytes, sizeof(hdr_nbytes), 1, fp);
 
     fwrite(data, 1, nbytes, fp);
 }
diff --git a/tools/lc3bin.h b/tools/lc3bin.h
index 378511b..3eccb37 100644
--- a/tools/lc3bin.h
+++ b/tools/lc3bin.h
@@ -42,8 +42,8 @@
  * Read LC3 block of data
  * fp              Opened file
  * nchannels       Number of channels
- * buffer          Output buffer of `nchannels * LC3_MAX_FRAME_BYTES`
- * return          Size of each 'nchannels` frames, -1 on error
+ * buffer          Output buffer of `nchannels * LC3_HR_MAX_FRAME_BYTES`
+ * return          Size of the frames block, -1 on error
  */
 int lc3bin_read_data(FILE *fp, int nchannels, void *buffer);
 
@@ -65,11 +65,9 @@
  * Write LC3 block of data
  * fp              Opened file
  * data            The frames data
- * nchannels       Number of channels
- * frame_bytes     Size of each `nchannels` frames
+ * nbytes          Size of the frames block
  */
-void lc3bin_write_data(FILE *fp,
-    const void *data, int nchannels, int frame_bytes);
+void lc3bin_write_data(FILE *fp, const void *data, int nbytes);
 
 
 #endif /* __LC3BIN_H */