Chris@41
|
1 /*
|
Chris@41
|
2 ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
|
Chris@41
|
3 ** All rights reserved.
|
Chris@41
|
4 **
|
Chris@41
|
5 ** This code is released under 2-clause BSD license. Please see the
|
Chris@41
|
6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
|
Chris@41
|
7 */
|
Chris@41
|
8
|
Chris@41
|
9 #include "config.h"
|
Chris@41
|
10
|
Chris@41
|
11 #include <stdio.h>
|
Chris@41
|
12 #include <stdlib.h>
|
Chris@41
|
13 #include <string.h>
|
Chris@41
|
14 #include <math.h>
|
Chris@41
|
15 #include <time.h>
|
Chris@41
|
16
|
Chris@41
|
17 #if (HAVE_FFTW3)
|
Chris@41
|
18
|
Chris@41
|
19 #include <fftw3.h>
|
Chris@41
|
20
|
Chris@41
|
21 #include <samplerate.h>
|
Chris@41
|
22
|
Chris@41
|
23 #include "util.h"
|
Chris@41
|
24
|
Chris@41
|
25 #define BUFFER_LEN 50000
|
Chris@41
|
26 #define MAX_FREQS 4
|
Chris@41
|
27 #define MAX_RATIOS 6
|
Chris@41
|
28 #define MAX_SPEC_LEN (1<<15)
|
Chris@41
|
29
|
Chris@41
|
30 #ifndef M_PI
|
Chris@41
|
31 #define M_PI 3.14159265358979323846264338
|
Chris@41
|
32 #endif
|
Chris@41
|
33
|
Chris@41
|
34 enum
|
Chris@41
|
35 { BOOLEAN_FALSE = 0,
|
Chris@41
|
36 BOOLEAN_TRUE = 1
|
Chris@41
|
37 } ;
|
Chris@41
|
38
|
Chris@41
|
39 typedef struct
|
Chris@41
|
40 { int freq_count ;
|
Chris@41
|
41 double freqs [MAX_FREQS] ;
|
Chris@41
|
42
|
Chris@41
|
43 double src_ratio ;
|
Chris@41
|
44 int pass_band_peaks ;
|
Chris@41
|
45
|
Chris@41
|
46 double snr ;
|
Chris@41
|
47 double peak_value ;
|
Chris@41
|
48 } SINGLE_TEST ;
|
Chris@41
|
49
|
Chris@41
|
50 typedef struct
|
Chris@41
|
51 { int converter ;
|
Chris@41
|
52 int tests ;
|
Chris@41
|
53 int do_bandwidth_test ;
|
Chris@41
|
54 SINGLE_TEST test_data [10] ;
|
Chris@41
|
55 } CONVERTER_TEST ;
|
Chris@41
|
56
|
Chris@41
|
57 static double snr_test (SINGLE_TEST *snr_test_data, int number, int converter, int verbose) ;
|
Chris@41
|
58 static double find_peak (float *output, int output_len) ;
|
Chris@41
|
59 static double bandwidth_test (int converter, int verbose) ;
|
Chris@41
|
60
|
Chris@41
|
61 int
|
Chris@41
|
62 main (int argc, char *argv [])
|
Chris@41
|
63 { CONVERTER_TEST snr_test_data [] =
|
Chris@41
|
64 {
|
Chris@41
|
65 { SRC_ZERO_ORDER_HOLD,
|
Chris@41
|
66 8,
|
Chris@41
|
67 BOOLEAN_FALSE,
|
Chris@41
|
68 { { 1, { 0.01111111111 }, 3.0, 1, 28.0, 1.0 },
|
Chris@41
|
69 { 1, { 0.01111111111 }, 0.6, 1, 36.0, 1.0 },
|
Chris@41
|
70 { 1, { 0.01111111111 }, 0.3, 1, 36.0, 1.0 },
|
Chris@41
|
71 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
|
Chris@41
|
72 { 1, { 0.01111111111 }, 1.001, 1, 38.0, 1.0 },
|
Chris@41
|
73 { 2, { 0.011111, 0.324 }, 1.9999, 2, 14.0, 1.0 },
|
Chris@41
|
74 { 2, { 0.012345, 0.457 }, 0.456789, 1, 12.0, 1.0 },
|
Chris@41
|
75 { 1, { 0.3511111111 }, 1.33, 1, 10.0, 1.0 }
|
Chris@41
|
76 }
|
Chris@41
|
77 },
|
Chris@41
|
78
|
Chris@41
|
79 { SRC_LINEAR,
|
Chris@41
|
80 8,
|
Chris@41
|
81 BOOLEAN_FALSE,
|
Chris@41
|
82 { { 1, { 0.01111111111 }, 3.0, 1, 73.0, 1.0 },
|
Chris@41
|
83 { 1, { 0.01111111111 }, 0.6, 1, 73.0, 1.0 },
|
Chris@41
|
84 { 1, { 0.01111111111 }, 0.3, 1, 73.0, 1.0 },
|
Chris@41
|
85 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
|
Chris@41
|
86 { 1, { 0.01111111111 }, 1.001, 1, 77.0, 1.0 },
|
Chris@41
|
87 { 2, { 0.011111, 0.324 }, 1.9999, 2, 15.0, 0.94 },
|
Chris@41
|
88 { 2, { 0.012345, 0.457 }, 0.456789, 1, 25.0, 0.96 },
|
Chris@41
|
89 { 1, { 0.3511111111 }, 1.33, 1, 22.0, 0.99 }
|
Chris@41
|
90 }
|
Chris@41
|
91 },
|
Chris@41
|
92
|
Chris@41
|
93 { SRC_SINC_FASTEST,
|
Chris@41
|
94 9,
|
Chris@41
|
95 BOOLEAN_TRUE,
|
Chris@41
|
96 { { 1, { 0.01111111111 }, 3.0, 1, 100.0, 1.0 },
|
Chris@41
|
97 { 1, { 0.01111111111 }, 0.6, 1, 99.0, 1.0 },
|
Chris@41
|
98 { 1, { 0.01111111111 }, 0.3, 1, 100.0, 1.0 },
|
Chris@41
|
99 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
|
Chris@41
|
100 { 1, { 0.01111111111 }, 1.001, 1, 100.0, 1.0 },
|
Chris@41
|
101 { 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 1.0 },
|
Chris@41
|
102 { 2, { 0.012345, 0.457 }, 0.456789, 1, 100.0, 0.5 },
|
Chris@41
|
103 { 2, { 0.011111, 0.45 }, 0.6, 1, 97.0, 0.5 },
|
Chris@41
|
104 { 1, { 0.3511111111 }, 1.33, 1, 97.0, 1.0 }
|
Chris@41
|
105 }
|
Chris@41
|
106 },
|
Chris@41
|
107
|
Chris@41
|
108 { SRC_SINC_MEDIUM_QUALITY,
|
Chris@41
|
109 9,
|
Chris@41
|
110 BOOLEAN_TRUE,
|
Chris@41
|
111 { { 1, { 0.01111111111 }, 3.0, 1, 145.0, 1.0 },
|
Chris@41
|
112 { 1, { 0.01111111111 }, 0.6, 1, 132.0, 1.0 },
|
Chris@41
|
113 { 1, { 0.01111111111 }, 0.3, 1, 138.0, 1.0 },
|
Chris@41
|
114 { 1, { 0.01111111111 }, 1.0, 1, 157.0, 1.0 },
|
Chris@41
|
115 { 1, { 0.01111111111 }, 1.001, 1, 148.0, 1.0 },
|
Chris@41
|
116 { 2, { 0.011111, 0.324 }, 1.9999, 2, 127.0, 1.0 },
|
Chris@41
|
117 { 2, { 0.012345, 0.457 }, 0.456789, 1, 123.0, 0.5 },
|
Chris@41
|
118 { 2, { 0.011111, 0.45 }, 0.6, 1, 126.0, 0.5 },
|
Chris@41
|
119 { 1, { 0.43111111111 }, 1.33, 1, 121.0, 1.0 }
|
Chris@41
|
120 }
|
Chris@41
|
121 },
|
Chris@41
|
122
|
Chris@41
|
123 { SRC_SINC_BEST_QUALITY,
|
Chris@41
|
124 9,
|
Chris@41
|
125 BOOLEAN_TRUE,
|
Chris@41
|
126 { { 1, { 0.01111111111 }, 3.0, 1, 147.0, 1.0 },
|
Chris@41
|
127 { 1, { 0.01111111111 }, 0.6, 1, 147.0, 1.0 },
|
Chris@41
|
128 { 1, { 0.01111111111 }, 0.3, 1, 148.0, 1.0 },
|
Chris@41
|
129 { 1, { 0.01111111111 }, 1.0, 1, 155.0, 1.0 },
|
Chris@41
|
130 { 1, { 0.01111111111 }, 1.001, 1, 148.0, 1.0 },
|
Chris@41
|
131 { 2, { 0.011111, 0.324 }, 1.9999, 2, 146.0, 1.0 },
|
Chris@41
|
132 { 2, { 0.012345, 0.457 }, 0.456789, 1, 147.0, 0.5 },
|
Chris@41
|
133 { 2, { 0.011111, 0.45 }, 0.6, 1, 144.0, 0.5 },
|
Chris@41
|
134 { 1, { 0.43111111111 }, 1.33, 1, 145.0, 1.0 }
|
Chris@41
|
135 }
|
Chris@41
|
136 },
|
Chris@41
|
137 } ; /* snr_test_data */
|
Chris@41
|
138
|
Chris@41
|
139 double best_snr, snr, freq3dB ;
|
Chris@41
|
140 int j, k, converter, verbose = 0 ;
|
Chris@41
|
141
|
Chris@41
|
142 if (argc == 2 && strcmp (argv [1], "--verbose") == 0)
|
Chris@41
|
143 verbose = 1 ;
|
Chris@41
|
144
|
Chris@41
|
145 puts ("") ;
|
Chris@41
|
146
|
Chris@41
|
147 for (j = 0 ; j < ARRAY_LEN (snr_test_data) ; j++)
|
Chris@41
|
148 { best_snr = 5000.0 ;
|
Chris@41
|
149
|
Chris@41
|
150 converter = snr_test_data [j].converter ;
|
Chris@41
|
151
|
Chris@41
|
152 printf (" Converter %d : %s\n", converter, src_get_name (converter)) ;
|
Chris@41
|
153 printf (" %s\n", src_get_description (converter)) ;
|
Chris@41
|
154
|
Chris@41
|
155 for (k = 0 ; k < snr_test_data [j].tests ; k++)
|
Chris@41
|
156 { snr = snr_test (&(snr_test_data [j].test_data [k]), k, converter, verbose) ;
|
Chris@41
|
157 if (best_snr > snr)
|
Chris@41
|
158 best_snr = snr ;
|
Chris@41
|
159 } ;
|
Chris@41
|
160
|
Chris@41
|
161 printf (" Worst case Signal-to-Noise Ratio : %.2f dB.\n", best_snr) ;
|
Chris@41
|
162
|
Chris@41
|
163 if (snr_test_data [j].do_bandwidth_test == BOOLEAN_FALSE)
|
Chris@41
|
164 { puts (" Bandwith test not performed on this converter.\n") ;
|
Chris@41
|
165 continue ;
|
Chris@41
|
166 }
|
Chris@41
|
167
|
Chris@41
|
168 freq3dB = bandwidth_test (converter, verbose) ;
|
Chris@41
|
169
|
Chris@41
|
170 printf (" Measured -3dB rolloff point : %5.2f %%.\n\n", freq3dB) ;
|
Chris@41
|
171 } ;
|
Chris@41
|
172
|
Chris@41
|
173 fftw_cleanup () ;
|
Chris@41
|
174
|
Chris@41
|
175 return 0 ;
|
Chris@41
|
176 } /* main */
|
Chris@41
|
177
|
Chris@41
|
178 /*==============================================================================
|
Chris@41
|
179 */
|
Chris@41
|
180
|
Chris@41
|
181 static double
|
Chris@41
|
182 snr_test (SINGLE_TEST *test_data, int number, int converter, int verbose)
|
Chris@41
|
183 { static float data [BUFFER_LEN + 1] ;
|
Chris@41
|
184 static float output [MAX_SPEC_LEN] ;
|
Chris@41
|
185
|
Chris@41
|
186 SRC_STATE *src_state ;
|
Chris@41
|
187 SRC_DATA src_data ;
|
Chris@41
|
188
|
Chris@41
|
189 double output_peak, snr ;
|
Chris@41
|
190 int k, output_len, input_len, error ;
|
Chris@41
|
191
|
Chris@41
|
192 if (verbose != 0)
|
Chris@41
|
193 { printf ("\tSignal-to-Noise Ratio Test %d.\n"
|
Chris@41
|
194 "\t=====================================\n", number) ;
|
Chris@41
|
195 printf ("\tFrequencies : [ ") ;
|
Chris@41
|
196 for (k = 0 ; k < test_data->freq_count ; k++)
|
Chris@41
|
197 printf ("%6.4f ", test_data->freqs [k]) ;
|
Chris@41
|
198
|
Chris@41
|
199 printf ("]\n\tSRC Ratio : %8.4f\n", test_data->src_ratio) ;
|
Chris@41
|
200 }
|
Chris@41
|
201 else
|
Chris@41
|
202 { printf ("\tSignal-to-Noise Ratio Test %d : ", number) ;
|
Chris@41
|
203 fflush (stdout) ;
|
Chris@41
|
204 } ;
|
Chris@41
|
205
|
Chris@41
|
206 /* Set up the output array. */
|
Chris@41
|
207 if (test_data->src_ratio >= 1.0)
|
Chris@41
|
208 { output_len = MAX_SPEC_LEN ;
|
Chris@41
|
209 input_len = (int) ceil (MAX_SPEC_LEN / test_data->src_ratio) ;
|
Chris@41
|
210 if (input_len > BUFFER_LEN)
|
Chris@41
|
211 input_len = BUFFER_LEN ;
|
Chris@41
|
212 }
|
Chris@41
|
213 else
|
Chris@41
|
214 { input_len = BUFFER_LEN ;
|
Chris@41
|
215 output_len = (int) ceil (BUFFER_LEN * test_data->src_ratio) ;
|
Chris@41
|
216 output_len &= ((~0u) << 4) ;
|
Chris@41
|
217 if (output_len > MAX_SPEC_LEN)
|
Chris@41
|
218 output_len = MAX_SPEC_LEN ;
|
Chris@41
|
219 input_len = (int) ceil (output_len / test_data->src_ratio) ;
|
Chris@41
|
220 } ;
|
Chris@41
|
221
|
Chris@41
|
222 memset (output, 0, sizeof (output)) ;
|
Chris@41
|
223
|
Chris@41
|
224 /* Generate input data array. */
|
Chris@41
|
225 gen_windowed_sines (test_data->freq_count, test_data->freqs, 1.0, data, input_len) ;
|
Chris@41
|
226
|
Chris@41
|
227 /* Perform sample rate conversion. */
|
Chris@41
|
228 if ((src_state = src_new (converter, 1, &error)) == NULL)
|
Chris@41
|
229 { printf ("\n\nLine %d : src_new() failed : %s.\n\n", __LINE__, src_strerror (error)) ;
|
Chris@41
|
230 exit (1) ;
|
Chris@41
|
231 } ;
|
Chris@41
|
232
|
Chris@41
|
233 src_data.end_of_input = 1 ; /* Only one buffer worth of input. */
|
Chris@41
|
234
|
Chris@41
|
235 src_data.data_in = data ;
|
Chris@41
|
236 src_data.input_frames = input_len ;
|
Chris@41
|
237
|
Chris@41
|
238 src_data.src_ratio = test_data->src_ratio ;
|
Chris@41
|
239
|
Chris@41
|
240 src_data.data_out = output ;
|
Chris@41
|
241 src_data.output_frames = output_len ;
|
Chris@41
|
242
|
Chris@41
|
243 if ((error = src_process (src_state, &src_data)))
|
Chris@41
|
244 { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ;
|
Chris@41
|
245 exit (1) ;
|
Chris@41
|
246 } ;
|
Chris@41
|
247
|
Chris@41
|
248 src_state = src_delete (src_state) ;
|
Chris@41
|
249
|
Chris@41
|
250 if (verbose != 0)
|
Chris@41
|
251 printf ("\tOutput Len : %ld\n", src_data.output_frames_gen) ;
|
Chris@41
|
252
|
Chris@41
|
253 if (abs (src_data.output_frames_gen - output_len) > 4)
|
Chris@41
|
254 { printf ("\n\nLine %d : output data length should be %d.\n\n", __LINE__, output_len) ;
|
Chris@41
|
255 exit (1) ;
|
Chris@41
|
256 } ;
|
Chris@41
|
257
|
Chris@41
|
258 /* Check output peak. */
|
Chris@41
|
259 output_peak = find_peak (output, src_data.output_frames_gen) ;
|
Chris@41
|
260
|
Chris@41
|
261 if (verbose != 0)
|
Chris@41
|
262 printf ("\tOutput Peak : %6.4f\n", output_peak) ;
|
Chris@41
|
263
|
Chris@41
|
264 if (fabs (output_peak - test_data->peak_value) > 0.01)
|
Chris@41
|
265 { printf ("\n\nLine %d : output peak (%6.4f) should be %6.4f\n\n", __LINE__, output_peak, test_data->peak_value) ;
|
Chris@41
|
266 save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, output_len) ;
|
Chris@41
|
267 exit (1) ;
|
Chris@41
|
268 } ;
|
Chris@41
|
269
|
Chris@41
|
270 /* Calculate signal-to-noise ratio. */
|
Chris@41
|
271 snr = calculate_snr (output, src_data.output_frames_gen, test_data->pass_band_peaks) ;
|
Chris@41
|
272
|
Chris@41
|
273 if (snr < 0.0)
|
Chris@41
|
274 { /* An error occurred. */
|
Chris@41
|
275 save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, src_data.output_frames_gen) ;
|
Chris@41
|
276 exit (1) ;
|
Chris@41
|
277 } ;
|
Chris@41
|
278
|
Chris@41
|
279 if (verbose != 0)
|
Chris@41
|
280 printf ("\tSNR Ratio : %.2f dB\n", snr) ;
|
Chris@41
|
281
|
Chris@41
|
282 if (snr < test_data->snr)
|
Chris@41
|
283 { printf ("\n\nLine %d : SNR (%5.2f) should be > %6.2f dB\n\n", __LINE__, snr, test_data->snr) ;
|
Chris@41
|
284 exit (1) ;
|
Chris@41
|
285 } ;
|
Chris@41
|
286
|
Chris@41
|
287 if (verbose != 0)
|
Chris@41
|
288 puts ("\t-------------------------------------\n\tPass\n") ;
|
Chris@41
|
289 else
|
Chris@41
|
290 puts ("Pass") ;
|
Chris@41
|
291
|
Chris@41
|
292 return snr ;
|
Chris@41
|
293 } /* snr_test */
|
Chris@41
|
294
|
Chris@41
|
295 static double
|
Chris@41
|
296 find_peak (float *data, int len)
|
Chris@41
|
297 { double peak = 0.0 ;
|
Chris@41
|
298 int k = 0 ;
|
Chris@41
|
299
|
Chris@41
|
300 for (k = 0 ; k < len ; k++)
|
Chris@41
|
301 if (fabs (data [k]) > peak)
|
Chris@41
|
302 peak = fabs (data [k]) ;
|
Chris@41
|
303
|
Chris@41
|
304 return peak ;
|
Chris@41
|
305 } /* find_peak */
|
Chris@41
|
306
|
Chris@41
|
307
|
Chris@41
|
308 static double
|
Chris@41
|
309 find_attenuation (double freq, int converter, int verbose)
|
Chris@41
|
310 { static float input [BUFFER_LEN] ;
|
Chris@41
|
311 static float output [2 * BUFFER_LEN] ;
|
Chris@41
|
312
|
Chris@41
|
313 SRC_DATA src_data ;
|
Chris@41
|
314 double output_peak ;
|
Chris@41
|
315 int error ;
|
Chris@41
|
316
|
Chris@41
|
317 gen_windowed_sines (1, &freq, 1.0, input, BUFFER_LEN) ;
|
Chris@41
|
318
|
Chris@41
|
319 src_data.end_of_input = 1 ; /* Only one buffer worth of input. */
|
Chris@41
|
320
|
Chris@41
|
321 src_data.data_in = input ;
|
Chris@41
|
322 src_data.input_frames = BUFFER_LEN ;
|
Chris@41
|
323
|
Chris@41
|
324 src_data.src_ratio = 1.999 ;
|
Chris@41
|
325
|
Chris@41
|
326 src_data.data_out = output ;
|
Chris@41
|
327 src_data.output_frames = ARRAY_LEN (output) ;
|
Chris@41
|
328
|
Chris@41
|
329 if ((error = src_simple (&src_data, converter, 1)))
|
Chris@41
|
330 { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ;
|
Chris@41
|
331 exit (1) ;
|
Chris@41
|
332 } ;
|
Chris@41
|
333
|
Chris@41
|
334 output_peak = find_peak (output, ARRAY_LEN (output)) ;
|
Chris@41
|
335
|
Chris@41
|
336 if (verbose)
|
Chris@41
|
337 printf ("\tFreq : %6f InPeak : %6f OutPeak : %6f Atten : %6.2f dB\n",
|
Chris@41
|
338 freq, 1.0, output_peak, 20.0 * log10 (1.0 / output_peak)) ;
|
Chris@41
|
339
|
Chris@41
|
340 return 20.0 * log10 (1.0 / output_peak) ;
|
Chris@41
|
341 } /* find_attenuation */
|
Chris@41
|
342
|
Chris@41
|
343 static double
|
Chris@41
|
344 bandwidth_test (int converter, int verbose)
|
Chris@41
|
345 { double f1, f2, a1, a2 ;
|
Chris@41
|
346 double freq, atten ;
|
Chris@41
|
347
|
Chris@41
|
348 f1 = 0.35 ;
|
Chris@41
|
349 a1 = find_attenuation (f1, converter, verbose) ;
|
Chris@41
|
350
|
Chris@41
|
351 f2 = 0.495 ;
|
Chris@41
|
352 a2 = find_attenuation (f2, converter, verbose) ;
|
Chris@41
|
353
|
Chris@41
|
354 if (a1 > 3.0 || a2 < 3.0)
|
Chris@41
|
355 { printf ("\n\nLine %d : cannot bracket 3dB point.\n\n", __LINE__) ;
|
Chris@41
|
356 exit (1) ;
|
Chris@41
|
357 } ;
|
Chris@41
|
358
|
Chris@41
|
359 while (a2 - a1 > 1.0)
|
Chris@41
|
360 { freq = f1 + 0.5 * (f2 - f1) ;
|
Chris@41
|
361 atten = find_attenuation (freq, converter, verbose) ;
|
Chris@41
|
362
|
Chris@41
|
363 if (atten < 3.0)
|
Chris@41
|
364 { f1 = freq ;
|
Chris@41
|
365 a1 = atten ;
|
Chris@41
|
366 }
|
Chris@41
|
367 else
|
Chris@41
|
368 { f2 = freq ;
|
Chris@41
|
369 a2 = atten ;
|
Chris@41
|
370 } ;
|
Chris@41
|
371 } ;
|
Chris@41
|
372
|
Chris@41
|
373 freq = f1 + (3.0 - a1) * (f2 - f1) / (a2 - a1) ;
|
Chris@41
|
374
|
Chris@41
|
375 return 200.0 * freq ;
|
Chris@41
|
376 } /* bandwidth_test */
|
Chris@41
|
377
|
Chris@41
|
378 #else /* (HAVE_FFTW3) == 0 */
|
Chris@41
|
379
|
Chris@41
|
380 /* Alternative main function when librfftw is not available. */
|
Chris@41
|
381
|
Chris@41
|
382 int
|
Chris@41
|
383 main (void)
|
Chris@41
|
384 { puts ("\n"
|
Chris@41
|
385 "****************************************************************\n"
|
Chris@41
|
386 " This test cannot be run without FFTW (http://www.fftw.org/).\n"
|
Chris@41
|
387 " Both the real and the complex versions of the library are\n"
|
Chris@41
|
388 " required.") ;
|
Chris@41
|
389 puts ("****************************************************************\n") ;
|
Chris@41
|
390
|
Chris@41
|
391 return 0 ;
|
Chris@41
|
392 } /* main */
|
Chris@41
|
393
|
Chris@41
|
394 #endif
|
Chris@41
|
395
|