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