LIBTTAr_TTA_ENCODE(3)

NAME
libttaR_tta_encode, libttaR_tta_decode - a reentrant TTA codec

SYNOPSIS
#include <libttaR.h>
int libttaR_tta_encode(
    uint8_t *dest, const int32_t *src, size_t dest_len,
    size_t src_len, size_t ni32_target,
    struct LibTTAr_CodecState_Priv *priv,
    struct LibTTAr_CodecState_User *user,
    enum TTASampleBytes samplebytes, unsigned int nchan,
    size_t ni32_perframe
);
int libttaR_tta_decode(
    int32_t *dest, const uint8_t *src, size_t dest_len,
    size_t src_len, size_t ni32_target, size_t nbytes_tta_target,
    struct LibTTAr_CodecState_Priv *priv,
    struct LibTTAr_CodecState_User *user,
    enum TTASampleBytes samplebytes, unsigned int nchan,
    size_t ni32_perframe, size_t nbytes_tta_perframe
);

DESCRIPTION
libttaR_tta_encode() encodes at most ni32_target signed 32-bit PCM samples of originally samplebytes-sized PCM with nchan channels into TTA with ni32_perframe total PCM samples per TTA frame from buffer src of length src_len into buffer dest of size dest_len while reading and writing the encoder's state from/to priv and user. libttaR_tta_decode() decodes at most nbytes_tta_target bytes of TTA with ni32_perframe total signed 32-bit PCM samples per TTA frame and an encoded frame size of nbytes_tta_perframe into at most ni32_target total samples of signed 32-bit PCM of originally samplebytes-sized PCM with nchan channels from buffer src of size src_len into buffer dest of length dest_len while reading and writing the decoder's state from/to priv and user.

  Arguments
*dest
    The destination buffer. Needs to be padded with at least libttaR_ttabuf_safety_margin() bytes when encoding.
*src
    The source buffer. Needs to be padded with at least libttaR_ttabuf_safety_margin() bytes when decoding.
dest_len
    The length of the destination buffer.
src_len
    The length of the source buffer.
ni32_target
    The target number of int32_t PCM from the src/dest buffer to encode/decode. Must be evenly divisible by nchan.
nbytes_tta_target
    The target number of TTA bytes from the dest/src buffer to encode/decode.
*priv
    The codec's private state. The struct is opaque and needs to be allocated with the size from libttaR_codecstate_priv_size().
*user
    The codec's user readable state. Must be initialized with LIBTTAr_CODECSTATE_USER_INIT before the first call for a new frame.
    struct LibTTAr_CodecState_User {
        uint32_t    ncalls_codec;
        uint32_t    crc;
        size_t      ni32;
        size_t      ni32_total;
        size_t      nbytes_tta;
        size_t      nbytes_tta_total;
    };
    ncalls_codec:
        number of successful calls to the codec function
    crc:
        frame CRC
    ni32:
        number of int32_t PCM read/written for the last call
    ni32_total:
        total number of int32_t PCM read/written across all calls for the current frame
    nbytes_tta:
        number of TTA bytes written/read for the last call
    nbytes_tta_total:
        total number of TTA bytes written/read across all calls for the current frame
samplebytes
    The number of bytes per samples in the originally sized PCM.
    enum TTASampleBytes {
        TTASAMPLEBYTES_1 = 1u,
        TTASAMPLEBYTES_2 = 2u,
        TTASAMPLEBYTES_3 = 3u
    };
nchan
    The number of audio channels in the PCM.
ni32_perframe
    The number of uncoded int32_t per TTA frame.
nbytes_tta_perframe
    The number of encoded bytes in the current TTA frame.

  Warning
*priv, *user, nchan, ni32_perframe, and nbytes_tta_perframe should not be modified between consecutive calls for the same frame, unless you know what you are doing.

RETURN VALUE
On success:
    LIBTTAr_RET_DONE
        The frame finished coding.
    LIBTTAr_RET_AGAIN
        The frame did not finish coding.
    LIBTTAr_RET_DECFAIL
        The frame finished decoding, but (user->nbytes_tta_total != nbytes_tta_perframe), or the frame did not finish decoding, but (user->nbytes_tta_total > nbytes_tta_perframe). This would be caused by either corrupted or malformed TTA data. The absense of this value does not guarantee that the data was correctly decoded, only that the "correct" number of bytes was read. There is a check in the rice decoder to stop after reading so many bytes, but it does not return an error, it just stops reading the current code and then continues (for performance reasons). It should be possible to construct an invalid TTA frame (with a good CRC) that could get the decoder to read the "correct" number of bytes.

ERRORS
    >=LIBTTAr_RET_INVAL
        (ni32_target % nchan != 0) or other bad parameter, such as a size_t argument that could cause a bounds error. LIBTTAr_RET_INVAL is used as the base value; the functions can return greater values.
    LIBTTAr_RET_MISCONFIG
        The library was misconfigured when built; see libttaR_test_nchan().

