Plan 9 from Bell Labs’s /usr/web/sources/plan9/sys/src/games/mp3enc/pcm.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* -*- mode: C; mode: fold -*- */

/* $Id: pcm.c,v 1.7 2001/02/17 14:30:56 aleidinger Exp $ */

/*
 *  There are a lot of not tested return codes.
 *  This is currently intention to make the code more readable
 *  in the design phase.
 *  Keine Ber�ichtigung des Ein- und Ausschwingens des Downsamplefilters am
 *  Anfang und am Ende wie bei meinem Resample-Programm
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "bitstream.h"
#include "id3tag.h"

#define FN(x)	do { static unsigned int cnt = 0; if (cnt < 100000) fprintf (stderr,"[%3u]>>>%s<<<\n",++cnt,(x)), fflush(stderr); } while (0)

#ifdef KLEMM_44

/*{{{ #includes                       */

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <memory.h>
#include <unistd.h>
#include "pcm.h"

/*}}}*/
/*{{{ bitstream object                */

/*
 *  About handling of octetstreams:
 *
 *  CHAR_BIT = 8: data points to a normal memory block which can be written to
 *                disk via fwrite
 *  CHAR_BIT > 8: On every char only the bits from 0...7 are used. Depending on the
 *                host I/O it can be possible that you must first pack the data
 *                stream before writing to disk/network/...
 *  CHAR_BIT < 8: Not allowed by C
 */

octetstream_t*  octetstream_open ( OUT size_t  size )
{
    octetstream_t*  ret = (octetstream_t*) calloc ( 1, sizeof(octetstream_t) );
    FN("octetstream_open");
    ret -> data = (uint8_t*) calloc ( 1, size );
    ret -> size = size;
    return ret;
}

int  octetstream_resize ( INOUT octetstream_t* const  os, OUT size_t  size )
{
    FN("octetstream_resize");
    if ( size > os->size ) {
        os -> data = (uint8_t*) realloc ( os -> data, size );
        memset ( os -> data + os -> size, 0, size - os -> size );
        os -> size = size;
    } else if ( size < os->size ) {
	os -> data = (uint8_t*) realloc ( os -> data, os->size = size );
    }
    return 0;
}

int  octetstream_close ( INOUT octetstream_t* const  os )
{
    FN("octetstream_close");
    if ( os == NULL )
        return -1;
    if ( os -> data != NULL ) {
        free (os -> data);
        os -> data = NULL;
        free (os);
        return 0;
    } else {
        free (os);
        return -1;
    }
}

/*}}}*/
/*{{{ encode one frame                */

static inline int  lame_encode_frame (
        INOUT lame_t*     lame,
        OUTTR sample_t**  inbuf,
        IN    uint8_t*    mp3buf,
        OUT   size_t      mp3buf_size )
{
    int  ret;
#if 1
    int           i;
    static int    j  = 0;
    static FILE*  fp = NULL;
    if ( fp == NULL )
        fp = fopen ("pcm_data.txt", "w");
    for ( i = 0; i < lame->frame_size; i++ )
        fprintf ( fp, "%7d %11.4f %11.4f\n", j++, inbuf[0][i], inbuf[1][i] );
    fprintf ( fp, "\n" );
    fflush ( fp );
#endif
    
    FN("lame_encode_frame");

    switch ( lame -> coding ) {
#ifdef HAVE_MPEG_LAYER1
    case coding_MPEG_Layer_1:
        ret = lame_encode_mp1_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#endif
#ifdef HAVE_MPEG_LAYER2
    case coding_MPEG_Layer_2:
        ret = lame_encode_mp2_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#endif
    case coding_MPEG_Layer_3:
        ret = lame_encode_mp3_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#ifdef HAVE_MPEG_PLUS
    case coding_MPEG_plus:
        ret = lame_encode_mpp_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#endif
#ifdef HAVE_AAC
    case coding_MPEG_AAC:
        ret = lame_encode_aac_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#endif
#ifdef HAVE_VORBIS
    case coding_Ogg_Vorbis:
        ret = lame_encode_ogg_frame ( lame->global_flags, inbuf[0], inbuf[1], mp3buf, mp3buf_size );
        break;
#endif
    default:
        ret = -5;
        break;
    }
    
    if ( ret >= 0 ) {
        lame->frame_count++;
        if ( lame->analyzer_callback != NULL )
            lame->analyzer_callback ( lame, lame->frame_size );
    }
    return ret;
}

/*}}}*/
/*{{{ demultiplexing tools            */

/*
 * Now there are following the so called peek functions. They got a pointer and returning
 * the data to this pointer as a sample. The size of the memory object can be from
 * 8 up to 80 bits. One sample must be fully determined by it's bits, not by the history
 * or by other channels or things like that. Also the input must have a integral byte size.
 *
 * That means:
 *
 *   - 4 or 6 bit PCM can't be decoded
 *   - APCM can't be decoded
 *   - ulaw/alaw *can* be decoded
 *
 * Note: In the future there will be a SMART define supported which only
 *       support native endian shorts.
 */

static const int16_t  ulaw [256] = {
    -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
    -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
    -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
    -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
      -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
      -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
      -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
      -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
      -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
       -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
      7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
      5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
      3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
      2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
      1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
      1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
       876,    844,    812,    780,    748,    716,    684,    652,
       620,    588,    556,    524,    492,    460,    428,    396,
       372,    356,    340,    324,    308,    292,    276,    260,
       244,    228,    212,    196,    180,    164,    148,    132,
       120,    112,    104,     96,     88,     80,     72,     64,
        56,     48,     40,     32,     24,     16,      8,      0,
};

static const int16_t  alaw [256] = {
     -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
     -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
     -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
     -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
    -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
    -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
    -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
    -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
      -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
      -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
       -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
      -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
     -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
      5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
      7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
      2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
      3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
     22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
     30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
     11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
     15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
       344,    328,    376,    360,    280,    264,    312,    296,
       472,    456,    504,    488,    408,    392,    440,    424,
        88,     72,    120,    104,     24,      8,     56,     40,
       216,    200,    248,    232,    152,    136,    184,    168,
      1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
      1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
       688,    656,    752,    720,    560,    528,    624,    592,
       944,    912,   1008,    976,    816,    784,    880,    848,
};

/*
 *  These macros get 1...4 bytes and calculating a value between -32768 and +32768.
 *  The first argument of the macros is the MSB, the last the LSB.
 *  These are used to decode integer PCM (if there is no faster code available).
 */

#define BYTES1(x1)          ((((int8_t)(x1)) << 8))
#define BYTES2(x1,x2)       ((((int8_t)(x1)) << 8) + (uint8_t)(x2))
#define BYTES3(x1,x2,x3)    ((((int8_t)(x1)) << 8) + (uint8_t)(x2) + 1/256.*(uint8_t)(x3))
#define BYTES4(x1,x2,x3,x4) ((((int8_t)(x1)) << 8) + (uint8_t)(x2) + 1/256.*(uint8_t)(x3) + 1/65536.*(uint8_t)(x4))

