Merged origin/master into nmux

This commit is contained in:
ha7ilm 2017-01-19 17:00:16 +01:00
commit 3246e20864
6 changed files with 736 additions and 311 deletions

View file

@ -29,7 +29,7 @@
LIBSOURCES = fft_fftw.c libcsdr_wrapper.c LIBSOURCES = fft_fftw.c libcsdr_wrapper.c
#SOURCES = csdr.c $(LIBSOURCES) #SOURCES = csdr.c $(LIBSOURCES)
cpufeature = $(if $(findstring $(1),$(shell cat /proc/cpuinfo)),$(2)) cpufeature = $(if $(findstring $(1),$(shell cat /proc/cpuinfo)),$(2))
PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4,-msse4) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2) -mfpmath=sse PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4a,-msse4a) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2 -msse4) -mfpmath=sse
PARAMS_NEON = -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS PARAMS_NEON = -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS
#tnx Jan Szumiec for the Raspberry Pi support #tnx Jan Szumiec for the Raspberry Pi support
PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optimizations -Wformat=0 PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optimizations -Wformat=0
@ -92,7 +92,7 @@ emcc-get-deps:
emmake make; \ emmake make; \
emmake make install emmake make install
emcc: emcc:
emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`" emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -s TOTAL_MEMORY=67108864 -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`"
cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js
emcc-beautify: emcc-beautify:
bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi' bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi'

118
README.md
View file

