On Thu, Oct 30, 2014 at 11:33:51PM +0530, Senjuti Kundu wrote: > Implemented an SNR for audio files which takes into a account the > psychoacoustic masking. This results in an SNR which is closer to how humans > percieve sound, compared to tiny_psnr which directly compares audio signals > > Signed-off-by: Senjuti Kundu <[email protected]> > --- > tests/psy_snr.c | 421 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 421 insertions(+) > create mode 100644 tests/psy_snr.c > > diff --git a/tests/psy_snr.c b/tests/psy_snr.c > new file mode 100644 > index 0000000..94041ed > --- /dev/null > +++ b/tests/psy_snr.c > @@ -0,0 +1,421 @@ > +/* > + * Copyright (c) 2003 Michael Niedermayer <[email protected]> > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg 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.1 of the License, or (at your option) any later version. > + * > + * FFmpeg 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 > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +/* > + * Psy-SNR - Psychoacoustic SNR for audio files. > + * Author - Senjuti Kundu <[email protected]> > + * Input format - tiny_psysnr <file1> <file2> > + * [<elem size>|u8|s16|f32|f64 [<shift> [<skip bytes> [<shift > search range>]]]] > + * WAV headers are skipped automatically. > + * SIZE can be changed to adjust window size as need be. > + * compile using gcc psysnr.c $(pkg-config --cflags --libs libavformat > libavcodec) > + * -I /usr/local/include/libavcodec/ > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <inttypes.h> > +#include <math.h> > +#include <float.h> > +#include <limits.h> > + > +#include "libavutil/intfloat.h" > +#include "libavutil/intreadwrite.h" > +#include "libavcodec/avfft.h" > +#include "libavutil/mem.h" > + > +#define FFMIN(a, b) ((a) > (b) ? (b) : (a)) > +#define FFMAX(a, b) ((a) > (b) ? (a) : (b)) > +#define F 100 > +//size should be close to 20k > +#define SIZE 1024
> +#define db_fw_rollof 4
> +#define db_bw_rollof 4
> +#define db_attenuation 0.1
#defines
should be all uppercase
> +
> +uint64_t exp16_table[21] = {
> + 65537,
> + 65538,
> + 65540,
> + 65544,
> + 65552,
> + 65568,
> + 65600,
> + 65664,
> + 65793,
> + 66050,
> + 66568,
> + 67616,
> + 69763,
> + 74262,
> + 84150,
> + 108051,
> + 178145,
> + 484249,
> + 3578144,
> + 195360063,
> + 582360139072LL,
> +};
> +
> +#if 0
> +// 16.16 fixpoint exp()
> +static unsigned int exp16(unsigned int a){
> + int i;
> + int out= 1<<16;
> +
> + for(i=19;i>=0;i--){
> + if(a&(1<<i))
> + out= (out*exp16_table[i] + (1<<15))>>16;
> + }
> +
> + return out;
> +}
> +#endif
> +
> +// 16.16 fixpoint log()
> +static int64_t log16(uint64_t a)
> +{
> + int i;
> + int out = 0;
> +
> + if (a < 1 << 16)
> + return -log16((1LL << 32) / a);
> + a <<= 16;
> +
> + for (i = 20; i >= 0; i--) {
> + int64_t b = exp16_table[i];
> + if (a < (b << 16))
> + continue;
> + out |= 1 << i;
> + a = ((a / b) << 16) + (((a % b) << 16) + b / 2) / b;
> + }
> + return out;
> +}
> +
> +static uint64_t int_sqrt(uint64_t a)
> +{
> + uint64_t ret = 0;
> + uint64_t ret_sq = 0;
> + int s;
> +
> + for (s = 31; s >= 0; s--) {
> + uint64_t b = ret_sq + (1ULL << (s * 2)) + (ret << s) * 2;
> + if (b <= a) {
> + ret_sq = b;
> + ret += 1ULL << s;
> + }
> + }
> + return ret;
> +}
> +
these functions look duplicated from tiny_psnr, it would be better
to share them
> +static int16_t get_s16l(uint8_t *p)
> +{
> + union {
> + uint16_t u;
> + int16_t s;
> + } v;
> + v.u = p[0] | p[1] << 8;
> + return v.s;
> +}
> +
> +static float get_f32l(uint8_t *p)
> +{
> + union av_intfloat32 v;
> + v.i = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
> + return v.f;
> +}
> +
> +static double get_f64l(uint8_t *p)
> +{
> + return av_int2double(AV_RL64(p));
> +}
> +
> +static float* get_mask_array(int tempsize){
> + //modelling the mask function as a parabole. Others can be
> + //explored as need be. y=(-(x-mid)2+c)/c
> + int i = 0;
> + float* maskingfunc = malloc(tempsize*sizeof(float));
> + maskingfunc[tempsize/2] = exp(-db_attenuation*log(10));
> + for (i = (tempsize/2)+1; i<tempsize; i++){
> + maskingfunc[i] =
> maskingfunc[i-1]*exp(-(db_fw_rollof*log(10))/(20*(i-(tempsize/2))));;
double ;
> + }
> + for(i = (tempsize/2)-1; i >= 0; i--){
> + maskingfunc[i] =
> maskingfunc[i+1]*exp(-(2*db_bw_rollof*log(10))/(20*((tempsize/2)-i)));
this can be simplified
> + }
> + return maskingfunc;
> +}
> +
> +static float* get_mask(FFTComplex* a, int tempsize, float* maskingfunc){
> + int i = 0;
> + int j = 0;
> + float* mask = malloc(tempsize*sizeof(float));
> + float self = 0;
> + float next = 0;
> + float prev = 0;
missing malloc failure check
> +
> + for (i = 1; i<tempsize; i++){
> + self =
> maskingfunc[tempsize/2]*sqrt((a[i].re*a[i].re)+(a[i].im*a[i].im));
> + prev =
> maskingfunc[(tempsize/2)-1]*sqrt((a[i-1].re*a[i-1].re)+(a[i-1].im*a[i-1].im));
the "abs"() can be factored out
[...]
> + FFTContext* fftcontexta = av_fft_init(floor(log2(SIZE/len)),0);
mixing declarations ans statements causes problems with some compilers
also see av_log2() this doesnt need floats to caluclate the argument
also, has psy_snr been compared to some known to be correct/reference
implementation or been tested in some way ?
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Democracy is the form of government in which you can choose your dictator
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list [email protected] http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