/*
 * The next two functions can read a 32 and 64 bit floating pointer number
 * of an opposite byte order machine. This is done by byte swaping and using
 * the normal way to read such a variable.
 * Also note: peek function got their data from a variable called src, which is a pointer
 * to const unsigned char.
 */

static inline sample_t  read_opposite_float32 ( OUT uint8_t* const src )
{
    uint8_t  tmp [4];
    tmp[0] = src[3];
    tmp[1] = src[2];
    tmp[2] = src[1];
    tmp[3] = src[0];
    return *(const float32_t*)tmp;
}

static inline sample_t  read_opposite_float64 ( OUT uint8_t* const src )
{
    uint8_t  tmp [8];
    tmp[0] = src[7];
    tmp[1] = src[6];
    tmp[2] = src[5];
    tmp[3] = src[4];
    tmp[4] = src[3];
    tmp[5] = src[2];
    tmp[6] = src[1];
    tmp[7] = src[0];
    return *(const float64_t*)tmp;
}

/*
 *  The next two functions can read a 80 bit extended precision
 *  IEEE-854 floating point number. This code also can read the numbers
 *  on a machine not supporting 80 bit floats.
 */

static sample_t  read_float80_le ( OUT uint8_t* const src )
{
    int         sign     = src [9] & 128  ?  -1  :  +1;
    long        exponent =(src [9] & 127) * 256 +
                           src [8] - 16384 - 62;
    long double mantisse = src [7] * 72057594037927936.L +
                           src [6] * 281474976710656.L +
                           src [5] * 1099511627776.L +
                           src [4] * 4294967296.L +
                           src [3] * 16777216.L +
                           src [2] * 65536.L +
                           src [1] * 256.L +
                           src [0];
    return sign * ldexp (mantisse, exponent);
}

static sample_t  read_float80_be ( OUT uint8_t* const src )
{
    int         sign     = src [0] & 128  ?  -1  :  +1;
    long        exponent =(src [0] & 127) * 256 +
                           src [1] - 16384 - 62;
    long double mantisse = src [2] * 72057594037927936.L +
                           src [3] * 281474976710656.L +
                           src [4] * 1099511627776.L +
                           src [5] * 4294967296.L +
                           src [6] * 16777216.L +
                           src [7] * 65536.L +
                           src [8] * 256.L +
                           src [9];
    return sign * ldexp (mantisse, exponent);
}

static inline sample_t  read_opposite_float80 ( OUT uint8_t* const src )
{
    uint8_t  tmp [10];
    tmp[0] = src[9];
    tmp[1] = src[8];
    tmp[2] = src[7];
    tmp[3] = src[6];
    tmp[4] = src[5];
    tmp[5] = src[4];
    tmp[6] = src[3];
    tmp[7] = src[2];
    tmp[8] = src[1];
    tmp[9] = src[0];
    return *(const float80_t*)tmp;
}


/*
 *  Now we are building all resorting functions. The macro wants the name of the function
 *  and a peek function or macro. The created function wants the following input:
 *
 *     destination: Where to store the result as sample_t vector? The distance between
 *                  the elements is sizeof(sample_t)
 *     source:      Where to get the bytes which should converted to destination
 *     step size:   The distance between the input samples. This is at least the size
 *                  of one input element, but can be more due to
 *                    - alignment
 *                    - interleaved multi-channel input
 *     length:      The number of elements to process. Number must be positive.
 */

typedef void (*demux_t) ( IN sample_t* dst, OUT uint8_t* src, OUT ssize_t step, OUT size_t len );

#define FUNCTION(name,expr)       \
static void  name (               \
        IN  sample_t*  dst,       \
	OUT uint8_t*   src,       \
	OUT ssize_t    step,      \
	OUT size_t     len )      \
{                                 \
    size_t  i = len;              \
    do {                          \
        *dst++ = (expr);          \
        src   += (step);          \
    } while (--i);                \
}

/* Some of these function can be implemented byte order independent ... */

FUNCTION ( copy_silence, 0 )
FUNCTION ( copy_u8     , BYTES1 (src[0]-128) )
FUNCTION ( copy_s8     , BYTES1 (src[0]    ) )
FUNCTION ( copy_alaw   , alaw[*src] )
FUNCTION ( copy_ulaw   , ulaw[*src] )
FUNCTION ( copy_s24_le , BYTES3 (src[2], src[1], src[0] ) )
FUNCTION ( copy_s24_be , BYTES3 (src[0], src[1], src[2] ) )
FUNCTION ( copy_u24_le , BYTES3 (src[2]-128, src[1], src[0] ) )
FUNCTION ( copy_u24_be , BYTES3 (src[0]-128, src[1], src[2] ) )
FUNCTION ( copy_f80_le , read_float80_le (src) )
FUNCTION ( copy_f80_be , read_float80_be (src) )

/* ... and some are not or there are faster but byte order dependent possiblities */


#ifndef WORDS_BIGENDIAN

/* little endian */
FUNCTION ( copy_s16_le , *(const int16_t*)src )
FUNCTION ( copy_s16_be , BYTES2 (src[0], src[1] ) )
FUNCTION ( copy_u16_le , *(const uint16_t*)src - 32768 )
FUNCTION ( copy_u16_be , BYTES2 (src[0]-128, src[1] ) )
FUNCTION ( copy_s32_le , 1/65536. * *(const int32_t*)src )
FUNCTION ( copy_s32_be , BYTES4 (src[0], src[1], src[2], src[3] ) )
FUNCTION ( copy_u32_le , 1/65536. * *(const uint32_t*)src - 32768. )
FUNCTION ( copy_u32_be , BYTES4 (src[0]-128, src[1], src[2], src[3] ) )
FUNCTION ( copy_f32_le , *(const float32_t*)src )
FUNCTION ( copy_f32_be , read_opposite_float32 (src) )
FUNCTION ( copy_f64_le , *(const float64_t*)src )
FUNCTION ( copy_f64_be , read_opposite_float64 (src) )

#else

/* big endian */
FUNCTION ( copy_s16_le , BYTES2 (src[1], src[0] ) )
FUNCTION ( copy_s16_be , *(const int16_t*)src )
FUNCTION ( copy_u16_le , BYTES2 (src[1]-128, src[0] ) )
FUNCTION ( copy_u16_be , *(const uint16_t*)src - 32768 )
FUNCTION ( copy_s32_le , BYTES4 (src[3], src[2], src[1], src[0] ) )
FUNCTION ( copy_s32_be , 1/65536. * *(const int32_t*)src )
FUNCTION ( copy_u32_le , BYTES4 (src[3]-128, src[2], src[1], src[0] ) )
FUNCTION ( copy_u32_be , 1/65536. * *(const uint32_t*)src - 32768. )
FUNCTION ( copy_f32_le , read_opposite_float32 (src) )
FUNCTION ( copy_f32_be , *(const float32_t*)src )
FUNCTION ( copy_f64_le , read_opposite_float64 (src) )
FUNCTION ( copy_f64_be , *(const float64_t*)src )

