From 9776736cc4cc678f7aa2d0b9ebee65455bce9ce9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 16 Nov 2017 21:13:28 +0100 Subject: Restructure: Move compandor from common code to 'libcompandor' --- .gitignore | 1 + configure.ac | 1 + src/Makefile.am | 2 +- src/amps/Makefile.am | 1 + src/amps/amps.h | 2 +- src/cnetz/Makefile.am | 1 + src/cnetz/cnetz.h | 2 +- src/common/Makefile.am | 1 - src/common/compandor.c | 151 ------------------------------------------- src/common/compandor.h | 21 ------ src/jtacs/Makefile.am | 1 + src/libcompandor/Makefile.am | 6 ++ src/libcompandor/compandor.c | 151 +++++++++++++++++++++++++++++++++++++++++++ src/libcompandor/compandor.h | 22 +++++++ src/nmt/Makefile.am | 1 + src/nmt/nmt.h | 2 +- src/r2000/Makefile.am | 1 + src/r2000/r2000.h | 2 +- src/tacs/Makefile.am | 1 + src/test/Makefile.am | 1 + src/test/test_compandor.c | 2 +- 21 files changed, 194 insertions(+), 179 deletions(-) delete mode 100644 src/common/compandor.c delete mode 100644 src/common/compandor.h create mode 100644 src/libcompandor/Makefile.am create mode 100644 src/libcompandor/compandor.c create mode 100644 src/libcompandor/compandor.h diff --git a/.gitignore b/.gitignore index 5ebf7c6..b570c2d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ compile .libs .dirstamp m4 +src/libcompandor/libcompandor.a src/libgoertzel/libgoertzel.a src/libjitter/libjitter.a src/libsquelch/libsquelch.a diff --git a/configure.ac b/configure.ac index 9d57e85..1b9a604 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,7 @@ AS_IF([test "x$with_soapy" == "xyes"],[AC_MSG_NOTICE( Compiling with SoapySDR su AS_IF([test "x$somethingmagick" == "xyes"],[AC_MSG_NOTICE( Compiling with ImageMagick )],[AC_MSG_NOTICE( ImageMagick not supported )]) AC_OUTPUT( + src/libcompandor/Makefile src/libgoertzel/Makefile src/libjitter/Makefile src/libsquelch/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index e9cde59..f14df22 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = libgoertzel libjitter libsquelch libhagelbarger libdtmf libtimer libsamplerate libscrambler libemphasis libfsk libfm libfilter libwave libfft common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test +SUBDIRS = libcompandor libgoertzel libjitter libsquelch libhagelbarger libdtmf libtimer libsamplerate libscrambler libemphasis libfsk libfm libfilter libwave libfft common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 3990e9a..a3b40b7 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -26,6 +26,7 @@ amps_SOURCES = \ amps_LDADD = \ $(COMMON_LA) \ libamps.a \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/common/libmobile.a \ diff --git a/src/amps/amps.h b/src/amps/amps.h index 232745a..445675e 100644 --- a/src/amps/amps.h +++ b/src/amps/amps.h @@ -1,7 +1,7 @@ #include "../libgoertzel/goertzel.h" #include "../common/sender.h" #include "../libtimer/timer.h" -#include "../common/compandor.h" +#include "../libcompandor/compandor.h" #include "sysinfo.h" #include "transaction.h" diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index 8962b94..5d2cf2f 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -17,6 +17,7 @@ cnetz_SOURCES = \ cnetz_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ diff --git a/src/cnetz/cnetz.h b/src/cnetz/cnetz.h index 8a8c73c..55b5d2b 100644 --- a/src/cnetz/cnetz.h +++ b/src/cnetz/cnetz.h @@ -1,4 +1,4 @@ -#include "../common/compandor.h" +#include "../libcompandor/compandor.h" #include "../libtimer/timer.h" #include "../common/sender.h" #include "fsk_demod.h" diff --git a/src/common/Makefile.am b/src/common/Makefile.am index adabe55..3af2a7d 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -6,7 +6,6 @@ libcommon_a_SOURCES = \ sample.c \ debug.c \ sound_alsa.c \ - compandor.c \ display_wave.c \ display_measurements.c diff --git a/src/common/compandor.c b/src/common/compandor.c deleted file mode 100644 index aea20cd..0000000 --- a/src/common/compandor.c +++ /dev/null @@ -1,151 +0,0 @@ -/* Compandor to use various networks like C-Netz / NMT / AMPS / TACS - * - * (C) 2016 by Andreas Eversberg - * 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 as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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, see . - */ - -#include -#include -#include -#include -#include "sample.h" -#include "compandor.h" - -//#define db2level(db) pow(10, (double)db / 20.0) - -/* factor is the gain (raise and fall) after given attack/recovery time */ -#define COMPRESS_ATTACK_FACTOR 1.83 /* about 1.5 after 12 dB step up */ -#define COMPRESS_RECOVERY_FACTOR 0.44 /* about 0.75 after 12 dB step down */ -#define EXPAND_ATTACK_FACTOR 1.145 /* about 0.57 after 6 dB step up */ -#define EXPAND_RECOVERY_FACTOR 0.753 /* about 1.51 after 6 dB step down */ - -/* Minimum level value to keep state */ -#define ENVELOPE_MIN 0.001 - -/* Maximum level, to prevent sqrt_tab to overflow */ -#define ENVELOPE_MAX 9.990 - -static double sqrt_tab[10000]; - -/* - * Init compandor according to ITU-T G.162 specification - * - * Hopefully this is correct - * - */ -void init_compandor(compandor_t *state, double samplerate, double attack_ms, double recovery_ms, double unaffected_level) -{ - int i; - - memset(state, 0, sizeof(*state)); - - state->c.peak = 1.0; - state->c.envelope = 1.0; - state->e.peak = 1.0; - state->e.envelope = 1.0; - state->c.step_up = pow(COMPRESS_ATTACK_FACTOR, 1000.0 / attack_ms / samplerate); - state->c.step_down = pow(COMPRESS_RECOVERY_FACTOR, 1000.0 / recovery_ms / samplerate); - state->e.step_up = pow(EXPAND_ATTACK_FACTOR, 1000.0 / attack_ms / samplerate); - state->e.step_down = pow(EXPAND_RECOVERY_FACTOR, 1000.0 / recovery_ms / samplerate); - state->c.unaffected = unaffected_level; - state->e.unaffected = unaffected_level; - - // FIXME: make global, not at instance - for (i = 0; i < 10000; i++) - sqrt_tab[i] = sqrt(i * 0.001); -} - -void compress_audio(compandor_t *state, sample_t *samples, int num) -{ - double value, peak, envelope, step_up, step_down, unaffected; - int i; - - step_up = state->c.step_up; - step_down = state->c.step_down; - peak = state->c.peak; - envelope = state->c.envelope; - unaffected = state->c.unaffected; - -// printf("envelope=%.4f\n", envelope); - for (i = 0; i < num; i++) { - /* normalize sample value to unaffected level */ - value = *samples / unaffected; - - /* 'peak' is the level that raises directly with the signal - * level, but falls with specified recovery rate. */ - if (fabs(value) > peak) - peak = fabs(value); - else - peak *= step_down; - /* 'evelope' is the level that raises with the specified attack - * rate to 'peak', but falls with specified recovery rate. */ - if (peak > envelope) - envelope *= step_up; - else - envelope = peak; - if (envelope < ENVELOPE_MIN) - envelope = ENVELOPE_MIN; - if (envelope > ENVELOPE_MAX) - envelope = ENVELOPE_MAX; - - value = value / sqrt_tab[(int)(envelope / 0.001)]; -//if (i > 47000.0 && i < 48144) -//printf("time=%.4f envelope=%.4fdb, value=%.4f\n", (double)i/48000.0, 20*log10(envelope), value); - - *samples++ = value * unaffected; - } -//exit(0); - - state->c.envelope = envelope; - state->c.peak = peak; -} - -void expand_audio(compandor_t *state, sample_t *samples, int num) -{ - double value, peak, envelope, step_up, step_down, unaffected; - int i; - - step_up = state->e.step_up; - step_down = state->e.step_down; - peak = state->e.peak; - envelope = state->e.envelope; - unaffected = state->e.unaffected; - - for (i = 0; i < num; i++) { - /* normalize sample value to 0 DB level */ - value = *samples / unaffected; - - /* for comments: see compress_audio() */ - if (fabs(value) > peak) - peak = fabs(value); - else - peak *= step_down; - if (peak > envelope) - envelope *= step_up; - else - envelope = peak; - if (envelope < ENVELOPE_MIN) - envelope = ENVELOPE_MIN; - - value = value * envelope; - - *samples++ = value * unaffected; - } - - state->e.envelope = envelope; - state->e.peak = peak; -} - diff --git a/src/common/compandor.h b/src/common/compandor.h deleted file mode 100644 index cc53ad8..0000000 --- a/src/common/compandor.h +++ /dev/null @@ -1,21 +0,0 @@ -typedef struct compandor { - struct { - double unaffected; - double step_up; - double step_down; - double peak; - double envelope; - } c; - struct { - double unaffected; - double step_up; - double step_down; - double peak; - double envelope; - } e; -} compandor_t; - -void init_compandor(compandor_t *state, double samplerate, double attack_ms, double recovery_ms, double unaffected_level); -void compress_audio(compandor_t *state, sample_t *samples, int num); -void expand_audio(compandor_t *state, sample_t *samples, int num); - diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am index 15a657b..1128133 100644 --- a/src/jtacs/Makefile.am +++ b/src/jtacs/Makefile.am @@ -12,6 +12,7 @@ jtacs_SOURCES = \ jtacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/common/libmobile.a \ diff --git a/src/libcompandor/Makefile.am b/src/libcompandor/Makefile.am new file mode 100644 index 0000000..4c70a7e --- /dev/null +++ b/src/libcompandor/Makefile.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = libcompandor.a + +libcompandor_a_SOURCES = \ + compandor.c diff --git a/src/libcompandor/compandor.c b/src/libcompandor/compandor.c new file mode 100644 index 0000000..c2a326c --- /dev/null +++ b/src/libcompandor/compandor.c @@ -0,0 +1,151 @@ +/* Compandor to use various networks like C-Netz / NMT / AMPS / TACS + * + * (C) 2016 by Andreas Eversberg + * 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 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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, see . + */ + +#include +#include +#include +#include +#include "../common/sample.h" +#include "compandor.h" + +//#define db2level(db) pow(10, (double)db / 20.0) + +/* factor is the gain (raise and fall) after given attack/recovery time */ +#define COMPRESS_ATTACK_FACTOR 1.83 /* about 1.5 after 12 dB step up */ +#define COMPRESS_RECOVERY_FACTOR 0.44 /* about 0.75 after 12 dB step down */ +#define EXPAND_ATTACK_FACTOR 1.145 /* about 0.57 after 6 dB step up */ +#define EXPAND_RECOVERY_FACTOR 0.753 /* about 1.51 after 6 dB step down */ + +/* Minimum level value to keep state */ +#define ENVELOPE_MIN 0.001 + +/* Maximum level, to prevent sqrt_tab to overflow */ +#define ENVELOPE_MAX 9.990 + +static double sqrt_tab[10000]; + +/* + * Init compandor according to ITU-T G.162 specification + * + * Hopefully this is correct + * + */ +void init_compandor(compandor_t *state, double samplerate, double attack_ms, double recovery_ms, double unaffected_level) +{ + int i; + + memset(state, 0, sizeof(*state)); + + state->c.peak = 1.0; + state->c.envelope = 1.0; + state->e.peak = 1.0; + state->e.envelope = 1.0; + state->c.step_up = pow(COMPRESS_ATTACK_FACTOR, 1000.0 / attack_ms / samplerate); + state->c.step_down = pow(COMPRESS_RECOVERY_FACTOR, 1000.0 / recovery_ms / samplerate); + state->e.step_up = pow(EXPAND_ATTACK_FACTOR, 1000.0 / attack_ms / samplerate); + state->e.step_down = pow(EXPAND_RECOVERY_FACTOR, 1000.0 / recovery_ms / samplerate); + state->c.unaffected = unaffected_level; + state->e.unaffected = unaffected_level; + + // FIXME: make global, not at instance + for (i = 0; i < 10000; i++) + sqrt_tab[i] = sqrt(i * 0.001); +} + +void compress_audio(compandor_t *state, sample_t *samples, int num) +{ + double value, peak, envelope, step_up, step_down, unaffected; + int i; + + step_up = state->c.step_up; + step_down = state->c.step_down; + peak = state->c.peak; + envelope = state->c.envelope; + unaffected = state->c.unaffected; + +// printf("envelope=%.4f\n", envelope); + for (i = 0; i < num; i++) { + /* normalize sample value to unaffected level */ + value = *samples / unaffected; + + /* 'peak' is the level that raises directly with the signal + * level, but falls with specified recovery rate. */ + if (fabs(value) > peak) + peak = fabs(value); + else + peak *= step_down; + /* 'evelope' is the level that raises with the specified attack + * rate to 'peak', but falls with specified recovery rate. */ + if (peak > envelope) + envelope *= step_up; + else + envelope = peak; + if (envelope < ENVELOPE_MIN) + envelope = ENVELOPE_MIN; + if (envelope > ENVELOPE_MAX) + envelope = ENVELOPE_MAX; + + value = value / sqrt_tab[(int)(envelope / 0.001)]; +//if (i > 47000.0 && i < 48144) +//printf("time=%.4f envelope=%.4fdb, value=%.4f\n", (double)i/48000.0, 20*log10(envelope), value); + + *samples++ = value * unaffected; + } +//exit(0); + + state->c.envelope = envelope; + state->c.peak = peak; +} + +void expand_audio(compandor_t *state, sample_t *samples, int num) +{ + double value, peak, envelope, step_up, step_down, unaffected; + int i; + + step_up = state->e.step_up; + step_down = state->e.step_down; + peak = state->e.peak; + envelope = state->e.envelope; + unaffected = state->e.unaffected; + + for (i = 0; i < num; i++) { + /* normalize sample value to 0 DB level */ + value = *samples / unaffected; + + /* for comments: see compress_audio() */ + if (fabs(value) > peak) + peak = fabs(value); + else + peak *= step_down; + if (peak > envelope) + envelope *= step_up; + else + envelope = peak; + if (envelope < ENVELOPE_MIN) + envelope = ENVELOPE_MIN; + + value = value * envelope; + + *samples++ = value * unaffected; + } + + state->e.envelope = envelope; + state->e.peak = peak; +} + diff --git a/src/libcompandor/compandor.h b/src/libcompandor/compandor.h new file mode 100644 index 0000000..25d51ea --- /dev/null +++ b/src/libcompandor/compandor.h @@ -0,0 +1,22 @@ + +typedef struct compandor { + struct { + double unaffected; + double step_up; + double step_down; + double peak; + double envelope; + } c; + struct { + double unaffected; + double step_up; + double step_down; + double peak; + double envelope; + } e; +} compandor_t; + +void init_compandor(compandor_t *state, double samplerate, double attack_ms, double recovery_ms, double unaffected_level); +void compress_audio(compandor_t *state, sample_t *samples, int num); +void expand_audio(compandor_t *state, sample_t *samples, int num); + diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index 545cb27..6429c77 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -22,6 +22,7 @@ nmt_SOURCES = \ nmt_LDADD = \ $(COMMON_LA) \ libdmssms.a \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h index 3564a73..5179fb2 100644 --- a/src/nmt/nmt.h +++ b/src/nmt/nmt.h @@ -1,6 +1,6 @@ #include "../common/sender.h" #include "../libtimer/timer.h" -#include "../common/compandor.h" +#include "../libcompandor/compandor.h" #include "../libdtmf/dtmf_encode.h" #include "../common/call.h" #include "../libfsk/fsk.h" diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index 1c763c4..7a8b61b 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -12,6 +12,7 @@ radiocom2000_SOURCES = \ main.c radiocom2000_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ $(top_builddir)/src/common/libmobile.a \ diff --git a/src/r2000/r2000.h b/src/r2000/r2000.h index c9012ea..553258b 100644 --- a/src/r2000/r2000.h +++ b/src/r2000/r2000.h @@ -1,4 +1,4 @@ -#include "../common/compandor.h" +#include "../libcompandor/compandor.h" #include "../libtimer/timer.h" #include "../common/sender.h" #include "../common/call.h" diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am index 7f3afbf..2bca149 100644 --- a/src/tacs/Makefile.am +++ b/src/tacs/Makefile.am @@ -13,6 +13,7 @@ tacs_SOURCES = \ tacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/common/libmobile.a \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 24666bb..6e86ce7 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -32,6 +32,7 @@ test_compandor_SOURCES = dummy.x test_compandor.c test_compandor_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(ALSA_LIBS) \ diff --git a/src/test/test_compandor.c b/src/test/test_compandor.c index 4b0ff7b..d222928 100644 --- a/src/test/test_compandor.c +++ b/src/test/test_compandor.c @@ -3,7 +3,7 @@ #include #include #include "../common/sample.h" -#include "../common/compandor.h" +#include "../libcompandor/compandor.h" #define level2db(level) (20 * log10(level)) #define db2level(db) pow(10, (double)db / 20.0) -- cgit v1.2.3