| /* |
| * lame utility library source file |
| * |
| * Copyright (c) 1999 Albert L Faber |
| * Copyright (c) 2000-2005 Alexander Leidinger |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| /* $Id: util.c,v 1.140.2.4 2010/03/21 12:15:56 robert Exp $ */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include "lame.h" |
| #include "machine.h" |
| #include "encoder.h" |
| #include "util.h" |
| #include "lame_global_flags.h" |
| |
| #define PRECOMPUTE |
| #if defined(__FreeBSD__) && !defined(__alpha__) |
| # include <machine/floatingpoint.h> |
| #endif |
| |
| |
| /*********************************************************************** |
| * |
| * Global Function Definitions |
| * |
| ***********************************************************************/ |
| /*empty and close mallocs in gfc */ |
| |
| void |
| free_id3tag(lame_internal_flags * const gfc) |
| { |
| if (gfc->tag_spec.title != 0) { |
| free(gfc->tag_spec.title); |
| gfc->tag_spec.title = 0; |
| } |
| if (gfc->tag_spec.artist != 0) { |
| free(gfc->tag_spec.artist); |
| gfc->tag_spec.artist = 0; |
| } |
| if (gfc->tag_spec.album != 0) { |
| free(gfc->tag_spec.album); |
| gfc->tag_spec.album = 0; |
| } |
| if (gfc->tag_spec.comment != 0) { |
| free(gfc->tag_spec.comment); |
| gfc->tag_spec.comment = 0; |
| } |
| |
| if (gfc->tag_spec.albumart != 0) { |
| free(gfc->tag_spec.albumart); |
| gfc->tag_spec.albumart = 0; |
| gfc->tag_spec.albumart_size = 0; |
| gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE; |
| } |
| if (gfc->tag_spec.values != 0) { |
| unsigned int i; |
| for (i = 0; i < gfc->tag_spec.num_values; ++i) { |
| free(gfc->tag_spec.values[i]); |
| } |
| free(gfc->tag_spec.values); |
| gfc->tag_spec.values = 0; |
| gfc->tag_spec.num_values = 0; |
| } |
| if (gfc->tag_spec.v2_head != 0) { |
| FrameDataNode *node = gfc->tag_spec.v2_head; |
| do { |
| void *p = node->dsc.ptr.b; |
| void *q = node->txt.ptr.b; |
| void *r = node; |
| node = node->nxt; |
| free(p); |
| free(q); |
| free(r); |
| } while (node != 0); |
| gfc->tag_spec.v2_head = 0; |
| gfc->tag_spec.v2_tail = 0; |
| } |
| } |
| |
| |
| void |
| freegfc(lame_internal_flags * const gfc) |
| { /* bit stream structure */ |
| int i; |
| |
| |
| for (i = 0; i <= 2 * BPC; i++) |
| if (gfc->blackfilt[i] != NULL) { |
| free(gfc->blackfilt[i]); |
| gfc->blackfilt[i] = NULL; |
| } |
| if (gfc->inbuf_old[0]) { |
| free(gfc->inbuf_old[0]); |
| gfc->inbuf_old[0] = NULL; |
| } |
| if (gfc->inbuf_old[1]) { |
| free(gfc->inbuf_old[1]); |
| gfc->inbuf_old[1] = NULL; |
| } |
| |
| if (gfc->bs.buf != NULL) { |
| free(gfc->bs.buf); |
| gfc->bs.buf = NULL; |
| } |
| |
| if (gfc->VBR_seek_table.bag) { |
| free(gfc->VBR_seek_table.bag); |
| gfc->VBR_seek_table.bag = NULL; |
| gfc->VBR_seek_table.size = 0; |
| } |
| if (gfc->ATH) { |
| free(gfc->ATH); |
| } |
| if (gfc->PSY) { |
| free(gfc->PSY); |
| } |
| if (gfc->rgdata) { |
| free(gfc->rgdata); |
| } |
| if (gfc->s3_ll) { |
| /* XXX allocated in psymodel_init() */ |
| free(gfc->s3_ll); |
| } |
| if (gfc->s3_ss) { |
| /* XXX allocated in psymodel_init() */ |
| free(gfc->s3_ss); |
| } |
| if (gfc->in_buffer_0) { |
| free(gfc->in_buffer_0); |
| } |
| if (gfc->in_buffer_1) { |
| free(gfc->in_buffer_1); |
| } |
| free_id3tag(gfc); |
| #ifdef DECODE_ON_THE_FLY |
| if (gfc->hip) { |
| hip_decode_exit(gfc->hip); |
| gfc->hip = 0; |
| } |
| #endif |
| free(gfc); |
| } |
| |
| void |
| malloc_aligned(aligned_pointer_t * ptr, unsigned int size, unsigned int bytes) |
| { |
| if (ptr) { |
| if (!ptr->pointer) { |
| ptr->pointer = malloc(size + bytes); |
| if (bytes > 0) { |
| ptr->aligned = (void *) ((((size_t) ptr->pointer + bytes - 1) / bytes) * bytes); |
| } |
| else { |
| ptr->aligned = ptr->pointer; |
| } |
| } |
| } |
| } |
| |
| void |
| free_aligned(aligned_pointer_t * ptr) |
| { |
| if (ptr) { |
| if (ptr->pointer) { |
| free(ptr->pointer); |
| ptr->pointer = 0; |
| ptr->aligned = 0; |
| } |
| } |
| } |
| |
| /*those ATH formulas are returning |
| their minimum value for input = -1*/ |
| |
| static FLOAT |
| ATHformula_GB(FLOAT f, FLOAT value) |
| { |
| /* from Painter & Spanias |
| modified by Gabriel Bouvigne to better fit the reality |
| ath = 3.640 * pow(f,-0.8) |
| - 6.800 * exp(-0.6*pow(f-3.4,2.0)) |
| + 6.000 * exp(-0.15*pow(f-8.7,2.0)) |
| + 0.6* 0.001 * pow(f,4.0); |
| |
| |
| In the past LAME was using the Painter &Spanias formula. |
| But we had some recurrent problems with HF content. |
| We measured real ATH values, and found the older formula |
| to be inacurate in the higher part. So we made this new |
| formula and this solved most of HF problematic testcases. |
| The tradeoff is that in VBR mode it increases a lot the |
| bitrate. */ |
| |
| |
| /*this curve can be udjusted according to the VBR scale: |
| it adjusts from something close to Painter & Spanias |
| on V9 up to Bouvigne's formula for V0. This way the VBR |
| bitrate is more balanced according to the -V value.*/ |
| |
| FLOAT ath; |
| |
| /* the following Hack allows to ask for the lowest value */ |
| if (f < -.3) |
| f = 3410; |
| |
| f /= 1000; /* convert to khz */ |
| f = Max(0.1, f); |
| /* f = Min(21.0, f); |
| */ |
| ath = 3.640 * pow(f, -0.8) |
| - 6.800 * exp(-0.6 * pow(f - 3.4, 2.0)) |
| + 6.000 * exp(-0.15 * pow(f - 8.7, 2.0)) |
| + (0.6 + 0.04 * value) * 0.001 * pow(f, 4.0); |
| return ath; |
| } |
| |
| |
| |
| FLOAT |
| ATHformula(FLOAT f, lame_global_flags const *gfp) |
| { |
| FLOAT ath; |
| switch (gfp->ATHtype) { |
| case 0: |
| ath = ATHformula_GB(f, 9); |
| break; |
| case 1: |
| ath = ATHformula_GB(f, -1); /*over sensitive, should probably be removed */ |
| break; |
| case 2: |
| ath = ATHformula_GB(f, 0); |
| break; |
| case 3: |
| ath = ATHformula_GB(f, 1) + 6; /*modification of GB formula by Roel */ |
| break; |
| case 4: |
| ath = ATHformula_GB(f, gfp->ATHcurve); |
| break; |
| default: |
| ath = ATHformula_GB(f, 0); |
| break; |
| } |
| return ath; |
| } |
| |
| /* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ |
| FLOAT |
| freq2bark(FLOAT freq) |
| { |
| /* input: freq in hz output: barks */ |
| if (freq < 0) |
| freq = 0; |
| freq = freq * 0.001; |
| return 13.0 * atan(.76 * freq) + 3.5 * atan(freq * freq / (7.5 * 7.5)); |
| } |
| |
| /* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ |
| FLOAT |
| freq2cbw(FLOAT freq) |
| { |
| /* input: freq in hz output: critical band width */ |
| freq = freq * 0.001; |
| return 25 + 75 * pow(1 + 1.4 * (freq * freq), 0.69); |
| } |
| |
| |
| |
| |
| |
| |
| #define ABS(A) (((A)>0) ? (A) : -(A)) |
| |
| int |
| FindNearestBitrate(int bRate, /* legal rates from 8 to 320 */ |
| int version, int samplerate) |
| { /* MPEG-1 or MPEG-2 LSF */ |
| int bitrate; |
| int i; |
| |
| if (samplerate < 16000) |
| version = 2; |
| |
| bitrate = bitrate_table[version][1]; |
| |
| for (i = 2; i <= 14; i++) { |
| if (bitrate_table[version][i] > 0) { |
| if (ABS(bitrate_table[version][i] - bRate) < ABS(bitrate - bRate)) |
| bitrate = bitrate_table[version][i]; |
| } |
| } |
| return bitrate; |
| } |
| |
| |
| |
| |
| |
| #ifndef Min |
| #define Min(A, B) ((A) < (B) ? (A) : (B)) |
| #endif |
| #ifndef Max |
| #define Max(A, B) ((A) > (B) ? (A) : (B)) |
| #endif |
| |
| |
| /* Used to find table index when |
| * we need bitrate-based values |
| * determined using tables |
| * |
| * bitrate in kbps |
| * |
| * Gabriel Bouvigne 2002-11-03 |
| */ |
| int |
| nearestBitrateFullIndex(const int bitrate) |
| { |
| /* borrowed from DM abr presets */ |
| |
| const int full_bitrate_table[] = |
| { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }; |
| |
| |
| int lower_range = 0, lower_range_kbps = 0, upper_range = 0, upper_range_kbps = 0; |
| |
| |
| int b; |
| |
| |
| /* We assume specified bitrate will be 320kbps */ |
| upper_range_kbps = full_bitrate_table[16]; |
| upper_range = 16; |
| lower_range_kbps = full_bitrate_table[16]; |
| lower_range = 16; |
| |
| /* Determine which significant bitrates the value specified falls between, |
| * if loop ends without breaking then we were correct above that the value was 320 |
| */ |
| for (b = 0; b < 16; b++) { |
| if ((Max(bitrate, full_bitrate_table[b + 1])) != bitrate) { |
| upper_range_kbps = full_bitrate_table[b + 1]; |
| upper_range = b + 1; |
| lower_range_kbps = full_bitrate_table[b]; |
| lower_range = (b); |
| break; /* We found upper range */ |
| } |
| } |
| |
| /* Determine which range the value specified is closer to */ |
| if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps)) { |
| return lower_range; |
| } |
| return upper_range; |
| } |
| |
| |
| |
| |
| |
| /* map frequency to a valid MP3 sample frequency |
| * |
| * Robert Hegemann 2000-07-01 |
| */ |
| int |
| map2MP3Frequency(int freq) |
| { |
| if (freq <= 8000) |
| return 8000; |
| if (freq <= 11025) |
| return 11025; |
| if (freq <= 12000) |
| return 12000; |
| if (freq <= 16000) |
| return 16000; |
| if (freq <= 22050) |
| return 22050; |
| if (freq <= 24000) |
| return 24000; |
| if (freq <= 32000) |
| return 32000; |
| if (freq <= 44100) |
| return 44100; |
| |
| return 48000; |
| } |
| |
| int |
| BitrateIndex(int bRate, /* legal rates from 32 to 448 kbps */ |
| int version, /* MPEG-1 or MPEG-2/2.5 LSF */ |
| int samplerate) |
| { /* convert bitrate in kbps to index */ |
| int i; |
| if (samplerate < 16000) |
| version = 2; |
| for (i = 0; i <= 14; i++) { |
| if (bitrate_table[version][i] > 0) { |
| if (bitrate_table[version][i] == bRate) { |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| /* convert samp freq in Hz to index */ |
| |
| int |
| SmpFrqIndex(int sample_freq, int *const version) |
| { |
| switch (sample_freq) { |
| case 44100: |
| *version = 1; |
| return 0; |
| case 48000: |
| *version = 1; |
| return 1; |
| case 32000: |
| *version = 1; |
| return 2; |
| case 22050: |
| *version = 0; |
| return 0; |
| case 24000: |
| *version = 0; |
| return 1; |
| case 16000: |
| *version = 0; |
| return 2; |
| case 11025: |
| *version = 0; |
| return 0; |
| case 12000: |
| *version = 0; |
| return 1; |
| case 8000: |
| *version = 0; |
| return 2; |
| default: |
| *version = 0; |
| return -1; |
| } |
| } |
| |
| |
| /***************************************************************************** |
| * |
| * End of bit_stream.c package |
| * |
| *****************************************************************************/ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| /* resampling via FIR filter, blackman window */ |
| inline static FLOAT |
| blackman(FLOAT x, FLOAT fcn, int l) |
| { |
| /* This algorithm from: |
| SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C |
| S.D. Stearns and R.A. David, Prentice-Hall, 1992 |
| */ |
| FLOAT bkwn, x2; |
| FLOAT const wcn = (PI * fcn); |
| |
| x /= l; |
| if (x < 0) |
| x = 0; |
| if (x > 1) |
| x = 1; |
| x2 = x - .5; |
| |
| bkwn = 0.42 - 0.5 * cos(2 * x * PI) + 0.08 * cos(4 * x * PI); |
| if (fabs(x2) < 1e-9) |
| return wcn / PI; |
| else |
| return (bkwn * sin(l * wcn * x2) / (PI * l * x2)); |
| |
| |
| } |
| |
| /* gcd - greatest common divisor */ |
| /* Joint work of Euclid and M. Hendry */ |
| |
| static int |
| gcd(int i, int j) |
| { |
| /* assert ( i > 0 && j > 0 ); */ |
| return j ? gcd(j, i % j) : i; |
| } |
| |
| |
| |
| /* copy in new samples from in_buffer into mfbuf, with resampling |
| if necessary. n_in = number of samples from the input buffer that |
| were used. n_out = number of samples copied into mfbuf */ |
| |
| void |
| fill_buffer(lame_global_flags const *gfp, |
| sample_t * mfbuf[2], sample_t const *in_buffer[2], int nsamples, int *n_in, int *n_out) |
| { |
| lame_internal_flags const *const gfc = gfp->internal_flags; |
| int ch, i; |
| |
| /* copy in new samples into mfbuf, with resampling if necessary */ |
| if ((gfc->resample_ratio < .9999) || (gfc->resample_ratio > 1.0001)) { |
| for (ch = 0; ch < gfc->channels_out; ch++) { |
| *n_out = |
| fill_buffer_resample(gfp, &mfbuf[ch][gfc->mf_size], |
| gfp->framesize, in_buffer[ch], nsamples, n_in, ch); |
| } |
| } |
| else { |
| *n_out = Min(gfp->framesize, nsamples); |
| *n_in = *n_out; |
| for (i = 0; i < *n_out; ++i) { |
| mfbuf[0][gfc->mf_size + i] = in_buffer[0][i]; |
| if (gfc->channels_out == 2) |
| mfbuf[1][gfc->mf_size + i] = in_buffer[1][i]; |
| } |
| } |
| } |
| |
| |
| |
| |
| int |
| fill_buffer_resample(lame_global_flags const *gfp, |
| sample_t * outbuf, |
| int desired_len, sample_t const *inbuf, int len, int *num_used, int ch) |
| { |
| |
| |
| lame_internal_flags *const gfc = gfp->internal_flags; |
| int BLACKSIZE; |
| FLOAT offset, xvalue; |
| int i, j = 0, k; |
| int filter_l; |
| FLOAT fcn, intratio; |
| FLOAT *inbuf_old; |
| int bpc; /* number of convolution functions to pre-compute */ |
| bpc = gfp->out_samplerate / gcd(gfp->out_samplerate, gfp->in_samplerate); |
| if (bpc > BPC) |
| bpc = BPC; |
| |
| intratio = (fabs(gfc->resample_ratio - floor(.5 + gfc->resample_ratio)) < .0001); |
| fcn = 1.00 / gfc->resample_ratio; |
| if (fcn > 1.00) |
| fcn = 1.00; |
| filter_l = 31; |
| if (0 == filter_l % 2) |
| --filter_l; /* must be odd */ |
| filter_l += intratio; /* unless resample_ratio=int, it must be even */ |
| |
| |
| BLACKSIZE = filter_l + 1; /* size of data needed for FIR */ |
| |
| if (gfc->fill_buffer_resample_init == 0) { |
| gfc->inbuf_old[0] = calloc(BLACKSIZE, sizeof(gfc->inbuf_old[0][0])); |
| gfc->inbuf_old[1] = calloc(BLACKSIZE, sizeof(gfc->inbuf_old[0][0])); |
| for (i = 0; i <= 2 * bpc; ++i) |
| gfc->blackfilt[i] = calloc(BLACKSIZE, sizeof(gfc->blackfilt[0][0])); |
| |
| gfc->itime[0] = 0; |
| gfc->itime[1] = 0; |
| |
| /* precompute blackman filter coefficients */ |
| for (j = 0; j <= 2 * bpc; j++) { |
| FLOAT sum = 0.; |
| offset = (j - bpc) / (2. * bpc); |
| for (i = 0; i <= filter_l; i++) |
| sum += gfc->blackfilt[j][i] = blackman(i - offset, fcn, filter_l); |
| for (i = 0; i <= filter_l; i++) |
| gfc->blackfilt[j][i] /= sum; |
| } |
| gfc->fill_buffer_resample_init = 1; |
| } |
| |
| inbuf_old = gfc->inbuf_old[ch]; |
| |
| /* time of j'th element in inbuf = itime + j/ifreq; */ |
| /* time of k'th element in outbuf = j/ofreq */ |
| for (k = 0; k < desired_len; k++) { |
| double time0; |
| int joff; |
| |
| time0 = k * gfc->resample_ratio; /* time of k'th output sample */ |
| j = floor(time0 - gfc->itime[ch]); |
| |
| /* check if we need more input data */ |
| if ((filter_l + j - filter_l / 2) >= len) |
| break; |
| |
| /* blackman filter. by default, window centered at j+.5(filter_l%2) */ |
| /* but we want a window centered at time0. */ |
| offset = (time0 - gfc->itime[ch] - (j + .5 * (filter_l % 2))); |
| assert(fabs(offset) <= .501); |
| |
| /* find the closest precomputed window for this offset: */ |
| joff = floor((offset * 2 * bpc) + bpc + .5); |
| |
| xvalue = 0.; |
| for (i = 0; i <= filter_l; ++i) { |
| int const j2 = i + j - filter_l / 2; |
| sample_t y; |
| assert(j2 < len); |
| assert(j2 + BLACKSIZE >= 0); |
| y = (j2 < 0) ? inbuf_old[BLACKSIZE + j2] : inbuf[j2]; |
| #ifdef PRECOMPUTE |
| xvalue += y * gfc->blackfilt[joff][i]; |
| #else |
| xvalue += y * blackman(i - offset, fcn, filter_l); /* very slow! */ |
| #endif |
| } |
| outbuf[k] = xvalue; |
| } |
| |
| |
| /* k = number of samples added to outbuf */ |
| /* last k sample used data from [j-filter_l/2,j+filter_l-filter_l/2] */ |
| |
| /* how many samples of input data were used: */ |
| *num_used = Min(len, filter_l + j - filter_l / 2); |
| |
| /* adjust our input time counter. Incriment by the number of samples used, |
| * then normalize so that next output sample is at time 0, next |
| * input buffer is at time itime[ch] */ |
| gfc->itime[ch] += *num_used - k * gfc->resample_ratio; |
| |
| /* save the last BLACKSIZE samples into the inbuf_old buffer */ |
| if (*num_used >= BLACKSIZE) { |
| for (i = 0; i < BLACKSIZE; i++) |
| inbuf_old[i] = inbuf[*num_used + i - BLACKSIZE]; |
| } |
| else { |
| /* shift in *num_used samples into inbuf_old */ |
| int const n_shift = BLACKSIZE - *num_used; /* number of samples to shift */ |
| |
| /* shift n_shift samples by *num_used, to make room for the |
| * num_used new samples */ |
| for (i = 0; i < n_shift; ++i) |
| inbuf_old[i] = inbuf_old[i + *num_used]; |
| |
| /* shift in the *num_used samples */ |
| for (j = 0; i < BLACKSIZE; ++i, ++j) |
| inbuf_old[i] = inbuf[j]; |
| |
| assert(j == *num_used); |
| } |
| return k; /* return the number samples created at the new samplerate */ |
| } |
| |
| |
| |
| |
| |
| /*********************************************************************** |
| * |
| * Message Output |
| * |
| ***********************************************************************/ |
| void |
| lame_debugf(const lame_internal_flags * gfc, const char *format, ...) |
| { |
| va_list args; |
| |
| va_start(args, format); |
| |
| if (gfc->report.debugf != NULL) { |
| gfc->report.debugf(format, args); |
| } |
| else { |
| (void) vfprintf(stderr, format, args); |
| fflush(stderr); /* an debug function should flush immediately */ |
| } |
| |
| va_end(args); |
| } |
| |
| |
| void |
| lame_msgf(const lame_internal_flags * gfc, const char *format, ...) |
| { |
| va_list args; |
| |
| va_start(args, format); |
| |
| if (gfc->report.msgf != NULL) { |
| gfc->report.msgf(format, args); |
| } |
| else { |
| (void) vfprintf(stderr, format, args); |
| fflush(stderr); /* we print to stderr, so me may want to flush */ |
| } |
| |
| va_end(args); |
| } |
| |
| |
| void |
| lame_errorf(const lame_internal_flags * gfc, const char *format, ...) |
| { |
| va_list args; |
| |
| va_start(args, format); |
| |
| if (gfc->report.errorf != NULL) { |
| gfc->report.errorf(format, args); |
| } |
| else { |
| (void) vfprintf(stderr, format, args); |
| fflush(stderr); /* an error function should flush immediately */ |
| } |
| |
| va_end(args); |
| } |
| |
| |
| |
| /*********************************************************************** |
| * |
| * routines to detect CPU specific features like 3DNow, MMX, SSE |
| * |
| * donated by Frank Klemm |
| * added Robert Hegemann 2000-10-10 |
| * |
| ***********************************************************************/ |
| |
| #ifdef HAVE_NASM |
| extern int has_MMX_nasm(void); |
| extern int has_3DNow_nasm(void); |
| extern int has_SSE_nasm(void); |
| extern int has_SSE2_nasm(void); |
| #endif |
| |
| int |
| has_MMX(void) |
| { |
| #ifdef HAVE_NASM |
| return has_MMX_nasm(); |
| #else |
| return 0; /* don't know, assume not */ |
| #endif |
| } |
| |
| int |
| has_3DNow(void) |
| { |
| #ifdef HAVE_NASM |
| return has_3DNow_nasm(); |
| #else |
| return 0; /* don't know, assume not */ |
| #endif |
| } |
| |
| int |
| has_SSE(void) |
| { |
| #ifdef HAVE_NASM |
| return has_SSE_nasm(); |
| #else |
| #ifdef _M_X64 |
| return 1; |
| #else |
| return 0; /* don't know, assume not */ |
| #endif |
| #endif |
| } |
| |
| int |
| has_SSE2(void) |
| { |
| #ifdef HAVE_NASM |
| return has_SSE2_nasm(); |
| #else |
| #ifdef _M_X64 |
| return 1; |
| #else |
| return 0; /* don't know, assume not */ |
| #endif |
| #endif |
| } |
| |
| void |
| disable_FPE(void) |
| { |
| /* extremly system dependent stuff, move to a lib to make the code readable */ |
| /*==========================================================================*/ |
| |
| |
| |
| /* |
| * Disable floating point exceptions |
| */ |
| |
| |
| |
| |
| #if defined(__FreeBSD__) && !defined(__alpha__) |
| { |
| /* seet floating point mask to the Linux default */ |
| fp_except_t mask; |
| mask = fpgetmask(); |
| /* if bit is set, we get SIGFPE on that error! */ |
| fpsetmask(mask & ~(FP_X_INV | FP_X_DZ)); |
| /* DEBUGF("FreeBSD mask is 0x%x\n",mask); */ |
| } |
| #endif |
| |
| #if defined(__riscos__) && !defined(ABORTFP) |
| /* Disable FPE's under RISC OS */ |
| /* if bit is set, we disable trapping that error! */ |
| /* _FPE_IVO : invalid operation */ |
| /* _FPE_DVZ : divide by zero */ |
| /* _FPE_OFL : overflow */ |
| /* _FPE_UFL : underflow */ |
| /* _FPE_INX : inexact */ |
| DisableFPETraps(_FPE_IVO | _FPE_DVZ | _FPE_OFL); |
| #endif |
| |
| /* |
| * Debugging stuff |
| * The default is to ignore FPE's, unless compiled with -DABORTFP |
| * so add code below to ENABLE FPE's. |
| */ |
| |
| #if defined(ABORTFP) |
| #if defined(_MSC_VER) |
| { |
| #if 0 |
| /* rh 061207 |
| the following fix seems to be a workaround for a problem in the |
| parent process calling LAME. It would be better to fix the broken |
| application => code disabled. |
| */ |
| |
| /* set affinity to a single CPU. Fix for EAC/lame on SMP systems from |
| "Todd Richmond" <todd.richmond@openwave.com> */ |
| SYSTEM_INFO si; |
| GetSystemInfo(&si); |
| SetProcessAffinityMask(GetCurrentProcess(), si.dwActiveProcessorMask); |
| #endif |
| #include <float.h> |
| unsigned int mask; |
| mask = _controlfp(0, 0); |
| mask &= ~(_EM_OVERFLOW | _EM_UNDERFLOW | _EM_ZERODIVIDE | _EM_INVALID); |
| mask = _controlfp(mask, _MCW_EM); |
| } |
| #elif defined(__CYGWIN__) |
| # define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) |
| # define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) |
| |
| # define _EM_INEXACT 0x00000020 /* inexact (precision) */ |
| # define _EM_UNDERFLOW 0x00000010 /* underflow */ |
| # define _EM_OVERFLOW 0x00000008 /* overflow */ |
| # define _EM_ZERODIVIDE 0x00000004 /* zero divide */ |
| # define _EM_INVALID 0x00000001 /* invalid */ |
| { |
| unsigned int mask; |
| _FPU_GETCW(mask); |
| /* Set the FPU control word to abort on most FPEs */ |
| mask &= ~(_EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID); |
| _FPU_SETCW(mask); |
| } |
| # elif defined(__linux__) |
| { |
| |
| # include <fpu_control.h> |
| # ifndef _FPU_GETCW |
| # define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) |
| # endif |
| # ifndef _FPU_SETCW |
| # define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) |
| # endif |
| |
| /* |
| * Set the Linux mask to abort on most FPE's |
| * if bit is set, we _mask_ SIGFPE on that error! |
| * mask &= ~( _FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM ); |
| */ |
| |
| unsigned int mask; |
| _FPU_GETCW(mask); |
| mask &= ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM); |
| _FPU_SETCW(mask); |
| } |
| #endif |
| #endif /* ABORTFP */ |
| } |
| |
| |
| |
| |
| |
| #ifdef USE_FAST_LOG |
| /*********************************************************************** |
| * |
| * Fast Log Approximation for log2, used to approximate every other log |
| * (log10 and log) |
| * maximum absolute error for log10 is around 10-6 |
| * maximum *relative* error can be high when x is almost 1 because error/log10(x) tends toward x/e |
| * |
| * use it if typical RESULT values are > 1e-5 (for example if x>1.00001 or x<0.99999) |
| * or if the relative precision in the domain around 1 is not important (result in 1 is exact and 0) |
| * |
| ***********************************************************************/ |
| |
| |
| #define LOG2_SIZE (512) |
| #define LOG2_SIZE_L2 (9) |
| |
| static ieee754_float32_t log_table[LOG2_SIZE + 1]; |
| |
| |
| |
| void |
| init_log_table(void) |
| { |
| int j; |
| static int init = 0; |
| |
| /* Range for log2(x) over [1,2[ is [0,1[ */ |
| assert((1 << LOG2_SIZE_L2) == LOG2_SIZE); |
| |
| if (!init) { |
| for (j = 0; j < LOG2_SIZE + 1; j++) |
| log_table[j] = log(1.0f + j / (ieee754_float32_t) LOG2_SIZE) / log(2.0f); |
| } |
| init = 1; |
| } |
| |
| |
| |
| ieee754_float32_t |
| fast_log2(ieee754_float32_t x) |
| { |
| ieee754_float32_t log2val, partial; |
| union { |
| ieee754_float32_t f; |
| int i; |
| } fi; |
| int mantisse; |
| fi.f = x; |
| mantisse = fi.i & 0x7fffff; |
| log2val = ((fi.i >> 23) & 0xFF) - 0x7f; |
| partial = (mantisse & ((1 << (23 - LOG2_SIZE_L2)) - 1)); |
| partial *= 1.0f / ((1 << (23 - LOG2_SIZE_L2))); |
| |
| |
| mantisse >>= (23 - LOG2_SIZE_L2); |
| |
| /* log2val += log_table[mantisse]; without interpolation the results are not good */ |
| log2val += log_table[mantisse] * (1.0f - partial) + log_table[mantisse + 1] * partial; |
| |
| return log2val; |
| } |
| |
| #else /* Don't use FAST_LOG */ |
| |
| |
| void |
| init_log_table(void) |
| { |
| } |
| |
| |
| #endif |
| |
| /* end of util.c */ |