#endif

/*
 *  The global collection of channel demultiplexer.
 *  For every data type we have the size of one memory object and two
 *  demultiplexer, one for big endians, one for little endians.
 *  The demultiplexers
 *    - 1st argument is the destination of the data converted to sample_t (and normalized to +/-32768)
 *    - 2nd argument is a pointer to the source data, in any format
 *    - 3rd argument is 1st argument of the table (multiplied by the channel count in the case of 
 *      interleaved data)
 *    - 4th argument is the count of samples per channel to convert
 */

typedef struct {
    const ssize_t  size;
    const demux_t  demultiplexer_be;
    const demux_t  demultiplexer_le;
} demux_info_t;

const demux_info_t  demux_info [] = {
    { -1, NULL        , NULL         }, /* 00: */
    {  0, copy_silence, copy_silence }, /* 01: */
    {  1, copy_u8     , copy_u8      }, /* 02: */
    {  1, copy_s8     , copy_s8      }, /* 03: */
    {  2, copy_u16_be , copy_u16_le  }, /* 04: */
    {  2, copy_s16_be , copy_s16_le  }, /* 05: */
    {  3, copy_u24_be , copy_u24_le  }, /* 06: */
    {  3, copy_s24_be , copy_s24_le  }, /* 07: */
    {  4, copy_u32_be , copy_u32_le  }, /* 08: */
    {  4, copy_s32_be , copy_s32_le  }, /* 09: */
    { -1, NULL        , NULL         }, /* 0A: */
    { -1, NULL        , NULL         }, /* 0B: */
    { -1, NULL        , NULL         }, /* 0C: */
    { -1, NULL        , NULL         }, /* 0D: */
    { -1, NULL        , NULL         }, /* 0E: */
    { -1, NULL        , NULL         }, /* 0F: */
    { -1, NULL        , NULL         }, /* 10: */
    { -1, NULL        , NULL         }, /* 11: */
    { -1, NULL        , NULL         }, /* 12: */
    { -1, NULL        , NULL         }, /* 13: */
    {  4, copy_f32_be , copy_f32_le  }, /* 14: */
    { -1, NULL        , NULL         }, /* 15: */
    { -1, NULL        , NULL         }, /* 16: */
    { -1, NULL        , NULL         }, /* 17: */
    {  8, copy_f64_be , copy_f64_le  }, /* 18: */
    { -1, NULL        , NULL         }, /* 19: */
    { 10, copy_f80_be , copy_f80_le  }, /* 1A: */
    { -1, NULL        , NULL         }, /* 1B: */
    { 12, copy_f80_be , copy_f80_le  }, /* 1C: */
    { -1, NULL        , NULL         }, /* 1D: */
    { -1, NULL        , NULL         }, /* 1E: */
    { -1, NULL        , NULL         }, /* 1F: */
    { 16, copy_f80_be , copy_f80_le  }, /* 20: */

    { sizeof(short)      , NULL        , NULL         }, /* 21: */
    { sizeof(int)        , NULL        , NULL         }, /* 22: */
    { sizeof(long)       , NULL        , NULL         }, /* 23: */
    { sizeof(float)      , copy_f32_be , copy_f32_le  }, /* 24: */
    { sizeof(double)     , copy_f64_be , copy_f64_le  }, /* 25: */
    { sizeof(long double), NULL        , NULL         }, /* 26: */

    { -1, NULL        , NULL         }, /* 27: */
    { -1, NULL        , NULL         }, /* 28: */
    { -1, NULL        , NULL         }, /* 29: */
    { -1, NULL        , NULL         }, /* 2A: */
    { -1, NULL        , NULL         }, /* 2B: */
    { -1, NULL        , NULL         }, /* 2C: */
    { -1, NULL        , NULL         }, /* 2D: */
    { -1, NULL        , NULL         }, /* 2E: */
    { -1, NULL        , NULL         }, /* 2F: */
    { -1, NULL        , NULL         }, /* 30: */
    {  1, copy_alaw   , copy_alaw    }, /* 31: */
    {  1, copy_ulaw   , copy_ulaw    }, /* 32: */
    { -1, NULL        , NULL         }, /* 33: */
    { -1, NULL        , NULL         }, /* 34: */
    { -1, NULL        , NULL         }, /* 35: */
    { -1, NULL        , NULL         }, /* 36: */
    { -1, NULL        , NULL         }, /* 37: */
    { -1, NULL        , NULL         }, /* 38: */
    { -1, NULL        , NULL         }, /* 39: */
    { -1, NULL        , NULL         }, /* 3A: */
    { -1, NULL        , NULL         }, /* 3B: */
    { -1, NULL        , NULL         }, /* 3C: */
    { -1, NULL        , NULL         }, /* 3D: */
    { -1, NULL        , NULL         }, /* 3E: */
    { -1, NULL        , NULL         }, /* 3F: */
};

/*
 *  Selects the right demultiplexer from the attribute field
 *  (currently endian and type information is used, rest is done in
 *  lame_encode_pcm)
 */

static inline int  select_demux ( OUT uint32_t mode, IN demux_t* retf, IN ssize_t* size )
{
    int                  big    = mode >> 24;
    const demux_info_t*  tabptr = demux_info + ((mode >> 16) & 0x3F);

    FN("select_demux");

#ifdef WORDS_BIGENDIAN
    /* big endian */
    big  = (big >> 1) ^ big ^ 1;        // 0=big, 1=little, 2=little, 3=big
#else
    /* little endian */                 // 0=little, 1=big, 2=little, 3=big
#endif

    *size = tabptr -> size;
    *retf = big & 1  ?  tabptr -> demultiplexer_be
                     :  tabptr -> demultiplexer_le;
    return *retf != NULL  ?  0  :  -1;
}

/*}}}*/
/*{{{ amplify/resample stuff          */

/*
 *  routine to feed EXACTLY one frame (lame->frame_size) worth of data to the
 *  encoding engine. All buffering, resampling, etc, handled by calling program.
 */

