├── .gitignore ├── CMakeLists.txt ├── LICENSE-GPL ├── README.md ├── cmake ├── DetectIfunc.cmake └── ifunc_test.c ├── debian ├── changelog ├── compat ├── control ├── copyright ├── csdr.install ├── libcsdr-dev.install ├── libcsdr0.install ├── nmux.install ├── rules └── source │ ├── format │ └── options ├── grc_tests ├── bpsk31_baseband_sample_complex_8000_sps_010101.raw ├── bpsk31_ber.py ├── bpsk31_scurve.m ├── bpsk31_tedvar.m ├── psk31_sigmodel.m ├── test_agc_gen.grc ├── test_agc_get_testfile.sh ├── test_agc_wav.grc ├── test_amdemod.grc ├── test_ammod.grc ├── test_awgn.grc ├── test_bandpass_fir_fft.grc ├── test_bandpass_fir_fft_via_fifo.grc ├── test_bpsk31_parts.grc ├── test_bpsk31_to_octave.grc ├── test_bpsk_costas_loop.grc ├── test_bpsk_costas_loop_convertwavs.sh ├── test_conversions.grc ├── test_dcblock.grc ├── test_debug_gr_agc2.grc ├── test_deemphasis_nfm.grc ├── test_deemphasis_wfm.grc ├── test_dsb.grc ├── test_fastddc.grc ├── test_fft_grc.grc ├── test_fir_interpolate_cc.grc ├── test_fixed_amplitude_cc.grc ├── test_fmdemod.grc ├── test_fmmod.grc ├── test_fractional_decimator.grc ├── test_ima_adpcm.grc ├── test_m_fsk.grc ├── test_noise.grc ├── test_peaks_fir.grc ├── test_rational_resampler.grc ├── test_rtty_parts.grc ├── test_shift.grc ├── test_shift_remote.grc ├── test_shift_remote.sh ├── test_simple_agc.grc ├── test_ssb_concepts.grc └── test_ssbgen.grc ├── include ├── adpcm.hpp ├── afc.hpp ├── agc.hpp ├── amdemod.hpp ├── async.hpp ├── audioresampler.hpp ├── baudot.hpp ├── benchmark.hpp ├── ccir476.hpp ├── ccir493.hpp ├── complex.hpp ├── converter.hpp ├── cw.hpp ├── dbpsk.hpp ├── dcblock.hpp ├── deemphasis.hpp ├── downmix.hpp ├── dsc.hpp ├── exec.hpp ├── fax.hpp ├── fft.hpp ├── fftexchangesides.hpp ├── fftfilter.hpp ├── filter.hpp ├── fir.hpp ├── firdecimate.hpp ├── fmdemod.hpp ├── fractionaldecimator.hpp ├── gain.hpp ├── limit.hpp ├── logaveragepower.hpp ├── logpower.hpp ├── mfrtty.hpp ├── module.hpp ├── navtex.hpp ├── noise.hpp ├── noisefilter.hpp ├── phasedemod.hpp ├── power.hpp ├── reader.hpp ├── realpart.hpp ├── ringbuffer.hpp ├── rtty.hpp ├── shift.hpp ├── sink.hpp ├── sitorb.hpp ├── snr.hpp ├── source.hpp ├── sstv.hpp ├── throttle.hpp ├── timingrecovery.hpp ├── varicode.hpp ├── version.hpp ├── window.hpp └── writer.hpp └── src ├── CMakeLists.txt ├── Config.cmake.in ├── apps ├── CMakeLists.txt ├── csdr │ ├── CLI11.hpp │ ├── CMakeLists.txt │ ├── commands.cpp │ ├── commands.hpp │ ├── csdr.cpp │ └── csdr.hpp └── nmux │ ├── CMakeLists.txt │ ├── nmux.cpp │ ├── nmux.h │ ├── shims.h │ ├── tsmpool.cpp │ └── tsmpool.h ├── csdr.pc.in └── lib ├── CMakeLists.txt ├── adpcm.cpp ├── afc.cpp ├── agc.cpp ├── amdemod.cpp ├── async.cpp ├── audioresampler.cpp ├── baudot.cpp ├── benchmark.cpp ├── ccir476.cpp ├── ccir493.cpp ├── converter.cpp ├── cw.cpp ├── dbpsk.cpp ├── dcblock.cpp ├── deemphasis.cpp ├── downmix.cpp ├── dsc.cpp ├── exec.cpp ├── fax.cpp ├── fft.cpp ├── fftexchangesides.cpp ├── fftfilter.cpp ├── filter.cpp ├── fir.cpp ├── firdecimate.cpp ├── fmdemod.cpp ├── fmv.h ├── fractionaldecimator.cpp ├── gain.cpp ├── limit.cpp ├── logaveragepower.cpp ├── logpower.cpp ├── mfrtty.cpp ├── module.cpp ├── navtex.cpp ├── noise.cpp ├── noisefilter.cpp ├── phasedemod.cpp ├── power.cpp ├── predefined.h ├── reader.cpp ├── realpart.cpp ├── ringbuffer.cpp ├── rtty.cpp ├── shift.cpp ├── sink.cpp ├── sitorb.cpp ├── snr.cpp ├── source.cpp ├── sstv.cpp ├── throttle.cpp ├── timingrecovery.cpp ├── varicode.cpp ├── version.cpp ├── window.cpp └── writer.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij Idea 2 | .idea 3 | # cmake 4 | build -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | cmake_minimum_required (VERSION 3.0) 19 | 20 | if(NOT CMAKE_BUILD_TYPE) 21 | set(CMAKE_BUILD_TYPE Release) 22 | endif() 23 | 24 | if (CMAKE_BUILD_TYPE STREQUAL None) 25 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 26 | endif() 27 | 28 | project (csdr VERSION 0.18.2) 29 | add_definitions(-DVERSION="${PROJECT_VERSION}") 30 | 31 | enable_language(CXX) 32 | set(CMAKE_CXX_STANDARD 11) 33 | 34 | include(GNUInstallDirs) 35 | 36 | find_package(Threads REQUIRED) 37 | 38 | include(CheckLibraryExists) 39 | check_library_exists(m floorf "" CSDR_HAS_LIBM) 40 | 41 | include(FindPkgConfig) 42 | pkg_check_modules(FFTW3 REQUIRED fftw3f) 43 | 44 | include(cmake/DetectIfunc.cmake) 45 | 46 | pkg_check_modules(SAMPLERATE REQUIRED samplerate) 47 | 48 | if(NOT DEFINED CSDR_GPL) 49 | set(CSDR_GPL true) 50 | endif() 51 | 52 | if(NOT DEFINED CSDR_IMA_ADPCM) 53 | set(CSDR_IMA_ADPCM true) 54 | endif() 55 | 56 | if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") 57 | SET(CMAKE_CXX_FLAGS "-ffast-math -mfpmath=sse") 58 | SET(CMAKE_C_FLAGS "-ffast-math -mfpmath=sse") 59 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ^arm.*) 60 | execute_process(COMMAND "cat" "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO) 61 | string(FIND ${CPUINFO} "neon" NEON_POSITION) 62 | if(NEON_POSITION GREATER_EQUAL 0) 63 | set(HAS_NEON true) 64 | endif() 65 | if (HAS_NEON) 66 | SET(CMAKE_CXX_FLAGS "-ffast-math -march=armv7-a -mtune=cortex-a8 -funsafe-math-optimizations -Wformat=0 -mfloat-abi=hard -mfpu=neon -mvectorize-with-neon-quad") 67 | SET(CMAKE_C_FLAGS "-ffast-math -march=armv7-a -mtune=cortex-a8 -funsafe-math-optimizations -Wformat=0 -mfloat-abi=hard -mfpu=neon -mvectorize-with-neon-quad") 68 | else() 69 | SET(CMAKE_CXX_FLAGS "-ffast-math -march=armv7-a -mtune=cortex-a8 -funsafe-math-optimizations -Wformat=0") 70 | SET(CMAKE_C_FLAGS "-ffast-math -march=armv7-a -mtune=cortex-a8 -funsafe-math-optimizations -Wformat=0") 71 | endif() 72 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ^aarch64.*) 73 | # aarch64 mandated neon 74 | set(HAS_NEON true) 75 | SET(CMAKE_CXX_FLAGS "-ffast-math -march=armv8-a -mtune=cortex-a72 -funsafe-math-optimizations -Wformat=0") 76 | SET(CMAKE_C_FLAGS "-ffast-math -march=armv8-a -mtune=cortex-a72 -funsafe-math-optimizations -Wformat=0") 77 | endif() 78 | 79 | SET(CMAKE_CXX_FLAGS_RELEASE "-O3") 80 | SET(CMAKE_C_FLAGS_RELEASE "-O3") 81 | SET(CMAKE_CXX_FLAGS_DEBUG "-g -O3") 82 | SET(CMAKE_C_FLAGS_DEBUG "-g -O3") 83 | SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O3 -DNDEBUG") 84 | SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O3 -DNDEBUG") 85 | 86 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 87 | 88 | add_subdirectory(src) 89 | -------------------------------------------------------------------------------- /cmake/DetectIfunc.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | try_compile(HAS_IFUNC "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ifunc_test.c") -------------------------------------------------------------------------------- /cmake/ifunc_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021-2022 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #if defined(__x86_64) 21 | __attribute__((target_clones("avx","sse4.2","sse3","sse2","default"))) 22 | #endif 23 | void ifunc_test() {} 24 | int main(int argc, char** argv) {} -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: csdr 2 | Maintainer: Marat Fayzullin 3 | Section: hamradio 4 | Priority: optional 5 | Standards-Version: 4.3.0 6 | Build-Depends: debhelper (>= 10), libfftw3-dev (>= 3.3), libsamplerate0-dev (>= 0.1.8) 7 | 8 | Package: libcsdr0 9 | Architecture: any 10 | Depends: ${shlibs:Depends}, ${misc:Depends} 11 | Description: simple library for software defined radio 12 | A simple DSP library for Software Defined Radio. 13 | 14 | Package: libcsdr-dev 15 | Architecture: any 16 | Depends: libcsdr0 (=${binary:Version}), libfftw3-dev (>= 3.3), libsamplerate0-dev (>= 0.1.8), ${shlibs:Depends}, ${misc:Depends} 17 | Description: development dependencies includes for libcsdr 18 | A simple DSP library for Software Defined Radio. 19 | 20 | Package: csdr 21 | Architecture: any 22 | Depends: libcsdr0 (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends} 23 | Recommends: nmux (=${binary:Version}) 24 | Description: command-line sdr 25 | A simple DSP command-line tool for Software Defined Radio. 26 | 27 | Package: nmux 28 | Architecture: any 29 | Depends: ${shlibs:Depends}, ${misc:Depends} 30 | Conflicts: csdr (<= 0.18.0~133) 31 | Description: TCP stream multiplexer 32 | It reads data from the standard input, and sends it to each client connected 33 | through TCP sockets. 34 | -------------------------------------------------------------------------------- /debian/csdr.install: -------------------------------------------------------------------------------- 1 | usr/bin/csdr* -------------------------------------------------------------------------------- /debian/libcsdr-dev.install: -------------------------------------------------------------------------------- 1 | usr/include 2 | usr/lib/*/pkgconfig 3 | usr/lib/*/*.so 4 | usr/lib/*/cmake -------------------------------------------------------------------------------- /debian/libcsdr0.install: -------------------------------------------------------------------------------- 1 | usr/lib/*/*.so.* -------------------------------------------------------------------------------- /debian/nmux.install: -------------------------------------------------------------------------------- 1 | usr/bin/nmux -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | 5 | override_dh_builddeb: 6 | dh_builddeb -- -Zxz 7 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/source/options: -------------------------------------------------------------------------------- 1 | # Use xz instead of zstd 2 | compression = "xz" 3 | -------------------------------------------------------------------------------- /grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luarvique/csdr/a067f35231706ad6edd85a216f50ff72cd17f19d/grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw -------------------------------------------------------------------------------- /grc_tests/bpsk31_ber.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os, time, signal 4 | from subprocess import * 5 | #https://bugs.python.org/issue1652 6 | 7 | def p(x): 8 | global printcmds 9 | if printcmds: print x 10 | return check_output(x, shell=True) 11 | 12 | printcmds=True 13 | 14 | 15 | def genfiles(snr): 16 | cmd="""(while true; do echo -n 'CQ CQ CQ DE HA7ILM HA7ILM HA7ILM PSE K '; done) | \ 17 | csdr psk31_varicode_encoder_u8_u8 | \ 18 | tee /s/bpsk31_testin | \ 19 | csdr differential_encoder_u8_u8 | \ 20 | csdr psk_modulator_u8_c 2 | \ 21 | csdr psk31_interpolate_sine_cc 256 | \ 22 | csdr awgn_cc %d | \ 23 | csdr timing_recovery_cc GARDNER 256 0.5 2 --add_q | \ 24 | csdr dbpsk_decoder_c_u8 | \ 25 | dd bs=1024 count=10 of=/s/bpsk31_testout 26 | """%snr 27 | signal.signal(signal.SIGPIPE, signal.SIG_DFL) 28 | if printcmds: print cmd 29 | os.system(cmd) 30 | 31 | def getminsize(): 32 | return min(os.path.getsize("/s/bpsk31_testout"), os.path.getsize("/s/bpsk31_testin")) 33 | 34 | def mkdiff(shift): 35 | if shift==0: 36 | return int(p("cmp -l /s/bpsk31_testin /s/bpsk31_testout | wc -l")) 37 | elif shift<0: 38 | return int(p("(dd if=/dev/zero bs=%d count=1; cat /s/bpsk31_testin)>/s/bpsk31_testin0; cmp -l /s/bpsk31_testin0 /s/bpsk31_testout | wc -l"%-shift)) 39 | elif shift>0: 40 | return int(p("(dd if=/dev/zero bs=%d count=1; cat /s/bpsk31_testout)>/s/bpsk31_testout0; cmp -l /s/bpsk31_testin /s/bpsk31_testout0 | wc -l"%shift)) 41 | 42 | 43 | lf=open("/s/output_results","w") 44 | 45 | for snr in range(0,20,2): 46 | genfiles(snr) 47 | num_totalbits=getminsize() 48 | num_errors=None 49 | for shift in range(-5,5): 50 | curr_num_errors = mkdiff(shift) 51 | if not num_errors or (num_errors and num_errors > curr_num_errors): 52 | num_errors = curr_num_errors 53 | lf.write("%d; %d; %d; %d\n" %(snr, num_errors, num_totalbits, num_errors/float(num_totalbits))) 54 | -------------------------------------------------------------------------------- /grc_tests/bpsk31_scurve.m: -------------------------------------------------------------------------------- 1 | #!/usr/bin/octave 2 | 3 | %{ 4 | function [output]=fgc(path, type) 5 | if(type(1)=='f') 6 | elseif(type(1)=='c') 7 | end 8 | end 9 | %} 10 | 11 | function output=shrunf(cmd) 12 | SIGTERM=15; 13 | output=[]; 14 | [pin, pout, pid]=popen2('bash',{'-c', cmd}); 15 | %fclose(pin); 16 | sleep(0.1) 17 | do 18 | current_output=fread(pout, Inf, 'float32'); 19 | output=[output; current_output]; 20 | until(feof(pout)) 21 | waitpid(pid); 22 | %kill(pid, SIGTERM); 23 | fclose(pin); 24 | fclose(pout); 25 | end 26 | 27 | function error_value=run_tr(skip, which_ted) 28 | out_vect=shrunf(sprintf('dd bs=8 skip=%d if=bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc %s 256 --add_q --output_error', skip, which_ted)); 29 | error_value=out_vect(2); 30 | end 31 | 32 | function error_values=mkscurve(which_ted, skips) 33 | error_values=[] 34 | for skip=skips 35 | error_values=[error_values run_tr(skip, which_ted)]; 36 | end 37 | end 38 | 39 | function fmtplot(h) 40 | FN = findall(h,'-property','FontName'); 41 | set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); 42 | set(FN,'FontName','times'); 43 | FS = findall(h,'-property','FontSize'); 44 | set(FS,'FontSize',18); 45 | xlabel('Phase offset in number of samples'); 46 | ylabel('Error value (TED output)'); 47 | end 48 | 49 | skips_gardner=0:16:256 50 | error_values_gardner=mkscurve('GARDNER',skips_gardner); 51 | skips_earlylate=0:16:256 52 | error_values_earlylate=mkscurve('EARLYLATE',skips_earlylate); 53 | 54 | %graphics_toolkit("gnuplot") 55 | h=figure(1); 56 | 57 | plot((skips_gardner-128)/256, -error_values_gardner, 'linewidth', 2); 58 | title('S-curve for Gardner TED'); 59 | fmtplot(h) 60 | grid on 61 | pause 62 | 63 | plot((skips_earlylate-128)/256, error_values_earlylate, 'linewidth', 2); 64 | title('S-curve for early-late TED'); 65 | fmtplot(h) 66 | grid on 67 | pause 68 | -------------------------------------------------------------------------------- /grc_tests/bpsk31_tedvar.m: -------------------------------------------------------------------------------- 1 | #!/usr/bin/octave 2 | 3 | %you need to first install the parallel and struct packages: 4 | %pkg install -forge struct 5 | %pkg install -forge parallel 6 | pkg load parallel 7 | 8 | function y=inarg(x) 9 | for i=1:length(argv()) 10 | if strcmp(argv(){i},x) 11 | y=1; 12 | return 13 | end 14 | end 15 | y=0; 16 | end 17 | 18 | bpfcmd="csdr bandpass_fir_fft_cc $(csdr \"=-31.25/8e3\") $(csdr \"=31.25/8e3\") $(csdr \"=31.25/8e3\") | "; 19 | 20 | if !inarg('--nogen') 21 | fwrite(stdout, "===========================================\nGenerating baseband signal from random data\n===========================================\n"); 22 | system(["cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | " bpfcmd "csdr add_n_zero_samples_at_beginning_f 170 | pv -ps 2g | dd iflag=fullblock bs=128M count=16 of=/tmp/psk31-raw-data"]); 23 | fwrite(stdout, "===========================================\nGenerating Gaussian white noise for agwn_cc\n===========================================\n"); 24 | system(["csdr gaussian_noise_c | " bpfcmd "pv -ps 256m | dd of=/tmp/psk31-gaussian-noise iflag=fullblock bs=256M count=1"]); 25 | end 26 | if inarg('--onlygen') 27 | exit(0) 28 | end 29 | fwrite(stdout, "===========================================\nCalculating variance graph data \n===========================================\n"); 30 | 31 | function output=shrun(cmd, type, minsize) 32 | SIGTERM=15; 33 | output=[]; 34 | cmd 35 | [pin, pout, pid]=popen2('bash',{'-c', cmd}); 36 | %fclose(pin); 37 | do 38 | sleep(0.3) 39 | fwrite(stdout,'.'); 40 | %size(output) 41 | %output 42 | current_output=fread(pout, Inf, type); 43 | frewind(pout); 44 | output=[output; current_output]; 45 | until(size(output)(1)>=minsize) 46 | waitpid(pid); 47 | kill(pid, SIGTERM); 48 | fclose(pin); 49 | fclose(pout); 50 | end 51 | 52 | function variance=run_var(snr, which_ted) 53 | disp('ran a command') 54 | out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr simple_agc_cc 0.0001 0.5 | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); 55 | disp('run_var output:'); 56 | out_vect' 57 | variance=out_vect(1); 58 | end 59 | 60 | function variances=mkvarplot(which_ted, snrs) 61 | fun = @(x) run_var(x, which_ted); 62 | variances=pararrayfun(nproc, fun, snrs); 63 | %{ 64 | variances=[] 65 | for snr=snrs 66 | snr 67 | variances=[variances run_var(snr, which_ted)]; 68 | end 69 | %} 70 | end 71 | 72 | function fmtplot(h) 73 | FN = findall(h,'-property','FontName'); 74 | set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); 75 | set(FN,'FontName','times'); 76 | FS = findall(h,'-property','FontSize'); 77 | set(FS,'FontSize',18); 78 | xlabel('E_b/N_0 [dB]'); 79 | ylabel('Phase error variance [rad^2]'); 80 | end 81 | 82 | %snrs=-10:5:10 83 | snrs=-10:5:25 84 | %snrs=[10] 85 | error_values=mkvarplot('EARLYLATE',snrs); 86 | 87 | %graphics_toolkit("gnuplot") 88 | h=figure(1); 89 | 90 | ebn0=snrs+9.7 91 | 92 | semilogy(ebn0, error_values, 'linewidth', 2); 93 | title('Estimation variance'); 94 | fmtplot(h) 95 | pause 96 | 97 | if !inarg('--nogen') 98 | system('rm /tmp/psk31-raw-data /tmp/psk31-gaussian-noise'); 99 | end 100 | -------------------------------------------------------------------------------- /grc_tests/psk31_sigmodel.m: -------------------------------------------------------------------------------- 1 | #!/usr/bin/octave 2 | 3 | global Tb=20 4 | 5 | function g=gbb(t) %impulse response of pulse shaping filter 6 | global Tb 7 | g=t; 8 | for i = 1:size(t)(2) 9 | if (t(i)>1*Tb || t(i)<=-1*Tb) 10 | g(i) = 0; 11 | else 12 | g(i) = 0.5+cos((t(i)/(Tb*1))*pi)/2; %this is not RRC, rather a sinusoidal pulse shape 13 | end 14 | end 15 | end 16 | 17 | global padding=[-2 2]; 18 | 19 | function [toreturny, plotrange]=y(s) 20 | global Tb 21 | global padding 22 | slen=size(s)(2) 23 | plotrange=((padding(1)-1)*Tb):(slen+padding(2))*Tb-1; 24 | plotlen=size(plotrange)(2) 25 | toreturny=zeros(1,plotlen); 26 | for i=1:slen %sum of (symbol[i] * filter impulse response) for all symbols 27 | toreturny+=s(i)*gbb(plotrange.-(i-1)*Tb); 28 | end 29 | plotrange=plotrange/Tb 30 | end 31 | 32 | function fmtplot(h) 33 | FN = findall(h,'-property','FontName'); 34 | set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); 35 | set(FN,'FontName','times'); 36 | FS = findall(h,'-property','FontSize'); 37 | set(FS,'FontSize',18); 38 | set(FS,'FontSize',18); 39 | end 40 | 41 | h=figure(1); 42 | subplot(2, 1, 1); 43 | [a b]=y([1]); 44 | plot(b, a, 'linewidth', 2) 45 | title(sprintf("Impulse response of pulse shaping filter")) 46 | xlabel('t/Ts') 47 | ylabel('h(t)') 48 | 49 | subplot(2, 1, 2); 50 | [a b]=y([1 1 -1 -1 1 1 1 -1 1 -1 1 1]); 51 | plot(b, a, 'linewidth', 2) 52 | title("Baseband signal for modulator input\nbit sequence: 110011101011") %assuming that differential encoding has already been performed 53 | xlabel('t/Ts') 54 | ylabel('s(t)') 55 | xbounds = xlim; 56 | set(gca,'XTick',xbounds(1):xbounds(2)); 57 | fmtplot(h); 58 | pause 59 | exit 60 | 61 | %fourier analisys of baseband signal 62 | h2=figure(2); 63 | padding=[-1 1] 64 | plot(y([1])) 65 | h3=figure(3); 66 | fftvals=abs(fft(y([1]))); 67 | sizefftvals=size(fftvals)(2) 68 | fftvals=[fftvals(sizefftvals/2:sizefftvals) fftvals(2:sizefftvals/2)] 69 | plot(fftvals, "-") 70 | pause 71 | -------------------------------------------------------------------------------- /grc_tests/test_agc_get_testfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo \"agctest\" signal was made by SM5BSZ. 3 | echo downloading... 4 | wget -O agctest-125.zip http://sm5bsz.com/lir/agctest/agctest-125.zip 5 | echo unzipping... 6 | unzip agctest-125.zip 7 | echo converting wav to 48000 kHz Mono... 8 | sox agctest-125.wav -r48000 -c1 agctest.wav 9 | echo deleting temporary files... 10 | rm agctest-125.zip 11 | rm agctest-125.wav 12 | -------------------------------------------------------------------------------- /grc_tests/test_bpsk_costas_loop_convertwavs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sox -r 48k -t f32 -c 2 /s/costas_nco -t wav -e floating-point /s/costas_nco.wav 3 | sox -r 48k -t f32 -c 1 /s/costas_error -t wav -e floating-point /s/costas_error.wav 4 | sox -r 48k -t f32 -c 1 /s/costas_dphase -t wav -e floating-point --norm=-6 /s/costas_dphase.wav 5 | sox -r 48k -t f32 -c 2 /s/costas_input -t wav -e floating-point /s/costas_input.wav 6 | sox -r 48k -t f32 -c 2 /s/costas_output -t wav -e floating-point /s/costas_output.wav 7 | sox -r 48k -t f32 -c 2 /s/tr_input -t wav -e floating-point /s/tr_input.wav 8 | ls -al /s/costas_nco.wav /s/costas_error.wav /s/costas_dphase.wav /s/costas_output.wav /s/costas_input.wav 9 | 10 | 11 | -------------------------------------------------------------------------------- /grc_tests/test_shift_remote.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this script on a Raspberry Pi 2, while running test_shift_remote.grc on your PC. 3 | # It allows you to debug the NEON-accelerated version of specific DSP algorithms on the target hardware. 4 | TEMPSCRIPT="/tmp/test_shift_remote_exec.sh" 5 | echo '#!/bin/sh\ncsdr shift_addfast_cc -0.1' > $TEMPSCRIPT 6 | cat $TEMPSCRIPT 7 | chmod +x $TEMPSCRIPT 8 | ncat -vvl 5321 -e $TEMPSCRIPT 9 | rm $TEMPSCRIPT 10 | -------------------------------------------------------------------------------- /include/afc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "shift.hpp" 24 | 25 | #include 26 | 27 | namespace Csdr { 28 | 29 | class Afc: public ShiftAddfast { 30 | public: 31 | Afc(unsigned int updatePeriod = 4, unsigned int samplePeriod = 1); 32 | ~Afc(); 33 | 34 | protected: 35 | void process(complex* input, complex* output) override; 36 | 37 | private: 38 | // Configuration 39 | unsigned int updatePeriod; // Update period 40 | unsigned int samplePeriod; // Sampling period (<=updatePeriod) 41 | 42 | // State 43 | unsigned int updateCount; // Update counter 44 | double curShift; // Current frequency correction 45 | 46 | // FFT setup 47 | fftwf_complex *fftIn; 48 | fftwf_complex *fftOut; 49 | fftwf_plan fftPlan; 50 | 51 | // Compute squared magnitude of a complex value 52 | static float mag2(const fftwf_complex &v) 53 | { return(v[0]*v[0] + v[1]*v[1]); } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /include/agc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of libcsdr. 3 | 4 | Copyright (c) Andras Retzler, HA7ILM 5 | Copyright (c) Warren Pratt, NR0V 6 | Copyright (c) Jakob Ketterl, DD5JFK 7 | Copyright 2006,2010,2012 Free Software Foundation, Inc. 8 | 9 | libcsdr is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | libcsdr is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with libcsdr. If not, see . 21 | 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "module.hpp" 27 | #include "ringbuffer.hpp" 28 | #include "writer.hpp" 29 | 30 | namespace Csdr { 31 | 32 | class UntypedAgc { 33 | public: 34 | virtual ~UntypedAgc() = default; 35 | virtual void setReference(float reference) = 0; 36 | virtual void setAttack(float attack_rate) = 0; 37 | virtual void setDecay(float decay_rate) = 0; 38 | virtual void setMaxGain(float max_gain) = 0; 39 | virtual void setInitialGain(float initial_gain) = 0; 40 | virtual void setHangTime(unsigned long int hang_time) = 0; 41 | }; 42 | 43 | template 44 | class Agc: public UntypedAgc, public AnyLengthModule { 45 | public: 46 | void process(T* input, T* output, size_t work_size) override; 47 | 48 | void setReference(float reference) override; 49 | void setAttack(float attack_rate) override; 50 | void setDecay(float decay_rate) override; 51 | void setMaxGain(float max_gain) override; 52 | void setInitialGain(float initial_gain) override; 53 | void setHangTime(unsigned long int hang_time) override; 54 | private: 55 | float abs(T in); 56 | bool isZero(T in); 57 | T scale(T in); 58 | 59 | // params 60 | // fast profile defaults 61 | float reference = 0.8; 62 | float attack_rate = 0.1; 63 | float decay_rate = 0.001; 64 | float max_gain = 65535; 65 | unsigned long int hang_time = 200; 66 | float gain_filter_alpha = 1.5; 67 | // state 68 | float gain = 1; 69 | float last_peak = 0; 70 | unsigned long int hang_counter = 0; 71 | float xk = 0; 72 | float vk = 0; 73 | }; 74 | 75 | } -------------------------------------------------------------------------------- /include/amdemod.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | 25 | namespace Csdr { 26 | 27 | class AmDemod: public AnyLengthModule, float> { 28 | public: 29 | void process(complex* input, float* output, size_t work_size) override; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /include/async.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include 24 | #include 25 | 26 | namespace Csdr { 27 | 28 | class AsyncRunner { 29 | public: 30 | explicit AsyncRunner(UntypedModule* module); 31 | ~AsyncRunner(); 32 | void stop(); 33 | bool isRunning() const; 34 | private: 35 | void loop(); 36 | bool run = true; 37 | UntypedModule* module; 38 | std::mutex stateMutex; 39 | // any members that will be used by the thread must come above the thread itself in the member list here 40 | // C++ initializes the member variables in this order, so this ensures that members are available as soon 41 | // as the thread starts working 42 | std::thread thread; 43 | }; 44 | 45 | } -------------------------------------------------------------------------------- /include/audioresampler.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | #include 25 | 26 | namespace Csdr { 27 | 28 | class AudioResampler: public Module { 29 | public: 30 | AudioResampler(unsigned int inputRate, unsigned int outputRate); 31 | explicit AudioResampler(double rate); 32 | ~AudioResampler() override; 33 | bool canProcess() override; 34 | void process() override; 35 | private: 36 | double rate; 37 | SRC_STATE* srcState; 38 | }; 39 | 40 | } -------------------------------------------------------------------------------- /include/baudot.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | const unsigned char BAUDOT_LTR_SHIFT = 31; 27 | const unsigned char BAUDOT_FIG_SHIFT = 27; 28 | 29 | const unsigned char BAUDOT_LETTERS[] = { 30 | '\0', 'E', '\n', 'A', ' ', 'S', 'I', 'U', 31 | '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 32 | 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 33 | 'O', 'B', 'G', '\0', 'M', 'X', 'V', '\0' 34 | }; 35 | 36 | const unsigned char BAUDOT_FIGURES[] = { 37 | '\0', '3', '\n', '-', ' ', '\'', '8', '7', 38 | '\r', '$', '4', '\a', ',', '!', ':', '(', 39 | '5', '+', ')', '2', '#', '6', '0', '1', 40 | '9', '?', '&', '\0', '.', '/', '=', '\0' 41 | }; 42 | 43 | class BaudotDecoder: public Module { 44 | public: 45 | bool canProcess() override; 46 | void process() override; 47 | private: 48 | int mode = 0; 49 | }; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /include/benchmark.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014-2015, Andras Retzler 6 | Copyright (c) 2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include 35 | #include 36 | 37 | #include "module.hpp" 38 | 39 | namespace Csdr { 40 | 41 | class Benchmark { 42 | public: 43 | void run(); 44 | template 45 | void runModule(Module* module); 46 | template 47 | T* getTestData(); 48 | double timeTaken(struct ::timespec start, struct ::timespec end); 49 | }; 50 | 51 | } -------------------------------------------------------------------------------- /include/ccir476.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | const unsigned char CCIR476_LTR_SHIFT = 90; 27 | const unsigned char CCIR476_FIG_SHIFT = 54; 28 | const unsigned char CCIR476_SIA = 15; 29 | const unsigned char CCIR476_SIB = 51; 30 | const unsigned char CCIR476_RPT = 102; 31 | const unsigned char CCIR476_BLK = 106; 32 | const unsigned char CCIR476_BEL_FIG = 23; 33 | const unsigned char CCIR476_ENQ_FIG = 83; 34 | 35 | const unsigned char CCIR476_ZEROCOUNT[128] = { 36 | 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, // 0 37 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 16 38 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 32 39 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 48 40 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 64 41 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 80 42 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 96 43 | 4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0 // 112 44 | }; 45 | 46 | const unsigned char CCIR476_LETTERS[128] = { 47 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 48 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '>', // SIA 49 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'J', 50 | '\0', '\0', '\0', 'F', '\0', 'C', 'K', '\0', 51 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'W', 52 | '\0', '\0', '\0', 'Y', '\0', 'P', 'Q', '\0', 53 | '\0', '\0', '\0', '<', '\0', 'G', '\0', '\0', // SIB 54 | '\0', 'M', 'X', '\0', 'V', '\0', '\0', '\0', 55 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'A', 56 | '\0', '\0', '\0', 'S', '\0', 'I', 'U', '\0', 57 | '\0', '\0', '\0', 'D', '\0', 'R', 'E', '\0', 58 | '\0', 'N', '\0', '\0', ' ', '\0', '\0', '\0', 59 | '\0', '\0', '\0', 'Z', '\0', 'L', '^', '\0', // RPT 60 | '\0', 'H', '@', '\0', '\n', '\0', '\0', '\0', // BLK 61 | '\0', 'O', 'B', '\0', 'T', '\0', '\0', '\0', 62 | '\r', '\0', '\0', '\0', '\0', '\0', '\0', '\0' 63 | }; 64 | 65 | const unsigned char CCIR476_FIGURES[128] = { 66 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 67 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '>', // SIA 68 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\a', 69 | '\0', '\0', '\0', '!', '\0', ':', '(', '\0', 70 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '2', 71 | '\0', '\0', '\0', '6', '\0', '0', '1', '\0', 72 | '\0', '\0', '\0', '<', '\0', '&', '\0', '\0', // SIB 73 | '\0', '.', '/', '\0', '=', '\0', '\0', '\0', 74 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', 75 | '\0', '\0', '\0', '\'', '\0', '8', '7', '\0', 76 | '\0', '\0', '\0', '\0', '\0', '4', '3', '\0', 77 | '\0', ',', '\0', '\0', ' ', '\0', '\0', '\0', 78 | '\0', '\0', '\0', '+', '\0', ')', '^', '\0', // RPT 79 | '\0', '#', '@', '\0', '\n', '\0', '\0', '\0', // BLK 80 | '\0', '9', '?', '\0', '5', '\0', '\0', '\0', 81 | '\r', '\0', '\0', '\0', '\0', '\0', '\0', '\0' 82 | }; 83 | 84 | class Ccir476Decoder: public Module { 85 | public: 86 | bool canProcess() override; 87 | void process() override; 88 | 89 | private: 90 | int mode = 0; 91 | 92 | unsigned char ascii(unsigned char code); 93 | bool isValid(unsigned char code); 94 | }; 95 | 96 | } 97 | -------------------------------------------------------------------------------- /include/ccir493.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | const unsigned char CCIR493_ZEROCOUNT[128] = { 27 | 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, // 0 28 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 16 29 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 32 30 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 48 31 | 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, // 64 32 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 80 33 | 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, // 96 34 | 4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0 // 112 35 | }; 36 | 37 | const unsigned char CCIR493_PHASE_RX0 = 104; 38 | const unsigned char CCIR493_PHASE_RX1 = 105; 39 | const unsigned char CCIR493_PHASE_RX2 = 106; 40 | const unsigned char CCIR493_PHASE_RX3 = 107; 41 | const unsigned char CCIR493_PHASE_RX4 = 108; 42 | const unsigned char CCIR493_PHASE_RX5 = 109; 43 | const unsigned char CCIR493_PHASE_RX6 = 110; 44 | const unsigned char CCIR493_PHASE_RX7 = 111; 45 | const unsigned char CCIR493_PHASE_DX = 125; 46 | const unsigned char CCIR493_ACK_RQ = 117; 47 | const unsigned char CCIR493_ACK_BQ = 122; 48 | const unsigned char CCIR493_EMPTY = 126; 49 | const unsigned char CCIR493_EOS = 127; 50 | 51 | // Maximum message length is 40 symbols x 2 copies 52 | const unsigned int CCIR493_MAX_MSG_LEN = 2 * 40; 53 | 54 | class Ccir493Decoder: public Module { 55 | public: 56 | explicit Ccir493Decoder(unsigned int errorsAllowed = 4, bool invert = false) 57 | : errorsAllowed(errorsAllowed), invert(invert) {} 58 | 59 | bool canProcess() override; 60 | void process() override; 61 | 62 | private: 63 | unsigned int errorsAllowed; 64 | bool invert; 65 | 66 | unsigned short c1 = 0, c2 = 0, c3 = 0; 67 | unsigned int length = CCIR493_MAX_MSG_LEN; 68 | unsigned int errors = 0; 69 | bool rxPhase = false; 70 | 71 | bool toBit(float sample); 72 | bool isValid(unsigned short code); 73 | unsigned short fec(unsigned short code); 74 | char toCode(unsigned short code); 75 | unsigned short fromCode(char code); 76 | unsigned short tryRecovery(unsigned short x, unsigned short y); 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /include/complex.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021-2022 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | namespace Csdr { 25 | 26 | template 27 | class complex: public std::complex { 28 | public: 29 | complex(const T& i = T(), const T& q = T()): std::complex(i, q) {} 30 | complex(const std::complex& c): complex(c.real(), c.imag()) {} 31 | // in-phase 32 | T i() const { return std::complex::real(); } 33 | void i(T value) { std::complex::real(value); } 34 | // quadrature 35 | T q() const { return std::complex::imag(); } 36 | void q(T value) { std::complex::imag(value); } 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /include/converter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | template 27 | class Converter: public AnyLengthModule { 28 | public: 29 | void process(T* input, U* output, size_t length) override; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /include/dbpsk.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | namespace Csdr { 38 | 39 | class DBPskDecoder: public AnyLengthModule, unsigned char> { 40 | protected: 41 | void process(complex* input, unsigned char* output, size_t size) override; 42 | private: 43 | float last_phase = 0.0f; 44 | }; 45 | 46 | } -------------------------------------------------------------------------------- /include/dcblock.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class DcBlock : public Csdr::AnyLengthModule { 27 | public: 28 | void process(float *input, float *output, size_t length) override; 29 | 30 | private: 31 | float xm1 = 0.0f; 32 | float ym1 = 0.0f; 33 | }; 34 | 35 | } -------------------------------------------------------------------------------- /include/deemphasis.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "fir.hpp" 36 | #include "filter.hpp" 37 | 38 | namespace Csdr { 39 | 40 | class WfmDeemphasis: public AnyLengthModule { 41 | public: 42 | WfmDeemphasis(unsigned int sampleRate, float tau); 43 | protected: 44 | void process(float* input, float* output, size_t size) override; 45 | private: 46 | float dt; 47 | float alpha; 48 | float last_output = 0.0f; 49 | }; 50 | 51 | class NfmDeephasis: public FilterModule { 52 | public: 53 | explicit NfmDeephasis(unsigned int sampleRate); 54 | private: 55 | static FirFilter* getFilter(unsigned int sampleRate); 56 | }; 57 | 58 | } -------------------------------------------------------------------------------- /include/downmix.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | template 27 | class Downmix: public Module { 28 | public: 29 | explicit Downmix(unsigned int channels = 2); 30 | bool canProcess() override; 31 | void process() override; 32 | private: 33 | unsigned int channels; 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /include/exec.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | #include 25 | 26 | namespace Csdr { 27 | 28 | class UntypedExecModule { 29 | public: 30 | virtual void reload() = 0; 31 | virtual void restart() = 0; 32 | virtual void setArgs(const std::vector& args) = 0; 33 | }; 34 | 35 | template 36 | class ExecModule: public UntypedExecModule, public Module { 37 | public: 38 | explicit ExecModule(std::vector args, size_t flushSize = 0, bool doNotKill = false); 39 | ~ExecModule(); 40 | bool canProcess() override; 41 | void process() override; 42 | void setWriter(Writer* writer) override; 43 | void reload() override; 44 | void restart() override; 45 | void setArgs(const std::vector& args) override; 46 | private: 47 | void startChild(); 48 | void stopChild(); 49 | void readLoop(); 50 | void closePipes(); 51 | bool isPipeWriteable(); 52 | std::vector args; 53 | size_t flushSize = 0; 54 | bool doNotKill = false; 55 | std::mutex childMutex; 56 | pid_t child_pid = 0; 57 | int readPipe = -1; 58 | int writePipe = -1; 59 | std::thread* readThread = nullptr; 60 | bool run = true; 61 | int readOffset = 0; 62 | int writeOffset = 0; 63 | }; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /include/fft.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | #include "window.hpp" 25 | 26 | #include 27 | 28 | namespace Csdr { 29 | 30 | class Fft: public Module, complex> { 31 | public: 32 | Fft(unsigned int fftSize, unsigned int everyNSamples, Window* window = nullptr); 33 | ~Fft() override; 34 | bool canProcess() override; 35 | void process() override; 36 | void setEveryNSamples(unsigned int everyNSamples); 37 | private: 38 | unsigned int fftSize; 39 | unsigned int everyNSamples; 40 | unsigned int skipped = 0; 41 | PrecalculatedWindow* window; 42 | fftwf_plan plan; 43 | complex* windowed; 44 | complex* output_buffer; 45 | }; 46 | 47 | } -------------------------------------------------------------------------------- /include/fftexchangesides.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | 36 | namespace Csdr { 37 | 38 | class FftExchangeSides: public FixedLengthModule { 39 | public: 40 | FftExchangeSides(unsigned int fftSize); 41 | void process(float* input, float* output) override; 42 | size_t getLength() override; 43 | private: 44 | unsigned int fftSize; 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /include/fftfilter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "filter.hpp" 35 | #include "complex.hpp" 36 | #include "window.hpp" 37 | 38 | #include 39 | 40 | namespace Csdr { 41 | 42 | template 43 | class FftFilter: public Filter { 44 | public: 45 | FftFilter(size_t fftSize, complex* taps, size_t taps_length); 46 | ~FftFilter() override; 47 | size_t apply(T* input, T* output, size_t size) override; 48 | size_t getMinProcessingSize() override { return inputSize; } 49 | protected: 50 | explicit FftFilter(size_t fftSize); 51 | static size_t filterLength(float transition); 52 | static size_t getFftSize(size_t taps_length); 53 | complex* taps; 54 | size_t taps_length; 55 | size_t fftSize; 56 | size_t inputSize; 57 | private: 58 | fftwf_complex* forwardInput; 59 | fftwf_complex* forwardOutput; 60 | fftwf_plan forwardPlan; 61 | fftwf_complex* inverseInput; 62 | fftwf_complex* inverseOutput; 63 | fftwf_plan inversePlan; 64 | T* overlap; 65 | }; 66 | 67 | class FftBandPassFilter: public FftFilter> { 68 | public: 69 | FftBandPassFilter(float lowcut, float highcut, float transition, Window* window); 70 | }; 71 | 72 | } -------------------------------------------------------------------------------- /include/filter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | #include 25 | 26 | namespace Csdr { 27 | 28 | template 29 | class Filter { 30 | public: 31 | virtual ~Filter() = default; 32 | virtual size_t apply(T* input, T* output, size_t size) = 0; 33 | virtual size_t getMinProcessingSize() { return 0; } 34 | virtual size_t getOverhead() { return 0; }; 35 | }; 36 | 37 | template 38 | class SparseView; 39 | 40 | template 41 | class SampleFilter: public Filter { 42 | public: 43 | SparseView sparse(T* data); 44 | virtual T processSample(T* data, size_t index) = 0; 45 | size_t apply(T* input, T* output, size_t size) override; 46 | }; 47 | 48 | template 49 | class SparseView { 50 | public: 51 | SparseView(T* data, SampleFilter* filter); 52 | T operator[](size_t index); 53 | private: 54 | T* data; 55 | SampleFilter* filter; 56 | }; 57 | 58 | template 59 | class FilterModule: public Module { 60 | public: 61 | explicit FilterModule(Filter* filter); 62 | ~FilterModule() override; 63 | bool canProcess() override; 64 | void process() override; 65 | void setFilter(Filter* filter); 66 | private: 67 | Filter* filter; 68 | }; 69 | } -------------------------------------------------------------------------------- /include/fir.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "window.hpp" 35 | #include "complex.hpp" 36 | #include "module.hpp" 37 | #include "filter.hpp" 38 | #include "fftfilter.hpp" 39 | 40 | namespace Csdr { 41 | 42 | template 43 | class FirFilter: public SampleFilter { 44 | public: 45 | FirFilter(U* taps, size_t length); 46 | ~FirFilter(); 47 | T processSample(T* data, size_t index) override; 48 | T processSample_fmv(T* data, size_t index); 49 | size_t getOverhead() override; 50 | protected: 51 | explicit FirFilter(size_t length); 52 | static size_t filterLength(float transition); 53 | void allocateTaps(size_t length); 54 | U* taps; 55 | size_t taps_length; 56 | }; 57 | 58 | template 59 | class TapGenerator { 60 | public: 61 | explicit TapGenerator(Window* window); 62 | virtual T* generateTaps(size_t length) = 0; 63 | complex* generateFftTaps(size_t length, size_t fftSize); 64 | protected: 65 | void normalize(T* taps, size_t length); 66 | Window* window; 67 | }; 68 | 69 | class LowPassTapGenerator: public TapGenerator { 70 | public: 71 | LowPassTapGenerator(float cutoff, Window* window); 72 | float* generateTaps(size_t length) override; 73 | private: 74 | float cutoff; 75 | }; 76 | 77 | template 78 | class LowPassFilter: public FirFilter { 79 | public: 80 | LowPassFilter(float cutoff, float transition, Window* window); 81 | }; 82 | 83 | class BandPassTapGenerator: public TapGenerator> { 84 | public: 85 | BandPassTapGenerator(float lowcut, float highcut, Window* window); 86 | complex* generateTaps(size_t length) override; 87 | private: 88 | float lowcut; 89 | float highcut; 90 | }; 91 | 92 | template 93 | class BandPassFilter: public FirFilter> { 94 | public: 95 | BandPassFilter(float lowcut, float highcut, float transition, Window* window); 96 | }; 97 | } -------------------------------------------------------------------------------- /include/firdecimate.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | #include "window.hpp" 25 | #include "fir.hpp" 26 | 27 | namespace Csdr { 28 | 29 | class FirDecimate: public Module, complex> { 30 | public: 31 | FirDecimate(unsigned int decimation, float transitionBandwidth, Window* window, float cutoff); 32 | FirDecimate(unsigned int decimation, float transitionBandwidth, Window* window); 33 | ~FirDecimate() override; 34 | bool canProcess() override; 35 | void process() override; 36 | private: 37 | unsigned int decimation; 38 | LowPassFilter>* lowpass; 39 | }; 40 | 41 | } -------------------------------------------------------------------------------- /include/fmdemod.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | #define fmdemod_quadri_K 0.340447550238101026565118445432744920253753662109375 38 | 39 | namespace Csdr { 40 | 41 | class FmDemod: public AnyLengthModule, float> { 42 | public: 43 | void process(complex* input, float* output, size_t work_size) override; 44 | protected: 45 | size_t maxLength() override { return buffer_size; } 46 | private: 47 | float last_phase = 0; 48 | size_t buffer_size = 1024; 49 | }; 50 | 51 | } -------------------------------------------------------------------------------- /include/fractionaldecimator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | #include "fir.hpp" 37 | 38 | namespace Csdr { 39 | 40 | template 41 | class FractionalDecimator: public Module { 42 | public: 43 | FractionalDecimator(float rate, unsigned int num_poly_points, FirFilter* filter = nullptr); 44 | ~FractionalDecimator(); 45 | bool canProcess() override; 46 | void process() override; 47 | private: 48 | float where; 49 | unsigned int num_poly_points; //number of samples that the Lagrange interpolator will use 50 | float* poly_precalc_denomiator; //while we don't precalculate coefficients here as in a Farrow structure, because it is a fractional interpolator, but we rather precaculate part of the interpolator expression 51 | float* coeffs_buf; 52 | int xifirst; 53 | int xilast; 54 | float rate; 55 | FirFilter* filter; 56 | }; 57 | 58 | } -------------------------------------------------------------------------------- /include/gain.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | 25 | namespace Csdr { 26 | 27 | template 28 | class Gain: public AnyLengthModule { 29 | public: 30 | explicit Gain(float gain); 31 | void process(T* input, T* output, size_t size) override; 32 | private: 33 | float gain; 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /include/limit.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class Limit: public AnyLengthModule { 27 | public: 28 | explicit Limit(float maxAmplitude); 29 | void process(float* input, float* output, size_t size) override; 30 | private: 31 | float maxAmplitude; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /include/logaveragepower.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | namespace Csdr { 38 | 39 | class LogAveragePower: public Module, float> { 40 | public: 41 | LogAveragePower(unsigned int fftSize, unsigned int avgNumber, float add_db); 42 | LogAveragePower(unsigned int fftSize, unsigned int avgNumber); 43 | ~LogAveragePower() override; 44 | bool canProcess() override; 45 | void process() override; 46 | void setAvgNumber(unsigned int avgNumber); 47 | private: 48 | float* collector; 49 | unsigned int collected = 0; 50 | unsigned int fftSize; 51 | unsigned int avgNumber; 52 | float add_db; 53 | }; 54 | 55 | } -------------------------------------------------------------------------------- /include/logpower.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | namespace Csdr { 38 | 39 | class LogPower: public AnyLengthModule, float> { 40 | public: 41 | LogPower(); 42 | LogPower(float add_db); 43 | void process(complex* input, float* output, size_t size) override; 44 | private: 45 | float add_db = 0.0; 46 | }; 47 | 48 | } -------------------------------------------------------------------------------- /include/module.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "source.hpp" 23 | #include "sink.hpp" 24 | #include "complex.hpp" 25 | 26 | #include 27 | #include 28 | 29 | namespace Csdr { 30 | 31 | class UntypedModule { 32 | public: 33 | virtual ~UntypedModule() = default; 34 | virtual bool canProcess() = 0; 35 | virtual void process() = 0; 36 | virtual void wait(std::unique_lock& lock) = 0; 37 | virtual void unblock() = 0; 38 | }; 39 | 40 | template 41 | class Module: public UntypedModule, public Sink, public Source { 42 | public: 43 | ~Module() override; 44 | void wait(std::unique_lock& lock) override; 45 | void unblock() override; 46 | void setWriter(Writer* writer) override; 47 | void setReader(Reader* reader) override; 48 | protected: 49 | std::mutex processMutex; 50 | private: 51 | Reader* waitingReader = nullptr; 52 | }; 53 | 54 | template 55 | class AnyLengthModule: public Module { 56 | public: 57 | bool canProcess() override; 58 | void process() override; 59 | protected: 60 | virtual void process(T* input, U* output, size_t len) = 0; 61 | virtual size_t maxLength() { return SIZE_MAX; } 62 | size_t getWorkSize(); 63 | }; 64 | 65 | template 66 | class FixedLengthModule: public Module { 67 | public: 68 | bool canProcess() override; 69 | void process() override; 70 | protected: 71 | virtual void process(T* input, U* output) = 0; 72 | virtual size_t getLength() = 0; 73 | }; 74 | } -------------------------------------------------------------------------------- /include/navtex.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | // 11 minutes * 100 baud / 10 bit / 2 characters 26 | const size_t NAVTEX_MAX_CHARS = 11 * 60 * 100 / 10 / 2; 27 | 28 | class NavtexDecoder: public Module { 29 | public: 30 | bool canProcess() override; 31 | void process() override; 32 | 33 | private: 34 | bool receiving = false; 35 | size_t received; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /include/noise.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "source.hpp" 35 | 36 | namespace Csdr { 37 | 38 | template 39 | class NoiseSource: public Source { 40 | public: 41 | NoiseSource(); 42 | ~NoiseSource(); 43 | void setWriter(Writer* writer) override; 44 | private: 45 | void generateSamples(T* output, size_t length); 46 | void loop(); 47 | FILE* random; 48 | std::thread* thread = nullptr; 49 | }; 50 | 51 | } -------------------------------------------------------------------------------- /include/noisefilter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "filter.hpp" 23 | #include "complex.hpp" 24 | 25 | #include 26 | 27 | namespace Csdr { 28 | 29 | template 30 | class NoiseFilter: public Filter { 31 | public: 32 | NoiseFilter(size_t fftSize = 1024, size_t wndSize = 16, unsigned int decay = 10, unsigned int attack = 2); 33 | ~NoiseFilter() override; 34 | 35 | size_t apply(T* input, T* output, size_t size) override; 36 | size_t getMinProcessingSize() override { return fftSize-ovrSize; } 37 | 38 | void setThreshold(int dBthreshold); 39 | 40 | protected: 41 | size_t fftSize; // Size of the FFT 42 | size_t wndSize; // Actually, half-a-window 43 | size_t ovrSize; // Usually 1/64th of fftSize 44 | double threshold; // Filtering threshold 45 | double avgPower; // Power over multiple FFTs 46 | double attack; // Attack rate measuring avgPower 47 | double decay; // Decay rate measuring avgPower 48 | 49 | private: 50 | fftwf_complex* forwardInput; 51 | fftwf_complex* forwardOutput; 52 | fftwf_plan forwardPlan; 53 | fftwf_complex* inverseInput; 54 | fftwf_complex* inverseOutput; 55 | fftwf_plan inversePlan; 56 | fftwf_complex* overlapBuf; 57 | 58 | // Convert output complex into a sample 59 | inline T complex2sample(complex input); 60 | }; 61 | 62 | class AFNoiseFilter: public NoiseFilter { 63 | public: 64 | AFNoiseFilter(size_t fftSize = 1024, size_t wndSize = 16, unsigned int decay = 10, unsigned int attack = 2): 65 | NoiseFilter(fftSize, wndSize, decay, attack) {} 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /include/phasedemod.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | 25 | namespace Csdr { 26 | 27 | class PhaseDemod: public AnyLengthModule, float> { 28 | public: 29 | void process(complex* input, float* output, size_t work_size) override; 30 | protected: 31 | size_t maxLength() override { return buffer_size; } 32 | private: 33 | size_t buffer_size = 1024; 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /include/power.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include "module.hpp" 24 | #include "complex.hpp" 25 | 26 | namespace Csdr { 27 | 28 | template 29 | class Power: public Module { 30 | public: 31 | Power(size_t length, unsigned int decimation = 1, std::function callback = 0); 32 | size_t getLength(); 33 | bool canProcess() override; 34 | void process() override; 35 | protected: 36 | // to bo overridden by the squelch implementation 37 | virtual void forwardData(T* input, float power); 38 | private: 39 | size_t length; 40 | unsigned int decimation; 41 | std::function callback; 42 | }; 43 | 44 | template 45 | class Squelch: public Power { 46 | public: 47 | Squelch(size_t length, unsigned int decimation = 1, size_t hangLength = 0, size_t flushLength = 0, std::function callback = 0); 48 | void setSquelch(float squelchLevel); 49 | protected: 50 | void forwardData(T* input, float power) override; 51 | private: 52 | size_t hangLength; 53 | size_t flushLength; 54 | float squelchLevel = 0.0f; 55 | size_t hangCounter = 0; 56 | size_t flushCounter = 0; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /include/reader.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "complex.hpp" 23 | 24 | #include 25 | 26 | namespace Csdr { 27 | 28 | // container class for template-agnostic storage 29 | class UntypedReader { 30 | public: 31 | virtual ~UntypedReader() = default; 32 | virtual size_t available() = 0; 33 | virtual void advance(size_t how_much) = 0; 34 | virtual void wait() = 0; 35 | virtual void unblock() = 0; 36 | }; 37 | 38 | template 39 | class Reader: public UntypedReader { 40 | public: 41 | virtual T* getReadPointer() = 0; 42 | }; 43 | 44 | template 45 | class MemoryReader: public Reader { 46 | public: 47 | MemoryReader(T* data, size_t size); 48 | size_t available() override; 49 | T* getReadPointer() override; 50 | void advance(size_t how_much) override; 51 | void wait() override; 52 | void unblock() override {} 53 | void rewind(); 54 | private: 55 | T* data; 56 | size_t size; 57 | size_t read_pos = 0; 58 | }; 59 | 60 | } -------------------------------------------------------------------------------- /include/realpart.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | #include "complex.hpp" 24 | 25 | namespace Csdr { 26 | 27 | class Realpart: public AnyLengthModule, float> { 28 | public: 29 | void process(complex* input, float* output, size_t size) override; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /include/ringbuffer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "reader.hpp" 23 | #include "writer.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace Csdr { 33 | 34 | class BufferError: public std::runtime_error { 35 | public: 36 | explicit BufferError(const std::string& err): std::runtime_error(err) {} 37 | }; 38 | 39 | template 40 | class RingbufferReader; 41 | 42 | template 43 | class Ringbuffer: public Writer { 44 | public: 45 | explicit Ringbuffer(size_t size); 46 | ~Ringbuffer() override; 47 | size_t writeable() override; 48 | T* getWritePointer() override; 49 | T* getPointer(size_t pos); 50 | void advance(size_t how_much) override; 51 | void advance(size_t& what, size_t how_much); 52 | size_t available(size_t read_pos); 53 | size_t getWritePos(); 54 | void wait(); 55 | void unblock(); 56 | void addReader(RingbufferReader* reader); 57 | void removeReader(RingbufferReader* reader); 58 | private: 59 | T* allocate_mirrored(size_t size); 60 | T* data = nullptr; 61 | size_t size; 62 | size_t write_pos = 0; 63 | std::mutex mutex; 64 | std::condition_variable condition; 65 | std::set*> readers = {}; 66 | }; 67 | 68 | template 69 | class RingbufferReader: public Reader { 70 | public: 71 | explicit RingbufferReader(Ringbuffer* buffer); 72 | ~RingbufferReader(); 73 | size_t available() override; 74 | T* getReadPointer() override; 75 | void advance(size_t how_much) override; 76 | void wait() override; 77 | void unblock() override; 78 | void onBufferDelete(); 79 | private: 80 | Ringbuffer* buffer; 81 | size_t read_pos; 82 | }; 83 | 84 | } -------------------------------------------------------------------------------- /include/rtty.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class RttyDecoder: public Module { 27 | public: 28 | explicit RttyDecoder(bool invert); 29 | explicit RttyDecoder(); 30 | bool canProcess() override; 31 | void process() override; 32 | private: 33 | bool toBit(float sample); 34 | bool invert = true; 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /include/shift.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | namespace Csdr { 38 | 39 | class Shift { 40 | public: 41 | explicit Shift(float rate); 42 | virtual void setRate(float rate); 43 | protected: 44 | float rate; 45 | }; 46 | 47 | class ShiftAddfast: public Shift, public FixedLengthModule, complex> { 48 | public: 49 | explicit ShiftAddfast(float rate); 50 | void setRate(float rate) override; 51 | protected: 52 | void process(complex* input, complex* output) override; 53 | void process_fmv(complex* input, complex* output, size_t size); 54 | size_t getLength() override { return 1024; } 55 | private: 56 | float starting_phase = 0.0; 57 | float dsin[4]; 58 | float dcos[4]; 59 | float phase_increment; 60 | }; 61 | 62 | class ShiftMath: public Shift, public AnyLengthModule, complex> { 63 | public: 64 | explicit ShiftMath(float rate); 65 | void setRate(float rate) override; 66 | protected: 67 | void process(complex* input, complex* output, size_t size) override; 68 | void process_fmv(complex* input, complex* output, size_t size); 69 | private: 70 | float phase = 0.0; 71 | float phase_increment; 72 | }; 73 | 74 | } -------------------------------------------------------------------------------- /include/sink.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "reader.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class UntypedSink { 27 | public: 28 | virtual ~UntypedSink() = default; 29 | virtual bool hasReader() = 0; 30 | }; 31 | 32 | template 33 | class Sink: public UntypedSink { 34 | public: 35 | virtual void setReader(Reader* reader); 36 | virtual Reader* getReader(); 37 | bool hasReader() override; 38 | protected: 39 | Reader* reader = nullptr; 40 | }; 41 | 42 | 43 | } -------------------------------------------------------------------------------- /include/sitorb.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class SitorBDecoder: public Module { 27 | public: 28 | explicit SitorBDecoder(unsigned int errorsAllowed = 4, bool invert = false) 29 | : errorsAllowed(errorsAllowed), invert(invert) {} 30 | 31 | bool canProcess() override; 32 | void process() override; 33 | 34 | private: 35 | unsigned int errorsAllowed; 36 | bool invert; 37 | 38 | unsigned char c1 = '\0', c2 = '\0', c3 = '\0'; 39 | unsigned int errors = 0; 40 | bool rxPhase = false; 41 | 42 | bool toBit(float sample); 43 | unsigned char fec(unsigned char code); 44 | bool isValid(unsigned char code); 45 | unsigned char tryRecovery(unsigned char x, unsigned char y); 46 | }; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /include/snr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2022-2025 Marat Fayzullin 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the copyright holder nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #pragma once 32 | 33 | #include 34 | #include "module.hpp" 35 | #include 36 | 37 | namespace Csdr { 38 | 39 | template 40 | class Snr: public Module { 41 | public: 42 | Snr(size_t length, size_t fftSize = 256, std::function callback = 0); 43 | ~Snr() override; 44 | 45 | size_t getLength(); 46 | bool canProcess() override; 47 | void process() override; 48 | 49 | protected: 50 | // to be overridden by the squelch implementation 51 | virtual void forwardData(T* input, float snr); 52 | 53 | private: 54 | size_t length; 55 | size_t fftSize; 56 | std::function callback; 57 | 58 | fftwf_complex* fftInput; 59 | fftwf_complex* fftOutput; 60 | fftwf_plan fftPlan; 61 | }; 62 | 63 | template 64 | class SnrSquelch: public Snr { 65 | public: 66 | SnrSquelch(size_t length, size_t fftSize = 256, size_t hangLength = 0, size_t flushLength = 0, std::function callback = 0); 67 | void setSquelch(float squelchLevel); 68 | 69 | protected: 70 | void forwardData(T* input, float snr) override; 71 | 72 | private: 73 | std::function callback; 74 | size_t length; 75 | size_t hangLength; 76 | size_t flushLength; 77 | 78 | float squelchLevel = 0.0f; 79 | size_t hangCounter = 0; 80 | size_t flushCounter = 0; 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /include/source.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "writer.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Csdr { 29 | 30 | class UntypedSource { 31 | public: 32 | virtual ~UntypedSource() = default; 33 | virtual bool hasWriter() = 0; 34 | }; 35 | 36 | template 37 | class Source: public UntypedSource { 38 | public: 39 | virtual void setWriter(Writer* writer); 40 | virtual Writer* getWriter(); 41 | bool hasWriter() override; 42 | protected: 43 | Writer* writer = nullptr; 44 | }; 45 | 46 | class NetworkException: public std::runtime_error { 47 | public: 48 | NetworkException(const std::string& reason): std::runtime_error(reason) {} 49 | }; 50 | 51 | template 52 | class TcpSource: public Source { 53 | public: 54 | // TcpSource(std::string remote); 55 | TcpSource(in_addr_t ip, unsigned short port); 56 | ~TcpSource(); 57 | void setWriter(Writer* writer) override; 58 | void stop(); 59 | private: 60 | void loop(); 61 | int sock; 62 | bool run = true; 63 | std::thread* thread = nullptr; 64 | }; 65 | 66 | } -------------------------------------------------------------------------------- /include/throttle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2024 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | #include 25 | #include 26 | 27 | namespace Csdr { 28 | template 29 | class Throttle: public Module { 30 | public: 31 | Throttle(size_t rate, size_t chunkSize = 8096); 32 | ~Throttle() override; 33 | // processing is asynchronous, so this will always be false 34 | bool canProcess() override { return false; }; 35 | // this doesn't do anything either. the worker thread does the work. 36 | void process() override {}; 37 | void setReader(Reader* reader) override; 38 | void setWriter(Writer* writer) override; 39 | private: 40 | size_t rate; 41 | size_t chunkSize; 42 | std::chrono::duration nominalDuration; 43 | std::chrono::time_point> nextScheduledExecution; 44 | 45 | bool run = true; 46 | std::thread* worker = nullptr; 47 | void loop(); 48 | }; 49 | } -------------------------------------------------------------------------------- /include/timingrecovery.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "module.hpp" 35 | #include "complex.hpp" 36 | 37 | namespace Csdr { 38 | 39 | template 40 | class TimingRecovery: public Module { 41 | public: 42 | explicit TimingRecovery(unsigned int decimation, float loop_gain = 0.5f, float max_error = 2.0f); 43 | void process() override; 44 | bool canProcess() override; 45 | protected: 46 | virtual float getError() = 0; 47 | virtual int getErrorSign() = 0; 48 | float calculateError(int el_point_right_index, int el_point_left_index, int el_point_mid_index); 49 | unsigned int decimation; 50 | int correction_offset = 0; 51 | private: 52 | float loop_gain; 53 | float max_error; 54 | }; 55 | 56 | template 57 | class GardnerTimingRecovery: public TimingRecovery { 58 | public: 59 | using TimingRecovery::TimingRecovery; 60 | protected: 61 | float getError() override; 62 | int getErrorSign() override { return -1; } 63 | }; 64 | 65 | template 66 | class EarlyLateTimingRecovery: public TimingRecovery { 67 | public: 68 | using TimingRecovery::TimingRecovery; 69 | protected: 70 | float getError() override; 71 | int getErrorSign() override { return 1; } 72 | private: 73 | float earlylate_ratio = 0.25f; 74 | }; 75 | 76 | } -------------------------------------------------------------------------------- /include/version.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | namespace Csdr { 25 | 26 | extern const std::string version; 27 | 28 | } -------------------------------------------------------------------------------- /include/window.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #pragma once 33 | 34 | #include 35 | 36 | namespace Csdr { 37 | 38 | class PrecalculatedWindow { 39 | public: 40 | PrecalculatedWindow(float* windowt, size_t size); 41 | ~PrecalculatedWindow(); 42 | template 43 | void apply(T* input, T* output, size_t size); 44 | private: 45 | float* windowt; 46 | size_t size; 47 | }; 48 | 49 | class Window { 50 | public: 51 | virtual ~Window() = default; 52 | template 53 | void apply(T* input, T* output, size_t size); 54 | PrecalculatedWindow* precalculate(size_t size); 55 | virtual float kernel(float rate) = 0; 56 | }; 57 | 58 | class BoxcarWindow: public Window { 59 | public: 60 | float kernel(float rate) override; 61 | }; 62 | 63 | class BlackmanWindow: public Window { 64 | public: 65 | float kernel(float rate) override; 66 | }; 67 | 68 | class HammingWindow: public Window { 69 | public: 70 | float kernel(float rate) override; 71 | }; 72 | 73 | } -------------------------------------------------------------------------------- /include/writer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "complex.hpp" 23 | 24 | #include 25 | #include 26 | 27 | namespace Csdr { 28 | 29 | // container class for template-agnostic storage 30 | class UntypedWriter { 31 | public: 32 | virtual ~UntypedWriter() = default; 33 | virtual size_t writeable() = 0; 34 | virtual void advance(size_t how_much) = 0; 35 | }; 36 | 37 | template 38 | class Writer: public UntypedWriter { 39 | public: 40 | virtual T* getWritePointer() = 0; 41 | }; 42 | 43 | template 44 | class StdoutWriter: public Writer { 45 | public: 46 | StdoutWriter(); 47 | StdoutWriter(size_t buffer_size); 48 | ~StdoutWriter(); 49 | size_t writeable() override; 50 | T* getWritePointer() override; 51 | void advance(size_t how_much) override; 52 | private: 53 | size_t buffer_size; 54 | T* buffer; 55 | }; 56 | 57 | template 58 | class VoidWriter: public Writer { 59 | public: 60 | explicit VoidWriter(size_t buffer_size); 61 | VoidWriter(); 62 | ~VoidWriter(); 63 | size_t writeable() override; 64 | T* getWritePointer() override; 65 | void advance(__attribute__((unused)) size_t how_much) override {} 66 | private: 67 | size_t buffer_size; 68 | T* data; 69 | }; 70 | 71 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2023 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | configure_file(csdr.pc.in csdr.pc @ONLY) 19 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/csdr.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) 20 | 21 | install(EXPORT CsdrTargets 22 | FILE CsdrTargets.cmake 23 | NAMESPACE Csdr:: 24 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Csdr 25 | ) 26 | 27 | include(CMakePackageConfigHelpers) 28 | 29 | configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in 30 | "${CMAKE_CURRENT_BINARY_DIR}/CsdrConfig.cmake" 31 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Csdr 32 | ) 33 | 34 | write_basic_package_version_file( 35 | "${CMAKE_CURRENT_BINARY_DIR}/CsdrConfigVersion.cmake" 36 | VERSION ${PROJECT_VERSION} 37 | COMPATIBILITY AnyNewerVersion 38 | ) 39 | 40 | install(FILES 41 | "${CMAKE_CURRENT_BINARY_DIR}/CsdrConfig.cmake" 42 | "${CMAKE_CURRENT_BINARY_DIR}/CsdrConfigVersion.cmake" 43 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Csdr 44 | ) 45 | 46 | add_subdirectory(lib) 47 | add_subdirectory(apps) -------------------------------------------------------------------------------- /src/Config.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | @PACKAGE_INIT@ 19 | 20 | include("${CMAKE_CURRENT_LIST_DIR}/CsdrTargets.cmake") 21 | 22 | check_required_components(Csdr) -------------------------------------------------------------------------------- /src/apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | add_subdirectory(csdr) 19 | add_subdirectory(nmux) -------------------------------------------------------------------------------- /src/apps/csdr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Jakob Ketterl 2 | # 3 | # This file is part of csdr. 4 | # 5 | # csdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # csdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with csdr. If not, see . 17 | 18 | add_executable(csdr-bin csdr.cpp commands.cpp) 19 | set_target_properties(csdr-bin PROPERTIES OUTPUT_NAME csdr) 20 | target_link_libraries(csdr-bin csdr++) 21 | install(TARGETS csdr-bin DESTINATION ${CMAKE_INSTALL_BINDIR}) 22 | -------------------------------------------------------------------------------- /src/apps/csdr/csdr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021-2023 Jakob Ketterl 3 | 4 | This file is part of csdr. 5 | 6 | csdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | csdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with csdr. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "module.hpp" 23 | 24 | namespace Csdr { 25 | 26 | class Cli { 27 | public: 28 | int main(int argc, char** argv); 29 | private: 30 | template 31 | void runModule(Module* module); 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/apps/nmux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2023 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | add_executable(nmux nmux.cpp tsmpool.cpp) 19 | target_link_libraries(nmux ${CMAKE_THREAD_LIBS_INIT}) 20 | install(TARGETS nmux DESTINATION ${CMAKE_INSTALL_BINDIR}) -------------------------------------------------------------------------------- /src/apps/nmux/nmux.h: -------------------------------------------------------------------------------- 1 | #ifdef __APPLE__ 2 | #include "shims.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "tsmpool.h" 20 | 21 | #define MSG_START "nmux: " 22 | #define NMUX_DEBUG 0 23 | 24 | typedef enum client_status_e 25 | { 26 | CS_CREATED, 27 | CS_THREAD_RUNNING, 28 | CS_THREAD_FINISHED 29 | } client_status_t; 30 | 31 | 32 | typedef struct client_s 33 | { 34 | struct sockaddr_in addr; 35 | int socket; 36 | int error; //set to non-zero on error (data transfer failed) 37 | pthread_t thread; 38 | tsmthread_t* tsmthread; 39 | client_status_t status; 40 | //the following members are there to give access to some global variables inside the thread: 41 | tsmpool* lpool; 42 | int sleeping; 43 | } client_t; 44 | 45 | void print_exit(const char* why); 46 | void sig_handler(int signo); 47 | void* client_thread (void* param); 48 | void error_exit(const char* why); 49 | void maxfd(int* maxfd, int fd); 50 | int set_nonblocking(int fd); 51 | -------------------------------------------------------------------------------- /src/apps/nmux/shims.h: -------------------------------------------------------------------------------- 1 | #ifndef SHIMS_H 2 | #define SHIMS_H 3 | 4 | #define _DARWIN_C_SOURCE 5 | #define MSG_NOSIGNAL 0x2000 /* don't raise SIGPIPE */ 6 | #define F_SETPIPE_SZ 0x407 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/apps/nmux/tsmpool.cpp: -------------------------------------------------------------------------------- 1 | #include "tsmpool.h" 2 | 3 | tsmpool::tsmpool(size_t size, int num) : 4 | size(size), 5 | num(num) //number of buffers of (size) to alloc 6 | { 7 | this->threads_cntr = 0; 8 | this->ok = 1; 9 | this->lowest_read_index = -1; 10 | this->write_index = 0; 11 | this->my_read_index = index_before(0); 12 | if (pthread_mutex_init(&this->mutex, NULL) != 0) { this->ok = 0; return; } 13 | for(int i=0; iok = 0; return; } 17 | buffers.push_back(newptr); 18 | } 19 | } 20 | 21 | int tsmpool::is_ok() { return this->ok; } 22 | 23 | void* tsmpool::get_write_buffer() 24 | { 25 | //if(write_index==index_before(lowest_read_index)) return NULL; 26 | pthread_mutex_lock(&this->mutex); 27 | void* to_return = buffers[write_index]; 28 | write_index = index_next(write_index); 29 | pthread_mutex_unlock(&this->mutex); 30 | if(TSM_DEBUG) fprintf(stderr, "gwb: write_index = %d\n", write_index); 31 | return to_return; 32 | } 33 | 34 | tsmthread_t* tsmpool::register_thread() 35 | { 36 | if(!ok) return NULL; 37 | pthread_mutex_lock(&this->mutex); 38 | tsmthread_t* thread = new tsmthread_t(); 39 | thread->read_index = index_before(write_index); 40 | threads.push_back(thread); 41 | pthread_mutex_unlock(&this->mutex); 42 | return thread; 43 | } 44 | 45 | void tsmpool::remove_thread(tsmthread_t* thread) 46 | { 47 | pthread_mutex_lock(&this->mutex); 48 | for(int i=0;imutex); 56 | } 57 | 58 | void* tsmpool::get_read_buffer(tsmthread_t* thread) 59 | { 60 | pthread_mutex_lock(&this->mutex); 61 | int* actual_read_index = (thread==NULL) ? &my_read_index : &thread->read_index; 62 | if(*actual_read_index==index_before(write_index)) 63 | { 64 | if(TSM_DEBUG) fprintf(stderr, "grb: fail," 65 | "read_index %d is just before write_index\n", *actual_read_index); 66 | pthread_mutex_unlock(&this->mutex); 67 | return NULL; 68 | } 69 | void* to_return = buffers[*actual_read_index]; 70 | *actual_read_index=index_next(*actual_read_index); 71 | pthread_mutex_unlock(&this->mutex); 72 | if(TSM_DEBUG) fprintf(stderr, "grb: read_index = %d\n", *actual_read_index); 73 | return to_return; 74 | } 75 | -------------------------------------------------------------------------------- /src/apps/nmux/tsmpool.h: -------------------------------------------------------------------------------- 1 | //tsmpool stands for Thread-Safe Memory Pool. 2 | 3 | //It implements a big circular buffer that one thread writes into, and multiple threads read from. 4 | //The reader threads have lower priority than the writer thread (they can be left behind if the don't read fast enough). 5 | 6 | #include 7 | #include 8 | 9 | #define TSM_DEBUG 0 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef struct tsmthread_s 15 | { 16 | int read_index; //it always points to the next buffer to be read 17 | } tsmthread_t; 18 | 19 | class tsmpool 20 | { 21 | private: 22 | vector threads; 23 | vector buffers; 24 | int threads_cntr; 25 | pthread_mutex_t mutex; 26 | int ok; //tsmpool is expected to be included in C-style programs. 27 | // If something fails in the constructor, it will be seen here instead of a try{}catch{} 28 | int write_index; //it always points to the next buffer to be written 29 | int lowest_read_index; //unused 30 | int my_read_index; //it is used when tsmpool is used as a single writer - single reader circular buffer 31 | 32 | public: 33 | const size_t size; 34 | const int num; 35 | int is_ok(); 36 | tsmpool(size_t size, int num); 37 | void* get_write_buffer(); 38 | tsmthread_t* register_thread(); 39 | void remove_thread(tsmthread_t* thread); 40 | void* get_read_buffer(tsmthread_t* thread); 41 | int index_next(int index) { return (index+1==num)?0:index+1; } 42 | int index_before(int index) { return (index-1<0)?num-1:index-1; } 43 | }; 44 | -------------------------------------------------------------------------------- /src/csdr.pc.in: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | prefix=@CMAKE_INSTALL_PREFIX@ 19 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 20 | libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ 21 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 22 | 23 | csdr_utility=csdr 24 | 25 | Name: @PROJECT_NAME@ 26 | Description: @PROJECT_DESCRIPTION@ 27 | URL: https://github.com/luarvique/csdr 28 | Version: @PROJECT_VERSION@ 29 | 30 | Libs: -L${libdir} -lcsdr++ 31 | Cflags: -I${includedir} 32 | @FFTW3F_REQUIRES@ 33 | -------------------------------------------------------------------------------- /src/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2023 Jakob Ketterl 2 | # 3 | # This file is part of libcsdr. 4 | # 5 | # libcsdr is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # libcsdr is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with libcsdr. If not, see . 17 | 18 | add_library(csdr++ SHARED 19 | module.cpp 20 | ringbuffer.cpp 21 | writer.cpp 22 | agc.cpp 23 | fmdemod.cpp 24 | amdemod.cpp 25 | dcblock.cpp 26 | converter.cpp 27 | fft.cpp 28 | window.cpp 29 | logpower.cpp 30 | logaveragepower.cpp 31 | fftexchangesides.cpp 32 | realpart.cpp 33 | shift.cpp 34 | firdecimate.cpp 35 | fir.cpp 36 | benchmark.cpp 37 | reader.cpp 38 | fractionaldecimator.cpp 39 | adpcm.cpp 40 | limit.cpp 41 | power.cpp 42 | deemphasis.cpp 43 | gain.cpp 44 | filter.cpp 45 | fftfilter.cpp 46 | dbpsk.cpp 47 | varicode.cpp 48 | timingrecovery.cpp 49 | async.cpp 50 | source.cpp 51 | sink.cpp 52 | audioresampler.cpp 53 | downmix.cpp 54 | version.cpp 55 | noise.cpp 56 | phasedemod.cpp 57 | rtty.cpp 58 | baudot.cpp 59 | exec.cpp 60 | throttle.cpp 61 | afc.cpp 62 | noisefilter.cpp 63 | mfrtty.cpp 64 | cw.cpp 65 | sstv.cpp 66 | fax.cpp 67 | sitorb.cpp 68 | ccir476.cpp 69 | dsc.cpp 70 | ccir493.cpp 71 | navtex.cpp 72 | snr.cpp 73 | ) 74 | 75 | set_target_properties(csdr++ PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") 76 | file(GLOB LIBCSDR_HEADERS "${PROJECT_SOURCE_DIR}/include/*.hpp") 77 | set_target_properties(csdr++ PROPERTIES PUBLIC_HEADER "${LIBCSDR_HEADERS}") 78 | target_link_libraries(csdr++ ${FFTW3_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${SAMPLERATE_LIBRARIES}) 79 | target_compile_definitions(csdr++ PRIVATE "-D_GNU_SOURCE") 80 | 81 | if (HAS_IFUNC) 82 | target_compile_definitions(csdr++ PUBLIC "-DCSDR_FMV") 83 | endif() 84 | 85 | install(TARGETS csdr++ 86 | EXPORT CsdrTargets 87 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 88 | PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/csdr" 89 | ) 90 | -------------------------------------------------------------------------------- /src/lib/afc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "afc.hpp" 21 | #include "complex.hpp" 22 | #include 23 | #include 24 | 25 | using namespace Csdr; 26 | 27 | #if defined __arm__ || __aarch64__ 28 | #define CSDR_FFTW_FLAGS (FFTW_DESTROY_INPUT | FFTW_ESTIMATE) 29 | #else 30 | #define CSDR_FFTW_FLAGS (FFTW_DESTROY_INPUT | FFTW_MEASURE) 31 | #endif 32 | 33 | Afc::Afc(unsigned int updatePeriod, unsigned int samplePeriod): ShiftAddfast(0.0) 34 | { 35 | // Verify and initialize configuration 36 | this->samplePeriod = samplePeriod = samplePeriod>1? samplePeriod : 1; 37 | this->updatePeriod = updatePeriod = updatePeriod>samplePeriod? updatePeriod : samplePeriod; 38 | updateCount = updatePeriod; 39 | curShift = 0.0; 40 | 41 | // Set up FFT 42 | unsigned int fftSize = samplePeriod * getLength(); 43 | fftIn = fftwf_alloc_complex(fftSize); 44 | fftOut = fftwf_alloc_complex(fftSize); 45 | fftPlan = fftwf_plan_dft_1d(fftSize, fftIn, fftOut, FFTW_FORWARD, CSDR_FFTW_FLAGS); 46 | } 47 | 48 | Afc::~Afc() 49 | { 50 | // Destroy FFT 51 | fftwf_destroy_plan(fftPlan); 52 | fftwf_free(fftIn); 53 | fftwf_free(fftOut); 54 | } 55 | 56 | void Afc::process(complex* input, complex* output) 57 | { 58 | unsigned int size = getLength(); 59 | int j, i; 60 | 61 | // Count updates 62 | updateCount--; 63 | 64 | // If sampling input signal... 65 | if(updateCountmaxMag) { i=j;maxMag=mag; } 88 | } 89 | 90 | // Take negative shifts into account 91 | i = i>=fftSize/2? fftSize-i : -i; 92 | 93 | // Update frequency shift, if the change is large enough 94 | double newShift = (double)i / fftSize; 95 | if(fabs(newShift-curShift)>0.0001) setRate(curShift = newShift); 96 | } 97 | } 98 | 99 | // Shift frequency 100 | process_fmv(input, output, size); 101 | } 102 | -------------------------------------------------------------------------------- /src/lib/amdemod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "amdemod.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | void AmDemod::process(complex* input, float* output, size_t work_size) { 25 | for (size_t i = 0; i < work_size; i++) { 26 | output[i] = std::abs(input[i]); 27 | } 28 | } -------------------------------------------------------------------------------- /src/lib/async.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "async.hpp" 21 | #include "ringbuffer.hpp" 22 | 23 | using namespace Csdr; 24 | 25 | AsyncRunner::AsyncRunner(UntypedModule* module): 26 | module(module), 27 | thread([this] { loop(); }) 28 | {} 29 | 30 | AsyncRunner::~AsyncRunner() { 31 | stop(); 32 | } 33 | 34 | void AsyncRunner::stop() { 35 | { 36 | std::lock_guard lock(stateMutex); 37 | if (run) { 38 | run = false; 39 | module->unblock(); 40 | } 41 | } 42 | try { 43 | thread.join(); 44 | } catch (std::system_error&) { 45 | // NOOP - thread is not joinable 46 | } 47 | } 48 | 49 | bool AsyncRunner::isRunning() const { 50 | return run; 51 | } 52 | 53 | void AsyncRunner::loop() { 54 | // can't use run as a loop condition due to the locking system 55 | while (true) { 56 | 57 | // the lock must be obtained before checking the condition, but it must be released before looping to be able to stop 58 | std::unique_lock lock(stateMutex); 59 | 60 | if (!run) return; 61 | 62 | try { 63 | if (module->canProcess()) { 64 | // don't hold the lock during the actual processing since that may cause deadlocks 65 | // we should be safe during this period as far as state is concerned 66 | lock.unlock(); 67 | module->process(); 68 | } else { 69 | // lock will be released and re-locked during blocking operation by the wait() method 70 | module->wait(lock); 71 | } 72 | } catch (const BufferError&) { 73 | run = false; 74 | break; 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /src/lib/audioresampler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "audioresampler.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | AudioResampler::AudioResampler(double rate): 25 | rate(rate) 26 | { 27 | int error = 0; 28 | srcState = src_new(SRC_SINC_MEDIUM_QUALITY, 1, &error); 29 | } 30 | 31 | AudioResampler::AudioResampler(unsigned int inputRate, unsigned int outputRate): 32 | AudioResampler((double) outputRate / inputRate) 33 | {} 34 | 35 | AudioResampler::~AudioResampler() { 36 | src_delete(srcState); 37 | } 38 | 39 | bool AudioResampler::canProcess() { 40 | std::lock_guard lock(this->processMutex); 41 | return reader->available() > 0 && writer->writeable() > 0; 42 | } 43 | 44 | void AudioResampler::process() { 45 | std::lock_guard lock(processMutex); 46 | SRC_DATA data = { 47 | .data_in = reader->getReadPointer(), 48 | .data_out = writer->getWritePointer(), 49 | .input_frames = (long) reader->available(), 50 | .output_frames = (long) writer->writeable(), 51 | .end_of_input = 0, 52 | .src_ratio = rate 53 | }; 54 | 55 | src_process(srcState, &data); 56 | 57 | reader->advance(data.input_frames_used); 58 | writer->advance(data.output_frames_gen); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/lib/baudot.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "baudot.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | bool BaudotDecoder::canProcess() { 25 | std::lock_guard lock(this->processMutex); 26 | return reader->available() > 0; 27 | } 28 | 29 | void BaudotDecoder::process() { 30 | std::lock_guard lock(this->processMutex); 31 | unsigned char* input = reader->getReadPointer(); 32 | size_t length = reader->available(); 33 | for (size_t i = 0; i < length; i++) { 34 | unsigned char c = input[i]; 35 | switch (c) { 36 | case BAUDOT_FIG_SHIFT: 37 | mode = 1; 38 | break; 39 | case BAUDOT_LTR_SHIFT: 40 | mode = 0; 41 | break; 42 | default: 43 | c = c>31? '\0' : mode? BAUDOT_FIGURES[c] : BAUDOT_LETTERS[c]; 44 | * (writer->getWritePointer()) = c? c : '_'; 45 | writer->advance(1); 46 | break; 47 | } 48 | } 49 | reader->advance(length); 50 | } 51 | -------------------------------------------------------------------------------- /src/lib/ccir476.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "ccir476.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | bool Ccir476Decoder::canProcess() { 25 | std::lock_guard lock(this->processMutex); 26 | return reader->available() > 0; 27 | } 28 | 29 | void Ccir476Decoder::process() { 30 | std::lock_guard lock(this->processMutex); 31 | unsigned char *input = reader->getReadPointer(); 32 | size_t length = reader->available(); 33 | 34 | for (size_t i = 0; i < length; i++) { 35 | unsigned char c = input[i]; 36 | switch (c) { 37 | case '\0': 38 | case CCIR476_SIB: 39 | case CCIR476_BLK: 40 | break; 41 | case CCIR476_SIA: 42 | case CCIR476_RPT: 43 | // Reset shift on phasing 44 | mode = 0; 45 | break; 46 | case CCIR476_FIG_SHIFT: 47 | mode = 1; 48 | break; 49 | case CCIR476_LTR_SHIFT: 50 | mode = 0; 51 | break; 52 | default: 53 | c = ascii(c); 54 | *(writer->getWritePointer()) = c? c : '_'; 55 | writer->advance(1); 56 | break; 57 | } 58 | } 59 | 60 | reader->advance(length); 61 | } 62 | 63 | unsigned char Ccir476Decoder::ascii(unsigned char code) { 64 | return code>127? '\0' : mode? CCIR476_FIGURES[code] : CCIR476_LETTERS[code]; 65 | } 66 | 67 | bool Ccir476Decoder::isValid(unsigned char code) { 68 | return (code < 128) && (CCIR476_ZEROCOUNT[code] == 3); 69 | } 70 | -------------------------------------------------------------------------------- /src/lib/converter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021-2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "converter.hpp" 21 | #include "complex.hpp" 22 | 23 | #include 24 | 25 | using namespace Csdr; 26 | 27 | template <> void Converter::process(float* input, short* output, size_t length) { 28 | for (int i = 0; i < length; i++) { 29 | output[i] = input[i] * SHRT_MAX; 30 | } 31 | } 32 | 33 | template <> void Converter::process(short* input, float* output, size_t length) { 34 | for (int i = 0; i < length; i++) { 35 | output[i] = (float) input[i] / SHRT_MAX; 36 | } 37 | } 38 | 39 | template <> void Converter::process(unsigned char *input, float *output, size_t length) { 40 | for (int i = 0; i < length; i++) { 41 | output[i] = ((float) input[i]) / (UCHAR_MAX / 2.0) - 1.0; 42 | } 43 | } 44 | 45 | template <> void Converter::process(float *input, unsigned char *output, size_t length) { 46 | for(int i=0; i < length; i++) { 47 | output[i] = input[i] * UCHAR_MAX * 0.5 + 128; 48 | } 49 | } 50 | 51 | template <> 52 | void Converter, complex>::process(complex *input, complex *output, size_t length) { 53 | for (int i = 0; i < length * 2; i++) { 54 | ((short*) output)[i] = ((float*) input)[i] * SHRT_MAX; 55 | } 56 | } 57 | 58 | template <> 59 | void Converter, complex>::process(complex *input, complex* output, size_t length) { 60 | for (int i = 0; i < length * 2; i++) { 61 | ((float*) output)[i] = (float) ((short*) input)[i] / SHRT_MAX; 62 | } 63 | } 64 | 65 | template<> 66 | void Converter, complex>::process(complex *input, complex *output, size_t length) { 67 | for (int i = 0; i < length * 2; i++) { 68 | ((unsigned char*) output)[i] = ((float*) input)[i] * UCHAR_MAX * 0.5 + 128; 69 | } 70 | } 71 | 72 | template <> 73 | void Converter, complex>::process(complex *input, complex *output, size_t length) { 74 | for (int i = 0; i < length * 2; i++) { 75 | ((float*) output)[i] = ((float) ((unsigned char*) input)[i]) / (UCHAR_MAX / 2.0) - 1.0; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/lib/dbpsk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "dbpsk.hpp" 33 | #include 34 | 35 | using namespace Csdr; 36 | 37 | void DBPskDecoder::process(complex *input, unsigned char *output, size_t size) { 38 | for (size_t i = 0; i < size; i++) { 39 | float phase = std::arg(input[i]); 40 | if (std::isnan(phase)) phase = 0.0f; 41 | float dphase = phase - last_phase; 42 | while (dphase < -M_PI) dphase += 2 * M_PI; 43 | while (dphase >= M_PI) dphase -= 2 * M_PI; 44 | if (dphase > (M_PI / 2) || dphase < (-M_PI / 2)) { 45 | output[i] = 0; 46 | } else { 47 | output[i] = 1; 48 | } 49 | last_phase = phase; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/lib/dcblock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "dcblock.hpp" 21 | 22 | #include 23 | 24 | using namespace Csdr; 25 | 26 | #define R 0.998f 27 | #define GAIN ((1 + R) / 2) 28 | 29 | void DcBlock::process(float *input, float *output, size_t length) { 30 | for (size_t i = 0; i < length; i++) { 31 | // dc block filter implementation according to https://www.dsprelated.com/freebooks/filters/DC_Blocker.html 32 | float x = input[i]; 33 | if (std::isnan(x)) x = 0.0f; 34 | float y = GAIN * (x - xm1) + R * ym1; 35 | xm1 = x; 36 | ym1 = y; 37 | output[i] = y; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/deemphasis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "deemphasis.hpp" 33 | #include "predefined.h" 34 | 35 | #include 36 | 37 | using namespace Csdr; 38 | 39 | WfmDeemphasis::WfmDeemphasis(unsigned int sampleRate, float tau): dt(1.0f / sampleRate), alpha(dt / tau + dt) {} 40 | 41 | void WfmDeemphasis::process(float *input, float *output, size_t size) { 42 | /* 43 | typical time constant (tau) values: 44 | WFM transmission in USA: 75 us -> tau = 75e-6 45 | WFM transmission in EU: 50 us -> tau = 50e-6 46 | More info at: http://www.cliftonlaboratories.com/fm_receivers_and_de-emphasis.htm 47 | Simulate in octave: tau=75e-6; dt=1/48000; alpha = dt/(tau+dt); freqz([alpha],[1 -(1-alpha)]) 48 | */ 49 | if (std::isnan(last_output)) last_output = 0.0; 50 | for (int i = 0; i < size; i++) { 51 | output[i] = last_output = alpha * input[i] + (1 - alpha) * last_output; //this is the simplest IIR LPF 52 | } 53 | } 54 | 55 | NfmDeephasis::NfmDeephasis(unsigned int sampleRate): FilterModule(getFilter(sampleRate)) {} 56 | 57 | FirFilter* NfmDeephasis::getFilter(unsigned int sampleRate) { 58 | switch (sampleRate) { 59 | // we only cover selected sample rates. see predefined.h for details. 60 | case 8000: 61 | return new FirFilter(deemphasis_nfm_predefined_fir_8000, 79); 62 | case 11025: 63 | return new FirFilter(deemphasis_nfm_predefined_fir_11025, 79); 64 | case 12000: 65 | return new FirFilter(deemphasis_nfm_predefined_fir_12000, 79); 66 | case 24000: 67 | return new FirFilter(deemphasis_nfm_predefined_fir_24000, 199); 68 | case 44100: 69 | return new FirFilter(deemphasis_nfm_predefined_fir_44100, 199); 70 | case 48000: 71 | return new FirFilter(deemphasis_nfm_predefined_fir_48000, 199); 72 | default: 73 | // we do not have a filter for this rate, but have to return 74 | // some filter, so let us go with a closest one 75 | sampleRate = 76 | sampleRate < 11025? 8000 : 77 | sampleRate < 12000? 11025 : 78 | sampleRate < 24000? 12000 : 79 | sampleRate < 44100? 24000 : 80 | sampleRate < 48000? 44100 : 48000; 81 | return getFilter(sampleRate); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/lib/downmix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "downmix.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | template 25 | Downmix::Downmix(unsigned int channels): channels(channels) {} 26 | 27 | template 28 | bool Downmix::canProcess() { 29 | return this->reader->available() >= channels && this->writer->writeable() > 0; 30 | } 31 | 32 | template 33 | void Downmix::process() { 34 | std::lock_guard lock(this->processMutex); 35 | size_t numSamples = std::min(this->reader->available() / channels, this->writer->writeable()); 36 | T* input = this->reader->getReadPointer(); 37 | T* output = this->writer->getWritePointer(); 38 | for (size_t i = 0; i < numSamples; i++) { 39 | T sum = 0; 40 | for (unsigned int k = 0; k < channels; k++) { 41 | sum += input[i * channels + k] / channels; 42 | } 43 | output[i] = sum; 44 | } 45 | this->reader->advance(numSamples * channels); 46 | this->writer->advance(numSamples); 47 | } 48 | 49 | namespace Csdr { 50 | template class Downmix; 51 | template class Downmix; 52 | } -------------------------------------------------------------------------------- /src/lib/fft.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "fft.hpp" 21 | 22 | #include 23 | 24 | using namespace Csdr; 25 | 26 | Fft::Fft(unsigned int fftSize, unsigned int everyNSamples, Window* window): fftSize(fftSize), everyNSamples(everyNSamples) { 27 | windowed = (complex*) malloc(sizeof(complex) * fftSize); 28 | output_buffer = (complex*) malloc(sizeof(complex) * fftSize); 29 | plan = fftwf_plan_dft_1d(fftSize, (fftwf_complex*) windowed, (fftwf_complex*) output_buffer, FFTW_FORWARD, FFTW_ESTIMATE); 30 | this->window = window->precalculate(fftSize); 31 | } 32 | 33 | Fft::~Fft() { 34 | free(windowed); 35 | free(output_buffer); 36 | delete window; 37 | fftwf_destroy_plan(plan); 38 | } 39 | 40 | bool Fft::canProcess() { 41 | std::lock_guard lock(this->processMutex); 42 | return std::min(reader->available(), writer->writeable()) > fftSize; 43 | } 44 | 45 | void Fft::process() { 46 | std::lock_guard lock(processMutex); 47 | size_t available = reader->available(); 48 | if (skipped + available >= everyNSamples) { 49 | // start of next fft is in range 50 | if (everyNSamples > skipped) { 51 | // move forward to the beginning (align) 52 | unsigned int toSkip = everyNSamples - skipped; 53 | reader->advance(toSkip); 54 | skipped += toSkip; 55 | available -= toSkip; 56 | } 57 | 58 | // do we still have enough data for an fft now? 59 | if (available >= fftSize) { 60 | if (window != nullptr) { 61 | window->apply(reader->getReadPointer(), windowed, fftSize); 62 | } else { 63 | memcpy(windowed, reader->getReadPointer(), fftSize); 64 | } 65 | fftwf_execute(plan); 66 | std::memcpy(writer->getWritePointer(), output_buffer, sizeof(complex) * fftSize); 67 | writer->advance(fftSize); 68 | 69 | skipped = 0; 70 | } 71 | } else { 72 | // drop data 73 | reader->advance(available); 74 | skipped += available; 75 | } 76 | } 77 | 78 | void Fft::setEveryNSamples(unsigned int everyNSamples) { 79 | this->everyNSamples = everyNSamples; 80 | } 81 | -------------------------------------------------------------------------------- /src/lib/fftexchangesides.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "fftexchangesides.hpp" 33 | 34 | #include 35 | 36 | using namespace Csdr; 37 | 38 | FftExchangeSides::FftExchangeSides(unsigned int fftSize): fftSize(fftSize) {} 39 | 40 | size_t FftExchangeSides::getLength() { 41 | return fftSize; 42 | } 43 | 44 | void FftExchangeSides::process(float* input, float* output) { 45 | unsigned int half = fftSize / 2; 46 | std::memcpy(output, input + half, sizeof(float) * half); 47 | std::memcpy(output + half, input, sizeof(float) * half); 48 | } -------------------------------------------------------------------------------- /src/lib/filter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "filter.hpp" 21 | #include "complex.hpp" 22 | 23 | using namespace Csdr; 24 | 25 | template 26 | SparseView SampleFilter::sparse(T* data) { 27 | return SparseView(data, this); 28 | } 29 | 30 | template 31 | size_t SampleFilter::apply(T *input, T *output, size_t size) { 32 | for (size_t i = 0; i < size; i++) { 33 | output[i] = processSample(input, i); 34 | } 35 | return size; 36 | } 37 | 38 | template 39 | SparseView::SparseView(T *data, SampleFilter *filter): 40 | data(data), 41 | filter(filter) 42 | {} 43 | 44 | template 45 | T SparseView::operator[](size_t index) { 46 | return filter->processSample(data, index); 47 | } 48 | 49 | template 50 | FilterModule::FilterModule(Filter *filter): filter(filter) {} 51 | 52 | template 53 | FilterModule::~FilterModule() { 54 | delete filter; 55 | } 56 | 57 | template 58 | void FilterModule::setFilter(Filter* filter) { 59 | std::lock_guard lock(this->processMutex); 60 | delete this->filter; 61 | this->filter = filter; 62 | } 63 | 64 | template 65 | bool FilterModule::canProcess() { 66 | std::lock_guard lock(this->processMutex); 67 | return this->reader->available() > filter->getMinProcessingSize() + filter->getOverhead() && this->writer->writeable() > filter->getMinProcessingSize(); 68 | } 69 | 70 | template 71 | void FilterModule::process() { 72 | std::lock_guard lock(this->processMutex); 73 | size_t available = this->reader->available(); 74 | size_t writeable = this->writer->writeable(); 75 | size_t filterOverhead = filter->getOverhead(); 76 | 77 | // sanity check 78 | // if this condition is not met, the calculation below produces impossible results due to negative numbers 79 | if (available < filterOverhead) return; 80 | 81 | size_t size = std::min(available - filterOverhead, writeable); 82 | 83 | T* input = this->reader->getReadPointer(); 84 | T* output = this->writer->getWritePointer(); 85 | size = filter->apply(input, output, size); 86 | this->reader->advance(size); 87 | this->writer->advance(size); 88 | } 89 | 90 | namespace Csdr { 91 | template class SampleFilter>; 92 | template class SampleFilter; 93 | 94 | template class SparseView>; 95 | template class SparseView; 96 | 97 | template class FilterModule>; 98 | template class FilterModule; 99 | } -------------------------------------------------------------------------------- /src/lib/firdecimate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "firdecimate.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | FirDecimate::FirDecimate(unsigned int decimation, float transitionBandwidth, Window* window, float cutoff): 25 | decimation(decimation), 26 | lowpass(new LowPassFilter>(cutoff / (float) decimation, transitionBandwidth, window)) 27 | {} 28 | 29 | FirDecimate::FirDecimate(unsigned int decimation, float transitionBandwidth, Window* window): 30 | FirDecimate(decimation, transitionBandwidth, window, 0.5f) 31 | {} 32 | 33 | FirDecimate::~FirDecimate() { 34 | delete lowpass; 35 | } 36 | 37 | void FirDecimate::process() { 38 | std::lock_guard lock(processMutex); 39 | size_t available = reader->available(); 40 | size_t writeable = writer->writeable(); 41 | size_t lpLen = lowpass->getOverhead(); 42 | 43 | // sanity check 44 | // if this condition is not met, the calculation below produces impossible results due to negative numbers 45 | if (available < lpLen) return; 46 | 47 | size_t samples = std::min((available - lpLen) / decimation, writeable); 48 | 49 | complex* output = writer->getWritePointer(); 50 | SparseView> sparseView = lowpass->sparse(reader->getReadPointer()); 51 | for (size_t i = 0; i < samples; i++) { 52 | output[i] = sparseView[i * decimation]; 53 | } 54 | reader->advance(samples * decimation); 55 | writer->advance(samples); 56 | } 57 | 58 | bool FirDecimate::canProcess() { 59 | std::lock_guard lock(processMutex); 60 | size_t available = reader->available(); 61 | size_t writeable = writer->writeable(); 62 | size_t lpLen = lowpass->getOverhead(); 63 | return available > lpLen && (available - lpLen) / decimation > 0 && writeable > 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/lib/fmdemod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "fmdemod.hpp" 33 | 34 | #include 35 | 36 | using namespace Csdr; 37 | 38 | void FmDemod::process(complex* input, float* output, size_t work_size) { 39 | float phase, dphase; 40 | for (size_t i = 0; i < work_size; i++) { 41 | phase = std::arg(input[i]); 42 | dphase = phase - last_phase; 43 | while (dphase < -M_PI) dphase += 2 * M_PI; 44 | while (dphase > M_PI) dphase -= 2 * M_PI; 45 | output[i] = dphase / M_PI; 46 | last_phase = phase; 47 | } 48 | } -------------------------------------------------------------------------------- /src/lib/fmv.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2022 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #ifndef FMV_H 21 | 22 | #ifdef CSDR_FMV 23 | #if defined(__has_attribute) 24 | #if __has_attribute(target_clones) 25 | #if defined(__x86_64) 26 | #define CSDR_TARGET_CLONES __attribute__((target_clones("avx","sse4.2","sse3","sse2","default"))) 27 | #endif 28 | #endif 29 | #endif 30 | #endif 31 | 32 | #ifndef CSDR_TARGET_CLONES 33 | #define CSDR_TARGET_CLONES 34 | #endif 35 | 36 | #endif -------------------------------------------------------------------------------- /src/lib/gain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "gain.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | 25 | template 26 | Gain::Gain(float gain): gain(gain) {} 27 | 28 | template 29 | void Gain::process(T *input, T *output, size_t size) { 30 | for (size_t i = 0; i < size; i++) { 31 | output[i] = static_cast(input[i] * gain); 32 | } 33 | } 34 | 35 | namespace Csdr { 36 | template class Gain; 37 | template class Gain>; 38 | } -------------------------------------------------------------------------------- /src/lib/limit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "limit.hpp" 21 | 22 | Csdr::Limit::Limit(float maxAmplitude): maxAmplitude(maxAmplitude) {} 23 | 24 | void Csdr::Limit::process(float *input, float *output, size_t size) { 25 | for (size_t i = 0; i < size; i++) { 26 | if (input[i] > maxAmplitude) { 27 | output[i] = maxAmplitude; 28 | } else if (input[i] < -maxAmplitude) { 29 | output[i] = -maxAmplitude; 30 | } else { 31 | output[i] = input[i]; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/lib/logaveragepower.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "logaveragepower.hpp" 33 | 34 | #include 35 | 36 | using namespace Csdr; 37 | 38 | LogAveragePower::LogAveragePower(unsigned int fftSize, unsigned int avgNumber, float add_db): fftSize(fftSize), avgNumber(avgNumber), add_db(add_db) { 39 | collector = (float*) malloc(sizeof(float) * fftSize); 40 | std::memset(collector, 0, sizeof(float) * fftSize); 41 | } 42 | 43 | LogAveragePower::LogAveragePower(unsigned int fftSize, unsigned int avgNumber): LogAveragePower(fftSize, avgNumber, 0.0) {} 44 | 45 | LogAveragePower::~LogAveragePower() { 46 | free(collector); 47 | } 48 | 49 | void LogAveragePower::setAvgNumber(unsigned int avgNumber) { 50 | this->avgNumber = avgNumber; 51 | } 52 | 53 | bool LogAveragePower::canProcess() { 54 | std::lock_guard lock(processMutex); 55 | return reader->available() > fftSize && writer->writeable() > fftSize; 56 | } 57 | 58 | void LogAveragePower::process() { 59 | std::lock_guard lock(processMutex); 60 | complex* input = reader->getReadPointer(); 61 | for (int i = 0; i < fftSize; i++) { 62 | collector[i] += std::norm(input[i]); 63 | } 64 | reader->advance(fftSize); 65 | if (++collected == avgNumber) { 66 | float* output = writer->getWritePointer(); 67 | float correction = add_db - 10.0 * log10(avgNumber); 68 | 69 | for (int i = 0; i < fftSize; i++) { 70 | output[i] = log10(collector[i]); 71 | } 72 | 73 | for (int i = 0; i < fftSize; i++) { 74 | output[i] = 10 * output[i] + correction; 75 | } 76 | 77 | writer->advance(fftSize); 78 | 79 | std::memset(collector, 0, sizeof(float) * fftSize); 80 | collected = 0; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/lib/logpower.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "logpower.hpp" 33 | 34 | #include 35 | 36 | using namespace Csdr; 37 | 38 | LogPower::LogPower(float add_db): add_db(add_db) {} 39 | 40 | LogPower::LogPower(): LogPower(0.0) {} 41 | 42 | void LogPower::process(complex* input, float* output, size_t size) { 43 | for (int i = 0; i < size; i++) { 44 | output[i] = std::norm(input[i]); 45 | } 46 | 47 | for (int i = 0; i < size; i++) { 48 | output[i] = log10(output[i]); 49 | } 50 | 51 | for (int i = 0; i < size; i++) { 52 | output[i] = 10 * output[i] + add_db; 53 | } 54 | } -------------------------------------------------------------------------------- /src/lib/navtex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "navtex.hpp" 21 | #include 22 | 23 | using namespace Csdr; 24 | 25 | bool NavtexDecoder::canProcess() { 26 | std::lock_guard lock(this->processMutex); 27 | return reader->available() >= 11; 28 | } 29 | 30 | void NavtexDecoder::process() { 31 | std::lock_guard lock(this->processMutex); 32 | unsigned char *in = reader->getReadPointer(); 33 | size_t length = reader->available(); 34 | size_t i; 35 | 36 | // If looking for a message... 37 | if (!receiving) { 38 | // Need at least 11 characters 39 | if (length < 11) return; 40 | 41 | // Look for a message start 42 | receiving = 43 | (in[0]=='Z') && (in[1]=='C') && (in[2]=='Z') && (in[3]=='C') && 44 | (in[4]==' ') && (in[9]=='\r') && (in[10]=='\n'); 45 | 46 | // Reset character counter when starting a message 47 | if (receiving) { 48 | received = 0; 49 | } else { 50 | reader->advance(1); 51 | return; 52 | } 53 | } 54 | 55 | // 56 | // ... RECEIVING NAVTEX MESSAGE ... 57 | // 58 | 59 | // Look for a message end 60 | for (i = 0 ; i + 7 <= length ; i++) { 61 | unsigned char *p = in + i; 62 | receiving = !( 63 | (p[0]=='N') && (p[1]=='N') && (p[2]=='N') && (p[3]=='N') && 64 | (p[4]=='\r') && (p[5]=='\n') && (p[6]=='\n') 65 | ); 66 | 67 | if (!receiving) { 68 | i += 7; 69 | break; 70 | } 71 | } 72 | 73 | // Copy received message content to the output 74 | memcpy(writer->getWritePointer(), in, i); 75 | writer->advance(i); 76 | reader->advance(i); 77 | received += i; 78 | 79 | // Limit the number of characters per message 80 | if (received >= NAVTEX_MAX_CHARS) receiving = false; 81 | } 82 | -------------------------------------------------------------------------------- /src/lib/noise.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2023 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "noise.hpp" 33 | #include 34 | 35 | using namespace Csdr; 36 | 37 | template 38 | NoiseSource::NoiseSource() { 39 | random = fopen("/dev/urandom", "r"); 40 | } 41 | 42 | template 43 | NoiseSource::~NoiseSource() { 44 | fclose(random); 45 | } 46 | 47 | template 48 | void NoiseSource::setWriter(Writer *writer) { 49 | Source::setWriter(writer); 50 | if (thread == nullptr) { 51 | thread = new std::thread( [this] () { loop(); }); 52 | } 53 | } 54 | 55 | template 56 | void NoiseSource::loop() { 57 | while (true) { 58 | generateSamples(this->writer->getWritePointer(), 1024); 59 | this->writer->advance(1024); 60 | } 61 | } 62 | 63 | template <> 64 | void NoiseSource>::generateSamples(complex *output, size_t length) { 65 | int* pioutput = (int*)output; 66 | fread(output, sizeof(complex), length, random); 67 | for(int i = 0; i < length * 2; i++) { 68 | complex tempi = { 69 | pioutput[i * 2], 70 | pioutput[i * 2 + 1] 71 | }; 72 | output[i] = { 73 | tempi.i() / ((float) (INT_MAX)), 74 | tempi.q() / ((float) (INT_MAX)) 75 | }; 76 | } 77 | 78 | } 79 | 80 | namespace Csdr { 81 | template class NoiseSource>; 82 | } -------------------------------------------------------------------------------- /src/lib/phasedemod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "phasedemod.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | void PhaseDemod::process(complex *input, float *output, size_t work_size) { 25 | for (size_t i = 0; i < work_size; i++) { 26 | output[i] = std::arg(input[i]); 27 | } 28 | 29 | for (size_t i = 0; i < work_size; i++) { 30 | if (std::isnan(output[i])) output[i] = 0.0f; 31 | } 32 | } -------------------------------------------------------------------------------- /src/lib/power.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "power.hpp" 21 | 22 | #include 23 | #include 24 | 25 | using namespace Csdr; 26 | 27 | template 28 | Power::Power(size_t length, unsigned int decimation, std::function callback): 29 | length(std::max(length, (size_t)1)), 30 | decimation(std::max(decimation, (unsigned int)1)), 31 | callback(std::move(callback)) 32 | {} 33 | 34 | template 35 | bool Power::canProcess() { 36 | std::lock_guard lock(this->processMutex); 37 | size_t length = this->getLength(); 38 | return (this->reader->available() > length && this->writer->writeable() > length); 39 | } 40 | 41 | template 42 | void Power::process() { 43 | std::lock_guard lock(this->processMutex); 44 | T* input = this->reader->getReadPointer(); 45 | size_t length = this->getLength(); 46 | 47 | float power = 0.0f; 48 | for (size_t i = 0; i < length; i += decimation) { 49 | power += std::norm(input[i]); 50 | } 51 | 52 | // compute average power 53 | power /= ceilf((float) length / decimation); 54 | 55 | // report power 56 | if (callback) callback(power); 57 | 58 | // pass data 59 | forwardData(input, power); 60 | 61 | // advance input 62 | this->reader->advance(length); 63 | } 64 | 65 | template 66 | size_t Power::getLength() { 67 | return length; 68 | } 69 | 70 | template 71 | void Power::forwardData(T* input, float power) { 72 | T* output = this->writer->getWritePointer(); 73 | size_t length = this->getLength(); 74 | std::memcpy(output, input, length * sizeof(T)); 75 | this->writer->advance(length); 76 | } 77 | 78 | template 79 | Squelch::Squelch(size_t length, unsigned int decimation, size_t hangLength, size_t flushLength, std::function callback): 80 | Power(length, decimation, callback), 81 | flushLength(flushLength), 82 | hangLength(hangLength) 83 | {} 84 | 85 | template 86 | void Squelch::setSquelch(float squelchLevel) { 87 | this->squelchLevel = squelchLevel; 88 | } 89 | 90 | template 91 | void Squelch::forwardData(T *input, float power) { 92 | if (squelchLevel == 0.0f || power >= squelchLevel) { 93 | Power::forwardData(input, power); 94 | flushCounter = hangCounter = 0; 95 | } else if (hangCounter < hangLength) { 96 | // keep forwarding for a while in case signal comes back 97 | Power::forwardData(input, power); 98 | hangCounter += this->getLength(); 99 | } else if (flushCounter < flushLength) { 100 | // produce some 0s to flush any subsequent modules 101 | // if they have any overhead (e.g. FIR filter delays) 102 | T* output = this->writer->getWritePointer(); 103 | size_t length = std::min(this->getLength(), flushLength - flushCounter); 104 | std::memset(output, 0, sizeof(T) * length); 105 | this->writer->advance(length); 106 | flushCounter += length; 107 | } 108 | } 109 | 110 | namespace Csdr { 111 | template class Power; 112 | template class Power>; 113 | template class Squelch; 114 | template class Squelch>; 115 | } 116 | -------------------------------------------------------------------------------- /src/lib/reader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "reader.hpp" 21 | #include "complex.hpp" 22 | 23 | using namespace Csdr; 24 | 25 | template 26 | MemoryReader::MemoryReader(T *data, size_t size): data(data), size(size) {} 27 | 28 | template 29 | size_t MemoryReader::available() { 30 | return size - read_pos; 31 | } 32 | 33 | template 34 | T* MemoryReader::getReadPointer() { 35 | return data + read_pos; 36 | } 37 | 38 | template 39 | void MemoryReader::advance(size_t how_much) { 40 | read_pos += how_much; 41 | } 42 | 43 | template 44 | void MemoryReader::wait() { 45 | // not implemented. the data should be in memory already. 46 | } 47 | 48 | template 49 | void MemoryReader::rewind() { 50 | read_pos = 0; 51 | } 52 | 53 | namespace Csdr { 54 | template class MemoryReader>; 55 | template class MemoryReader; 56 | template class MemoryReader; 57 | } -------------------------------------------------------------------------------- /src/lib/realpart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "realpart.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | void Realpart::process(complex* input, float* output, size_t size) { 25 | for (size_t i = 0; i < size; i++) { 26 | output[i] = input[i].i(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/lib/rtty.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "rtty.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | RttyDecoder::RttyDecoder(bool invert): 25 | Module(), 26 | invert(invert) 27 | {} 28 | 29 | RttyDecoder::RttyDecoder(): 30 | RttyDecoder(false) 31 | {} 32 | 33 | bool RttyDecoder::canProcess() { 34 | std::lock_guard lock(this->processMutex); 35 | return reader->available() > 8; 36 | } 37 | 38 | void RttyDecoder::process() { 39 | std::lock_guard lock(this->processMutex); 40 | float* data = reader->getReadPointer(); 41 | if (!toBit(data[0]) && toBit(data[6])) { 42 | unsigned char output = 0; 43 | for (int i = 0; i < 5; i++) { 44 | bool bit = toBit(data[5 - i]); 45 | output = (output << 1) | bit; 46 | } 47 | reader->advance(7); 48 | *(writer->getWritePointer()) = output; 49 | writer->advance(1); 50 | } else { 51 | reader->advance(1); 52 | } 53 | } 54 | 55 | bool RttyDecoder::toBit(float sample) { 56 | return (sample > 0) != invert; 57 | } 58 | -------------------------------------------------------------------------------- /src/lib/sink.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "sink.hpp" 21 | 22 | using namespace Csdr; 23 | 24 | template 25 | void Sink::setReader(Reader* reader) { 26 | if (reader == this->reader) return; 27 | auto oldReader = this->reader; 28 | this->reader = reader; 29 | // if we had a reader before, there's a chance we're still wait()ing on it in a thread. 30 | // this makes sure we start reading on the new reader immediately. 31 | if (oldReader != nullptr) oldReader->unblock(); 32 | } 33 | 34 | template 35 | Reader* Sink::getReader() { 36 | return reader; 37 | } 38 | 39 | template 40 | bool Sink::hasReader() { 41 | return reader != nullptr; 42 | } 43 | 44 | namespace Csdr { 45 | template class Sink; 46 | template class Sink; 47 | template class Sink>; 48 | template class Sink>; 49 | template class Sink; 50 | template class Sink>; 51 | } -------------------------------------------------------------------------------- /src/lib/sitorb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023-2024 Marat Fayzullin 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "sitorb.hpp" 21 | #include "ccir476.hpp" 22 | 23 | using namespace Csdr; 24 | 25 | bool SitorBDecoder::canProcess() { 26 | std::lock_guard lock(this->processMutex); 27 | return reader->available() >= 7; 28 | } 29 | 30 | void SitorBDecoder::process() { 31 | std::lock_guard lock(this->processMutex); 32 | float *data = reader->getReadPointer(); 33 | unsigned int output = 0; 34 | int i; 35 | 36 | // Get seven input bits 37 | for (i = 0; i < 7; i++) { 38 | output |= toBit(data[i])? (1 << i) : 0; 39 | } 40 | 41 | // Resync after several repeated errors 42 | if (!isValid(output) && (errors > errorsAllowed)) { 43 | // Skip a bit 44 | reader->advance(1); 45 | } else { 46 | // Count repeating errors 47 | if(isValid(output)) errors = 0; else errors++; 48 | // Process and output received character 49 | output = fec(output); 50 | if (output) { 51 | *(writer->getWritePointer()) = output; 52 | writer->advance(1); 53 | } 54 | // Skip 7 bits 55 | reader->advance(7); 56 | } 57 | } 58 | 59 | bool SitorBDecoder::toBit(float sample) { 60 | return (sample > 0) != invert; 61 | } 62 | 63 | bool SitorBDecoder::isValid(unsigned char code) { 64 | return (code < 128) && (CCIR476_ZEROCOUNT[code] == 3); 65 | } 66 | 67 | unsigned char SitorBDecoder::fec(unsigned char code) { 68 | switch (code) { 69 | case CCIR476_SIA: 70 | // This symbol is always received in DX phase 71 | rxPhase = false; 72 | errors = 0; 73 | break; 74 | case CCIR476_RPT: 75 | // The DX phase had to have CCIR476_SIA 76 | code = c1==CCIR476_SIA? c1 : '\0'; 77 | // DX phase next 78 | rxPhase = false; 79 | errors = code? 0 : errors + 1; 80 | return code; 81 | } 82 | 83 | if (rxPhase) { 84 | code = c1==CCIR476_SIA? code 85 | : c1==code? code 86 | : isValid(code)? code 87 | : isValid(c1)? c1 88 | : isValid(c1|code)? (c1|code) 89 | : isValid(c1&code)? (c1&code) 90 | : 128; //tryRecovery(code, c1); 91 | } else { 92 | c1 = c2; 93 | c2 = c3; 94 | c3 = code; 95 | code = '\0'; 96 | } 97 | 98 | rxPhase = !rxPhase; 99 | return code; 100 | } 101 | 102 | unsigned char SitorBDecoder::tryRecovery(unsigned char x, unsigned char y) { 103 | unsigned char badBits = x ^ y; 104 | unsigned char bit, data; 105 | unsigned char bits[8]; 106 | int j, i; 107 | 108 | // Must have mismatching bits 109 | if (!badBits) return x; 110 | 111 | // Count number of mismatching bits 112 | for (j = 0, bit = 0, i = badBits ; i ; i >>= 1, bit++) { 113 | if (i&1) bits[j++] = bit; 114 | } 115 | 116 | // Try all bit permutations 117 | for (j = (1<= 0 ; j--) { 118 | // Choose bits to be selected from x vs y 119 | for (data = 0, bit = 0, i = j ; i ; i >>= 1, bit++) { 120 | if (i&1) data |= 1 << bits[bit]; 121 | } 122 | // Combine bits from x and y 123 | data = (x & data) | (y & ~data); 124 | // Return first valid combination found 125 | if (isValid(data)) return data; 126 | } 127 | 128 | // No valid combinations found 129 | return 128; 130 | } 131 | -------------------------------------------------------------------------------- /src/lib/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "source.hpp" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace Csdr; 27 | 28 | template 29 | void Source::setWriter(Writer* writer) { 30 | this->writer = writer; 31 | } 32 | 33 | template 34 | Writer* Source::getWriter() { 35 | return writer; 36 | } 37 | 38 | template 39 | bool Source::hasWriter() { 40 | return writer != nullptr; 41 | } 42 | 43 | template 44 | TcpSource::~TcpSource() { 45 | ::close(sock); 46 | } 47 | 48 | template 49 | TcpSource::TcpSource(in_addr_t ip, unsigned short port) { 50 | sockaddr_in remote{}; 51 | std::memset(&remote, 0, sizeof(remote)); 52 | 53 | remote.sin_family = AF_INET; 54 | remote.sin_port = htons(port); 55 | remote.sin_addr.s_addr = ip; 56 | 57 | sock = socket(AF_INET, SOCK_STREAM, 0); 58 | if (sock < 0) { 59 | throw NetworkException("unable to create socket"); 60 | } 61 | 62 | if (connect(sock, (struct sockaddr*)&remote, sizeof(remote)) < 0) { 63 | ::close(sock); 64 | throw NetworkException("connection failed"); 65 | } 66 | 67 | } 68 | 69 | template 70 | void TcpSource::setWriter(Writer *writer) { 71 | Source::setWriter(writer); 72 | if (thread == nullptr) { 73 | thread = new std::thread( [this] () { loop(); }); 74 | } 75 | } 76 | 77 | template 78 | void TcpSource::loop() { 79 | int read_bytes; 80 | int available; 81 | int offset = 0; 82 | pollfd pfd = { 83 | .fd = sock, 84 | .events = POLLIN 85 | }; 86 | int rc; 87 | 88 | while (run) { 89 | rc = poll(&pfd, 1, 10000); 90 | if (rc == -1) { 91 | run = false; 92 | } else if (pfd.revents & POLLERR) { 93 | run = false; 94 | } else if (pfd.revents & POLLIN) { 95 | available = std::min(this->writer->writeable(), (size_t) 1024) * sizeof(T) - offset; 96 | read_bytes = recv(sock, ((char*) this->writer->getWritePointer()) + offset, available, 0); 97 | if (read_bytes <= 0) { 98 | run = false; 99 | } else { 100 | this->writer->advance((offset + read_bytes) / sizeof(T)); 101 | offset = (offset + read_bytes) % sizeof(T); 102 | } 103 | } 104 | } 105 | } 106 | 107 | template 108 | void TcpSource::stop() { 109 | run = false; 110 | if (thread != nullptr) { 111 | auto t = thread; 112 | thread = nullptr; 113 | t->join(); 114 | delete(t); 115 | } 116 | } 117 | 118 | namespace Csdr { 119 | template class Source; 120 | template class Source; 121 | template class Source>; 122 | template class Source>; 123 | template class Source; 124 | template class Source>; 125 | 126 | template class TcpSource; 127 | template class TcpSource; 128 | template class TcpSource; 129 | template class TcpSource>; 130 | template class TcpSource>; 131 | template class TcpSource>; 132 | } -------------------------------------------------------------------------------- /src/lib/throttle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2024 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "throttle.hpp" 21 | 22 | #include 23 | #include 24 | 25 | using namespace Csdr; 26 | 27 | template 28 | Throttle::Throttle(size_t rate, size_t chunkSize): 29 | Module(), 30 | rate(rate), 31 | chunkSize(chunkSize), 32 | nominalDuration(chunkSize * 1E6 / rate) 33 | {} 34 | 35 | template 36 | Throttle::~Throttle() { 37 | if (worker != nullptr) { 38 | std::thread* old = worker; 39 | worker = nullptr; 40 | run = false; 41 | old->join(); 42 | delete(old); 43 | } 44 | } 45 | 46 | template 47 | void Throttle::setReader(Reader *reader) { 48 | Module::setReader(reader); 49 | std::lock_guard lock(this->processMutex); 50 | if (worker == nullptr && this->reader != nullptr && this->writer != nullptr) { 51 | worker = new std::thread([this] { loop(); }); 52 | } 53 | } 54 | 55 | template 56 | void Throttle::setWriter(Writer* writer) { 57 | Module::setWriter(writer); 58 | std::lock_guard lock(this->processMutex); 59 | if (worker == nullptr && this->reader != nullptr && this->writer != nullptr) { 60 | worker = new std::thread([this] { loop(); }); 61 | } 62 | } 63 | 64 | template 65 | void Throttle::loop() { 66 | while (run) { 67 | { 68 | std::lock_guard lock(this->processMutex); 69 | if (this->reader->available() < chunkSize) { 70 | // std::cerr << "Csdr::Throttle buffer under-run" << std::endl; 71 | } else if (this->writer->writeable() < chunkSize) { 72 | // std::cerr << "Csdr::Throttle buffer over-run" << std::endl; 73 | } else { 74 | std::memcpy(this->writer->getWritePointer(), this->reader->getReadPointer(), sizeof(T) * chunkSize); 75 | this->reader->advance(chunkSize); 76 | this->writer->advance(chunkSize); 77 | } 78 | } 79 | 80 | 81 | std::chrono::time_point now = std::chrono::system_clock::now(); 82 | if (nextScheduledExecution != std::chrono::system_clock::time_point()) { 83 | nextScheduledExecution += nominalDuration; 84 | } else { 85 | nextScheduledExecution = now + nominalDuration; 86 | } 87 | 88 | std::chrono::duration toSleep = nextScheduledExecution - now; 89 | 90 | if (toSleep > std::chrono::microseconds(0)) { 91 | std::this_thread::sleep_for(toSleep); 92 | } 93 | } 94 | } 95 | 96 | namespace Csdr { 97 | template class Throttle; 98 | template class Throttle; 99 | } 100 | -------------------------------------------------------------------------------- /src/lib/varicode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This software is part of libcsdr, a set of simple DSP routines for 3 | Software Defined Radio. 4 | 5 | Copyright (c) 2014, Andras Retzler 6 | Copyright (c) 2019-2021 Jakob Ketterl 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "varicode.hpp" 33 | 34 | using namespace Csdr; 35 | 36 | constexpr varicode_item VaricodeDecoder::varicode_items[]; 37 | 38 | bool VaricodeDecoder::canProcess() { 39 | std::lock_guard lock(this->processMutex); 40 | return reader->available() > 0 && writer->writeable() > 0; 41 | } 42 | 43 | void VaricodeDecoder::process() { 44 | std::lock_guard lock(this->processMutex); 45 | unsigned char symbol = *(reader->getReadPointer()); 46 | reader->advance(1); 47 | 48 | status = (status << 1) | (symbol & 0b1); //shift new bit in shift register 49 | 50 | if ((status & 0xFFF) == 0) return; 51 | 52 | for (auto item: varicode_items) { 53 | unsigned long long mask = (1 << (item.bitcount + 4)) - 1; 54 | if ((item.code << 2) == (status & mask)) { 55 | *(writer->getWritePointer()) = item.ascii; 56 | writer->advance(1); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/lib/version.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "version.hpp" 21 | 22 | namespace Csdr { 23 | 24 | const std::string version = VERSION; 25 | 26 | } -------------------------------------------------------------------------------- /src/lib/writer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Jakob Ketterl 3 | 4 | This file is part of libcsdr. 5 | 6 | libcsdr is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | libcsdr is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with libcsdr. If not, see . 18 | */ 19 | 20 | #include "writer.hpp" 21 | #include "complex.hpp" 22 | 23 | #include 24 | 25 | using namespace Csdr; 26 | 27 | template 28 | StdoutWriter::StdoutWriter(size_t buffer_size): 29 | buffer_size(buffer_size), 30 | buffer((T*) malloc(sizeof(T) * buffer_size)) 31 | {} 32 | 33 | template 34 | StdoutWriter::StdoutWriter(): StdoutWriter(10240) {} 35 | 36 | template 37 | StdoutWriter::~StdoutWriter() { 38 | free(buffer); 39 | } 40 | 41 | template 42 | size_t StdoutWriter::writeable() { 43 | return buffer_size; 44 | } 45 | 46 | template 47 | T* StdoutWriter::getWritePointer() { 48 | return buffer; 49 | } 50 | 51 | template 52 | void StdoutWriter::advance(size_t how_much) { 53 | write(fileno(stdout), (const char*) buffer, sizeof(T) * how_much); 54 | } 55 | 56 | template 57 | VoidWriter::VoidWriter(size_t buffer_size): 58 | buffer_size(buffer_size), 59 | data((T*) malloc(sizeof(T) * buffer_size)) 60 | {} 61 | 62 | template 63 | VoidWriter::VoidWriter(): VoidWriter(1024) {} 64 | 65 | template 66 | VoidWriter::~VoidWriter() { 67 | free(data); 68 | } 69 | 70 | template 71 | size_t VoidWriter::writeable() { 72 | return buffer_size; 73 | } 74 | 75 | template 76 | T* VoidWriter::getWritePointer() { 77 | return data; 78 | } 79 | 80 | namespace Csdr { 81 | template class StdoutWriter; 82 | template class StdoutWriter; 83 | template class StdoutWriter; 84 | template class StdoutWriter; 85 | template class StdoutWriter>; 86 | 87 | template class VoidWriter>; 88 | template class VoidWriter; 89 | template class VoidWriter; 90 | template class VoidWriter; 91 | } --------------------------------------------------------------------------------