Added new features, e.g. the IMA ADPCM codec and sdr.js

This commit is contained in:
ha7ilm 2015-08-16 23:40:42 +02:00
parent 46468973d8
commit c50ffaac1b
17 changed files with 2673 additions and 246 deletions

View file

@ -38,9 +38,10 @@ PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optim
PARAMS_ARM = $(if $(call cpufeature,BCM2708,dummy-text),$(PARAMS_RASPI),$(PARAMS_NEON))
PARAMS_SIMD = $(if $(call cpufeature,sse,dummy-text),$(PARAMS_SSE),$(PARAMS_ARM))
PARAMS_LOOPVECT = -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect
PARAMS_LIBS = -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL
PARAMS_LIBS = -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM
PARAMS_SO = -fpic
PARAMS_MISC = -Wno-unused-result
FFTW_PACKAGE = fftw-3.3.3
all: clean-vect
@echo NOTE: you may have to manually edit Makefile to optimize for your CPU \(especially if you compile on ARM, please edit PARAMS_NEON\).
@ -64,3 +65,22 @@ install:
uninstall:
rm /usr/lib/libcsdr.so /usr/bin/csdr /usr/bin/csdr-fm
ldconfig
emcc-clean:
-rm sdr.js/sdr.js
-rm sdr.js/sdrjs-compiled.js
-rm -rf sdr.js/$(FFTW_PACKAGE)
emcc-get-deps:
echo "getting and compiling fftw3 with emscripten..."
cd sdr.js; \
wget http://fftw.org/$(FFTW_PACKAGE).tar.gz; \
tar -xvf $(FFTW_PACKAGE).tar.gz; \
rm $(FFTW_PACKAGE).tar.gz; \
cd $(FFTW_PACKAGE); \
emconfigure ./configure --enable-float --disable-fortran --prefix=`pwd`/emscripten-install --libdir=`pwd`/emscripten-lib; \
emmake make; \
emmake make install
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`"
cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js
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'

View file

@ -10,6 +10,8 @@ Most of the code is available under the permissive BSD license, with some option
- The code of *libcsdr* was intended to be easy to follow.
- *libcsdr* was designed to use auto-vectorization available in *gcc*. It means that it can achieve some speedup by taking advantage of SIMD command sets available in today's CPUs (e.g. SSE on x86 and NEON on ARM).
Moreover, *libcsdr* serves as the base for the new, experimental <a href="#sdr.js">sdr.js</a>, which takes Software Defined Radio DSP to today's web browsers that provide JavScript JIT compilation.
How to compile
--------------
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
@ -155,15 +157,33 @@ It multiplies all samples by `gain`.
It copies the input to the output.
none
The `csdr` process just exits with 0.
yes_f <to_repeat> [buf_times]
It outputs continously the `to_repeat` float number.
If `buf_times` is not given, it never stops.
Else, after outputing `buf_times` number of buffers (the size of which is stated in the `BUFSIZE` macro), it exits.
detect_nan_ff
Along with copying its input samples to the output, it prints a warning message to *stderr* if it finds any IEEE floating point NaN values among the samples.
floatdump_f
It prints any floating point input samples.
The format string used is `"%g "`.
flowcontrol <data_rate> <reads_per_second>
It limits the data rate of a stream to a given `data_rate` number of bytes per second.
It copies `data_rate / reads_per_second` bytes from the input to the output, doing it `reads_per_second` times every second.
shift_math_cc <rate>
It shifts the complex spectrum by `rate`.
It shifts the signal in the frequency domain by `rate`.
`rate` is a floating point number between -0.5 and 0.5.
`rate` is relative to the sampling rate.
@ -179,6 +199,17 @@ Internally, this function uses trigonometric addition formulas to generate sine
This function was used to test the accuracy of the method above.
shift_table_cc <rate> [table_size]
Operation is the same as with `shift_math_cc`.
Internally, this function uses a look-up table (LUT) to recall the values of the sine function (for the first quadrant).
The higher the table size is, the smaller the phase error is.
decimating_shift_addition_cc <rate> [decimation]
It shifts the input signal in the frequency domain, and also decimates it, without filtering. It will be useful as a part of the FFT channelizer implementation (to be done).
It cannot be used as a channelizer by itself, use `fir_decimate_cc` instead.
dcblock_ff
This is a DC blocking IIR filter.
@ -214,7 +245,7 @@ It uses fixed filters so it works only on predefined sample rates, for the actua
It is an AM demodulator that uses `sqrt`. On some architectures `sqrt` can be directly calculated by dedicated CPU instructions, but on others it may be slower.
amdemod_estimator_cf
amdemod_estimator_cf
It is an AM demodulator that uses an estimation method that is faster but less accurate than `amdemod_cf`.
@ -296,10 +327,28 @@ FFTW can be faster if we let it optimalize a while before starting the first tra
It measures the time taken to process `fft_cycles` transforms of `fft_size`.
It lets FFTW optimalize if used with the `--benchmark` switch.
lowpower_cf [add_db]
logpower_cf [add_db]
Calculates `10*log10(i^2+q^2)+add_db` for the input complex samples. It is useful for drawing power spectrum graphs.
encode_ima_adpcm_i16_u8
Encodes the audio stream to IMA ADPCM, which decreases the size to 25% of the original.
decode_ima_adpcm_u8_i16
Decodes the audio stream from IMA ADPCM.
compress_fft_adpcm_f_u8 <fft_size>
Encodes the FFT output vectors of `fft_size`. It should be used on the data output from `logpower_cf`.
It resets the ADPCM encoder at the beginning of every vector, and to compensate it, `COMPRESS_FFT_PAD_N` samples are added at beginning (these equal to the first relevant sample).
The actual number of padding samples can be determined by running `cat csdr.c | grep "define COMPRESS_FFT_PAD_N"`.
fft_exchange_sides_ff <fft_size>
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`.
#### Control via pipes
Some parameters can be changed while the `csdr` process is running. To achieve this, some `csdr` functions have special parameters. You have to supply a fifo previously created by the `mkfifo` command. Processing will only start after the first control command has been received by `csdr` over the FIFO.
@ -326,6 +375,28 @@ E.g. you can send `-0.05 0.02\n`
`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.
## [sdr.js] (#sdr.js)
*sdr.js* is *libcsdr* compiled to JavaScript code with *Emscripten*. Nowadays JavaScript runs quite fast in browsers, as all major browser vendors included JavaScript JIT machines into their product. You can find a <a href="https://kripken.github.io/mloc_emscripten_talk/cppcon.html">great introductory slideshow here</a> about *Emscripten*.
The purpose of *sdr.js* is to make SDR DSP processing available in the web browser. However, it is not easy to use in production yet. By now, only those functions have wrappers that the front-end of OpenWebRX uses.
To compile *sdr.js*, you will need <a href="http://emscripten.org/">emscripten</a>. (It turns out that *emscripten* is already included in Ubuntu repositories.)
To install and build dependencies (for now, only FFTW3):
make emcc-get-deps
To compile *sdr.js* (which will be created in the `sdr.js` subdirectory):
make emcc
You can test *sdr.js* by opening *sdr.html*. It contains a test for *firdes_lowpass_f* for this time.
To remove *sdr.js* and the compiled dependencies:
make emcc-clean
## [Licensing] (#licensing)
Most of the code of `libcsdr` is under BSD license.

263
csdr.c
View file

@ -44,6 +44,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include "libcsdr.h"
#include "libcsdr_gpl.h"
#include "ima_adpcm.h"
#include <sched.h>
#include <math.h>
char usage[]=
"csdr - a simple commandline tool for Software Defined Radio receiver DSP.\n\n"
@ -59,10 +62,16 @@ char usage[]=
" limit_ff [max_amplitude]\n"
" gain_ff <gain>\n"
" clone\n"
" none\n"
" yes_f <to_repeat> [buf_times]\n"
" detect_nan_ff\n"
" floatdump_f\n"
" flowcontrol <data_rate> <reads_per_second>\n"
" shift_math_cc <rate>\n"
" shift_addition_cc <rate>\n"
" shift_addition_cc_test\n"
" shift_table_cc <rate> [table_size]\n"
" decimating_shift_addition_cc <rate> [decimation]\n"
" dcblock_ff\n"
" fastdcblock_ff\n"
" fmdemod_atan_cf\n"
@ -83,12 +92,22 @@ char usage[]=
" logpower_cf [add_db]\n"
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
" encode_ima_adpcm_i16_u8\n"
" decode_ima_adpcm_u8_i16\n"
" compress_fft_adpcm_f_u8 <fft_size>\n"
" fft_exchange_sides_ff <fft_size>\n"
" \n"
;
#define BUFSIZE (1024*8)
#define BUFSIZE (1024)
#define BIG_BUFSIZE (1024*16)
//should be multiple of 16! (size of double complex)
//also, keep in mind that shift_addition_cc works better the smaller this buffer is.
#define YIELD_EVERY_N_TIMES 3
#define TRY_YIELD if(++yield_counter%YIELD_EVERY_N_TIMES==0) sched_yield()
unsigned yield_counter=0;
int badsyntax(char* why)
{
if(why==0) fprintf(stderr, "%s", usage);
@ -113,6 +132,7 @@ int clone()
{
fread(clone_buffer, sizeof(unsigned char), BUFSIZE, stdin);
fwrite(clone_buffer, sizeof(unsigned char), BUFSIZE, stdout);
TRY_YIELD;
}
}
@ -121,6 +141,8 @@ int clone()
#define FWRITE_R fwrite(output_buffer, sizeof(float), BUFSIZE, stdout)
#define FWRITE_C fwrite(output_buffer, sizeof(float)*2, BUFSIZE, stdout)
#define FEOF_CHECK if(feof(stdin)) return 0
#define BIG_FREAD_C fread(input_buffer, sizeof(float)*2, BIG_BUFSIZE, stdin)
#define BIG_FWRITE_C fwrite(output_buffer, sizeof(float)*2, BIG_BUFSIZE, stdout)
int init_fifo(int argc, char *argv[])
{
@ -180,11 +202,11 @@ int read_fifo_ctl(int fd, char* format, ...)
int main(int argc, char *argv[])
{
static float input_buffer[BUFSIZE*2];
static unsigned char buffer_u8[BUFSIZE*2];
static float output_buffer[BUFSIZE*2];
static short buffer_i16[BUFSIZE*2];
static float temp_f[BUFSIZE*4];
static float input_buffer[BIG_BUFSIZE*2];
static unsigned char buffer_u8[BIG_BUFSIZE*2];
static float output_buffer[BIG_BUFSIZE*2];
static short buffer_i16[BIG_BUFSIZE*2];
static float temp_f[BIG_BUFSIZE*4];
if(argc<=1) return badsyntax(0);
if(!strcmp(argv[1],"--help")) return badsyntax(0);
if(!strcmp(argv[1],"convert_u8_f"))
@ -195,6 +217,7 @@ int main(int argc, char *argv[])
fread(buffer_u8, sizeof(unsigned char), BUFSIZE, stdin);
convert_u8_f(buffer_u8, output_buffer, BUFSIZE);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"convert_f_u8")) //not tested
@ -205,6 +228,7 @@ int main(int argc, char *argv[])
FREAD_R;
convert_f_u8(input_buffer, buffer_u8, BUFSIZE);
fwrite(buffer_u8, sizeof(unsigned char), BUFSIZE, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"convert_f_i16"))
@ -215,6 +239,7 @@ int main(int argc, char *argv[])
FREAD_R;
convert_f_i16(input_buffer, buffer_i16, BUFSIZE);
fwrite(buffer_i16, sizeof(short), BUFSIZE, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"convert_i16_f")) //not tested
@ -225,6 +250,7 @@ int main(int argc, char *argv[])
fread(buffer_i16, sizeof(short), BUFSIZE, stdin);
convert_i16_f(buffer_i16, output_buffer, BUFSIZE);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"realpart_cf"))
@ -235,6 +261,7 @@ int main(int argc, char *argv[])
FREAD_C;
for(int i=0;i<BUFSIZE;i++) output_buffer[i]=iof(input_buffer,i);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"clipdetect_ff"))
@ -245,6 +272,7 @@ int main(int argc, char *argv[])
FREAD_R;
clipdetect_ff(input_buffer, BUFSIZE);
fwrite(input_buffer, sizeof(float), BUFSIZE, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"gain_ff"))
@ -258,6 +286,7 @@ int main(int argc, char *argv[])
FREAD_R;
gain_ff(input_buffer, output_buffer, BUFSIZE, gain);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"clone"))
@ -274,6 +303,7 @@ int main(int argc, char *argv[])
FREAD_R;
limit_ff(input_buffer, output_buffer, BUFSIZE, max_amplitude);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"yes_f"))
@ -284,7 +314,11 @@ int main(int argc, char *argv[])
int buf_times = 0;
if(argc>=4) sscanf(argv[3],"%d",&buf_times);
for(int i=0;i<BUFSIZE;i++) output_buffer[i]=to_repeat;
for(int i=0;(!buf_times)||i<buf_times;i++) fwrite(output_buffer, sizeof(float), BUFSIZE, stdout);
for(int i=0;(!buf_times)||i<buf_times;i++)
{
fwrite(output_buffer, sizeof(float), BUFSIZE, stdout);
TRY_YIELD;
}
return 0;
}
if(!strcmp(argv[1],"shift_math_cc"))
@ -299,13 +333,60 @@ int main(int argc, char *argv[])
if(!FREAD_C) break;
starting_phase=shift_math_cc((complexf*)input_buffer, (complexf*)output_buffer, BUFSIZE, rate, starting_phase);
FWRITE_C;
TRY_YIELD;
}
return 0;
}
//speed tests:
//csdr yes_f 1 1000000 | time csdr shift_math_cc 0.2 >/dev/null
//csdr yes_f 1 1000000 | time csdr shift_addition_cc 0.2 >/dev/null
//csdr yes_f 1 1000000 | time csdr shift_table_cc 0.2 >/dev/null
if(!strcmp(argv[1],"shift_table_cc"))
{
if(argc<=2) return badsyntax("need required parameter (rate)");
float starting_phase=0;
float rate;
int table_size=65536;
sscanf(argv[2],"%g",&rate);
if(argc>3) sscanf(argv[3],"%d",&table_size);
shift_table_data_t table_data=shift_table_init(table_size);
fprintf(stderr,"shift_table_cc: LUT initialized\n");
for(;;)
{
FEOF_CHECK;
if(!BIG_FREAD_C) break;
starting_phase=shift_table_cc((complexf*)input_buffer, (complexf*)output_buffer, BIG_BUFSIZE, rate, table_data, starting_phase);
BIG_FWRITE_C;
TRY_YIELD;
}
return 0;
}
#ifdef LIBCSDR_GPL
if(!strcmp(argv[1],"decimating_shift_addition_cc"))
{
if(argc<=2) return badsyntax("need required parameter (rate)");
float starting_phase=0;
float rate;
int decimation=1;
sscanf(argv[2],"%g",&rate);
if(argc>3) sscanf(argv[3],"%d",&decimation);
shift_addition_data_t d=decimating_shift_addition_init(rate, decimation);
decimating_shift_addition_status_t s;
s.decimation_remain=0;
s.starting_phase=0;
for(;;)
{
FEOF_CHECK;
if(!BIG_FREAD_C) break;
s=decimating_shift_addition_cc((complexf*)input_buffer, (complexf*)output_buffer, BIG_BUFSIZE, d, decimation, s);
fwrite(output_buffer, sizeof(float)*2, s.output_size, stdout);
TRY_YIELD;
}
return 0;
}
if(!strcmp(argv[1],"shift_addition_cc"))
{
float starting_phase=0;
@ -329,10 +410,11 @@ int main(int argc, char *argv[])
for(;;)
{
FEOF_CHECK;
if(!FREAD_C) break;
starting_phase=shift_addition_cc((complexf*)input_buffer, (complexf*)output_buffer, BUFSIZE, data, starting_phase);
FWRITE_C;
if(!BIG_FREAD_C) break;
starting_phase=shift_addition_cc((complexf*)input_buffer, (complexf*)output_buffer, BIG_BUFSIZE, data, starting_phase);
BIG_FWRITE_C;
if(read_fifo_ctl(fd,"%g\n",&rate)) break;
TRY_YIELD;
}
}
return 0;
@ -357,6 +439,7 @@ int main(int argc, char *argv[])
FREAD_R;
dcp=dcblock_ff(input_buffer, output_buffer, BUFSIZE, 0, dcp);
FWRITE_R;
TRY_YIELD;
}
}
@ -372,6 +455,7 @@ int main(int argc, char *argv[])
fread(dcblock_buffer, sizeof(float), dcblock_bufsize, stdin);
last_dc_level=fastdcblock_ff(dcblock_buffer, dcblock_buffer, dcblock_bufsize, last_dc_level);
fwrite(dcblock_buffer, sizeof(float), dcblock_bufsize, stdout);
TRY_YIELD;
}
}
@ -385,6 +469,7 @@ int main(int argc, char *argv[])
if(feof(stdin)) return 0;
last_phase=fmdemod_atan_cf((complexf*)input_buffer, output_buffer, BUFSIZE, last_phase);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"fmdemod_quadri_cf"))
@ -398,6 +483,7 @@ int main(int argc, char *argv[])
FREAD_C;
last_sample=fmdemod_quadri_cf((complexf*)input_buffer, output_buffer, BUFSIZE, temp_f, last_sample);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"fmdemod_quadri_novect_cf"))
@ -411,6 +497,7 @@ int main(int argc, char *argv[])
FREAD_C;
last_sample=fmdemod_quadri_novect_cf((complexf*)input_buffer, output_buffer, BUFSIZE, last_sample);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"deemphasis_wfm_ff"))
@ -421,7 +508,6 @@ int main(int argc, char *argv[])
float tau;
sscanf(argv[3],"%g",&tau);
fprintf(stderr,"deemphasis_wfm_ff: tau = %g, sample_rate = %d\n",tau,sample_rate);
float last_output=0;
for(;;)
{
@ -429,8 +515,42 @@ int main(int argc, char *argv[])
FREAD_R;
last_output=deemphasis_wfm_ff(input_buffer, output_buffer, BUFSIZE, tau, sample_rate, last_output);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"detect_nan_ff"))
{
for(;;)
{
FEOF_CHECK;
FREAD_R;
int nan_detect=0;
for(int i=0; i<BUFSIZE;i++)
{
if(is_nan(input_buffer[i]))
{
nan_detect=1;
break;
}
}
if(nan_detect) fprintf(stderr, "detect_nan_f: NaN detected!\n");
fwrite(input_buffer, sizeof(float), BUFSIZE, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"floatdump_f"))
{
for(;;)
{
FEOF_CHECK;
FREAD_R;
for(int i=0; i<BUFSIZE;i++) fprintf(stderr, "%g ",input_buffer[i]);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"deemphasis_nfm_ff"))
{
if(argc<=2) return badsyntax("need required parameter (sample rate)");
@ -446,6 +566,7 @@ int main(int argc, char *argv[])
if(!processed) return badsyntax("deemphasis_nfm_ff: invalid sample rate (this function works only with specific sample rates).");
memmove(input_buffer,input_buffer+processed,(BUFSIZE-processed)*sizeof(float)); //memmove lets the source and destination overlap
fwrite(output_buffer, sizeof(float), processed, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"amdemod_cf"))
@ -456,6 +577,7 @@ int main(int argc, char *argv[])
FREAD_C;
amdemod_cf((complexf*)input_buffer, output_buffer, BUFSIZE);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"amdemod_estimator_cf"))
@ -466,6 +588,7 @@ int main(int argc, char *argv[])
FREAD_C;
amdemod_estimator_cf((complexf*)input_buffer, output_buffer, BUFSIZE, 0., 0.);
FWRITE_R;
TRY_YIELD;
}
}
if(!strcmp(argv[1],"fir_decimate_cc"))
@ -496,13 +619,14 @@ int main(int argc, char *argv[])
for(;;)
{
FEOF_CHECK;
output_size=fir_decimate_cc((complexf*)input_buffer, (complexf*)output_buffer, BUFSIZE, factor, taps, taps_length);
output_size=fir_decimate_cc((complexf*)input_buffer, (complexf*)output_buffer, BIG_BUFSIZE, factor, taps, taps_length);
fwrite(output_buffer, sizeof(complexf), output_size, stdout);
fflush(stdout);
TRY_YIELD;
input_skip=factor*output_size;
memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(BUFSIZE-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap
fread(((complexf*)input_buffer)+(BUFSIZE-input_skip), sizeof(complexf), input_skip, stdin);
//fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BUFSIZE-input_skip),(BUFSIZE-input_skip));
memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(BIG_BUFSIZE-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap
fread(((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip), sizeof(complexf), input_skip, stdin);
//fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip));
}
}
/*if(!strcmp(argv[1],"ejw_test"))
@ -639,6 +763,7 @@ int main(int argc, char *argv[])
FREAD_R;
last_gain=agc_ff(input_buffer, output_buffer, BUFSIZE, reference, attack_rate, decay_rate, max_gain, hang_time, attack_wait, filter_alpha, last_gain);
FWRITE_R;
TRY_YIELD;
}
}
#endif
@ -663,6 +788,7 @@ int main(int argc, char *argv[])
fread(input.buffer_input, sizeof(float), input.input_size, stdin);
fastagc_ff(&input, agc_output_buffer);
fwrite(agc_output_buffer, sizeof(float), input.input_size, stdout);
TRY_YIELD;
}
}
@ -715,6 +841,7 @@ int main(int argc, char *argv[])
d=rational_resampler_ff(input_buffer, resampler_output_buffer, BUFSIZE, interpolation, decimation, taps, taps_length, d.last_taps_delay);
//fprintf(stderr,"resampled %d %d, %d\n",d.output_size, d.input_processed, d.input_processed);
fwrite(resampler_output_buffer, sizeof(float), d.output_size, stdout);
TRY_YIELD;
}
}
@ -754,6 +881,7 @@ int main(int argc, char *argv[])
fread(input_buffer+(BUFSIZE-d.input_processed), sizeof(float), d.input_processed, stdin);
d = fractional_decimator_ff(input_buffer, output_buffer, BUFSIZE, rate, taps, taps_length, d);
fwrite(output_buffer, sizeof(float), d.output_size, stdout);
TRY_YIELD;
}
}
@ -823,6 +951,7 @@ int main(int argc, char *argv[])
);
}
else fwrite(output, sizeof(complexf), fft_size, stdout);
TRY_YIELD;
}
}
#define LOGPOWERCF_BUFSIZE 64
@ -837,10 +966,60 @@ int main(int argc, char *argv[])
fread(input_buffer, sizeof(complexf), LOGPOWERCF_BUFSIZE, stdin);
logpower_cf((complexf*)input_buffer,output_buffer,LOGPOWERCF_BUFSIZE,add_db);
fwrite(output_buffer, sizeof(float), LOGPOWERCF_BUFSIZE, stdout);
//bufsize is so small, I don't dare to TRY_YIELD
}
}
if(!strcmp(argv[1],"fft_exchange_sides_ff"))
{
if(argc<=2) return badsyntax("need required parameters (fft_size)");
int fft_size;
sscanf(argv[2],"%d",&fft_size);
float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2);
float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2);
for(;;)
{
FEOF_CHECK;
fread(input_buffer_s1, sizeof(float), fft_size/2, stdin);
fread(input_buffer_s2, sizeof(float), fft_size/2, stdin);
fwrite(input_buffer_s2, sizeof(float), fft_size/2, stdout);
fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout);
TRY_YIELD;
}
}
#ifdef USE_IMA_ADPCM
#define COMPRESS_FFT_PAD_N 10
//We will pad the FFT at the beginning, with the first value of the input data, COMPRESS_FFT_PAD_N times.
//No, this is not advanced DSP, just the ADPCM codec produces some gabarge samples at the beginning,
//so we just add data to become garbage and get skipped.
//COMPRESS_FFT_PAD_N should be even.
if(!strcmp(argv[1],"compress_fft_adpcm_f_u8"))
{
if(argc<=2) return badsyntax("need required parameters (fft_size)");
int fft_size;
sscanf(argv[2],"%d",&fft_size);
int real_data_size=fft_size+COMPRESS_FFT_PAD_N;
float* input_buffer_cwa = (float*)malloc(sizeof(float)*real_data_size);
short* temp_buffer_cwa = (short*)malloc(sizeof(short)*real_data_size);
unsigned char* output_buffer_cwa = (unsigned char*)malloc(sizeof(unsigned char)*(real_data_size/2));
ima_adpcm_state_t d;
d.index=d.previousValue=0;
for(;;)
{
FEOF_CHECK;
fread(input_buffer_cwa+COMPRESS_FFT_PAD_N, sizeof(float), fft_size, stdin);
for(int i=0;i<COMPRESS_FFT_PAD_N;i++) input_buffer_cwa[i]=input_buffer_cwa[COMPRESS_FFT_PAD_N]; //do padding
for(int i=0;i<real_data_size;i++) temp_buffer_cwa[i]=input_buffer_cwa[i]*100; //convert float dB values to short
encode_ima_adpcm_i16_u8(temp_buffer_cwa, output_buffer_cwa, real_data_size, d); //we always return to original d at any new buffer
fwrite(output_buffer_cwa, sizeof(unsigned char), real_data_size/2, stdout);
TRY_YIELD;
}
}
#endif
#define TIME_TAKEN(start,end) ((end.tv_sec-start.tv_sec)+(end.tv_nsec-start.tv_nsec)/1e9)
@ -955,11 +1134,65 @@ int main(int argc, char *argv[])
apply_fir_fft_cc (plan_forward, plan_inverse, taps_fft, last_overlap, overlap_length);
int returned=fwrite(plan_inverse->output, sizeof(complexf), input_size, stdout);
if(read_fifo_ctl(fd,"%g %g\n",&low_cut,&high_cut)) break;
TRY_YIELD;
}
}
}
#ifdef USE_IMA_ADPCM
#define IMA_ADPCM_BUFSIZE BUFSIZE
if(!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))
{
ima_adpcm_state_t d;
d.index=d.previousValue=0;
for(;;)
{
FEOF_CHECK;
fread(buffer_i16, sizeof(short), IMA_ADPCM_BUFSIZE, stdin);
d=encode_ima_adpcm_i16_u8(buffer_i16, buffer_u8, IMA_ADPCM_BUFSIZE, d);
fwrite(buffer_u8, sizeof(unsigned char), IMA_ADPCM_BUFSIZE/2, stdout);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))
{
ima_adpcm_state_t d;
d.index=d.previousValue=0;
for(;;)
{
FEOF_CHECK;
fread(buffer_u8, sizeof(unsigned char), IMA_ADPCM_BUFSIZE/2, stdin);
d=decode_ima_adpcm_u8_i16(buffer_u8, buffer_i16, IMA_ADPCM_BUFSIZE/2, d);
fwrite(buffer_i16, sizeof(short), IMA_ADPCM_BUFSIZE, stdout);
TRY_YIELD;
}
}
#endif
if(!strcmp(argv[1],"flowcontrol"))
{
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
int data_rate;
sscanf(argv[2],"%d",&data_rate);
int reads_per_second;
sscanf(argv[3],"%d",&reads_per_second);
int flowcontrol_bufsize=ceil(1.*(double)data_rate/reads_per_second);
unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize);
int flowcontrol_sleep=floor(1000000./reads_per_second);
fprintf(stderr, "flowcontrol: flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_bufsize, flowcontrol_sleep);
for(;;)
{
FEOF_CHECK;
fread(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdin);
fwrite(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdout);
usleep(flowcontrol_sleep);
TRY_YIELD;
}
}
if(!strcmp(argv[1],"none"))
{
return 0;

View file

@ -0,0 +1,844 @@
<?xml version='1.0' encoding='ASCII'?>
<?grc format='1' created='3.7.5'?>
<flow_graph>
<timestamp>Sun Jan 25 13:25:30 2015</timestamp>
<block>
<key>options</key>
<param>
<key>id</key>
<value>top_block</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>title</key>
<value></value>
</param>
<param>
<key>author</key>
<value></value>
</param>
<param>
<key>description</key>
<value></value>
</param>
<param>
<key>window_size</key>
<value>1280, 1024</value>
</param>
<param>
<key>generate_options</key>
<value>wx_gui</value>
</param>
<param>
<key>category</key>
<value>Custom</value>
</param>
<param>
<key>run_options</key>
<value>prompt</value>
</param>
<param>
<key>run</key>
<value>True</value>
</param>
<param>
<key>max_nouts</key>
<value>0</value>
</param>
<param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(10, 10)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>id</key>
<value>samp_rate</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>value</key>
<value>32000</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(176, 11)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>variable_slider</key>
<param>
<key>id</key>
<value>amp</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>label</key>
<value></value>
</param>
<param>
<key>value</key>
<value>0.5</value>
</param>
<param>
<key>min</key>
<value>0</value>
</param>
<param>
<key>max</key>
<value>1</value>
</param>
<param>
<key>num_steps</key>
<value>100</value>
</param>
<param>
<key>style</key>
<value>wx.SL_HORIZONTAL</value>
</param>
<param>
<key>converver</key>
<value>float_converter</value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value></value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(544, 11)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>analog_sig_source_x</key>
<param>
<key>id</key>
<value>analog_sig_source_x_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>waveform</key>
<value>analog.GR_COS_WAVE</value>
</param>
<param>
<key>freq</key>
<value>freq</value>
</param>
<param>
<key>amp</key>
<value>amp</value>
</param>
<param>
<key>offset</key>
<value>0</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 163)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>blocks_throttle</key>
<param>
<key>id</key>
<value>blocks_throttle_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>samples_per_second</key>
<value>samp_rate</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
<param>
<key>ignoretag</key>
<value>True</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(176, 195)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>wxgui_scopesink2</key>
<param>
<key>id</key>
<value>wxgui_scopesink2_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>title</key>
<value>Scope Plot of Original Signal</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>v_scale</key>
<value>0</value>
</param>
<param>
<key>v_offset</key>
<value>0</value>
</param>
<param>
<key>t_scale</key>
<value>0</value>
</param>
<param>
<key>ac_couple</key>
<value>False</value>
</param>
<param>
<key>xy_mode</key>
<value>False</value>
</param>
<param>
<key>num_inputs</key>
<value>1</value>
</param>
<param>
<key>win_size</key>
<value></value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value>nb0,0</value>
</param>
<param>
<key>trig_mode</key>
<value>wxgui.TRIG_MODE_AUTO</value>
</param>
<param>
<key>y_axis_label</key>
<value>Counts</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(352, 331)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>notebook</key>
<param>
<key>id</key>
<value>nb0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>style</key>
<value>wx.NB_TOP</value>
</param>
<param>
<key>labels</key>
<value>['Scope', 'FFT']</value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value></value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(272, 11)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>notebook</key>
<param>
<key>id</key>
<value>nb1</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>style</key>
<value>wx.NB_TOP</value>
</param>
<param>
<key>labels</key>
<value>['Scope', 'FFT']</value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value></value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(272, 99)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>wxgui_fftsink2</key>
<param>
<key>id</key>
<value>wxgui_fftsink2_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>title</key>
<value>FFT Plot of Original Signal</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>baseband_freq</key>
<value>0</value>
</param>
<param>
<key>y_per_div</key>
<value>10</value>
</param>
<param>
<key>y_divs</key>
<value>10</value>
</param>
<param>
<key>ref_level</key>
<value>0</value>
</param>
<param>
<key>ref_scale</key>
<value>2.0</value>
</param>
<param>
<key>fft_size</key>
<value>1024</value>
</param>
<param>
<key>fft_rate</key>
<value>15</value>
</param>
<param>
<key>peak_hold</key>
<value>False</value>
</param>
<param>
<key>average</key>
<value>False</value>
</param>
<param>
<key>avg_alpha</key>
<value>0</value>
</param>
<param>
<key>win</key>
<value>None</value>
</param>
<param>
<key>win_size</key>
<value></value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value>nb0,1</value>
</param>
<param>
<key>freqvar</key>
<value>None</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(352, 459)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>wxgui_scopesink2</key>
<param>
<key>id</key>
<value>wxgui_scopesink2_0_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>title</key>
<value>Scope Plot of Processed Signal (csdr)</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>v_scale</key>
<value>0</value>
</param>
<param>
<key>v_offset</key>
<value>0</value>
</param>
<param>
<key>t_scale</key>
<value>0</value>
</param>
<param>
<key>ac_couple</key>
<value>False</value>
</param>
<param>
<key>xy_mode</key>
<value>False</value>
</param>
<param>
<key>num_inputs</key>
<value>1</value>
</param>
<param>
<key>win_size</key>
<value></value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value>nb1,0</value>
</param>
<param>
<key>trig_mode</key>
<value>wxgui.TRIG_MODE_AUTO</value>
</param>
<param>
<key>y_axis_label</key>
<value>Counts</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(760, 171)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>wxgui_fftsink2</key>
<param>
<key>id</key>
<value>wxgui_fftsink2_0_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>title</key>
<value>FFT Plot of Processed Signal (csdr)</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>baseband_freq</key>
<value>0</value>
</param>
<param>
<key>y_per_div</key>
<value>10</value>
</param>
<param>
<key>y_divs</key>
<value>10</value>
</param>
<param>
<key>ref_level</key>
<value>0</value>
</param>
<param>
<key>ref_scale</key>
<value>2.0</value>
</param>
<param>
<key>fft_size</key>
<value>1024</value>
</param>
<param>
<key>fft_rate</key>
<value>15</value>
</param>
<param>
<key>peak_hold</key>
<value>False</value>
</param>
<param>
<key>average</key>
<value>False</value>
</param>
<param>
<key>avg_alpha</key>
<value>0</value>
</param>
<param>
<key>win</key>
<value>None</value>
</param>
<param>
<key>win_size</key>
<value></value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value>nb1,1</value>
</param>
<param>
<key>freqvar</key>
<value>None</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(760, 299)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>ha5kfu_execproc_xx</key>
<param>
<key>id</key>
<value>ha5kfu_execproc_xx_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>ff</value>
</param>
<param>
<key>commandline</key>
<value>csdr convert_f_i16 | csdr encode_ima_adpcm_i16_u8 | csdr decode_ima_adpcm_u8_i16 | csdr convert_i16_f</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(448, 195)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>variable_slider</key>
<param>
<key>id</key>
<value>freq</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>label</key>
<value></value>
</param>
<param>
<key>value</key>
<value>1000</value>
</param>
<param>
<key>min</key>
<value>0</value>
</param>
<param>
<key>max</key>
<value>samp_rate/2</value>
</param>
<param>
<key>num_steps</key>
<value>100</value>
</param>
<param>
<key>style</key>
<value>wx.SL_HORIZONTAL</value>
</param>
<param>
<key>converver</key>
<value>float_converter</value>
</param>
<param>
<key>grid_pos</key>
<value></value>
</param>
<param>
<key>notebook</key>
<value></value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
<value>(424, 11)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<connection>
<source_block_id>analog_sig_source_x_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>ha5kfu_execproc_xx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>wxgui_scopesink2_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>wxgui_fftsink2_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>ha5kfu_execproc_xx_0</source_block_id>
<sink_block_id>wxgui_scopesink2_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>ha5kfu_execproc_xx_0</source_block_id>
<sink_block_id>wxgui_fftsink2_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
</flow_graph>

View file

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='ASCII'?>
<?grc format='1' created='3.7.5'?>
<flow_graph>
<timestamp>Tue Nov 25 18:15:25 2014</timestamp>
<timestamp>Tue Mar 17 19:40:27 2015</timestamp>
<block>
<key>options</key>
<param>
@ -77,7 +77,7 @@
</param>
<param>
<key>value</key>
<value>2</value>
<value>1</value>
</param>
<param>
<key>alias</key>
@ -104,7 +104,7 @@
</param>
<param>
<key>value</key>
<value>5</value>
<value>4</value>
</param>
<param>
<key>alias</key>
@ -939,49 +939,6 @@
<value>0</value>
</param>
</block>
<block>
<key>ha5kfu_execproc_xx</key>
<param>
<key>id</key>
<value>ha5kfu_execproc_xx_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>ff</value>
</param>
<param>
<key>commandline</key>
<value>"csdr rational_resampler_ff %d %d 0.05"%(interpolation,decimation)</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(752, 195)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<block>
<key>notebook</key>
<param>
@ -1076,6 +1033,49 @@
<value>0</value>
</param>
</block>
<block>
<key>ha5kfu_execproc_xx</key>
<param>
<key>id</key>
<value>ha5kfu_execproc_xx_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>ff</value>
</param>
<param>
<key>commandline</key>
<value>"csdr rational_resampler_ff %d %d 0.05"%(interpolation,decimation)</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(752, 195)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
</block>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>ha5kfu_execproc_xx_0</sink_block_id>

File diff suppressed because it is too large Load diff

176
ima_adpcm.c Normal file
View file

@ -0,0 +1,176 @@
/*
This software is part of libcsdr, a set of simple DSP routines for
Software Defined Radio.
Copyright (c) 2015, Andras Retzler <randras@sdr.hu>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright 1997 Tim Kientzle. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Tim Kientzle
and published in ``The Programmer's Guide to Sound.''
4. Neither the names of Tim Kientzle nor Addison-Wesley
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL TIM KIENTZLE OR ADDISON-WESLEY BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/***********************************************************
Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
#ifdef USE_IMA_ADPCM
#include "ima_adpcm.h"
const int indexAdjustTable[16] = {
-1, -1, -1, -1, // +0 - +3, decrease the step size
2, 4, 6, 8, // +4 - +7, increase the step size
-1, -1, -1, -1, // -0 - -3, decrease the step size
2, 4, 6, 8, // -4 - -7, increase the step size
};
const int _stepSizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34,
37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
27086, 29794, 32767
};
static inline short ImaAdpcmDecode(unsigned char deltaCode, ima_adpcm_state_t* state) {
// Get the current step size
int step = _stepSizeTable[state->index];
// Construct the difference by scaling the current step size
// This is approximately: difference = (deltaCode+.5)*step/4
int difference = step>>3;
if ( deltaCode & 1 ) difference += step>>2;
if ( deltaCode & 2 ) difference += step>>1;
if ( deltaCode & 4 ) difference += step;
if ( deltaCode & 8 ) difference = -difference;
// Build the new sample
state->previousValue += difference;
if (state->previousValue > 32767) state->previousValue = 32767;
else if (state->previousValue < -32768) state->previousValue = -32768;
// Update the step for the next sample
state->index += indexAdjustTable[deltaCode];
if (state->index < 0) state->index = 0;
else if (state->index > 88) state->index = 88;
return state->previousValue;
}
static inline unsigned char ImaAdpcmEncode(short sample, ima_adpcm_state_t* state) {
int diff = sample - state->previousValue;
int step = _stepSizeTable[state->index];
int deltaCode = 0;
// Set sign bit
if (diff < 0) { deltaCode = 8; diff = -diff; }
// This is essentially deltaCode = (diff<<2)/step,
// except the roundoff is handled differently.
if ( diff >= step ) { deltaCode |= 4; diff -= step; }
step >>= 1;
if ( diff >= step ) { deltaCode |= 2; diff -= step; }
step >>= 1;
if ( diff >= step ) { deltaCode |= 1; diff -= step; }
ImaAdpcmDecode(deltaCode,state); // update state
return deltaCode;
}
ima_adpcm_state_t encode_ima_adpcm_i16_u8(short* input, unsigned char* output, int input_length, ima_adpcm_state_t state)
{
int k=0;
for(int i=0;i<input_length/2;i++)
{
output[k]=ImaAdpcmEncode(input[2*i],&state);
output[k++]|=ImaAdpcmEncode(input[2*i+1],&state)<<4;
}
return state;
}
ima_adpcm_state_t decode_ima_adpcm_u8_i16(unsigned char* input, short* output, int input_length, ima_adpcm_state_t state)
{
int k=0;
for(int i=0;i<input_length;i++)
{
output[k++]=ImaAdpcmDecode(input[i]&0xf,&state);
output[k++]=ImaAdpcmDecode( (input[i]>>4)&0xf,&state);
}
return state;
}
#endif

13
ima_adpcm.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#ifdef USE_IMA_ADPCM
typedef struct ImaState {
int index; // Index into step size table
int previousValue; // Most recent sample value
} ima_adpcm_state_t;
ima_adpcm_state_t encode_ima_adpcm_i16_u8(short* input, unsigned char* output, int input_length, ima_adpcm_state_t state);
ima_adpcm_state_t decode_ima_adpcm_u8_i16(unsigned char* input, short* output, int input_length, ima_adpcm_state_t state);
#endif

View file

@ -205,6 +205,64 @@ float shift_math_cc(complexf *input, complexf* output, int input_size, float rat
return phase;
}
shift_table_data_t shift_table_init(int table_size)
{
//RTODO
shift_table_data_t output;
output.table=(float*)malloc(sizeof(float)*table_size);
output.table_size=table_size;
for(int i=0;i<table_size;i++)
{
output.table[i]=sin(((float)i/table_size)*(PI/2));
}
return output;
}
void shift_table_deinit(shift_table_data_t table_data)
{
free(table_data.table);
}
float shift_table_cc(complexf* input, complexf* output, int input_size, float rate, shift_table_data_t table_data, float starting_phase)
{
//RTODO
rate*=2;
//Shifts the complex spectrum. Basically a complex mixer. This version uses a pre-built sine table.
float phase=starting_phase;
float phase_increment=rate*PI;
float cosval, sinval;
for(int i=0;i<input_size; i++) //@shift_math_cc
{
int sin_index, cos_index, temp_index, sin_sign, cos_sign;
//float vphase=fmodf(phase,PI/2); //between 0 and 90deg
int quadrant=phase/(PI/2); //between 0 and 3
float vphase=phase-quadrant*(PI/2);
sin_index=(vphase/(PI/2))*table_data.table_size;
cos_index=table_data.table_size-1-sin_index;
if(quadrant&1) //in quadrant 1 and 3
{
temp_index=sin_index;
sin_index=cos_index;
cos_index=temp_index;
}
sin_sign=(quadrant>1)?-1:1; //in quadrant 2 and 3
cos_sign=(quadrant&&quadrant<3)?-1:1; //in quadrant 1 and 2
sinval=sin_sign*table_data.table[sin_index];
cosval=cos_sign*table_data.table[cos_index];
//we multiply two complex numbers.
//how? enter this to maxima (software) for explanation:
// (a+b*%i)*(c+d*%i), rectform;
iof(output,i)=cosval*iof(input,i)-sinval*qof(input,i);
qof(output,i)=sinval*iof(input,i)+cosval*qof(input,i);
phase+=phase_increment;
while(phase>2*PI) phase-=2*PI; //@shift_math_cc: normalize phase
while(phase<0) phase+=2*PI;
}
return phase;
}
int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decimation, float *taps, int taps_length)
{
//Theory: http://www.dspguru.com/dsp/faqs/multirate/decimation
@ -339,6 +397,8 @@ fractional_decimator_ff_t fractional_decimator_ff(float* input, float* output, i
void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size)
{
//use the overlap & add method for filtering
//calculate FFT on input buffer
fft_execute(plan);
@ -593,6 +653,14 @@ complexf fmdemod_quadri_cf(complexf* input, float* output, int input_size, float
return input[input_size-1];
}
inline int is_nan(float f)
{
//http://stackoverflow.com/questions/570669/checking-if-a-double-or-float-is-nan-in-c
unsigned u = *(unsigned*)&f;
return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF); // Both NaN and qNan.
}
float deemphasis_wfm_ff (float* input, float* output, int input_size, float tau, int sample_rate, float last_output)
{
/*
@ -604,6 +672,7 @@ float deemphasis_wfm_ff (float* input, float* output, int input_size, float tau,
*/
float dt = 1.0/sample_rate;
float alpha = dt/(tau+dt);
if(is_nan(last_output)) last_output=0.0; //if last_output is NaN
output[0]=alpha*input[0]+(1-alpha)*last_output;
for (int i=1;i<input_size;i++) //@deemphasis_wfm_ff
output[i]=alpha*input[i]+(1-alpha)*output[i-1]; //this is the simplest IIR LPF
@ -628,6 +697,7 @@ int deemphasis_nfm_ff (float* input, float* output, int input_size, int sample_r
DNFMFF_ADD_ARRAY(48000)
DNFMFF_ADD_ARRAY(44100)
DNFMFF_ADD_ARRAY(8000)
DNFMFF_ADD_ARRAY(11025)
if(!taps_length) return 0; //sample rate n
int i;

View file

@ -97,6 +97,7 @@ void amdemod_estimator_cf(complexf* input, float *output, int input_size, float
void limit_ff(float* input, float* output, int input_size, float max_amplitude);
//filters, decimators, resamplers, shift, etc.
float fir_one_pass_ff(float* input, float* taps, int taps_length);
int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decimation, float *taps, int taps_length);
int deemphasis_nfm_ff (float* input, float* output, int input_size, int sample_rate);
float deemphasis_wfm_ff (float* input, float* output, int input_size, float tau, int sample_rate, float last_output);
@ -146,6 +147,16 @@ typedef struct fractional_decimator_ff_s
} fractional_decimator_ff_t;
fractional_decimator_ff_t fractional_decimator_ff(float* input, float* output, int input_size, float rate, float *taps, int taps_length, fractional_decimator_ff_t d);
typedef struct shift_table_data_s
{
float* table;
int table_size;
} shift_table_data_t;
void shift_table_deinit(shift_table_data_t table_data);
shift_table_data_t shift_table_init(int table_size);
float shift_table_cc(complexf* input, complexf* output, int input_size, float rate, shift_table_data_t table_data, float starting_phase);
int log2n(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);
@ -156,6 +167,4 @@ void convert_f_u8(float* input, unsigned char* 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);
int is_nan(float f);

View file

@ -96,6 +96,43 @@ void shift_addition_cc_test(shift_addition_data_t d)
printf("]; error_vector_db=20*log10(error_vector); plot(error_vector_db);\n");
}
shift_addition_data_t decimating_shift_addition_init(float rate, int decimation)
{
return shift_addition_init(rate*decimation);
}
decimating_shift_addition_status_t decimating_shift_addition_cc(complexf *input, complexf* output, int input_size, shift_addition_data_t d, int decimation, decimating_shift_addition_status_t s)
{
//The original idea was taken from wdsp:
//http://svn.tapr.org/repos_sdr_hpsdr/trunk/W5WC/PowerSDR_HPSDR_mRX_PS/Source/wdsp/shift.c
//However, this method introduces noise (from floating point rounding errors), which increases until the end of the buffer.
//fprintf(stderr, "cosd=%g sind=%g\n", d.cosdelta, d.sindelta);
float cosphi=cos(s.starting_phase);
float sinphi=sin(s.starting_phase);
float cosphi_last, sinphi_last;
int i;
int k=0;
for(i=s.decimation_remain;i<input_size;i+=decimation) //@shift_addition_cc: work
{
iof(output,k)=cosphi*iof(input,i)-sinphi*qof(input,i);
qof(output,k)=sinphi*iof(input,i)+cosphi*qof(input,i);
k++;
//using the trigonometric addition formulas
//cos(phi+delta)=cos(phi)cos(delta)-sin(phi)*sin(delta)
cosphi_last=cosphi;
sinphi_last=sinphi;
cosphi=cosphi_last*d.cosdelta-sinphi_last*d.sindelta;
sinphi=sinphi_last*d.cosdelta+cosphi_last*d.sindelta;
}
s.decimation_remain=i-input_size;
s.starting_phase+=d.rate*PI*k;
s.output_size=k;
while(s.starting_phase>PI) s.starting_phase-=2*PI; //@shift_addition_cc: normalize starting_phase
while(s.starting_phase<-PI) s.starting_phase+=2*PI;
return s;
}
float agc_ff(float* input, float* output, int input_size, float reference, float attack_rate, float decay_rate, float max_gain, short hang_time, short attack_wait_time, float gain_filter_alpha, float last_gain)
{
/*

View file

@ -35,5 +35,14 @@ void shift_addition_cc_test(shift_addition_data_t d);
float agc_ff(float* input, float* output, int input_size, float reference, float attack_rate, float decay_rate, float max_gain, short hang_time, short attack_wait_time, float gain_filter_alpha, float last_gain);
typedef struct decimating_shift_addition_status_s
{
int decimation_remain;
float starting_phase;
int output_size;
} decimating_shift_addition_status_t;
decimating_shift_addition_status_t decimating_shift_addition_cc(complexf *input, complexf* output, int input_size, shift_addition_data_t d, int decimation, decimating_shift_addition_status_t s);
shift_addition_data_t decimating_shift_addition_init(float rate, int decimation);
#endif

View file

@ -1,3 +1,4 @@
#include "libcsdr.c"
#include "libcsdr_gpl.c"
#include "ima_adpcm.c"
//this wrapper helps parsevect.py to generate better output

View file

@ -50,11 +50,9 @@ function mkdeemph(sr,tapnum,norm_freq)
printf("%g, ",coeffs);
printf("\n")
end
mkdeemph(48000,199,500)
*/
//mkdeemph(48000,199,500)
float deemphasis_nfm_predefined_fir_48000[] =
{ 0.00172568, 0.00179665, 0.00191952, 0.00205318, 0.00215178, 0.00217534, 0.00209924, 0.00192026, 0.00165789, 0.0013502, 0.00104545, 0.000790927, 0.000621911, 0.000553077, 0.000574554, 0.000653624, 0.000741816, 0.000785877, 0.000740151, 0.000577506, 0.000296217, -7.89273e-05, -0.0005017, -0.000914683, -0.00126243, -0.00150456, -0.00162564, -0.0016396, -0.00158725, -0.00152751, -0.00152401, -0.00163025, -0.00187658, -0.00226223, -0.00275443, -0.003295, -0.0038132, -0.00424193, -0.00453375, -0.00467274, -0.00467943, -0.00460728, -0.00453119, -0.00453056, -0.00467051, -0.00498574, -0.00547096, -0.00608027, -0.00673627, -0.00734698, -0.00782705, -0.00811841, -0.00820539, -0.00812057, -0.00793936, -0.00776415, -0.00770111, -0.00783479, -0.00820643, -0.00880131, -0.00954878, -0.0103356, -0.0110303, -0.011514, -0.0117094, -0.0116029, -0.0112526, -0.0107795, -0.010343, -0.0101053, -0.0101917, -0.0106561, -0.0114608, -0.0124761, -0.0135018, -0.0143081, -0.0146885, -0.0145126, -0.0137683, -0.0125796, -0.0111959, -0.00994914, -0.00918404, -0.00917447, -0.0100402, -0.0116822, -0.0137533, -0.0156723, -0.0166881, -0.0159848, -0.0128153, -0.00664117, 0.00274383, 0.0151313, 0.0298729, 0.0459219, 0.0619393, 0.076451, 0.0880348, 0.0955087, 0.098091, 0.0955087, 0.0880348, 0.076451, 0.0619393, 0.0459219, 0.0298729, 0.0151313, 0.00274383, -0.00664117, -0.0128153, -0.0159848, -0.0166881, -0.0156723, -0.0137533, -0.0116822, -0.0100402, -0.00917447, -0.00918404, -0.00994914, -0.0111959, -0.0125796, -0.0137683, -0.0145126, -0.0146885, -0.0143081, -0.0135018, -0.0124761, -0.0114608, -0.0106561, -0.0101917, -0.0101053, -0.010343, -0.0107795, -0.0112526, -0.0116029, -0.0117094, -0.011514, -0.0110303, -0.0103356, -0.00954878, -0.00880131, -0.00820643, -0.00783479, -0.00770111, -0.00776415, -0.00793936, -0.00812057, -0.00820539, -0.00811841, -0.00782705, -0.00734698, -0.00673627, -0.00608027, -0.00547096, -0.00498574, -0.00467051, -0.00453056, -0.00453119, -0.00460728, -0.00467943, -0.00467274, -0.00453375, -0.00424193, -0.0038132, -0.003295, -0.00275443, -0.00226223, -0.00187658, -0.00163025, -0.00152401, -0.00152751, -0.00158725, -0.0016396, -0.00162564, -0.00150456, -0.00126243, -0.000914683, -0.0005017, -7.89273e-05, 0.000296217, 0.000577506, 0.000740151, 0.000785877, 0.000741816, 0.000653624, 0.000574554, 0.000553077, 0.000621911, 0.000790927, 0.00104545, 0.0013502, 0.00165789, 0.00192026, 0.00209924, 0.00217534, 0.00215178, 0.00205318, 0.00191952, 0.00179665, 0.00172568 };
@ -64,3 +62,7 @@ float deemphasis_nfm_predefined_fir_8000[] =
float deemphasis_nfm_predefined_fir_44100[] =
{ 0.0025158, 0.00308564, 0.00365507, 0.00413598, 0.00446279, 0.00461162, 0.00460866, 0.00452474, 0.00445739, 0.00450444, 0.00473648, 0.0051757, 0.0057872, 0.00648603, 0.00715856, 0.00769296, 0.00801081, 0.00809096, 0.00797853, 0.00777577, 0.00761627, 0.00762871, 0.00789987, 0.00844699, 0.00920814, 0.0100543, 0.0108212, 0.0113537, 0.011551, 0.0113994, 0.0109834, 0.0104698, 0.0100665, 0.00996618, 0.0102884, 0.0110369, 0.0120856, 0.0131998, 0.0140907, 0.0144924, 0.0142417, 0.0133401, 0.0119771, 0.0105043, 0.00935909, 0.00895022, 0.00952985, 0.0110812, 0.0132522, 0.015359, 0.0164664, 0.0155409, 0.0116496, 0.00416925, -0.00703664, -0.021514, -0.0382135, -0.0555955, -0.0718318, -0.0850729, -0.0937334, -0.0967458, -0.0937334, -0.0850729, -0.0718318, -0.0555955, -0.0382135, -0.021514, -0.00703664, 0.00416925, 0.0116496, 0.0155409, 0.0164664, 0.015359, 0.0132522, 0.0110812, 0.00952985, 0.00895022, 0.00935909, 0.0105043, 0.0119771, 0.0133401, 0.0142417, 0.0144924, 0.0140907, 0.0131998, 0.0120856, 0.0110369, 0.0102884, 0.00996618, 0.0100665, 0.0104698, 0.0109834, 0.0113994, 0.011551, 0.0113537, 0.0108212, 0.0100543, 0.00920814, 0.00844699, 0.00789987, 0.00762871, 0.00761627, 0.00777577, 0.00797853, 0.00809096, 0.00801081, 0.00769296, 0.00715856, 0.00648603, 0.0057872, 0.0051757, 0.00473648, 0.00450444, 0.00445739, 0.00452474, 0.00460866, 0.00461162, 0.00446279, 0.00413598, 0.00365507, 0.00308564, 0.0025158 };
//mkdeemph(11025,79,500)
float deemphasis_nfm_predefined_fir_11025[] =
{ 0.00113162, 0.000911207, 0.00173815, -0.000341385, -0.000849373, -0.00033066, -0.00290692, -0.00357326, -0.0031917, -0.00607078, -0.00659201, -0.00601551, -0.00886603, -0.00880243, -0.00759841, -0.0100344, -0.0088993, -0.00664423, -0.00835258, -0.00572919, -0.00214109, -0.00302443, 0.00132902, 0.00627003, 0.00596494, 0.0120731, 0.0180437, 0.0176243, 0.0253776, 0.0316572, 0.0298485, 0.0393389, 0.0446019, 0.0389943, 0.0516463, 0.0521951, 0.0350192, 0.0600945, 0.0163128, -0.217526, -0.378533, -0.217526, 0.0163128, 0.0600945, 0.0350192, 0.0521951, 0.0516463, 0.0389943, 0.0446019, 0.0393389, 0.0298485, 0.0316572, 0.0253776, 0.0176243, 0.0180437, 0.0120731, 0.00596494, 0.00627003, 0.00132902, -0.00302443, -0.00214109, -0.00572919, -0.00835258, -0.00664423, -0.0088993, -0.0100344, -0.00759841, -0.00880243, -0.00886603, -0.00601551, -0.00659201, -0.00607078, -0.0031917, -0.00357326, -0.00290692, -0.00033066, -0.000849373, -0.000341385, 0.00173815, 0.000911207, 0.00113162 };

View file

@ -0,0 +1,81 @@
"""
This software is part of libcsdr, a set of simple DSP routines for
Software Defined Radio.
Copyright (c) 2014, Andras Retzler <randras@sdr.hu>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
exported_functions= \
"""firdes_lowpass_f
firdes_bandpass_c
firdes_wkernel_blackman
firdes_wkernel_hamming
firdes_wkernel_boxcar
firdes_get_window_from_string
firdes_get_string_from_window
firdes_filter_len
fmdemod_quadri_cf
fmdemod_quadri_novect_cf
fmdemod_atan_cf
amdemod_cf
amdemod_estimator_cf
limit_ff
fir_decimate_cc
deemphasis_nfm_ff
deemphasis_wfm_ff
shift_math_cc
dcblock_ff
fastdcblock_ff
fastagc_ff
rational_resampler_ff
rational_resampler_get_lowpass_f
apply_window_c
apply_window_f
logpower_cf
fractional_decimator_ff
shift_table_deinit
shift_table_init
shift_table_cc
log2n
next_pow2
apply_fir_fft_cc
gain_ff
convert_u8_f
convert_f_u8
convert_f_i16
convert_i16_f
shift_addition_init
shift_addition_cc
shift_addition_cc_test
agc_ff
decimating_shift_addition_cc
decimating_shift_addition_init
encode_ima_adpcm_i16_u8
decode_ima_adpcm_u8_i16"""
exported_functions_quoted=map(lambda x:"'_"+x+"'",exported_functions.split("\n"))
print "["+(", ".join(exported_functions_quoted))+"]"

296
sdr.js/sdrjs-footer.js Normal file
View file

@ -0,0 +1,296 @@
// ==========================================================
// ========= / THE CODE COMPILED BY EMCC ENDS HERE ==========
// ==========================================================
asm$ =
{
malloc: function(type, size)
{
real_size=size*type.BYTES_PER_ELEMENT;
pointer = Module._malloc(real_size);
heap = new Uint8Array(Module.HEAPU8.buffer, pointer, real_size);
return {
asm$: true,
ptr: heap.byteOffset,
free: function() { Module._free(this.ptr); },
arr: new type(heap.buffer, heap.byteOffset, size),
size: size
};
},
cpy: function(dst, dst_offset, src, src_offset, size)
{
if(typeof dst.asm$!='undefined') dst=dst.arr;
if(typeof src.asm$!='undefined') src=src.arr;
for(var i=0;i<size;i++)
dst[dst_offset+i]=src[src_offset+i];
}
};
// void firdes_lowpass_f(float *output, int length, float cutoff_rate, window_t window)
firdes_lowpass_f = Module.cwrap('firdes_lowpass_f', null, ['number', 'number', 'number', 'number']);
// 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 = Module.cwrap('rational_resampler_ff', 'struct', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
rational_resampler_ff=function(pinput,poutput,input_length,interpolation,decimation,ptaps,taps_length,last_taps_delay )
{ stackbase=STACKTOP;
STACKTOP+=4*3;
_rational_resampler_ff(stackbase, pinput, poutput, input_length, interpolation, decimation, ptaps, taps_length,last_taps_delay);
returnstruct={ input_processed: getValue(stackbase,'i32'), output_size: getValue(stackbase+4,'i32'), last_taps_delay: getValue(stackbase+8,'i32') };
STACKTOP=stackbase;
return returnstruct;
}
sdrjs={};
sdrjs.WINDOW_BOXCAR=0;
sdrjs.WINDOW_BLACKMAN=1;
sdrjs.WINDOW_HAMMING=2;
//this will be impportant whil converting arrays
//http://stackoverflow.com/questions/25839216/convert-float32array-to-int16array
/*sdrjs.prototype.FirdesLowpassF=function(taps_length,transition_bw,window)
{
this.calculate=function(){}
this.get_output=function(){}
this.get_output_heap=function(){}
};*/
sdrjs.ConvertI16_F=function(i16data)
{
var f32data=new Float32Array(i16data.length);
for(var i=0;i<i16data.length;i++) f32data[i]=i16data[i]/32768;
return f32data;
}
ima_adpcm_codec=function(encode,pinput,poutput,input_length,state)
{
myfunc=(encode)?_encode_ima_adpcm_i16_u8:_decode_ima_adpcm_u8_i16;
stackbase=STACKTOP;
STACKTOP+=4*2; //sizeof(int)*2
myfunc(stackbase, pinput, poutput, input_length, state.ptr);
state.arr[0]=getValue(stackbase+0,'i32');
state.arr[1]=getValue(stackbase+4,'i32');
STACKTOP=stackbase;
};
sdrjs.ImaAdpcm=function()
{
this.BUFSIZE=1024*64;
this.ima_adpcm_state=asm$.malloc(Int32Array,2);
this.i16_buffer=asm$.malloc(Int16Array,this.BUFSIZE*2);
this.u8_buffer=asm$.malloc(Uint8Array,this.BUFSIZE);
this.ima_adpcm_state.arr[0]=0;
this.ima_adpcm_state.arr[1]=0;
this.encode=function(data)
{
//not_tested_yet
asm$.cpy(this.i16_buffer.arr,0,data,0,data.length);
ima_adpcm_codec(true,this.i16_buffer.ptr,this.u8_buffer.ptr,data.length,this.ima_adpcm_state);
out=new Uint8Array(data.length/2);
asm$.cpy(out,0,this.u8_buffer,0,data.length/2);
return out;
};
this.decode=function(data)
{
asm$.cpy(this.u8_buffer.arr,0,data,0,data.length);
ima_adpcm_codec(false,this.u8_buffer.ptr,this.i16_buffer.ptr,data.length,this.ima_adpcm_state);
out=new Int16Array(data.length*2);
asm$.cpy(out,0,this.i16_buffer.arr,0,data.length*2);
return out;
};
this.reset=function() { this.ima_adpcm_state.arr[0]=this.ima_adpcm_state.arr[1]=0|0; }
};
sdrjs.REBUFFER_FIXED=0; //rebuffer should return arrays of fixed size
sdrjs.REBUFFER_MAX=1; //rebuffer should return arrays with a maximal size of the parameter size
sdrjs.Rebuffer=function(size,mode)
{
this.mode=mode;
this.size=size;
this.total_size=0;
this.arrays=[];
this.last_arr=[];
this.last_arr_offset=0;
this.push=function(data)
{
this.total_size+=data.length;
this.arrays.push(data);
};
this.remaining=function()
{
var fixed_bufs_num=Math.floor(this.total_size/this.size);
if(!this.mode) return fixed_bufs_num;
else return fixed_bufs_num+(!!(this.total_size-fixed_bufs_num*this.size)); //if REBUFFER_MAX, add one if we could return one more buffer (smaller than the fixed size)
};
this.take=function() { var a=this._take(); /*console.log(a);*/ return a; };
this._take=function()
{
var remain=this.size;
var offset=0;
var obuf=new Float32Array(size);
//console.log("==== get new obuf ====", size);
while(remain)
{
if(this.last_arr_offset==this.last_arr.length)
{
if(this.arrays.length==0)
{
//console.log("this should not happen");
if(this.mode) //REBUFFER_MAX
{
this.total_size=0;
return obuf.subarray(0,offset);
}
else return new Float32Array(0); //REBUFFER_FIXED
}
//console.log("pick new last_arr");
this.last_arr=this.arrays.shift();
this.last_arr_offset=0;
}
var rwithin=this.last_arr.length-this.last_arr_offset;
//console.log("b :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
if(remain<rwithin)
{
//console.log("remain < rwithin"); //seems problematic @Andris
for(var i=0;i<remain;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
remain=0;
}
else
{
//console.log("remain > rwithin");
for(var i=0;i<rwithin;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
remain-=rwithin;
}
//console.log("e :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
}
this.total_size-=obuf.length;
//console.log("return _take");
return obuf;
};
};
sdrjs.RationalResamplerFF=function(interpolation,decimation,transition_bw,window)
{
this.interpolation=interpolation;
this.decimation=decimation;
this.transition_bw = (typeof transition_bw=='undefined')?0.05:transition_bw;
this.window = (typeof window=='undefined')?1:window;
this.buffer_size=1024*512;
this.output_buffer_size=Math.floor((this.buffer_size*interpolation)/decimation);
this.input_buffer = asm$.malloc(Float32Array,this.buffer_size);
this.output_buffer = asm$.malloc(Float32Array,this.output_buffer_size);
//Calculate filter
this.taps_length = Math.floor(4/this.transition_bw);
this.taps = asm$.malloc(Float32Array,this.taps_length);
var cutoff_for_interpolation=1.0/interpolation;
var cutoff_for_decimation=1.0/decimation;
var cutoff = (cutoff_for_interpolation<cutoff_for_decimation)?cutoff_for_interpolation:cutoff_for_decimation; //get the lower
firdes_lowpass_f(this.taps.ptr, this.taps_length, cutoff/2, window);
this.remain = 0;
this.remain_offset=0;
this.last_taps_delay=0;
this.process=function(input)
{
if(input.length+this.remain > this.buffer_size)
{
return new Float32Array(0); console.log("sdrjs.RationalResamplerFF: critical audio buffering error"); //This should not happen...
/* console.log("RationalResamplerFF: splitting..."); //TODO: this branch has not been checked
output_buffers=Array();
new_buffer_size=this.buffer_size/2;
i=0;
//process the input in chunks of new_buffer_size, and add the output product Float32Array-s to output_buffers.
while((i++)*new_buffer_size<=input.length)
{
output_buffers.push(this._process_noheapcheck(input.subarray(i*new_buffer_size,(i+1)*new_buffer_size)));
}
//add up the sizes of the output_buffer-s.
total_output_length=0;
output_buffers.forEach(function(a){total_output_length+=a.length;});
//create one big buffer from concatenating the output_buffer-s
output=new Float32Array(total_output_length);
output_pos=0;
output_buffers.forEach(function(a){
asm$.cpy(output,output_pos,a,0,a.length);
output_pos+=a.length;
});
return output;*/
}
else return this._process_noheapcheck(input);
};
this._process_noheapcheck=function(input) //if we are sure we have enough space in the buffers
{
asm$.cpy(this.input_buffer.arr,0,this.input_buffer.arr,this.remain_offset,this.remain);
asm$.cpy(this.input_buffer.arr, this.remain, input, 0, input.length);
var total_input_size=input.length+this.remain;
d=rational_resampler_ff(this.input_buffer.ptr, this.output_buffer.ptr, total_input_size, this.interpolation, this.decimation, this.taps.ptr, this.taps_length, this.last_taps_delay);
this.last_taps_delay=d.last_taps_delay;
this.remain=total_input_size-d.input_processed;
this.remain_offset=d.input_processed;
var output_copy_arr=new Float32Array(d.output_size);
asm$.cpy(output_copy_arr,0,this.output_buffer.arr,0,d.output_size);
return output_copy_arr;
};
};
_sdrjs_logb=function(what) { document.body.innerHTML+=what+"<br />"; }
function test_firdes_lowpass_f_original()
{
//Original method explained over here:
//http://kapadia.github.io/emscripten/2013/09/13/emscripten-pointers-and-pointers.html
_sdrjs_logb("test_firdes_lowpass_f_original():");
_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
var outputSize = 101*4;
var outputPtr = Module._malloc(outputSize);
var outputHeap = new Uint8Array(Module.HEAPU8.buffer, outputPtr, outputSize);
firdes_lowpass_f(outputHeap.byteOffset,101,0.1,2);
var output = new Float32Array(outputHeap.buffer, outputHeap.byteOffset, 101);
outputStr=String();
for(i=0;i<output.length;i++) outputStr+=output[i].toFixed(6)+", ";
Module._free(outputHeap.byteOffset);
_sdrjs_logb(outputStr);
}
function test_firdes_lowpass_f_new()
{
//This is much simpler, using asm$
_sdrjs_logb("test_firdes_lowpass_f_new():");
_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
output=asm$.malloc(Float32Array,101);
firdes_lowpass_f(output.ptr,101,0.1,2);
outputStr=String();
for(i=0;i<output.arr.length;i++) outputStr+=(output.arr[i]).toFixed(6)+", ";
output.free();
_sdrjs_logb(outputStr);
}
function test_struct_return_value()
{
v=STACKTOP;
STACKTOP+=4*3;
_shift_addition_init(v,0.2);
console.log(
"sinval=", getValue(v,'float'),
"cosval=", getValue(v+4,'float'),
"rate=", getValue(v+8,'float')
);
STACKTOP=v;
}

25
sdr.js/sdrjs-header.js Normal file
View file

@ -0,0 +1,25 @@
/*
This file is part of libcsdr.
Copyright (c) Andras Retzler, HA7ILM <randras@sdr.hu>
Copyright (c) Warren Pratt, NR0V <warren@wpratt.com>
Copyright 2006,2010,2012 Free Software Foundation, Inc.
libcsdr 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.
libcsdr 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 libcsdr. If not, see <http://www.gnu.org/licenses/>.
*/
// ==========================================================
// ========= THE CODE COMPILED BY EMCC STARTS HERE: =========
// ==========================================================