static inline int  internal_lame_encoding_pcm (
        INOUT lame_t*           const lame,
        INOUT octetstream_t*    const os,
        OUT   sample_t* const * const data,
        OUT   size_t                  len )
{
    size_t           i;
    double           ampl;
    double           dampl;
    int              ampl_on;
    size_t           ch;
    size_t           mf_needed;
    int              ret;
    size_t           n_in;
    size_t           n_out;
    size_t           remaining = len;
    sample_t*        mfbuf [MAX_CHANNELS];
    const sample_t*  pdata [MAX_CHANNELS];

    FN("internal_lame_encoding_pcm");

    /// this should be moved to lame_init_params();
    // some sanity checks
#if ENCDELAY < MDCTDELAY
# error ENCDELAY is less than MDCTDELAY, see <encoder.h>
#endif
#if FFTOFFSET > BLKSIZE
# error FFTOFFSET is greater than BLKSIZE, see <encoder.h>
#endif

    mf_needed = BLKSIZE + lame->frame_size - FFTOFFSET;           // amount needed for FFT
    mf_needed = MAX ( mf_needed, 286 + 576 * (1+lame->mode_gr) ); // amount needed for MDCT/filterbank
    assert ( mf_needed <= MFSIZE );
    ///

    os -> length = 0;
    pdata [0]    = data [0];
    pdata [1]    = data [1];
    mfbuf [0]    = lame->mfbuf [0];
    mfbuf [1]    = lame->mfbuf [1];

    ampl    = lame->last_ampl;
    dampl   = 0.;
    if ( lame->ampl != ampl ) {
        if (remaining <= 1) {           // constant amplification
            ampl_on = 1;
        } else {                        // fading
            ampl_on = 2;
            dampl   = (lame->ampl - ampl) / remaining * lame->sampfreq_out / lame->sampfreq_in;
        }
        lame->last_ampl = lame->ampl;
    } else if ( lame->ampl != 1. ) {    // constant amplification
        ampl_on = 1;
    } else {                            // no manipulation (fastest)
        ampl_on = 0;
    }

    while ( (int) remaining > 0 ) {

        FN("internal_lame_encoding_pcm 3");

        /* copy in new samples into mfbuf, with resampling if necessary */
        if ( lame->resample_in != NULL )  {
	
            FN("internal_lame_encoding_pcm 10");
	
            for ( ch = 0; ch < lame->channels_out; ch++ ) {
                n_in  = remaining;
                n_out = lame->frame_size;
		
                FN("internal_lame_encoding_pcm 12");

                // resample filter virtually should have no delay !
                ret   = resample_buffer (
                            lame->resample_in,
                            mfbuf [ch] + lame->mf_size, &n_out,
                            pdata [ch]                , &n_in,
                            ch );
                if ( ret < 0 )
                    return ret;
                pdata [ch] += n_in;
            }
	    
            FN("internal_lame_encoding_pcm 13");
	    
        }
        else {
	
            FN("internal_lame_encoding_pcm 14");
	
            n_in = n_out = MIN ( lame->frame_size, remaining );

            FN("internal_lame_encoding_pcm 15");

            for ( ch = 0; ch < lame->channels_out; ch++ ) {
                memcpy (  mfbuf [ch] + lame->mf_size,
                          pdata [ch],
                          n_out * sizeof (**mfbuf) );
                pdata [ch] += n_in;
            }
	    
            FN("internal_lame_encoding_pcm 16");
	    
        }

        FN("internal_lame_encoding_pcm 4");

        switch ( ampl_on ) {
        case 0:
            break;
        case 1:
            for ( ch = 0; ch < lame->channels_out; ch++ )
                for ( i = 0; i < n_out; i++ )
                    mfbuf [ch] [lame->mf_size + i] *= ampl;
            break;
        case 2:
            for ( i = 0; i < n_out; i++, ampl += dampl )
                for ( ch = 0; ch < lame->channels_out; ch++ )
                    mfbuf [ch] [lame->mf_size + i] *= ampl;
            break;
        default:
            assert (0);
            break;
        }

        FN("internal_lame_encoding_pcm 4");

        fprintf ( stderr, "n_in=%d, n_out=%d, remaining=%d, remaining=%d\n", n_in, n_out, remaining, remaining-n_in );

        remaining                  -= n_in;
        lame->mf_size              += n_out;
        lame->mf_samples_to_encode += n_out;

        // encode ONE frame if enough data available
        if ( lame->mf_size >= mf_needed ) {
            // Enlarge octetstream buffer if (possibly) needed by (25% + 16K)
            if ( os->size < 16384 + os->length )
                octetstream_resize ( os, os->size + os->size/4 + 16384 );
            // Encode one frame
            ret = lame_encode_frame ( lame, mfbuf,
                                      os->data + os->length, os->size - os->length );

            if (ret < 0)
                return ret;
            os->length += ret;

            FN("internal_lame_encoding_pcm 5");

            // shift out old samples
            lame->mf_size              -= lame->frame_size;
            lame->mf_samples_to_encode -= lame->frame_size;
            for ( ch = 0; ch < lame->channels_out; ch++ )
                memmove ( mfbuf [ch] + 0, mfbuf [ch] + lame->frame_size, lame->mf_size * sizeof (**mfbuf) );
		
            FN("internal_lame_encoding_pcm 6");

        }
    }
    assert (remaining == 0);
    return 0;
}

/*}}}*/
/*{{{ demultiplexing stuff            */

static inline void  average ( sample_t* dst, const sample_t* src1, const sample_t* src2, size_t len )
{
    FN("average");

    while (len--)
        *dst++ = (*src1++ + *src2++) * 0.5;
}

int  lame_encode_pcm (
        lame_t* const   lame,
        octetstream_t*  os,
        const void*     pcm,
        size_t          len,
        uint32_t        flags )
{
    sample_t*           data [2];
    demux_t             retf;
    ssize_t             size;
    const uint8_t*      p;
    const uint8_t* const*  q;
    int                 ret;
    size_t              channels_in = flags & 0xFFFF;

    FN("lame_encode_pcm");

    if (len == 0)
        return 0;

    if (select_demux ( flags, &retf, &size ) < 0)
        return -1;

    data[0] = (sample_t*) calloc (sizeof(sample_t), len);
    data[1] = (sample_t*) calloc (sizeof(sample_t), len);

    switch (flags >> 28) {
    case LAME_INTERLEAVED >> 28:
        p = (const uint8_t*) pcm;
        switch ( lame->channels_out ) {
        case 1:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], p+0*size, 1*size, len );
                break;
            case 2:
                retf ( data[0], p+0*size, 2*size, len );
                retf ( data[1], p+1*size, 2*size, len );
                average ( data[0], data[0], data[1], len );
                memset ( data[1], 0, sizeof(sample_t)*len );
                break;
            default:
                return -1;
                break;
            }
            break;
        case 2:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], p+0*size, 1*size, len );
                memcpy ( data[1], data[0], sizeof(sample_t)*len );
                break;
            case 2:
                retf ( data[0], p+0*size, 2*size, len );
                retf ( data[1], p+1*size, 2*size, len );
                break;
            default:
                return -1;
                break;
            }
            break;
        default:
            return -1;
        }
        break;

    case LAME_CHAINED >> 28:
        p = (const uint8_t*) pcm;
        switch ( lame->channels_out ) {
        case 1:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], p+0*size*len, size, len );
                break;
            case 2:
                retf ( data[0], p+0*size*len, size, len );
                retf ( data[1], p+1*size*len, size, len );
                average ( data[0], data[0], data[1], len );
                memset ( data[1], 0, sizeof(sample_t)*len );
                break;
            default:
                return -1;
                break;
            }
            break;
        case 2:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], p+0*size*len, size, len );
                memcpy ( data[1], data[0], sizeof(sample_t)*len );
                break;
            case 2:
                retf ( data[0], p+0*size*len, size, len );
                retf ( data[1], p+1*size*len, size, len );
                break;
            default:
                return -1;
                break;
            }
            break;
        default:
            return -1;
        }
        break;

    case LAME_INDIRECT >> 28:
        q = (const uint8_t* const*) pcm;
        switch ( lame->channels_out ) {
        case 1:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], q[0], size, len );
                break;
            case 2:
                retf ( data[0], q[0], size, len );
                retf ( data[1], q[1], size, len );
                average ( data[0], data[0], data[1], len );
                memset ( data[1], 0, sizeof(sample_t)*len );
                break;
            default:
                return -1;
                break;
            }
            break;
        case 2:
            switch ( channels_in ) {
            case 1:
                retf ( data[0], q[0], size, len );
                memcpy ( data[1], data[0], sizeof(sample_t)*len );
                break;
            case 2:
                retf ( data[0], q[0], size, len );
                retf ( data[1], q[1], size, len );
                break;
            default:
                return -1;
                break;
            }
            break;
        default:
            return -1;
        }
        break;

    default:
        return -1;
    }

    ret = internal_lame_encoding_pcm ( lame, os, (sample_t const* const*) data, len );

    free ( data[0] );
    free ( data[1] );
    return ret;
}

