├── .clang-format ├── .github ├── actions │ ├── build │ │ └── action.yml │ ├── package │ │ └── action.yml │ └── test │ │ └── action.yml ├── dependabot.yml ├── labeler.yml └── workflows │ ├── build.yml │ ├── codeql.yml │ ├── doc.yml │ └── labeler.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── modules │ ├── CodeAnalysis.cmake │ ├── FindCoverxygen.cmake │ └── FindCppCheck.cmake ├── cmake_uninstall.cmake.in ├── doc ├── API.md ├── Building.md ├── CMakeLists.txt └── Index.md ├── src ├── CMakeLists.txt ├── include │ └── sigutils │ │ ├── agc.h │ │ ├── block.h │ │ ├── clock.h │ │ ├── coef.h │ │ ├── dc_corrector.h │ │ ├── decider.h │ │ ├── defs.h │ │ ├── detect.h │ │ ├── equalizer.h │ │ ├── iir.h │ │ ├── lfsr.h │ │ ├── log.h │ │ ├── matfile.h │ │ ├── ncqo.h │ │ ├── pll.h │ │ ├── property.h │ │ ├── sampling.h │ │ ├── sigutils.h │ │ ├── smoothpsd.h │ │ ├── softtune.h │ │ ├── specific │ │ └── apt.h │ │ ├── specttuner.h │ │ ├── taps.h │ │ ├── tvproc.h │ │ ├── types.h │ │ ├── util │ │ ├── compat-fcntl.h │ │ ├── compat-in.h │ │ ├── compat-inet.h │ │ ├── compat-mman.h │ │ ├── compat-netdb.h │ │ ├── compat-poll.h │ │ ├── compat-pwd.h │ │ ├── compat-select.h │ │ ├── compat-socket.h │ │ ├── compat-stat.h │ │ ├── compat-statvfs.h │ │ ├── compat-stdlib.h │ │ ├── compat-termios.h │ │ ├── compat-time.h │ │ ├── compat-unistd.h │ │ ├── util.h │ │ ├── win32-fcntl.h │ │ ├── win32-in.h │ │ ├── win32-inet.h │ │ ├── win32-mman.h │ │ ├── win32-netdb.h │ │ ├── win32-poll.h │ │ ├── win32-pwd.h │ │ ├── win32-socket.h │ │ ├── win32-stat.h │ │ ├── win32-statvfs.h │ │ ├── win32-stdlib.h │ │ ├── win32-termios.h │ │ ├── win32-time.h │ │ └── win32-unistd.h │ │ └── version.h ├── sigutils │ ├── agc.c │ ├── block.c │ ├── clock.c │ ├── coef.c │ ├── dc_corrector.c │ ├── detect.c │ ├── equalizer.c │ ├── iir.c │ ├── lfsr.c │ ├── lib.c │ ├── log.c │ ├── matfile.c │ ├── ncqo.c │ ├── pll.c │ ├── property.c │ ├── smoothpsd.c │ ├── softtune.c │ ├── specific │ │ └── apt.c │ ├── specttuner.c │ ├── taps.c │ ├── tvproc.c │ └── version.c └── util │ ├── util.c │ ├── win32-fcntl.c │ ├── win32-mman.c │ ├── win32-poll.c │ ├── win32-pwd.c │ ├── win32-statvfs.c │ ├── win32-stdlib.c │ ├── win32-termios.c │ ├── win32-time.c │ └── win32-unistd.c └── tests ├── CMakeLists.txt ├── catch.hpp └── test_ncqo.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | --- 4 | Language: Cpp 5 | 6 | # 1. Two space indentation (never-ever use tabs) 7 | IndentWidth: 2 8 | UseTab: Never 9 | 10 | # 2. Max number of columns is 80 11 | ColumnLimit: 80 12 | 13 | # 3. No space before parenthesis except for flow control statements 14 | # (if, for, switch, etc) and sizeof. 15 | # Warning: It seems there is no option for spacing after sizeof 16 | SpaceBeforeCaseColon: false 17 | SpaceBeforeParens: ControlStatements 18 | SpaceBeforeRangeBasedForLoopColon: true 19 | 20 | # 4. Opening and closing braces in the same line as the statement they refer to, 21 | # preceded by a space (if () {) except for function definitions 22 | # (opening braces in a new line) 23 | BreakBeforeBraces: Linux 24 | 25 | # 5. Variable declarations at the beginning of the innermost block they are 26 | # required. 27 | # Warn: Cannot be tested 28 | 29 | # 6. Return type and qualifiers of a function prototype goes in the same line 30 | # as the function name. 31 | # 7. Return type and qualifiers of a function definition goes in two separate 32 | # lines (qualifiers, types, line break, name(...)) 33 | AlwaysBreakAfterDefinitionReturnType: All 34 | AlwaysBreakAfterReturnType: AllDefinitions 35 | 36 | # 8. If a line is too long (more than 80 chars) we break it according to the 37 | # following rules: 38 | # - We break from left to right, until all sublines honor the 80 column limit 39 | # - Line break increments the indentation level of all sublines in one unit 40 | # (2 spaces) except the first one 41 | # - Unary operations are never broken 42 | # - Binary operations are broken between the first operand and the operation 43 | # - Ternary operations are broken in three lines, with the first break 44 | # between the conditional expression and the "?", and the second break 45 | # right before the ":" 46 | # - Function calls are broken right after the parenthesis, with every 47 | # argument in a separate line except if the grouping of certain arguments 48 | # improves readability (e.g. pairs of I/Q components, groups of 3 spatial 49 | # coordinates, etc) 50 | # - Function definitions are broken right after the parenthesis, with every 51 | # argument definition in a separate line, always. 52 | BreakBeforeBinaryOperators: NonAssignment 53 | BreakBeforeTernaryOperators: true 54 | AllowAllArgumentsOnNextLine: false 55 | BinPackArguments: false 56 | AllowAllParametersOfDeclarationOnNextLine: false 57 | BinPackParameters: false 58 | 59 | # 9. Assignments inside conditional statements are allowed, unless it impacts 60 | # readability 61 | # Warn: Cannot be tested 62 | 63 | # 10. Braceless blocks (i.e. when the body of certain control flow statement 64 | # consists in only one statement) are preferred, according to the following 65 | # rules: 66 | # - The statement itself and its body is separated by a line break, with the 67 | # body indentation incremented by one unit. 68 | # - If the statement is an if-else construct, and one of either blocks 69 | # contain more than 1 statement, both blocks use braces. 70 | # - If the statement consists of several nested blocks of the same kind, and 71 | # any of the statement bodies cannot be expressed as a braceless block, all 72 | # nested blocks use braces. 73 | # Warn: Cannot be tested. 74 | # Note: Going by the statements above, one-liners will be avoided. 75 | AllowShortIfStatementsOnASingleLine: Never 76 | AllowShortBlocksOnASingleLine: false 77 | AllowShortCaseLabelsOnASingleLine: false 78 | AllowShortEnumsOnASingleLine: false 79 | AllowShortFunctionsOnASingleLine: None 80 | AllowShortLoopsOnASingleLine: false 81 | AlignAfterOpenBracket: AlwaysBreak 82 | 83 | # 11. Variable names in declarations are not aligned, unless it improves 84 | # readability. 85 | # Warn: A general rule must be set. Going for not aligned. 86 | 87 | # 12. Structure member names are not aligned, unless it improves readability. 88 | # Warn: A general rule must be set. Going for not aligned. 89 | 90 | # 13. Pointer declarations leave a space between the type and the stars, and no 91 | # space between the stars and the identifier, or between the stars themselves. 92 | DerivePointerAlignment: false 93 | PointerAlignment: Right 94 | 95 | # 14. In C code, we favor lower snake case for variables, types and function 96 | # names. 97 | # Warn: Cannot be checked. User responsibility. 98 | 99 | # 15. In C/C++ code, we favor upper snake case for #defines and enumerated constants. 100 | # Warn: Cannot be checked. User responsibility. 101 | 102 | # 16. Ident preprocessor directives after the hash 103 | IndentPPDirectives: AfterHash 104 | -------------------------------------------------------------------------------- /.github/actions/build/action.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | description: 'Build a CMake project with optional configuration and building parameters' 3 | 4 | inputs: 5 | shell: 6 | required: false 7 | default: bash 8 | cmake_build_type: 9 | default: 'Release' 10 | required: false 11 | cmake_configuration_parameters: 12 | required: false 13 | cmake_build_paramters: 14 | required: false 15 | target: 16 | default: 'all' 17 | 18 | runs: 19 | using: "composite" 20 | steps: 21 | - name: Configure 22 | shell: ${{inputs.shell}} 23 | run: cmake -B build -DCMAKE_BUILD_TYPE=${{inputs.cmake_build_type}} ${{inputs.cmake_configuration_parameters}} 24 | 25 | - name: Build 26 | shell: ${{inputs.shell}} 27 | run: cmake --build build --config ${{inputs.cmake_build_type}} --verbose ${{inputs.cmake_build_paramters}} --target ${{inputs.target}} 28 | -------------------------------------------------------------------------------- /.github/actions/package/action.yml: -------------------------------------------------------------------------------- 1 | name: Package 2 | description: 'Package a CMake project with CPack support' 3 | 4 | inputs: 5 | generators: 6 | required: true 7 | 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Package 12 | shell: bash 13 | run: cpack --config build/CPackConfig.cmake --verbose -G "${{inputs.generators}}" 14 | 15 | - name: Upload DEB artifact 16 | if: runner.os == 'Linux' 17 | uses: actions/upload-artifact@v4 18 | with: 19 | name: sigutils-linux-deb.zip 20 | path: build/dist/*.deb 21 | 22 | - name: Upload TGZ artifact 23 | if: runner.os == 'Linux' 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: sigutils-linux-tgz.zip 27 | path: build/dist/*.tar.gz 28 | 29 | - name: Upload TGZ artifact 30 | if: runner.os == 'MacOS' 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: sigutils-macos-tgz.zip 34 | path: build/dist/*.tar.gz 35 | 36 | - name: Upload ZIP artifact 37 | if: runner.os == 'Windows' 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: sigutils-windows-zip.zip 41 | path: build/dist/*.zip 42 | -------------------------------------------------------------------------------- /.github/actions/test/action.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | description: 'Test a CMake project with CTest support' 3 | 4 | inputs: 5 | shell: 6 | required: false 7 | default: bash 8 | 9 | runs: 10 | using: "composite" 11 | steps: 12 | - name: Test 13 | shell: ${{inputs.shell}} 14 | run: ctest --test-dir build -VV --rerun-failed --output-on-failure 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | target-branch: "master" 9 | schedule: 10 | interval: "weekly" 11 | - package-ecosystem: "gitsubmodule" 12 | directory: "/" 13 | target-branch: "master" 14 | schedule: 15 | interval: "weekly" 16 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | ci: 2 | - all: 3 | - changed-files: 4 | - any-glob-to-any-file: '.github/**' 5 | 6 | build_system: 7 | - all: 8 | - changed-files: 9 | - any-glob-to-any-file: 10 | - 'CMake*' 11 | - '**/CMakeLists.txt' 12 | - '**/*.cmake' 13 | 14 | sigutils: 15 | - all: 16 | - changed-files: 17 | - any-glob-to-any-file: 'src/**' 18 | - all-globs-to-all-files: '!src/CMakeLists.txt' 19 | 20 | documentation: 21 | - all: 22 | - changed-files: 23 | - any-glob-to-any-file: 'doc/**' 24 | - all-globs-to-all-files: '!doc/CMakeLists.txt' 25 | 26 | tests: 27 | - all: 28 | - changed-files: 29 | - any-glob-to-any-file: 'tests/**' 30 | - all-globs-to-all-files: '!tests/CMakeLists.txt' 31 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | build-linux: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Install dependencies 10 | run: sudo apt-get update && sudo apt-get install libsndfile1-dev libvolk2-dev libfftw3-dev catch2 11 | 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | submodules: true 16 | fetch-depth: 0 17 | 18 | - name: Build 19 | uses: "./.github/actions/build" 20 | with: 21 | target: sigutils 22 | cmake_configuration_parameters: -DCMAKE_INSTALL_PREFIX=/usr 23 | 24 | - name: Build tests 25 | uses: "./.github/actions/build" 26 | with: 27 | target: sigutils_test 28 | 29 | - name: Test 30 | uses: "./.github/actions/test" 31 | 32 | - name: Package 33 | uses: "./.github/actions/package" 34 | with: 35 | generators: TGZ;DEB 36 | 37 | build-macos: 38 | runs-on: macos-latest 39 | steps: 40 | - name: Install dependencies 41 | run: brew install libsndfile volk fftw catch2 42 | 43 | - name: Checkout 44 | uses: actions/checkout@v4 45 | with: 46 | submodules: true 47 | fetch-depth: 0 48 | 49 | - name: Build 50 | uses: "./.github/actions/build" 51 | with: 52 | target: sigutils 53 | 54 | - name: Build tests 55 | uses: "./.github/actions/build" 56 | with: 57 | target: sigutils_test 58 | 59 | - name: Test 60 | uses: "./.github/actions/test" 61 | 62 | - name: Package 63 | uses: "./.github/actions/package" 64 | with: 65 | generators: TGZ 66 | 67 | build-windows: 68 | runs-on: windows-latest 69 | defaults: 70 | run: 71 | shell: msys2 {0} 72 | steps: 73 | - name: Install dependencies 74 | uses: msys2/setup-msys2@v2 75 | with: 76 | msystem: MINGW64 77 | update: true 78 | install: git mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake mingw-w64-x86_64-libsndfile mingw-w64-x86_64-fftw mingw-w64-x86_64-volk mingw-w64-x86_64-catch 79 | 80 | - name: Checkout 81 | uses: actions/checkout@v4 82 | with: 83 | submodules: true 84 | fetch-depth: 0 85 | 86 | - name: Build 87 | uses: "./.github/actions/build" 88 | with: 89 | shell: msys2 {0} 90 | target: sigutils 91 | 92 | - name: Build tests 93 | uses: "./.github/actions/build" 94 | with: 95 | shell: msys2 {0} 96 | target: sigutils_test 97 | 98 | - name: Test 99 | uses: "./.github/actions/test" 100 | with: 101 | shell: msys2 {0} 102 | 103 | - name: Package 104 | uses: "./.github/actions/package" 105 | with: 106 | generators: ZIP 107 | 108 | release: 109 | runs-on: "ubuntu-latest" 110 | needs: 111 | - build-linux 112 | - build-macos 113 | - build-windows 114 | 115 | steps: 116 | - name: Get current date 117 | id: date 118 | run: echo "::set-output name=date::$(date +'%Y-%m-%d')" 119 | 120 | - name: Download binaries 121 | uses: actions/download-artifact@v4 122 | 123 | - name: Release nightly 124 | if: github.ref == 'refs/heads/master' 125 | uses: marvinpinto/action-automatic-releases@v1.2.1 126 | with: 127 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 128 | automatic_release_tag: "latest" 129 | prerelease: true 130 | title: "Sigutils nightly (${{steps.date.outputs.date}})" 131 | files: sigutils*/* 132 | 133 | - name: Release stable 134 | if: contains(github.ref, 'refs/tags/v') 135 | uses: marvinpinto/action-automatic-releases@v1.2.1 136 | with: 137 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 138 | prerelease: false 139 | title: "Sigutils ${{github.ref_name}}" 140 | files: sigutils*/* 141 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | paths: 7 | - src/ 8 | pull_request: 9 | branches: [ "master" ] 10 | paths: 11 | - src/ 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-latest 17 | permissions: 18 | actions: read 19 | contents: read 20 | security-events: write 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | language: [ 'cpp' ] 26 | 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@v4 30 | with: 31 | submodules: true 32 | fetch-depth: 0 33 | 34 | - name: Initialize CodeQL 35 | uses: github/codeql-action/init@v3 36 | with: 37 | languages: ${{ matrix.language }} 38 | 39 | - name: Install dependencies 40 | run: sudo apt-get update && sudo apt-get install libsndfile1-dev libvolk2-dev libfftw3-dev 41 | 42 | - name: Autobuild 43 | uses: github/codeql-action/autobuild@v3 44 | 45 | - name: Perform CodeQL Analysis 46 | uses: github/codeql-action/analyze@v3 47 | with: 48 | category: "/language:${{matrix.language}}" 49 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: [push, pull_request_target, workflow_dispatch] 4 | 5 | permissions: 6 | id-token: write 7 | pages: write 8 | pull-requests: write 9 | 10 | jobs: 11 | build-documentation: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | sudo apt-get update 17 | sudo apt-get install libsndfile1-dev libvolk2-dev libfftw3-dev doxygen python3-pip 18 | sudo pip3 install coverxygen 19 | 20 | - name: Determine checkout ref 21 | uses: haya14busa/action-cond@v1 22 | id: fetch_ref 23 | with: 24 | cond: ${{ github.event_name == 'pull_request_target' }} 25 | if_true: "${{ github.event.pull_request.merge_commit_sha }}" 26 | if_false: "" 27 | 28 | - name: Checkout 29 | uses: actions/checkout@v4 30 | with: 31 | ref: "${{ steps.fetch_ref.outputs.value }}" 32 | fetch-depth: 0 33 | submodules: true 34 | 35 | - name: Build documentation 36 | uses: "./.github/actions/build" 37 | with: 38 | target: doxygen 39 | 40 | - name: Upload documentation artifact 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: documentation 44 | path: build/doc/html/ 45 | 46 | - name: Setup Pages 47 | if: contains(github.ref, 'master') && (github.event_name != 'pull_request_target') 48 | uses: actions/configure-pages@v5 49 | with: 50 | enablement: true 51 | 52 | - name: Upload documentation to Github Pages 53 | if: contains(github.ref, 'master') && (github.event_name != 'pull_request_target') 54 | uses: actions/upload-pages-artifact@v3 55 | with: 56 | path: build/doc/html/ 57 | 58 | - name: Deploy to GitHub Pages 59 | if: contains(github.ref, 'master') && (github.event_name != 'pull_request_target') 60 | uses: actions/deploy-pages@v4 61 | 62 | - name: Documentation coverage 63 | if: github.event_name == 'pull_request_target' 64 | uses: "./.github/actions/build" 65 | with: 66 | target: coverxygen_summary 67 | 68 | - name: Documentation coverage report generation 69 | if: github.event_name == 'pull_request_target' 70 | run: | 71 | EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) 72 | echo "report<<$EOF" >> "$GITHUB_ENV" 73 | cat build/doc/doc-coverage.markdown-summary.info >> "$GITHUB_ENV" 74 | echo "$EOF" >> "$GITHUB_ENV" 75 | 76 | - name: Documentation coverage report 77 | if: github.event_name == 'pull_request_target' 78 | uses: marocchino/sticky-pull-request-comment@v2 79 | with: 80 | recreate: true 81 | message: | 82 | Documentation coverage report 83 | ${{ env.report }} 84 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | triage: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/labeler@v5 13 | with: 14 | sync-labels: true 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cmake/cmake-gitversiondetect"] 2 | path = cmake/cmake-gitversiondetect 3 | url = https://github.com/antoniovazquezblanco/cmake-gitversiondetect.git 4 | [submodule "cmake/cmake-pcfilegenerator"] 5 | path = cmake/cmake-pcfilegenerator 6 | url = https://github.com/antoniovazquezblanco/cmake-pcfilegenerator.git 7 | [submodule "cmake/cmake-relativefilemacro"] 8 | path = cmake/cmake-relativefilemacro 9 | url = https://github.com/antoniovazquezblanco/cmake-relativefilemacro.git 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | - Gonzalo José Carracedo Carballal 2 | Original code base 3 | 4 | - Mehdi Asgari 5 | Complex float API support in C++ 6 | 7 | - Ángel Ruiz Fernández 8 | Windows support 9 | 10 | - Antonio Vázquez Blanco 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt: CMake configuration file for sigutils 3 | # 4 | # Copyright (C) 2019 Gonzalo José Carracedo Carballal 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this program. If not, see 17 | # 18 | # 19 | # 20 | 21 | cmake_minimum_required(VERSION 3.20.0) 22 | 23 | # CMake modules search path 24 | file(GLOB MODULE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*/" LIST_DIRECTORIES true) 25 | list(APPEND CMAKE_MODULE_PATH "${MODULE_DIRS}") 26 | 27 | # Check that all required submodules are there 28 | set( 29 | GIT_CMAKE_SUBMODULES 30 | cmake-gitversiondetect 31 | cmake-pcfilegenerator 32 | cmake-relativefilemacro) 33 | 34 | foreach (submodule IN ITEMS ${GIT_CMAKE_SUBMODULES}) 35 | if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${submodule}/.git") 36 | message( FATAL_ERROR "Required CMake submodule `${submodule}' not found. This \ 37 | is most likely caused by an incomplete clone from the main repository. Please run: 38 | $ git submodule update --init --recursive 39 | to clone all required submodules and run CMake again.") 40 | endif() 41 | endforeach() 42 | 43 | # Use git version detect to obtain a project version based on tags 44 | include(GitVersionDetect) 45 | set(SIGUTILS_VERSION_MAJOR ${GITVERSIONDETECT_VERSION_MAJOR}) 46 | set(SIGUTILS_VERSION_MINOR ${GITVERSIONDETECT_VERSION_MINOR}) 47 | set(SIGUTILS_VERSION_PATCH ${GITVERSIONDETECT_VERSION_PATCH}) 48 | set(SIGUTILS_VERSION ${SIGUTILS_VERSION_MAJOR}.${SIGUTILS_VERSION_MINOR}.${SIGUTILS_VERSION_PATCH}) 49 | 50 | # Define the project 51 | project( 52 | sigutils 53 | VERSION ${SIGUTILS_VERSION} 54 | DESCRIPTION "Small signal processing utility library" 55 | HOMEPAGE_URL "http://github.org/BatchDrake/sigutils" 56 | LANGUAGES C CXX) 57 | 58 | # Always use top level dir for generated targets to avoid linker problems 59 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 60 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 61 | 62 | # The library code is in src 63 | add_subdirectory(src) 64 | 65 | # The documentation is in doc 66 | add_subdirectory(doc) 67 | 68 | # Tests are in the tests dir 69 | include(CTest) 70 | add_subdirectory(tests) 71 | 72 | # uninstall target 73 | if(NOT TARGET uninstall) 74 | configure_file( 75 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 76 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 77 | IMMEDIATE @ONLY) 78 | 79 | add_custom_target(uninstall 80 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 81 | endif() 82 | 83 | # Run ldconfig for certain Unix systems 84 | if(UNIX AND NOT APPLE) 85 | install(CODE "exec_program(ldconfig)") 86 | endif() 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The sigutils library - Getting started 2 | 3 | [![Build](https://github.com/BatchDrake/sigutils/actions/workflows/build.yml/badge.svg)](https://github.com/BatchDrake/sigutils/actions/workflows/build.yml) 4 | 5 | The sigutils library is a digital signal processing library written in C, designed for blind signal analysis and automatic demodulation. 6 | 7 | ## Documentation 8 | 9 | Project documentation and instructions on how to build and install the project can be found at https://batchdrake.github.io/sigutils/. 10 | -------------------------------------------------------------------------------- /cmake/modules/CodeAnalysis.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | CodeAnalysis 6 | ------- 7 | 8 | Add code format target. 9 | 10 | Custom Targets 11 | ^^^^^^^^^^^^^^^^ 12 | 13 | This module provides the following custom target, if found: 14 | 15 | ``cppcheck-analysis`` 16 | The code analysis custom target. 17 | 18 | #]=======================================================================] 19 | 20 | if(TARGET codeanalysis) 21 | return() 22 | endif() 23 | 24 | find_package(CppCheck) 25 | 26 | if(CppCheck_FOUND) 27 | message("Cppcheck analysis already added") 28 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 29 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) 30 | add_custom_target(codeanalysis 31 | COMMAND ${CPPCHECK_COMMAND}) 32 | endif() 33 | -------------------------------------------------------------------------------- /cmake/modules/FindCoverxygen.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-3.0-or-later 2 | # Copyright 2023 Antonio Vázquez Blanco 3 | 4 | # This package uses FindPython3, set min ver acordingly 5 | cmake_minimum_required(VERSION 3.12.0) 6 | 7 | # Check if python is available... 8 | find_package(Python3 COMPONENTS Interpreter) 9 | 10 | if(Python3_Interpreter_FOUND) 11 | # Python found. Try to find the module... 12 | execute_process( 13 | COMMAND ${Python3_EXECUTABLE} -c "import coverxygen" 14 | RESULT_VARIABLE EXIT_CODE 15 | OUTPUT_QUIET 16 | ) 17 | if (${EXIT_CODE} EQUAL 0) 18 | set(Coverxygen_FOUND ON) 19 | set(Coverxygen_COMMAND "${Python3_EXECUTABLE} -m coverxygen") 20 | endif() 21 | endif() 22 | 23 | if (NOT Coverxygen_FOUND) 24 | message("Coverxygen not found") 25 | endif() 26 | 27 | function(coverxygen_add_report targetName srcDir doxygenTarget reportFormat) 28 | get_filename_component(absSrcDir "${srcDir}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 29 | add_custom_target(${targetName} VERBATIM 30 | COMMAND "${Python3_EXECUTABLE}" -m coverxygen --xml-dir "${CMAKE_CURRENT_BINARY_DIR}/xml" --src-dir "${absSrcDir}" --output "${CMAKE_CURRENT_BINARY_DIR}/doc-coverage.${reportFormat}.info" --format ${reportFormat} 31 | DEPENDS ${doxygenTarget} 32 | COMMENT "Generate documentation coverage report in ${reportFormat} for ${targetName}" 33 | ) 34 | endfunction() 35 | -------------------------------------------------------------------------------- /cmake/modules/FindCppCheck.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindCppCheck 6 | ------- 7 | 8 | Finds the CppCheck Tool. 9 | 10 | Custom Targets 11 | ^^^^^^^^^^^^^^^^ 12 | 13 | This module provides the following custom targets, if found: 14 | 15 | ``cppcheck-analysis`` 16 | The CppCheck custom target 17 | 18 | Result Variables 19 | ^^^^^^^^^^^^^^^^ 20 | 21 | This will define the following variables: 22 | 23 | ``CppCheck_FOUND`` 24 | True if the system has the cppcheck tool. 25 | ``CppCheck_VERSION`` 26 | Version of cppcheck tool. 27 | 28 | #]=======================================================================] 29 | 30 | if(CPPCHECK_ROOT_DIR) 31 | find_program(CPPCHECK_BIN 32 | NAMES 33 | cppcheck 34 | PATHS 35 | "${CPPCHECK_ROOT_DIR}" 36 | NO_DEFAULT_PATH) 37 | endif() 38 | 39 | if(NOT CPPCHECK_BIN) 40 | find_program(CPPCHECK_BIN NAMES cppcheck) 41 | endif() 42 | 43 | if(CPPCHECK_BIN) 44 | execute_process( 45 | COMMAND ${CPPCHECK_BIN} --version 46 | OUTPUT_VARIABLE CppCheck_VERSION 47 | ERROR_QUIET 48 | OUTPUT_STRIP_TRAILING_WHITESPACE 49 | ) 50 | 51 | set(CPPCHECK_THREADS_ARG "-j4" 52 | CACHE STRING "The number of threads to use") 53 | set(CPPCHECK_PROJECT_ARG "--project=${PROJECT_BINARY_DIR}/compile_commands.json" 54 | CACHE STRING "The project directory to use") 55 | set(CPPCHECK_BUILD_DIR_ARG "--cppcheck-build-dir=${PROJECT_BINARY_DIR}/analysis/cppcheck" 56 | CACHE STRING "The build directory to use") 57 | 58 | # Don't show these errors 59 | if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck-suppressions") 60 | set(CPPCHECK_SUPPRESSIONS "--suppressions-list=${CMAKE_SOURCE_DIR}/.cppcheck-suppressions" 61 | CACHE STRING "The suppressions file to use") 62 | else() 63 | set(CPPCHECK_SUPPRESSIONS "" 64 | CACHE STRING "The suppressions file to use") 65 | endif() 66 | 67 | # Show these errors but don't fail the build 68 | if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck-exitcode-suppressions") 69 | set(CPPCHECK_EXITCODE_SUPPRESSIONS "--exitcode-suppressions=${CMAKE_SOURCE_DIR}/.cppcheck-exitcode-suppressions" 70 | CACHE STRING "The exitcode suppressions file to use") 71 | else() 72 | set(CPPCHECK_EXITCODE_SUPPRESSIONS "" 73 | CACHE STRING "The exitcode suppressions file to use") 74 | endif() 75 | 76 | set(CPPCHECK_ERROR_EXITCODE_ARG "--error-exitcode=1" 77 | CACHE STRING "The exitcode to use if an error is found") 78 | set(CPPCHECK_CHECKS_ARGS "--enable=warning" 79 | CACHE STRING "Arguments for the checks to run") 80 | set(CPPCHECK_OTHER_ARGS "" 81 | CACHE STRING "Other arguments") 82 | 83 | set(_CPPCHECK_EXCLUDES) 84 | foreach(ex ${CPPCHECK_EXCLUDES}) 85 | list(APPEND _CPPCHECK_EXCLUDES "-i${ex}") 86 | endforeach(ex) 87 | 88 | set(CPPCHECK_ALL_ARGS 89 | ${CPPCHECK_THREADS_ARG} 90 | ${CPPCHECK_PROJECT_ARG} 91 | ${CPPCHECK_BUILD_DIR_ARG} 92 | ${CPPCHECK_ERROR_EXITCODE_ARG} 93 | ${CPPCHECK_SUPPRESSIONS} 94 | ${CPPCHECK_EXITCODE_SUPPRESSIONS} 95 | ${CPPCHECK_CHECKS_ARGS} 96 | ${CPPCHECK_OTHER_ARGS} 97 | ${_CPPCHECK_EXCLUDES} 98 | ) 99 | 100 | if(NOT CPPCHECK_XML_OUTPUT) 101 | set(CPPCHECK_COMMAND 102 | ${CPPCHECK_BIN} 103 | ${CPPCHECK_ALL_ARGS} 104 | ) 105 | else() 106 | set(CPPCHECK_COMMAND 107 | ${CPPCHECK_BIN} 108 | ${CPPCHECK_ALL_ARGS} 109 | --xml 110 | --xml-version=2 111 | 2> ${CPPCHECK_XML_OUTPUT}) 112 | endif() 113 | endif() 114 | 115 | # handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE 116 | include(FindPackageHandleStandardArgs) 117 | find_package_handle_standard_args( 118 | CppCheck 119 | DEFAULT_MSG 120 | CPPCHECK_BIN) 121 | 122 | mark_as_advanced( 123 | CPPCHECK_BIN 124 | CPPCHECK_THREADS_ARG 125 | CPPCHECK_PROJECT_ARG 126 | CPPCHECK_BUILD_DIR_ARG 127 | CPPCHECK_SUPPRESSIONS 128 | CPPCHECK_EXITCODE_SUPPRESSIONS 129 | CPPCHECK_ERROR_EXITCODE_ARG 130 | CPPCHECK_CHECKS_ARGS 131 | CPPCHECK_OTHER_ARGS) 132 | 133 | if(CppCheck_FOUND) 134 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) 135 | add_custom_target(cppcheck-analysis 136 | COMMAND ${CPPCHECK_COMMAND}) 137 | message("CppCheck found. Use cppcheck-analysis targets to run it") 138 | else() 139 | message("CppCheck not found") 140 | endif() 141 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") 3 | endif() 4 | 5 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach(file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if(NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif() 18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif() 21 | endforeach() 22 | -------------------------------------------------------------------------------- /doc/API.md: -------------------------------------------------------------------------------- 1 | \page api API overview 2 | 3 | ## Sigutils type foundation 4 | 5 | All API levels share the following set of data types, used to exchange data in a coherent way: 6 | 7 | `SUFLOAT`: Default real-valued sample type. Currently maps to `double`. 8 | `SUSCOUNT`: Used to enumerate samples. Maps to `unsigned long`. 9 | `SUBOOL`: Boolean type (defined as `int`). Can be either `SU_TRUE` (1) or `SU_FALSE` (0). 10 | `SUCOMPLEX`: Complex type, composed of a real and an imaginary party, mostly used to store I/Q data. Currently defined to `complex SUFLOAT`. 11 | `SUSYMBOL`: Data type used for the decision device output. Special values are: 12 | * `SU_NOSYMBOL`: decision device output queue is currently empty, the symbol reader is faster than the demodulator. 13 | * `SU_EOS`: End of stream, the signal source cannot provide any more samples (this happens when the actual underlying device has been disconnected, or when the end of a recorded signal has been reached). 14 | 15 | Any other value is considered a valid symbol identifier. 16 | 17 | 18 | ## The modem API 19 | 20 | The core of the modem API is the `su_modem_t` object, which can be configured to retrieve discrete symbols from a variety of sources and modulations. Currently, only the QPSK modem, WAV file source and generic block source are implemented. 21 | 22 | 23 | ### Creating a QPSK modem 24 | 25 | Modems are created using the modem constructor `su_modem_new`, which accepts the class name of the specific modem to instantiate: 26 | 27 | ``` 28 | su_modem_t *modem; 29 | 30 | if ((modem = su_modem_new("qpsk")) == NULL) { 31 | fprintf(stderr, "su_modem_new: failed to initialize QPSK modem\n"); 32 | exit(EXIT_FAILURE); 33 | } 34 | ``` 35 | 36 | 37 | ### Configuring the modem 38 | 39 | Once an appropriate modem type has been initialized, it must be configured before reading samples from it. Two actions are required to configure a modem: setting the signal source and setting modem parameters. If the signal source is a WAV file, this can be configured by calling `su_modem_set_wav_source`: 40 | 41 | ``` 42 | if (!su_modem_set_wav_source(modem, "test.wav")) { 43 | fprintf( 44 | stderr, 45 | "su_modem_set_wav_source: failed to set modem wav source to test.wav\n"); 46 | exit(EXIT_FAILURE); 47 | } 48 | ``` 49 | 50 | Alternatively, arbitrary block sources can be specified using `su_modem_set_source`: 51 | 52 | ``` 53 | su_block_t *source_block = /* initialize source */; 54 | 55 | if (!su_modem_set_source(modem, source_block)) { 56 | fprintf( 57 | stderr, 58 | "su_modem_set_source: failed to set modem source\n"); 59 | exit(EXIT_FAILURE); 60 | } 61 | ``` 62 | 63 | Modem parameters are configured through the `su_modem_set_*` methods. Although every modem can accept a different set of parameters, they generally use the same naming convention for equivalent parameters: 64 | 65 | ``` 66 | su_modem_set_bool(modem, "abc", SU_FALSE); /* Automatic baud rate control */ 67 | su_modem_set_bool(modem, "afc", SU_TRUE); /* Automatic frequency control */ 68 | su_modem_set_int(modem, "mf_span", 4); /* Matched filter span (in symbols) */ 69 | su_modem_set_float(modem, "baud", 468); /* Baud rate: 468 baud */ 70 | su_modem_set_float(modem, "fc", 910); /* Carrier frequency: 910 Hz */ 71 | su_modem_set_float(modem, "rolloff", .25); /* Roll-off factor of the matched filter */ 72 | ``` 73 | 74 | Additionally, if the WAV source is being used, the `int` parameter `samp_rate` is automatically initialized, matching the WAV file sample rate. Otherwise, this parameter must be configured manually. 75 | 76 | After both the source and modem parameters have been properly initialized, the modem can be *switched on* by calling `su_modem_start`: 77 | 78 | ``` 79 | if (!su_modem_start(modem)) { 80 | fprintf(stderr, "su_modem_start: failed to start modem\n"); 81 | exit(EXIT_FAILURE); 82 | } 83 | ``` 84 | 85 | This tells the modem to preallocate any parameter-dependent temporary data to start demodulation. Note that this method itself will not start demodulation. Demodulation happens in an *on demand* basis when a symbol read operation is requested. 86 | 87 | 88 | ### Reading symbols 89 | 90 | After starting the modem, symbols can be read by looping over `su_modem_read`: 91 | 92 | ``` 93 | SUSYMBOL sym; 94 | 95 | /* While we don't reach the end of the stream */ 96 | while((sym = su_modem_read(modem)) != SU_EOS) { 97 | if (sym != SU_NOSYMBOL) { 98 | printf("Got symbol: %d\n", sym); 99 | } 100 | } 101 | 102 | ``` 103 | 104 | Symbols are retrieved as an integer value, starting from 1. If the modem considers there is too much noise to make a good decision, it will return `SU_NOSYMBOL`. If the source cannot provide any more samples, `su_modem_read` will return `SU_EOS`. 105 | 106 | 107 | ### Deleting the modem 108 | 109 | Once we are done using the modem object, it must be released using the `su_modem_destroy` method: 110 | 111 | ``` 112 | su_modem_destroy(modem); 113 | ``` 114 | -------------------------------------------------------------------------------- /doc/Building.md: -------------------------------------------------------------------------------- 1 | \page building Building 2 | 3 | **sigutils** has been tested in GNU/Linux (i386, x86_64 and armhf), but it will probably work in many other architectures as well. 4 | 5 | 6 | ## Getting the code 7 | 8 | Just clone it from the GitHub repository. Make sure you pass `--recurse-submodules` to `git clone` so all required submodules are also cloned. 9 | 10 | ```bash 11 | git clone --recurse-submodules https://github.com/BatchDrake/sigutils.git 12 | ``` 13 | 14 | 15 | ## Requirements and dependencies 16 | 17 | The following libraries (along with their respective development files) must also be present: 18 | 19 | * CMake 3.12.0 or higher is required for the build. 20 | * sndfile (1.0.2 or later) 21 | * fftw3 (3.0 or later) 22 | * volk (1.0 or later) (Optional) 23 | 24 | ### Requirements and dependencies in Ubuntu 25 | 26 | ```bash 27 | sudo apt-get install cmake libsndfile1-dev libvolk2-dev libfftw3-dev 28 | ``` 29 | 30 | ### Requirements and dependencies in Archlinux 31 | 32 | ```bash 33 | sudo pacman -S libsndfile libvolk fftw cmake 34 | ``` 35 | 36 | ### Requirements and dependencies in Windows MSYS2 MinGW64 37 | 38 | ```bash 39 | pacman -S mingw-w64-x86_64-cc mingw-w64-x86_64-make mingw-w64-x86_64-cmake mingw-w64-x86_64-libsndfile mingw-w64-x86_64-fftw mingw-w64-x86_64-volk 40 | ``` 41 | 42 | 43 | ## Building and installing sigutils 44 | 45 | ### Configuring the project 46 | 47 | You can configure the project into a `build/` folder by executing the following command. This will check for dependencies automatically. 48 | 49 | ```bash 50 | cmake -B build . 51 | ``` 52 | 53 | You may want to specify extra options. 54 | 55 | 56 | #### Configuring in Windows MSYS2 MinGW64 57 | 58 | In Windows you may want to instruct that you want MSYS makefiles and the mingw PREFIX. 59 | 60 | ```bash 61 | /msys64/mingw64/bin/cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=/msys64/mingw64 62 | ``` 63 | 64 | 65 | ### Building 66 | 67 | If the previous commands were successful, you can start the build by typing: 68 | 69 | ```bash 70 | cmake --build build 71 | ``` 72 | 73 | 74 | ### Installing 75 | 76 | You may want to install the built library in your system: 77 | 78 | ```bash 79 | sudo cmake --build build --target install 80 | ``` 81 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Check for the required dependencies 2 | find_package(Doxygen) 3 | find_package(Coverxygen) 4 | 5 | if (NOT DOXYGEN_FOUND) 6 | message("Doxygen needs to be installed to generate the documentation") 7 | else() 8 | # Select doxygen output formats 9 | set(DOXYGEN_GENERATE_HTML YES) 10 | if(${Coverxygen_FOUND}) 11 | set(DOXYGEN_GENERATE_XML YES) 12 | endif() 13 | 14 | # Other doxy options 15 | set(DOXYGEN_EXTRACT_ALL YES) 16 | set(DOXYGEN_EXTRACT_PRIVATE YES) 17 | set(DOXYGEN_EXTRACT_PACKAGE YES) 18 | set(DOXYGEN_EXTRACT_STATIC YES) 19 | set(DOXYGEN_EXTRACT_LOCAL_CLASSES YES) 20 | set(DOXYGEN_EXTRACT_LOCAL_METHODS YES) 21 | set(DOXYGEN_EXTRACT_ANON_NSPACES YES) 22 | set(DOXYGEN_MACRO_EXPANSION YES) 23 | get_target_property(DOXYGEN_INCLUDE_PATH sigutils INCLUDE_DIRECTORIES) 24 | set(DOXYGEN_SKIP_FUNCTION_MACROS NO) 25 | 26 | # Add a Doxygen target 27 | doxygen_add_docs(doxygen "../src" ".") 28 | endif() 29 | 30 | if (DOXYGEN_FOUND AND NOT Coverxygen_FOUND) 31 | message("Coverxygen needs to be installed to generate the documentation coverage reports") 32 | else() 33 | coverxygen_add_report(coverxygen_summary "../src" doxygen markdown-summary) 34 | endif() 35 | -------------------------------------------------------------------------------- /doc/Index.md: -------------------------------------------------------------------------------- 1 | \mainpage Sigutils documentation 2 | 3 | The sigutils library is a digital signal processing library written in C, designed for blind signal analysis and automatic demodulation. 4 | 5 | You may be able to install sigutils in your operating system using your default package manager. If not, you can build the project form source and install it. For instructions on how to do so, please visit section \ref building. 6 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt: CMake configuration file for sigutils 3 | # 4 | # Copyright (C) 2019 Gonzalo José Carracedo Carballal 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this program. If not, see 17 | # 18 | # 19 | # 20 | 21 | # Set the ABI version manually 22 | set(SIGUTILS_ABI_VERSION 1) 23 | 24 | # Late module imports that depend on project definitions 25 | include(FindPkgConfig) 26 | include(CodeAnalysis) 27 | include(GNUInstallDirs) 28 | include(RelativeFileMacro) 29 | include(PcFileGenerator) 30 | 31 | # Find requirements 32 | find_package(Threads) 33 | 34 | pkg_check_modules(SNDFILE REQUIRED sndfile>=1.0.2) 35 | include_directories(${SNDFILE_INCLUDE_DIRS}) 36 | link_directories(${SNDFILE_LIBRARY_DIRS}) 37 | 38 | pkg_check_modules(FFTW3 REQUIRED fftw3f>=3.0) 39 | include_directories(${FFTW3_INCLUDE_DIRS}) 40 | link_directories(${FFTW3_LIBRARY_DIRS}) 41 | 42 | pkg_check_modules(VOLK volk>=1.0) 43 | if(VOLK_FOUND) 44 | include_directories(${VOLK_INCLUDE_DIRS}) 45 | link_directories(${VOLK_LIBRARY_DIRS}) 46 | endif() 47 | 48 | # Project build options 49 | if(NOT CMAKE_BUILD_TYPE) 50 | set(CMAKE_BUILD_TYPE Debug CACHE STRING 51 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 52 | FORCE) 53 | endif() 54 | if (CMAKE_C_COMPILER_ID STREQUAL "GNU") 55 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffast-math -s") 56 | endif() 57 | 58 | option(SIGUTILS_SINGLE_PRECISSION "Use single precission data types" ON) 59 | 60 | if (DEFINED PKGVERSION) 61 | # If you are building sigutils for your own software distribution, you may want 62 | # to set PKGVERSION to some descriptive string. 63 | add_compile_definitions(SIGUTILS_PKGVERSION="${PKGVERSION}") 64 | endif() 65 | 66 | # Source location 67 | file(GLOB_RECURSE SRCS LIST_DIRECTORIES false *.c) 68 | file(GLOB_RECURSE SRCS_WIN LIST_DIRECTORIES false win32-*.c) 69 | if(NOT WIN32) 70 | list(REMOVE_ITEM SRCS ${SRCS_WIN}) 71 | endif() 72 | 73 | # Define the library target 74 | add_library(sigutils SHARED ${SRCS}) 75 | 76 | # Define relative filename macros 77 | target_add_relative_file_macro(sigutils) 78 | 79 | # Add public include directories 80 | target_include_directories(sigutils PUBLIC include/) 81 | 82 | # Extra compilation definitions 83 | if(SIGUTILS_SINGLE_PRECISSION) 84 | target_compile_definitions(sigutils PUBLIC _SU_SINGLE_PRECISION) 85 | endif() 86 | 87 | if(VOLK_FOUND) 88 | target_compile_definitions(sigutils PUBLIC HAVE_VOLK) 89 | endif() 90 | 91 | # Target properties 92 | set_property(TARGET sigutils PROPERTY VERSION ${SIGUTILS_VERSION}) 93 | set_property(TARGET sigutils PROPERTY SOVERSION ${SIGUTILS_ABI_VERSION}) 94 | 95 | # Target dependencies 96 | target_link_libraries(sigutils ${SNDFILE_LIBRARIES}) 97 | target_link_libraries(sigutils ${FFTW3_LIBRARIES}) 98 | target_link_libraries(sigutils fftw3f_threads) 99 | target_link_libraries(sigutils ${CMAKE_THREAD_LIBS_INIT}) 100 | target_link_libraries(sigutils m) 101 | 102 | if(WIN32) 103 | target_link_libraries(sigutils ws2_32) 104 | endif() 105 | 106 | if(VOLK_FOUND) 107 | target_link_libraries(sigutils ${VOLK_LIBRARIES}) 108 | endif() 109 | 110 | # PC file generation 111 | target_pc_file_generate(sigutils "Digital signal processing utility library") 112 | 113 | # File install 114 | install(TARGETS sigutils LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT LIB) 115 | install(DIRECTORY include/sigutils DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT DEVEL) 116 | install(FILES ${PROJECT_BINARY_DIR}/src/sigutils.pc DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR} COMPONENT DEVEL) 117 | 118 | # General packaging settings 119 | set(CPACK_PACKAGE_NAME sigutils) 120 | set(CPACK_PACKAGE_DIRECTORY ${PROJECT_BINARY_DIR}/dist) 121 | 122 | # DEB packaging settings 123 | set(CPACK_DEB_COMPONENT_INSTALL ON) 124 | if(GITVERSIONDETECT_VERSION_COMMIT_NUM) 125 | set(CPACK_DEBIAN_PACKAGE_VERSION ${GITVERSIONDETECT_VERSION}) 126 | endif() 127 | set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) 128 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "arf20 ") 129 | set(CPACK_DEBIAN_LIB_PACKAGE_DEPENDS "libsndfile1 (>= 1.0.31-2build1), libvolk2.5 (>= 2.5.1-1), libfftw3-single3 (>= 3.3.8-2)") 130 | set(CPACK_DEBIAN_DEVEL_PACKAGE_DEPENDS "libsndfile1-dev (>= 1.0.31-2build1), libvolk2-dev (>= 2.5.1-1), libfftw3-dev (>= 3.3.8-2)") 131 | set(CPACK_DEBIAN_LIB_PACKAGE_NAME "libsigutils") 132 | set(CPACK_DEBIAN_DEVEL_PACKAGE_NAME "libsigutils-dev") 133 | set(CPACK_DEBIAN_LIB_PACKAGE_SECTION "libs") 134 | set(CPACK_DEBIAN_DEVEL_PACKAGE_SECTION "libdevel") 135 | 136 | # Include CPack 137 | include(CPack) 138 | 139 | # CPack component information 140 | cpack_add_component(LIB DISPLAY_NAME "Runtime library") 141 | cpack_add_component(DEVEL DISPLAY_NAME "Development files" DEPENDS LIB) 142 | -------------------------------------------------------------------------------- /src/include/sigutils/agc.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_AGC_H 21 | #define _SIGUTILS_AGC_H 22 | 23 | #include "defs.h" 24 | #include "types.h" 25 | 26 | #ifdef __cplusplus 27 | # ifdef __clang__ 28 | # pragma clang diagnostic push 29 | # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" 30 | # endif // __clang__ 31 | extern "C" { 32 | #endif /* __cplusplus */ 33 | 34 | /* 35 | * This Hang AGC implementation is essentially inspired in GQRX's 36 | */ 37 | 38 | #define SU_AGC_RESCALE 0.7 39 | 40 | struct sigutils_agc { 41 | SUBOOL enabled; 42 | 43 | /* AGC parameters */ 44 | SUFLOAT knee; /* AGC Knee in dBs */ 45 | SUFLOAT gain_slope; /* Gain slope in dBs (0..10) */ 46 | SUFLOAT fixed_gain; /* Gain below knee */ 47 | unsigned int hang_max; /* Hang time in number of samples */ 48 | unsigned int hang_n; /* Hang timer */ 49 | 50 | /* AGC memory - delay line */ 51 | SUCOMPLEX *delay_line; 52 | unsigned int delay_line_size; 53 | unsigned int delay_line_ptr; 54 | 55 | /* AGC memory - signal magnitude history */ 56 | SUFLOAT *mag_history; 57 | unsigned int mag_history_size; 58 | unsigned int mag_history_ptr; 59 | 60 | SUFLOAT peak; /* Current peak value in history */ 61 | 62 | /* Used to correct transitional spikes */ 63 | SUFLOAT fast_alpha_rise; 64 | SUFLOAT fast_alpha_fall; 65 | SUFLOAT fast_level; 66 | 67 | /* Used to correct a steady signal */ 68 | SUFLOAT slow_alpha_rise; 69 | SUFLOAT slow_alpha_fall; 70 | SUFLOAT slow_level; 71 | }; 72 | 73 | typedef struct sigutils_agc su_agc_t; 74 | 75 | #define su_agc_INITIALIZER \ 76 | { \ 77 | 0, 0., 0., 0., 0, 0, NULL, 0, 0, NULL, 0, 0, 0., 0., 0., 0., 0., 0., 0. \ 78 | } 79 | 80 | struct su_agc_params { 81 | SUFLOAT threshold; 82 | SUFLOAT slope_factor; 83 | unsigned int hang_max; 84 | unsigned int delay_line_size; 85 | unsigned int mag_history_size; 86 | 87 | /* Time constants (in samples) for transient spikes */ 88 | SUFLOAT fast_rise_t; 89 | SUFLOAT fast_fall_t; 90 | 91 | /* Time constants (in samples) for steady signals */ 92 | SUFLOAT slow_rise_t; 93 | SUFLOAT slow_fall_t; 94 | }; 95 | 96 | #define su_agc_params_INITIALIZER \ 97 | { \ 98 | -100, 6, 100, 20, 20, 2, 4, 20, 40 \ 99 | } 100 | 101 | SU_CONSTRUCTOR(su_agc, const struct su_agc_params *params); 102 | SU_DESTRUCTOR(su_agc); 103 | 104 | SU_METHOD(su_agc, SUCOMPLEX, feed, SUCOMPLEX x); 105 | 106 | #ifdef __cplusplus 107 | # ifdef __clang__ 108 | # pragma clang diagnostic pop 109 | # endif // __clang__ 110 | } 111 | #endif /* __cplusplus */ 112 | 113 | #endif /* _SIGUTILS_AGC_H */ 114 | -------------------------------------------------------------------------------- /src/include/sigutils/block.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_BLOCK_H 21 | #define _SIGUTILS_BLOCK_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif /* __cplusplus */ 35 | 36 | #define SU_BLOCK_STREAM_BUFFER_SIZE 4096 37 | 38 | #define SU_BLOCK_PORT_READ_END_OF_STREAM 0 39 | #define SU_BLOCK_PORT_READ_ERROR_NOT_INITIALIZED -1 40 | #define SU_BLOCK_PORT_READ_ERROR_ACQUIRE -2 41 | #define SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC -3 42 | 43 | #define SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED 0 44 | #define SU_FLOW_CONTROLLER_DESYNC -1 45 | #define SU_FLOW_CONTROLLER_END_OF_STREAM -2 46 | #define SU_FLOW_CONTROLLER_INTERNAL_ERROR -3 47 | 48 | typedef uint64_t su_off_t; 49 | 50 | struct sigutils_stream { 51 | SUCOMPLEX *buffer; 52 | unsigned int size; /* Stream size */ 53 | unsigned int ptr; /* Buffer pointer */ 54 | unsigned int avail; /* Samples available for reading */ 55 | 56 | su_off_t pos; /* Stream position */ 57 | }; 58 | 59 | typedef struct sigutils_stream su_stream_t; 60 | 61 | #define su_stream_INITIALIZER \ 62 | { \ 63 | NULL, /* buffer */ \ 64 | 0, /* size */ \ 65 | 0, /* ptr */ \ 66 | 0, /* avail */ \ 67 | 0 /* post */ \ 68 | } 69 | 70 | /* su_stream operations */ 71 | SU_CONSTRUCTOR(su_stream, SUSCOUNT size); 72 | SU_DESTRUCTOR(su_stream); 73 | 74 | SU_METHOD(su_stream, void, write, const SUCOMPLEX *data, SUSCOUNT size); 75 | SU_METHOD(su_stream, SUSCOUNT, advance_contiguous, SUSCOUNT size); 76 | SU_GETTER( 77 | su_stream, 78 | SUSCOUNT, 79 | get_contiguous, 80 | SUCOMPLEX **start, 81 | SUSCOUNT size); 82 | SU_GETTER(su_stream, su_off_t, tell); 83 | SU_GETTER( 84 | su_stream, 85 | SUSDIFF, 86 | read, 87 | su_off_t off, 88 | SUCOMPLEX *data, 89 | SUSCOUNT size); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif /* __cplusplus */ 94 | 95 | #endif /* _SIGUTILS_BLOCK_H */ 96 | -------------------------------------------------------------------------------- /src/include/sigutils/coef.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_COEF_H 21 | #define _SIGUTILS_COEF_H 22 | 23 | #include 24 | 25 | SUFLOAT *su_dcof_bwlp(int n, SUFLOAT fcf); 26 | SUFLOAT *su_dcof_bwhp(int n, SUFLOAT fcf); 27 | SUFLOAT *su_dcof_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f); 28 | SUFLOAT *su_dcof_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f); 29 | 30 | SUFLOAT *su_ccof_bwlp(int n); 31 | SUFLOAT *su_ccof_bwhp(int n); 32 | SUFLOAT *su_ccof_bwbp(int n); 33 | SUFLOAT *su_ccof_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f); 34 | 35 | SUFLOAT su_sf_bwlp(int n, SUFLOAT fcf); 36 | SUFLOAT su_sf_bwhp(int n, SUFLOAT fcf); 37 | SUFLOAT su_sf_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f); 38 | SUFLOAT su_sf_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f); 39 | 40 | #endif /* _SIGUTILS_COEF_H */ 41 | -------------------------------------------------------------------------------- /src/include/sigutils/dc_corrector.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2023 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_DC_CORRECTOR_H 21 | #define _SIGUTILS_DC_CORRECTOR_H 22 | 23 | #include "defs.h" 24 | #include "types.h" 25 | 26 | 27 | struct sigutils_dc_corrector { 28 | SUSCOUNT soft_dc_train_samples; 29 | SUSCOUNT soft_dc_count; 30 | SUBOOL training; 31 | SUBOOL have_dc_offset; 32 | SUFLOAT soft_dc_alpha; 33 | SUCOMPLEX dc_offset; 34 | SUCOMPLEX dc_c; 35 | }; 36 | 37 | typedef struct sigutils_dc_corrector su_dc_corrector_t; 38 | 39 | #define su_sigutils_dc_corrector_INITIALIZER \ 40 | { \ 41 | 0, 0, SU_FALSE, 0., 0., 0. \ 42 | } 43 | 44 | SU_METHOD(su_dc_corrector, SUBOOL, init_with_training_period, SUSCOUNT); 45 | SU_METHOD(su_dc_corrector, SUBOOL, init_with_alpha, SUFLOAT); 46 | 47 | SU_METHOD(su_dc_corrector, void, set_training_state, SUBOOL); 48 | SU_METHOD(su_dc_corrector, void, reset); 49 | SU_METHOD(su_dc_corrector, void, correct, SUCOMPLEX *buffer, SUSCOUNT size); 50 | 51 | #endif /* _SIGUTILS_DC_CORRECTOR_H */ 52 | -------------------------------------------------------------------------------- /src/include/sigutils/decider.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2017 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _DECIDER_H 21 | #define _DECIDER_H 22 | 23 | #include 24 | #include 25 | 26 | struct sigutils_decider_params { 27 | SUFLOAT min_val; 28 | SUFLOAT max_val; 29 | unsigned int bits; 30 | }; 31 | 32 | #define sigutils_decider_params_INITIALIZER \ 33 | { \ 34 | -PI, /* min_val */ \ 35 | PI, /* max_val */ \ 36 | 1, /* bits */ \ 37 | } 38 | 39 | struct sigutils_decider { 40 | struct sigutils_decider_params params; 41 | SUFLOAT width; 42 | SUFLOAT h_inv; /* 2 ^ bits / width */ 43 | SUBITS mask; 44 | }; 45 | 46 | typedef struct sigutils_decider su_decider_t; 47 | 48 | SU_GETTER(su_decider, const struct sigutils_decider_params *, get_params); 49 | 50 | const struct sigutils_decider_params * 51 | su_decider_get_params(const su_decider_t *self) 52 | { 53 | return &self->params; 54 | } 55 | 56 | SUBOOL 57 | su_decider_init( 58 | su_decider_t *decider, 59 | const struct sigutils_decider_params *params) 60 | { 61 | if (params->bits > 8) 62 | return SU_FALSE; 63 | 64 | if (params->min_val >= params->max_val) 65 | return SU_FALSE; 66 | 67 | decider->params = *params; 68 | decider->width = params->max_val - params->min_val; 69 | decider->mask = (1 << params->bits) - 1; 70 | decider->h_inv = (1 << params->bits) / decider->width; 71 | 72 | return SU_TRUE; 73 | } 74 | 75 | SUINLINE SUBITS 76 | su_decider_decide(const su_decider_t *decider, SUFLOAT x) 77 | { 78 | x -= decider->params.min_val; 79 | 80 | if (x < 0) 81 | return 0; 82 | else if (x >= decider->width) 83 | return decider->mask; 84 | else 85 | return (SUBITS)SU_FLOOR(x * decider->h_inv); 86 | } 87 | 88 | SUINLINE SUBITS 89 | su_decider_decide_cyclic(const su_decider_t *decider, SUFLOAT x) 90 | { 91 | x -= decider->params.min_val; 92 | 93 | return decider->mask & (SUBITS)SU_FLOOR(x * decider->h_inv); 94 | } 95 | 96 | #endif /* _DECIDER_H */ 97 | -------------------------------------------------------------------------------- /src/include/sigutils/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2021 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_DEFS_H 21 | #define _SIGUTILS_DEFS_H 22 | 23 | #include 24 | 25 | #ifndef su_calloc 26 | # define su_calloc(len, size) calloc(len, size) 27 | #endif /* su_calloc */ 28 | 29 | #ifndef su_free 30 | # define su_free(ptr) free(ptr) 31 | #endif /* su_free */ 32 | 33 | #ifndef su_malloc 34 | # define su_malloc(size) malloc(size) 35 | #endif /* su_malloc */ 36 | 37 | #define SU_TYPENAME(class) JOIN(class, _t) 38 | #define SU_METHOD_NAME(class, name) JOIN(class, JOIN(_, name)) 39 | #define SU_METHOD(class, ret, name, ...) \ 40 | ret SU_METHOD_NAME(class, name)(SU_TYPENAME(class) * self, ##__VA_ARGS__) 41 | 42 | #define SU_METHOD_CONST(class, ret, name, ...) \ 43 | ret SU_METHOD_NAME(class, name)( \ 44 | const SU_TYPENAME(class) * self, \ 45 | ##__VA_ARGS__) 46 | 47 | #define SU_GETTER SU_METHOD_CONST 48 | 49 | #define SU_CONSTRUCTOR_TYPED(ret, class, ...) \ 50 | ret SU_METHOD_NAME(class, init)(SU_TYPENAME(class) * self, ##__VA_ARGS__) 51 | 52 | #define SU_CONSTRUCTOR(class, ...) \ 53 | SU_CONSTRUCTOR_TYPED(SUBOOL, class, ##__VA_ARGS__) 54 | 55 | #define SU_DESTRUCTOR(class) \ 56 | void SU_METHOD_NAME(class, finalize)(SU_TYPENAME(class) * self) 57 | 58 | #define SU_INSTANCER(class, ...) \ 59 | SU_TYPENAME(class) * SU_METHOD_NAME(class, new)(__VA_ARGS__) 60 | 61 | #define SU_COPY_INSTANCER(class, ...) \ 62 | SU_METHOD_CONST(class, SU_TYPENAME(class) *, dup, ##__VA_ARGS__) 63 | 64 | #define SU_COLLECTOR(class) \ 65 | void SU_METHOD_NAME(class, destroy)(SU_TYPENAME(class) * self) 66 | 67 | #define SU_ALLOCATE_MANY_CATCH(dest, len, type, action) \ 68 | if ((dest = su_calloc(len, sizeof(type))) == NULL) { \ 69 | SU_ERROR( \ 70 | "failed to allocate %d objects of type \"%s\"\n", \ 71 | len, \ 72 | STRINGIFY(type)); \ 73 | action; \ 74 | } 75 | 76 | #define SU_ALLOCATE_CATCH(dest, type, action) \ 77 | if ((dest = su_calloc(1, sizeof(type))) == NULL) { \ 78 | SU_ERROR( \ 79 | "failed to allocate one object of type \"%s\"\n", \ 80 | STRINGIFY(type)); \ 81 | action; \ 82 | } 83 | 84 | #define SU_MAKE_CATCH(dest, class, action, ...) \ 85 | if ((dest = JOIN(class, _new)(__VA_ARGS__)) == NULL) { \ 86 | SU_ERROR("failed to create instance of class \"%s\"\n", STRINGIFY(class)); \ 87 | action; \ 88 | } 89 | 90 | #define SU_CONSTRUCT_CATCH(class, dest, action, arg...) \ 91 | if (!JOIN(class, _init)(dest, ##arg)) { \ 92 | SU_ERROR( \ 93 | "failed to call constructor of class \"%s\"\n", \ 94 | STRINGIFY(class)); \ 95 | action; \ 96 | } 97 | 98 | #define SU_DESTRUCT(class, dest) JOIN(class, _finalize)(dest) 99 | #define SU_DISPOSE(class, dest) JOIN(class, _destroy)(dest) 100 | 101 | /* __REL_FILE__ is provided byt the build system, use it. 102 | Otherwise, set the variable to an empty string as we 103 | don't want to leak full paths into the binary. 104 | */ 105 | #ifndef __REL_FILE__ 106 | # define __REL_FILE__ "" 107 | #endif /* __REL_FILE__ */ 108 | 109 | #define SU_TRYCATCH(expr, action) \ 110 | if (!(expr)) { \ 111 | SU_ERROR( \ 112 | "exception in \"%s\" (%s:%d)\n", \ 113 | STRINGIFY(expr), \ 114 | __REL_FILE__, \ 115 | __LINE__); \ 116 | action; \ 117 | } 118 | 119 | /* Macros for "goto done" style error recovery */ 120 | #define SU_TRY(expr) SU_TRYCATCH(expr, goto done) 121 | #define SU_TRYC(expr) SU_TRY((expr) != -1) 122 | #define SU_TRYZ(expr) SU_TRY((expr) == 0) 123 | 124 | #define SU_ALLOCATE_MANY(dest, len, type) \ 125 | SU_ALLOCATE_MANY_CATCH(dest, len, type, goto done) 126 | 127 | #define SU_ALLOCATE(dest, type) SU_ALLOCATE_CATCH(dest, type, goto done) 128 | 129 | #define SU_MAKE(dest, class, ...) \ 130 | SU_MAKE_CATCH(dest, class, goto done, __VA_ARGS__) 131 | 132 | #define SU_CONSTRUCT(class, dest, arg...) \ 133 | SU_CONSTRUCT_CATCH(class, dest, goto done, ##arg) 134 | 135 | /* Macros for "goto fail" style error recovery */ 136 | #define SU_TRY_FAIL(expr) SU_TRYCATCH(expr, goto fail) 137 | #define SU_TRYC_FAIL(expr) SU_TRY_FAIL((expr) != -1) 138 | #define SU_TRYZ_FAIL(expr) SU_TRY_FAIL((expr) == 0) 139 | 140 | #define SU_ALLOCATE_MANY_FAIL(dest, len, type) \ 141 | SU_ALLOCATE_MANY_CATCH(dest, len, type, goto fail) 142 | 143 | #define SU_ALLOCATE_FAIL(dest, type) SU_ALLOCATE_CATCH(dest, type, goto fail) 144 | 145 | #define SU_MAKE_FAIL(dest, class, ...) \ 146 | SU_MAKE_CATCH(dest, class, goto fail, __VA_ARGS__) 147 | 148 | #define SU_CONSTRUCT_FAIL(class, dest, arg...) \ 149 | SU_CONSTRUCT_CATCH(class, dest, goto fail, ##arg) 150 | 151 | #endif /* _SIGUTILS_DEFS_H */ 152 | -------------------------------------------------------------------------------- /src/include/sigutils/equalizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_EQUALIZER_H 21 | #define _SIGUTILS_EQUALIZER_H 22 | 23 | #include 24 | 25 | enum sigutils_equalizer_algorithm { 26 | SU_EQUALIZER_ALGORITHM_CMA, /* Default */ 27 | }; 28 | 29 | struct sigutils_equalizer_params { 30 | enum sigutils_equalizer_algorithm algorithm; 31 | SUSCOUNT length; 32 | SUFLOAT mu; 33 | }; 34 | 35 | #define sigutils_equalizer_params_INITIALIZER \ 36 | { \ 37 | SU_EQUALIZER_ALGORITHM_CMA, /* algorithm */ \ 38 | 10, /* length */ \ 39 | 0.2, /* mu */ \ 40 | } 41 | 42 | /* 43 | * A signal equalizer is basically an adaptive filter, so we can leverage 44 | * the existing su_iir_filt API 45 | */ 46 | 47 | struct sigutils_equalizer { 48 | struct sigutils_equalizer_params params; 49 | SUCOMPLEX *w; 50 | SUCOMPLEX *x; 51 | SUSCOUNT ptr; 52 | }; 53 | 54 | typedef struct sigutils_equalizer su_equalizer_t; 55 | 56 | #define su_equalizer_INITIALIZER \ 57 | { \ 58 | sigutils_equalizer_params_INITIALIZER, /* params */ \ 59 | NULL, /* w */ \ 60 | NULL, /* x */ \ 61 | 0, /* ptr */ \ 62 | } 63 | 64 | SUBOOL su_equalizer_init( 65 | su_equalizer_t *eq, 66 | const struct sigutils_equalizer_params *params); 67 | 68 | void su_equalizer_reset(su_equalizer_t *eq); 69 | 70 | SUCOMPLEX su_equalizer_feed(su_equalizer_t *eq, SUCOMPLEX x); 71 | 72 | void su_equalizer_finalize(su_equalizer_t *eq); 73 | 74 | #endif /* _SIGUTILS_EQUALIZER_H */ 75 | -------------------------------------------------------------------------------- /src/include/sigutils/iir.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_IIR_H 21 | #define _SIGUTILS_IIR_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | #define SU_FLOAT_GUARD INFINITY 28 | 29 | #ifdef __cplusplus 30 | # ifdef __clang__ 31 | # pragma clang diagnostic push 32 | # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" 33 | # endif // __clang__ 34 | extern "C" { 35 | #endif /* __cplusplus */ 36 | 37 | /* TODO: Builtin filters */ 38 | struct sigutils_iir_filt { 39 | unsigned int x_size; 40 | unsigned int y_size; 41 | 42 | unsigned int x_alloc; 43 | unsigned int y_alloc; 44 | 45 | int x_ptr; 46 | int y_ptr; 47 | 48 | SUCOMPLEX curr_y; 49 | 50 | SUCOMPLEX *y; 51 | SUCOMPLEX *x; 52 | 53 | SUFLOAT *a; 54 | SUFLOAT *b; 55 | 56 | SUFLOAT gain; 57 | }; 58 | 59 | typedef struct sigutils_iir_filt su_iir_filt_t; 60 | 61 | #define su_iir_filt_INITIALIZER \ 62 | { \ 63 | 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 1 \ 64 | } 65 | 66 | /* Push sample to filter */ 67 | SUCOMPLEX su_iir_filt_feed(su_iir_filt_t *filt, SUCOMPLEX x); 68 | 69 | /* Push a bunch of samples to filter */ 70 | void su_iir_filt_feed_bulk( 71 | su_iir_filt_t *filt, 72 | const SUCOMPLEX *__restrict x, 73 | SUCOMPLEX *__restrict y, 74 | SUSCOUNT len); 75 | 76 | /* Get last output */ 77 | SUCOMPLEX su_iir_filt_get(const su_iir_filt_t *filt); 78 | 79 | void su_iir_filt_reset(su_iir_filt_t *filt); 80 | 81 | /* Initialize filter */ 82 | SUBOOL su_iir_filt_init( 83 | su_iir_filt_t *filt, 84 | SUSCOUNT y_size, 85 | const SUFLOAT *__restrict a, 86 | SUSCOUNT x_size, 87 | const SUFLOAT *__restrict b); 88 | 89 | /* Initialize filter (internal) */ 90 | SUBOOL __su_iir_filt_init( 91 | su_iir_filt_t *filt, 92 | SUSCOUNT y_size, 93 | SUFLOAT *__restrict a, 94 | SUSCOUNT x_size, 95 | SUFLOAT *__restrict b, 96 | SUBOOL copy_coef); 97 | 98 | /* Set output gain */ 99 | void su_iir_filt_set_gain(su_iir_filt_t *filt, SUFLOAT gain); 100 | 101 | /* Initialize Butterworth low-pass filter of order N */ 102 | SUBOOL su_iir_bwlpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); 103 | 104 | /* Initialize Butterworth band-pass filter of order N */ 105 | SUBOOL 106 | su_iir_bwbpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT f1, SUFLOAT f2); 107 | 108 | /* Initialize Butterworh high-pass filter of order N */ 109 | SUBOOL su_iir_bwhpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); 110 | 111 | /* Initialize Root Raised Cosine filter */ 112 | SUBOOL 113 | su_iir_rrc_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT T, SUFLOAT beta); 114 | 115 | /* Initialize Hilbert transform */ 116 | SUBOOL su_iir_hilbert_init(su_iir_filt_t *filt, SUSCOUNT n); 117 | 118 | /* Initialize brickwall LPF filter */ 119 | SUBOOL su_iir_brickwall_lp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); 120 | 121 | /* Initialize brickwall BPF filter */ 122 | SUBOOL su_iir_brickwall_bp_init( 123 | su_iir_filt_t *filt, 124 | SUSCOUNT n, 125 | SUFLOAT bw, 126 | SUFLOAT ifnor); 127 | 128 | /* Destroy filter */ 129 | void su_iir_filt_finalize(su_iir_filt_t *filt); 130 | 131 | #ifdef __cplusplus 132 | # ifdef __clang__ 133 | # pragma clang diagnostic pop 134 | # endif // __clang__ 135 | } 136 | #endif /* __cplusplus */ 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /src/include/sigutils/lfsr.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_LFSR_H 21 | #define _SIGUTILS_LFSR_H 22 | 23 | #include 24 | 25 | enum su_lfsr_mode { 26 | SU_LFSR_MODE_ADDITIVE, 27 | SU_LFSR_MODE_MULTIPLICATIVE 28 | }; 29 | 30 | struct sigutils_lfsr { 31 | SUBITS *coef; /* LFSR coefficients */ 32 | SUBITS *buffer; /* State buffer */ 33 | SUSCOUNT order; /* Polynomial degree */ 34 | enum su_lfsr_mode mode; /* LFSR mode */ 35 | 36 | SUBITS F_prev; 37 | SUSCOUNT zeroes; 38 | SUSCOUNT p; /* Buffer pointer */ 39 | }; 40 | 41 | typedef struct sigutils_lfsr su_lfsr_t; 42 | 43 | #define su_lfsr_INITIALIZER \ 44 | { \ 45 | NULL, NULL, 0 \ 46 | } 47 | 48 | SUBOOL su_lfsr_init_coef(su_lfsr_t *lfsr, const SUBITS *coef, SUSCOUNT order); 49 | void su_lfsr_finalize(su_lfsr_t *lfsr); 50 | void su_lfsr_set_mode(su_lfsr_t *lfsr, enum su_lfsr_mode mode); 51 | 52 | void su_lfsr_set_buffer(su_lfsr_t *lfsr, const SUBITS *seq); 53 | SUBITS su_lfsr_feed(su_lfsr_t *lfsr, SUBITS input); 54 | 55 | /* 56 | * Auto-syncing mode: look for a sequence that once multiplitcatively 57 | * descrambled produces `order' zeroes, and switch to additive 58 | * scrambling right after that 59 | */ 60 | void su_lfsr_blind_sync_reset(su_lfsr_t *lfsr); 61 | SUBITS su_lfsr_blind_sync_feed(su_lfsr_t *lfsr, SUBITS input); 62 | 63 | #endif /* _SIGUTILS_LFSR_H */ 64 | -------------------------------------------------------------------------------- /src/include/sigutils/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2017 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_LOG_H 21 | #define _SIGUTILS_LOG_H 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif /* __cplusplus */ 32 | 33 | enum sigutils_log_severity { 34 | SU_LOG_SEVERITY_DEBUG, 35 | SU_LOG_SEVERITY_INFO, 36 | SU_LOG_SEVERITY_WARNING, 37 | SU_LOG_SEVERITY_ERROR, 38 | SU_LOG_SEVERITY_CRITICAL 39 | }; 40 | 41 | struct sigutils_log_message { 42 | enum sigutils_log_severity severity; 43 | struct timeval time; 44 | const char *domain; 45 | const char *function; 46 | unsigned int line; 47 | const char *message; 48 | }; 49 | 50 | #define sigutils_log_message_INITIALIZER \ 51 | { \ 52 | SU_LOG_SEVERITY_DEBUG, /* severity */ \ 53 | {0, 0}, /* time */ \ 54 | NULL, /* domain */ \ 55 | NULL, /* function */ \ 56 | 0, /* line */ \ 57 | NULL, /* message */ \ 58 | } 59 | 60 | struct sigutils_log_config { 61 | void *priv; 62 | SUBOOL exclusive; 63 | void (*log_func)(void *priv, const struct sigutils_log_message *msg); 64 | }; 65 | 66 | #define sigutils_log_config_INITIALIZER \ 67 | { \ 68 | NULL, /* private */ \ 69 | SU_TRUE, /* exclusive */ \ 70 | NULL, /* log_func */ \ 71 | } 72 | 73 | #ifndef SU_LOG_DOMAIN 74 | # define SU_LOG_DOMAIN __REL_FILE__ 75 | #endif /* SU_LOG_DOMAIN */ 76 | 77 | #define SU_ERROR(fmt, arg...) \ 78 | su_logprintf( \ 79 | SU_LOG_SEVERITY_ERROR, \ 80 | SU_LOG_DOMAIN, \ 81 | __FUNCTION__, \ 82 | __LINE__, \ 83 | fmt, \ 84 | ##arg) 85 | 86 | #define SU_WARNING(fmt, arg...) \ 87 | su_logprintf( \ 88 | SU_LOG_SEVERITY_WARNING, \ 89 | SU_LOG_DOMAIN, \ 90 | __FUNCTION__, \ 91 | __LINE__, \ 92 | fmt, \ 93 | ##arg) 94 | 95 | #define SU_INFO(fmt, arg...) \ 96 | su_logprintf( \ 97 | SU_LOG_SEVERITY_INFO, \ 98 | SU_LOG_DOMAIN, \ 99 | __FUNCTION__, \ 100 | __LINE__, \ 101 | fmt, \ 102 | ##arg) 103 | 104 | void su_log_mask_severity(enum sigutils_log_severity sev); 105 | 106 | void su_log_unmask_severity(enum sigutils_log_severity sev); 107 | 108 | uint32_t su_log_get_mask(void); 109 | 110 | void su_log_set_mask(uint32_t mask); 111 | 112 | const char *su_log_severity_to_string(enum sigutils_log_severity sev); 113 | 114 | SUBOOL su_log_is_masked(enum sigutils_log_severity sev); 115 | 116 | void sigutils_log_message_destroy(struct sigutils_log_message *msg); 117 | 118 | struct sigutils_log_message *sigutils_log_message_dup( 119 | const struct sigutils_log_message *msg); 120 | 121 | void su_log( 122 | enum sigutils_log_severity sev, 123 | const char *domain, 124 | const char *method, 125 | unsigned int line, 126 | const char *message); 127 | 128 | void su_logvprintf( 129 | enum sigutils_log_severity sev, 130 | const char *domain, 131 | const char *method, 132 | unsigned int line, 133 | const char *msgfmt, 134 | va_list ap); 135 | 136 | void su_logprintf( 137 | enum sigutils_log_severity sev, 138 | const char *domain, 139 | const char *method, 140 | unsigned int line, 141 | const char *msgfmt, 142 | ...); 143 | 144 | void su_log_init(const struct sigutils_log_config *config); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif /* __cplusplus */ 149 | 150 | #endif /* _SIGUTILS_LOG_H */ 151 | -------------------------------------------------------------------------------- /src/include/sigutils/matfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2020 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_MATFILE_H 21 | #define _SIGUTILS_MATFILE_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | struct sigutils_mat_matrix { 32 | char *name; 33 | int cols; 34 | int rows; 35 | 36 | int cols_alloc; 37 | int rows_alloc; 38 | 39 | int col_ptr; /* Keep col pointer in order to populate matrix */ 40 | 41 | int col_start; /* All columns before this one were dumped */ 42 | SUFLOAT **coef; 43 | }; 44 | 45 | typedef struct sigutils_mat_matrix su_mat_matrix_t; 46 | 47 | SUINLINE SUFLOAT 48 | su_mat_matrix_get(const su_mat_matrix_t *self, int row, int col) 49 | { 50 | if (row < 0 || row >= self->rows || col < 0 51 | || col >= (self->cols + self->col_start)) 52 | return 0; 53 | 54 | if (self->coef[col] == NULL) 55 | return 0; 56 | 57 | return self->coef[col][row]; 58 | } 59 | 60 | su_mat_matrix_t *su_mat_matrix_new(const char *name, int rows, int cols); 61 | 62 | SUBOOL su_mat_matrix_write_col_va(su_mat_matrix_t *, va_list); 63 | SUBOOL su_mat_matrix_write_col(su_mat_matrix_t *, ...); 64 | SUBOOL su_mat_matrix_write_col_array(su_mat_matrix_t *, const SUFLOAT *); 65 | SUBOOL su_mat_matrix_set_col_ptr(su_mat_matrix_t *, int); 66 | SUBOOL su_mat_matrix_resize(su_mat_matrix_t *, int, int); 67 | void su_mat_matrix_discard_cols(su_mat_matrix_t *); 68 | void su_mat_matrix_destroy(su_mat_matrix_t *); 69 | 70 | struct sigutils_mat_file { 71 | PTR_LIST(su_mat_matrix_t, matrix); 72 | 73 | FILE *fp; 74 | su_mat_matrix_t *sm; 75 | 76 | SUSCOUNT sm_off; 77 | SUSCOUNT sm_contents_off; 78 | SUSCOUNT sm_last_col; 79 | }; 80 | 81 | typedef struct sigutils_mat_file su_mat_file_t; 82 | 83 | su_mat_file_t *su_mat_file_new(void); 84 | 85 | int su_mat_file_lookup_matrix_handle(const su_mat_file_t *, const char *); 86 | 87 | su_mat_matrix_t *su_mat_file_get_matrix_by_handle(const su_mat_file_t *, int); 88 | 89 | su_mat_matrix_t *su_mat_file_lookup_matrix(const su_mat_file_t *, const char *); 90 | 91 | SUBOOL su_mat_file_give_matrix(su_mat_file_t *, su_mat_matrix_t *); 92 | SUBOOL su_mat_file_give_streaming_matrix(su_mat_file_t *, su_mat_matrix_t *); 93 | 94 | su_mat_matrix_t *su_mat_file_make_matrix( 95 | su_mat_file_t *self, 96 | const char *name, 97 | int rows, 98 | int cols); 99 | 100 | su_mat_matrix_t *su_mat_file_make_streaming_matrix( 101 | su_mat_file_t *self, 102 | const char *name, 103 | int rows, 104 | int cols); 105 | 106 | SUBOOL su_mat_file_stream_col(su_mat_file_t *, ...); 107 | 108 | SUBOOL su_mat_file_dump(su_mat_file_t *, const char *); 109 | SUBOOL su_mat_file_flush(su_mat_file_t *); 110 | void su_mat_file_destroy(su_mat_file_t *); 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif /* __cplusplus */ 115 | 116 | #endif /* _SIGUTILS_MATFILE_H */ 117 | -------------------------------------------------------------------------------- /src/include/sigutils/pll.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_PLL_H 21 | #define _SIGUTILS_PLL_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | # ifdef __clang__ 30 | # pragma clang diagnostic push 31 | # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" 32 | # endif // __clang__ 33 | extern "C" { 34 | #endif /* __cplusplus */ 35 | 36 | #define SU_PLL_ORDER_DEFAULT 5 37 | #define SU_COSTAS_FIR_ORDER_THRESHOLD 20 38 | 39 | struct sigutils_pll { 40 | SUFLOAT alpha; 41 | SUFLOAT beta; 42 | SUFLOAT lock; 43 | SUCOMPLEX a; 44 | su_ncqo_t ncqo; 45 | }; 46 | 47 | typedef struct sigutils_pll su_pll_t; 48 | 49 | #define su_pll_INITIALIZER \ 50 | { \ 51 | 0., 0., 0., 0, su_ncqo_INITIALIZER \ 52 | } 53 | 54 | enum sigutils_costas_kind { 55 | SU_COSTAS_KIND_NONE, 56 | SU_COSTAS_KIND_BPSK, 57 | SU_COSTAS_KIND_QPSK, 58 | SU_COSTAS_KIND_8PSK 59 | }; 60 | 61 | struct sigutils_costas { 62 | enum sigutils_costas_kind kind; 63 | SUFLOAT a; 64 | SUFLOAT b; 65 | SUFLOAT lock; 66 | su_iir_filt_t af; /* Arm filter */ 67 | SUCOMPLEX z; /* Arm filter output */ 68 | SUCOMPLEX y; /* Demodulation result */ 69 | SUCOMPLEX y_alpha; /* Result alpha */ 70 | SUFLOAT gain; /* Loop gain */ 71 | su_ncqo_t ncqo; 72 | }; 73 | 74 | typedef struct sigutils_costas su_costas_t; 75 | 76 | #define su_costas_INITIALIZER \ 77 | { \ 78 | SU_COSTAS_KIND_NONE, 0., 0., 0., su_iir_filt_INITIALIZER, 0., 0., 0., 1., \ 79 | su_ncqo_INITIALIZER \ 80 | } 81 | 82 | /* Second order PLL */ 83 | SU_CONSTRUCTOR(su_pll, SUFLOAT fhint, SUFLOAT fc); 84 | SU_DESTRUCTOR(su_pll); 85 | 86 | SU_METHOD(su_pll, SUCOMPLEX, track, SUCOMPLEX x); 87 | SU_METHOD(su_pll, void, feed, SUFLOAT x); 88 | 89 | SUINLINE 90 | SU_METHOD(su_pll, SUFLOAT, locksig) 91 | { 92 | return self->lock; 93 | } 94 | 95 | SUINLINE 96 | SU_METHOD(su_pll, void, set_angfreq, SUFLOAT omega) 97 | { 98 | su_ncqo_set_angfreq(&self->ncqo, omega); 99 | } 100 | 101 | SUINLINE 102 | SU_METHOD(su_pll, void, set_freq, SUFLOAT omega) 103 | { 104 | su_ncqo_set_freq(&self->ncqo, omega); 105 | } 106 | 107 | SUINLINE 108 | SU_METHOD(su_pll, void, inc_angfreq, SUFLOAT delta) 109 | { 110 | su_ncqo_inc_angfreq(&self->ncqo, delta); 111 | } 112 | 113 | SUINLINE 114 | SU_GETTER(su_pll, SUFREQ, get_freq) 115 | { 116 | return su_ncqo_get_freq(&self->ncqo); 117 | } 118 | 119 | SUINLINE 120 | SU_GETTER(su_pll, SUFREQ, get_angfreq) 121 | { 122 | return su_ncqo_get_angfreq(&self->ncqo); 123 | } 124 | 125 | SUINLINE 126 | SU_METHOD(su_pll, void, set_cutoff, SUFLOAT fc) 127 | { 128 | SUFLOAT dinv; 129 | 130 | fc = SU_NORM2ANG_FREQ(fc); 131 | 132 | /* Settings taken from GNU Radio */ 133 | dinv = 1.f / (1.f + 2.f * .707f * fc + fc * fc); 134 | 135 | self->alpha = 4 * fc * fc * dinv; 136 | self->beta = 4 * 0.707 * fc * dinv; 137 | } 138 | 139 | /* QPSK costas loops are way more complex than that */ 140 | SU_CONSTRUCTOR( 141 | su_costas, 142 | enum sigutils_costas_kind kind, 143 | SUFLOAT fhint, 144 | SUFLOAT arm_bw, 145 | unsigned int arm_order, 146 | SUFLOAT loop_bw); 147 | SU_DESTRUCTOR(su_costas); 148 | 149 | SU_METHOD(su_costas, void, set_kind, enum sigutils_costas_kind kind); 150 | SU_METHOD(su_costas, void, set_loop_gain, SUFLOAT gain); 151 | SU_METHOD(su_costas, SUCOMPLEX, feed, SUCOMPLEX x); 152 | 153 | #ifdef __cplusplus 154 | # ifdef __clang__ 155 | # pragma clang diagnostic pop 156 | # endif // __clang__ 157 | } 158 | #endif /* __cplusplus */ 159 | 160 | #endif /* _SIGUTILS_PLL_H */ 161 | -------------------------------------------------------------------------------- /src/include/sigutils/property.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_PROPERTY_H 21 | #define _SIGUTILS_PROPERTY_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | enum sigutils_property_type { 32 | SU_PROPERTY_TYPE_ANY, 33 | SU_PROPERTY_TYPE_BOOL, 34 | SU_PROPERTY_TYPE_INTEGER, 35 | SU_PROPERTY_TYPE_FLOAT, 36 | SU_PROPERTY_TYPE_COMPLEX, 37 | SU_PROPERTY_TYPE_OBJECT 38 | }; 39 | 40 | typedef enum sigutils_property_type su_property_type_t; 41 | 42 | struct sigutils_property { 43 | su_property_type_t type; 44 | char *name; 45 | SUBOOL mandatory; 46 | 47 | union { 48 | uint64_t *int_ptr; 49 | SUFLOAT *float_ptr; 50 | SUCOMPLEX *complex_ptr; 51 | SUBOOL *bool_ptr; 52 | void *generic_ptr; 53 | }; 54 | }; 55 | 56 | typedef struct sigutils_property su_property_t; 57 | 58 | struct sigutils_property_set { 59 | PTR_LIST(su_property_t, property); 60 | }; 61 | 62 | typedef struct sigutils_property_set su_property_set_t; 63 | 64 | const char *su_property_type_to_string(su_property_type_t type); 65 | 66 | /* Property API */ 67 | su_property_t *su_property_new( 68 | const char *name, 69 | su_property_type_t type, 70 | SUBOOL mandatory, 71 | void *p); 72 | 73 | /* Property set API */ 74 | void su_property_set_init(su_property_set_t *set); 75 | su_property_t *su_property_set_lookup( 76 | const su_property_set_t *set, 77 | const char *name); 78 | su_property_t *su_property_set_assert_property( 79 | su_property_set_t *set, 80 | const char *name, 81 | su_property_type_t type); 82 | su_property_t *su_property_set_assert_mandatory_property( 83 | su_property_set_t *set, 84 | const char *name, 85 | su_property_type_t type); 86 | su_property_t *__su_property_set_assert_property( 87 | su_property_set_t *set, 88 | const char *name, 89 | su_property_type_t type, 90 | SUBOOL mandatory); 91 | 92 | void su_property_set_finalize(su_property_set_t *set); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif /* __cplusplus */ 97 | 98 | #endif /* _SIGUTILS_PROPERTY_H */ 99 | -------------------------------------------------------------------------------- /src/include/sigutils/sampling.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_SAMPLING_H 21 | #define _SIGUTILS_SAMPLING_H 22 | 23 | #include 24 | 25 | /* 26 | * Conventions used for frequency representation 27 | * --------------------------------------------- 28 | * SAMPLING FREQUENCY (fs): How many samples are taken per second, in Hz. 29 | * 30 | * NORMALIZED FREQUENCY (fnor): Represents the frequency of a discretized 31 | * signal, ranging from 0 (constant signal) to 1 (a signal that flips sign on 32 | * each time step). Units: hcps ("half cycles per sample") 33 | * 34 | * ABSOLUTE FREQUENCY (freq): Represents the actual frequency of the signal, 35 | * in Hz. It is defined as: 36 | * 37 | * freq = fnor * fs / 2. 38 | * 39 | * NORMALIZED ANGULAR FREQUENCY (omrel): Represents how many radians are added 40 | * to the signal phase in each time step. It is defined as: 41 | * 42 | * omrel = PI * fnor 43 | * 44 | * as the flipping sign signal's phase increments in 180 degrees on each 45 | * time step. 46 | */ 47 | 48 | #define SU_ABS2NORM_FREQ(fs, freq) (2 * (SUFLOAT)(freq) / (SUFLOAT)(fs)) 49 | #define SU_NORM2ABS_FREQ(fs, fnor) ((SUFLOAT)(fs) * (SUFLOAT)(fnor) / 2.) 50 | 51 | /* 52 | * Normalized and absolute baud rates are transformed using a different 53 | * rule: since CDR block works with the symbol period, it's convenient 54 | * to define the baud rate as the inverse of the symbol period in samples. 55 | * 56 | * As a consequence of this, a normalized baudrate of 1 means 1 symbol per 57 | * sample. 58 | */ 59 | 60 | #define SU_ABS2NORM_BAUD(fs, freq) ((SUFLOAT)(freq) / (SUFLOAT)(fs)) 61 | #define SU_NORM2ABS_BAUD(fs, fnor) ((SUFLOAT)(fs) * (SUFLOAT)(fnor)) 62 | 63 | #define SU_NORM2ANG_FREQ(freq) (PI * (freq)) 64 | #define SU_ANG2NORM_FREQ(omrel) ((omrel) / (PI)) 65 | 66 | #define SU_T2N(fs, t) ((unsigned int)SU_FLOOR((t) * (SUFLOAT)(fs))) 67 | #define SU_N2T(fs, n) ((unsigned int)SU_FLOOR((n) / (SUFLOAT)(fs))) 68 | 69 | #define SU_T2N_COUNT(fs, t) ((unsigned int)SU_CEIL((t) * (SUFLOAT)(fs))) 70 | #define SU_N2T_COUNT(fs, n) ((unsigned int)SU_CEIL((n) / (SUFLOAT)(fs))) 71 | 72 | #define SU_T2N_FLOAT(fs, t) ((t) * (SUFLOAT)(fs)) 73 | #define SU_N2T_FLOAT(fs, n) ((n) / (SUFLOAT)(fs)) 74 | 75 | #endif /* _SIGUTILS_SAMPLING_H */ 76 | -------------------------------------------------------------------------------- /src/include/sigutils/sigutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_SIGUTILS_H 21 | #define _SIGUTILS_SIGUTILS_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif /* __cplusplus */ 31 | 32 | /* Library initialization */ 33 | SUBOOL su_lib_init_ex(const struct sigutils_log_config *logconfig); 34 | SUBOOL su_lib_init(void); 35 | 36 | /* FFT wisdom file handling */ 37 | SUBOOL su_lib_is_using_wisdom(void); 38 | SUBOOL su_lib_set_wisdom_enabled(SUBOOL); 39 | SUBOOL su_lib_set_wisdom_file(const char *); 40 | SUBOOL su_lib_save_wisdom(void); 41 | void su_lib_gen_wisdom(void); 42 | 43 | /* Internal */ 44 | int su_lib_fftw_strategy(void); 45 | SU_FFTW(_plan) su_lib_plan_dft_1d(int n, SU_FFTW(_complex) *in, 46 | SU_FFTW(_complex) *out, int sign, unsigned flags); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif /* __cplusplus */ 51 | 52 | #endif /* _SIGUTILS_SIGUTILS_H */ 53 | -------------------------------------------------------------------------------- /src/include/sigutils/smoothpsd.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2021 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_SMOOTHPSD_H 21 | #define _SIGUTILS_SMOOTHPSD_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | struct sigutils_smoothpsd_params { 32 | unsigned int fft_size; 33 | SUFLOAT samp_rate; 34 | SUFLOAT refresh_rate; 35 | enum sigutils_channel_detector_window window; 36 | }; 37 | 38 | #define sigutils_smoothpsd_params_INITIALIZER \ 39 | { \ 40 | 4096, /* fft_size */ \ 41 | 1e6, /* samp_rate */ \ 42 | 25, /* refresh_rate */ \ 43 | SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS /* window */ \ 44 | } 45 | 46 | struct sigutils_smoothpsd { 47 | struct sigutils_smoothpsd_params params; 48 | SUFLOAT nominal_rate; 49 | pthread_mutex_t mutex; 50 | SUBOOL mutex_init; 51 | 52 | SUBOOL (*psd_func)(void *userdata, const SUFLOAT *psd, unsigned int size); 53 | void *userdata; 54 | 55 | unsigned int p; 56 | unsigned int fft_p; 57 | unsigned int max_p; 58 | 59 | SUSCOUNT iters; 60 | 61 | SU_FFTW(_complex) * window_func; 62 | SU_FFTW(_complex) * buffer; 63 | SU_FFTW(_plan) fft_plan; 64 | 65 | union { 66 | SU_FFTW(_complex) * fft; 67 | SUFLOAT *realfft; 68 | }; 69 | }; 70 | 71 | typedef struct sigutils_smoothpsd su_smoothpsd_t; 72 | 73 | SUINLINE 74 | SU_GETTER(su_smoothpsd, SUFLOAT, get_nominal_samp_rate) 75 | { 76 | return self->nominal_rate; 77 | } 78 | 79 | SUINLINE 80 | SU_METHOD( 81 | su_smoothpsd, 82 | void, 83 | set_nominal_samp_rate, 84 | SUFLOAT rate) 85 | { 86 | self->nominal_rate = rate; 87 | } 88 | 89 | SUINLINE 90 | SU_GETTER(su_smoothpsd, SUSCOUNT, get_iters) 91 | { 92 | return self->iters; 93 | } 94 | 95 | SUINLINE 96 | SU_GETTER(su_smoothpsd, unsigned int, get_fft_size) 97 | { 98 | return self->params.fft_size; 99 | } 100 | 101 | SUINLINE 102 | SU_GETTER(su_smoothpsd, SUFLOAT *, get_last_psd) 103 | { 104 | return self->realfft; 105 | } 106 | 107 | SU_INSTANCER( 108 | su_smoothpsd, 109 | const struct sigutils_smoothpsd_params *params, 110 | SUBOOL (*psd_func)(void *userdata, const SUFLOAT *psd, unsigned int size), 111 | void *userdata); 112 | 113 | SU_COLLECTOR(su_smoothpsd); 114 | 115 | SU_METHOD(su_smoothpsd, SUBOOL, feed, const SUCOMPLEX *data, SUSCOUNT size); 116 | 117 | SU_METHOD( 118 | su_smoothpsd, 119 | SUBOOL, 120 | set_params, 121 | const struct sigutils_smoothpsd_params *params); 122 | 123 | #ifdef __cplusplus 124 | } 125 | #endif /* __cplusplus */ 126 | 127 | #endif /* _SIGUTILS_SMOOTHPSD_H */ 128 | -------------------------------------------------------------------------------- /src/include/sigutils/softtune.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo Jose Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_SOFTTUNE_H 21 | #define _SIGUTILS_SOFTTUNE_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* Extra bandwidth given to antialias filter */ 30 | #define SU_SOFTTUNER_ANTIALIAS_EXTRA_BW 2 31 | #define SU_SOFTTUNER_ANTIALIAS_ORDER 4 32 | 33 | struct sigutils_channel { 34 | SUFREQ fc; /* Channel central frequency */ 35 | SUFREQ f_lo; /* Lower frequency belonging to the channel */ 36 | SUFREQ f_hi; /* Upper frequency belonging to the channel */ 37 | SUFLOAT bw; /* Equivalent bandwidth */ 38 | SUFLOAT snr; /* Signal-to-noise ratio */ 39 | SUFLOAT S0; /* Peak signal power */ 40 | SUFLOAT N0; /* Noise level */ 41 | SUFREQ ft; /* Tuner frequency */ 42 | uint32_t age; /* Channel age */ 43 | uint32_t present; /* Is channel present? */ 44 | }; 45 | 46 | typedef struct sigutils_channel su_channel_t; 47 | 48 | struct sigutils_softtuner_params { 49 | SUSCOUNT samp_rate; 50 | SUSCOUNT decimation; 51 | SUFREQ fc; 52 | SUFLOAT bw; 53 | }; 54 | 55 | #define sigutils_softtuner_params_INITIALIZER \ 56 | { \ 57 | 0, /* samp_rate */ \ 58 | 0, /* decimation */ \ 59 | 0, /* fc */ \ 60 | 0, /* bw */ \ 61 | } 62 | 63 | struct sigutils_softtuner { 64 | struct sigutils_softtuner_params params; 65 | su_ncqo_t lo; /* Local oscillator */ 66 | su_iir_filt_t antialias; /* Antialiasing filter */ 67 | su_stream_t output; /* Output stream */ 68 | su_off_t read_ptr; 69 | SUSCOUNT decim_ptr; 70 | SUBOOL filtered; 71 | SUFLOAT avginv; 72 | }; 73 | 74 | typedef struct sigutils_softtuner su_softtuner_t; 75 | 76 | SUINLINE void 77 | su_channel_detector_set_fc(su_softtuner_t *cd, SUFLOAT fc) 78 | { 79 | cd->params.fc = fc; 80 | 81 | su_ncqo_init(&cd->lo, SU_ABS2NORM_FREQ(cd->params.samp_rate, cd->params.fc)); 82 | } 83 | 84 | void su_softtuner_params_adjust_to_channel( 85 | struct sigutils_softtuner_params *params, 86 | const struct sigutils_channel *channel); 87 | 88 | SUBOOL su_softtuner_init( 89 | su_softtuner_t *tuner, 90 | const struct sigutils_softtuner_params *params); 91 | 92 | SUSCOUNT 93 | su_softtuner_feed(su_softtuner_t *tuner, const SUCOMPLEX *input, SUSCOUNT size); 94 | 95 | SUSDIFF su_softtuner_read(su_softtuner_t *tuner, SUCOMPLEX *out, SUSCOUNT size); 96 | 97 | void su_softtuner_finalize(su_softtuner_t *tuner); 98 | 99 | #endif /* _SIGUTILS_SOFTTUNE_H */ 100 | -------------------------------------------------------------------------------- /src/include/sigutils/specific/apt.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2021 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_SPECIFIC_APT_H 21 | #define _SIGUTILS_SPECIFIC_APT_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | /* https://web.archive.org/web/20070505090431/http://www2.ncdc.noaa.gov/docs/klm/html/c4/sec4-2.htm 32 | */ 33 | 34 | #define SU_APT_IF_RATE 4160 35 | #define SU_APT_LINE_LEN (SU_APT_IF_RATE / 2) 36 | #define SU_APT_CHANNEL_LEN (SU_APT_LINE_LEN / 2) 37 | 38 | #define SU_APT_SYNC_SIZE 39 /* By spec */ 39 | #define SU_APT_SYNC_MIN_SNR 40 40 | 41 | #define SU_APT_AM_CARRIER_FREQ 2400 42 | #define SU_APT_AM_BANDWIDTH 2400 43 | 44 | #define SU_APT_BUFF_LEN (2 * SU_APT_LINE_LEN + 2 * SU_APT_SYNC_SIZE) 45 | #define SU_APT_LINE_BUFF_LEN SU_APT_BUFF_LEN 46 | #define SU_APT_TRAINING_LINES 50 47 | #define SU_APT_LINE_LEN_THRESHOLD (SU_APT_SYNC_SIZE / 2) 48 | #define SU_APT_MINUTE_MARKER_LEN 47 49 | #define SU_APT_VIDEO_DATA_LEN 909 50 | #define SU_APT_TELEMETRY_LEN 45 51 | #define SU_APT_SYNC_B_OFFSET \ 52 | (SU_APT_SYNC_SIZE + SU_APT_MINUTE_MARKER_LEN + SU_APT_TELEMETRY_LEN \ 53 | + SU_APT_VIDEO_DATA_LEN) 54 | #define SU_APT_LEVEL_LEN 10 55 | #define SU_APT_BLACK_START 1085 56 | #define SU_APT_WHITE_START 45 57 | #define SU_APT_MIN_CARRIER_DB 1 58 | #define SU_APT_MIN_LEVEL 1e-30 59 | 60 | enum sigutils_apt_decoder_channel { 61 | SU_APT_DECODER_CHANNEL_A, 62 | SU_APT_DECODER_CHANNEL_B 63 | }; 64 | 65 | struct sigutils_apt_decoder; 66 | 67 | struct sigutils_apt_decoder_callbacks { 68 | void *userdata; 69 | 70 | SUBOOL (*on_carrier)(struct sigutils_apt_decoder *, void *, SUFLOAT); 71 | SUBOOL (*on_sync)(struct sigutils_apt_decoder *, void *, SUSCOUNT); 72 | SUBOOL (*on_line)(struct sigutils_apt_decoder *, void *, SUFLOAT); 73 | SUBOOL(*on_line_data) 74 | (struct sigutils_apt_decoder *, 75 | void *, 76 | SUSCOUNT, 77 | enum sigutils_apt_decoder_channel, 78 | SUBOOL, 79 | const uint8_t *, 80 | size_t); 81 | }; 82 | 83 | #define sigutils_apt_decoder_callbacks_INITIALIZER \ 84 | { \ 85 | NULL, /* userdata */ \ 86 | NULL, /* on_carrier */ \ 87 | NULL, /* on_sync */ \ 88 | NULL, /* on_line */ \ 89 | NULL, /* on_line_data */ \ 90 | } 91 | 92 | struct sigutils_apt_decoder { 93 | SUFLOAT samp_rate; 94 | su_pll_t pll; /* To center carrier */ 95 | su_iir_filt_t mf; /* Matched filter for 4160 Hz */ 96 | su_sampler_t resampler; /* Resampler */ 97 | 98 | /* The following objects work at a 4160 rate */ 99 | SUSCOUNT count; 100 | 101 | SUCOMPLEX samp_buffer[SU_APT_BUFF_LEN]; 102 | unsigned int samp_ptr; 103 | SUSCOUNT samp_epoch; 104 | 105 | SUFLOAT mean_i; 106 | SUFLOAT mean_q; 107 | 108 | /* Correlator data */ 109 | SUFLOAT sync_snr; 110 | SUCOMPLEX sync_fft[SU_APT_BUFF_LEN]; 111 | SUCOMPLEX corr_fft[SU_APT_BUFF_LEN]; 112 | SU_FFTW(_plan) direct_plan; 113 | SU_FFTW(_plan) reverse_plan; 114 | 115 | /* Sync detection */ 116 | SUSCOUNT last_sync; 117 | SUSCOUNT next_sync; 118 | SUSCOUNT next_search; 119 | SUFLOAT last_sync_delta; 120 | 121 | /* Line buffer */ 122 | SUFLOAT line_buffer[SU_APT_LINE_BUFF_LEN]; 123 | SUSCOUNT last_epoch; 124 | unsigned int line_ptr; 125 | unsigned int line_last_samp; 126 | 127 | /* Image */ 128 | PTR_LIST(uint8_t, scan_line); 129 | 130 | SUSCOUNT lines; 131 | SUFLOAT line_len_alpha; 132 | SUFLOAT line_len; 133 | SUFLOAT mean_black; 134 | SUFLOAT mean_white; 135 | SUBOOL have_levels; 136 | 137 | struct sigutils_apt_decoder_callbacks callbacks; 138 | }; 139 | 140 | typedef struct sigutils_apt_decoder su_apt_decoder_t; 141 | 142 | su_apt_decoder_t *su_apt_decoder_new( 143 | SUFLOAT fs, 144 | const struct sigutils_apt_decoder_callbacks *); 145 | 146 | SUBOOL su_apt_decoder_feed_ex( 147 | su_apt_decoder_t *self, 148 | SUBOOL phase_only, 149 | const SUCOMPLEX *buffer, 150 | SUSCOUNT count); 151 | 152 | SUBOOL su_apt_decoder_feed( 153 | su_apt_decoder_t *self, 154 | const SUCOMPLEX *buffer, 155 | SUSCOUNT count); 156 | 157 | void su_apt_decoder_clear_image(su_apt_decoder_t *self); 158 | 159 | void su_apt_decoder_set_snr(su_apt_decoder_t *self, SUFLOAT); 160 | 161 | SUBOOL su_apt_decoder_dump_pgm(const su_apt_decoder_t *self, const char *path); 162 | 163 | void su_apt_decoder_destroy(su_apt_decoder_t *self); 164 | 165 | #ifdef __cplusplus 166 | } 167 | #endif /* __cplusplus */ 168 | 169 | #endif /* _SIGUTILS_SPECIFIC_APT_H */ 170 | -------------------------------------------------------------------------------- /src/include/sigutils/taps.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #ifndef _SIGUTILS_TAPS_H 21 | #define _SIGUTILS_TAPS_H 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif /* __cplusplus */ 28 | 29 | #define SU_HAMMING_ALPHA 0.54 30 | #define SU_MAMMING_BETA (1 - SU_HAMMING_ALPHA) 31 | 32 | #define SU_HANN_ALPHA 0.5 33 | #define SU_HANN_BETA (1 - SU_HANN_ALPHA) 34 | 35 | #define SU_FLAT_TOP_A0 1 36 | #define SU_FLAT_TOP_A1 1.93 37 | #define SU_FLAT_TOP_A2 1.29 38 | #define SU_FLAT_TOP_A3 0.388 39 | #define SU_FLAT_TOP_A4 0.028 40 | 41 | #define SU_BLACKMANN_HARRIS_A0 0.35875 42 | #define SU_BLACKMANN_HARRIS_A1 0.48829 43 | #define SU_BLACKMANN_HARRIS_A2 0.14128 44 | #define SU_BLACKMANN_HARRIS_A3 0.01168 45 | 46 | /* Window functions */ 47 | void su_taps_apply_hamming(SUFLOAT *h, SUSCOUNT size); 48 | void su_taps_apply_hann(SUFLOAT *h, SUSCOUNT size); 49 | 50 | void su_taps_apply_hamming_complex(SUCOMPLEX *h, SUSCOUNT size); 51 | void su_taps_apply_hann_complex(SUCOMPLEX *h, SUSCOUNT size); 52 | 53 | void su_taps_apply_flat_top(SUFLOAT *h, SUSCOUNT size); 54 | void su_taps_apply_flat_top_complex(SUCOMPLEX *h, SUSCOUNT size); 55 | 56 | void su_taps_apply_blackmann_harris(SUFLOAT *h, SUSCOUNT size); 57 | void su_taps_apply_blackmann_harris_complex(SUCOMPLEX *h, SUSCOUNT size); 58 | 59 | /* Hilbert transform */ 60 | void su_taps_hilbert_init(SUFLOAT *h, SUSCOUNT size); 61 | 62 | /* Get coefficients of a RRC filter */ 63 | void su_taps_rrc_init(SUFLOAT *h, SUFLOAT T, SUFLOAT beta, SUSCOUNT size); 64 | 65 | void su_taps_brickwall_lp_init(SUFLOAT *h, SUFLOAT fc, SUSCOUNT size); 66 | 67 | void su_taps_brickwall_bp_init( 68 | SUFLOAT *h, 69 | SUFLOAT bw, 70 | SUFLOAT if_nor, 71 | SUSCOUNT size); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif /* __cplusplus */ 76 | 77 | #endif /* _SIGUTILS_TAPS_H */ 78 | -------------------------------------------------------------------------------- /src/include/sigutils/tvproc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2020 Gonzalo José Carracedo Carballal 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _SIGUTILS_TVPROC_H 19 | #define _SIGUTILS_TVPROC_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif /* __cplusplus */ 28 | 29 | struct sigutils_tv_processor_params { 30 | /* Flags */ 31 | SUBOOL enable_sync; 32 | SUBOOL reverse; 33 | SUBOOL interlace; 34 | SUBOOL enable_agc; 35 | SUFLOAT x_off; 36 | 37 | /* Geometry */ 38 | SUSCOUNT frame_lines; 39 | SUFLOAT frame_spacing; 40 | 41 | /* Filtering */ 42 | SUBOOL enable_comb; 43 | SUBOOL comb_reverse; 44 | 45 | /* Timing */ 46 | SUFLOAT hsync_len; 47 | SUFLOAT vsync_len; 48 | SUFLOAT line_len; 49 | SUSCOUNT vsync_odd_trigger; 50 | SUBOOL dominance; 51 | 52 | /* Tolerances */ 53 | SUFLOAT t_tol; /* Timing tolerance */ 54 | SUFLOAT l_tol; /* Level tolerance */ 55 | SUFLOAT g_tol; /* Geometry tolerance. */ 56 | 57 | /* Error triggers */ 58 | SUFLOAT hsync_huge_err; /* .25 */ 59 | SUFLOAT hsync_max_err; /* .15 */ 60 | SUFLOAT hsync_min_err; /* .1 */ 61 | 62 | /* Time constants */ 63 | SUFLOAT hsync_len_tau; /* 9.5 */ 64 | SUFLOAT hsync_fast_track_tau; /* 9.5 */ 65 | SUFLOAT hsync_slow_track_tau; 66 | SUFLOAT line_len_tau; /* 9.5 */ 67 | 68 | SUFLOAT agc_tau; /* 3 */ 69 | }; 70 | 71 | struct sigutils_pulse_finder { 72 | SUFLOAT base; 73 | SUFLOAT peak_thr; 74 | SUSCOUNT length; 75 | SUFLOAT level_tolerance; 76 | SUFLOAT time_tolerance; 77 | 78 | SUFLOAT last_y; 79 | 80 | su_iir_filt_t corr; 81 | SUBOOL present; 82 | SUFLOAT accum; 83 | SUFLOAT w_accum; 84 | SUFLOAT duration; 85 | SUFLOAT rel_pos; 86 | }; 87 | 88 | typedef struct sigutils_pulse_finder su_pulse_finder_t; 89 | 90 | SU_INSTANCER( 91 | su_pulse_finder, 92 | SUFLOAT base, 93 | SUFLOAT peak, 94 | SUSCOUNT len, 95 | SUFLOAT tolerance); 96 | SU_COLLECTOR(su_pulse_finder); 97 | 98 | SU_METHOD(su_pulse_finder, SUBOOL, feed, SUFLOAT x); 99 | SU_GETTER(su_pulse_finder, SUFLOAT, get_pos); 100 | 101 | struct sigutils_tv_frame_buffer { 102 | int width, height; 103 | SUFLOAT *buffer; 104 | struct sigutils_tv_frame_buffer *next; 105 | }; 106 | 107 | typedef struct sigutils_tv_frame_buffer su_tv_frame_buffer_t; 108 | 109 | SU_INSTANCER( 110 | su_tv_frame_buffer, 111 | const struct sigutils_tv_processor_params *params); 112 | 113 | SU_COPY_INSTANCER(su_tv_frame_buffer); 114 | SU_COLLECTOR(su_tv_frame_buffer); 115 | 116 | enum sigutils_tv_processor_state { 117 | SU_TV_PROCESSOR_SEARCH, 118 | SU_TV_PROCESSOR_SYNCED, 119 | }; 120 | 121 | struct sigutils_tv_processor { 122 | struct sigutils_tv_processor_params params; 123 | enum sigutils_tv_processor_state state; 124 | 125 | struct sigutils_tv_frame_buffer *free_pool; 126 | struct sigutils_tv_frame_buffer *current; 127 | 128 | /* Sample counter */ 129 | SUSCOUNT ptr; 130 | 131 | /* Precalculated data */ 132 | SUSCOUNT field_lines; 133 | SUFLOAT agc_alpha; 134 | SUFLOAT pulse_alpha; 135 | SUFLOAT hsync_len_alpha; 136 | SUFLOAT hsync_slow_track_alpha; 137 | SUFLOAT hsync_fast_track_alpha; 138 | SUFLOAT line_len_alpha; 139 | 140 | /* Frame state */ 141 | SUFLOAT field_line_due; 142 | SUSCOUNT field_x; 143 | SUFLOAT field_x_dec; 144 | SUSCOUNT field_y; 145 | SUBOOL field_parity; 146 | SUBOOL field_complete; 147 | SUSCOUNT field_prev_ptr; 148 | 149 | /* Comb filter's delay line */ 150 | SUFLOAT *delay_line; 151 | SUSCOUNT delay_line_len; 152 | SUSCOUNT delay_line_ptr; 153 | 154 | /* AGC */ 155 | SUFLOAT agc_gain; 156 | SUFLOAT agc_line_max; 157 | SUFLOAT agc_accum; 158 | SUSCOUNT agc_lines; 159 | 160 | /* Pulse output */ 161 | SUFLOAT pulse_x; 162 | 163 | /* Sync pulse detection */ 164 | SUBOOL sync_found; 165 | SUSCOUNT sync_start; 166 | 167 | /* HSYNC detection */ 168 | SUSCOUNT last_hsync; 169 | SUBOOL have_last_hsync; 170 | SUFLOAT est_hsync_len; 171 | SUBOOL hsync_slow_track; 172 | 173 | /* VSYNC detection */ 174 | SUSCOUNT last_frame; 175 | SUSCOUNT last_vsync; 176 | SUSCOUNT vsync_counter; 177 | SUBOOL frame_has_vsync; 178 | 179 | /* Line length estimation */ 180 | SUFLOAT est_line_len; 181 | SUFLOAT est_line_len_accum; 182 | SUSCOUNT est_line_len_count; 183 | }; 184 | 185 | typedef struct sigutils_tv_processor su_tv_processor_t; 186 | 187 | SU_INSTANCER( 188 | su_tv_processor, 189 | const struct sigutils_tv_processor_params *params); 190 | SU_COLLECTOR(su_tv_processor); 191 | 192 | void su_tv_processor_params_pal( 193 | struct sigutils_tv_processor_params *self, 194 | SUFLOAT samp_rate); 195 | 196 | void su_tv_processor_params_ntsc( 197 | struct sigutils_tv_processor_params *self, 198 | SUFLOAT samp_rate); 199 | 200 | SU_METHOD( 201 | su_tv_processor, 202 | SUBOOL, 203 | set_params, 204 | const struct sigutils_tv_processor_params *params); 205 | SU_METHOD(su_tv_processor, SUBOOL, feed, SUFLOAT x); 206 | 207 | SU_METHOD(su_tv_processor, su_tv_frame_buffer_t *, take_frame); 208 | SU_METHOD(su_tv_processor, void, return_frame, su_tv_frame_buffer_t *); 209 | 210 | #ifdef __cplusplus 211 | } 212 | #endif /* __cplusplus */ 213 | 214 | #endif /* _SIGUTILS_TVPROC_H */ 215 | -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-fcntl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_FCNTL_H 19 | #define _UTIL_COMPAT_FCNTL_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-fcntl.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_FCNTL_H */ 28 | -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-in.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_IN_H 19 | #define _UTIL_COMPAT_IN_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-in.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_IN_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-inet.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_INET_H 19 | #define _UTIL_COMPAT_INET_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-inet.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_INET_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-mman.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_MMAN_H 19 | #define _UTIL_COMPAT_MMAN_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-mman.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_MMAN_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-netdb.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_NETDB_H 19 | #define _UTIL_COMPAT_NETDB_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-netdb.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_NETDB_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-poll.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_POLL_H 19 | #define _UTIL_COMPAT_POLL_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-poll.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_POLL_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-pwd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_PWD_H 19 | #define _UTIL_COMPAT_PWD_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-pwd.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_PWD_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-select.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_SELECT_H 19 | #define _UTIL_COMPAT_SELECT_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-time.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_SELECT_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_SOCKET_H 19 | #define _UTIL_COMPAT_SOCKET_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-socket.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_SOCKET_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-stat.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_STAT_H 19 | #define _UTIL_COMPAT_STAT_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-stat.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_STAT_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-statvfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_STATVFS_H 19 | #define _UTIL_COMPAT_STATVFS_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-statvfs.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_STATVFS_H */ 28 | -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_STDLIB_H 19 | #define _UTIL_COMPAT_STDLIB_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-stdlib.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_STDLIB_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-termios.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_TERMIOS_H 19 | #define _UTIL_COMPAT_TERMIOS_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-termios.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_TERMIOS_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_TIME_H 19 | #define _UTIL_COMPAT_TIME_H 20 | 21 | #ifdef _WIN32 22 | # include /* nanosleep() */ 23 | # include /* rest of time.h (time(), ctime()) */ 24 | 25 | # include "win32-time.h" /* timersub() */ 26 | #else 27 | # include 28 | # include 29 | #endif /* _WIN32 */ 30 | 31 | #endif /* _UTIL_COMPAT_TIME_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/compat-unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_COMPAT_UNISTD_H 19 | #define _UTIL_COMPAT_UNISTD_H 20 | 21 | #ifdef _WIN32 22 | # include "win32-unistd.h" 23 | #else 24 | # include 25 | #endif /* _WIN32 */ 26 | 27 | #endif /* _UTIL_COMPAT_UNISTD_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-fcntl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_FCNTL_H 19 | #define _UTIL_FCNTL_H 20 | 21 | #define _O_BINARY 0x8000 /* Input and output is not translated. */ 22 | 23 | #define F_GETFL 3 /* Get file flags */ 24 | #define F_SETFL 4 /* Set file flags */ 25 | 26 | #define O_NONBLOCK 0x4000 /* Non blocking I/O (POSIX style) */ 27 | 28 | #include 29 | 30 | int fcntl(int fd, int cmd, ... /* arg */); 31 | 32 | #endif /* _UTIL_FCNTL_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-in.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_IN_H 19 | #define _UTIL_IN_H 20 | 21 | #define WIN32_LEAN_AND_MEAN 22 | #include 23 | #include 24 | 25 | /* for gods sake microsoft */ 26 | #ifdef interface 27 | # undef interface 28 | #endif /* interface */ 29 | 30 | #endif /* _UTIL_IN_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-inet.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_INET_H 19 | #define _UTIL_INET_H 20 | 21 | #define WIN32_LEAN_AND_MEAN 22 | #include 23 | #include 24 | 25 | #define getsockopt(sockfd, level, optname, optval, optLen) \ 26 | getsockopt(sockfd, level, optname, (char *)optval, optLen) 27 | 28 | #ifdef interface 29 | # undef interface 30 | #endif /* interface */ 31 | 32 | #endif /* _UTIL_INET_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-mman.h: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/klauspost/mman-win32 (unlicensed) 2 | 3 | /* 4 | Copyright (C) 2012 Klaus Post 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | You should have received a copy of the GNU Lesser General Public 13 | License along with this program. If not, see 14 | 15 | */ 16 | 17 | #ifndef _SYS_MMAN_H_ 18 | #define _SYS_MMAN_H_ 19 | 20 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 21 | # define _WIN32_WINNT \ 22 | 0x0501 // Change this to the appropriate value to target other versions of 23 | // Windows. 24 | #endif 25 | 26 | /* All the headers include this file. */ 27 | #ifndef _MSC_VER 28 | # include <_mingw.h> 29 | #endif 30 | 31 | #include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #define PROT_NONE 0 38 | #define PROT_READ 1 39 | #define PROT_WRITE 2 40 | #define PROT_EXEC 4 41 | 42 | #define MAP_FILE 0 43 | #define MAP_SHARED 1 44 | #define MAP_PRIVATE 2 45 | #define MAP_TYPE 0xf 46 | #define MAP_FIXED 0x10 47 | #define MAP_ANONYMOUS 0x20 48 | #define MAP_ANON MAP_ANONYMOUS 49 | 50 | #define MAP_FAILED ((void *)-1) 51 | 52 | /* Flags for msync. */ 53 | #define MS_ASYNC 1 54 | #define MS_SYNC 2 55 | #define MS_INVALIDATE 4 56 | 57 | void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); 58 | int munmap(void *addr, size_t len); 59 | int mprotect(void *addr, size_t len, int prot); 60 | int msync(void *addr, size_t len, int flags); 61 | int mlock(const void *addr, size_t len); 62 | int munlock(const void *addr, size_t len); 63 | 64 | #ifdef __cplusplus 65 | }; 66 | #endif 67 | 68 | #endif /* _SYS_MMAN_H_ */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-netdb.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_NETDB_H 19 | #define _UTIL_NETDB_H 20 | 21 | #define WIN32_LEAN_AND_MEAN 22 | #include 23 | #include 24 | 25 | /* for gods sake microsoft */ 26 | #ifdef interface 27 | # undef interface 28 | #endif /* interface */ 29 | 30 | #endif /* _UTIL_NETDB_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-poll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Public domain 3 | * 4 | * poll(2) emulation for Windows 5 | * 6 | * This emulates just-enough poll functionality on Windows to work in the 7 | * context of the openssl(1) program. This is not a replacement for 8 | * POSIX.1-2001 poll(2). 9 | * 10 | * Dongsheng Song 11 | * Brent Cook 12 | */ 13 | 14 | #ifndef _UTIL_POLL_H 15 | #define _UTIL_POLL_H 16 | 17 | #ifndef _WIN32 18 | # include_next 19 | #else 20 | 21 | # include 22 | 23 | /* Type used for the number of file descriptors. */ 24 | typedef unsigned long int nfds_t; 25 | 26 | # if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) 27 | /* Data structure describing a polling request. */ 28 | struct pollfd { 29 | int fd; /* file descriptor */ 30 | short events; /* requested events */ 31 | short revents; /* returned events */ 32 | }; 33 | 34 | /* Event types that can be polled */ 35 | # define POLLIN 0x001 /* There is data to read. */ 36 | # define POLLPRI 0x002 /* There is urgent data to read. */ 37 | # define POLLOUT 0x004 /* Writing now will not block. */ 38 | 39 | # define POLLRDNORM 0x040 /* Normal data may be read. */ 40 | # define POLLRDBAND 0x080 /* Priority data may be read. */ 41 | # define POLLWRNORM 0x100 /* Writing now will not block. */ 42 | # define POLLWRBAND 0x200 /* Priority data may be written. */ 43 | 44 | /* Event types always implicitly polled. */ 45 | # define POLLERR 0x008 /* Error condition. */ 46 | # define POLLHUP 0x010 /* Hung up. */ 47 | # define POLLNVAL 0x020 /* Invalid polling request. */ 48 | 49 | # endif 50 | 51 | # ifdef __cplusplus 52 | extern "C" { 53 | # endif 54 | 55 | int poll(struct pollfd *pfds, nfds_t nfds, int timeout); 56 | 57 | # ifdef __cplusplus 58 | } 59 | # endif 60 | 61 | #endif /* HAVE_POLL */ 62 | 63 | #endif /* _UTIL_POLL_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-pwd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _PWD_H_ 19 | #define _PWD_H_ 20 | 21 | #include 22 | 23 | typedef int uid_t; 24 | typedef int gid_t; 25 | 26 | struct passwd { 27 | char *pw_name; /* user name */ 28 | char *pw_passwd; /* encrypted password */ 29 | uid_t pw_uid; /* user uid */ 30 | gid_t pw_gid; /* user gid */ 31 | time_t pw_change; /* password change time */ 32 | char *pw_class; /* user access class */ 33 | char *pw_gecos; /* Honeywell login info */ 34 | char *pw_dir; /* home directory */ 35 | char *pw_shell; /* default shell */ 36 | time_t pw_expire; /* account expiration */ 37 | }; 38 | 39 | uid_t getuid(); 40 | struct passwd *getpwuid(uid_t uid); 41 | 42 | #endif /* _PWD_H_ */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_SOCKET_H 19 | #define _UTIL_SOCKET_H 20 | 21 | #define WIN32_LEAN_AND_MEAN 22 | #include 23 | 24 | #define getsockopt(sockfd, level, optname, optval, optLen) \ 25 | getsockopt(sockfd, level, optname, (char *)optval, optLen) 26 | #define setsockopt(sockfd, level, optname, optval, optLen) \ 27 | setsockopt(sockfd, level, optname, (const char *)optval, optLen) 28 | #define send(sockfd, buf, len, flags) \ 29 | send(sockfd, (const char *)buf, len, flags) 30 | 31 | #ifdef interface 32 | # undef interface 33 | #endif /* interface */ 34 | 35 | static inline void 36 | win32_graceful_socket_close(SOCKET s) 37 | { 38 | char discard; 39 | 40 | shutdown(s, SD_SEND); 41 | (void) recv(s, &discard, sizeof(char), 0); 42 | closesocket(s); 43 | } 44 | 45 | #endif /* _UTIL_SOCKET_H */ 46 | -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-stat.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_STAT_H 19 | #define _UTIL_STAT_H 20 | 21 | #include 22 | 23 | #if (defined(_WIN32) || defined(__WIN32__)) 24 | # define mkdir(A, B) mkdir(A) 25 | #endif 26 | 27 | #endif /* _UTIL_STAT_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-statvfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_STATVFS_H 19 | #define _UTIL_STATVFS_H 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | typedef unsigned long fsblkcnt_t; 26 | typedef unsigned long fsfilcnt_t; 27 | 28 | struct statvfs { 29 | unsigned long f_bsize; /* Filesystem block size */ 30 | unsigned long f_frsize; /* Fragment size */ 31 | fsblkcnt_t f_blocks; /* * Size of fs in f_frsize units */ 32 | fsblkcnt_t f_bfree; /* Number of free blocks */ 33 | fsblkcnt_t f_bavail; /* * Number of free blocks for 34 | unprivileged users */ 35 | fsfilcnt_t f_files; /* Number of inodes */ 36 | fsfilcnt_t f_ffree; /* Number of free inodes */ 37 | fsfilcnt_t f_favail; /* Number of free inodes for 38 | unprivileged users */ 39 | unsigned long f_fsid; /* Filesystem ID */ 40 | unsigned long f_flag; /* Mount flags */ 41 | unsigned long f_namemax; /* Maximum filename length */ 42 | }; 43 | 44 | int statvfs(const char *__restrict path, struct statvfs *__restrict buf); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif /* __cplusplus */ 49 | 50 | #endif /* _UTIL_STATVFS_H */ 51 | -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_STDLIB_H 19 | #define _UTIL_STDLIB_H 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | int setenv(const char *name, const char *value, int overwrite); 26 | int unsetenv(const char *name); 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif /* __cplusplus */ 31 | 32 | #endif /* _UTIL_STDLIB_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-termios.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_TERMIOS_H 19 | #define _UTIL_TERMIOS_H 20 | 21 | #include 22 | 23 | typedef unsigned char cc_t; 24 | typedef unsigned int speed_t; 25 | typedef unsigned int tcflag_t; 26 | 27 | #define NCCS 32 28 | struct termios { 29 | tcflag_t c_iflag; 30 | tcflag_t c_oflag; 31 | tcflag_t c_cflag; 32 | tcflag_t c_lflag; 33 | cc_t c_cc[NCCS]; 34 | speed_t c_ispeed; 35 | speed_t c_ospeed; 36 | }; 37 | 38 | #define TCSANOW 0 39 | 40 | #define ICANON 2 41 | #define ECHO 8 42 | 43 | #define read read_noecho_noicanon 44 | 45 | ssize_t read_noecho_noicanon(int fd, void *buf, size_t count); 46 | int tcgetattr(int fd, struct termios *termios_p); 47 | int tcsetattr(int fd, int optional_actions, const struct termios *termios_p); 48 | 49 | #endif /* _UTIL_TERMIOS_H */ -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_TIME_H 19 | #define _UTIL_TIME_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #define gmtime_r(timep, result) gmtime_s(result, timep) 26 | #define localtime_r(timep, result) localtime_s(result, timep) 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif /* __cplusplus */ 31 | 32 | /* timeradd, timersub, timercmp were borrowed from the 33 | Standard GNU C Library */ 34 | #ifndef timercmp 35 | # define timercmp(a, b, CMP) \ 36 | (((a)->tv_sec == (b)->tv_sec) ? ((a)->tv_usec CMP(b)->tv_usec) \ 37 | : ((a)->tv_sec CMP(b)->tv_sec)) 38 | #endif /* timercmp */ 39 | 40 | #ifndef timeradd 41 | # define timeradd(a, b, result) \ 42 | do { \ 43 | (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ 44 | (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ 45 | if ((result)->tv_usec >= 1000000) { \ 46 | ++(result)->tv_sec; \ 47 | (result)->tv_usec -= 1000000; \ 48 | } \ 49 | } while (0) 50 | #endif /* timeradd */ 51 | 52 | #ifndef timersub 53 | # define timersub(a, b, result) \ 54 | do { \ 55 | (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 56 | (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 57 | if ((result)->tv_usec < 0) { \ 58 | --(result)->tv_sec; \ 59 | (result)->tv_usec += 1000000; \ 60 | } \ 61 | } while (0) 62 | #endif /* timersub */ 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif /* __cplusplus */ 67 | 68 | #endif /* _UTIL_TIME_H */ 69 | -------------------------------------------------------------------------------- /src/include/sigutils/util/win32-unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _UTIL_UNISTD_H 19 | #define _UTIL_UNISTD_H 20 | 21 | #include 22 | 23 | #include "win32-fcntl.h" 24 | 25 | #ifndef _SC_NPROCESSORS_ONLN 26 | # define _SC_NPROCESSORS_ONLN 84 27 | #endif /* _SC_NPROCESSORS_ONLN */ 28 | 29 | #define pipe(fds) _pipe(fds, 4096, _O_BINARY) 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif /* __cplusplus */ 34 | 35 | long sysconf(int name); 36 | int getpagesize(); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif /* __cplusplus */ 41 | 42 | #endif /* _UTIL_UNISTD_H */ 43 | -------------------------------------------------------------------------------- /src/include/sigutils/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2020 Gonzalo José Carracedo Carballal 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #ifndef _SIGUTILS_VERSION 19 | #define _SIGUTILS_VERSION 20 | 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif /* __cplusplus */ 26 | 27 | /* 28 | * Sigutils API uses semantic versioning (see https://semver.org/). 29 | * 30 | * Sigutils ABI follows the same strategy as Mongocxx (see 31 | * http://mongocxx.org/mongocxx-v3/api-abi-versioning/): ABI is a simple 32 | * scalar that is bumped on an incompatible ABI change (e.g. a function 33 | * becomes a macro or vice-versa). ABI additions DO NOT increment 34 | * the ABI number. 35 | */ 36 | 37 | /* API version macros */ 38 | #define SIGUTILS_VERSION_MAJOR 0 39 | #define SIGUTILS_VERSION_MINOR 3 40 | #define SIGUTILS_VERSION_PATCH 0 41 | 42 | /* ABI version macros */ 43 | #define SIGUTILS_ABI_VERSION 1 44 | 45 | /* Utility macros */ 46 | #define __SU_VN(num, shift) ((uint32_t)((uint8_t)(num)) << (shift)) 47 | 48 | #define SU_VER(major, minor, patch) \ 49 | (__SU_VN(major, 16) | __SU_VN(minor, 8) | __SU_VN(patch, 0)) 50 | 51 | #define SIGUTILS_VERSION \ 52 | SU_VER(SIGUTILS_VERSION_MAJOR, SIGUTILS_VERSION_MINOR, SIGUTILS_VERSION_PATCH) 53 | 54 | #define SIGUTILS_API_VERSION \ 55 | SU_VER(SIGUTILS_VERSION_MAJOR, SIGUTILS_VERSION_MINOR, 0) 56 | 57 | #define SIGUTILS_VERSION_STRING \ 58 | STRINGIFY(SIGUTILS_VERSION_MAJOR) \ 59 | "." STRINGIFY(SIGUTILS_VERSION_MINOR) "." STRINGIFY(SIGUTILS_VERSION_PATCH) 60 | 61 | unsigned int sigutils_abi_version(void); 62 | const char *sigutils_api_version(void); 63 | const char *sigutils_pkgversion(void); 64 | 65 | void sigutils_abi_check(unsigned int); 66 | 67 | #define SIGUTILS_ABI_CHECK() sigutils_abi_check(SIGUTILS_ABI_VERSION) 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif /* __cplusplus */ 72 | 73 | #endif /* _SIGUTILS_VERSION */ 74 | -------------------------------------------------------------------------------- /src/sigutils/agc.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | SU_CONSTRUCTOR(su_agc, const struct su_agc_params *params) 28 | { 29 | memset(self, 0, sizeof(su_agc_t)); 30 | 31 | SU_ALLOCATE_MANY_FAIL(self->mag_history, params->mag_history_size, SUFLOAT); 32 | 33 | SU_ALLOCATE_MANY_FAIL(self->delay_line, params->delay_line_size, SUCOMPLEX); 34 | 35 | self->mag_history_size = params->mag_history_size; 36 | self->delay_line_size = params->delay_line_size; 37 | self->knee = params->threshold; 38 | self->hang_max = params->hang_max; 39 | self->gain_slope = params->slope_factor * 1e-2; 40 | self->fast_alpha_rise = 1 - SU_EXP(-1. / params->fast_rise_t); 41 | self->fast_alpha_fall = 1 - SU_EXP(-1. / params->fast_fall_t); 42 | self->slow_alpha_rise = 1 - SU_EXP(-1. / params->slow_rise_t); 43 | self->slow_alpha_fall = 1 - SU_EXP(-1. / params->slow_fall_t); 44 | self->fixed_gain = SU_MAG_RAW(self->knee * (self->gain_slope - 1)); 45 | 46 | self->enabled = SU_TRUE; 47 | 48 | return SU_TRUE; 49 | 50 | fail: 51 | SU_DESTRUCT(su_agc, self); 52 | 53 | return SU_FALSE; 54 | } 55 | 56 | SU_DESTRUCTOR(su_agc) 57 | { 58 | if (self->mag_history != NULL) 59 | free(self->mag_history); 60 | 61 | if (self->delay_line != NULL) 62 | free(self->delay_line); 63 | } 64 | 65 | /* 66 | * AGC Algorithm (inspired by GQRX's AGC) 67 | * 68 | * 1. Put x in delay buffer and magnitude in dBs 69 | * 2. Retrieve oldest sample and magnitude in dBs. 70 | * 3. Compute peak value. 71 | * 4. Update averagers 72 | * 5. In decay averager: update only if hangtime has elapsed 73 | * 6. Get magnitude from the biggest of both averagers 74 | * 7. Output sample 75 | */ 76 | 77 | SU_METHOD(su_agc, SUCOMPLEX, feed, SUCOMPLEX x) 78 | { 79 | unsigned int i; 80 | 81 | SUCOMPLEX x_delayed; 82 | SUFLOAT x_dBFS; 83 | SUFLOAT x_dBFS_delayed; 84 | SUFLOAT peak_delta; 85 | 86 | /* Push sample */ 87 | x_delayed = self->delay_line[self->delay_line_ptr]; 88 | 89 | self->delay_line[self->delay_line_ptr++] = x; 90 | if (self->delay_line_ptr >= self->delay_line_size) 91 | self->delay_line_ptr = 0; 92 | 93 | if (self->enabled) { 94 | x_dBFS = .5 * SU_DB(x * SU_C_CONJ(x)) - SUFLOAT_MAX_REF_DB; 95 | 96 | /* Push mag */ 97 | x_dBFS_delayed = self->mag_history[self->mag_history_ptr]; 98 | 99 | self->mag_history[self->mag_history_ptr++] = x_dBFS; 100 | if (self->mag_history_ptr >= self->mag_history_size) 101 | self->mag_history_ptr = 0; 102 | 103 | if (x_dBFS > self->peak) 104 | self->peak = x_dBFS; 105 | else if (self->peak == x_dBFS_delayed) { 106 | /* 107 | * We've just removed the peak value from the magnitude history, we 108 | * need to recalculate the current peak value. 109 | */ 110 | self->peak = SUFLOAT_MIN_REF_DB; 111 | 112 | for (i = 0; i < self->mag_history_size; ++i) { 113 | if (self->peak < self->mag_history[i]) 114 | self->peak = self->mag_history[i]; 115 | } 116 | } 117 | 118 | /* Update levels for fast averager */ 119 | peak_delta = self->peak - self->fast_level; 120 | if (peak_delta > 0) 121 | self->fast_level += self->fast_alpha_rise * peak_delta; 122 | else 123 | self->fast_level += self->fast_alpha_fall * peak_delta; 124 | 125 | /* Update levels for slow averager */ 126 | peak_delta = self->peak - self->slow_level; 127 | if (peak_delta > 0) { 128 | self->slow_level += self->slow_alpha_rise * peak_delta; 129 | self->hang_n = 0; 130 | } else if (self->hang_n >= self->hang_max) 131 | self->slow_level += self->slow_alpha_fall * peak_delta; 132 | else 133 | ++self->hang_n; 134 | 135 | /* Keep biggest magnitude */ 136 | x_dBFS_delayed = SU_MAX(self->fast_level, self->slow_level); 137 | 138 | /* Is AGC on? */ 139 | if (x_dBFS_delayed < self->knee) 140 | x_delayed *= self->fixed_gain; 141 | else 142 | x_delayed *= SU_MAG_RAW(x_dBFS_delayed * (self->gain_slope - 1)); 143 | 144 | x_delayed *= SU_AGC_RESCALE; 145 | } 146 | 147 | return x_delayed; 148 | } 149 | -------------------------------------------------------------------------------- /src/sigutils/block.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #define SU_LOG_LEVEL "block" 24 | 25 | #include 26 | #include 27 | 28 | /****************************** su_stream API ********************************/ 29 | SU_CONSTRUCTOR(su_stream, SUSCOUNT size) 30 | { 31 | SUSCOUNT i = 0; 32 | 33 | memset(self, 0, sizeof(su_stream_t)); 34 | 35 | SU_ALLOCATE_MANY_CATCH(self->buffer, size, SUCOMPLEX, return SU_FALSE); 36 | 37 | /* Populate uninitialized buffer with NaNs */ 38 | for (i = 0; i < size; ++i) 39 | self->buffer[i] = nan("uninitialized"); 40 | 41 | self->size = size; 42 | self->ptr = 0; 43 | self->avail = 0; 44 | self->pos = 0ull; 45 | 46 | return SU_TRUE; 47 | } 48 | 49 | SU_DESTRUCTOR(su_stream) 50 | { 51 | if (self->buffer != NULL) 52 | free(self->buffer); 53 | } 54 | 55 | SU_METHOD(su_stream, void, write, const SUCOMPLEX *data, SUSCOUNT size) 56 | { 57 | SUSCOUNT skip = 0; 58 | SUSCOUNT chunksz; 59 | 60 | /* 61 | * We increment this always. Current reading position is 62 | * stream->pos - stream->avail 63 | */ 64 | self->pos += size; 65 | 66 | if (size > self->size) { 67 | SU_WARNING("write will overflow stream, keeping latest samples\n"); 68 | 69 | skip = size - self->size; 70 | data += skip; 71 | size -= skip; 72 | } 73 | 74 | if ((chunksz = self->size - self->ptr) > size) 75 | chunksz = size; 76 | 77 | /* This needs to be updated only once */ 78 | if (self->avail < self->size) 79 | self->avail += chunksz; 80 | 81 | memcpy(self->buffer + self->ptr, data, chunksz * sizeof(SUCOMPLEX)); 82 | self->ptr += chunksz; 83 | 84 | /* Rollover only can happen here */ 85 | if (self->ptr == self->size) { 86 | self->ptr = 0; 87 | 88 | /* Is there anything left to be written? */ 89 | if (size > 0) { 90 | size -= chunksz; 91 | data += chunksz; 92 | 93 | memcpy(self->buffer + self->ptr, data, size * sizeof(SUCOMPLEX)); 94 | self->ptr += size; 95 | } 96 | } 97 | } 98 | 99 | SU_GETTER(su_stream, su_off_t, tell) 100 | { 101 | return self->pos - self->avail; 102 | } 103 | 104 | SU_GETTER(su_stream, SUSCOUNT, get_contiguous, SUCOMPLEX **start, SUSCOUNT size) 105 | { 106 | SUSCOUNT avail = self->size - self->ptr; 107 | 108 | if (size > avail) { 109 | size = avail; 110 | } 111 | 112 | *start = self->buffer + self->ptr; 113 | 114 | return size; 115 | } 116 | 117 | SU_METHOD(su_stream, SUSCOUNT, advance_contiguous, SUSCOUNT size) 118 | { 119 | SUSCOUNT avail = self->size - self->ptr; 120 | 121 | if (size > avail) { 122 | size = avail; 123 | } 124 | 125 | self->pos += size; 126 | self->ptr += size; 127 | if (self->avail < self->size) { 128 | self->avail += size; 129 | } 130 | 131 | /* Rollover */ 132 | if (self->ptr == self->size) { 133 | self->ptr = 0; 134 | } 135 | 136 | return size; 137 | } 138 | 139 | SU_GETTER( 140 | su_stream, 141 | SUSDIFF, 142 | read, 143 | su_off_t off, 144 | SUCOMPLEX *data, 145 | SUSCOUNT size) 146 | { 147 | SUSCOUNT avail; 148 | su_off_t readpos = su_stream_tell(self); 149 | SUSCOUNT reloff; 150 | SUSCOUNT chunksz; 151 | SUSDIFF ptr; 152 | 153 | /* Slow reader */ 154 | if (off < readpos) 155 | return -1; 156 | 157 | /* Greedy reader */ 158 | if (off >= self->pos) 159 | return 0; 160 | 161 | reloff = off - readpos; 162 | 163 | /* Compute how many samples are available from here */ 164 | avail = self->avail - reloff; 165 | if (avail < size) { 166 | size = avail; 167 | } 168 | 169 | /* Compute position in the stream buffer to read from */ 170 | if ((ptr = self->ptr - avail) < 0) 171 | ptr += self->size; 172 | 173 | /* Adjust in case reloff causes ptr to rollover */ 174 | if (ptr > self->size) 175 | ptr = ptr - self->size; 176 | 177 | if (ptr + size > self->size) 178 | chunksz = self->size - ptr; 179 | else 180 | chunksz = size; 181 | 182 | memcpy(data, self->buffer + ptr, chunksz * sizeof(SUCOMPLEX)); 183 | size -= chunksz; 184 | 185 | /* Is there anything left to read? */ 186 | if (size > 0) 187 | memcpy(data + chunksz, self->buffer, size * sizeof(SUCOMPLEX)); 188 | 189 | return chunksz + size; 190 | } 191 | -------------------------------------------------------------------------------- /src/sigutils/clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #define SU_LOG_LEVEL "clock" 23 | 24 | #include 25 | #include 26 | 27 | 28 | /* 29 | * Fixed sampler 30 | */ 31 | 32 | SU_CONSTRUCTOR(su_sampler, SUFLOAT bnor) 33 | { 34 | SU_TRYCATCH(bnor >= 0, return SU_FALSE); 35 | 36 | self->bnor = bnor; 37 | if (bnor > 0) 38 | self->period = 1. / bnor; 39 | else 40 | self->period = 0; 41 | 42 | self->phase = 0; 43 | self->prev = 0; 44 | self->phase0_rel = 0; 45 | 46 | return SU_TRUE; 47 | } 48 | 49 | SU_METHOD(su_sampler, SUBOOL, set_rate, SUFLOAT bnor) 50 | { 51 | SU_TRYCATCH(bnor >= 0, return SU_FALSE); 52 | 53 | self->bnor = bnor; 54 | if (bnor > 0) { 55 | self->period = 1. / bnor; 56 | if (self->phase > self->period) 57 | self->phase -= self->period * SU_FLOOR(self->phase / self->period); 58 | 59 | self->phase0 = self->phase0_rel * self->period; 60 | } else { 61 | self->period = 0; 62 | } 63 | 64 | return SU_TRUE; 65 | } 66 | 67 | /* Phase is always set in a relative fashion */ 68 | SU_METHOD(su_sampler, void, set_phase, SUFLOAT phase) 69 | { 70 | if (phase > 1) 71 | phase -= SU_FLOOR(phase); 72 | 73 | self->phase = self->period * phase; 74 | } 75 | 76 | SU_DESTRUCTOR(su_sampler) 77 | { /* No-op */ 78 | } 79 | 80 | /* 81 | * Clock detector 82 | */ 83 | 84 | SU_DESTRUCTOR(su_clock_detector) 85 | { 86 | su_stream_finalize(&self->sym_stream); 87 | } 88 | 89 | SU_CONSTRUCTOR( 90 | su_clock_detector, 91 | SUFLOAT loop_gain, 92 | SUFLOAT bhint, 93 | SUSCOUNT bufsiz) 94 | { 95 | memset(self, 0, sizeof(su_clock_detector_t)); 96 | 97 | SU_CONSTRUCT_FAIL(su_stream, &self->sym_stream, bufsiz); 98 | 99 | self->alpha = SU_PREFERED_CLOCK_ALPHA; 100 | self->beta = SU_PREFERED_CLOCK_BETA; 101 | self->algo = SU_CLOCK_DETECTOR_ALGORITHM_GARDNER; 102 | self->phi = .25; 103 | self->bnor = bhint; 104 | self->bmin = 0; 105 | self->bmax = 1; 106 | self->gain = loop_gain; /* Somehow this parameter is critical */ 107 | 108 | return SU_TRUE; 109 | 110 | fail: 111 | SU_DESTRUCT(su_clock_detector, self); 112 | 113 | return SU_FALSE; 114 | } 115 | 116 | SU_METHOD(su_clock_detector, void, set_baud, SUFLOAT bnor) 117 | { 118 | self->bnor = bnor; 119 | self->phi = 0; 120 | memset(self->x, 0, sizeof(self->x)); 121 | } 122 | 123 | SU_METHOD(su_clock_detector, SUBOOL, set_bnor_limits, SUFLOAT lo, SUFLOAT hi) 124 | { 125 | if (lo > hi) { 126 | SU_ERROR("Invalid baud rate limits\n"); 127 | return SU_FALSE; 128 | } 129 | 130 | if (self->bnor < self->bmin) { 131 | self->bnor = self->bmin; 132 | } else if (self->bnor > self->bmax) { 133 | self->bnor = self->bmax; 134 | } 135 | 136 | return SU_TRUE; 137 | } 138 | 139 | SU_METHOD(su_clock_detector, void, feed, SUCOMPLEX val) 140 | { 141 | SUFLOAT alpha; 142 | SUFLOAT e; 143 | SUCOMPLEX p; 144 | 145 | if (self->algo == SU_CLOCK_DETECTOR_ALGORITHM_NONE) { 146 | SU_ERROR("Invalid clock detector\n"); 147 | return; 148 | } 149 | 150 | /* Increment phase */ 151 | self->phi += self->bnor; 152 | 153 | switch (self->algo) { 154 | case SU_CLOCK_DETECTOR_ALGORITHM_GARDNER: 155 | if (self->phi >= .5) { 156 | /* Toggle halfcycle flag */ 157 | self->halfcycle = !self->halfcycle; 158 | 159 | /* Interpolate between this and previous sample */ 160 | alpha = self->bnor * (self->phi - .5); 161 | 162 | p = (1 - alpha) * val + alpha * self->prev; 163 | 164 | self->phi -= .5; 165 | if (!self->halfcycle) { 166 | self->x[2] = self->x[0]; 167 | self->x[0] = p; 168 | 169 | /* Compute error signal */ 170 | e = self->gain 171 | * SU_C_REAL(SU_C_CONJ(self->x[1]) * (self->x[0] - self->x[2])); 172 | self->e = e; 173 | /* Adjust phase and frequency */ 174 | self->phi += self->alpha * e; 175 | self->bnor += self->beta * e; 176 | 177 | /* Check that current baudrate is within some reasonable limits */ 178 | if (self->bnor > self->bmax) 179 | self->bnor = self->bmax; 180 | if (self->bnor < self->bmin) 181 | self->bnor = self->bmin; 182 | 183 | su_stream_write(&self->sym_stream, &p, 1); 184 | } else { 185 | self->x[1] = p; 186 | } 187 | } 188 | break; 189 | 190 | default: 191 | SU_ERROR("Unsupported clock detection algorithm\n"); 192 | } 193 | 194 | self->prev = val; 195 | } 196 | 197 | SU_METHOD(su_clock_detector, SUSDIFF, read, SUCOMPLEX *buf, size_t size) 198 | { 199 | SUSDIFF result = 0; 200 | 201 | result = su_stream_read(&self->sym_stream, self->sym_stream_pos, buf, size); 202 | 203 | if (result < 0) { 204 | SU_WARNING("Symbols lost, resync requested\n"); 205 | self->sym_stream_pos = su_stream_tell(&self->sym_stream); 206 | result = 0; 207 | } 208 | 209 | self->sym_stream_pos += result; 210 | 211 | return result; 212 | } 213 | -------------------------------------------------------------------------------- /src/sigutils/dc_corrector.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2023 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | 24 | SU_METHOD(su_dc_corrector, SUBOOL, init_with_training_period, SUSCOUNT train) 25 | { 26 | memset(self, 0, sizeof (su_dc_corrector_t)); 27 | 28 | self->soft_dc_train_samples = train; 29 | self->training = SU_TRUE; 30 | 31 | return SU_TRUE; 32 | } 33 | 34 | SU_METHOD(su_dc_corrector, SUBOOL, init_with_alpha, SUFLOAT alpha) 35 | { 36 | memset(self, 0, sizeof (su_dc_corrector_t)); 37 | 38 | self->soft_dc_alpha = alpha; 39 | self->training = SU_TRUE; 40 | self->have_dc_offset = SU_TRUE; 41 | 42 | return SU_TRUE; 43 | } 44 | 45 | SU_METHOD(su_dc_corrector, void, set_training_state, SUBOOL enabled) 46 | { 47 | self->training = enabled; 48 | } 49 | 50 | SU_METHOD(su_dc_corrector, void, reset) 51 | { 52 | self->soft_dc_count = 0; 53 | self->dc_offset = 0; 54 | self->dc_c = 0; 55 | 56 | if (self->soft_dc_train_samples > 0) 57 | self->have_dc_offset = SU_FALSE; 58 | } 59 | 60 | SU_METHOD(su_dc_corrector, void, correct, SUCOMPLEX *buffer, SUSCOUNT result) 61 | { 62 | SUCOMPLEX y, c, t, sum; 63 | SUSCOUNT i; 64 | 65 | if (self->training) { 66 | c = self->dc_c; 67 | sum = self->dc_offset; 68 | 69 | for (i = 0; i < result; ++i) { 70 | y = buffer[i] - c; 71 | t = sum + y; 72 | c = (t - sum) - y; 73 | sum = t; 74 | } 75 | 76 | if (self->soft_dc_train_samples > 0) { 77 | /* Correction based on training samples */ 78 | self->dc_c = c; 79 | self->dc_offset = sum; 80 | self->soft_dc_count += result; 81 | 82 | if (self->soft_dc_count > self->soft_dc_train_samples) { 83 | self->dc_offset /= self->soft_dc_count; 84 | self->training = SU_FALSE; 85 | self->have_dc_offset = SU_TRUE; 86 | } 87 | } else { 88 | /* Correction based on single-pole filters */ 89 | SU_SPLPF_FEED(self->dc_offset, sum / result, self->soft_dc_alpha); 90 | } 91 | } 92 | 93 | if (self->have_dc_offset) 94 | for (i = 0; i < result; ++i) 95 | buffer[i] -= self->dc_offset; 96 | } 97 | -------------------------------------------------------------------------------- /src/sigutils/equalizer.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | SUPRIVATE void 28 | su_equalizer_push_x(su_equalizer_t *eq, SUCOMPLEX x) 29 | { 30 | eq->x[eq->ptr++] = x; 31 | if (eq->ptr >= eq->params.length) 32 | eq->ptr = 0; 33 | } 34 | 35 | SUPRIVATE SUCOMPLEX 36 | su_equalizer_eval(const su_equalizer_t *eq) 37 | { 38 | SUCOMPLEX y = 0; 39 | unsigned int i; 40 | int p; 41 | 42 | /* Input feedback */ 43 | p = eq->ptr - 1; 44 | for (i = 0; i < eq->params.length; ++i) { 45 | if (p < 0) 46 | p += eq->params.length; 47 | 48 | y += eq->w[i] * eq->x[p--]; 49 | } 50 | 51 | return y; 52 | } 53 | 54 | SUPRIVATE void 55 | su_equalizer_update_weights(su_equalizer_t *eq, SUCOMPLEX y) 56 | { 57 | unsigned int i; 58 | int p; 59 | SUCOMPLEX y2; 60 | SUCOMPLEX err; 61 | 62 | y2 = y * SU_C_CONJ(y); 63 | err = y * (y2 - 1.); 64 | 65 | p = eq->ptr - 1; 66 | for (i = 0; i < eq->params.length; ++i) { 67 | if (p < 0) 68 | p += eq->params.length; 69 | 70 | eq->w[i] -= eq->params.mu * SU_C_CONJ(eq->x[p--]) * err; 71 | } 72 | } 73 | 74 | SUBOOL 75 | su_equalizer_init( 76 | su_equalizer_t *eq, 77 | const struct sigutils_equalizer_params *params) 78 | { 79 | memset(eq, 0, sizeof(su_equalizer_t)); 80 | 81 | eq->params = *params; 82 | 83 | SU_TRYCATCH(eq->w = calloc(sizeof(SUCOMPLEX), params->length), goto fail); 84 | SU_TRYCATCH(eq->x = calloc(sizeof(SUCOMPLEX), params->length), goto fail); 85 | 86 | eq->w[0] = 1.; /* Identity */ 87 | 88 | return SU_TRUE; 89 | 90 | fail: 91 | su_equalizer_finalize(eq); 92 | 93 | return SU_FALSE; 94 | } 95 | 96 | void 97 | su_equalizer_reset(su_equalizer_t *eq) 98 | { 99 | memset(eq->w, 0, sizeof(SUCOMPLEX) * eq->params.length); 100 | 101 | eq->w[0] = 1.; 102 | } 103 | 104 | SUCOMPLEX 105 | su_equalizer_feed(su_equalizer_t *eq, SUCOMPLEX x) 106 | { 107 | SUCOMPLEX y; 108 | 109 | su_equalizer_push_x(eq, x); 110 | y = su_equalizer_eval(eq); 111 | 112 | su_equalizer_update_weights(eq, y); 113 | 114 | return y; 115 | } 116 | 117 | void 118 | su_equalizer_finalize(su_equalizer_t *eq) 119 | { 120 | if (eq->x != NULL) 121 | free(eq->x); 122 | 123 | if (eq->w != NULL) 124 | free(eq->w); 125 | } 126 | -------------------------------------------------------------------------------- /src/sigutils/lfsr.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2017 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #define SU_LOG_LEVEL "lfsr" 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | SUBOOL 29 | su_lfsr_init_coef(su_lfsr_t *lfsr, const SUBITS *coef, SUSCOUNT order) 30 | { 31 | memset(lfsr, 0, sizeof(su_lfsr_t)); 32 | 33 | SU_TRYCATCH(lfsr->coef = malloc(order * sizeof(SUBITS)), goto fail); 34 | 35 | SU_TRYCATCH(lfsr->buffer = calloc(order, sizeof(SUBITS)), goto fail); 36 | 37 | memcpy(lfsr->coef, coef, order * sizeof(SUBITS)); 38 | lfsr->order = order; 39 | 40 | return SU_TRUE; 41 | 42 | fail: 43 | su_lfsr_finalize(lfsr); 44 | 45 | return SU_FALSE; 46 | } 47 | 48 | void 49 | su_lfsr_finalize(su_lfsr_t *lfsr) 50 | { 51 | if (lfsr->coef != NULL) 52 | free(lfsr->coef); 53 | 54 | if (lfsr->buffer != NULL) 55 | free(lfsr->buffer); 56 | } 57 | 58 | void 59 | su_lfsr_set_mode(su_lfsr_t *lfsr, enum su_lfsr_mode mode) 60 | { 61 | lfsr->mode = mode; 62 | } 63 | 64 | /* 65 | * There is a common part for both additive and multiplicative 66 | * descramblers, related to the shift register. 67 | * 68 | * Assuming that we have some function with memory F(P, x) which 69 | * returns the evaluation of some Z2 polynomial P taking x 70 | * as the new element in the shift reg: 71 | * 72 | * ADDITIVE DESCRAMBLER: 73 | * y = F(P, F_prev) ^ x 74 | * 75 | * MULTIPLICATIVE DESCRAMBLER: 76 | * y = F(P, x) ^ x 77 | * 78 | */ 79 | SUINLINE SUBITS 80 | su_lfsr_transfer(su_lfsr_t *lfsr, SUBITS x) 81 | { 82 | SUBITS F = 0; 83 | uint64_t i; 84 | uint64_t n = lfsr->p; 85 | 86 | for (i = 1; i < lfsr->order; ++i) { 87 | if (++n == lfsr->order) 88 | n = 0; 89 | 90 | if (lfsr->coef[i]) 91 | F ^= lfsr->buffer[n]; 92 | } 93 | 94 | /* 95 | * When we leave the loop (i.e. when i = order), 96 | * n = (p + order - 1) % order = (p - 1) % order 97 | */ 98 | lfsr->buffer[lfsr->p] = x; 99 | lfsr->p = n; 100 | 101 | return F; 102 | } 103 | 104 | void 105 | su_lfsr_set_buffer(su_lfsr_t *lfsr, const SUBITS *seq) 106 | { 107 | unsigned int i; 108 | 109 | for (i = 0; i < lfsr->order; ++i) 110 | lfsr->buffer[lfsr->order - i - 1] = seq[i]; 111 | lfsr->p = lfsr->order - 1; 112 | } 113 | 114 | SUBITS 115 | su_lfsr_feed(su_lfsr_t *lfsr, SUBITS x) 116 | { 117 | SUBITS y; 118 | x = !!x; 119 | 120 | switch (lfsr->mode) { 121 | case SU_LFSR_MODE_ADDITIVE: 122 | lfsr->F_prev = su_lfsr_transfer(lfsr, lfsr->F_prev); 123 | y = lfsr->F_prev ^ x; 124 | break; 125 | 126 | case SU_LFSR_MODE_MULTIPLICATIVE: 127 | y = su_lfsr_transfer(lfsr, x) ^ x; 128 | break; 129 | 130 | default: 131 | y = SU_NOSYMBOL; 132 | } 133 | 134 | return y; 135 | } 136 | 137 | void 138 | su_lfsr_blind_sync_reset(su_lfsr_t *lfsr) 139 | { 140 | lfsr->zeroes = 0; 141 | su_lfsr_set_mode(lfsr, SU_LFSR_MODE_MULTIPLICATIVE); 142 | memset(lfsr->buffer, 0, lfsr->order * sizeof(SUBITS)); 143 | } 144 | 145 | SUBITS 146 | su_lfsr_blind_sync_feed(su_lfsr_t *lfsr, SUBITS x) 147 | { 148 | SUBITS y = x; 149 | 150 | y = su_lfsr_feed(lfsr, x); 151 | 152 | /* LFSR running in scan mode */ 153 | if (lfsr->mode == SU_LFSR_MODE_MULTIPLICATIVE) { 154 | if (y != 0) 155 | lfsr->zeroes = 0; 156 | else if (++lfsr->zeroes == 2 * lfsr->order) { 157 | /* Synchronization sequence found! Switch to additive */ 158 | su_lfsr_set_mode(lfsr, SU_LFSR_MODE_ADDITIVE); 159 | printf("Sync sequence found!\n"); 160 | lfsr->zeroes = 0; 161 | } 162 | } 163 | 164 | return y; 165 | } 166 | -------------------------------------------------------------------------------- /src/sigutils/lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #define SU_LOG_LEVEL "lib" 23 | 24 | #include 25 | #include 26 | 27 | #define SU_MIN_PRECALC_FFT_EXP 9 /* 512 bin FFT */ 28 | #define SU_MAX_PRECALC_FFT_EXP 20 /* 1M bin FFT */ 29 | 30 | SUPRIVATE SUBOOL g_fftw_init = SU_FALSE; 31 | SUPRIVATE SUBOOL g_su_log_cr = SU_TRUE; 32 | SUPRIVATE SUBOOL g_su_measure_ffts = SU_FALSE; 33 | SUPRIVATE char *g_su_wisdom_file = NULL; 34 | SUPRIVATE pthread_mutex_t g_fft_plan_mutex = PTHREAD_MUTEX_INITIALIZER; 35 | 36 | SUPRIVATE char 37 | su_log_severity_to_char(enum sigutils_log_severity sev) 38 | { 39 | const char *sevstr = "di!ex"; 40 | 41 | if (sev < 0 || sev > SU_LOG_SEVERITY_CRITICAL) 42 | return '?'; 43 | 44 | return sevstr[sev]; 45 | } 46 | 47 | SUPRIVATE void 48 | su_log_func_default(void *private, const struct sigutils_log_message *msg) 49 | { 50 | SUBOOL *cr = (SUBOOL *)private; 51 | size_t msglen; 52 | 53 | if (*cr) 54 | fprintf( 55 | stderr, 56 | "[%c] %s:%u: ", 57 | su_log_severity_to_char(msg->severity), 58 | msg->function, 59 | msg->line); 60 | 61 | msglen = strlen(msg->message); 62 | 63 | *cr = msg->message[msglen - 1] == '\n' || msg->message[msglen - 1] == '\r'; 64 | 65 | fputs(msg->message, stderr); 66 | } 67 | 68 | /* Log config */ 69 | SUPRIVATE struct sigutils_log_config g_su_lib_log_config = { 70 | &g_su_log_cr, /* private */ 71 | SU_TRUE, /* exclusive */ 72 | su_log_func_default, /* log_func */ 73 | }; 74 | 75 | SUBOOL 76 | su_lib_is_using_wisdom(void) 77 | { 78 | return g_su_measure_ffts; 79 | } 80 | 81 | SUBOOL 82 | su_lib_set_wisdom_enabled(SUBOOL enabled) 83 | { 84 | if (g_su_wisdom_file == NULL) { 85 | SU_ERROR("Not enabling FFT wisdom: wisdom file path not set\n"); 86 | enabled = SU_FALSE; 87 | } 88 | 89 | g_su_measure_ffts = enabled; 90 | 91 | return SU_TRUE; 92 | } 93 | 94 | SUBOOL 95 | su_lib_set_wisdom_file(const char *cpath) 96 | { 97 | SUBOOL ok = SU_FALSE; 98 | char *path = NULL; 99 | 100 | SU_FFTW(_forget_wisdom)(); 101 | 102 | if (cpath != NULL) { 103 | SU_TRY(path = strbuild(cpath)); 104 | if (!SU_FFTW(_import_wisdom_from_filename) (path)) { 105 | SU_INFO("No previous FFT wisdom found (yet)\n"); 106 | } 107 | } else { 108 | g_su_measure_ffts = SU_FALSE; 109 | } 110 | 111 | if (g_su_wisdom_file != NULL) 112 | free(g_su_wisdom_file); 113 | 114 | g_su_wisdom_file = path; 115 | 116 | ok = SU_TRUE; 117 | 118 | done: 119 | return ok; 120 | } 121 | 122 | SUBOOL 123 | su_lib_save_wisdom(void) 124 | { 125 | if (g_su_wisdom_file != NULL) 126 | return SU_FFTW(_export_wisdom_to_filename) (g_su_wisdom_file); 127 | 128 | return SU_TRUE; 129 | } 130 | 131 | int 132 | su_lib_fftw_strategy(void) 133 | { 134 | return g_su_measure_ffts ? FFTW_MEASURE : FFTW_ESTIMATE; 135 | } 136 | 137 | SU_FFTW(_plan) 138 | su_lib_plan_dft_1d(int n, SU_FFTW(_complex) *in, SU_FFTW(_complex) *out, 139 | int sign, unsigned flags) 140 | { 141 | SU_FFTW(_plan) plan = NULL; 142 | SUBOOL mutex_acquired = SU_FALSE; 143 | int nthreads; 144 | 145 | if (n < 32768) 146 | nthreads = 1; 147 | else if (n == 32768) 148 | nthreads = 2; 149 | else 150 | nthreads = 4; 151 | 152 | SU_TRYZ(pthread_mutex_lock(&g_fft_plan_mutex)); 153 | mutex_acquired = SU_TRUE; 154 | 155 | SU_FFTW(_plan_with_nthreads)(nthreads); 156 | SU_TRY(plan = SU_FFTW(_plan_dft_1d)(n, in, out, sign, flags)); 157 | 158 | done: 159 | if (mutex_acquired) { 160 | SU_FFTW(_plan_with_nthreads)(1); 161 | pthread_mutex_unlock(&g_fft_plan_mutex); 162 | } 163 | 164 | return plan; 165 | } 166 | 167 | void 168 | su_lib_gen_wisdom(void) 169 | { 170 | unsigned e; 171 | int size; 172 | SU_FFTW(_complex) *buffer = NULL; 173 | 174 | SU_TRY(buffer = SU_FFTW(_malloc) ((1 << 20) * sizeof(SUCOMPLEX))); 175 | 176 | for (e = SU_MIN_PRECALC_FFT_EXP; e <= SU_MAX_PRECALC_FFT_EXP; ++e) { 177 | size = 1 << e; 178 | 179 | SU_FFTW(_plan) plan = su_lib_plan_dft_1d( 180 | size, 181 | buffer, 182 | buffer, 183 | FFTW_FORWARD, 184 | FFTW_MEASURE); 185 | 186 | if (plan != NULL) 187 | SU_FFTW(_destroy_plan) (plan); 188 | } 189 | 190 | done: 191 | if (buffer != NULL) 192 | SU_FFTW(_free)(buffer); 193 | } 194 | 195 | SUBOOL 196 | su_lib_init_ex(const struct sigutils_log_config *logconfig) 197 | { 198 | if (logconfig != NULL) 199 | su_log_init(logconfig); 200 | 201 | if (!g_fftw_init) { 202 | SU_FFTW(_init_threads)(); 203 | SU_FFTW(_make_planner_thread_safe)(); 204 | g_fftw_init = SU_TRUE; 205 | } 206 | 207 | return SU_TRUE; 208 | } 209 | 210 | SUBOOL 211 | su_lib_init(void) 212 | { 213 | return su_lib_init_ex(&g_su_lib_log_config); 214 | } 215 | -------------------------------------------------------------------------------- /src/sigutils/property.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #define SU_LOG_LEVEL "property" 24 | 25 | #include 26 | #include 27 | 28 | /************************** su_block_property API ****************************/ 29 | su_property_t * 30 | su_property_new(const char *name, su_property_type_t type, SUBOOL m, void *p) 31 | { 32 | su_property_t *new = NULL; 33 | char *namedup = NULL; 34 | 35 | if ((new = malloc(sizeof(su_property_t))) == NULL) 36 | goto fail; 37 | 38 | if ((namedup = strdup(name)) == NULL) 39 | goto fail; 40 | 41 | new->mandatory = m; 42 | new->name = namedup; 43 | new->type = type; 44 | new->generic_ptr = p; 45 | 46 | return new; 47 | 48 | fail: 49 | if (new != NULL) 50 | free(new); 51 | 52 | if (namedup != NULL) 53 | free(namedup); 54 | 55 | return NULL; 56 | } 57 | 58 | void 59 | su_property_destroy(su_property_t *prop) 60 | { 61 | if (prop->name != NULL) 62 | free(prop->name); 63 | 64 | free(prop); 65 | } 66 | 67 | /************************** su_block_property_set API *************************/ 68 | void 69 | su_property_set_init(su_property_set_t *set) 70 | { 71 | memset(set, 0, sizeof(su_property_set_t)); 72 | } 73 | 74 | su_property_t * 75 | su_property_set_lookup(const su_property_set_t *set, const char *name) 76 | { 77 | su_property_t *this = NULL; 78 | 79 | FOR_EACH_PTR(this, set, property) 80 | if (strcmp(this->name, name) == 0) 81 | return this; 82 | 83 | return NULL; 84 | } 85 | 86 | const char * 87 | su_property_type_to_string(su_property_type_t type) 88 | { 89 | switch (type) { 90 | case SU_PROPERTY_TYPE_ANY: 91 | return "(any)"; 92 | 93 | case SU_PROPERTY_TYPE_BOOL: 94 | return "bool"; 95 | 96 | case SU_PROPERTY_TYPE_INTEGER: 97 | return "int"; 98 | 99 | case SU_PROPERTY_TYPE_FLOAT: 100 | return "float"; 101 | 102 | case SU_PROPERTY_TYPE_COMPLEX: 103 | return "complex"; 104 | 105 | case SU_PROPERTY_TYPE_OBJECT: 106 | return "object"; 107 | 108 | default: 109 | return "unknown"; 110 | } 111 | } 112 | 113 | su_property_t * 114 | __su_property_set_assert_property( 115 | su_property_set_t *set, 116 | const char *name, 117 | su_property_type_t type, 118 | SUBOOL mandatory) 119 | { 120 | su_property_t *prop = NULL; 121 | 122 | if ((prop = su_property_set_lookup(set, name)) == NULL) { 123 | if ((prop = su_property_new(name, type, mandatory, NULL)) == NULL) { 124 | SU_ERROR( 125 | "failed to create new %s property", 126 | su_property_type_to_string(type)); 127 | return NULL; 128 | } 129 | 130 | if (PTR_LIST_APPEND_CHECK(set->property, prop) == -1) { 131 | SU_ERROR( 132 | "failed to append new %s property", 133 | su_property_type_to_string(type)); 134 | su_property_destroy(prop); 135 | return NULL; 136 | } 137 | } else if (prop->type != type) { 138 | SU_ERROR( 139 | "property `%s' found, mismatching type (req: %s, found: %s)\n", 140 | name, 141 | su_property_type_to_string(type), 142 | su_property_type_to_string(prop->type)); 143 | return NULL; 144 | } 145 | 146 | return prop; 147 | } 148 | 149 | su_property_t * 150 | su_property_set_assert_property( 151 | su_property_set_t *set, 152 | const char *name, 153 | su_property_type_t type) 154 | { 155 | return __su_property_set_assert_property(set, name, type, SU_FALSE); 156 | } 157 | 158 | su_property_t * 159 | su_property_set_assert_mandatory_property( 160 | su_property_set_t *set, 161 | const char *name, 162 | su_property_type_t type) 163 | { 164 | return __su_property_set_assert_property(set, name, type, SU_TRUE); 165 | } 166 | 167 | void 168 | su_property_set_finalize(su_property_set_t *set) 169 | { 170 | su_property_t *this = NULL; 171 | 172 | FOR_EACH_PTR(this, set, property) 173 | su_property_destroy(this); 174 | 175 | if (set->property_list != NULL) 176 | free(set->property_list); 177 | } 178 | -------------------------------------------------------------------------------- /src/sigutils/softtune.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #define SU_LOG_DOMAIN "softtuner" 24 | 25 | #include 26 | #include 27 | 28 | void 29 | su_softtuner_params_adjust_to_channel( 30 | struct sigutils_softtuner_params *params, 31 | const struct sigutils_channel *channel) 32 | { 33 | SUFLOAT width; 34 | 35 | width = MAX(channel->f_hi - channel->f_lo, channel->bw); 36 | 37 | if ((params->decimation = .3 * SU_CEIL(params->samp_rate / width)) < 1) 38 | params->decimation = 1; 39 | 40 | params->bw = width; 41 | params->fc = channel->fc - channel->ft; 42 | } 43 | 44 | SUBOOL 45 | su_softtuner_init( 46 | su_softtuner_t *tuner, 47 | const struct sigutils_softtuner_params *params) 48 | { 49 | assert(params->samp_rate > 0); 50 | assert(params->decimation > 0); 51 | 52 | memset(tuner, 0, sizeof(su_softtuner_t)); 53 | 54 | tuner->params = *params; 55 | tuner->avginv = 1. / params->decimation; 56 | 57 | SU_TRYCATCH( 58 | su_stream_init(&tuner->output, SU_BLOCK_STREAM_BUFFER_SIZE), 59 | goto fail); 60 | 61 | su_ncqo_init_fixed( 62 | &tuner->lo, 63 | SU_ABS2NORM_FREQ(params->samp_rate, params->fc)); 64 | 65 | if (params->bw > 0.0) { 66 | SU_TRYCATCH( 67 | su_iir_bwlpf_init( 68 | &tuner->antialias, 69 | SU_SOFTTUNER_ANTIALIAS_ORDER, 70 | .5 * SU_ABS2NORM_FREQ(params->samp_rate, params->bw) 71 | * SU_SOFTTUNER_ANTIALIAS_EXTRA_BW), 72 | goto fail); 73 | tuner->filtered = SU_TRUE; 74 | } 75 | 76 | return SU_TRUE; 77 | 78 | fail: 79 | su_softtuner_finalize(tuner); 80 | 81 | return SU_FALSE; 82 | } 83 | 84 | SUSCOUNT 85 | su_softtuner_feed(su_softtuner_t *tuner, const SUCOMPLEX *input, SUSCOUNT size) 86 | { 87 | SUSCOUNT i = 0; 88 | SUCOMPLEX x; 89 | SUSCOUNT avail; 90 | SUCOMPLEX *buf; 91 | SUSCOUNT n = 0; 92 | 93 | avail = su_stream_get_contiguous( 94 | &tuner->output, 95 | &buf, 96 | SU_BLOCK_STREAM_BUFFER_SIZE); 97 | 98 | SU_TRYCATCH(avail > 0, return 0); 99 | 100 | buf[0] = 0; 101 | 102 | for (i = 0; i < size && n < avail; ++i) { 103 | /* Carrier centering. Must happen *before* decimation */ 104 | x = input[i] * SU_C_CONJ(su_ncqo_read(&tuner->lo)); 105 | 106 | if (tuner->filtered) 107 | x = su_iir_filt_feed(&tuner->antialias, x); 108 | 109 | if (tuner->params.decimation > 1) { 110 | if (++tuner->decim_ptr < tuner->params.decimation) { 111 | buf[n] += tuner->avginv * x; 112 | } else { 113 | if (++n < avail) 114 | buf[n] = 0; 115 | tuner->decim_ptr = 0; /* Reset decimation pointer */ 116 | } 117 | } else { 118 | buf[n++] = x; 119 | } 120 | } 121 | 122 | su_stream_advance_contiguous(&tuner->output, n); 123 | 124 | return i; 125 | } 126 | 127 | SUSDIFF 128 | su_softtuner_read(su_softtuner_t *tuner, SUCOMPLEX *out, SUSCOUNT size) 129 | { 130 | SUSDIFF result; 131 | 132 | result = su_stream_read(&tuner->output, tuner->read_ptr, out, size); 133 | 134 | if (result == -1) { 135 | SU_ERROR("Samples lost while reading from tuner!\n"); 136 | tuner->read_ptr = su_stream_tell(&tuner->output); 137 | return 0; 138 | } 139 | 140 | tuner->read_ptr += result; 141 | 142 | return result; 143 | } 144 | 145 | void 146 | su_softtuner_finalize(su_softtuner_t *tuner) 147 | { 148 | if (tuner->filtered) 149 | su_iir_filt_finalize(&tuner->antialias); 150 | 151 | su_stream_finalize(&tuner->output); 152 | 153 | memset(tuner, 0, sizeof(su_softtuner_t)); 154 | } 155 | -------------------------------------------------------------------------------- /src/sigutils/taps.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2016 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | /************************* Real window functions *****************************/ 26 | SUPRIVATE void 27 | su_taps_scale(SUFLOAT *h, SUFLOAT k, SUSCOUNT size) 28 | { 29 | unsigned int i; 30 | 31 | for (i = 0; i < size; ++i) 32 | h[i] *= k; 33 | } 34 | 35 | void 36 | su_taps_apply_hamming(SUFLOAT *h, SUSCOUNT size) 37 | { 38 | unsigned int i; 39 | 40 | for (i = 0; i < size; ++i) 41 | h[i] *= 42 | SU_HAMMING_ALPHA - SU_MAMMING_BETA * SU_COS(2 * M_PI * i / (size - 1)); 43 | } 44 | 45 | void 46 | su_taps_apply_hann(SUFLOAT *h, SUSCOUNT size) 47 | { 48 | unsigned int i; 49 | 50 | for (i = 0; i < size; ++i) 51 | h[i] *= SU_HANN_ALPHA - SU_HANN_BETA * SU_COS(2 * M_PI * i / (size - 1)); 52 | } 53 | 54 | void 55 | su_taps_apply_flat_top(SUFLOAT *h, SUSCOUNT size) 56 | { 57 | unsigned int i; 58 | 59 | for (i = 0; i < size; ++i) 60 | h[i] *= SU_FLAT_TOP_A0 - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) 61 | + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) 62 | - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) 63 | + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); 64 | } 65 | 66 | void 67 | su_taps_apply_blackmann_harris(SUFLOAT *h, SUSCOUNT size) 68 | { 69 | unsigned int i; 70 | 71 | for (i = 0; i < size; ++i) 72 | h[i] *= SU_BLACKMANN_HARRIS_A0 73 | - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) 74 | + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) 75 | - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); 76 | } 77 | 78 | /********************** Complex window functions ****************************/ 79 | void 80 | su_taps_apply_hamming_complex(SUCOMPLEX *h, SUSCOUNT size) 81 | { 82 | unsigned int i; 83 | 84 | for (i = 0; i < size; ++i) 85 | h[i] *= 86 | SU_HAMMING_ALPHA - SU_MAMMING_BETA * SU_COS(2 * M_PI * i / (size - 1)); 87 | } 88 | 89 | void 90 | su_taps_apply_hann_complex(SUCOMPLEX *h, SUSCOUNT size) 91 | { 92 | unsigned int i; 93 | 94 | for (i = 0; i < size; ++i) 95 | h[i] *= SU_HANN_ALPHA - SU_HANN_BETA * SU_COS(2 * M_PI * i / (size - 1)); 96 | } 97 | 98 | void 99 | su_taps_apply_flat_top_complex(SUCOMPLEX *h, SUSCOUNT size) 100 | { 101 | unsigned int i; 102 | 103 | for (i = 0; i < size; ++i) 104 | h[i] *= SU_FLAT_TOP_A0 - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) 105 | + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) 106 | - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) 107 | + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); 108 | } 109 | 110 | void 111 | su_taps_apply_blackmann_harris_complex(SUCOMPLEX *h, SUSCOUNT size) 112 | { 113 | unsigned int i; 114 | 115 | for (i = 0; i < size; ++i) 116 | h[i] *= SU_BLACKMANN_HARRIS_A0 117 | - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) 118 | + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) 119 | - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); 120 | } 121 | 122 | void 123 | su_taps_normalize_Linf(SUFLOAT *h, SUSCOUNT size) 124 | { 125 | unsigned int i; 126 | SUFLOAT max = 0; 127 | 128 | for (i = 0; i < size; ++i) 129 | if (SU_ABS(h[i]) > max) 130 | max = SU_ABS(h[i]); 131 | 132 | if (max > 0) 133 | su_taps_scale(h, 1. / max, size); 134 | } 135 | 136 | void 137 | su_taps_normalize_L2(SUFLOAT *h, SUSCOUNT size) 138 | { 139 | unsigned int i; 140 | SUFLOAT energy = 0; 141 | 142 | for (i = 0; i < size; ++i) 143 | energy += h[i] * h[i]; 144 | 145 | if (energy > 0) 146 | su_taps_scale(h, 1. / SU_SQRT(energy), size); 147 | } 148 | 149 | void 150 | su_taps_normalize_L1(SUFLOAT *h, SUSCOUNT size) 151 | { 152 | unsigned int i; 153 | SUFLOAT amplitude = 0; 154 | 155 | for (i = 0; i < size; ++i) 156 | amplitude += SU_ABS(h[i]); 157 | 158 | if (amplitude > 0) 159 | su_taps_scale(h, 1. / amplitude, size); 160 | } 161 | 162 | /***************************** Hilbert transform *****************************/ 163 | void 164 | su_taps_hilbert_init(SUFLOAT *h, SUSCOUNT size) 165 | { 166 | unsigned int i; 167 | int n = -size / 2; 168 | 169 | for (i = 0; i < size; ++i, ++n) 170 | h[i] = 2. / (M_PI * (n - .5f)); 171 | 172 | su_taps_apply_hamming(h, size); 173 | } 174 | 175 | void 176 | su_taps_rrc_init(SUFLOAT *h, SUFLOAT T, SUFLOAT beta, SUSCOUNT size) 177 | { 178 | unsigned int i; 179 | SUFLOAT r_t; 180 | SUFLOAT dem; 181 | SUFLOAT num; 182 | SUFLOAT f; 183 | 184 | for (i = 0; i < size; ++i) { 185 | r_t = (i - size / 2.) / T; 186 | f = 4 * beta * r_t; 187 | dem = M_PI * r_t * (1. - f * f); 188 | num = SU_SIN(M_PI * r_t * (1 - beta)) 189 | + 4 * beta * r_t * SU_COS(M_PI * r_t * (1 + beta)); 190 | 191 | if (SU_ABS(r_t) < SUFLOAT_THRESHOLD) 192 | h[i] = 1. - beta + 4. * beta / M_PI; 193 | else if (SU_ABS(dem) < SUFLOAT_THRESHOLD) 194 | h[i] = beta / SU_SQRT(2) 195 | * ((1 + 2 / M_PI) * sin(M_PI / (4 * beta)) 196 | + (1 - 2 / M_PI) * cos(M_PI / (4 * beta))); 197 | else 198 | h[i] = num / dem; 199 | 200 | h[i] *= 1. / T; 201 | } 202 | 203 | su_taps_apply_hamming(h, size); 204 | } 205 | 206 | void 207 | su_taps_brickwall_lp_init(SUFLOAT *h, SUFLOAT fc, SUSCOUNT size) 208 | { 209 | unsigned int i; 210 | SUFLOAT t = 0; 211 | 212 | for (i = 0; i < size; ++i) { 213 | t = i - (size >> 1); 214 | h[i] = fc * su_sinc(fc * t); 215 | } 216 | 217 | su_taps_apply_hamming(h, size); 218 | } 219 | 220 | void 221 | su_taps_brickwall_bp_init(SUFLOAT *h, SUFLOAT bw, SUFLOAT if_nor, SUSCOUNT size) 222 | { 223 | unsigned int i; 224 | SUFLOAT t = 0; 225 | SUFLOAT omega = SU_NORM2ANG_FREQ(if_nor); 226 | 227 | /* 228 | * If intermediate frequency is lesser than or equal to half the bandwidth, 229 | * the product-by-cosine trick will not work: negative and positive 230 | * pass bands will overlap, creating a spurious gain of 6 dB in the 231 | * intersection. There are two ways to overcome this: 232 | * 233 | * a) Replace SU_COS() by SU_C_EXP and use complex coefficients. This 234 | * implies changing the IIR filter implementation. Costly. 235 | * b) Detect this situation, and if if_nor <= bw / 2, use a 236 | * low pass filter with fc = if_nor + bw / 2 237 | */ 238 | 239 | if (if_nor <= .5 * bw) { 240 | su_taps_brickwall_lp_init(h, if_nor + .5 * bw, size); 241 | } else { 242 | for (i = 0; i < size; ++i) { 243 | t = i - .5 * size; 244 | h[i] = bw * su_sinc(.5 * bw * t) * SU_COS(omega * t); 245 | } 246 | 247 | su_taps_apply_hamming(h, size); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/sigutils/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2020 Gonzalo José Carracedo Carballal 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this program. If not, see 16 | 17 | 18 | */ 19 | 20 | #include 21 | 22 | #ifndef SIGUTILS_PKGVERSION 23 | # define SIGUTILS_PKGVERSION \ 24 | "custom build on " __DATE__ " at " __TIME__ " (" __VERSION__ ")" 25 | #endif /* SIGUTILS_BUILD_STRING */ 26 | 27 | unsigned int 28 | sigutils_abi_version(void) 29 | { 30 | return SIGUTILS_ABI_VERSION; 31 | } 32 | 33 | const char * 34 | sigutils_api_version(void) 35 | { 36 | return SIGUTILS_VERSION_STRING; 37 | } 38 | 39 | const char * 40 | sigutils_pkgversion(void) 41 | { 42 | return SIGUTILS_PKGVERSION; 43 | } 44 | 45 | void 46 | sigutils_abi_check(unsigned int abi) 47 | { 48 | if (abi != SIGUTILS_ABI_VERSION) { 49 | fprintf(stderr, "*** SIGUTILS CRITICAL LIBRARY ERROR ***\n"); 50 | fprintf( 51 | stderr, 52 | "Expected ABI version (v%u) is incompatible with current\n", 53 | abi); 54 | fprintf(stderr, "sigutils ABI version (v%u).\n\n", (unsigned) SIGUTILS_ABI_VERSION); 55 | 56 | if (abi < SIGUTILS_ABI_VERSION) { 57 | fprintf( 58 | stderr, 59 | "The current sigutils ABI version is too new compared to\n"); 60 | fprintf(stderr, "the version expected by the user software. Please\n"); 61 | fprintf(stderr, "update your software or rebuild it with an updated\n"); 62 | fprintf(stderr, "version of sigutils' development files\n\n"); 63 | } else { 64 | fprintf( 65 | stderr, 66 | "The current sigutils ABI version is too old compared to\n"); 67 | fprintf( 68 | stderr, 69 | "the version expected by the user software. This usually\n"); 70 | fprintf( 71 | stderr, 72 | "happens when the user software is installed in an older\n"); 73 | fprintf( 74 | stderr, 75 | "system without fixing its dependencies. Please verify\n"); 76 | fprintf(stderr, "your installation and try again.\n"); 77 | } 78 | 79 | abort(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/util/win32-fcntl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU Lesser General Public License as 5 | published by the Free Software Foundation, version 3. 6 | This program is distributed in the hope that it will be useful, but 7 | WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU Lesser General Public License for more details. 10 | You should have received a copy of the GNU Lesser General Public 11 | License along with this program. If not, see 12 | 13 | */ 14 | 15 | #include 16 | 17 | #include 18 | 19 | /* WARN: EXTREMELY ADHOC */ 20 | int 21 | fcntl(int fd, int cmd, ... /* arg */) 22 | { 23 | switch (cmd) { 24 | case F_GETFL: { 25 | /* Assume suscan just wants whatever flags the fd has and add O_NONBLOCK 26 | * to them, so it doesn't matter what this returns */ 27 | return 0; 28 | } break; 29 | case F_SETFL: { 30 | /* Assume suscan always wants to set fd to non blocking mode */ 31 | u_long iMode = 0; 32 | int iResult = ioctlsocket(fd, FIONBIO, &iMode); 33 | if (iResult != NO_ERROR) 34 | return -1; 35 | } break; 36 | } 37 | return 0; 38 | } -------------------------------------------------------------------------------- /src/util/win32-mman.c: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/klauspost/mman-win32 (unlicensed) 2 | 3 | /* 4 | Copyright (C) 2012 Klaus Post 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, version 3. 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | You should have received a copy of the GNU Lesser General Public 13 | License along with this program. If not, see 14 | 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #ifndef FILE_MAP_EXECUTE 24 | # define FILE_MAP_EXECUTE 0x0020 25 | #endif /* FILE_MAP_EXECUTE */ 26 | 27 | static int 28 | __map_mman_error(const DWORD err, const int deferr) 29 | { 30 | if (err == 0) 31 | return 0; 32 | // TODO: implement 33 | return err; 34 | } 35 | 36 | static DWORD 37 | __map_mmap_prot_page(const int prot) 38 | { 39 | DWORD protect = 0; 40 | 41 | if (prot == PROT_NONE) 42 | return protect; 43 | 44 | if ((prot & PROT_EXEC) != 0) { 45 | protect = 46 | ((prot & PROT_WRITE) != 0) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; 47 | } else { 48 | protect = ((prot & PROT_WRITE) != 0) ? PAGE_READWRITE : PAGE_READONLY; 49 | } 50 | 51 | return protect; 52 | } 53 | 54 | static DWORD 55 | __map_mmap_prot_file(const int prot) 56 | { 57 | DWORD desiredAccess = 0; 58 | 59 | if (prot == PROT_NONE) 60 | return desiredAccess; 61 | 62 | if ((prot & PROT_READ) != 0) 63 | desiredAccess |= FILE_MAP_READ; 64 | if ((prot & PROT_WRITE) != 0) 65 | desiredAccess |= FILE_MAP_WRITE; 66 | if ((prot & PROT_EXEC) != 0) 67 | desiredAccess |= FILE_MAP_EXECUTE; 68 | 69 | return desiredAccess; 70 | } 71 | 72 | void * 73 | mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) 74 | { 75 | HANDLE fm, h; 76 | 77 | void *map = MAP_FAILED; 78 | 79 | #ifdef _MSC_VER 80 | # pragma warning(push) 81 | # pragma warning(disable : 4293) 82 | #endif 83 | 84 | const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) 85 | ? (DWORD)off 86 | : (DWORD)(off & 0xFFFFFFFFL); 87 | const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) 88 | ? (DWORD)0 89 | : (DWORD)((off >> 32) & 0xFFFFFFFFL); 90 | const DWORD protect = __map_mmap_prot_page(prot); 91 | const DWORD desiredAccess = __map_mmap_prot_file(prot); 92 | 93 | const off_t maxSize = off + (off_t)len; 94 | 95 | const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) 96 | ? (DWORD)maxSize 97 | : (DWORD)(maxSize & 0xFFFFFFFFL); 98 | const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) 99 | ? (DWORD)0 100 | : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL); 101 | 102 | #ifdef _MSC_VER 103 | # pragma warning(pop) 104 | #endif 105 | 106 | errno = 0; 107 | 108 | if (len == 0 109 | /* Unsupported flag combinations */ 110 | || (flags & MAP_FIXED) != 0 111 | /* Usupported protection combinations */ 112 | || prot == PROT_EXEC) { 113 | errno = EINVAL; 114 | return MAP_FAILED; 115 | } 116 | 117 | h = ((flags & MAP_ANONYMOUS) == 0) ? (HANDLE)_get_osfhandle(fildes) 118 | : INVALID_HANDLE_VALUE; 119 | 120 | if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE) { 121 | errno = EBADF; 122 | return MAP_FAILED; 123 | } 124 | 125 | fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL); 126 | 127 | if (fm == NULL) { 128 | errno = __map_mman_error(GetLastError(), EPERM); 129 | return MAP_FAILED; 130 | } 131 | 132 | map = 133 | MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len); 134 | 135 | CloseHandle(fm); 136 | 137 | if (map == NULL) { 138 | errno = __map_mman_error(GetLastError(), EPERM); 139 | return MAP_FAILED; 140 | } 141 | 142 | return map; 143 | } 144 | 145 | int 146 | munmap(void *addr, size_t len) 147 | { 148 | if (UnmapViewOfFile(addr)) 149 | return 0; 150 | 151 | errno = __map_mman_error(GetLastError(), EPERM); 152 | 153 | return -1; 154 | } 155 | 156 | int 157 | mprotect(void *addr, size_t len, int prot) 158 | { 159 | DWORD newProtect = __map_mmap_prot_page(prot); 160 | DWORD oldProtect = 0; 161 | 162 | if (VirtualProtect(addr, len, newProtect, &oldProtect)) 163 | return 0; 164 | 165 | errno = __map_mman_error(GetLastError(), EPERM); 166 | 167 | return -1; 168 | } 169 | 170 | int 171 | msync(void *addr, size_t len, int flags) 172 | { 173 | if (FlushViewOfFile(addr, len)) 174 | return 0; 175 | 176 | errno = __map_mman_error(GetLastError(), EPERM); 177 | 178 | return -1; 179 | } 180 | 181 | int 182 | mlock(const void *addr, size_t len) 183 | { 184 | if (VirtualLock((LPVOID)addr, len)) 185 | return 0; 186 | 187 | errno = __map_mman_error(GetLastError(), EPERM); 188 | 189 | return -1; 190 | } 191 | 192 | int 193 | munlock(const void *addr, size_t len) 194 | { 195 | if (VirtualUnlock((LPVOID)addr, len)) 196 | return 0; 197 | 198 | errno = __map_mman_error(GetLastError(), EPERM); 199 | 200 | return -1; 201 | } -------------------------------------------------------------------------------- /src/util/win32-pwd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | // WARN: VERY ADHOC: dummy function lol 23 | uid_t 24 | getuid() 25 | { 26 | return 0; 27 | } 28 | 29 | // WARN: VERY ADHOC: ignores uid, only populates pw_dir 30 | struct passwd * 31 | getpwuid(uid_t uid) 32 | { 33 | struct passwd *pw = malloc(sizeof(struct passwd)); 34 | memset(pw, 0, sizeof(struct passwd)); 35 | 36 | char *homeDirStr = malloc(MAX_PATH); 37 | if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, homeDirStr))) { 38 | pw->pw_dir = homeDirStr; 39 | } else { 40 | return NULL; 41 | } 42 | 43 | return pw; 44 | } -------------------------------------------------------------------------------- /src/util/win32-statvfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | /* A bit adhoc */ 24 | int 25 | statvfs(const char *restrict path, struct statvfs *restrict buf) 26 | { 27 | DWORD SectorsPerCluster = 0; 28 | DWORD BytesPerSector = 0; 29 | DWORD NumberOfFreeClusters = 0; 30 | DWORD TotalNumberOfClusters = 0; 31 | int r = GetDiskFreeSpaceA( 32 | path, 33 | &SectorsPerCluster, 34 | &BytesPerSector, 35 | &NumberOfFreeClusters, 36 | &TotalNumberOfClusters); 37 | 38 | buf->f_frsize = BytesPerSector * SectorsPerCluster; 39 | buf->f_bsize = buf->f_frsize; 40 | 41 | buf->f_blocks = TotalNumberOfClusters; 42 | buf->f_bavail = NumberOfFreeClusters; 43 | 44 | return r; 45 | } 46 | -------------------------------------------------------------------------------- /src/util/win32-stdlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | int 23 | setenv(const char *name, const char *value, int overwrite) 24 | { 25 | int errcode = 0; 26 | if (!overwrite) { 27 | size_t envsize = 0; 28 | errcode = getenv_s(&envsize, NULL, 0, name); 29 | if (errcode || envsize) 30 | return errcode; 31 | } 32 | return _putenv_s(name, value); 33 | } 34 | 35 | int 36 | unsetenv(const char *name) 37 | { 38 | return _putenv_s(name, ""); 39 | } -------------------------------------------------------------------------------- /src/util/win32-termios.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | ssize_t 23 | read_noecho_noicanon(int fd, void *buf, size_t count) 24 | { 25 | char *buff = (char *)buf; 26 | for (int i = 0; i < count; i++) { 27 | buff[i] = (char)_getch(); 28 | buff++; 29 | } 30 | return count; 31 | } 32 | 33 | int 34 | tcgetattr(int fd, struct termios *termios_p) 35 | { 36 | return 0; 37 | } 38 | 39 | int 40 | tcsetattr(int fd, int optional_actions, const struct termios *termios_p) 41 | { 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/util/win32-time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Martin Willi 3 | * Copyright (C) 2013 revosec AG 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. See . 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 | * for more details. 14 | */ 15 | 16 | #include 17 | -------------------------------------------------------------------------------- /src/util/win32-unistd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022 Ángel Ruiz Fernández 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, version 3. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this program. If not, see 15 | 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | long 23 | sysconf(int name) 24 | { 25 | switch (name) { 26 | case _SC_NPROCESSORS_ONLN: { 27 | SYSTEM_INFO si; 28 | GetSystemInfo(&si); 29 | return si.dwNumberOfProcessors; 30 | } break; 31 | default: 32 | return 0; 33 | } 34 | return 0; 35 | } 36 | 37 | int 38 | getpagesize() 39 | { 40 | SYSTEM_INFO sysInfo; 41 | GetSystemInfo(&sysInfo); 42 | return sysInfo.dwPageSize; 43 | } 44 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Catch2) 2 | 3 | if(Catch2_FOUND) 4 | # General options 5 | file(GLOB_RECURSE TEST_SRCS LIST_DIRECTORIES false *.cpp) 6 | add_executable(sigutils_test EXCLUDE_FROM_ALL ${TEST_SRCS}) 7 | target_include_directories(sigutils_test PUBLIC $) 8 | target_compile_definitions(sigutils_test PUBLIC $) 9 | target_link_libraries(sigutils_test $) 10 | include(Catch) 11 | catch_discover_tests(sigutils_test) 12 | 13 | if(Catch2_VERSION_MAJOR EQUAL 2) 14 | target_compile_definitions(sigutils_test PUBLIC CATCH2_V2) 15 | target_link_libraries(sigutils_test Catch2::Catch2) 16 | elseif(Catch2_VERSION_MAJOR EQUAL 3) 17 | target_compile_definitions(sigutils_test PUBLIC CATCH2_V3) 18 | target_link_libraries(sigutils_test Catch2::Catch2WithMain) 19 | else() 20 | message("Unsuported Catch2 version") 21 | endif() 22 | else() 23 | message("Catch2 needs to be installed to perform unit testing") 24 | endif() 25 | -------------------------------------------------------------------------------- /tests/catch.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2023 Antonio Vázquez Blanco 2 | * SPDX-License-Identifier: GPL-3.0-only 3 | */ 4 | 5 | #ifndef _CATCH_TEST_H 6 | #define _CATCH_TEST_H 7 | 8 | #ifdef CATCH2_V2 9 | #define CATCH_CONFIG_MAIN 10 | #include 11 | #endif 12 | 13 | #ifdef CATCH2_V3 14 | #include 15 | #endif 16 | 17 | #if !defined(CATCH2_V2) && !defined(CATCH2_V3) 18 | #error "No Catch2 version specified!" 19 | #endif 20 | 21 | #endif -------------------------------------------------------------------------------- /tests/test_ncqo.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2023 Antonio Vázquez Blanco 2 | * SPDX-License-Identifier: GPL-3.0-only 3 | */ 4 | 5 | #include "catch.hpp" 6 | 7 | #include 8 | 9 | TEST_CASE("Test normalized frecuency scale", "[NCQO]") 10 | { 11 | su_ncqo_t ncqo; 12 | su_ncqo_init(&ncqo, 1.0); 13 | REQUIRE(SUFLOAT_EQUAL(su_ncqo_read_i(&ncqo), 1.0)); 14 | REQUIRE(SUFLOAT_EQUAL(su_ncqo_read_i(&ncqo), -1.0)); 15 | REQUIRE(SUFLOAT_EQUAL(su_ncqo_read_i(&ncqo), 1.0)); 16 | REQUIRE(SUFLOAT_EQUAL(su_ncqo_read_i(&ncqo), -1.0)); 17 | } 18 | --------------------------------------------------------------------------------