diff options
Diffstat (limited to 'sys/src/cmd/audio/mp3enc/pcm.c')
| -rw-r--r-- | sys/src/cmd/audio/mp3enc/pcm.c | 1609 |
1 files changed, 1609 insertions, 0 deletions
diff --git a/sys/src/cmd/audio/mp3enc/pcm.c b/sys/src/cmd/audio/mp3enc/pcm.c new file mode 100644 index 000000000..9b8a32a57 --- /dev/null +++ b/sys/src/cmd/audio/mp3enc/pcm.c @@ -0,0 +1,1609 @@ +/* -*- 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ücksichtigung 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 */ |
