shithub: sox

ref: dd448e56da071aebba7572eb6ea81788038133e8
dir: /src/st.h/

View raw version
/*
 * Sound Tools Library
 *
 * Copyright 1999-2007 Chris Bagwell and SoX Contributors.
 *
 * This source code is freely redistributable and may be used for
 * any purpose.  This copyright notice must be maintained.
 * Chris Bagwell And SoX Contributors are not responsible for
 * the consequences of using this software.
 */

#ifndef ST_H
#define ST_H

#include <stdio.h>
#include <stdlib.h>
#include "ststdint.h"

/* The following is the API version of libst.  It is not meant
 * to follow the version number of SoX but it has historically.
 * Please do not count of these numbers being in sync.
 * The following is at 13.0.0
 */
#define ST_LIB_VERSION_CODE 0x0d0000
#define ST_LIB_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))

/* Avoid warnings about unused parameters. */
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#endif

/* C language enhancements: */

/* Boolean type, compatible with C++ */
typedef enum {st_false, st_true} st_bool;

typedef int32_t int24_t;     /* But beware of the extra byte. */
typedef uint32_t uint24_t;   /* ditto */

#define ST_INT_MIN(bits) (1 <<((bits)-1))
#define ST_INT_MAX(bits) (-1U>>(33-(bits)))
#define ST_UINT_MAX(bits) (ST_INT_MIN(bits)|ST_INT_MAX(bits))

#define ST_INT8_MAX  ST_INT_MAX(8)
#define ST_INT16_MAX ST_INT_MAX(16)
#define ST_INT24_MAX ST_INT_MAX(24)
#define ST_INT32_MAX ST_INT_MAX(32)
#define ST_INT64_MAX 0x7fffffffffffffffLL /* Not in use yet */

typedef int32_t st_sample_t;
typedef uint32_t st_usample_t; /* FIXME: this naming is different from
                                  other types */
/* Minimum and maximum values a sample can hold. */
#define ST_SAMPLE_MAX (st_sample_t)ST_INT_MAX(32)
#define ST_SAMPLE_MIN (st_sample_t)ST_INT_MIN(32)



/*                Conversions: Linear PCM <--> st_sample_t
 *
 *   I/O       I/O     st_sample_t  Clips?    I/O     st_sample_t  Clips? 
 *  Format   Minimum     Minimum     I O    Maximum     Maximum     I O      
 *  ------  ---------  ------------ -- --   --------  ------------ -- --  
 *  Float      -1     -1.00000000047 y y       1           1        y n         
 *  Byte      -128        -128       n n      127     127.9999999   n y   
 *  Word     -32768      -32768      n n     32767    32767.99998   n y   
 *  24bit   -8388608    -8388608     n n    8388607   8388607.996   n y   
 *  Dword  -2147483648 -2147483648   n n   2147483647 2147483647    n n   
 *
 * Conversions are as accurate as possible (with rounding).
 *
 * Rounding: halves toward +inf, all others to nearest integer.
 *
 * Clips? shows whether on not there is the possibility of a conversion
 * clipping to the minimum or maximum value when inputing from or outputing 
 * to a given type.
 *
 * Unsigned integers are converted to and from signed integers by flipping
 * the upper-most bit then treating them as signed integers.
 */

/* Temporary variables to prevent multiple evaluation of macro arguments: */
static st_sample_t st_macro_temp_sample UNUSED;
static double st_macro_temp_double UNUSED;

#define ST_SAMPLE_NEG ST_INT_MIN(32)
#define ST_SAMPLE_TO_UNSIGNED(bits,d,clips) \
  (uint##bits##_t)( \
    st_macro_temp_sample=d, \
    st_macro_temp_sample>(st_sample_t)(ST_SAMPLE_MAX-(1U<<(31-bits)))? \
      ++(clips),ST_UINT_MAX(bits): \
      ((uint32_t)(st_macro_temp_sample^ST_SAMPLE_NEG)+(1U<<(31-bits)))>>(32-bits))