/*}}}*/
/*{{{ lame_encode_pcm_flush           */

int  lame_encode_pcm_flush (
        lame_t*        const  lame,
        octetstream_t* const  os )
{
    int  ret;
    int  ret_cb;

    FN("lame_encode_pcm_flush");

    ret = lame_encode_pcm ( lame, os, NULL, 
                            lame->mf_samples_to_encode + lame->frame_size, 
			    LAME_INTERLEAVED | LAME_SILENCE | 1 );


    // ugly, not encapsulated
    flush_bitstream (lame -> global_flags);       // mp3 related stuff. bit buffer might still contain some mp3 data
    id3tag_write_v1 (lame -> global_flags);       // write a ID3 tag to the bitstream
    ret_cb = copy_buffer (os->data, os->size - os->length, &lame->bs);
    if (ret_cb < 0) 
        return ret_cb;
    os->length += ret_cb;


    return ret;
}

/*
 *  Data flow
 *  ~~~~~~~~~
 *  lame_encode_buffer (public)
 *  lame_encode_buffer_interleaved (public)
 *      - do some little preparations and calls lame_encode_pcm
 *  lame_encode_pcm (public)
 *      - demultiplexing
 *      - type converting
 *      - endian handling
 *      - alignment handling
 *      - channel number converting (currently averaging or duplicating)
 *  internal_lame_encoding_pcm
 *      - resampling
 *      - level attenuator/amplifier, fader
 *      - divide input into frames
 *      - merge encoded data to one stream
 *      - does a lot of things which should be done in the setup
 *  lame_encode_frame
 *      - calls the right next stage encoder
 *      - counts the number of encoded frames
 *      - analyzer call back
 *  lame_encode_???_frame
 *      - out of the scope of this file
 */

/*}}}*/
/*{{{ Legacy stuff                    */

static lame_t*  pointer2lame ( void* const handle )
{
    lame_t*             lame = (lame_t*)handle;
    lame_global_flags*  gfp  = (lame_global_flags*)handle;

    FN("pointer2lame");

    if ( lame == NULL )
        return NULL;
    if ( lame->Class_ID == LAME_ID )
        return lame;

    if ( gfp->num_channels == 1  ||  gfp->num_channels == 2 ) {
        lame = (lame_t*) (gfp->internal_flags);

        if ( lame == NULL )
            return NULL;
        if ( lame->Class_ID == LAME_ID )
            return lame;
    }
    return NULL;
}


int  lame_encode_buffer (
        void* const    gfp,
        const int16_t  buffer_l [],
        const int16_t  buffer_r [],
        const size_t   nsamples,
        void* const    mp3buf,
        const size_t   mp3buf_size )
{
    const int16_t*  pcm [2];
    octetstream_t*  os;
    int             ret;
    lame_t*         lame;

    FN("lame_encode_buffer");

    lame    = pointer2lame (gfp);
    os      = octetstream_open (mp3buf_size);
    pcm [0] = buffer_l;
    pcm [1] = buffer_r;

    ret     = lame_encode_pcm ( lame, os, pcm, nsamples,
                                LAME_INDIRECT | LAME_NATIVE_ENDIAN | LAME_INT16 |
                                lame->channels_in );

    memcpy ( mp3buf, os->data, os->length );
    if (ret == 0) ret = os->length;
    octetstream_close (os);
    return ret;
}


int  lame_encode_buffer_interleaved (
        void* const    gfp,
        const int16_t  buffer [],
        size_t         nsamples,
        void* const    mp3buf,
        const size_t   mp3buf_size )
{
    octetstream_t*  os;
    int             ret;
    lame_t*         lame;

    FN("lame_encode_buffer_interleaved");

    lame    = pointer2lame (gfp);
    os      = octetstream_open (mp3buf_size);

    ret     = lame_encode_pcm ( lame, os, buffer, nsamples,
                                LAME_INTERLEAVED | LAME_NATIVE_ENDIAN | LAME_INT16 |
                                lame->channels_in );

    memcpy ( mp3buf, os->data, os->length );
    if (ret == 0) ret = os->length;
    octetstream_close (os);
    return ret;
}


int  lame_encode_flush (
        void* const    gfp,
        void* const    mp3buf,
        const size_t   mp3buf_size )
{
    octetstream_t*  os;
    int             ret;
    lame_t*         lame;

    FN("lame_encode_flush");

    lame    = pointer2lame (gfp);
    os      = octetstream_open (mp3buf_size);

    ret     = lame_encode_pcm_flush ( lame, os );

    memcpy ( mp3buf, os->data, os->length );
    if (ret == 0) ret = os->length;
    octetstream_close (os);
    return ret;
}

/*}}}*/
/*{{{ sin/cos/sinc/rounding functions */

static inline long  round_nearest ( long double x )
{
    if ( x >= 0. )
        return (long)(x+0.5);
    else
        return (long)(x-0.5);
}


static inline long  round_down ( long double x )
{
    if ( x >= 0. )
        return +(long)(+x);
    else
        return -(long)(-x);
}


