1 /*-
2  * Copyright (c) 2005 Boris Mikhaylov
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 /* libsndfile is copyright by Erik de Castro Lopo.
29  * http://www.mega-nerd.com/libsndfile/
30  */
31 #include <sndfile.h>
32 
33 #include "bs2b.h"
34 
35 #define	 BUFFER_LEN	1024 /* must be multiply of 2 */
36 
37 static void copy_metadata( SNDFILE *outfile, SNDFILE *infile );
38 static void copy_data( SNDFILE *outfile, SNDFILE *infile, t_bs2bdp bs2bdp );
39 
print_usage(char * progname)40 static void print_usage( char *progname )
41 {
42 	printf( "\n"
43 		"Bauer stereophonic-to-binaural DSP converter. Version %s\n\n",
44 		BS2B_VERSION_STR );
45 	printf(
46 		"Usage : %s [-l L|(L1 L2)] <input file> <output file>\n",
47 		progname );
48 	printf(
49 		"-h - this help.\n"
50 		"-l - crossfeed level, L = d|c|m:\n"
51 		"     d - default preset     - 700Hz/260us, 4.5 dB;\n"
52 		"     c - Chu Moy's preset   - 700Hz/260us, 6.0 dB;\n"
53 		"     m - Jan Meier's preset - 650Hz/280us, 9.5 dB.\n"
54 		"     Or L1 = [%d..%d] mB of feed level (%d..%d dB)\n"
55 		"     and L2 = [%d..%d] Hz of cut frequency.\n",
56 		BS2B_MINFEED, BS2B_MAXFEED, BS2B_MINFEED / 10, BS2B_MAXFEED / 10,
57 		BS2B_MINFCUT, BS2B_MAXFCUT );
58 } /* print_usage() */
59 
main(int argc,char * argv[])60 int main( int argc, char *argv[] )
61 {
62 	char     *progname, *infilename, *outfilename, *tmpstr;
63 	SNDFILE  *infile, *outfile;
64 	SF_INFO  sfinfo;
65 	t_bs2bdp bs2bdp;
66 	uint32_t srate = BS2B_DEFAULT_SRATE;
67 	uint32_t level = BS2B_DEFAULT_CLEVEL;
68 	int i;
69 
70 	tmpstr = strrchr( argv[ 0 ], '/' );
71 	tmpstr = tmpstr ? tmpstr + 1 : argv[ 0 ];
72 	progname = strrchr( tmpstr, '\\' );
73 	progname = progname ? progname + 1 : tmpstr;
74 
75 	if( argc >= 3 )
76 	{
77 		outfilename = argv[ --argc ];
78 		infilename  = argv[ --argc ];
79 	}
80 	else
81 	{
82 		print_usage( progname );
83 		return 1;
84 	}
85 
86 	for( i = 1; i < argc; i++ )
87 	{
88 		if( '-' == argv[ i ][ 0 ] )
89 		{
90 			switch( argv[ i ][ 1 ] )
91 			{
92 			case 'h':
93 				print_usage( progname );
94 				return 1;
95 
96 			case 'l':
97 				if( ++i >= argc )
98 				{
99 					print_usage( progname );
100 					return 1;
101 				}
102 				switch( argv[ i ][ 0 ] )
103 				{
104 				case 'd':
105 					level = BS2B_DEFAULT_CLEVEL;
106 					break;
107 				case 'c':
108 					level = BS2B_CMOY_CLEVEL;
109 					break;
110 				case 'm':
111 					level = BS2B_JMEIER_CLEVEL;
112 					break;
113 				default:
114 					{
115 						int feed, fcut;
116 
117 						feed = atoi( argv[ i ] );
118 						if( ++i >= argc )
119 						{
120 							print_usage( progname );
121 							return 1;
122 						}
123 						fcut = atoi( argv[ i ] );
124 						if( feed < BS2B_MINFEED || feed > BS2B_MAXFEED ||
125 							fcut < BS2B_MINFCUT || fcut > BS2B_MAXFCUT )
126 						{
127 							print_usage( progname );
128 							return 1;
129 						}
130 						level = ( ( uint32_t )feed << 16 ) | ( uint32_t )fcut;
131 					}
132 				} /* switch */
133 				break;
134 
135 			default:
136 				print_usage( progname );
137 				return 1;
138 			} /* swith */
139 		}
140 		else
141 		{
142 			print_usage( progname );
143 			return 1;
144 		}
145 	} /* for */
146 
147 	if( strcmp( infilename, outfilename ) == 0 )
148 	{
149 		printf( "Error : Input and output filenames are the same.\n\n" );
150 		return 1;
151 	}
152 
153 	if( ( infile = sf_open( infilename, SFM_READ, &sfinfo ) ) == NULL )
154 	{
155 		printf( "Not able to open input file %s.\n", infilename );
156 		printf( sf_strerror( NULL ) );
157 		return 1;
158 	}
159 
160 	if( sfinfo.channels != 2 )
161 	{
162 		printf( "Input file is not a stereo.\n" );
163 		sf_close( infile );
164 		return 1;
165 	}
166 
167 	srate = sfinfo.samplerate;
168 
169 	if( srate < BS2B_MINSRATE || srate > BS2B_MAXSRATE )
170 	{
171 		printf( "Not supported sample rate '%d'.\n", srate );
172 		sf_close( infile );
173 		return 1;
174 	}
175 
176 	/* Open the output file. */
177 	if( ( outfile = sf_open( outfilename, SFM_WRITE, &sfinfo ) ) == NULL )
178 	{
179 		printf( "Not able to open output file %s : %s\n",
180 			outfilename, sf_strerror( NULL ) );
181 		sf_close( infile );
182 		return 1;
183 	}
184 
185 	if( NULL == ( bs2bdp = bs2b_open() ) )
186 	{
187 		printf( "Not able to allocate data\n" );
188 		sf_close( infile );
189 		sf_close( outfile );
190 		return 1;
191 	}
192 
193 	bs2b_set_srate( bs2bdp, srate );
194 	bs2b_set_level( bs2bdp, level );
195 
196 	printf( "Crossfeed level: %.1f dB, %d Hz, %d us.\n",
197 		( double )bs2b_get_level_feed( bs2bdp ) / 10.0,
198 		bs2b_get_level_fcut( bs2bdp ), bs2b_get_level_delay( bs2bdp ) );
199 	printf( "Converting file '%s' to file '%s'\nsample rate = %u...",
200 		infilename, outfilename, bs2b_get_srate( bs2bdp ) );
201 
202 	copy_metadata( outfile, infile );
203 
204 	copy_data( outfile, infile, bs2bdp );
205 
206 	bs2b_close( bs2bdp );
207 	bs2bdp = 0;
208 
209 	sf_close( infile );
210 	sf_close( outfile );
211 
212 	printf( " Done.\n" );
213 
214 	return 0;
215 } /* main() */
216 
copy_metadata(SNDFILE * outfile,SNDFILE * infile)217 static void copy_metadata( SNDFILE *outfile, SNDFILE *infile )
218 {
219 	const char *str;
220 	int k, err = 0;
221 
222 	for( k = SF_STR_FIRST; k <= SF_STR_LAST; k++ )
223 	{
224 		str = sf_get_string( infile, k );
225 		if( str != NULL )
226 			err = sf_set_string( outfile, k, str );
227 	}
228 
229 	err = sf_set_string( outfile, SF_STR_COMMENT, "CROSSFEEDED" );
230 } /* copy_metadata() */
231 
copy_data(SNDFILE * outfile,SNDFILE * infile,t_bs2bdp bs2bdp)232 static void copy_data( SNDFILE *outfile, SNDFILE *infile, t_bs2bdp bs2bdp )
233 {
234 	static double data[ BUFFER_LEN ];
235 	int readcount;
236 
237 	for( ;; )
238 	{
239 		readcount = ( int )sf_read_double( infile, data, BUFFER_LEN );
240 		if( readcount < 2 ) break;
241 		bs2b_cross_feed_d( bs2bdp, data, readcount / 2 );
242 		sf_write_double( outfile, data, readcount );
243 	}
244 } /* copy_data() */
245