ref: 37b86df09ff381bcc4f60802d43e57bd9bfcac73
dir: /sys/src/cmd/audio/mp3enc/pcm.c/
/* -*- 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 */