From 1b183864bb0dc135838cded1a3f31594979e837f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 13 Nov 2017 19:34:05 +0100 Subject: Restructure: Move sample rate conversion from common code to 'libsamplerate' --- .gitignore | 1 + configure.ac | 1 + src/Makefile.am | 2 +- src/amps/Makefile.am | 1 + src/anetz/Makefile.am | 1 + src/bnetz/Makefile.am | 1 + src/cnetz/Makefile.am | 1 + src/common/Makefile.am | 1 - src/common/emphasis.h | 2 + src/common/mncc_console.c | 2 +- src/common/samplerate.c | 157 ----------------------------------------- src/common/samplerate.h | 19 ----- src/common/sender.h | 2 +- src/jtacs/Makefile.am | 1 + src/libsamplerate/Makefile.am | 6 ++ src/libsamplerate/samplerate.c | 157 +++++++++++++++++++++++++++++++++++++++++ src/libsamplerate/samplerate.h | 19 +++++ src/nmt/Makefile.am | 1 + src/r2000/Makefile.am | 1 + src/tacs/Makefile.am | 1 + src/test/Makefile.am | 4 ++ 21 files changed, 201 insertions(+), 180 deletions(-) delete mode 100644 src/common/samplerate.c delete mode 100644 src/common/samplerate.h create mode 100644 src/libsamplerate/Makefile.am create mode 100644 src/libsamplerate/samplerate.c create mode 100644 src/libsamplerate/samplerate.h diff --git a/.gitignore b/.gitignore index 961b61b..f59d993 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ compile .libs .dirstamp m4 +src/libsamplerate/libsamplerate.a src/libfilter/libfilter.a src/common/libcommon.a src/common/libmobile.a diff --git a/configure.ac b/configure.ac index cea6660..62e21b0 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/libsamplerate/Makefile src/libfilter/Makefile src/common/Makefile src/anetz/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 378d449..79f134e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = libfilter common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test +SUBDIRS = libsamplerate libfilter common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 43e4887..390a69e 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -28,6 +28,7 @@ amps_LDADD = \ libamps.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am index b742481..26ad266 100644 --- a/src/anetz/Makefile.am +++ b/src/anetz/Makefile.am @@ -14,6 +14,7 @@ anetz_LDADD = \ $(top_builddir)/src/common/libgermanton.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am index 38adde6..f00b82b 100644 --- a/src/bnetz/Makefile.am +++ b/src/bnetz/Makefile.am @@ -16,6 +16,7 @@ bnetz_LDADD = \ $(top_builddir)/src/common/libgermanton.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index ee678e7..8065736 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -20,6 +20,7 @@ cnetz_LDADD = \ $(top_builddir)/src/common/libgermanton.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 7a59d64..6f8ae93 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -11,7 +11,6 @@ libcommon_a_SOURCES = \ goertzel.c \ jitter.c \ dtmf.c \ - samplerate.c \ emphasis.c \ compandor.c \ fft.c \ diff --git a/src/common/emphasis.h b/src/common/emphasis.h index 0e91509..43d54e6 100644 --- a/src/common/emphasis.h +++ b/src/common/emphasis.h @@ -1,3 +1,5 @@ +#include "../libfilter/iir_filter.h" + typedef struct emphasis { struct { iir_filter_t lp; diff --git a/src/common/mncc_console.c b/src/common/mncc_console.c index 1e65d04..fc779f4 100644 --- a/src/common/mncc_console.c +++ b/src/common/mncc_console.c @@ -25,7 +25,7 @@ #include #include #include "sample.h" -#include "samplerate.h" +#include "../libsamplerate/samplerate.h" #include "jitter.h" #include "debug.h" #include "testton.h" diff --git a/src/common/samplerate.c b/src/common/samplerate.c deleted file mode 100644 index db6b278..0000000 --- a/src/common/samplerate.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Sample rate conversion - * - * (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 -#include "sample.h" -#include "samplerate.h" - -int init_samplerate(samplerate_t *state, double low_samplerate, double high_samplerate, double filter_cutoff) -{ - memset(state, 0, sizeof(*state)); - state->factor = high_samplerate / low_samplerate; - if (state->factor < 1.0) { - fprintf(stderr, "Software error: Low sample rate must be lower than high sample rate, aborting!\n"); - abort(); - } - - iir_lowpass_init(&state->up.lp, filter_cutoff, high_samplerate, 2); - iir_lowpass_init(&state->down.lp, filter_cutoff, high_samplerate, 2); - - return 0; -} - -/* convert high sample rate to low sample rate */ -int samplerate_downsample(samplerate_t *state, sample_t *samples, int input_num) -{ - int output_num = 0, i, idx; - double factor = state->factor, in_index, diff; - sample_t output[(int)((double)input_num / factor + 0.5) + 10]; /* add some safety */ - sample_t last_sample; - - /* filter down */ - iir_process(&state->down.lp, samples, input_num); - - /* get last sample for interpolation */ - last_sample = state->down.last_sample; - - /* resample filtered result */ - in_index = state->down.in_index; - - for (i = 0; ; i++) { - /* convert index to int */ - idx = (int)in_index; - /* if index is outside input sample range, we are done */ - if (idx >= input_num) - break; - /* linear interpolation */ - diff = in_index - (double)idx; - if (idx) - output[i] = samples[idx - 1] * (1.0 - diff) + samples[idx] * diff; - else - output[i] = last_sample * (1.0 - diff) + samples[idx] * diff; - /* count output number */ - output_num++; - /* increment input index */ - in_index += factor; - } - - /* store last sample for interpolation */ - if (input_num) - state->down.last_sample = samples[input_num - 1]; - - /* remove number of input samples from index */ - in_index -= (double)input_num; - /* in_index cannot be negative, excpet due to rounding error, so... */ - if ((int)in_index < 0) - in_index = 0.0; - - state->down.in_index = in_index; - - /* copy samples */ - for (i = 0; i < output_num; i++) - *samples++ = output[i]; - - return output_num; -} - -/* convert low sample rate to high sample rate */ -int samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output) -{ - int output_num = 0, i, idx; - double factor = 1.0 / state->factor, in_index, diff; - sample_t buff[(int)((double)input_num / factor + 0.5) + 10]; /* add some safety */ - sample_t *samples, last_sample; - - /* get last sample for interpolation */ - last_sample = state->up.last_sample; - - if (input == output) - samples = buff; - else - samples = output; - - /* resample input */ - in_index = state->up.in_index; - - for (i = 0; ; i++) { - /* convert index to int */ - idx = (int)in_index; - /* if index is outside input sample range, we are done */ - if (idx >= input_num) - break; - /* linear interpolation */ - diff = in_index - (double)idx; - if (idx) - samples[i] = input[idx - 1] * (1.0 - diff) + input[idx] * diff; - else - samples[i] = last_sample * (1.0 - diff) + input[idx] * diff; - /* count output number */ - output_num++; - /* increment input index */ - in_index += factor; - } - - /* store last sample for interpolation */ - if (input_num) - state->up.last_sample = input[input_num - 1]; - - /* remove number of input samples from index */ - in_index -= (double)input_num; - /* in_index cannot be negative, excpet due to rounding error, so... */ - if ((int)in_index < 0) - in_index = 0.0; - - state->up.in_index = in_index; - - /* filter up */ - iir_process(&state->up.lp, samples, output_num); - - if (input == output) { - /* copy samples */ - for (i = 0; i < output_num; i++) - *output++ = samples[i]; - } - - return output_num; -} - diff --git a/src/common/samplerate.h b/src/common/samplerate.h deleted file mode 100644 index 8f8ea87..0000000 --- a/src/common/samplerate.h +++ /dev/null @@ -1,19 +0,0 @@ -#include "../libfilter/iir_filter.h" - -typedef struct samplerate { - double factor; - struct { - iir_filter_t lp; - sample_t last_sample; - double in_index; - } down; - struct { - iir_filter_t lp; - sample_t last_sample; - double in_index; - } up; -} samplerate_t; - -int init_samplerate(samplerate_t *state, double low_samplerate, double high_samplerate, double filter_cutoff); -int samplerate_downsample(samplerate_t *state, sample_t *samples, int input_num); -int samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output); diff --git a/src/common/sender.h b/src/common/sender.h index 4ca728f..c222fda 100644 --- a/src/common/sender.h +++ b/src/common/sender.h @@ -3,7 +3,7 @@ #include "sdr.h" #endif #include "wave.h" -#include "samplerate.h" +#include "../libsamplerate/samplerate.h" #include "jitter.h" #include "emphasis.h" #include "display.h" diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am index b4e6fdf..763df25 100644 --- a/src/jtacs/Makefile.am +++ b/src/jtacs/Makefile.am @@ -14,6 +14,7 @@ jtacs_LDADD = \ ../amps/libamps.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/libsamplerate/Makefile.am b/src/libsamplerate/Makefile.am new file mode 100644 index 0000000..bd2319f --- /dev/null +++ b/src/libsamplerate/Makefile.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = libsamplerate.a + +libsamplerate_a_SOURCES = \ + samplerate.c diff --git a/src/libsamplerate/samplerate.c b/src/libsamplerate/samplerate.c new file mode 100644 index 0000000..fd2fea9 --- /dev/null +++ b/src/libsamplerate/samplerate.c @@ -0,0 +1,157 @@ +/* Sample rate conversion + * + * (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 +#include "../common/sample.h" +#include "samplerate.h" + +int init_samplerate(samplerate_t *state, double low_samplerate, double high_samplerate, double filter_cutoff) +{ + memset(state, 0, sizeof(*state)); + state->factor = high_samplerate / low_samplerate; + if (state->factor < 1.0) { + fprintf(stderr, "Software error: Low sample rate must be lower than high sample rate, aborting!\n"); + abort(); + } + + iir_lowpass_init(&state->up.lp, filter_cutoff, high_samplerate, 2); + iir_lowpass_init(&state->down.lp, filter_cutoff, high_samplerate, 2); + + return 0; +} + +/* convert high sample rate to low sample rate */ +int samplerate_downsample(samplerate_t *state, sample_t *samples, int input_num) +{ + int output_num = 0, i, idx; + double factor = state->factor, in_index, diff; + sample_t output[(int)((double)input_num / factor + 0.5) + 10]; /* add some safety */ + sample_t last_sample; + + /* filter down */ + iir_process(&state->down.lp, samples, input_num); + + /* get last sample for interpolation */ + last_sample = state->down.last_sample; + + /* resample filtered result */ + in_index = state->down.in_index; + + for (i = 0; ; i++) { + /* convert index to int */ + idx = (int)in_index; + /* if index is outside input sample range, we are done */ + if (idx >= input_num) + break; + /* linear interpolation */ + diff = in_index - (double)idx; + if (idx) + output[i] = samples[idx - 1] * (1.0 - diff) + samples[idx] * diff; + else + output[i] = last_sample * (1.0 - diff) + samples[idx] * diff; + /* count output number */ + output_num++; + /* increment input index */ + in_index += factor; + } + + /* store last sample for interpolation */ + if (input_num) + state->down.last_sample = samples[input_num - 1]; + + /* remove number of input samples from index */ + in_index -= (double)input_num; + /* in_index cannot be negative, excpet due to rounding error, so... */ + if ((int)in_index < 0) + in_index = 0.0; + + state->down.in_index = in_index; + + /* copy samples */ + for (i = 0; i < output_num; i++) + *samples++ = output[i]; + + return output_num; +} + +/* convert low sample rate to high sample rate */ +int samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output) +{ + int output_num = 0, i, idx; + double factor = 1.0 / state->factor, in_index, diff; + sample_t buff[(int)((double)input_num / factor + 0.5) + 10]; /* add some safety */ + sample_t *samples, last_sample; + + /* get last sample for interpolation */ + last_sample = state->up.last_sample; + + if (input == output) + samples = buff; + else + samples = output; + + /* resample input */ + in_index = state->up.in_index; + + for (i = 0; ; i++) { + /* convert index to int */ + idx = (int)in_index; + /* if index is outside input sample range, we are done */ + if (idx >= input_num) + break; + /* linear interpolation */ + diff = in_index - (double)idx; + if (idx) + samples[i] = input[idx - 1] * (1.0 - diff) + input[idx] * diff; + else + samples[i] = last_sample * (1.0 - diff) + input[idx] * diff; + /* count output number */ + output_num++; + /* increment input index */ + in_index += factor; + } + + /* store last sample for interpolation */ + if (input_num) + state->up.last_sample = input[input_num - 1]; + + /* remove number of input samples from index */ + in_index -= (double)input_num; + /* in_index cannot be negative, excpet due to rounding error, so... */ + if ((int)in_index < 0) + in_index = 0.0; + + state->up.in_index = in_index; + + /* filter up */ + iir_process(&state->up.lp, samples, output_num); + + if (input == output) { + /* copy samples */ + for (i = 0; i < output_num; i++) + *output++ = samples[i]; + } + + return output_num; +} + diff --git a/src/libsamplerate/samplerate.h b/src/libsamplerate/samplerate.h new file mode 100644 index 0000000..8f8ea87 --- /dev/null +++ b/src/libsamplerate/samplerate.h @@ -0,0 +1,19 @@ +#include "../libfilter/iir_filter.h" + +typedef struct samplerate { + double factor; + struct { + iir_filter_t lp; + sample_t last_sample; + double in_index; + } down; + struct { + iir_filter_t lp; + sample_t last_sample; + double in_index; + } up; +} samplerate_t; + +int init_samplerate(samplerate_t *state, double low_samplerate, double high_samplerate, double filter_cutoff); +int samplerate_downsample(samplerate_t *state, sample_t *samples, int input_num); +int samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output); diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index 923dfde..4fde118 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -24,6 +24,7 @@ nmt_LDADD = \ libdmssms.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index d17a392..704d734 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -14,6 +14,7 @@ radiocom2000_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am index 190e9a2..7ba0e6a 100644 --- a/src/tacs/Makefile.am +++ b/src/tacs/Makefile.am @@ -15,6 +15,7 @@ tacs_LDADD = \ ../amps/libamps.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 1c86d46..a30f003 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -15,6 +15,7 @@ test_filter_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ @@ -38,6 +39,7 @@ test_emphasis_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ @@ -51,6 +53,7 @@ test_dms_LDADD = \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ @@ -64,6 +67,7 @@ test_sms_LDADD = \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ -- cgit v1.2.3