521 lines · 12.9 KB · C
RawDownload
/*** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>** All rights reserved.**** This code is released under 2-clause BSD license. Please see the** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING*/ #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h> #include "src_config.h" #if (HAVE_FFTW3 && HAVE_SNDFILE && HAVE_SYS_TIMES_H) #include <time.h>#include <sys/times.h> #include <sndfile.h>#include <math.h>#include <sys/utsname.h> #include "util.h" #define	MAX_FREQS		4#define	BUFFER_LEN		80000 #define SAFE_STRNCAT(dest,src,len)								\		{	int safe_strncat_count ;							\			safe_strncat_count = (len) - strlen (dest) - 1 ;	\			strncat ((dest), (src), safe_strncat_count) ;		\			(dest) [(len) - 1] = 0 ;							\			} ; typedef struct{	int		freq_count ;	double	freqs [MAX_FREQS] ; 	int		output_samplerate ;	int		pass_band_peaks ; 	double	peak_value ;} SNR_TEST ; typedef struct{	const char	*progname ;	const char	*version_cmd ;	const char	*version_start ;	const char	*convert_cmd ;	int			format ;} RESAMPLE_PROG ; static char *get_progname (char *) ;static void usage_exit (const char *, const RESAMPLE_PROG *prog, int count) ;static void measure_program (const RESAMPLE_PROG *prog, int verbose) ;static void generate_source_wav (const char *filename, const double *freqs, int freq_count, int format) ;static const char* get_machine_details (void) ; static char	version_string [512] ; intmain (int argc, char *argv []){	static RESAMPLE_PROG resample_progs [] =	{	{	"sndfile-resample",			"examples/sndfile-resample --version",			"libsamplerate",			"examples/sndfile-resample --max-speed -c 0 -to %d source.wav destination.wav",			SF_FORMAT_WAV | SF_FORMAT_PCM_32			},		{	"sox",			"sox -h 2>&1",			"sox",			"sox source.wav -r %d destination.wav resample 0.835",			SF_FORMAT_WAV | SF_FORMAT_PCM_32			},		{	"ResampAudio",			"ResampAudio --version",			"ResampAudio",			"ResampAudio -f cutoff=0.41,atten=100,ratio=128 -s %d source.wav destination.wav",			SF_FORMAT_WAV | SF_FORMAT_PCM_32			}, 		/*-		{	/+*			** The Shibatch converter doesn't work for all combinations of			** source and destination sample rates. Therefore it can't be			** included in this test.			*+/			"shibatch",			"ssrc",			"Shibatch",			"ssrc --rate %d source.wav destination.wav",			SF_FORMAT_WAV | SF_FORMAT_PCM_32			},-*/ 		/*-		{	/+*			** The resample program is not able to match the bandwidth and SNR			** specs or sndfile-resample and hence will not be tested.			*+/			"resample",			"resample -version",			"resample",			"resample -to %d source.wav destination.wav",			SF_FORMAT_WAV | SF_FORMAT_FLOAT			},-*/ 		/*-		{	"mplayer",			"mplayer -v 2>&1",			"MPlayer ",			"mplayer -ao pcm -srate %d source.wav >/dev/null 2>&1 && mv audiodump.wav destination.wav",			SF_FORMAT_WAV | SF_FORMAT_PCM_32			},-*/ 		} ; /* resample_progs */ 	char	*progname ;	int 	prog = 0, verbose = 0 ; 	progname = get_progname (argv [0]) ; 	printf ("\n  %s : evaluate a sample rate converter.\n", progname) ; 	if (argc == 3 && strcmp ("--verbose", argv [1]) == 0)	{	verbose = 1 ;		prog = atoi (argv [2]) ;		}	else if (argc == 2)	{	verbose = 0 ;		prog = atoi (argv [1]) ;		}	else		usage_exit (progname, resample_progs, ARRAY_LEN (resample_progs)) ; 	if (prog < 0 || prog >= ARRAY_LEN (resample_progs))		usage_exit (progname, resample_progs, ARRAY_LEN (resample_progs)) ; 	measure_program (& (resample_progs [prog]), verbose) ; 	puts ("") ; 	return 0 ;} /* main */ /*==============================================================================*/ static char *get_progname (char *progname){	char *cptr ; 	if ((cptr = strrchr (progname, '/')) != NULL)		progname = cptr + 1 ; 	if ((cptr = strrchr (progname, '\\')) != NULL)		progname = cptr + 1 ; 	return progname ;} /* get_progname */ static voidusage_exit (const char *progname, const RESAMPLE_PROG *prog, int count){	int k ; 	printf ("\n  Usage : %s <number>\n\n", progname) ; 	puts ("  where <number> specifies the program to test:\n") ; 	for (k = 0 ; k < count ; k++)		printf ("    %d : %s\n", k, prog [k].progname) ; 	puts ("\n"		" Obviously to test a given program you have to have it available on\n"		" your system. See http://libsndfile.github.io/libsamplerate/quality.html for\n"		" the download location of these programs.\n") ; 	exit (1) ;} /* usage_exit */ static const char*get_machine_details (void){	static char namestr [262] ; 	struct utsname name ; 	if (uname (&name) != 0)	{	snprintf (namestr, sizeof (namestr), "Unknown") ;		return namestr ;		} ; 	snprintf (namestr, sizeof (namestr), "%s (%s %s %s)", name.nodename,			name.machine, name.sysname, name.release) ; 	return namestr ;} /* get_machine_details */  /*==============================================================================*/ static voidget_version_string (const RESAMPLE_PROG *prog){	FILE *file ;	char *cptr ; 	/* Default. */	snprintf (version_string, sizeof (version_string), "no version") ; 	if (prog->version_cmd == NULL)		return ; 	if ((file = popen (prog->version_cmd, "r")) == NULL)		return ; 	while ((cptr = fgets (version_string, sizeof (version_string), file)) != NULL)	{		if (strstr (cptr, prog->version_start) != NULL)			break ; 		version_string [0] = 0 ;		} ; 	pclose (file) ; 	/* Remove trailing newline. */	if ((cptr = strchr (version_string, '\n')) != NULL)		cptr [0] = 0 ; 	/* Remove leading whitespace from version string. */	cptr = version_string ;	while (cptr [0] != 0 && isspace (cptr [0]))		cptr ++ ; 	if (cptr != version_string)	{	strncpy (version_string, cptr, sizeof (version_string) - 1) ;		version_string [sizeof (version_string) - 1] = 0 ;		} ; 	return ;} /* get_version_string */ static voidgenerate_source_wav (const char *filename, const double *freqs, int freq_count, int format){	static float buffer [BUFFER_LEN] ; 	SNDFILE *sndfile ;	SF_INFO sfinfo ; 	sfinfo.channels = 1 ;	sfinfo.samplerate = 44100 ;	sfinfo.format = format ; 	if ((sndfile = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)	{	printf ("Line %d : cound not open '%s' : %s\n", __LINE__, filename, sf_strerror (NULL)) ;		exit (1) ;		} ; 	sf_command (sndfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; 	gen_windowed_sines (freq_count, freqs, 0.9, buffer, ARRAY_LEN (buffer)) ; 	if (sf_write_float (sndfile, buffer, ARRAY_LEN (buffer)) != ARRAY_LEN (buffer))	{	printf ("Line %d : sf_write_float short write.\n", __LINE__) ;		exit (1) ;		} ; 	sf_close (sndfile) ;} /* generate_source_wav */ static doublemeasure_destination_wav (char *filename, int *output_samples, int expected_peaks){	static float buffer [250000] ; 	SNDFILE *sndfile ;	SF_INFO sfinfo ;	double snr ; 	if ((sndfile = sf_open (filename, SFM_READ, &sfinfo)) == NULL)	{	printf ("Line %d : Cound not open '%s' : %s\n", __LINE__, filename, sf_strerror (NULL)) ;		exit (1) ;		} ; 	if (sfinfo.channels != 1)	{	printf ("Line %d : Bad channel count (%d). Should be 1.\n", __LINE__, sfinfo.channels) ;		exit (1) ;		} ; 	if (sfinfo.frames > ARRAY_LEN (buffer))	{	printf ("Line %d : Too many frames (%ld) of data in file.\n", __LINE__, (long) sfinfo.frames) ;		exit (1) ;		} ; 	*output_samples = (int) sfinfo.frames ; 	if (sf_read_float (sndfile, buffer, sfinfo.frames) != sfinfo.frames)	{	printf ("Line %d : Bad read.\n", __LINE__) ;		exit (1) ;		} ; 	sf_close (sndfile) ; 	snr = calculate_snr (buffer, sfinfo.frames, expected_peaks) ; 	return snr ;} /* measure_desination_wav */ static doublemeasure_snr (const RESAMPLE_PROG *prog, int *output_samples, int verbose){	static SNR_TEST snr_test [] =	{		{	1,	{ 0.211111111111 },		48000,		1,	1.0 },		{	1,	{ 0.011111111111 },		132301,		1,	1.0 },		{	1,	{ 0.111111111111 },		92301,		1,	1.0 },		{	1,	{ 0.011111111111 },		26461,		1,	1.0 },		{	1,	{ 0.011111111111 },		13231,		1,	1.0 },		{	1,	{ 0.011111111111 },		44101,		1,	1.0 },		{	2,	{ 0.311111, 0.49 },		78199,		2,	1.0 },		{	2,	{ 0.011111, 0.49 },		12345,		1,	0.5 },		{	2,	{ 0.0123456, 0.4 },		20143,		1,	0.5 },		{	2,	{ 0.0111111, 0.4 },		26461,		1,	0.5 },		{	1,	{ 0.381111111111 },		58661,		1,	1.0 }		} ; /* snr_test */	static char command [256] ; 	double snr, worst_snr = 500.0 ;	int k , retval, sample_count ; 	*output_samples = 0 ; 	for (k = 0 ; k < ARRAY_LEN (snr_test) ; k++)	{	remove ("source.wav") ;		remove ("destination.wav") ; 		if (verbose)			printf ("       SNR test #%d : ", k) ;		fflush (stdout) ;		generate_source_wav ("source.wav", snr_test [k].freqs, snr_test [k].freq_count, prog->format) ; 		snprintf (command, sizeof (command), prog->convert_cmd, snr_test [k].output_samplerate) ;		SAFE_STRNCAT (command, " >/dev/null 2>&1", sizeof (command)) ;		if ((retval = system (command)) != 0)			printf ("system returned %d\n", retval) ; 		snr = measure_destination_wav ("destination.wav", &sample_count, snr_test->pass_band_peaks) ; 		*output_samples += sample_count ; 		if (fabs (snr) < fabs (worst_snr))			worst_snr = fabs (snr) ; 		if (verbose)			printf ("%6.2f dB\n", snr) ;		} ; 	return worst_snr ;} /* measure_snr */ /*------------------------------------------------------------------------------*/ static doublemeasure_destination_peak (const char *filename){	static float data [2 * BUFFER_LEN] ;	SNDFILE		*sndfile ;	SF_INFO		sfinfo ;	double		peak = 0.0 ;	int			k = 0 ; 	if ((sndfile = sf_open (filename, SFM_READ, &sfinfo)) == NULL)	{	printf ("Line %d : failed to open file %s\n", __LINE__, filename) ;		exit (1) ;		} ; 	if (sfinfo.channels != 1)	{	printf ("Line %d : bad channel count.\n", __LINE__) ;		exit (1) ;		} ; 	if (sfinfo.frames > ARRAY_LEN (data) + 4 || sfinfo.frames < ARRAY_LEN (data) - 100)	{	printf ("Line %d : bad frame count (got %d, expected %d).\n", __LINE__, (int) sfinfo.frames, ARRAY_LEN (data)) ;		exit (1) ;		} ; 	if (sf_read_float (sndfile, data, sfinfo.frames) != sfinfo.frames)	{	printf ("Line %d : bad read.\n", __LINE__) ;		exit (1) ;		} ; 	sf_close (sndfile) ; 	for (k = 0 ; k < (int) sfinfo.frames ; k++)		if (fabs (data [k]) > peak)			peak = fabs (data [k]) ; 	return peak ;} /* measure_destination_peak */ static doublefind_attenuation (double freq, const RESAMPLE_PROG *prog, int verbose){	static char	command [256] ;	double	output_peak ;	int		retval ;	char	*filename ; 	filename = "destination.wav" ; 	generate_source_wav ("source.wav", &freq, 1, prog->format) ; 	remove (filename) ; 	snprintf (command, sizeof (command), prog->convert_cmd, 88189) ;	SAFE_STRNCAT (command, " >/dev/null 2>&1", sizeof (command)) ;	if ((retval = system (command)) != 0)		printf ("system returned %d\n", retval) ; 	output_peak = measure_destination_peak (filename) ; 	if (verbose)		printf ("        freq : %f     peak : %f\n", freq, output_peak) ; 	return fabs (20.0 * log10 (output_peak)) ;} /* find_attenuation */ static doublebandwidth_test (const RESAMPLE_PROG *prog, int verbose){	double	f1, f2, a1, a2 ;	double	freq, atten ; 	f1 = 0.35 ;	a1 = find_attenuation (f1, prog, verbose) ; 	f2 = 0.49999 ;	a2 = find_attenuation (f2, prog, verbose) ;  	if (fabs (a1) < 1e-2 && a2 < 3.0)		return -1.0 ; 	if (a1 > 3.0 || a2 < 3.0)	{	printf ("\n\nLine %d : cannot bracket 3dB point.\n\n", __LINE__) ;		exit (1) ;		} ; 	while (a2 - a1 > 1.0)	{	freq = f1 + 0.5 * (f2 - f1) ;		atten = find_attenuation (freq, prog, verbose) ; 		if (atten < 3.0)		{	f1 = freq ;			a1 = atten ;			}		else		{	f2 = freq ;			a2 = atten ;			} ;		} ; 	freq = f1 + (3.0 - a1) * (f2 - f1) / (a2 - a1) ; 	return 200.0 * freq ;} /* bandwidth_test */ static voidmeasure_program (const RESAMPLE_PROG *prog, int verbose){	double	snr, bandwidth, conversion_rate ;	int		output_samples ;	struct	tms	time_data ;	time_t	time_now ; 	printf ("\n  Machine : %s\n", get_machine_details ()) ;	time_now = time (NULL) ;	printf ("  Date    : %s", ctime (&time_now)) ; 	get_version_string (prog) ;	printf ("  Program : %s\n", version_string) ;	printf ("  Command : %s\n\n", prog->convert_cmd) ; 	snr = measure_snr (prog, &output_samples, verbose) ; 	printf ("  Worst case SNR     : %6.2f dB\n", snr) ; 	times (&time_data) ; 	conversion_rate = (1.0 * output_samples * sysconf (_SC_CLK_TCK)) / time_data.tms_cutime ; 	printf ("  Conversion rate    : %5.0f samples/sec\n", conversion_rate) ; 	bandwidth = bandwidth_test (prog, verbose) ; 	if (bandwidth > 0.0)		printf ("  Measured bandwidth : %5.2f %%\n", bandwidth) ;	else		printf ("  Could not measure bandwidth (no -3dB point found).\n") ; 	return ;} /* measure_program */

Lines 1–500 of 521.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t