Software Development Kit

Audio

By convention and without declaration, the audio format is G.711 a-law.

This is the structure that holds the APP13 audio data:

#define M_APP13 0xed

#define M_MXAUDIO M_APP13  /* mobotix audio record */

typedef struct{
/*  0 */  u8  ff_0;             /* Marker-leadin, 0xff */
/*  1 */  u8  au_marker;        /* app13-Marker M_MXAUDIO */
/*  2 */  u8  len_hi, len_lo;   /* Length of APP13 block (2 bytes) */  
/*  4 */  u32 dur_us;           /* duration of block in us, little-endian */
/*  8 */  u64 start_us;         /* time (GMT) of first sample 
				 * in us since 1970, little-endian */
/* 16 */  u8  au_samples[0];    /* array of up to 64k - sizeof(jh_mxm_audio_hdr_t) */
                                /* the number of samples is computed as 
				 * ((len_hi << 8) + len_lo) - (sizeof(jh_mxm_audio_hdr_t) - 2) 
				 * (because the marker is not included in the length, we 
				 * need to subtract 2 */

} jh_mxm_audio_hdr_t;

start_us is a sample of the system clock that may show drifts or other errors. Therefore 8000 samples may not exactly amount to 1 second. The audio rendering software should correct these slight drifts.

According to the standard, all samples are XORed by 0x55. To convert them into 12-bit signed values, you may use the following routine:

/************************************************************/
/* a-law code/decode                                        */
/************************************************************/

static int a3_to_s12_tab[256] = {
  -672,  -640,  -736,  -704,  -544,  -512,  -608,  -576,
  -928,  -896,  -992,  -960,  -800,  -768,  -864,  -832,
  -336,  -320,  -368,  -352,  -272,  -256,  -304,  -288,
  -464,  -448,  -496,  -480,  -400,  -384,  -432,  -416,
 -2688, -2560, -2944, -2816, -2176, -2048, -2432, -2304,
 -3712, -3584, -3968, -3840, -3200, -3072, -3456, -3328,
 -1344, -1280, -1472, -1408, -1088, -1024, -1216, -1152,
 -1856, -1792, -1984, -1920, -1600, -1536, -1728, -1664,
   -42,   -40,   -46,   -44,   -34,   -32,   -38,   -36,
   -58,   -56,   -62,   -60,   -50,   -48,   -54,   -52,
   -10,    -8,   -14,   -12,    -2,     0,    -6,    -4,
   -26,   -24,   -30,   -28,   -18,   -16,   -22,   -20,
  -168,  -160,  -184,  -176,  -136,  -128,  -152,  -144,
  -232,  -224,  -248,  -240,  -200,  -192,  -216,  -208,
   -84,   -80,   -92,   -88,   -68,   -64,   -76,   -72,
  -116,  -112,  -124,  -120,  -100,   -96,  -108,  -104,
   672,   640,   736,   704,   544,   512,   608,   576, 
   928,   896,   992,   960,   800,   768,   864,   832,
   336,   320,   368,   352,   272,   256,   304,   288,
   464,   448,   496,   480,   400,   384,   432,   416,
  2688,  2560,  2944,  2816,  2176,  2048,  2432,  2304,
  3712,  3584,  3968,  3840,  3200,  3072,  3456,  3328,
  1344,  1280,  1472,  1408,  1088,  1024,  1216,  1152,
  1856,  1792,  1984,  1920,  1600,  1536,  1728,  1664,
    42,    40,    46,    44,    34,    32,    38,    36,
    58,    56,    62,    60,    50,    48,    54,    52,
    10,     8,    14,    12,     2,     0,     6,     4,
    26,    24,    30,    28,    18,    16,    22,    20,
   168,   160,   184,   176,   136,   128,   152,   144,
   232,   224,   248,   240,   200,   192,   216,   208,
    84,    80,    92,    88,    68,    64,    76,    72,
   116,   112,   124,   120,   100,    96,   108,   104 
};

#define a3_to_s12(x) (a3_to_s12_tab[x])

static inline int s12_to_a3(int x) {
/* 12 bit + sign amplitude -> a-law code
   positive cases:
   0000 0000 00ab cde* -> 100a bcde  ; first 32 codes are linear !
   0000 0000 01ab cd** -> 1010 abcd
   0000 0000 1abc d*** -> 1011 abdc
   0000 0001 abcd **** -> 1100 abdc
   0000 001a bcd* **** -> 1101 abdc
   0000 01ab cd** **** -> 1110 abdc
   0000 1abc d*** **** -> 1111 abdc
   negative cases:
   0001 0000 0000 **** _> 0111 1111  ; "-4096 -> +4095"
   otherwise MSB = 0; |x| is treated as positive
*/

    int sign7;
        
    sign7 = ((~x) >> 5) & 0x80;
    /* force code 0x1000 (and some smaller ones) to 0x0FF0, as the a-law-code 
is symmetrical (has "-0") */
    if (!sign7) x =  (((u32)((x + 0x0FF0))) >> 20)  -x; 

    if (x < 64) return (0x55 ^ (sign7 ^ (x >> 1)));
    if (x & 0xC00) {sign7 += (2 << 4); x >>= 2;} 
    if (x & 0x300) {sign7 += (2 << 4); x >>= 2;} 
    if (x & 0x080) {sign7 += (1 << 4); x >>= 1;}
    return (0x55 ^ (sign7 + 32 +  ((x & 0x03C) >> 2)));
}

In order to avoid distortions, the PCM data have to further pass through a sin(x)/x filter (contained in telco codecs).

Copyright (c) 2005-2007, MOBOTIX AG. All rights reserved.