ATTRIBUTES
Both are MT-Safe.

EXAMPLES

  libttaR/src/cli/modes/mode_encode_loop.c
    // may be older code
    static void
    enc_frame_encode(
        struct EncBuf *const restrict encbuf,
        /*@reldef@*/ struct LibTTAr_CodecState_Priv *const restrict priv,
        /*@out@*/ struct LibTTAr_CodecState_User *const restrict user_out,
        const enum TTASampleBytes samplebytes, const uint nchan,
        const size_t ni32_perframe
    )
    /*@globals      fileSystem,
                    internalState
    @*/
    /*@modifies     fileSystem,
                    internalState,
                    encbuf->ttabuf_len,
                    *encbuf->i32buf,
                    encbuf->ttabuf,
                    *encbuf->ttabuf,
                    *priv,
                    *user_out
    @*/
    {
        struct LibTTAr_CodecState_User user = LIBTTAr_CODECSTATE_USER_INIT;
        size_t ni32_target = ni32_perframe;
        union { size_t  z;
                int     d;
        } t;
        assert(encbuf->i32buf != NULL);
        // convert pcm to i32
        t.z = libttaR_pcm_read(
                encbuf->i32buf, encbuf->pcmbuf, ni32_target, samplebytes
        );
        assert(t.z == ni32_target);
        // encode i32 to tta
        goto loop_entr;
        do {
               encbuf_adjust(encbuf, TTABUF_LEN_DEFAULT, nchan);
               ni32_target = ni32_perframe - user.ni32_total;
    loop_entr:
               t.d = libttaR_tta_encode(
                       &encbuf->ttabuf[user.nbytes_tta_total],
                       &encbuf->i32buf[user.ni32_total],
                       encbuf->ttabuf_len - user.nbytes_tta_total,
                       encbuf->i32buf_len - user.ni32_total,
                       ni32_target, priv, &user, samplebytes, nchan,
                       ni32_perframe
               );
               assert((t.d == LIBTTAr_RET_DONE)
                     ||
                      (t.d == LIBTTAr_RET_AGAIN)
               );
        }
        while ( t.d == LIBTTAr_RET_AGAIN );
        *user_out = user;
        return;
    }

  libttaR/src/cli/modes/mode_decode_loop.c
    // may be older code
    static int
    dec_frame_decode(
        struct DecBuf *const restrict decbuf,
        /*@reldef@*/ struct LibTTAr_CodecState_Priv *const restrict priv,
        /*@out@*/ struct LibTTAr_CodecState_User *const restrict user_out,
        const enum TTASampleBytes samplebytes, const uint nchan,
        size_t ni32_perframe, const size_t nbytes_tta_perframe,
        /*@out@*/ size_t *const restrict nsamples_flat_2pad
    )
    /*@modifies     *decbuf->i32buf,
                    *decbuf->pcmbuf,
                    *priv,
                    *user_out,
                    *nsamples_flat_2pad
    @*/
    {
        int r;
        struct LibTTAr_CodecState_User user = LIBTTAr_CODECSTATE_USER_INIT;
        size_t pad_target = 0;
        union { size_t z; } t;
    #ifdef NDEBUG
        (void) t.z;     // gcc
    #endif
        assert(decbuf->i32buf != NULL);
        goto loop_entr;
        do {
               // frame has a truncated last sample; needs zero-padding later
               pad_target     = (size_t) (nchan - (ni32_perframe % nchan));
               ni32_perframe += pad_target;
    loop_entr:
               // decode tta to i32
               r = libttaR_tta_decode(
                       decbuf->i32buf, decbuf->ttabuf, decbuf->i32buf_len,
                       decbuf->ttabuf_len, ni32_perframe,
                       nbytes_tta_perframe, priv, &user, samplebytes, nchan,
                       ni32_perframe, nbytes_tta_perframe
               );
               // with the way the decoding is setup, RET_AGAIN shouldn't
               //   happen
               // >=RET_INVAL may happen if the last sample is truncated
               assert((r == LIBTTAr_RET_DONE)
                     ||
                      (r == LIBTTAr_RET_DECFAIL)
                     ||
                      (r >= LIBTTAr_RET_INVAL)
               );
        }
        while UNLIKELY ( r >= LIBTTAr_RET_INVAL );
        if UNLIKELY ( r == LIBTTAr_RET_DECFAIL ){
               pad_target     += ni32_perframe - user.ni32_total;
               user.ni32_total = ni32_perframe;
        }
        // convert i32 to pcm
        t.z = libttaR_pcm_write(
               decbuf->pcmbuf, decbuf->i32buf, user.ni32_total, samplebytes
        );
        assert(t.z == user.ni32);
        *user_out           = user;
        *nsamples_flat_2pad = pad_target;
        return r;
    }

SEE ALSO
libttaR_pcm_read(3), libttaR_pcm_write(3), libttaR_crc32(3), libttaR_misc(3)

AUTHOR
Shane Seelig
    Developer