2008-09-03 19:02:00 +00:00
/*
* SpanDSP - a series of DSP components for telephony
*
* v29_tests . c
*
* Written by Steve Underwood < steveu @ coppice . org >
*
* Copyright ( C ) 2003 Steve Underwood
*
* All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 , as
* published by the Free Software Foundation .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*! \page v29_tests_page V.29 modem tests
\ section v29_tests_page_sec_1 What does it do ?
These tests test one way paths , as V .29 is a half - duplex modem . They allow either :
- A V .29 transmit modem to feed a V .29 receive modem through a telephone line
model . BER testing is then used to evaluate performance under various line
conditions . This is effective for testing the basic performance of the
receive modem . It is also the only test mode provided for evaluating the
transmit modem .
2009-06-18 06:13:59 +00:00
- A V .29 receive modem is used to decode V .29 audio , stored in an audio file .
2008-09-03 19:02:00 +00:00
This is good way to evaluate performance with audio recorded from other
models of modem , and with real world problematic telephone lines .
If the appropriate GUI environment exists , the tests are built such that a visual
display of modem status is maintained .
\ section v29_tests_page_sec_2 How is it used ?
*/
2009-01-28 04:48:03 +00:00
/* Enable the following definition to enable direct probing into the FAX structures */
# define WITH_SPANDSP_INTERNALS
2008-09-03 19:02:00 +00:00
# if defined(HAVE_CONFIG_H)
# include "config.h"
# endif
# if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
# define ENABLE_GUI
# endif
# include <stdlib.h>
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
2009-06-18 06:13:59 +00:00
# include <sndfile.h>
2010-07-24 19:29:44 +00:00
# include <signal.h>
# if defined(HAVE_FENV_H)
2011-07-02 06:45:27 +00:00
# define __USE_GNU
2010-07-24 19:29:44 +00:00
# include <fenv.h>
# endif
2008-09-03 19:02:00 +00:00
2009-01-28 04:48:03 +00:00
//#if defined(WITH_SPANDSP_INTERNALS)
# define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
//#endif
2008-09-03 19:02:00 +00:00
# include "spandsp.h"
# include "spandsp-sim.h"
# if defined(ENABLE_GUI)
# include "modem_monitor.h"
# include "line_model_monitor.h"
# endif
# define BLOCK_LEN 160
# define OUT_FILE_NAME "v29.wav"
char * decode_test_file = NULL ;
int use_gui = FALSE ;
int symbol_no = 0 ;
int rx_bits = 0 ;
bert_state_t bert ;
one_way_line_model_state_t * line_model ;
# if defined(ENABLE_GUI)
qam_monitor_t * qam_monitor ;
# endif
bert_results_t latest_results ;
static void reporter ( void * user_data , int reason , bert_results_t * results )
{
switch ( reason )
{
case BERT_REPORT_REGULAR :
2009-07-22 15:18:32 +00:00
fprintf ( stderr , " BERT report regular - %d bits, %d bad bits, %d resyncs \n " , results - > total_bits , results - > bad_bits , results - > resyncs ) ;
2008-09-03 19:02:00 +00:00
memcpy ( & latest_results , results , sizeof ( latest_results ) ) ;
break ;
default :
2009-07-22 15:18:32 +00:00
fprintf ( stderr , " BERT report %s \n " , bert_event_to_str ( reason ) ) ;
2008-09-03 19:02:00 +00:00
break ;
}
}
/*- End of function --------------------------------------------------------*/
2009-02-20 18:25:22 +00:00
static void v29_rx_status ( void * user_data , int status )
2008-09-03 19:02:00 +00:00
{
v29_rx_state_t * rx ;
int i ;
int len ;
2008-09-09 17:04:42 +00:00
# if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t * coeffs ;
# else
2008-09-03 19:02:00 +00:00
complexf_t * coeffs ;
2008-09-09 17:04:42 +00:00
# endif
2008-09-03 19:02:00 +00:00
2008-09-09 17:04:42 +00:00
printf ( " V.29 rx status is %s (%d) \n " , signal_status_to_str ( status ) , status ) ;
2008-09-03 19:02:00 +00:00
rx = ( v29_rx_state_t * ) user_data ;
switch ( status )
{
2008-09-09 17:04:42 +00:00
case SIG_STATUS_TRAINING_SUCCEEDED :
2008-09-03 19:02:00 +00:00
printf ( " Training succeeded \n " ) ;
2008-09-09 17:04:42 +00:00
# if defined(SPANDSP_USE_FIXED_POINT)
len = v29_rx_equalizer_state ( rx , & coeffs ) ;
printf ( " Equalizer: \n " ) ;
for ( i = 0 ; i < len ; i + + )
printf ( " %3d (%15.5f, %15.5f) \n " , i , coeffs [ i ] . re / 4096.0f , coeffs [ i ] . im / 4096.0f ) ;
# else
2008-09-03 19:02:00 +00:00
len = v29_rx_equalizer_state ( rx , & coeffs ) ;
printf ( " Equalizer: \n " ) ;
for ( i = 0 ; i < len ; i + + )
printf ( " %3d (%15.5f, %15.5f) -> %15.5f \n " , i , coeffs [ i ] . re , coeffs [ i ] . im , powerf ( & coeffs [ i ] ) ) ;
2008-09-09 17:04:42 +00:00
# endif
2008-09-03 19:02:00 +00:00
break ;
}
}
/*- End of function --------------------------------------------------------*/
static void v29putbit ( void * user_data , int bit )
{
v29_rx_state_t * rx ;
if ( bit < 0 )
{
v29_rx_status ( user_data , bit ) ;
return ;
}
rx = ( v29_rx_state_t * ) user_data ;
if ( decode_test_file )
printf ( " Rx bit %d - %d \n " , rx_bits + + , bit ) ;
else
bert_put_bit ( & bert , bit ) ;
}
/*- End of function --------------------------------------------------------*/
2009-02-20 18:25:22 +00:00
static void v29_tx_status ( void * user_data , int status )
2008-09-03 19:02:00 +00:00
{
2008-09-09 17:04:42 +00:00
printf ( " V.29 tx status is %s (%d) \n " , signal_status_to_str ( status ) , status ) ;
2008-09-03 19:02:00 +00:00
}
/*- End of function --------------------------------------------------------*/
static int v29getbit ( void * user_data )
{
return bert_get_bit ( & bert ) ;
}
/*- End of function --------------------------------------------------------*/
static void qam_report ( void * user_data , const complexf_t * constel , const complexf_t * target , int symbol )
{
int i ;
int len ;
2008-09-09 17:04:42 +00:00
# if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t * coeffs ;
# else
2008-09-03 19:02:00 +00:00
complexf_t * coeffs ;
2008-09-09 17:04:42 +00:00
# endif
2008-09-03 19:02:00 +00:00
float fpower ;
v29_rx_state_t * rx ;
static float smooth_power = 0.0f ;
static int update_interval = 100 ;
rx = ( v29_rx_state_t * ) user_data ;
if ( constel )
{
fpower = ( constel - > re - target - > re ) * ( constel - > re - target - > re )
+ ( constel - > im - target - > im ) * ( constel - > im - target - > im ) ;
smooth_power = 0.95f * smooth_power + 0.05f * fpower ;
# if defined(ENABLE_GUI)
if ( use_gui )
{
qam_monitor_update_constel ( qam_monitor , constel ) ;
qam_monitor_update_carrier_tracking ( qam_monitor , v29_rx_carrier_frequency ( rx ) ) ;
//qam_monitor_update_carrier_tracking(qam_monitor, (fpower) ? fpower : 0.001f);
qam_monitor_update_symbol_tracking ( qam_monitor , v29_rx_symbol_timing_correction ( rx ) ) ;
}
# endif
2009-04-20 18:33:33 +00:00
printf ( " %8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %9.4f %7.3f %7.4f \n " ,
2008-09-03 19:02:00 +00:00
symbol_no ,
constel - > re ,
constel - > im ,
target - > re ,
target - > im ,
symbol ,
fpower ,
smooth_power ,
v29_rx_carrier_frequency ( rx ) ,
v29_rx_signal_power ( rx ) ,
v29_rx_symbol_timing_correction ( rx ) ) ;
symbol_no + + ;
if ( - - update_interval < = 0 )
{
2008-09-09 17:04:42 +00:00
# if defined(SPANDSP_USE_FIXED_POINT)
len = v29_rx_equalizer_state ( rx , & coeffs ) ;
printf ( " Equalizer A: \n " ) ;
for ( i = 0 ; i < len ; i + + )
printf ( " %3d (%15.5f, %15.5f) \n " , i , coeffs [ i ] . re / 4096.0f , coeffs [ i ] . im / 4096.0f ) ;
# if defined(ENABLE_GUI)
if ( use_gui )
qam_monitor_update_int_equalizer ( qam_monitor , coeffs , len ) ;
# endif
# else
2008-09-03 19:02:00 +00:00
len = v29_rx_equalizer_state ( rx , & coeffs ) ;
printf ( " Equalizer A: \n " ) ;
for ( i = 0 ; i < len ; i + + )
printf ( " %3d (%15.5f, %15.5f) -> %15.5f \n " , i , coeffs [ i ] . re , coeffs [ i ] . im , powerf ( & coeffs [ i ] ) ) ;
# if defined(ENABLE_GUI)
if ( use_gui )
qam_monitor_update_equalizer ( qam_monitor , coeffs , len ) ;
2008-09-09 17:04:42 +00:00
# endif
2008-09-03 19:02:00 +00:00
# endif
update_interval = 100 ;
}
}
}
/*- End of function --------------------------------------------------------*/
2010-07-24 19:29:44 +00:00
# if defined(HAVE_FENV_H)
static void sigfpe_handler ( int sig_num , siginfo_t * info , void * data )
{
switch ( sig_num )
{
case SIGFPE :
switch ( info - > si_code )
{
case FPE_INTDIV :
fprintf ( stderr , " integer divide by zero at %p \n " , info - > si_addr ) ;
break ;
case FPE_INTOVF :
fprintf ( stderr , " integer overflow at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTDIV :
fprintf ( stderr , " FP divide by zero at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTOVF :
fprintf ( stderr , " FP overflow at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTUND :
fprintf ( stderr , " FP underflow at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTRES :
fprintf ( stderr , " FP inexact result at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTINV :
fprintf ( stderr , " FP invalid operation at %p \n " , info - > si_addr ) ;
break ;
case FPE_FLTSUB :
fprintf ( stderr , " subscript out of range at %p \n " , info - > si_addr ) ;
break ;
}
break ;
default :
fprintf ( stderr , " Unexpected signal %d \n " , sig_num ) ;
break ;
}
exit ( 2 ) ;
}
/*- End of function --------------------------------------------------------*/
static void fpe_trap_setup ( void )
{
struct sigaction trap ;
sigemptyset ( & trap . sa_mask ) ;
trap . sa_flags = SA_SIGINFO ;
trap . sa_sigaction = sigfpe_handler ;
sigaction ( SIGFPE , & trap , NULL ) ;
//feenableexcept(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW);
//feenableexcept(FE_ALL_EXCEPT);
feenableexcept ( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW ) ;
}
/*- End of function --------------------------------------------------------*/
# endif
2008-09-03 19:02:00 +00:00
int main ( int argc , char * argv [ ] )
{
2009-01-28 04:48:03 +00:00
v29_rx_state_t * rx ;
v29_tx_state_t * tx ;
2008-09-03 19:02:00 +00:00
bert_results_t bert_results ;
int16_t gen_amp [ BLOCK_LEN ] ;
int16_t amp [ BLOCK_LEN ] ;
2009-06-18 06:13:59 +00:00
SNDFILE * inhandle ;
SNDFILE * outhandle ;
2008-09-03 19:02:00 +00:00
int outframes ;
int samples ;
int tep ;
int test_bps ;
int noise_level ;
int signal_level ;
int bits_per_test ;
int line_model_no ;
2009-04-20 18:33:33 +00:00
int block_no ;
2008-09-03 19:02:00 +00:00
int log_audio ;
int channel_codec ;
int rbs_pattern ;
int opt ;
2009-01-28 04:48:03 +00:00
logging_state_t * logging ;
2008-09-03 19:02:00 +00:00
channel_codec = MUNGE_CODEC_NONE ;
rbs_pattern = 0 ;
test_bps = 9600 ;
tep = FALSE ;
line_model_no = 0 ;
decode_test_file = NULL ;
use_gui = FALSE ;
noise_level = - 70 ;
signal_level = - 13 ;
bits_per_test = 50000 ;
log_audio = FALSE ;
2009-01-28 04:48:03 +00:00
while ( ( opt = getopt ( argc , argv , " b:B:c:d:glm:n:r:s:t " ) ) ! = - 1 )
2008-09-03 19:02:00 +00:00
{
switch ( opt )
{
case ' b ' :
2009-01-28 04:48:03 +00:00
test_bps = atoi ( optarg ) ;
if ( test_bps ! = 9600 & & test_bps ! = 7200 & & test_bps ! = 4800 )
{
fprintf ( stderr , " Invalid bit rate specified \n " ) ;
exit ( 2 ) ;
}
break ;
case ' B ' :
2008-09-03 19:02:00 +00:00
bits_per_test = atoi ( optarg ) ;
break ;
case ' c ' :
channel_codec = atoi ( optarg ) ;
break ;
case ' d ' :
decode_test_file = optarg ;
break ;
case ' g ' :
# if defined(ENABLE_GUI)
use_gui = TRUE ;
# else
fprintf ( stderr , " Graphical monitoring not available \n " ) ;
exit ( 2 ) ;
# endif
break ;
case ' l ' :
log_audio = TRUE ;
break ;
case ' m ' :
line_model_no = atoi ( optarg ) ;
break ;
case ' n ' :
noise_level = atoi ( optarg ) ;
break ;
case ' r ' :
rbs_pattern = atoi ( optarg ) ;
break ;
case ' s ' :
signal_level = atoi ( optarg ) ;
break ;
case ' t ' :
tep = TRUE ;
break ;
default :
//usage();
exit ( 2 ) ;
break ;
}
}
inhandle = NULL ;
outhandle = NULL ;
2010-07-24 19:29:44 +00:00
# if defined(HAVE_FENV_H)
fpe_trap_setup ( ) ;
# endif
2008-09-03 19:02:00 +00:00
if ( log_audio )
{
2009-06-18 06:13:59 +00:00
if ( ( outhandle = sf_open_telephony_write ( OUT_FILE_NAME , 1 ) ) = = NULL )
2008-09-03 19:02:00 +00:00
{
2009-06-18 06:13:59 +00:00
fprintf ( stderr , " Cannot create audio file '%s' \n " , OUT_FILE_NAME ) ;
2008-09-03 19:02:00 +00:00
exit ( 2 ) ;
}
}
if ( decode_test_file )
{
2009-06-18 06:13:59 +00:00
/* We will decode the audio from a file. */
2009-01-28 04:48:03 +00:00
tx = NULL ;
2009-06-18 06:13:59 +00:00
if ( ( inhandle = sf_open_telephony_read ( decode_test_file , 1 ) ) = = NULL )
2008-09-03 19:02:00 +00:00
{
2009-06-18 06:13:59 +00:00
fprintf ( stderr , " Cannot open audio file '%s' \n " , decode_test_file ) ;
2008-09-03 19:02:00 +00:00
exit ( 2 ) ;
}
}
else
{
/* We will generate V.29 audio, and add some noise to it. */
2009-01-28 04:48:03 +00:00
tx = v29_tx_init ( NULL , test_bps , tep , v29getbit , NULL ) ;
v29_tx_power ( tx , signal_level ) ;
v29_tx_set_modem_status_handler ( tx , v29_tx_status , ( void * ) tx ) ;
# if defined(WITH_SPANDSP_INTERNALS)
2008-09-03 19:02:00 +00:00
/* Move the carrier off a bit */
2009-01-28 04:48:03 +00:00
tx - > carrier_phase_rate = dds_phase_ratef ( 1710.0f ) ;
tx - > carrier_phase = 0 ;
# endif
2008-09-03 19:02:00 +00:00
bert_init ( & bert , bits_per_test , BERT_PATTERN_ITU_O152_11 , test_bps , 20 ) ;
bert_set_report ( & bert , 10000 , reporter , NULL ) ;
if ( ( line_model = one_way_line_model_init ( line_model_no , ( float ) noise_level , channel_codec , rbs_pattern ) ) = = NULL )
{
fprintf ( stderr , " Failed to create line model \n " ) ;
exit ( 2 ) ;
}
}
2009-01-28 04:48:03 +00:00
rx = v29_rx_init ( NULL , test_bps , v29putbit , NULL ) ;
v29_rx_signal_cutoff ( rx , - 45.5f ) ;
v29_rx_set_modem_status_handler ( rx , v29_rx_status , ( void * ) rx ) ;
v29_rx_set_qam_report_handler ( rx , qam_report , ( void * ) rx ) ;
# if defined(WITH_SPANDSP_INTERNALS)
2008-09-03 19:02:00 +00:00
/* Rotate the starting phase */
2009-01-28 04:48:03 +00:00
rx - > carrier_phase = 0x80000000 ;
# endif
logging = v29_rx_get_logging_state ( rx ) ;
span_log_set_level ( logging , SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW ) ;
span_log_set_tag ( logging , " V.29-rx " ) ;
2008-09-03 19:02:00 +00:00
# if defined(ENABLE_GUI)
if ( use_gui )
{
qam_monitor = qam_monitor_init ( 6.0f , NULL ) ;
if ( ! decode_test_file )
{
start_line_model_monitor ( 129 ) ;
line_model_monitor_line_model_update ( line_model - > near_filter , line_model - > near_filter_len ) ;
}
}
# endif
memset ( & latest_results , 0 , sizeof ( latest_results ) ) ;
2009-04-20 18:33:33 +00:00
for ( block_no = 0 ; ; block_no + + )
2008-09-03 19:02:00 +00:00
{
if ( decode_test_file )
{
2009-06-18 06:13:59 +00:00
samples = sf_readf_short ( inhandle , amp , BLOCK_LEN ) ;
2008-09-03 19:02:00 +00:00
# if defined(ENABLE_GUI)
if ( use_gui )
qam_monitor_update_audio_level ( qam_monitor , amp , samples ) ;
# endif
if ( samples = = 0 )
break ;
}
else
{
2009-01-28 04:48:03 +00:00
samples = v29_tx ( tx , gen_amp , BLOCK_LEN ) ;
2008-09-03 19:02:00 +00:00
# if defined(ENABLE_GUI)
if ( use_gui )
qam_monitor_update_audio_level ( qam_monitor , gen_amp , samples ) ;
# endif
if ( samples = = 0 )
{
/* Push a little silence through, to ensure all the data bits get out of the buffers */
2010-07-24 19:29:44 +00:00
vec_zeroi16 ( amp , BLOCK_LEN ) ;
2009-01-28 04:48:03 +00:00
v29_rx ( rx , amp , BLOCK_LEN ) ;
2008-09-03 19:02:00 +00:00
/* Note that we might get a few bad bits as the carrier shuts down. */
bert_result ( & bert , & bert_results ) ;
2008-09-09 17:04:42 +00:00
fprintf ( stderr , " Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs \n " , signal_level , noise_level , bert_results . total_bits , bert_results . bad_bits , bert_results . resyncs ) ;
fprintf ( stderr , " Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs \n " , signal_level , noise_level , latest_results . total_bits , latest_results . bad_bits , latest_results . resyncs ) ;
2008-09-03 19:02:00 +00:00
/* See if bit errors are appearing yet. Also check we are getting enough bits out of the receiver. The last regular report
should be error free , though the final report will generally contain bits errors as the carrier was dying . The total
number of bits out of the receiver should be at least the number we sent . Also , since BERT sync should have occurred
rapidly at the start of transmission , the last report should have occurred at not much less than the total number of
bits we sent . */
if ( bert_results . total_bits < bits_per_test
| |
latest_results . total_bits < bits_per_test - 100
| |
latest_results . bad_bits ! = 0 )
{
break ;
}
memset ( & latest_results , 0 , sizeof ( latest_results ) ) ;
signal_level - - ;
2009-01-28 04:48:03 +00:00
v29_tx_restart ( tx , test_bps , tep ) ;
v29_tx_power ( tx , signal_level ) ;
v29_rx_restart ( rx , test_bps , FALSE ) ;
# if defined(WITH_SPANDSP_INTERNALS)
rx - > eq_put_step = rand ( ) % ( 48 * 10 / 3 ) ;
# endif
2008-09-03 19:02:00 +00:00
bert_init ( & bert , bits_per_test , BERT_PATTERN_ITU_O152_11 , test_bps , 20 ) ;
bert_set_report ( & bert , 10000 , reporter , NULL ) ;
one_way_line_model_release ( line_model ) ;
if ( ( line_model = one_way_line_model_init ( line_model_no , ( float ) noise_level , channel_codec , 0 ) ) = = NULL )
{
fprintf ( stderr , " Failed to create line model \n " ) ;
exit ( 2 ) ;
}
}
if ( log_audio )
{
2009-06-18 06:13:59 +00:00
outframes = sf_writef_short ( outhandle , gen_amp , samples ) ;
2008-09-03 19:02:00 +00:00
if ( outframes ! = samples )
{
2009-06-18 06:13:59 +00:00
fprintf ( stderr , " Error writing audio file \n " ) ;
2008-09-03 19:02:00 +00:00
exit ( 2 ) ;
}
}
one_way_line_model ( line_model , amp , gen_amp , samples ) ;
}
# if defined(ENABLE_GUI)
if ( use_gui & & ! decode_test_file )
line_model_monitor_line_spectrum_update ( amp , samples ) ;
# endif
2009-01-28 04:48:03 +00:00
v29_rx ( rx , amp , samples ) ;
2008-09-03 19:02:00 +00:00
}
if ( ! decode_test_file )
{
bert_result ( & bert , & bert_results ) ;
fprintf ( stderr , " At completion: \n " ) ;
2008-09-09 17:04:42 +00:00
fprintf ( stderr , " Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs \n " , signal_level , noise_level , bert_results . total_bits , bert_results . bad_bits , bert_results . resyncs ) ;
fprintf ( stderr , " Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs \n " , signal_level , noise_level , latest_results . total_bits , latest_results . bad_bits , latest_results . resyncs ) ;
2008-09-03 19:02:00 +00:00
one_way_line_model_release ( line_model ) ;
if ( signal_level > - 43 )
{
printf ( " Tests failed. \n " ) ;
exit ( 2 ) ;
}
printf ( " Tests passed. \n " ) ;
}
# if defined(ENABLE_GUI)
if ( use_gui )
qam_wait_to_end ( qam_monitor ) ;
# endif
2009-04-28 14:42:18 +00:00
if ( decode_test_file )
{
2009-06-18 06:13:59 +00:00
if ( sf_close ( inhandle ) )
2009-04-28 14:42:18 +00:00
{
2009-06-18 06:13:59 +00:00
fprintf ( stderr , " Cannot close audio file '%s' \n " , decode_test_file ) ;
2009-04-28 14:42:18 +00:00
exit ( 2 ) ;
}
}
2008-09-03 19:02:00 +00:00
if ( log_audio )
{
2009-06-18 06:13:59 +00:00
if ( sf_close ( outhandle ) )
2008-09-03 19:02:00 +00:00
{
2009-06-18 06:13:59 +00:00
fprintf ( stderr , " Cannot close audio file '%s' \n " , OUT_FILE_NAME ) ;
2008-09-03 19:02:00 +00:00
exit ( 2 ) ;
}
}
return 0 ;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/