@ -12,14 +12,22 @@ Most of the code is available under the permissive BSD license, with some option
How to compile How to compile
-------------- --------------
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
make make
sudo make install sudo make install
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for your CPU. If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for your CPU.
To run the examples, you will also need <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl_sdr</a> from Osmocom, and the following packages (at least on Debian): `mplayer octave gnuplot gnuplot-x11` To run the examples, you will also need <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl_sdr</a> from Osmocom, and the following packages (at least on Debian): `mplayer octave gnuplot gnuplot-x11`
If you compile *fftw3* from sources for use with *libcsdr*, you need to configure it with 32-bit float support enabled:
./configure --enable-float
(This is for *fftw3*, not *libcsdr*. You do not need to run the configure script before compiling *libcsdr*.)
Credits Credits
------- -------
The library was written by Andras Retzler, HA7ILM &lt;<randras@sdr.hu>&gt;. The library was written by Andras Retzler, HA7ILM &lt;<randras@sdr.hu>&gt;.
@ -31,7 +39,7 @@ Usage by example
### Demodulate WFM ### Demodulate WFM
rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
- Baseband I/Q signal is coming from an RTL-SDR USB dongle, with a center frequency of `-f 104300000` Hz, a sampling rate of `-s 240000` samples per second. - Baseband I/Q signal is coming from an RTL-SDR USB dongle, with a center frequency of `-f 104300000` Hz, a sampling rate of `-s 240000` samples per second.
- The `rtl_sdr` tool outputs an unsigned 8-bit I/Q signal (one byte of I sample and one byte of Q coming after each other), but `libcsdr` DSP routines internally use floating point data type, so we convert the data stream of `unsigned char` to `float` by `csdr convert_u8_f`. - The `rtl_sdr` tool outputs an unsigned 8-bit I/Q signal (one byte of I sample and one byte of Q coming after each other), but `libcsdr` DSP routines internally use floating point data type, so we convert the data stream of `unsigned char` to `float` by `csdr convert_u8_f`.
@ -43,7 +51,7 @@ Usage by example
### Demodulate WFM: advanced ### Demodulate WFM: advanced
rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
- We want to listen to one radio station, but input signal contains multiple stations, and its bandwidth is too large for sending it directly to the FM demodulator. - We want to listen to one radio station, but input signal contains multiple stations, and its bandwidth is too large for sending it directly to the FM demodulator.
- We shift the signal to the center frequency of the station we want to receive: `-0.085*2400000 = -204000`, so basically we will listen to the radio station centered at 89504000 Hz. - We shift the signal to the center frequency of the station we want to receive: `-0.085*2400000 = -204000`, so basically we will listen to the radio station centered at 89504000 Hz.
@ -64,7 +72,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
### Demodulate NFM ### Demodulate NFM
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
- Note that the decimation factor is higher (we want to select a ~25 kHz channel). - Note that the decimation factor is higher (we want to select a ~25 kHz channel).
- Also there is a python hack to calculate the relative shift offset. The real receiver frequency is `145350000` Hz. - Also there is a python hack to calculate the relative shift offset. The real receiver frequency is `145350000` Hz.
@ -72,7 +80,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
### Demodulate AM ### Demodulate AM
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
- `amdemod_cf` is used as demodulator. - `amdemod_cf` is used as demodulator.
- `agc_ff` should be used for AM and SSB. - `agc_ff` should be used for AM and SSB.
@ -87,7 +95,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
### Demodulate SSB ### Demodulate SSB
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
- It is a modified Weaver-demodulator. The complex FIR filter removes the lower sideband and lets only the upper pass (USB). If you want to demodulate LSB, change `bandpass_fir_fft_cc 0 0.05` to `bandpass_fir_fft_cc -0.05 0`. - It is a modified Weaver-demodulator. The complex FIR filter removes the lower sideband and lets only the upper pass (USB). If you want to demodulate LSB, change `bandpass_fir_fft_cc 0 0.05` to `bandpass_fir_fft_cc -0.05 0`.
@ -109,7 +117,7 @@ Data types are noted as it follows:
- `f` is `float` (single percision) - `f` is `float` (single percision)
- `c` is `complexf` (two single precision floating point values in a struct) - `c` is `complexf` (two single precision floating point values in a struct)
- `u8` is `unsigned char` of 1 byte/8 bits (e. g. the output of `rtl_sdr` is of `u8`) - `u8` is `unsigned char` of 1 byte/8 bits (e. g. the output of `rtl_sdr` is of `u8`)
- `i16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `i16`) - `s16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `s16`)
Functions usually end as: Functions usually end as:
@ -124,12 +132,14 @@ The following commands are available:
- `csdr convert_f_u8` - `csdr convert_f_u8`
- `csdr convert_s8_f` - `csdr convert_s8_f`
- `csdr convert_f_s8` - `csdr convert_f_s8`
- `csdr convert_i16_f` - `csdr convert_s16_f`
- `csdr convert_f_i16` - `csdr convert_f_s16`
How to interpret: `csdr convert_<src>_<dst>` How to interpret: `csdr convert_<src>_<dst>`
You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other). You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other).
> Note: The the functions with `i16` in their names have been renamed, but still work (e.g. `csdr convert_f_i16`).
#### csdr commands #### csdr commands
`csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`. `csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`.
@ -157,6 +167,10 @@ It multiplies all samples by `gain`.
It copies the input to the output. It copies the input to the output.
through
It copies the input to the output, while also displaying the speed of the data going through it.
none none
The `csdr` process just exits with 0. The `csdr` process just exits with 0.
@ -363,11 +377,45 @@ The actual number of padding samples can be determined by running `cat csdr.c |
It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`. It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`.
dsb_fc [q_value]
It converts a real signal to a double sideband complex signal centered around DC.
It does so by generating a complex signal:
* the real part of which is the input real signal,
* the imaginary part of which is `q_value` (0 by default).
With `q_value = 0` it is an AM-DSB/SC modulator. If you want to get an AM-DSB signal, you will have to add a carrier to it.
add_dcoffset_cc
It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_output = q_input / 2`
convert_f_samplerf <wait_for_this_sample>
It converts a real signal to the `-mRF` input format of [https://github.com/F5OEO/rpitx](rpitx), so it allows you to generate frequency modulation. The input signal will be the modulating signal. The `<wait_for_this_sample>` parameter is the value for `rpitx` indicating the time to wait between samples. For a sampling rate of 48 ksps, this is 20833.
fmmod_fc
It generates a complex FM modulated output from a real input signal.
fixed_amplitude_cc <new_amplitude>
It changes the amplitude of every complex input sample to a fixed value. It does not change the phase information of the samples.
mono2stereo_s16
It doubles every input sample.
setbuf <buffer_size> setbuf <buffer_size>
If the environment variable `CSDR_DYNAMIC_BUFSIZE_ON` is set to 1, then you can use this command to set the input buffer size for the next `csdr` process in the chain. See the [buffer sizes](#buffer_sizes) section.
squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>
This is a controllable squelch, which reads the squelch level input from `<squelch_fifo>` and writes the power level output to `<smeter_fifo>`. Both input and output are in the format of `%g\n`. While calculating the power level, it takes only every `<use_every_nth>` sample into consideration. It writes the S-meter value for every `<report_every_nth>` buffer to `<smeter_fifo>`. If the squelch level is set to 0, it it forces the squelch to be open. If the squelch is closed, it fills the output with zero.
fifo <buffer_size> <number_of_buffers>
It is similar to `clone`, but internally it uses a circular buffer. It reads as much as possible from the input. It discards input samples if the input buffer is full.
#### Control via pipes #### Control via pipes
@ -391,6 +439,56 @@ By writing to the given FIFO file with the syntax below, you can control the shi
E.g. you can send `-0.05 0.02\n` E.g. you can send `-0.05 0.02\n`
#### Buffer sizes
*csdr* has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables:
* *default:* 16k or 1k buffer is chosen based on function,
* *dynamic buffer size determination:* input buffer size is recommended by the previous process, output buffer size is determined by the process,
* *fixed buffer sizes*.
*csdr* can choose from two different buffer sizes by **default**.
* For operations handling the full-bandwidth I/Q data from the receiver, a buffer size of 16384 samples is used (see `env_csdr_fixed_big_bufsize` in the code).
* For operations handling only a selected channel, a buffer size of 1024 samples is used (see `env_csdr_fixed_bufsize` in the code).
*csdr* now has an experimental feature called **dynamic buffer size determination**, which is switched on by issuing `export CSDR_DYNAMIC_BUFSIZE_ON=1` in the shell before running `csdr`. If it is enabled:
* All `csdr` processes in a DSP chain acquire their recommended input buffer size from the previous `csdr` process. This information is in the first 8 bytes of the input stream.
* Each process can decide whether to use this or choose another input buffer size (if that's more practical).
* Every process sends out its output buffer size to the next process. Then it startss processing data.
* The DSP chain should start with a `csdr setbuf <buffer_size>` process, which only copies data from the input to the output, but also sends out the given buffer size information to the next process.
* The 8 bytes of information included in the beginning of the stream is:
* a preamble of the bytes 'c','s','d','r' (4 bytes),
* the buffer size stored as `int` (4 bytes).
* This size always counts as samples, as we expect that the user takes care of connecting the functions with right data types to each other.
> I added this feature while researching how to decrease the latency of a DSP chain consisting of several multirate algorithms.<br />
> For example, a `csdr fir_decimate_cc 10` would use an input buffer of 10240, and an output buffer of 1024. The next process in the chain, `csdr bandpass_fir_fft_cc` would automatically adjust to it, using a buffer of 1024 for both input and output.<br />
> In contrast to original expectations, using dynamic buffer sizes didn't decrease the latency much.
If dynamic buffer size determination is disabled, you can still set a **fixed buffer size** with `export CSDR_FIXED_BUFSIZE=<buffer_size>`.
For debug purposes, buffer sizes of all processes can be printed using `export CSDR_PRINT_BUFSIZES=1`.
If you add your own functions to `csdr`, you have to initialize the buffers before doing the processing. Buffer size will be stored in the global variable `the_bufsize`.
Example of initialization if the process generates N output samples for N input samples:
if(!sendbufsize(initialize_buffers())) return -2;
Example of initalization if the process generates N/D output samples for N input samples:
if(!initialize_buffers()) return -2;
sendbufsize(the_bufsize/D);
Example of initialization if the process allocates memory for itself, and it doesn't want to use the global buffers:
getbufsize(); //dummy
sendbufsize(my_own_bufsize);
Example of initialization if the process always works with a fixed output size, regardless of the input:
if(!initialize_buffers()) return -2;
sendbufsize(fft_size);
#### Testbench #### Testbench
`csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio. `csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio.

276
csdr.c
View file

@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sched.h> #include <sched.h>
#include <math.h> #include <math.h>
#include <strings.h> #include <strings.h>
#include <errno.h>
#include "fastddc.h" #include "fastddc.h"
char usage[]= char usage[]=
@ -60,8 +61,10 @@ char usage[]=
" convert_f_u8\n" " convert_f_u8\n"
" convert_s8_f\n" " convert_s8_f\n"
" convert_f_s8\n" " convert_f_s8\n"
" convert_f_i16\n" " convert_f_s16\n"
" convert_i16_f\n" " convert_s16_f\n"
" convert_f_s24 [--bigendian]\n"
" convert_s24_f [--bigendian]\n"
" realpart_cf\n" " realpart_cf\n"
" clipdetect_ff\n" " clipdetect_ff\n"
" limit_ff [max_amplitude]\n" " limit_ff [max_amplitude]\n"
@ -73,7 +76,9 @@ char usage[]=
" floatdump_f\n" " floatdump_f\n"
" flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n" " flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n"
" shift_math_cc <rate>\n" " shift_math_cc <rate>\n"
" shift_math_cc --fifo <fifo_path>\n"
" shift_addition_cc <rate>\n" " shift_addition_cc <rate>\n"
" shift_addition_cc --fifo <fifo_path>\n"
" shift_addition_cc_test\n" " shift_addition_cc_test\n"
" shift_table_cc <rate> [table_size]\n" " shift_table_cc <rate> [table_size]\n"
" decimating_shift_addition_cc <rate> [decimation]\n" " decimating_shift_addition_cc <rate> [decimation]\n"
@ -97,10 +102,21 @@ char usage[]=
" logpower_cf [add_db]\n" " logpower_cf [add_db]\n"
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n" " fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n" " bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
" encode_ima_adpcm_i16_u8\n" " bandpass_fir_fft_cc --fifo <fifo_path> <transition_bw> [window]\n"
" decode_ima_adpcm_u8_i16\n" " encode_ima_adpcm_s16_u8\n"
" decode_ima_adpcm_u8_s16\n"
" compress_fft_adpcm_f_u8 <fft_size>\n" " compress_fft_adpcm_f_u8 <fft_size>\n"
" flowcontrol <data_rate> <reads_per_second>\n"
" through\n"
" dsb_fc [q_value]\n"
" convert_f_samperf <wait_for_this_sample> \n"
" fmmod_fc\n"
" fixed_amplitude_cc <new_amplitude>\n"
" monos2stereo_s16\n"
" setbuf <buffer_size>\n"
" fft_exchange_sides_ff <fft_size>\n" " fft_exchange_sides_ff <fft_size>\n"
" squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>\n"
" fifo <buffer_size> <number_of_buffers>\n"
" \n" " \n"
; ;
@ -306,7 +322,7 @@ int parse_env()
envtmp=getenv("CSDR_FIXED_BUFSIZE"); envtmp=getenv("CSDR_FIXED_BUFSIZE");
if(envtmp) if(envtmp)
{ {
env_csdr_fixed_bufsize = atoi(envtmp); env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp);
} }
} }
envtmp=getenv("CSDR_PRINT_BUFSIZES"); envtmp=getenv("CSDR_PRINT_BUFSIZES");
@ -341,6 +357,94 @@ int main(int argc, char *argv[])
if(!sendbufsize(initialize_buffers())) return -2; if(!sendbufsize(initialize_buffers())) return -2;
clone_(the_bufsize); clone_(the_bufsize);
} }
#define SET_NONBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)
if(!strcmp(argv[1],"fifo"))
{
if(!sendbufsize(initialize_buffers())) return -2;
int fifo_buffer_size;
if(argc<=2) return badsyntax("need required parameter (buffer_size)");
sscanf(argv[2],"%d",&fifo_buffer_size);
int fifo_num_buffers;
if(argc<=3) return badsyntax("need required parameter (number of buffers)");
sscanf(argv[3],"%d",&fifo_num_buffers);
char** fifo_buffers = (char**)malloc(sizeof(char*)*fifo_num_buffers);
for(int i=0;i<fifo_num_buffers;i++) fifo_buffers[i]=(char*)malloc(sizeof(char)*fifo_buffer_size);
SET_NONBLOCK(STDIN_FILENO);
SET_NONBLOCK(STDOUT_FILENO);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(STDOUT_FILENO, &write_fds);
int highfd = ((STDOUT_FILENO > STDIN_FILENO) ? STDOUT_FILENO : STDIN_FILENO) + 1;
int fifo_actual_buffer_wr = fifo_num_buffers - 1;
int fifo_actual_buffer_rd = 0;
int fifo_actual_buffer_wr_pos = 0;
int fifo_actual_buffer_rd_pos = 0;
int fifo_error = 0;
int fifo_overrun_shown = 0;
for(;;)
{
select(highfd, &read_fds, NULL, NULL, NULL);
//try to read until buffer is full
if(FD_ISSET(STDIN_FILENO, &read_fds)) for(;;)
{
int read_bytes=read(STDIN_FILENO, fifo_buffers[fifo_actual_buffer_rd]+fifo_actual_buffer_rd_pos, fifo_buffer_size-fifo_actual_buffer_rd_pos);
//fprintf(stderr, "r %d %d | %d %d\n", read_bytes, fifo_buffer_size-fifo_actual_buffer_rd_pos, fifo_actual_buffer_rd, fifo_actual_buffer_rd_pos);
if(!read_bytes || ((read_bytes<0)&&(fifo_error=read_bytes)) ) break;
fifo_actual_buffer_rd_pos+=read_bytes;
if(!((fifo_actual_buffer_rd==fifo_actual_buffer_wr-1)||(fifo_actual_buffer_wr==0&&fifo_actual_buffer_rd==fifo_num_buffers-1)))
{
if(fifo_actual_buffer_rd_pos==fifo_buffer_size)
{
fifo_overrun_shown = 0;
fifo_actual_buffer_rd++;
fifo_actual_buffer_rd_pos = 0;
if(fifo_actual_buffer_rd>=fifo_num_buffers) fifo_actual_buffer_rd=0;
}
}
else
{
if(fifo_actual_buffer_rd_pos==fifo_buffer_size)
{
fifo_actual_buffer_rd_pos = 0; //rewrite same buffer
if(!fifo_overrun_shown) { fifo_overrun_shown=1; fprintf(stderr, "fifo: circular buffer full, dropping samples\n"); }
}
}
}
//try to write until buffer is empty
if(FD_ISSET(STDOUT_FILENO, &write_fds)) for(;;)
{
if(fifo_actual_buffer_wr == fifo_actual_buffer_rd) break;
int written_bytes=write(STDOUT_FILENO, fifo_buffers[fifo_actual_buffer_wr]+fifo_actual_buffer_wr_pos, fifo_buffer_size-fifo_actual_buffer_wr_pos);
//fprintf(stderr, "w %d %d | %d %d\n", written_bytes, fifo_buffer_size-fifo_actual_buffer_wr_pos, fifo_actual_buffer_wr, fifo_actual_buffer_wr_pos);
if(!written_bytes || ((written_bytes<0)&&(fifo_error=written_bytes)) ) break;
fifo_actual_buffer_wr_pos+=written_bytes;
if(fifo_actual_buffer_wr_pos==fifo_buffer_size)
{
fifo_actual_buffer_wr++;
fifo_actual_buffer_wr_pos = 0;
if(fifo_actual_buffer_wr>=fifo_num_buffers) fifo_actual_buffer_wr=0;
}
}
if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; }
}
return -1;
}
if(!strcmp(argv[1],"convert_u8_f")) if(!strcmp(argv[1],"convert_u8_f"))
{ {
@ -368,27 +472,29 @@ int main(int argc, char *argv[])
} }
if(!strcmp(argv[1],"convert_s8_f")) if(!strcmp(argv[1],"convert_s8_f"))
{ {
if(!sendbufsize(initialize_buffers())) return -2;
for(;;) for(;;)
{ {
FEOF_CHECK; FEOF_CHECK;
fread(buffer_s8, sizeof(signed char), BUFSIZE, stdin); fread((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdin);
convert_s8_f(buffer_s8, output_buffer, BUFSIZE); convert_s8_f((signed char*)buffer_u8, output_buffer, the_bufsize);
FWRITE_R; FWRITE_R;
TRY_YIELD; TRY_YIELD;
} }
} }
if(!strcmp(argv[1],"convert_f_s8")) //not tested if(!strcmp(argv[1],"convert_f_s8")) //not tested
{ {
if(!sendbufsize(initialize_buffers())) return -2;
for(;;) for(;;)
{ {
FEOF_CHECK; FEOF_CHECK;
FREAD_R; FREAD_R;
convert_f_s8(input_buffer, buffer_s8, BUFSIZE); convert_f_s8(input_buffer, (signed char*)buffer_u8, the_bufsize);
fwrite(buffer_s8, sizeof(signed char), BUFSIZE, stdout); fwrite((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdout);
TRY_YIELD; TRY_YIELD;
} }
} }
if(!strcmp(argv[1],"convert_f_i16")) if((!strcmp(argv[1],"convert_f_i16")) || (!strcmp(argv[1],"convert_f_s16")))
{ {
if(!sendbufsize(initialize_buffers())) return -2; if(!sendbufsize(initialize_buffers())) return -2;
for(;;) for(;;)
@ -400,7 +506,7 @@ int main(int argc, char *argv[])
TRY_YIELD; TRY_YIELD;
} }
} }
if(!strcmp(argv[1],"convert_i16_f")) //not tested if((!strcmp(argv[1],"convert_i16_f")) || (!strcmp(argv[1],"convert_s16_f")))
{ {
if(!sendbufsize(initialize_buffers())) return -2; if(!sendbufsize(initialize_buffers())) return -2;
for(;;) for(;;)
@ -412,6 +518,34 @@ int main(int argc, char *argv[])
TRY_YIELD; TRY_YIELD;
} }
} }
if(!strcmp(argv[1],"convert_f_s24"))
{
int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian"));
unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3);
if(!sendbufsize(initialize_buffers())) return -2;
for(;;)
{
FEOF_CHECK;
FREAD_R;
convert_f_s24(input_buffer, s24buffer, the_bufsize, bigendian);
fwrite(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"convert_s24_f"))
{
int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian"));
unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3);
if(!sendbufsize(initialize_buffers())) return -2;
for(;;)
{
FEOF_CHECK;
fread(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdin);
convert_s24_f(s24buffer, output_buffer, the_bufsize, bigendian);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"realpart_cf")) if(!strcmp(argv[1],"realpart_cf"))
{ {
if(!sendbufsize(initialize_buffers())) return -2; if(!sendbufsize(initialize_buffers())) return -2;
@ -906,11 +1040,15 @@ int main(int argc, char *argv[])
} }
else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window)); else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window));
int taps_length=firdes_filter_len(transition_bw);
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low
//fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize);
if(!initialize_buffers()) return -2; if(!initialize_buffers()) return -2;
sendbufsize(the_bufsize/factor); sendbufsize(the_bufsize/factor);
int taps_length=firdes_filter_len(transition_bw);
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
int padded_taps_length = taps_length; int padded_taps_length = taps_length;
float *taps; float *taps;
@ -1255,6 +1393,8 @@ int main(int argc, char *argv[])
FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark); FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark);
if(benchmark) fprintf(stderr," done\n"); if(benchmark) fprintf(stderr," done\n");
if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size);
float *windowt;
windowt = precalculate_window(fft_size, window);
for(;;) for(;;)
{ {
FEOF_CHECK; FEOF_CHECK;
@ -1273,7 +1413,8 @@ int main(int argc, char *argv[])
for(int i=0;i<fft_size-every_n_samples;i++) input[i]=input[i+every_n_samples]; for(int i=0;i<fft_size-every_n_samples;i++) input[i]=input[i+every_n_samples];
fread(input+fft_size-every_n_samples, sizeof(complexf), every_n_samples, stdin); fread(input+fft_size-every_n_samples, sizeof(complexf), every_n_samples, stdin);
} }
apply_window_c(input,windowed,fft_size,window); //apply_window_c(input,windowed,fft_size,window);
apply_precalculated_window_c(input,windowed,fft_size,windowt);
fft_execute(plan); fft_execute(plan);
if(octave) if(octave)
{ {
@ -1309,6 +1450,40 @@ int main(int argc, char *argv[])
} }
} }
if(!strcmp(argv[1],"logaveragepower_cf"))
{
bigbufs=1;
if(argc<=4) return badsyntax("need required parameters (add_db, table_size, avgnumber)");
float add_db=0;
int avgnumber=0;
int fft_size=0;
sscanf(argv[2],"%g",&add_db);
sscanf(argv[3],"%d",&fft_size);
sscanf(argv[4],"%d",&avgnumber);
float *input = malloc(sizeof(float)*2 * fft_size);
float *output = malloc(sizeof(float) * fft_size);
add_db -= 10.0*log10(avgnumber);
for(;;)
{
int i,n;
for(i = 0; i < fft_size; i++) {
output[i] = 0;
}
FEOF_CHECK;
for(n = 0; n < avgnumber; n++) {
fread (input, sizeof(float)*2, fft_size, stdin);
accumulate_power_cf((complexf*)input, output, fft_size);
}
log_ff(output, output, fft_size, add_db);
fwrite (output, sizeof(float), fft_size, stdout);
TRY_YIELD;
}
return 0;
}
if(!strcmp(argv[1],"fft_exchange_sides_ff")) if(!strcmp(argv[1],"fft_exchange_sides_ff"))
{ {
if(argc<=2) return badsyntax("need required parameters (fft_size)"); if(argc<=2) return badsyntax("need required parameters (fft_size)");
@ -1409,7 +1584,6 @@ int main(int argc, char *argv[])
float high_cut; float high_cut;
float transition_bw; float transition_bw;
window_t window = WINDOW_DEFAULT; window_t window = WINDOW_DEFAULT;
int fd; int fd;
if(fd=init_fifo(argc,argv)) if(fd=init_fifo(argc,argv))
{ {
@ -1485,7 +1659,7 @@ int main(int argc, char *argv[])
#ifdef USE_IMA_ADPCM #ifdef USE_IMA_ADPCM
#define IMA_ADPCM_BUFSIZE BUFSIZE #define IMA_ADPCM_BUFSIZE BUFSIZE
if(!strcmp(argv[1],"encode_ima_adpcm_i16_u8")) if( (!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))||(!strcmp(argv[1],"encode_ima_adpcm_s16_u8")) )
{ {
if(!sendbufsize(initialize_buffers()/2)) return -2; if(!sendbufsize(initialize_buffers()/2)) return -2;
ima_adpcm_state_t d; ima_adpcm_state_t d;
@ -1500,7 +1674,7 @@ int main(int argc, char *argv[])
} }
} }
if(!strcmp(argv[1],"decode_ima_adpcm_u8_i16")) if( (!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))||(!strcmp(argv[1],"decode_ima_adpcm_u8_s16")) )
{ {
ima_adpcm_state_t d; ima_adpcm_state_t d;
d.index=d.previousValue=0; d.index=d.previousValue=0;
@ -1515,7 +1689,7 @@ int main(int argc, char *argv[])
} }
} }
#endif #endif
/*
if(!strcmp(argv[1],"flowcontrol")) if(!strcmp(argv[1],"flowcontrol"))
{ {
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
@ -1537,9 +1711,9 @@ int main(int argc, char *argv[])
usleep(flowcontrol_sleep); usleep(flowcontrol_sleep);
TRY_YIELD; TRY_YIELD;
} }
}*/ }
#if 0
if(!strcmp(argv[1],"flowcontrol")) if(!strcmp(argv[1],"flowcontrol"))
{ {
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
@ -1638,6 +1812,7 @@ int main(int argc, char *argv[])
TRY_YIELD; TRY_YIELD;
} }
} }
#endif
if(!strcmp(argv[1],"through")) if(!strcmp(argv[1],"through"))
{ {
@ -1767,7 +1942,7 @@ int main(int argc, char *argv[])
} }
} }
if(!strcmp(argv[1],"mono2stereo_i16")) if((!strcmp(argv[1],"mono2stereo_i16"))||(!strcmp(argv[1],"mono2stereo_s16")))
{ {
if(!sendbufsize(initialize_buffers())) return -2; if(!sendbufsize(initialize_buffers())) return -2;
float last_phase = 0; float last_phase = 0;
@ -1785,6 +1960,59 @@ int main(int argc, char *argv[])
} }
} }
if(!strcmp(argv[1],"squelch_and_smeter_cc"))
{
if(!sendbufsize(initialize_buffers())) return -2;
float power;
float squelch_level;
int decimation;
int report_every_nth;
int fd;
char power_value_buf[101];
int power_value_buf_size;
int report_cntr=0;
complexf* zerobuf = (complexf*)malloc(sizeof(complexf)*the_bufsize);
for(int i=0;i<the_bufsize*2;i++) *(((float*)zerobuf)+i)=0;
if(fd=init_fifo(argc,argv)) while(!read_fifo_ctl(fd,"%g\n",&squelch_level)) usleep(10000);
else return badsyntax("need required parameter (--fifo <fifo>)");
fprintf(stderr, "squelch_and_power_cc: initial squelch level is %g\n", squelch_level);
if((argc<=5)||((argc>5)&&(strcmp(argv[4],"--outfifo")))) return badsyntax("need required parameter (--outfifo <fifo>)");
int fd2 = open(argv[5], O_WRONLY);
if(fd2==-1) return badsyntax("error while opening --outfifo");
int flags = fcntl(fd2, F_GETFL, 0);
fcntl(fd2, F_SETFL, flags | O_NONBLOCK);
if(argc<=6) return badsyntax("need required parameter (use_every_nth)");
sscanf(argv[6],"%d",&decimation);
if(decimation<=0) return badsyntax("use_every_nth <= 0 is invalid");
if(argc<=7) return badsyntax("need required parameter (report_every_nth)");
sscanf(argv[7],"%d",&report_every_nth);
if(report_every_nth<=0) return badsyntax("report_every_nth <= 0 is invalid");
for(;;)
{
FEOF_CHECK;
FREAD_C; //read input data
power = get_power_c((complexf*)input_buffer, the_bufsize, decimation);
if(report_cntr++>report_every_nth)
{
report_cntr=0;
power_value_buf_size=snprintf(power_value_buf,100,"%g\n",power);
write(fd2,power_value_buf,power_value_buf_size*sizeof(char));
}
if(squelch_level==0||power>=squelch_level)
{
//fprintf(stderr,"P");
fwrite(input_buffer, sizeof(complexf), the_bufsize, stdout);
}
else
{
//fprintf(stderr,"S");
fwrite(zerobuf, sizeof(complexf), the_bufsize, stdout);
}
if(read_fifo_ctl(fd,"%g\n",&squelch_level)) fprintf(stderr, "squelch_and_power_cc: new squelch level is %g\n", squelch_level);
TRY_YIELD;
}
}
if( !strcmp(argv[1],"fastddc_fwd_cc") ) //<decimation> [transition_bw [window]] if( !strcmp(argv[1],"fastddc_fwd_cc") ) //<decimation> [transition_bw [window]]
{ {
@ -1942,9 +2170,5 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]); fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]); return -1;
return -1;
} }