static inline long double  sinpi ( long double x )
{
    x -= round_down (x) & ~1;

    switch ( (int)(4.*x) ) {
    default: assert (0);
    case  0: return +SIN ( M_PIl * (0.0+x) );
    case  1: return +COS ( M_PIl * (0.5-x) );
    case  2: return +COS ( M_PIl * (x-0.5) );
    case  3: return +SIN ( M_PIl * (1.0-x) );
    case  4: return -SIN ( M_PIl * (x-1.0) );
    case  5: return -COS ( M_PIl * (1.5-x) );
    case  6: return -COS ( M_PIl * (x-1.5) );
    case  7: return -SIN ( M_PIl * (2.0-x) );
    }
}


static inline long double  cospi ( long double x )
{
    x -= round_down (x) & ~1;

    switch ( (int)(4.*x) ) {
    default: assert (0);
    case  0: return +COS ( M_PIl * (x-0.0) );
    case  1: return +SIN ( M_PIl * (0.5-x) );
    case  2: return -SIN ( M_PIl * (x-0.5) );
    case  3: return -COS ( M_PIl * (1.0-x) );
    case  4: return -COS ( M_PIl * (x-1.0) );
    case  5: return -SIN ( M_PIl * (1.5-x) );
    case  6: return +SIN ( M_PIl * (x-1.5) );
    case  7: return +COS ( M_PIl * (2.0-x) );
    }
}


static inline long double  sinc ( long double x )
{
    if ( x == 0. )
        return 1.;

    if ( x <  0. )
        x = -x;

    return sinpi ( x ) / ( M_PIl * x );
}

/*}}}*/
/*{{{ some window functions           */

static inline  double  hanning ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x = cospi (0.5 * x);
    return x * x;
}

static inline  double  hamming ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x = cospi (x);
    return 0.54 + 0.46 * x;
}

static inline  double  blackman ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x = cospi (x);
    return (0.16 * x + 0.50) * x + 0.34;        // using addition theorem of arc functions
}

static inline  double  blackman1 ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x += 1.;
    return 0.42 - 0.50*cospi(x) + 0.08*cospi(2*x);
}

static inline  double  blackman2 ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x += 1.;
    return 0.375 - 0.50*cospi(x) + 0.125*cospi(2*x);
}

static inline  double  blackmanharris_nuttall ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x += 1.;
    return (10 - 15*cospi (x) + 6*cospi (2*x) - cospi (3*x) ) * (1./32);
}

static inline  double  blackmanharris_min4 ( double x )
{
    if ( fabs (x) >= 1 )
        return 0.;

    x += 1.;
    return 0.355768 - 0.487396*cospi (x) + 0.144232*cospi (2*x) - 0.012604*cospi (3*x);
}

/*
 * Blackman-Harris windows, which have the general equation:
 *
 *          w(n) = a0 - a1 cos(2pn/N) + a2 cos(4pn/N) - a3 cos(6pn/N).
 *
 * When Nuttall set the ak coefficients to the "minimum 4-term" values of a0 = 0.355768, a1 =
 * 0.487396, a2 = 0.144232, and a3 = 0.012604, he obtained the window and the frequency
 * response shown in Figure 8. The minimum-4-term window loses some frequency
 * resolution because it has a wide main lobe, but the first side lobe drops to -93 db.
 *
 * If you require fast side-lobe rolloff in an application, consider Nuttall's Equation (30). It
 * applies the following coefficients to the general equation above: a0 = 10/32, a1 = 15/32, a2 =
 * 6/32, and a3 = 1/32. Figure 8 also includes the window and frequency response for Nuttall's
 * Equation (30). This window has a first side-lobe level of -61 dB and a significant side-lobe
 * rolloff of -42 dB/octave.
 *
 * The first investigators of windowing functions determined that window functions should
 * have zero values at their boundaries and so should their successive derivatives. If a
 * window's kth derivative is zero at the boundaries, the peaks of the window's side lobes will
 * decay at a rate of 6(k+2) dB/octave. T&MW.
 */

/*}}}*/
/*{{{ scalar stuff                    */


/**********************************************************
 *                                                        *
 *           Functions taken from scalar.nas              *
 *                                                        *
 **********************************************************/

/*
 * The scalarxx versions with xx=04,08,12,16,20,24 are fixed size for xx element scalars
 * The scalar1n version is suitable for every non negative length
 * The scalar4n version is only suitable for positive lengths which are a multiple of 4
 *
 * The following are equivalent:
 *    scalar12 (p, q);
 *    scalar4n (p, q, 3);
 *    scalar1n (p, q, 12);
 */

float_t  scalar04_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
}

float_t  scalar08_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]
          + p[4]*q[4] + p[5]*q[5] + p[6]*q[6] + p[7]*q[7];
}

float_t  scalar12_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[0]*q[0] + p[1]*q[1] + p[ 2]*q[ 2] + p[ 3]*q[ 3]
          + p[4]*q[4] + p[5]*q[5] + p[ 6]*q[ 6] + p[ 7]*q[ 7]
          + p[8]*q[8] + p[9]*q[9] + p[10]*q[10] + p[11]*q[11];
}

float_t  scalar16_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[ 0]*q[ 0] + p[ 1]*q[ 1] + p[ 2]*q[ 2] + p[ 3]*q[ 3]
          + p[ 4]*q[ 4] + p[ 5]*q[ 5] + p[ 6]*q[ 6] + p[ 7]*q[ 7]
          + p[ 8]*q[ 8] + p[ 9]*q[ 9] + p[10]*q[10] + p[11]*q[11]
          + p[12]*q[12] + p[13]*q[13] + p[14]*q[14] + p[15]*q[15];
}

float_t  scalar20_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[ 0]*q[ 0] + p[ 1]*q[ 1] + p[ 2]*q[ 2] + p[ 3]*q[ 3]
          + p[ 4]*q[ 4] + p[ 5]*q[ 5] + p[ 6]*q[ 6] + p[ 7]*q[ 7]
          + p[ 8]*q[ 8] + p[ 9]*q[ 9] + p[10]*q[10] + p[11]*q[11]
          + p[12]*q[12] + p[13]*q[13] + p[14]*q[14] + p[15]*q[15]
          + p[16]*q[16] + p[17]*q[17] + p[18]*q[18] + p[19]*q[19];
}

float_t  scalar24_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[ 0]*q[ 0] + p[ 1]*q[ 1] + p[ 2]*q[ 2] + p[ 3]*q[ 3]
          + p[ 4]*q[ 4] + p[ 5]*q[ 5] + p[ 6]*q[ 6] + p[ 7]*q[ 7]
          + p[ 8]*q[ 8] + p[ 9]*q[ 9] + p[10]*q[10] + p[11]*q[11]
          + p[12]*q[12] + p[13]*q[13] + p[14]*q[14] + p[15]*q[15]
          + p[16]*q[16] + p[17]*q[17] + p[18]*q[18] + p[19]*q[19]
          + p[20]*q[20] + p[21]*q[21] + p[22]*q[22] + p[23]*q[23];
}

