Added new features, e.g. the IMA ADPCM codec and sdr.js
This commit is contained in:
parent
46468973d8
commit
c50ffaac1b
17 changed files with 2673 additions and 246 deletions
22
Makefile
22
Makefile
|
@ -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'
|
||||
|
|
77
README.md
77
README.md
|
@ -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
263
csdr.c
|
@ -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;
|
||||
|
|
844
grc_tests/test_ima_adpcm.grc
Normal file
844
grc_tests/test_ima_adpcm.grc
Normal 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>
|
|
@ -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
176
ima_adpcm.c
Normal 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
13
ima_adpcm.h
Normal 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
|
70
libcsdr.c
70
libcsdr.c
|
@ -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;
|
||||
|
|
15
libcsdr.h
15
libcsdr.h
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "libcsdr.c"
|
||||
#include "libcsdr_gpl.c"
|
||||
#include "ima_adpcm.c"
|
||||
//this wrapper helps parsevect.py to generate better output
|
||||
|
|
|
@ -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 };
|
||||
|
|
81
sdr.js/exported_functions.py
Normal file
81
sdr.js/exported_functions.py
Normal 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
296
sdr.js/sdrjs-footer.js
Normal 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
25
sdr.js/sdrjs-header.js
Normal 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: =========
|
||||
// ==========================================================
|
||||
|
Loading…
Reference in a new issue