A typo fixed in the OKI ADPCM codec

The V.17 modem has been modified, so it will not clear the most recent
saved AGC value if long training is requested.
The T.38 gateway codec now has fillin implemented properly
This commit is contained in:
Steve Underwood 2010-06-16 21:34:57 +08:00
parent 1eb4b79c15
commit 01052800c7
7 changed files with 302 additions and 161 deletions

View File

@ -26,8 +26,6 @@
*
* The actual OKI ADPCM encode and decode method is derived from freely
* available code, whose exact origins seem uncertain.
*
* $Id: oki_adpcm.c,v 1.32 2009/02/10 13:06:46 steveu Exp $
*/
/*! \file */
@ -153,7 +151,7 @@ static const float cutoff_coeffs[] =
static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
{
int16_t e;
int16_t d;
int16_t ss;
int16_t linear;
@ -170,20 +168,20 @@ static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
*/
ss = step_size[s->step_index];
e = ss >> 3;
d = ss >> 3;
if (adpcm & 0x01)
e += (ss >> 2);
d += (ss >> 2);
/*endif*/
if (adpcm & 0x02)
e += (ss >> 1);
d += (ss >> 1);
/*endif*/
if (adpcm & 0x04)
e += ss;
d += ss;
/*endif*/
if (adpcm & 0x08)
e = -e;
d = -d;
/*endif*/
linear = s->last + e;
linear = s->last + d;
/* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
if (linear > 2047)
@ -206,32 +204,32 @@ static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
static uint8_t encode(oki_adpcm_state_t *s, int16_t linear)
{
int16_t e;
int16_t d;
int16_t ss;
uint8_t adpcm;
ss = step_size[s->step_index];
e = (linear >> 4) - s->last;
d = (linear >> 4) - s->last;
adpcm = (uint8_t) 0x00;
if (e < 0)
if (d < 0)
{
adpcm = (uint8_t) 0x08;
e = -e;
d = -d;
}
/*endif*/
if (e >= ss)
if (d >= ss)
{
adpcm |= (uint8_t) 0x04;
e -= ss;
d -= ss;
}
/*endif*/
if (e >= (ss >> 1))
if (d >= (ss >> 1))
{
adpcm |= (uint8_t) 0x02;
e -= ss;
d -= (ss >> 1);
}
/*endif*/
if (e >= (ss >> 2))
if (d >= (ss >> 2))
adpcm |= (uint8_t) 0x01;
/*endif*/

View File

@ -21,8 +21,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.h,v 1.5 2009/11/07 08:58:58 steveu Exp $
*/
/*! \file */
@ -35,7 +33,7 @@
*/
typedef struct
{
/*! Core T.38 IFP support */
/*! \brief Core T.38 IFP support */
t38_core_state_t t38;
/*! \brief TRUE if the NSF, NSC, and NSS are to be suppressed by altering
@ -61,9 +59,10 @@ typedef struct
{
/*! \brief The FAX modem set for the audio side fo the gateway. */
fax_modems_state_t modems;
/*! \brief The current receive signal handler. Actual receiving hop between this
/*! \brief The current receive signal handler. Actual receiving hops between this
and a dummy receive routine. */
span_rx_handler_t *base_rx_handler;
span_rx_fillin_handler_t *base_rx_fillin_handler;
} t38_gateway_audio_state_t;
/*!
@ -144,6 +143,8 @@ typedef struct
int supported_modems;
/*! \brief TRUE if ECM FAX mode is allowed through the gateway. */
int ecm_allowed;
/*! \brief Required time between T.38 transmissions, in ms. */
int ms_per_tx_chunk;
/*! \brief TRUE if in image data modem is to use short training. This usually
follows image_data_mode, but in ECM mode T.30 defines recovery

View File

@ -21,8 +21,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.h,v 1.2.4.1 2009/12/24 16:52:30 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_V17RX_H_)
@ -30,10 +28,11 @@
/* Target length for the equalizer is about 63 taps, to deal with the worst stuff
in V.56bis. */
/*! The length of the equalizer buffer */
#define V17_EQUALIZER_LEN 33
/*! Samples before the target position in the equalizer buffer */
#define V17_EQUALIZER_PRE_LEN 8
/*! Samples after the target position in the equalizer buffer */
#define V17_EQUALIZER_POST_LEN 8
#define V17_EQUALIZER_PRE_LEN 16
/*! The number of taps in the pulse shaping/bandpass filter */
#define V17_RX_FILTER_STEPS 27
@ -137,7 +136,7 @@ struct v17_rx_state_s
int eq_step;
/*! \brief Current write offset into the equalizer buffer. */
int eq_put_step;
/*! \brief Symbol counter to the next equalizer update. */
/*! \brief Symbol count to the next equalizer update. */
int eq_skip;
/*! \brief The current half of the baud. */
@ -152,11 +151,11 @@ struct v17_rx_state_s
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexi16_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexi16_t eq_coeff[V17_EQUALIZER_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexi16_t eq_coeff_save[V17_EQUALIZER_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexi16_t eq_buf[V17_EQUALIZER_LEN];
/*! Low band edge filter for symbol sync. */
int32_t symbol_sync_low[2];
@ -175,11 +174,11 @@ struct v17_rx_state_s
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexf_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexf_t eq_coeff[V17_EQUALIZER_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexf_t eq_coeff_save[V17_EQUALIZER_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexf_t eq_buf[V17_EQUALIZER_LEN];
/*! Low band edge filter for symbol sync. */
float symbol_sync_low[2];

View File

@ -287,7 +287,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len);
SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len);
/*! Get a snapshot of the current equalizer coefficients.
\brief Get a snapshot of the current equalizer coefficients.

View File

@ -22,8 +22,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.c,v 1.171.4.2 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@ -106,7 +104,8 @@
/* This is the target time per transmission chunk. The actual
packet timing will sync to the data octets. */
/*! The default number of milliseconds per transmitted IFP when sending bulk T.38 data */
#define MS_PER_TX_CHUNK 30
#define DEFAULT_MS_PER_TX_CHUNK 30
/*! The number of bytes which must be in the audio to T.38 HDLC buffer before we start
outputting them as IFP messages. */
#define HDLC_START_BUFFER_LEVEL 8
@ -185,11 +184,15 @@ static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit);
static void non_ecm_push_residue(t38_gateway_state_t *s);
static void tone_detected(void *user_data, int tone, int level, int delay);
static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, void *user_data)
static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, span_rx_fillin_handler_t *fillin_handler, void *user_data)
{
if (s->audio.modems.rx_handler != span_dummy_rx)
{
s->audio.modems.rx_handler = handler;
s->audio.modems.rx_fillin_handler = fillin_handler;
}
s->audio.base_rx_handler = handler;
s->audio.base_rx_fillin_handler = fillin_handler;
s->audio.modems.rx_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
@ -211,6 +214,20 @@ static void set_next_tx_handler(t38_gateway_state_t *s, span_tx_handler_t *handl
static void set_rx_active(t38_gateway_state_t *s, int active)
{
s->audio.modems.rx_handler = (active) ? s->audio.base_rx_handler : span_dummy_rx;
s->audio.modems.rx_fillin_handler = (active) ? s->audio.base_rx_fillin_handler : span_dummy_rx_fillin;
}
/*- End of function --------------------------------------------------------*/
static int v17_v21_rx_fillin(void *user_data, int len)
{
t38_gateway_state_t *t;
fax_modems_state_t *s;
t = (t38_gateway_state_t *) user_data;
s = &t->audio.modems;
v17_rx_fillin(&s->v17_rx, len);
fsk_rx_fillin(&s->v21_rx, len);
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -227,7 +244,7 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
/* The fast modem has trained, so we no longer need to run the slow
one in parallel. */
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->v17_rx));
set_rx_handler(t, (span_rx_handler_t *) &v17_rx, &s->v17_rx);
set_rx_handler(t, (span_rx_handler_t *) &v17_rx, (span_rx_fillin_handler_t *) &v17_rx_fillin, &s->v17_rx);
}
else
{
@ -235,7 +252,7 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
if (s->rx_signal_present)
{
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
}
/*endif*/
}
@ -244,6 +261,19 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
static int v27ter_v21_rx_fillin(void *user_data, int len)
{
t38_gateway_state_t *t;
fax_modems_state_t *s;
t = (t38_gateway_state_t *) user_data;
s = &t->audio.modems;
v27ter_rx_fillin(&s->v27ter_rx, len);
fsk_rx_fillin(&s->v21_rx, len);
return 0;
}
/*- End of function --------------------------------------------------------*/
static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
{
t38_gateway_state_t *t;
@ -257,7 +287,7 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
/* The fast modem has trained, so we no longer need to run the slow
one in parallel. */
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->v27ter_rx));
set_rx_handler(t, (span_rx_handler_t *) &v27ter_rx, &s->v27ter_rx);
set_rx_handler(t, (span_rx_handler_t *) &v27ter_rx, (span_rx_fillin_handler_t *) &v27ter_v21_rx_fillin, &s->v27ter_rx);
}
else
{
@ -265,7 +295,7 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
if (s->rx_signal_present)
{
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
}
/*endif*/
}
@ -274,6 +304,19 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
static int v29_v21_rx_fillin(void *user_data, int len)
{
t38_gateway_state_t *t;
fax_modems_state_t *s;
t = (t38_gateway_state_t *) user_data;
s = &t->audio.modems;
v29_rx_fillin(&s->v29_rx, len);
fsk_rx_fillin(&s->v21_rx, len);
return 0;
}
/*- End of function --------------------------------------------------------*/
static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
{
t38_gateway_state_t *t;
@ -287,7 +330,7 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
/* The fast modem has trained, so we no longer need to run the slow
one in parallel. */
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->v29_rx));
set_rx_handler(t, (span_rx_handler_t *) &v29_rx, &s->v29_rx);
set_rx_handler(t, (span_rx_handler_t *) &v29_rx, (span_rx_fillin_handler_t *) &v29_rx_fillin, &s->v29_rx);
}
else
{
@ -295,7 +338,7 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
if (s->rx_signal_present)
{
span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
}
/*endif*/
}
@ -651,7 +694,7 @@ static void edit_control_messages(t38_gateway_state_t *s, int from_modem, uint8_
{
case T30_DIS:
/* Make sure the V.8 capability doesn't pass through. If it
did then two V.34 capable FAX machines might start some
did, two V.34 capable FAX machines might start some
V.8 re-negotiation. */
buf[3] &= ~DISBIT6;
break;
@ -827,7 +870,6 @@ static void monitor_control_messages(t38_gateway_state_t *s,
if (len >= 6)
{
j = (buf[5] & (DISBIT7 | DISBIT6 | DISBIT5)) >> 4;
span_log(&s->logging, SPAN_LOG_FLOW, "Min bits test = 0x%X\n", buf[5]);
s->core.min_row_bits = (s->core.fast_bit_rate*minimum_scan_line_times[j])/1000;
}
else
@ -1468,7 +1510,7 @@ static void set_octets_per_data_packet(t38_gateway_state_t *s, int bit_rate)
{
int octets;
octets = MS_PER_TX_CHUNK*bit_rate/(8*1000);
octets = s->core.ms_per_tx_chunk*bit_rate/(8*1000);
if (octets < 1)
octets = 1;
/*endif*/
@ -2029,23 +2071,23 @@ static int restart_rx_modem(t38_gateway_state_t *s)
case T38_V17_RX:
v17_rx_restart(&s->audio.modems.v17_rx, s->core.fast_bit_rate, s->core.short_train);
v17_rx_set_put_bit(&s->audio.modems.v17_rx, put_bit_func, put_bit_user_data);
set_rx_handler(s, (span_rx_handler_t *) &v17_v21_rx, s);
set_rx_handler(s, &v17_v21_rx, &v17_v21_rx_fillin, s);
s->core.fast_rx_active = T38_V17_RX;
break;
case T38_V27TER_RX:
v27ter_rx_restart(&s->audio.modems.v27ter_rx, s->core.fast_bit_rate, FALSE);
v27ter_rx_set_put_bit(&s->audio.modems.v27ter_rx, put_bit_func, put_bit_user_data);
set_rx_handler(s, (span_rx_handler_t *) &v27ter_v21_rx, s);
set_rx_handler(s, &v27ter_v21_rx, &v27ter_v21_rx_fillin, s);
s->core.fast_rx_active = T38_V27TER_RX;
break;
case T38_V29_RX:
v29_rx_restart(&s->audio.modems.v29_rx, s->core.fast_bit_rate, FALSE);
v29_rx_set_put_bit(&s->audio.modems.v29_rx, put_bit_func, put_bit_user_data);
set_rx_handler(s, (span_rx_handler_t *) &v29_v21_rx, s);
set_rx_handler(s, &v29_v21_rx, &v29_v21_rx_fillin, s);
s->core.fast_rx_active = T38_V29_RX;
break;
default:
set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, &(s->audio.modems.v21_rx));
set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &(s->audio.modems.v21_rx));
s->core.fast_rx_active = T38_NONE;
break;
}
@ -2054,15 +2096,8 @@ static int restart_rx_modem(t38_gateway_state_t *s)
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
static void update_rx_timing(t38_gateway_state_t *s, int len)
{
int i;
#if defined(LOG_FAX_AUDIO)
if (s->audio.modems.audio_rx_log >= 0)
write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t));
/*endif*/
#endif
if (s->core.samples_to_timeout > 0)
{
if ((s->core.samples_to_timeout -= len) <= 0)
@ -2096,6 +2131,19 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
/*endif*/
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
{
int i;
#if defined(LOG_FAX_AUDIO)
if (s->audio.modems.audio_rx_log >= 0)
write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t));
/*endif*/
#endif
update_rx_timing(s, len);
for (i = 0; i < len; i++)
amp[i] = dc_restore(&(s->audio.modems.dc_restore), amp[i]);
/*endfor*/
@ -2106,7 +2154,28 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
{
/* TODO: handle things properly */
/* To mitigate the effect of lost packets on a packet network we should
try to sustain the status quo. If there is no receive modem running, keep
things that way. If there is a receive modem running, try to sustain its
operation, without causing a phase hop, or letting its adaptive functions
diverge. */
#if defined(LOG_FAX_AUDIO)
if (s->audio.modems.audio_rx_log >= 0)
{
int i;
#if defined(_MSC_VER)
int16_t *amp = (int16_t *) _alloca(sizeof(int16_t)*len);
#else
int16_t amp[len];
#endif
vec_zeroi16(amp, len);
write(s->modems.audio_rx_log, amp, len*sizeof(int16_t));
}
#endif
update_rx_timing(s, len);
/* TODO: handle the modems properly */
s->audio.modems.rx_fillin_handler(s->audio.modems.rx_user_data, len);
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -2301,11 +2370,12 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s,
t38_gateway_t38_init(s, tx_packet_handler, tx_packet_user_data);
set_rx_active(s, TRUE);
t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29);
t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\x00\x00\x00", 3, (const uint8_t *) "\x00\x00\x00", 3);
s->core.to_t38.octets_per_data_packet = 1;
s->core.ecm_allowed = TRUE;
s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK;
t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0);
restart_rx_modem(s);
s->core.timed_mode = TIMED_MODE_STARTUP;

