diff --git a/Makefile b/Makefile index 6b77fed556d45a33c67ce5ef1c7f7c030a4ed7ad..1752fc907c9fb2fb6617c138e1a2fd892e721eaf 100644 --- a/Makefile +++ b/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' diff --git a/README.md b/README.md index c306814dbf0f442eba2d91edd784236eb4843d51..b0c9d7910cf2be2954c0fcb7ea83bdac710d5eb4 100644 --- a/README.md +++ b/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. diff --git a/csdr.c b/csdr.c index 6aea2a85e9a8c34c6674b59d387b93a9fef5d919..905a879ab987b984942a9f04172da50ed0364be0 100644 --- a/csdr.c +++ b/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[]) { @@ -179,12 +201,12 @@ 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; diff --git a/grc_tests/test_ima_adpcm.grc b/grc_tests/test_ima_adpcm.grc new file mode 100644 index 0000000000000000000000000000000000000000..c0b77f86f86265da3a13fca82fde9b7eb8242a01 --- /dev/null +++ b/grc_tests/test_ima_adpcm.grc @@ -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> diff --git a/grc_tests/test_rational_resampler.grc b/grc_tests/test_rational_resampler.grc index 7bb2e71da0dc326131edd8afa38de7e48ad9e37a..fe8e838cedf055ce56459a7596454da9af359905 100644 --- a/grc_tests/test_rational_resampler.grc +++ b/grc_tests/test_rational_resampler.grc @@ -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> diff --git a/grc_tests/test_shift.grc b/grc_tests/test_shift.grc index 5f5a9ab51adc09ba81fffd94ff91a723f7e20c71..9fc1eb78104e09d2f9403288ffd2cd8fa2510e20 100644 --- a/grc_tests/test_shift.grc +++ b/grc_tests/test_shift.grc @@ -1,7 +1,7 @@ <?xml version='1.0' encoding='ASCII'?> <?grc format='1' created='3.7.5'?> <flow_graph> - <timestamp>Sat Nov 15 22:24:14 2014</timestamp> + <timestamp>Thu Jan 15 18:51:48 2015</timestamp> <block> <key>options</key> <param> @@ -69,7 +69,7 @@ <key>variable</key> <param> <key>id</key> - <value>samp_rate</value> + <value>rate</value> </param> <param> <key>_enabled</key> @@ -77,7 +77,7 @@ </param> <param> <key>value</key> - <value>250e3</value> + <value>-0.055</value> </param> <param> <key>alias</key> @@ -85,7 +85,7 @@ </param> <param> <key>_coordinate</key> - <value>(10, 170)</value> + <value>(8, 195)</value> </param> <param> <key>_rotation</key> @@ -93,58 +93,53 @@ </param> </block> <block> - <key>analog_sig_source_x</key> + <key>variable</key> <param> <key>id</key> - <value>analog_sig_source_x_0</value> + <value>decimation</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>samp_rate</key> - <value>samp_rate</value> - </param> - <param> - <key>waveform</key> - <value>analog.GR_CONST_WAVE</value> + <key>value</key> + <value>3</value> </param> <param> - <key>freq</key> - <value>20000</value> + <key>alias</key> + <value></value> </param> <param> - <key>amp</key> - <value>1</value> + <key>_coordinate</key> + <value>(16, 267)</value> </param> <param> - <key>offset</key> + <key>_rotation</key> <value>0</value> </param> + </block> + <block> + <key>variable</key> <param> - <key>alias</key> - <value></value> + <key>id</key> + <value>samp_rate</value> </param> <param> - <key>affinity</key> - <value></value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>value</key> + <value>250e3</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>alias</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(56, 243)</value> + <value>(176, 11)</value> </param> <param> <key>_rotation</key> @@ -152,10 +147,10 @@ </param> </block> <block> - <key>wxgui_fftsink2</key> + <key>analog_sig_source_x</key> <param> <key>id</key> - <value>wxgui_fftsink2_0</value> + <value>analog_sig_source_x_0</value> </param> <param> <key>_enabled</key> @@ -165,85 +160,45 @@ <key>type</key> <value>complex</value> </param> - <param> - <key>title</key> - <value>FFT Plot</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> + <key>waveform</key> + <value>analog.GR_CONST_WAVE</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>freq</key> + <value>20000</value> </param> <param> - <key>average</key> - <value>False</value> + <key>amp</key> + <value>1</value> </param> <param> - <key>avg_alpha</key> + <key>offset</key> <value>0</value> </param> <param> - <key>win</key> - <value>None</value> - </param> - <param> - <key>win_size</key> + <key>alias</key> <value></value> </param> <param> - <key>grid_pos</key> + <key>affinity</key> <value></value> </param> <param> - <key>notebook</key> - <value>nb0,0</value> - </param> - <param> - <key>freqvar</key> - <value>None</value> - </param> - <param> - <key>alias</key> - <value></value> + <key>minoutbuf</key> + <value>0</value> </param> <param> - <key>affinity</key> - <value></value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> <key>_coordinate</key> - <value>(952, 275)</value> + <value>(8, 75)</value> </param> <param> <key>_rotation</key> @@ -251,38 +206,42 @@ </param> </block> <block> - <key>notebook</key> + <key>ha5kfu_execproc_xx</key> <param> <key>id</key> - <value>nb0</value> + <value>ha5kfu_execproc_xx_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>style</key> - <value>wx.NB_TOP</value> + <key>type</key> + <value>cc</value> </param> <param> - <key>labels</key> - <value>['shift_math_ff', 'shift_addition_ff', 'original']</value> + <key>commandline</key> + <value>"csdr shift_math_cc %g"%rate</value> </param> <param> - <key>grid_pos</key> + <key>alias</key> <value></value> </param> <param> - <key>notebook</key> + <key>affinity</key> <value></value> </param> <param> - <key>alias</key> - <value></value> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> </param> <param> <key>_coordinate</key> - <value>(256, 27)</value> + <value>(488, 251)</value> </param> <param> <key>_rotation</key> @@ -290,10 +249,10 @@ </param> </block> <block> - <key>wxgui_fftsink2</key> + <key>ha5kfu_execproc_xx</key> <param> <key>id</key> - <value>wxgui_fftsink2_0_0</value> + <value>ha5kfu_execproc_xx_0_0</value> </param> <param> <key>_enabled</key> @@ -301,63 +260,54 @@ </param> <param> <key>type</key> - <value>complex</value> - </param> - <param> - <key>title</key> - <value>FFT Plot</value> - </param> - <param> - <key>samp_rate</key> - <value>samp_rate</value> + <value>cc</value> </param> <param> - <key>baseband_freq</key> - <value>0</value> + <key>commandline</key> + <value>"csdr shift_addition_cc %g"%rate</value> </param> <param> - <key>y_per_div</key> - <value>10</value> + <key>alias</key> + <value></value> </param> <param> - <key>y_divs</key> - <value>10</value> + <key>affinity</key> + <value></value> </param> <param> - <key>ref_level</key> + <key>minoutbuf</key> <value>0</value> </param> <param> - <key>ref_scale</key> - <value>2.0</value> - </param> - <param> - <key>fft_size</key> - <value>1024</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>fft_rate</key> - <value>15</value> + <key>_coordinate</key> + <value>(472, 411)</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>_rotation</key> + <value>0</value> </param> + </block> + <block> + <key>notebook</key> <param> - <key>average</key> - <value>False</value> + <key>id</key> + <value>nb0</value> </param> <param> - <key>avg_alpha</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>win</key> - <value>None</value> + <key>style</key> + <value>wx.NB_TOP</value> </param> <param> - <key>win_size</key> - <value></value> + <key>labels</key> + <value>['shift_math_cc', 'shift_addition_cc', 'shift_table_cc', 'decimating_shift_addition_cc','original']</value> </param> <param> <key>grid_pos</key> @@ -365,23 +315,15 @@ </param> <param> <key>notebook</key> - <value>nb0,2</value> - </param> - <param> - <key>freqvar</key> - <value>None</value> - </param> - <param> - <key>alias</key> <value></value> </param> <param> - <key>affinity</key> + <key>alias</key> <value></value> </param> <param> <key>_coordinate</key> - <value>(952, 59)</value> + <value>(272, 11)</value> </param> <param> <key>_rotation</key> @@ -392,7 +334,7 @@ <key>wxgui_fftsink2</key> <param> <key>id</key> - <value>wxgui_fftsink2_0_1</value> + <value>wxgui_fftsink2_0_0</value> </param> <param> <key>_enabled</key> @@ -464,7 +406,7 @@ </param> <param> <key>notebook</key> - <value>nb0,1</value> + <value>nb0,4</value> </param> <param> <key>freqvar</key> @@ -480,7 +422,7 @@ </param> <param> <key>_coordinate</key> - <value>(952, 635)</value> + <value>(496, 27)</value> </param> <param> <key>_rotation</key> @@ -531,7 +473,7 @@ </param> <param> <key>_coordinate</key> - <value>(232, 275)</value> + <value>(224, 107)</value> </param> <param> <key>_rotation</key> @@ -542,7 +484,7 @@ <key>wxgui_scopesink2</key> <param> <key>id</key> - <value>wxgui_scopesink2_0</value> + <value>wxgui_scopesink2_0_0_0</value> </param> <param> <key>_enabled</key> @@ -594,7 +536,7 @@ </param> <param> <key>notebook</key> - <value>nb0,0</value> + <value>nb0,2</value> </param> <param> <key>trig_mode</key> @@ -614,7 +556,7 @@ </param> <param> <key>_coordinate</key> - <value>(952, 491)</value> + <value>(1080, 899)</value> </param> <param> <key>_rotation</key> @@ -622,10 +564,10 @@ </param> </block> <block> - <key>wxgui_scopesink2</key> + <key>wxgui_fftsink2</key> <param> <key>id</key> - <value>wxgui_scopesink2_0_0</value> + <value>wxgui_fftsink2_0_1_0_0</value> </param> <param> <key>_enabled</key> @@ -637,35 +579,55 @@ </param> <param> <key>title</key> - <value>Scope Plot</value> + <value>FFT Plot</value> </param> <param> <key>samp_rate</key> - <value>samp_rate</value> + <value>samp_rate/decimation</value> </param> <param> - <key>v_scale</key> + <key>baseband_freq</key> <value>0</value> </param> <param> - <key>v_offset</key> - <value>0</value> + <key>y_per_div</key> + <value>10</value> </param> <param> - <key>t_scale</key> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> <value>0</value> </param> <param> - <key>ac_couple</key> + <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>xy_mode</key> + <key>average</key> <value>False</value> </param> <param> - <key>num_inputs</key> - <value>1</value> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>win</key> + <value>None</value> </param> <param> <key>win_size</key> @@ -677,10 +639,357 @@ </param> <param> <key>notebook</key> - <value>nb0,1</value> + <value>nb0,3</value> </param> <param> - <key>trig_mode</key> + <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>(320, 667)</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_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>Scope Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate/decimation</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,3</value> + </param> + <param> + <key>trig_mode</key> + <value>wxgui.TRIG_MODE_NORM</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>(320, 883)</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_0_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>cc</value> + </param> + <param> + <key>commandline</key> + <value>"csdr decimating_shift_addition_cc %g %d"%(rate, 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>(80, 835)</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_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>cc</value> + </param> + <param> + <key>commandline</key> + <value>"csdr shift_table_cc %g 32768"%rate</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>(824, 771)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>wxgui_fftsink2_0_1_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</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,2</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>(1080, 691)</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>complex</value> + </param> + <param> + <key>title</key> + <value>Scope Plot</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,1</value> + </param> + <param> + <key>trig_mode</key> <value>wxgui.TRIG_MODE_NORM</value> </param> <param> @@ -697,7 +1006,7 @@ </param> <param> <key>_coordinate</key> - <value>(952, 875)</value> + <value>(824, 571)</value> </param> <param> <key>_rotation</key> @@ -705,10 +1014,10 @@ </param> </block> <block> - <key>ha5kfu_execproc_xx</key> + <key>wxgui_fftsink2</key> <param> <key>id</key> - <value>ha5kfu_execproc_xx_0</value> + <value>wxgui_fftsink2_0_1</value> </param> <param> <key>_enabled</key> @@ -716,31 +1025,87 @@ </param> <param> <key>type</key> - <value>cc</value> + <value>complex</value> </param> <param> - <key>commandline</key> - <value>csdr shift_math_cc -0.25</value> + <key>title</key> + <value>FFT Plot</value> </param> <param> - <key>alias</key> - <value></value> + <key>samp_rate</key> + <value>samp_rate</value> </param> <param> - <key>affinity</key> - <value></value> + <key>baseband_freq</key> + <value>0</value> </param> <param> - <key>minoutbuf</key> + <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>maxoutbuf</key> + <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>(496, 483)</value> + <value>(824, 355)</value> </param> <param> <key>_rotation</key> @@ -748,10 +1113,10 @@ </param> </block> <block> - <key>ha5kfu_execproc_xx</key> + <key>wxgui_scopesink2</key> <param> <key>id</key> - <value>ha5kfu_execproc_xx_0_0</value> + <value>wxgui_scopesink2_0</value> </param> <param> <key>_enabled</key> @@ -759,11 +1124,59 @@ </param> <param> <key>type</key> - <value>cc</value> + <value>complex</value> </param> <param> - <key>commandline</key> - <value>csdr shift_addition_cc -0.25</value> + <key>title</key> + <value>Scope Plot</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_NORM</value> + </param> + <param> + <key>y_axis_label</key> + <value>Counts</value> </param> <param> <key>alias</key> @@ -774,16 +1187,107 @@ <value></value> </param> <param> - <key>minoutbuf</key> + <key>_coordinate</key> + <value>(824, 235)</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>maxoutbuf</key> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</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,0</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>(504, 635)</value> + <value>(824, 19)</value> </param> <param> <key>_rotation</key> @@ -838,4 +1342,40 @@ <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_0_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_0_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>ha5kfu_execproc_xx_0_0_0_0</source_block_id> + <sink_block_id>wxgui_scopesink2_0_0_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>ha5kfu_execproc_xx_0_0_0_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0_1_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>ha5kfu_execproc_xx_0_0_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0_1_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>ha5kfu_execproc_xx_0_0_0</source_block_id> + <sink_block_id>wxgui_scopesink2_0_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> </flow_graph> diff --git a/ima_adpcm.c b/ima_adpcm.c new file mode 100644 index 0000000000000000000000000000000000000000..03a9b7c579b1eb5e0428fac99ef0a1a582740686 --- /dev/null +++ b/ima_adpcm.c @@ -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 diff --git a/ima_adpcm.h b/ima_adpcm.h new file mode 100644 index 0000000000000000000000000000000000000000..7e7bd9d726bc65c096b6873b78c8e878500dc944 --- /dev/null +++ b/ima_adpcm.h @@ -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 diff --git a/libcsdr.c b/libcsdr.c index 7d6e449e4103fbecb687dccc608f9df97d9ea74b..2cf5e9b913e7483acdf37f8b1499b92c25f6b762 100644 --- a/libcsdr.c +++ b/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; diff --git a/libcsdr.h b/libcsdr.h index a66d72b19377848fc0f3b5e6c85368a1cf402d22..99774028fc057a12feaec4db063e84ad83f1ed04 100644 --- a/libcsdr.h +++ b/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); diff --git a/libcsdr_gpl.c b/libcsdr_gpl.c index 7798ae91acfe119b662be7eb8ae44434b2c1ae89..c17390daf97a6b8e5b63ab3c6deb1167f04a49ed 100644 --- a/libcsdr_gpl.c +++ b/libcsdr_gpl.c @@ -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) { /* diff --git a/libcsdr_gpl.h b/libcsdr_gpl.h index 98c0febbb0a7cd1b6b6d74e8941b0db0b68585a5..a4bfd230800940c6d6b58a0237938a7a615ed984 100644 --- a/libcsdr_gpl.h +++ b/libcsdr_gpl.h @@ -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 diff --git a/libcsdr_wrapper.c b/libcsdr_wrapper.c index 4ab53e3f0c35ae3c76eab98b755fa0c5adcd586d..3e6ab8772181395e3bbff123e8d78d3c19081c26 100644 --- a/libcsdr_wrapper.c +++ b/libcsdr_wrapper.c @@ -1,3 +1,4 @@ #include "libcsdr.c" #include "libcsdr_gpl.c" +#include "ima_adpcm.c" //this wrapper helps parsevect.py to generate better output diff --git a/predefined.h b/predefined.h index e0c74bbe9948a914b8757461df3e2498a829d917..a00607f33a20d5195a0d63628fc24e8b38ad400b 100644 --- a/predefined.h +++ b/predefined.h @@ -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 }; diff --git a/sdr.js/exported_functions.py b/sdr.js/exported_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..28b0021a19e915c60b9c7fe500290535ddc714ed --- /dev/null +++ b/sdr.js/exported_functions.py @@ -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))+"]" diff --git a/sdr.js/sdrjs-footer.js b/sdr.js/sdrjs-footer.js new file mode 100644 index 0000000000000000000000000000000000000000..21ea9925e9ce1e125601ee311f608980f782172f --- /dev/null +++ b/sdr.js/sdrjs-footer.js @@ -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; +} diff --git a/sdr.js/sdrjs-header.js b/sdr.js/sdrjs-header.js new file mode 100644 index 0000000000000000000000000000000000000000..f37e171608199b1a51155d746d9ad7fdfef90493 --- /dev/null +++ b/sdr.js/sdrjs-header.js @@ -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: ========= +// ========================================================== +