108
libcsdr.c
View file

@ -941,7 +941,7 @@ complexf fmdemod_quadri_cf(complexf* input, float* output, int input_size, float
} }
for (int i=0; i<input_size; i++) //@fmdemod_quadri_cf: output division for (int i=0; i<input_size; i++) //@fmdemod_quadri_cf: output division
{ {
output[i]=fmdemod_quadri_K*output[i]/temp[i]; output[i]=(temp[i])?fmdemod_quadri_K*output[i]/temp[i]:0;
} }
return input[input_size-1]; return input[input_size-1];
@ -1018,6 +1018,26 @@ void gain_ff(float* input, float* output, int input_size, float gain)
for(int i=0;i<input_size;i++) output[i]=gain*input[i]; //@gain_ff for(int i=0;i<input_size;i++) output[i]=gain*input[i]; //@gain_ff
} }
float get_power_f(float* input, int input_size, int decimation)
{
float acc = 0;
for(int i=0;i<input_size;i+=decimation)
{
acc += (input[i]*input[i])/input_size;
}
return acc;
}
float get_power_c(complexf* input, int input_size, int decimation)
{
float acc = 0;
for(int i=0;i<input_size;i+=decimation)
{
acc += (iof(input,i)*iof(input,i)+qof(input,i)*qof(input,i))/input_size;
}
return acc;
}
/* /*
__ __ _ _ _ __ __ _ _ _
| \/ | | | | | | | | \/ | | | | | | |
@ -1110,6 +1130,29 @@ void apply_window_c(complexf* input, complexf* output, int size, window_t window
} }
} }
float *precalculate_window(int size, window_t window)
{
float (*window_function)(float)=firdes_get_window_kernel(window);
float *windowt;
windowt = malloc(sizeof(float) * size);
for(int i=0;i<size;i++) //@precalculate_window
{
float rate=(float)i/(size-1);
windowt[i] = window_function(2.0*rate+1.0);
}
return windowt;
}
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt)
{
for(int i=0;i<size;i++) //@apply_precalculated_window_c
{
iof(output,i)=iof(input,i)*windowt[i];
qof(output,i)=qof(input,i)*windowt[i];
}
}
void apply_window_f(float* input, float* output, int size, window_t window) void apply_window_f(float* input, float* output, int size, window_t window)
{ {
float (*window_function)(float)=firdes_get_window_kernel(window); float (*window_function)(float)=firdes_get_window_kernel(window);
@ -1129,6 +1172,19 @@ void logpower_cf(complexf* input, float* output, int size, float add_db)
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3 for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
} }
void accumulate_power_cf(complexf* input, float* output, int size)
{
for(int i=0;i<size;i++) output[i] += iof(input,i)*iof(input,i) + qof(input,i)*qof(input,i); //@logpower_cf: pass 1
}
void log_ff(float* input, float* output, int size, float add_db) {
for(int i=0;i<size;i++) output[i]=log10(input[i]); //@logpower_cf: pass 2
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
}
/* /*
_____ _ _ _____ _ _
| __ \ | | (_) | __ \ | | (_)
@ -1149,9 +1205,9 @@ void convert_s8_f(signed char* input, float* output, int input_size)
for(int i=0;i<input_size;i++) output[i]=((float)input[i])/SCHAR_MAX; //@convert_s8_f for(int i=0;i<input_size;i++) output[i]=((float)input[i])/SCHAR_MAX; //@convert_s8_f
} }
void convert_i16_f(short* input, float* output, int input_size) void convert_s16_f(short* input, float* output, int input_size)
{ {
for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_i16_f for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_s16_f
} }
void convert_f_u8(float* input, unsigned char* output, int input_size) void convert_f_u8(float* input, unsigned char* output, int input_size)
@ -1166,16 +1222,56 @@ void convert_f_s8(float* input, signed char* output, int input_size)
for(int i=0;i<input_size;i++) output[i]=input[i]*SCHAR_MAX; //@convert_f_s8 for(int i=0;i<input_size;i++) output[i]=input[i]*SCHAR_MAX; //@convert_f_s8
} }
void convert_f_i16(float* input, short* output, int input_size) void convert_f_s16(float* input, short* output, int input_size)
{ {
/*for(int i=0;i<input_size;i++) /*for(int i=0;i<input_size;i++)
{ {
if(input[i]>1.0) input[i]=1.0; if(input[i]>1.0) input[i]=1.0;
if(input[i]<-1.0) input[i]=-1.0; if(input[i]<-1.0) input[i]=-1.0;
}*/ }*/
for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_i16 for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_s16
} }
void convert_i16_f(short* input, float* output, int input_size) { convert_s16_f(input, output, input_size); }
void convert_f_i16(float* input, short* output, int input_size) { convert_f_s16(input, output, input_size); }
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian)
{
int k=0;
if(bigendian) for(int i=0;i<input_size;i++)
{
int temp=input[i]*(INT_MAX>>8);
unsigned char* ptemp=(unsigned char*)&temp;
output[k++]=*ptemp;
output[k++]=*(ptemp+1);
output[k++]=*(ptemp+2);
}
else for(int i=0;i<input_size;i++)
{
int temp=input[i]*(INT_MAX>>8);
unsigned char* ptemp=(unsigned char*)&temp;
output[k++]=*(ptemp+2);
output[k++]=*(ptemp+1);
output[k++]=*ptemp;
}
}
void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian)
{
int k=0;
if(bigendian) for(int i=0;i<input_size*3;i+=3)
{
int temp=(input[i+2]<<24)|(input[i+1]<<16)|(input[i]<<8);
output[k++]=temp/(float)(INT_MAX-256);
}
else for(int i=0;i<input_size*3;i+=3)
{
int temp=(input[i+2]<<8)|(input[i+1]<<16)|(input[i]<<24);
output[k++]=temp/(float)(INT_MAX-256);
}
}
int trivial_vectorize() int trivial_vectorize()
{ {
//this function is trivial to vectorize and should pass on both NEON and SSE //this function is trivial to vectorize and should pass on both NEON and SSE
@ -1186,5 +1282,3 @@ int trivial_vectorize()
} }
return c[0]; return c[0];
} }