View File

@ -22,8 +22,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.c,v 1.153.4.6 2009/12/28 12:20:46 steveu Exp $
*/
/*! \file */
@ -98,9 +96,6 @@
/*! The 16 bit pattern used in the bridge section of the training sequence */
#define V17_BRIDGE_WORD 0x8880
/*! The length of the equalizer buffer */
#define V17_EQUALIZER_LEN (V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN)
enum
{
TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -233,6 +228,7 @@ static void equalizer_restore(v17_rx_state_t *s)
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
s->eq_step = 0;
s->eq_skip = 0;
}
/*- End of function --------------------------------------------------------*/
@ -253,6 +249,7 @@ static void equalizer_reset(v17_rx_state_t *s)
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
s->eq_step = 0;
s->eq_skip = 0;
}
/*- End of function --------------------------------------------------------*/
@ -565,7 +562,7 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
Passband Timing Recovery in an All-Digital Modem Receiver
IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */
/* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of
/* This is slightly rearranged from figure 3b of the Godard paper, as this saves a couple of
maths operations */
#if defined(SPANDSP_USE_FIXED_POINTx)
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
@ -579,12 +576,12 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
s->symbol_sync_dc_filter[0] = v;
/* A little integration will now filter away much of the HF noise */
s->baud_phase -= p;
if (abs(s->baud_phase) > 100*FP_FACTOR)
v = labs(s->baud_phase);
if (v > 100*FP_FACTOR)
{
if (s->baud_phase > 0)
i = (s->baud_phase > 1000*FP_FACTOR) ? 15 : 1;
else
i = (s->baud_phase < -1000*FP_FACTOR) ? -15 : -1;
i = (v > 1000*FP_FACTOR) ? 15 : 1;
if (s->baud_phase < 0)
i = -i;
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
@ -600,12 +597,12 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
s->symbol_sync_dc_filter[0] = v;
/* A little integration will now filter away much of the HF noise */
s->baud_phase -= p;
if (fabsf(s->baud_phase) > 100.0f)
v = fabsf(s->baud_phase);
if (v > 100.0f)
{
if (s->baud_phase > 0.0f)
i = (s->baud_phase > 1000.0f) ? 15 : 1;
else
i = (s->baud_phase < -1000.0f) ? -15 : -1;
i = (v > 1000.0f) ? 15 : 1;
if (s->baud_phase < 0.0f)
i = -i;
//printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
@ -732,9 +729,6 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
if (s->training_count == 100)
{
i = s->training_count;
/* Avoid the possibility of a divide by zero */
if (i)
{
j = i & 0xF;
ang = (s->angles[j] - s->start_angles[0])/i
+ (s->angles[j | 0x1] - s->start_angles[1])/i;
@ -743,7 +737,6 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->start_angles[0] = s->angles[j];
s->start_angles[1] = s->angles[j | 0x1];
}
//span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count);
span_log(&s->logging, SPAN_LOG_FLOW, "First coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
@ -1219,7 +1212,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len)
{
int i;
@ -1343,15 +1336,14 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
s->distances[0] = 0;
s->trellis_ptr = 14;
span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
s->carrier_phase = 0;
power_meter_init(&(s->power), 4);
if (s->short_train)
{
s->carrier_phase_rate = s->carrier_phase_rate_save;
s->agc_scaling = s->agc_scaling_save;
equalizer_restore(s);
s->agc_scaling = s->agc_scaling_save;
/* Don't allow any frequency correction at all, until we start to pull the phase in. */
#if defined(SPANDSP_USE_FIXED_POINTx)
s->carrier_track_i = 0;
@ -1366,18 +1358,19 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
equalizer_reset(s);
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling_save = 0;
//s->agc_scaling_save = 0;
s->agc_scaling = (float) FP_FACTOR*32768.0f*0.0017f/RX_PULSESHAPER_GAIN;
s->carrier_track_i = 5000;
s->carrier_track_p = 40000;
#else
s->agc_scaling_save = 0.0f;
//s->agc_scaling_save = 0.0f;
s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
s->carrier_track_i = 5000.0f;
s->carrier_track_p = 40000.0f;
#endif
}
s->last_sample = 0;
span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
/* Initialise the working data for symbol timing synchronisation */
#if defined(SPANDSP_USE_FIXED_POINTx)
@ -1432,8 +1425,13 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_
s->short_train = FALSE;
//s->scrambler_tap = 18 - 1;
v17_rx_signal_cutoff(s, -45.5f);
s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling_save = 0;
s->agc_scaling = (float) FP_FACTOR*32768.0f*0.0017f/RX_PULSESHAPER_GAIN;
#else
s->agc_scaling_save = 0.0f;
s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
#endif
s->carrier_phase_rate_save = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
v17_rx_restart(s, bit_rate, s->short_train);
return s;

View File

@ -22,8 +22,6 @@
* 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 02139, USA.
*
* $Id: oki_adpcm_tests.c,v 1.37 2009/05/30 15:23:14 steveu Exp $
*/
/*! \file */
@ -85,24 +83,33 @@ int main(int argc, char *argv[])
int hist_out;
oki_adpcm_state_t *oki_enc_state;
oki_adpcm_state_t *oki_dec_state;
oki_adpcm_state_t *oki_dec_state2;
int xx;
int total_pre_samples;
int total_compressed_bytes;
int total_post_samples;
int successive_08_bytes;
int successive_80_bytes;
int encoded_fd;
const char *encoded_file_name;
const char *in_file_name;
int log_encoded_data;
int opt;
bit_rate = 32000;
encoded_file_name = NULL;
in_file_name = IN_FILE_NAME;
log_encoded_data = FALSE;
while ((opt = getopt(argc, argv, "2i:l")) != -1)
while ((opt = getopt(argc, argv, "2d:i:l")) != -1)
{
switch (opt)
{
case '2':
bit_rate = 24000;
break;
case 'd':
encoded_file_name = optarg;
break;
case 'i':
in_file_name = optarg;
break;
@ -116,28 +123,43 @@ int main(int argc, char *argv[])
}
}
if (encoded_file_name)
{
if ((encoded_fd = open(encoded_file_name, O_RDONLY)) < 0)
{
fprintf(stderr, " Cannot open encoded file '%s'\n", encoded_file_name);
exit(2);
}
}
else
{
if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL)
{
fprintf(stderr, " Cannot open audio file '%s'\n", in_file_name);
exit(2);
}
if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
exit(2);
}
if ((oki_enc_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
{
fprintf(stderr, " Cannot create encoder\n");
exit(2);
}
}
if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
exit(2);
}
if ((oki_dec_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
{
fprintf(stderr, " Cannot create decoder\n");
exit(2);
}
if ((oki_dec_state2 = oki_adpcm_init(NULL, bit_rate)) == NULL)
{
fprintf(stderr, " Cannot create decoder\n");
exit(2);
}
hist_in = 0;
if (bit_rate == 32000)
@ -151,6 +173,33 @@ int main(int argc, char *argv[])
total_pre_samples = 0;
total_compressed_bytes = 0;
total_post_samples = 0;
if (encoded_file_name)
{
/* Decode a file of OKI ADPCM code to a linear wave file */
while ((oki_bytes = read(encoded_fd, oki_data, 80)) > 0)
{
total_compressed_bytes += oki_bytes;
dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes);
total_post_samples += dec_frames;
for (i = 0; i < dec_frames; i++)
{
post_energy += (double) post_amp[i] * (double) post_amp[i];
xx = post_amp[i] - history[hist_out++];
if (hist_out >= HIST_LEN)
hist_out = 0;
diff_energy += (double) xx * (double) xx;
}
outframes = sf_writef_short(outhandle, post_amp, dec_frames);
}
close(encoded_fd);
}
else
{
/* Perform a linear wave file -> OKI ADPCM -> linear wave file cycle. Along the way
check the decoder resets on the sequence specified for this codec, and the gain
and worst case sample distortion. */
successive_08_bytes = 0;
successive_80_bytes = 0;
while ((frames = sf_readf_short(inhandle, pre_amp, 159)))
{
total_pre_samples += frames;
@ -158,6 +207,29 @@ int main(int argc, char *argv[])
if (log_encoded_data)
write(1, oki_data, oki_bytes);
total_compressed_bytes += oki_bytes;
/* Look for a condition which is defined as something which should cause a reset of
the decoder (48 samples of 0, 8, 0, 8, etc.), and verify that it really does. Use
a second decode, which we feed byte by byte, for this. */
for (i = 0; i < oki_bytes; i++)
{
oki_adpcm_decode(oki_dec_state2, post_amp, &oki_data[i], 1);
if (oki_data[i] == 0x08)
successive_08_bytes++;
else
successive_08_bytes = 0;
if (oki_data[i] == 0x80)
successive_80_bytes++;
else
successive_80_bytes = 0;
if (successive_08_bytes == 24 || successive_80_bytes == 24)
{
if (oki_dec_state2->step_index != 0)
{
fprintf(stderr, "Decoder reset failure\n");
exit(2);
}
}
}
dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes);
total_post_samples += dec_frames;
for (i = 0; i < frames; i++)
@ -178,19 +250,6 @@ int main(int argc, char *argv[])
}
outframes = sf_writef_short(outhandle, post_amp, dec_frames);
}
if (sf_close(inhandle) != 0)
{
fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name);
exit(2);
}
if (sf_close(outhandle) != 0)
{
fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
exit(2);
}
oki_adpcm_release(oki_enc_state);
oki_adpcm_release(oki_dec_state);
printf("Pre samples: %d\n", total_pre_samples);
printf("Compressed bytes: %d\n", total_compressed_bytes);
printf("Post samples: %d\n", total_post_samples);
@ -199,9 +258,9 @@ int main(int argc, char *argv[])
printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy);
if (bit_rate == 32000)
{
if (fabs(1.0 - post_energy/pre_energy) > 0.05
if (fabs(1.0 - post_energy/pre_energy) > 0.01
||
fabs(diff_energy/post_energy) > 0.03)
fabs(diff_energy/post_energy) > 0.01)
{
printf("Tests failed.\n");
exit(2);
@ -209,15 +268,31 @@ int main(int argc, char *argv[])
}
else
{
if (fabs(1.0 - post_energy/pre_energy) > 0.20
if (fabs(1.0 - post_energy/pre_energy) > 0.11
||
fabs(diff_energy/post_energy) > 0.10)
fabs(diff_energy/post_energy) > 0.05)
{
printf("Tests failed.\n");
exit(2);
}
}
oki_adpcm_release(oki_enc_state);
if (sf_close(inhandle) != 0)
{
fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name);
exit(2);
}
}
oki_adpcm_release(oki_dec_state);
oki_adpcm_release(oki_dec_state2);
if (sf_close(outhandle) != 0)
{
fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
exit(2);
}
printf("Tests passed.\n");
return 0;
}