float_t  scalar32_float32 ( const sample_t* p, const sample_t* q )
{
    return  p[ 0]*q[ 0] + p[ 1]*q[ 1] + p[ 2]*q[ 2] + p[ 3]*q[ 3]
          + p[ 4]*q[ 4] + p[ 5]*q[ 5] + p[ 6]*q[ 6] + p[ 7]*q[ 7]
          + p[ 8]*q[ 8] + p[ 9]*q[ 9] + p[10]*q[10] + p[11]*q[11]
          + p[12]*q[12] + p[13]*q[13] + p[14]*q[14] + p[15]*q[15]
          + p[16]*q[16] + p[17]*q[17] + p[18]*q[18] + p[19]*q[19]
          + p[20]*q[20] + p[21]*q[21] + p[22]*q[22] + p[23]*q[23]
          + p[24]*q[24] + p[25]*q[25] + p[26]*q[26] + p[27]*q[27]
          + p[28]*q[28] + p[29]*q[29] + p[30]*q[30] + p[31]*q[31];
}

float_t  scalar4n_float32 ( const sample_t* p, const sample_t* q, size_t len )
{
    double sum = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];

    while (--len) {
        p   += 4;
        q   += 4;
        sum += p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
    }
    return sum;
}

float_t  scalar1n_float32 ( const sample_t* p, const sample_t* q, size_t len )
{
    float_t sum;

    switch (len & 3) {
    case 0:
        sum  = 0.;
        break;
    case 1:
        sum  = p[0]*q[0];
        p   += 1;
        q   += 1;
        break;
    case 2:
        sum  = p[0]*q[0] + p[1]*q[1];
        p   += 2;
        q   += 2;
        break;
    default:
        sum  = p[0]*q[0] + p[1]*q[1] + p[2]*q[2];
        p   += 3;
        q   += 3;
        break;
    }
    
    for ( len >>= 2; len--; ) {
        sum += p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
        p   += 4;
        q   += 4;
    }
    return sum;
}


scalar_t   scalar04 = scalar04_float32;
scalar_t   scalar08 = scalar08_float32;
scalar_t   scalar12 = scalar12_float32;
scalar_t   scalar16 = scalar16_float32;
scalar_t   scalar20 = scalar20_float32;
scalar_t   scalar24 = scalar24_float32;
scalar_t   scalar32 = scalar32_float32;
scalarn_t  scalar4n = scalar4n_float32;
scalarn_t  scalar1n = scalar1n_float32;


void  init_scalar_functions ( OUT lame_t* const lame )
{
    if ( lame -> CPU_features.i387 ) {
        scalar04 = scalar04_float32_i387;
        scalar08 = scalar08_float32_i387;
        scalar12 = scalar12_float32_i387;
        scalar16 = scalar16_float32_i387;
        scalar20 = scalar20_float32_i387;
        scalar24 = scalar24_float32_i387;
        scalar32 = scalar32_float32_i387;
        scalar4n = scalar4n_float32_i387;
        scalar1n = scalar1n_float32_i387;
    }

    if ( lame -> CPU_features.AMD_3DNow ) {
        scalar04 = scalar04_float32_3DNow;
        scalar08 = scalar08_float32_3DNow;
        scalar12 = scalar12_float32_3DNow;
        scalar16 = scalar16_float32_3DNow;
        scalar20 = scalar20_float32_3DNow;
        scalar24 = scalar24_float32_3DNow;
        scalar32 = scalar32_float32_3DNow;
        scalar4n = scalar4n_float32_3DNow;
        scalar1n = scalar1n_float32_3DNow;
    }

    if ( lame -> CPU_features.SIMD ) {
        scalar04 = scalar04_float32_SIMD;
        scalar08 = scalar08_float32_SIMD;
        scalar12 = scalar12_float32_SIMD;
        scalar16 = scalar16_float32_SIMD;
        scalar20 = scalar20_float32_SIMD;
        scalar24 = scalar24_float32_SIMD;
        scalar32 = scalar32_float32_SIMD;
        scalar4n = scalar4n_float32_SIMD;
        scalar1n = scalar1n_float32_SIMD;
    }
}

/*}}}*/
/*{{{ factorize                       */

/*
 *  Tries to find the best integral ratio for two sampling frequencies
 *  It searches the best ratio a:b with b <= MAX_TABLES
 */

static double  factorize ( 
        OUT long double  f1, 
	OUT long double  f2, 
	IN  int* const   x1, 
	IN  int* const   x2 )
{
    unsigned     i;
    long         ltmp;
    long double  ftmp;
    double       minerror = 1.;
    double       abserror = 1.;

    assert ( f1 > 0. );
    assert ( f2 > 0. );
    assert ( x1 != NULL );
    assert ( x2 != NULL );

    for ( i = 1; i <= MAX_TABLES; i++ ) {
        ftmp  = f2 * i / f1;
        ltmp  = (long) ( ftmp + 0.5 );
        if ( fabs ( (ltmp-ftmp)/ftmp ) < minerror ) {
            *x1      = i;
            *x2      = (int)ltmp;
            abserror = (ltmp-ftmp) / ftmp;
            minerror = 0.9999847412109375 * fabs (abserror);
        }
    }
    return abserror;
}

/*
 *  Some programmers and some file format only supporting integral sampling frequencies
 *  This patch tries to find the right sampling frequency for some know rounding victims.
 *  Better is to support directly 64 or 80 bit FPU precision.
 */

long double  unround_samplefrequency ( OUT long double freq )
{
    if ( freq != (unsigned short)freq )
        return freq;

    switch ( (unsigned short)freq ) {
    case 48662: case 48663: return 1411200/ 29.L;  // SB 128 "48 kHz"         48662.06896551724137931034
    case 44055: case 44056: return 2863636/ 65.L;  // NTSC PCM/LD PCM         44055.93846153846153846153
    case 32072: case 32073: return 1411200/ 44.L;  // SB 128 "32 kHz"         32072.72727272727272727272
    case 31468: case 31469: return 2863636/ 91.L;  // NTSC Hi8 Digital Audio  31468.52747252747252747252
    case 23918: case 23919: return 1411200/ 59.L;  // SB 128 "24 kHz"         23918.64406779661016949152
    case 22254: case 22255: return  244800/ 11.L;  // MAC HQ                  22254.54545454545454545454
    case 16036: case 16037: return 1411200/ 88.L;  // SB 128 "16 kHz"         16036.36363636363636363636
    case 11959: case 11960: return 1411200/118.L;  // SB 128 "12 kHz"         11959.32203389830508474576
    case 11127: case 11128: return  122400/ 11.L;  // MAC LQ                  11127.27272727272727272727
    case  8018: case  8019: return 1411200/176.L;  // SB 128  "8 kHz"          8018.18181818181818181818
    case  8012: case  8013: return  312500/ 39.L;  // NeXT/Telco               8012.82051282051282051282
    case  5512: case  5513: return   44100/  8.L;  // 1/8 CD                   5512.50000000000000000000
    }

    return freq;
}