View file

@ -137,9 +137,13 @@ typedef struct rational_resampler_ff_s
rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay); rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay);
void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window); void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window);
float *precalculate_window(int size, window_t window);
void apply_window_c(complexf* input, complexf* output, int size, window_t window); void apply_window_c(complexf* input, complexf* output, int size, window_t window);
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt);
void apply_window_f(float* input, float* output, int size, window_t window); void apply_window_f(float* input, float* output, int size, window_t window);
void logpower_cf(complexf* input, float* output, int size, float add_db); void logpower_cf(complexf* input, float* output, int size, float add_db);
void accumulate_power_cf(complexf* input, float* output, int size);
void log_ff(float* input, float* output, int size, float add_db);
typedef struct fractional_decimator_ff_s typedef struct fractional_decimator_ff_s
{ {
@ -182,6 +186,8 @@ int log2n(int x);
int next_pow2(int x); int next_pow2(int x);
void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size); void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size);
void gain_ff(float* input, float* output, int input_size, float gain); void gain_ff(float* input, float* output, int input_size, float gain);
float get_power_f(float* input, int input_size, int decimation);
float get_power_c(complexf* input, int input_size, int decimation);
void add_dcoffset_cc(complexf* input, complexf* output, int input_size); void add_dcoffset_cc(complexf* input, complexf* output, int input_size);
float fmmod_fc(float* input, complexf* output, int input_size, float last_phase); float fmmod_fc(float* input, complexf* output, int input_size, float last_phase);
@ -191,7 +197,12 @@ void convert_u8_f(unsigned char* input, float* output, int input_size);
void convert_f_u8(float* input, unsigned char* output, int input_size); void convert_f_u8(float* input, unsigned char* output, int input_size);
void convert_s8_f(signed char* input, float* output, int input_size); void convert_s8_f(signed char* input, float* output, int input_size);
void convert_f_s8(float* input, signed char* output, int input_size); void convert_f_s8(float* input, signed char* output, int input_size);
void convert_f_s16(float* input, short* output, int input_size);
void convert_s16_f(short* input, float* output, int input_size);
void convert_f_i16(float* input, short* output, int input_size); void convert_f_i16(float* input, short* output, int input_size);
void convert_i16_f(short* input, float* output, int input_size); void convert_i16_f(short* input, float* output, int input_size);
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian);
void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian);
int is_nan(float f); int is_nan(float f);