#define ST_SAMPLE_TO_SIGNED(bits,d,clips) \
  (int##bits##_t)(ST_SAMPLE_TO_UNSIGNED(bits,d,clips)^ST_INT_MIN(bits))
#define ST_SIGNED_TO_SAMPLE(bits,d)((st_sample_t)(d)<<(32-bits))
#define ST_UNSIGNED_TO_SAMPLE(bits,d)(ST_SIGNED_TO_SAMPLE(bits,d)^ST_SAMPLE_NEG)

#define ST_UNSIGNED_BYTE_TO_SAMPLE(d,clips) ST_UNSIGNED_TO_SAMPLE(8,d)
#define ST_SIGNED_BYTE_TO_SAMPLE(d,clips) ST_SIGNED_TO_SAMPLE(8,d)
#define ST_UNSIGNED_WORD_TO_SAMPLE(d,clips) ST_UNSIGNED_TO_SAMPLE(16,d)
#define ST_SIGNED_WORD_TO_SAMPLE(d,clips) ST_SIGNED_TO_SAMPLE(16,d)
#define ST_UNSIGNED_24BIT_TO_SAMPLE(d,clips) ST_UNSIGNED_TO_SAMPLE(24,d)
#define ST_SIGNED_24BIT_TO_SAMPLE(d,clips) ST_SIGNED_TO_SAMPLE(24,d)
#define ST_UNSIGNED_DWORD_TO_SAMPLE(d,clips) (st_sample_t)((d)^ST_SAMPLE_NEG)
#define ST_SIGNED_DWORD_TO_SAMPLE(d,clips) (st_sample_t)(d)
#define ST_FLOAT_DWORD_TO_SAMPLE ST_FLOAT_DDWORD_TO_SAMPLE
#define ST_FLOAT_DDWORD_TO_SAMPLE(d,clips) (st_macro_temp_double=d,st_macro_temp_double<-1?++(clips),(-ST_SAMPLE_MAX):st_macro_temp_double>1?++(clips),ST_SAMPLE_MAX:(st_sample_t)((uint32_t)((double)(st_macro_temp_double)*ST_SAMPLE_MAX+(ST_SAMPLE_MAX+.5))-ST_SAMPLE_MAX))
#define ST_SAMPLE_TO_UNSIGNED_BYTE(d,clips) ST_SAMPLE_TO_UNSIGNED(8,d,clips)
#define ST_SAMPLE_TO_SIGNED_BYTE(d,clips) ST_SAMPLE_TO_SIGNED(8,d,clips)
#define ST_SAMPLE_TO_UNSIGNED_WORD(d,clips) ST_SAMPLE_TO_UNSIGNED(16,d,clips)
#define ST_SAMPLE_TO_SIGNED_WORD(d,clips) ST_SAMPLE_TO_SIGNED(16,d,clips)
#define ST_SAMPLE_TO_UNSIGNED_24BIT(d,clips) ST_SAMPLE_TO_UNSIGNED(24,d,clips)
#define ST_SAMPLE_TO_SIGNED_24BIT(d,clips) ST_SAMPLE_TO_SIGNED(24,d,clips)
#define ST_SAMPLE_TO_UNSIGNED_DWORD(d,clips) (uint32_t)((d)^ST_SAMPLE_NEG)
#define ST_SAMPLE_TO_SIGNED_DWORD(d,clips) (int32_t)(d)
#define ST_SAMPLE_TO_FLOAT_DWORD ST_SAMPLE_TO_FLOAT_DDWORD
#define ST_SAMPLE_TO_FLOAT_DDWORD(d,clips) (st_macro_temp_sample=d,st_macro_temp_sample==ST_SAMPLE_MIN?++(clips),-1.0:((double)(st_macro_temp_sample)*(1.0/ST_SAMPLE_MAX)))



/* MACRO to clip a data type that is greater then st_sample_t to
 * st_sample_t's limits and increment a counter if clipping occurs..
 */
#define ST_SAMPLE_CLIP_COUNT(samp, clips) \
  do { \
    if (samp > ST_SAMPLE_MAX) \
      { samp = ST_SAMPLE_MAX; clips++; } \
    else if (samp < ST_SAMPLE_MIN) \
      { samp = ST_SAMPLE_MIN; clips++; } \
  } while (0)

/* Rvalue MACRO to round and clip a double to a st_sample_t,
 * and increment a counter if clipping occurs.
 */
#define ST_ROUND_CLIP_COUNT(d, clips) \
  ((d) < 0? (d) <= ST_SAMPLE_MIN - 0.5? ++(clips), ST_SAMPLE_MIN: (d) - 0.5 \
        : (d) >= ST_SAMPLE_MAX + 0.5? ++(clips), ST_SAMPLE_MAX: (d) + 0.5)

/* Rvalue MACRO to clip a st_sample_t to 24 bits,
 * and increment a counter if clipping occurs.
 */
#define ST_24BIT_CLIP_COUNT(l, clips) \
  ((l) >= ((st_sample_t)1 << 23)? ++(clips), ((st_sample_t)1 << 23) - 1 : \
   (l) <=-((st_sample_t)1 << 23)? ++(clips),-((st_sample_t)1 << 23) + 1 : (l))



typedef uint32_t st_size_t;
/* Maximum value size type can hold. (Minimum is 0). */
#define ST_SIZE_MAX 0xffffffff

typedef int32_t st_ssize_t;
/* Minimum and maximum value signed size type can hold. */
#define ST_SSIZE_MAX 0x7fffffff
#define ST_SSIZE_MIN (-ST_SSIZE_MAX - 1)

typedef unsigned st_rate_t;
/* Warning, this is a MAX value used in the library.  Each format and
 * effect may have its own limitations of rate.
 */
#define ST_MAXRATE      (50U * 1024) /* maximum sample rate in library */

typedef enum {
  ST_ENCODING_UNKNOWN   ,

  ST_ENCODING_ULAW      , /* u-law signed logs: US telephony, SPARC */
  ST_ENCODING_ALAW      , /* A-law signed logs: non-US telephony */
  ST_ENCODING_ADPCM     , /* G72x Compressed PCM */
  ST_ENCODING_MS_ADPCM  , /* Microsoft Compressed PCM */
  ST_ENCODING_IMA_ADPCM , /* IMA Compressed PCM */
  ST_ENCODING_OKI_ADPCM , /* Dialogic/OKI Compressed PCM */

  ST_ENCODING_SIZE_IS_WORD, /* FIXME: marks raw types (above) that mis-report size. st_signalinfo_t really needs a precision_in_bits item */

  ST_ENCODING_UNSIGNED  , /* unsigned linear: Sound Blaster */
  ST_ENCODING_SIGN2     , /* signed linear 2's comp: Mac */
  ST_ENCODING_FLOAT     , /* 32-bit float */
  ST_ENCODING_GSM       , /* GSM 6.10 33byte frame lossy compression */
  ST_ENCODING_MP3       , /* MP3 compression */
  ST_ENCODING_VORBIS    , /* Vorbis compression */
  ST_ENCODING_FLAC      , /* FLAC compression */

  ST_ENCODINGS            /* End of list marker */
} st_encoding_t;

/* Global parameters */

typedef struct  st_globalinfo
{
    st_bool octave_plot_effect;/* To help user choose effect & options */
    double speed;         /* Gather up all speed changes here, then resample */
} st_globalinfo_t;

typedef enum {ST_OPTION_NO, ST_OPTION_YES, ST_OPTION_DEFAULT} st_option_t;

/* Signal parameters */

typedef struct st_signalinfo
{
    st_rate_t rate;       /* sampling rate */
    int size;             /* compressed or uncompressed datum size */
    st_encoding_t encoding; /* format of sample numbers */
    unsigned channels;    /* number of sound channels */
    double compression;   /* compression factor (where applicable) */

    /* There is a delineation between these vars being tri-state and
     * effectively boolean.  Logically the line falls between setting
     * them up (could be done in stlib, or by the stlib client) and
     * using them (in stlib).  Stlib's logic to set them up includes
     * knowledge of the machine default and the format default.  (The
     * sox client logic adds to this a layer of overridability via user
     * options.)  The physical delineation is in the somewhat
     * snappily-named stlib function `set_endianness_if_not_already_set'
     * which is called at the right times (as files are openned) by the
     * stlib core, not by the file drivers themselves.  The file drivers
     * indicate to the stlib core if they have a preference using
     * ST_FILE_xxx flags.
     */
    st_option_t reverse_bytes;    /* endiannesses... */
    st_option_t reverse_nibbles;
    st_option_t reverse_bits;
} st_signalinfo_t;

/* Loop parameters */

typedef struct  st_loopinfo
{
    st_size_t    start;          /* first sample */
    st_size_t    length;         /* length */
    unsigned int count;          /* number of repeats, 0=forever */
    signed char  type;           /* 0=no, 1=forward, 2=forward/back */
} st_loopinfo_t;

/* Instrument parameters */

/* vague attempt at generic information for sampler-specific info */

typedef struct  st_instrinfo
{
    char MIDInote;       /* for unity pitch playback */
    char MIDIlow, MIDIhi;/* MIDI pitch-bend range */
    char loopmode;       /* semantics of loop data */
    signed char nloops;  /* number of active loops (max ST_MAX_NLOOPS) */
} st_instrinfo_t;

/* Loop modes, upper 4 bits mask the loop blass, lower 4 bits describe */
/* the loop behaviour, ie. single shot, bidirectional etc. */
#define ST_LOOP_NONE          0
#define ST_LOOP_8             32 /* 8 loops: don't know ?? */
#define ST_LOOP_SUSTAIN_DECAY 64 /* AIFF style: one sustain & one decay loop */

/*
 * File buffer info.  Holds info so that data can be read in blocks.
 */

typedef struct st_fileinfo
{
    char          *buf;                 /* Pointer to data buffer */
    size_t        size;                 /* Size of buffer */
    size_t        count;                /* Count read in to buffer */
    size_t        pos;                  /* Position in buffer */
    unsigned char eof;                  /* Marker that EOF has been reached */
} st_fileinfo_t;


/*
 *  Format information for input and output files.
 */

#define ST_MAX_FILE_PRIVSIZE    1000
#define ST_MAX_EFFECT_PRIVSIZE 1000

#define ST_MAX_NLOOPS           8

/*
 * Handler structure for each format.
 */

typedef struct st_soundstream *ft_t;

typedef struct st_format {
    const char   * const *names;
    const char   *usage;
    unsigned int flags;
    int          (*startread)(ft_t ft);
    st_size_t    (*read)(ft_t ft, st_sample_t *buf, st_size_t len);
    int          (*stopread)(ft_t ft);
    int          (*startwrite)(ft_t ft);
    st_size_t    (*write)(ft_t ft, const st_sample_t *buf, st_size_t len);
    int          (*stopwrite)(ft_t ft);
    int          (*seek)(ft_t ft, st_size_t offset);
} st_format_t;

struct st_soundstream {
    st_signalinfo_t signal;               /* signal specifications */
    st_instrinfo_t  instr;                /* instrument specification */
    st_loopinfo_t   loops[ST_MAX_NLOOPS]; /* Looping specification */
    st_bool         seekable;             /* can seek on this file */
    char            mode;                 /* read or write mode */
    st_size_t       length;               /* frames in file, or 0 if unknown. */
    st_size_t       clips;                /* increment if clipping occurs */
    char            *filename;            /* file name */
    char            *filetype;            /* type of file */
    char            *comment;             /* comment string */
    FILE            *fp;                  /* File stream pointer */
    unsigned char   eof;                  /* Marker that EOF has been reached */
    int             st_errno;             /* Failure error codes */
    char            st_errstr[256];       /* Extend Failure text */
    const st_format_t *h;                 /* format struct for this file */
    /* The following is a portable trick to align this variable on
     * an 8-byte boundery.  Once this is done, the buffer alloced
     * after it should be align on an 8-byte boundery as well.
     * This lets you cast any structure over the private area
     * without concerns of alignment.
     */
    double priv1;
    char   priv[ST_MAX_FILE_PRIVSIZE]; /* format's private data area */
};

/* file flags field */
#define ST_FILE_LOOPS   1  /* does file format support loops? */
#define ST_FILE_INSTR   2  /* does file format support instrument specs? */
#define ST_FILE_SEEK    4  /* does file format support seeking? */
#define ST_FILE_NOSTDIO 8  /* does not use stdio routines */
#define ST_FILE_DEVICE  16 /* file is an audio device */
#define ST_FILE_PHONY   32 /* phony file/device */
/* These two for use by the stlib core or stlib clients: */
#define ST_FILE_ENDIAN  64 /* is file format endian? */
#define ST_FILE_ENDBIG  128/* if so, is it big endian? */
/* These two for use by stlib drivers: */
#define ST_FILE_LIT_END  (0   + 64)
#define ST_FILE_BIG_END  (128 + 64)

/* Size field */
#define ST_SIZE_BYTE    1
#define ST_SIZE_8BIT    1
#define ST_SIZE_16BIT   2
#define ST_SIZE_24BIT   3
#define ST_SIZE_32BIT   4
#define ST_SIZE_64BIT   8
#define ST_INFO_SIZE_MAX     8

/* declared in misc.c */
extern const char * const st_sizes_str[];
extern const char * const st_size_bits_str[];
extern const char * const st_encodings_str[];

#define ST_EFF_CHAN     1           /* Effect can mix channels up/down */
#define ST_EFF_RATE     2           /* Effect can alter data rate */
#define ST_EFF_MCHAN    4           /* Effect can handle multi-channel */
#define ST_EFF_REPORT   8           /* Effect does not affect the audio */
#define ST_EFF_DEPRECATED 16        /* Effect is living on borrowed time */
#define ST_EFF_NULL     32          /* Effect does nothing */

/*
 * Handler structure for each effect.
 */

typedef struct st_effect *eff_t;

typedef struct
{
    char const *name;               /* effect name */
    char const *usage;
    unsigned int flags;

    int (*getopts)(eff_t effp, int argc, char *argv[]);
    int (*start)(eff_t effp);
    int (*flow)(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf,
                st_size_t *isamp, st_size_t *osamp);
    int (*drain)(eff_t effp, st_sample_t *obuf, st_size_t *osamp);
    int (*stop)(eff_t effp);
    int (*kill)(eff_t effp);
} st_effect_t;

struct st_effect
{
    char const *name;               /* effect name */
    struct st_globalinfo * globalinfo;/* global ST parameters */
    struct st_signalinfo ininfo;    /* input signal specifications */
    struct st_signalinfo outinfo;   /* output signal specifications */
    const st_effect_t *h;           /* effects driver */
    st_sample_t     *obuf;          /* output buffer */
    st_size_t       odone, olen;    /* consumed, total length */
    st_size_t       clips;   /* increment if clipping occurs */
    /* The following is a portable trick to align this variable on
     * an 8-byte boundary.  Once this is done, the buffer alloced
     * after it should be align on an 8-byte boundery as well.
     * This lets you cast any structure over the private area
     * without concerns of alignment.
     */
    double priv1;
    char priv[ST_MAX_EFFECT_PRIVSIZE]; /* private area for effect */
};

void set_endianness_if_not_already_set(ft_t ft);
extern ft_t st_open_read(const char *path, const st_signalinfo_t *info, 
                         const char *filetype);
ft_t st_open_write(
    st_bool (*overwrite_permitted)(const char *filename),
    const char *path,
    const st_signalinfo_t *info,
    const char *filetype,
    const char *comment,
    const st_instrinfo_t *instr,
    const st_loopinfo_t *loops);
extern st_size_t st_read(ft_t ft, st_sample_t *buf, st_size_t len);
extern st_size_t st_write(ft_t ft, const st_sample_t *buf, st_size_t len);
extern int st_close(ft_t ft);

#define ST_SEEK_SET 0
extern int st_seek(ft_t ft, st_size_t offset, int whence);

int st_geteffect_opt(eff_t, int, char **);
int st_geteffect(eff_t, const char *);
st_bool is_effect_name(char const * text);
int st_updateeffect(eff_t, const st_signalinfo_t *in, const st_signalinfo_t *out, int);
int st_gettype(ft_t, st_bool);
ft_t st_initformat(void);
char const * st_parsesamples(st_rate_t rate, const char *str, st_size_t *samples, char def);

/* The following routines are unique to the trim effect.
 * st_trim_get_start can be used to find what is the start
 * of the trim operation as specified by the user.
 * st_trim_clear_start will reset what ever the user specified
 * back to 0.
 * These two can be used together to find out what the user
 * wants to trim and use a st_seek() operation instead.  After
 * st_seek()'ing, you should set the trim option to 0.
 */
st_size_t st_trim_get_start(eff_t effp);
void st_trim_clear_start(eff_t effp);

extern char const * st_message_filename;

#define ST_EOF (-1)
#define ST_SUCCESS (0)

const char *st_version(void);                   /* return version number */

/* ST specific error codes.  The rest directly map from errno. */
#define ST_EHDR 2000            /* Invalid Audio Header */
#define ST_EFMT 2001            /* Unsupported data format */
#define ST_ERATE 2002           /* Unsupported rate for format */
#define ST_ENOMEM 2003          /* Can't alloc memory */
#define ST_EPERM 2004           /* Operation not permitted */
#define ST_ENOTSUP 2005         /* Operation not supported */
#define ST_EINVAL 2006          /* Invalid argument */
#define ST_EFFMT 2007           /* Unsupported file format */

#endif