/*}}}*/
/*{{{ resampling stuff                */

static inline void  Calc_Coeffs (
        IN  sample_t*  Coeff,
        OUT int        iNew,
        OUT int        iOld,
        OUT long       i,
        OUT long       k,
        OUT double     bandwidth )   // 0.0 ... 1.0: used bandwidth from 0...fs_out/2
{
    long double  w   = 1.L / (WINDOW_SIZE + 0.5);
    long double  sum = 0.;
    long double  tmp1;
    long double  tmp2;
    long         j;

    for ( j = 0; j <= 2*WINDOW_SIZE; j++ ) {
        tmp1 = ((k+j)*iNew - i*iOld) / (long double)iNew * bandwidth;
        tmp2 = ((k+j)*iNew - i*iOld) / (long double)iNew;
        sum += Coeff [j] = sinc (tmp1) * WINDOW (tmp2 * w);
    }

    for ( j = 0; j <= 2*WINDOW_SIZE; j++ )
        Coeff [j] /= sum;
}


resample_t*  resample_open (
        OUT long double  sampfreq_in,    // [Hz]
        OUT long double  sampfreq_out,   // [Hz]
        OUT double       lowpass_freq,   // [Hz] or <0 for auto mode
        OUT int          quality )       // Proposal: 0: default, 1: sample select, 2: linear interpolation
                                         //           4: 4-point interpolation, 32: 32-point interpolation
{
    resample_t* const  ret = calloc ( sizeof(resample_t), 1 );
    long               i;
    sample_t*          p;
    double             err;

    FN("resample_open");

    if ( sampfreq_in == sampfreq_out )
        return NULL;

    err = factorize ( sampfreq_out, sampfreq_in, &(ret->scale_out), &(ret->scale_in) );
    fprintf ( stderr, "(%.6g => %.6g Hz, Ratio %d:%d",
              (double)sampfreq_in, (double)sampfreq_out, ret->scale_in, ret->scale_out );
    if ( fabs (err) > 5.e-10 )                                            // 16 msec/year
        fprintf ( stderr, ", Error %+.3f ppm", 1.e6*err );
    fprintf ( stderr, ")\n" );
    fflush  ( stderr );

    if ( ret->scale_out == ret->scale_in )
        return NULL;

    ret->Class_ID        = RESAMPLE_ID;
    ret->samplefreq_in   = sampfreq_in;
    ret->samplefreq_out  = sampfreq_out;
    ret->taps            = TAPS;
    ret->lowpass_freq    = lowpass_freq < 0.  ?  0.50 * MIN (sampfreq_in, sampfreq_out)  :  lowpass_freq;
    ret->in_old [0]      = calloc ( sizeof(sample_t*)     , 2*TAPS );
    ret->in_old [1]      = calloc ( sizeof(sample_t*)     , 2*TAPS );
    ret->src_step        = calloc ( sizeof(unsigned char*), (unsigned)ret->scale_out );
    ret->fir             = calloc ( sizeof(sample_t*)     , (unsigned)ret->scale_out );
    ret->firfree         = calloc ( sizeof(sample_t)      , TAPS * ret->scale_out + 64/sizeof(sample_t) );
    p                    = (sample_t*) ( ((ptrdiff_t)(ret->firfree) | 63) + 1 ); /* 64 byte alignment */

    for ( i = 0; i < ret->scale_out; i++, p += TAPS ) {
        ret->src_step [i] = round_nearest ( (i+1.L) * ret->scale_in / ret->scale_out )
                          - round_nearest ( (i+0.L) * ret->scale_in / ret->scale_out );
                          
        Calc_Coeffs ( ret->fir [i] = p,
                      ret->scale_out, ret->scale_in,
                      i, round_nearest ( (double)i * ret->scale_in / ret->scale_out - WINDOW_SIZE ),
                      2.*ret->lowpass_freq / sampfreq_out );
    }

    return ret;
}


/* Should be done with more sanity checks */

int  resample_close ( INOUT resample_t* const r )
{
    FN("resample_close");

    if ( r == NULL )
        return -1;
    free ( r->in_old [0] );
    free ( r->in_old [1] );
    free ( r->fir [0]    );
    free ( r->fir        );
    free ( r->src_step   );
    return 0;
}


// in the future some of the copies should be avoided by usage of mfbuf
// also by the fill_buffer_resample() routine

/*
 *  Current working scheme:
 *
 *  | old | new                data in in_buf, consist of old *and new data
 *  |0 1 2|3 4 5 6 ...
 *
 *   <--1-->
 *     <--2-->
 *       <--3-->
 *
 *        | new                data in in, only new data
 *        |0 1 2 3 4 5 6
 *         <--4-->
 *           <--5-->
 *             <--6-->
 */

int  resample_buffer (                          // return code, 0 for success
        INOUT resample_t *const   r,            // internal structure
        IN    sample_t   *const   out,          // where to write the output data
        INOUT size_t     *const   out_req_len,  // requested output data len/really written output data len
        OUT   sample_t   *const   in,           // where are the input data?
        INOUT size_t     *const   in_avail_len, // available input data len/consumed input data len
        OUT   size_t              channel )     // number of the channel (needed for internal buffering)
{
    sample_t*  p           = out;
    sample_t*  in_old      = r->in_old [channel];
    size_t     len         = *in_avail_len;
    size_t     desired_len = *out_req_len;
    size_t     i;
    size_t     k;
    int        l;

    FN("resample_buffer");

    // copy TAPS samples to the second half of in_old
    memcpy ( in_old + TAPS, in, MIN (len*sizeof(*in), TAPS*sizeof(*in)) );

    // calculating k and l
    l = r->fir_stepper [channel];
    k = r->inp_stepper [channel];

    // doing converting for all samples which can be done in 'in_old'
    for ( i = 0; i < desired_len  &&  k < TAPS; i++ ) {
        *p++ = scalar32 ( in_old + k, r->fir [l] );
        k   += r->src_step [l];
        if ( ++l >= r->scale_out ) l = 0;
    }

    // doing converting for all samples which can be done in 'in'
    k -= TAPS;
    for ( ; i < desired_len  &&  k < len - TAPS; i++ ) {
        *p++ = scalar32 ( in + k, r->fir [l] );
        k   += r->src_step [l];
        if ( ++l >= r->scale_out ) l = 0;
    }

    // writing back processed in and out
    *in_avail_len  = k - r->inp_stepper [channel];
    *out_req_len   = p - out;

    r->fir_stepper [channel] = l;
    r->inp_stepper [channel] = k - r->inp_stepper [channel] - len;

    // make of copy of the overlap
    if ( len >= TAPS )
        memcpy  ( in_old, in + len - TAPS, TAPS*sizeof(sample_t) );
    else
        memmove ( in_old, in_old + len   , TAPS*sizeof(sample_t) );

    return 0;
}

/*}}}*/

#endif /* KLEMM_44 */

/* end of pcm.c */

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.