View file

@ -219,10 +219,9 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
} }
gain=gain+dgain; gain=gain+dgain;
//fprintf(stderr,"g=%f dg=%f\n",gain,dgain); //fprintf(stderr,"g=%f dg=%f\n",gain,dgain);
if(gain>max_gain) gain=max_gain; //We also have to limit our gain, it can't be infinity.
if(gain<0) gain=0;
} }
if(gain>max_gain) gain=max_gain; //We also have to limit our gain, it can't be infinity.
if(gain<0) gain=0;
//output[i]=gain*input[i]; //Here we do the actual scaling of the samples. //output[i]=gain*input[i]; //Here we do the actual scaling of the samples.
//Here we do the actual scaling of the samples, but we run an IIR filter on the gain values: //Here we do the actual scaling of the samples, but we run an IIR filter on the gain values:
output[i]=(gain=gain+last_gain-gain_filter_alpha*last_gain)*input[i]; //dc-pass-filter: freqz([1 -1],[1 -0.99]) y[i]=x[i]+y[i-1]-alpha*x[i-1] output[i]=(gain=gain+last_gain-gain_filter_alpha*last_gain)*input[i]; //dc-pass-filter: freqz([1 -1],[1 -0.99]) y[i]=x[i]+y[i-1]-alpha*x[i-1]
@ -234,4 +233,3 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
} }
#endif #endif