├── .gitmodules ├── CMakeLists.txt ├── README.md ├── cmake └── sanitizers │ ├── FindASan.cmake │ ├── FindMSan.cmake │ ├── FindSanitizers.cmake │ ├── FindTSan.cmake │ ├── FindUBSan.cmake │ ├── asan-wrapper │ └── sanitize-helpers.cmake ├── doc └── Doxyfile ├── include └── nanosnap │ ├── fft.h │ └── nanosnap.h ├── scripts └── bootstrap-linux.sh ├── src ├── audio_wav.cc ├── dr_wav.h ├── fastBPE.hpp ├── fft.cc ├── image.cc ├── mel.cc ├── nanocsv.h ├── ndarray.cc ├── pocketfft.c ├── pocketfft.h ├── rng.cc ├── signal.cc ├── speech_features.cc ├── stack_vector.h ├── stb_image.h ├── stb_image_resize.h ├── stb_image_write.h └── text-load-save.cc ├── tests ├── assets │ ├── 8k16bitpcm.wav │ ├── 8k8bitpcm.wav │ └── README.md ├── gen │ ├── README.md │ ├── common_util.py │ ├── gen_convolve_full.py │ ├── gen_convolve_same.py │ ├── gen_convolve_valid.py │ ├── gen_ifft.py │ ├── gen_librosa_filters_mel.py │ ├── gen_librosa_istft.py │ ├── gen_librosa_stft.py │ ├── gen_lifter.py │ ├── gen_medfilt1.py │ ├── gen_random_normal.py │ ├── gen_random_uniform.py │ ├── gen_rfft.py │ ├── gen_signal_get_window_hann.py │ └── run_all.sh ├── main.cc ├── test_audio.cc ├── test_convolve.cc ├── test_ifft.cc ├── test_librosa_filters_mel.cc ├── test_librosa_istft.cc ├── test_librosa_stft.cc ├── test_medfilt1.cc ├── test_random_uniform.cc ├── test_rfft.cc ├── test_signal_get_window_hann.cc ├── test_speech_features.cc └── testvector │ ├── convolve_full.inc │ ├── convolve_same.inc │ ├── convolve_valid.inc │ ├── ifft.inc │ ├── librosa_filters_mel.inc │ ├── librosa_istft.inc │ ├── librosa_stft.inc │ ├── lifter.inc │ ├── medfilt1.inc │ ├── random_normal.inc │ ├── random_uniform.inc │ ├── rfft.inc │ └── signal_get_window_hann.inc └── vcsetup.bat /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/doctest"] 2 | path = third_party/doctest 3 | url = https://github.com/onqtam/doctest.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | 4 | # ------------------------------------------------------------------------------ 5 | # ----------------------------------- Options ---------------------------------- 6 | # ------------------------------------------------------------------------------ 7 | option(NANOSNAP_BUILD_EXAMPLES "Build NanoSNAP example codes" ON) 8 | option(NANOSNAP_BUILD_TESTS "Build NanoSNAP test codes" OFF) 9 | message(STATUS "NanoSNAP: Build examples: ${NANOSNAP_BUILD_EXAMPLES}, tests: ${NANOSNAP_BUILD_TESTS}") 10 | 11 | if (NANOSNAP_BUILD_TESTS) 12 | if (NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/doctest/doctest") 13 | message(FATAL_ERROR "doctest submodule directory is missing!\n" 14 | "Please run \"git submodule update --init --recursive --depth 1\" to checkout submodules") 15 | endif () 16 | endif (NANOSNAP_BUILD_TESTS) 17 | 18 | # ------------------------------------------------------------------------------ 19 | # ----------------------------------- Common ----------------------------------- 20 | # ------------------------------------------------------------------------------ 21 | project(nanosnap CXX C) 22 | set (CMAKE_CXX_STANDARD 11) # C++ 11 23 | 24 | 25 | # Print make commands for debug 26 | # set(CMAKE_VERBOSE_MAKEFILE 1) 27 | 28 | # Set default build type 29 | if (NOT CMAKE_BUILD_TYPE) 30 | set(CMAKE_BUILD_TYPE Release) 31 | endif() 32 | 33 | # cmake modules 34 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 35 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/sanitizers) 36 | find_package(Sanitizers) # Address sanitizer (-DSANITIZE_ADDRESS=ON) 37 | 38 | # Set output directories 39 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 40 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 41 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 42 | 43 | # core include 44 | include_directories(${PROJECT_SOURCE_DIR}/include) 45 | 46 | # Internal third party includes 47 | # include_directories( 48 | # ${PROJECT_SOURCE_DIR}/third_party 49 | # ) 50 | 51 | # ------------------------------- libnanosnap ------------------------------- 52 | add_library(nanosnap STATIC 53 | ${PROJECT_SOURCE_DIR}/include/nanosnap/nanosnap.h 54 | ${PROJECT_SOURCE_DIR}/src/ndarray.cc 55 | ${PROJECT_SOURCE_DIR}/src/signal.cc 56 | ${PROJECT_SOURCE_DIR}/src/audio_wav.cc 57 | ${PROJECT_SOURCE_DIR}/src/speech_features.cc 58 | ${PROJECT_SOURCE_DIR}/src/fft.cc 59 | ${PROJECT_SOURCE_DIR}/src/rng.cc 60 | ${PROJECT_SOURCE_DIR}/src/text-load-save.cc 61 | ${PROJECT_SOURCE_DIR}/src/image.cc 62 | ${PROJECT_SOURCE_DIR}/src/mel.cc 63 | ${PROJECT_SOURCE_DIR}/src/pocketfft.c 64 | ) 65 | add_sanitizers(nanosnap) 66 | 67 | # raise compiler warning level. 68 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 69 | target_compile_options(nanosnap PRIVATE 70 | $<$: -Weverything -Werror -Wno-c++98-compat -Wno-padded> 71 | ) 72 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GCC") 73 | target_compile_options(nanosnap PRIVATE 74 | $<$: --pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wundef -Wno-unknown-pragmas> 75 | ) 76 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 77 | target_compile_options(nanosnap PRIVATE 78 | $<$: /W4> 79 | ) 80 | endif() 81 | 82 | 83 | #if (WIN32) 84 | # set_target_properties(nanosnap PROPERTIES 85 | # OUTPUT_NAME libnanosnap 86 | # ) 87 | #endif() 88 | 89 | # ------------------------------ test executables ------------------------------ 90 | if (NANOSNAP_BUILD_TESTS) 91 | add_executable(test_nanosnap 92 | ${PROJECT_SOURCE_DIR}/tests/main.cc 93 | ${PROJECT_SOURCE_DIR}/tests/test_audio.cc 94 | ${PROJECT_SOURCE_DIR}/tests/test_speech_features.cc 95 | ${PROJECT_SOURCE_DIR}/tests/test_medfilt1.cc 96 | ${PROJECT_SOURCE_DIR}/tests/test_rfft.cc 97 | ${PROJECT_SOURCE_DIR}/tests/test_ifft.cc 98 | ${PROJECT_SOURCE_DIR}/tests/test_convolve.cc 99 | ${PROJECT_SOURCE_DIR}/tests/test_librosa_stft.cc 100 | ${PROJECT_SOURCE_DIR}/tests/test_librosa_istft.cc 101 | ${PROJECT_SOURCE_DIR}/tests/test_librosa_filters_mel.cc 102 | ${PROJECT_SOURCE_DIR}/tests/test_signal_get_window_hann.cc 103 | # it looks numpy.random uses slightly different configuration of Mersenne Twistter 104 | # and does not produce same result with std::mt19937. Disable random test for a while. 105 | #${PROJECT_SOURCE_DIR}/tests/test_random_uniform.cc 106 | ) 107 | target_include_directories(test_nanosnap PRIVATE ${PROJECT_SOURCE_DIR}/src) 108 | target_include_directories(test_nanosnap PRIVATE ${PROJECT_SOURCE_DIR}/third_party/doctest) 109 | target_link_libraries(test_nanosnap nanosnap) 110 | add_sanitizers(test_nanosnap) 111 | 112 | # [VisualStudio] 113 | if (WIN32) 114 | # Set `test_nanosnap` as a startup project for VS IDE. 115 | if (CMAKE_VERSION VERSION_GREATER 3.6.0) 116 | set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT test_nanosnap) 117 | endif () 118 | 119 | # For easier debugging in VS IDE. 120 | if (CMAKE_VERSION VERSION_GREATER 3.8.0) 121 | set_target_properties(test_nanosnap PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") 122 | endif () 123 | 124 | endif() 125 | else() 126 | # [VisualStudio] 127 | if (WIN32) 128 | # Set `nanosnap` as a startup project for VS IDE. 129 | if (CMAKE_VERSION VERSION_GREATER 3.6.0) 130 | set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT nanosnap) 131 | endif () 132 | endif() 133 | endif() 134 | 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NanoSNAP, Nanoscale Signal, Noise and Audio Processing library in C++11 2 | 3 | NanoSNAP is a small and portable signal, audio and noise processing library in C++11. 🤞 4 | NanoSNAP depends only on C++11 STL. 5 | 6 | ## Usage 7 | 8 | * For running TTS(Text-to-speech) and ASR(Automatic Speech Recognition) on C++ Embedded device. 9 | * Image processing with neural netowork inference on C++ and Embedded device. 10 | * Implement audio and speech feature(e.g. using `rfft`, `mfcc` `stft`, `istft`) on your C++ machine learning library. 11 | 12 | ## Install and integration 13 | 14 | Simply copy `include` and `src` folder to your platform. 15 | 16 | ## Requirements 17 | 18 | * CMake(for building examples and tests, and build NanoSNAP as submodules) 19 | * C++11 compiler 20 | 21 | ## Supported platform 22 | 23 | * [x] Windows 24 | * [x] Linux 25 | * [x] macOS 26 | * [ ] Android(not tested yet, but should work) 27 | * [ ] Raspberry Pi(not tested yet, but should work) 28 | * [ ] RISC-V(not tested yet, but should work) 29 | 30 | ## Setup(can be skipped if you don't build tests) 31 | 32 | If you want to build tests(building tests are enabled by default), you need to checkout submodules. 33 | 34 | ``` 35 | $ git submodule update --init --recursive --depth 1 36 | ``` 37 | 38 | ## Build 39 | 40 | ``` 41 | $ mkdir build 42 | $ cd build 43 | $ cmake .. 44 | $ make 45 | ``` 46 | 47 | ### Build on Visual Studio 2017 48 | 49 | ``` 50 | > vcsetup.bat 51 | ``` 52 | 53 | Open `build/nanosnap.sln` and build it. 54 | 55 | ### Build and running tests 56 | 57 | ``` 58 | $ mkdir build 59 | $ cd build 60 | $ cmake -DNANOSNAP_ENABLE_TESTS=On .. 61 | $ make 62 | $ ./bin/test_nanosnap 63 | ``` 64 | 65 | ### Compiler macros 66 | 67 | * `NANOSNAP_NO_STDIO` Disable IO. e.g. `wav_read` is not available. This feature is useful when you want to use NanoSNAP in Android or embedded devices. 68 | 69 | 70 | ## API design 71 | 72 | NanoSNAP takes raw pointer for input array values followin its length information(or shape information). 73 | 74 | ```c++ 75 | bool proc(const float *input, int n); 76 | ``` 77 | 78 | Output array is usually `std::vector` type so that NanoSNAP can allocate buffer for output internally. 79 | Output array is a functiona argument when a function needs to return the status. 80 | 81 | ```c++ 82 | bool proc(int n, std::vector *output); 83 | ``` 84 | 85 | Otherwise, output array is a return value. 86 | 87 | ```c++ 88 | std::vector proc(int n); 89 | ``` 90 | 91 | ### Internal state. 92 | 93 | All API does not contain its internal state. 94 | 95 | #### Multithreading 96 | 97 | NanoSNAP API is re-entrant as it does not have any internal state, so it should be safe to use in multi-threading program unless input/output memory address does not overlap between threads. 98 | 99 | ### CMake option for developers 100 | 101 | * `-DSANITIZE_ADDRESS=On` : Enable Address Sanitizer(for developer). 102 | 103 | ## Data layout of array 104 | 105 | NanoSNAP process 2D and higher ND array data as 1D flattened array. 106 | 107 | The ordering of array data follows C language(This is same behavior in `numpy` array in C mode). For example, `img[H][W]` has `W` pixels in width(colums) , `H` pixels in height(rows). 108 | 109 | ``` 110 | -> memory address increases 111 | 112 | +-----------+-----------+ +-------------+-----------+ +---------------+ 113 | | img[0][0] | img[0][1] | ... | img[0][W-1] | img[1][0] | ... | img[H-1][W-1] | 114 | +-----------+-----------+ +-------------+-----------+ +---------------+ 115 | ``` 116 | 117 | In contrary to `numpy` or vision/ML library such like OpenCV, The notation of dimensional arguments for a function signature starts from inner most dimension(right-most array dim). This is rather common notation in C language and graphics community. i.e, 118 | 119 | ``` 120 | // `output` has the shape of [h][w] 121 | void create_image(size_t w, size_t h, float *output); 122 | 123 | // `output` has the shape of [d][h][w] 124 | void create_3d_tensor(size_t w, size_t h, size_t d, float *output); 125 | 126 | // `input` has the shape of [nrows][nframes]. 127 | void rfft(const float *inout, size_t nframes, size_t nrows, ...); 128 | ``` 129 | 130 | ## Features 131 | 132 | ### Numpy 133 | 134 | | NanoSNAP | Description | Python equivalent | 135 | | ---------------------- | -------------------------------------------------- | ------------------------------------ | 136 | | `reshape_with_strides` | Create an array with the given shape and strides. | `numpy.lib.stride_tricks.as_strided` | 137 | | `convolve` | 1D convolution | `numpy.convolve` | 138 | | `loadtxt` | Load 1D or 2D array | `numpy.loadtxt` | 139 | | `savetxt` | Save 1D or 2D array | `numpy.savetxt` | 140 | 141 | ### Random number generation 142 | 143 | | NanoSNAP | Description | Python equivalent | 144 | | ---------------------- | ---------------------- | ---------------------------------- | 145 | | `random_uniform` | Uniform random number | `numpy.random.rand` | 146 | | `random_shuffle` | Randomly shuffle array | `numpy.random.shuffle` | 147 | 148 | 149 | ### FFT 150 | 151 | | NanoSNAP | Description | Python equivalent | 152 | | ---------------------- | ---------------------------- | ----------------------------------- | 153 | | `rfft` | Real 1D FFT | `numpy.fft.rfft` | 154 | | `ifft` | Inverse Complex FFT | `numpy.fft.ifft` | 155 | 156 | ### Scipy 157 | 158 | | NanoSNAP | Description | Python equivalent | 159 | | ---------------------- | ----------------------------------------------------------- | ----------------------------------- | 160 | | `lfilter` | Filter data along one-dimension with an IIR or FIR filter. | `scipy.signal.lfilt` | 161 | | `medfilt` | Median filter | `scipy.signal.medfilt` | 162 | | `wav_read` | Read .WAV file | `scipy.io.wavfile.read` | 163 | | `wav_write` | Save .WAV file | `scipy.io.wavfile.write` | 164 | 165 | ### Python speech features 166 | 167 | | NanoSNAP | Description | Python equivalent | 168 | | ---------------------- | ------------------------------------------------- | ----------------------------------- | 169 | | `mel2hz` | Mel to Hz | `mel2hz` | 170 | | `hz2mel` | Hz to Mel | `hz2mel` | 171 | | `lifter` | Apply a cepstral lifter the the matrix of cepstra | `lifter` | 172 | 173 | #### Work in progress 174 | 175 | | NanoSNAP | Description | Python equivalent | 176 | | ---------------------- | ------------------------------------------------- | ----------------------------------- | 177 | | `mfcc` | Mel Frequency Cepstral Coefficients | `mfcc` | 178 | | `fbank` | Filterbank Energies | `fbank` | 179 | | `logfbank` | Log Filterbank Energies | `logfbank` | 180 | | `ssc` | Spectral Subband Centroids | `ssc` | 181 | 182 | 183 | ### Librosa 184 | 185 | | NanoSNAP | Description | Python equivalent | 186 | | ---------------------- | ---------------------------------------------------------------------- | ----------------------------------- | 187 | | `stft` | Short Term Fourier Transform | `librosa.stft` | 188 | | `istft` | Inverse STFT | `librosa.istft` | 189 | | `mel` | Create a Filterbank matrix to combine FFT bins into Mel-frequency bins | `librosa.filters.mel` | 190 | 191 | ### Image 192 | 193 | | NanoSNAP | Description | Python equivalent | 194 | | ---------------------- | ---------------------------- | ----------------------------------- | 195 | | `resize_bilinear` | Resize image with bilinear | `cv2.resize_image` | 196 | | `imread` | Load LDR image | `cv2.imread` | 197 | | `imsave` | Save image as LDR format | `cv2.imsave` | 198 | 199 | ## limited support 200 | 201 | * get_window : 'hann' only. `scipy.signal.get_window` equivalent. 202 | 203 | ## TODO 204 | 205 | * [ ] Better error handling(report error message) 206 | * [ ] Multithreading using C++11 `thread`. 207 | * [ ] Use `StackVector` as much as possible. 208 | * [ ] Read/write WAV from/to buffer(memory) 209 | * [ ] Integrate with `NanoNumCp` 210 | * FFT 211 | * [ ] Implement more FFT functions defined in `scipy.fft`. 212 | * [ ] 2D FFT 213 | * [ ] Replace pocketfft with our own C++11 FFT routuine or muFFT https://github.com/Themaister/muFFT. 214 | * [ ] Port more functions in `python_speech_features` 215 | * [ ] Implement more speech features implemented in sox, librosa, etc. 216 | * [ ] Plot and save figure/image in JPG/PNG/EXR 217 | 218 | ## Developer note 219 | 220 | ### Adding tests 221 | 222 | * Write testvector generator and put it to `tests/gen/` 223 | * Generate testvector file(`.inc`) 224 | * Add .cc to `tests`. Add it to CMakeLists.txt. 225 | 226 | ## License 227 | 228 | NanoSNAP is licensed under MIT license. 229 | 230 | ### Third party licenses. 231 | 232 | * stack_vector.h : Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license. 233 | * doctest : The MIT License (MIT). Copyright (c) 2016-2019 Viktor Kirilov 234 | * dr_wav : Public domain or MIT-0. By David Reid. 235 | * python_speech_features : The MIT License (MIT). Copyright (c) 2013 James Lyons. https://github.com/jameslyons/python_speech_features 236 | * pocketfft : FFT library used in numpy. Copyright (C) 2004-2018 Max-Planck-Society. 3-clause BSD-tyle license. https://gitlab.mpcdf.mpg.de/mtr/pocketfft 237 | * c_speech_features : Copyright (c) 2017 Chris Lord. MIT license. https://github.com/Cwiiis/c_speech_features 238 | * STB image : Public domain. https://github.com/nothings/stb 239 | * sRGB transform : Copyright (c) 2017 Project Nayuki. (MIT License) https://www.nayuki.io/page/srgb-transform-library 240 | * fastBPE: Copyright (c) 2019 Guillaume Lample,Timothée Lacroix(MIT License) https://github.com/glample/fastBPE 241 | -------------------------------------------------------------------------------- /cmake/sanitizers/FindASan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional. 29 | "-g -fsanitize=address -fno-omit-frame-pointer" 30 | "-g -fsanitize=address" 31 | 32 | # Older deprecated flag for ASan 33 | "-g -faddress-sanitizer" 34 | ) 35 | 36 | 37 | if (SANITIZE_ADDRESS AND (SANITIZE_THREAD OR SANITIZE_MEMORY)) 38 | message(FATAL_ERROR "AddressSanitizer is not compatible with " 39 | "ThreadSanitizer or MemorySanitizer.") 40 | endif () 41 | 42 | 43 | include(sanitize-helpers) 44 | 45 | if (SANITIZE_ADDRESS) 46 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" 47 | "ASan") 48 | 49 | find_program(ASan_WRAPPER "asan-wrapper" PATHS ${CMAKE_MODULE_PATH}) 50 | mark_as_advanced(ASan_WRAPPER) 51 | endif () 52 | 53 | function (add_sanitize_address TARGET) 54 | if (NOT SANITIZE_ADDRESS) 55 | return() 56 | endif () 57 | 58 | saitizer_add_flags(${TARGET} "AddressSanitizer" "ASan") 59 | endfunction () 60 | -------------------------------------------------------------------------------- /cmake/sanitizers/FindMSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | "-g -fsanitize=memory" 29 | ) 30 | 31 | 32 | include(sanitize-helpers) 33 | 34 | if (SANITIZE_MEMORY) 35 | if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 36 | message(WARNING "MemorySanitizer disabled for target ${TARGET} because " 37 | "MemorySanitizer is supported for Linux systems only.") 38 | set(SANITIZE_MEMORY Off CACHE BOOL 39 | "Enable MemorySanitizer for sanitized targets." FORCE) 40 | elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) 41 | message(WARNING "MemorySanitizer disabled for target ${TARGET} because " 42 | "MemorySanitizer is supported for 64bit systems only.") 43 | set(SANITIZE_MEMORY Off CACHE BOOL 44 | "Enable MemorySanitizer for sanitized targets." FORCE) 45 | else () 46 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "MemorySanitizer" 47 | "MSan") 48 | endif () 49 | endif () 50 | 51 | function (add_sanitize_memory TARGET) 52 | if (NOT SANITIZE_MEMORY) 53 | return() 54 | endif () 55 | 56 | saitizer_add_flags(${TARGET} "MemorySanitizer" "MSan") 57 | endfunction () 58 | -------------------------------------------------------------------------------- /cmake/sanitizers/FindSanitizers.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | # If any of the used compiler is a GNU compiler, add a second option to static 26 | # link against the sanitizers. 27 | option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off) 28 | 29 | 30 | 31 | 32 | set(FIND_QUIETLY_FLAG "") 33 | if (DEFINED Sanitizers_FIND_QUIETLY) 34 | set(FIND_QUIETLY_FLAG "QUIET") 35 | endif () 36 | 37 | find_package(ASan ${FIND_QUIETLY_FLAG}) 38 | find_package(TSan ${FIND_QUIETLY_FLAG}) 39 | find_package(MSan ${FIND_QUIETLY_FLAG}) 40 | find_package(UBSan ${FIND_QUIETLY_FLAG}) 41 | 42 | 43 | 44 | 45 | function(sanitizer_add_blacklist_file FILE) 46 | if(NOT IS_ABSOLUTE ${FILE}) 47 | set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}") 48 | endif() 49 | get_filename_component(FILE "${FILE}" REALPATH) 50 | 51 | sanitizer_check_compiler_flags("-fsanitize-blacklist=${FILE}" 52 | "SanitizerBlacklist" "SanBlist") 53 | endfunction() 54 | 55 | function(add_sanitizers ...) 56 | # If no sanitizer is enabled, return immediately. 57 | if (NOT (SANITIZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR 58 | SANITIZE_UNDEFINED)) 59 | return() 60 | endif () 61 | 62 | foreach (TARGET ${ARGV}) 63 | # Check if this target will be compiled by exactly one compiler. Other- 64 | # wise sanitizers can't be used and a warning should be printed once. 65 | sanitizer_target_compilers(${TARGET} TARGET_COMPILER) 66 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) 67 | if (NUM_COMPILERS GREATER 1) 68 | message(WARNING "Can't use any sanitizers for target ${TARGET}, " 69 | "because it will be compiled by incompatible compilers. " 70 | "Target will be compiled without sanitzers.") 71 | return() 72 | 73 | # If the target is compiled by no known compiler, ignore it. 74 | elseif (NUM_COMPILERS EQUAL 0) 75 | message(WARNING "Can't use any sanitizers for target ${TARGET}, " 76 | "because it uses an unknown compiler. Target will be " 77 | "compiled without sanitzers.") 78 | return() 79 | endif () 80 | 81 | # Add sanitizers for target. 82 | add_sanitize_address(${TARGET}) 83 | add_sanitize_thread(${TARGET}) 84 | add_sanitize_memory(${TARGET}) 85 | add_sanitize_undefined(${TARGET}) 86 | endforeach () 87 | endfunction(add_sanitizers) 88 | -------------------------------------------------------------------------------- /cmake/sanitizers/FindTSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | "-g -fsanitize=thread" 29 | ) 30 | 31 | 32 | # ThreadSanitizer is not compatible with MemorySanitizer. 33 | if (SANITIZE_THREAD AND SANITIZE_MEMORY) 34 | message(FATAL_ERROR "ThreadSanitizer is not compatible with " 35 | "MemorySanitizer.") 36 | endif () 37 | 38 | 39 | include(sanitize-helpers) 40 | 41 | if (SANITIZE_THREAD) 42 | if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 43 | message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " 44 | "ThreadSanitizer is supported for Linux systems only.") 45 | set(SANITIZE_THREAD Off CACHE BOOL 46 | "Enable ThreadSanitizer for sanitized targets." FORCE) 47 | elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) 48 | message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " 49 | "ThreadSanitizer is supported for 64bit systems only.") 50 | set(SANITIZE_THREAD Off CACHE BOOL 51 | "Enable ThreadSanitizer for sanitized targets." FORCE) 52 | else () 53 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ThreadSanitizer" 54 | "TSan") 55 | endif () 56 | endif () 57 | 58 | function (add_sanitize_thread TARGET) 59 | if (NOT SANITIZE_THREAD) 60 | return() 61 | endif () 62 | 63 | saitizer_add_flags(${TARGET} "ThreadSanitizer" "TSan") 64 | endfunction () 65 | -------------------------------------------------------------------------------- /cmake/sanitizers/FindUBSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_UNDEFINED 26 | "Enable UndefinedBehaviorSanitizer for sanitized targets." Off) 27 | 28 | set(FLAG_CANDIDATES 29 | "-g -fsanitize=undefined" 30 | ) 31 | 32 | 33 | include(sanitize-helpers) 34 | 35 | if (SANITIZE_UNDEFINED) 36 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" 37 | "UndefinedBehaviorSanitizer" "UBSan") 38 | endif () 39 | 40 | function (add_sanitize_undefined TARGET) 41 | if (NOT SANITIZE_UNDEFINED) 42 | return() 43 | endif () 44 | 45 | saitizer_add_flags(${TARGET} "UndefinedBehaviorSanitizer" "UBSan") 46 | endfunction () 47 | -------------------------------------------------------------------------------- /cmake/sanitizers/asan-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 6 | # 2013 Matthew Arsenault 7 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 8 | # 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | 27 | # This script is a wrapper for AddressSanitizer. In some special cases you need 28 | # to preload AddressSanitizer to avoid error messages - e.g. if you're 29 | # preloading another library to your application. At the moment this script will 30 | # only do something, if we're running on a Linux platform. OSX might not be 31 | # affected. 32 | 33 | 34 | # Exit immediately, if platform is not Linux. 35 | if [ "$(uname)" != "Linux" ] 36 | then 37 | exec $@ 38 | fi 39 | 40 | 41 | # Get the used libasan of the application ($1). If a libasan was found, it will 42 | # be prepended to LD_PRELOAD. 43 | libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1) 44 | if [ -n "$libasan" ] 45 | then 46 | if [ -n "$LD_PRELOAD" ] 47 | then 48 | export LD_PRELOAD="$libasan:$LD_PRELOAD" 49 | else 50 | export LD_PRELOAD="$libasan" 51 | fi 52 | fi 53 | 54 | # Execute the application. 55 | exec $@ 56 | -------------------------------------------------------------------------------- /cmake/sanitizers/sanitize-helpers.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | # Helper function to get the language of a source file. 26 | function (sanitizer_lang_of_source FILE RETURN_VAR) 27 | get_filename_component(FILE_EXT "${FILE}" EXT) 28 | string(TOLOWER "${FILE_EXT}" FILE_EXT) 29 | string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) 30 | 31 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 32 | foreach (LANG ${ENABLED_LANGUAGES}) 33 | list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) 34 | if (NOT ${TEMP} EQUAL -1) 35 | set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) 36 | return() 37 | endif () 38 | endforeach() 39 | 40 | set(${RETURN_VAR} "" PARENT_SCOPE) 41 | endfunction () 42 | 43 | 44 | # Helper function to get compilers used by a target. 45 | function (sanitizer_target_compilers TARGET RETURN_VAR) 46 | # Check if all sources for target use the same compiler. If a target uses 47 | # e.g. C and Fortran mixed and uses different compilers (e.g. clang and 48 | # gfortran) this can trigger huge problems, because different compilers may 49 | # use different implementations for sanitizers. 50 | set(BUFFER "") 51 | get_target_property(TSOURCES ${TARGET} SOURCES) 52 | foreach (FILE ${TSOURCES}) 53 | # If expression was found, FILE is a generator-expression for an object 54 | # library. Object libraries will be ignored. 55 | string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) 56 | if ("${_file}" STREQUAL "") 57 | sanitizer_lang_of_source(${FILE} LANG) 58 | if (LANG) 59 | list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) 60 | endif () 61 | endif () 62 | endforeach () 63 | 64 | list(REMOVE_DUPLICATES BUFFER) 65 | set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) 66 | endfunction () 67 | 68 | 69 | # Helper function to check compiler flags for language compiler. 70 | function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) 71 | if (${LANG} STREQUAL "C") 72 | include(CheckCCompilerFlag) 73 | check_c_compiler_flag("${FLAG}" ${VARIABLE}) 74 | 75 | elseif (${LANG} STREQUAL "CXX") 76 | include(CheckCXXCompilerFlag) 77 | check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) 78 | 79 | elseif (${LANG} STREQUAL "Fortran") 80 | # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible 81 | # with older Cmake versions, we will check if this module is present 82 | # before we use it. Otherwise we will define Fortran coverage support as 83 | # not available. 84 | include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) 85 | if (INCLUDED) 86 | check_fortran_compiler_flag("${FLAG}" ${VARIABLE}) 87 | elseif (NOT CMAKE_REQUIRED_QUIET) 88 | message(STATUS "Performing Test ${VARIABLE}") 89 | message(STATUS "Performing Test ${VARIABLE}" 90 | " - Failed (Check not supported)") 91 | endif () 92 | endif() 93 | endfunction () 94 | 95 | 96 | # Helper function to test compiler flags. 97 | function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) 98 | set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) 99 | 100 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 101 | foreach (LANG ${ENABLED_LANGUAGES}) 102 | # Sanitizer flags are not dependend on language, but the used compiler. 103 | # So instead of searching flags foreach language, search flags foreach 104 | # compiler used. 105 | set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) 106 | if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) 107 | foreach (FLAG ${FLAG_CANDIDATES}) 108 | if(NOT CMAKE_REQUIRED_QUIET) 109 | message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") 110 | endif() 111 | 112 | set(CMAKE_REQUIRED_FLAGS "${FLAG}") 113 | unset(${PREFIX}_FLAG_DETECTED CACHE) 114 | sanitizer_check_compiler_flag("${FLAG}" ${LANG} 115 | ${PREFIX}_FLAG_DETECTED) 116 | 117 | if (${PREFIX}_FLAG_DETECTED) 118 | # If compiler is a GNU compiler, search for static flag, if 119 | # SANITIZE_LINK_STATIC is enabled. 120 | if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) 121 | string(TOLOWER ${PREFIX} PREFIX_lower) 122 | sanitizer_check_compiler_flag( 123 | "-static-lib${PREFIX_lower}" ${LANG} 124 | ${PREFIX}_STATIC_FLAG_DETECTED) 125 | 126 | if (${PREFIX}_STATIC_FLAG_DETECTED) 127 | set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") 128 | endif () 129 | endif () 130 | 131 | set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING 132 | "${NAME} flags for ${COMPILER} compiler.") 133 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 134 | break() 135 | endif () 136 | endforeach () 137 | 138 | if (NOT ${PREFIX}_FLAG_DETECTED) 139 | set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING 140 | "${NAME} flags for ${COMPILER} compiler.") 141 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 142 | 143 | message(WARNING "${NAME} is not available for ${COMPILER} " 144 | "compiler. Targets using this compiler will be " 145 | "compiled without ${NAME}.") 146 | endif () 147 | endif () 148 | endforeach () 149 | endfunction () 150 | 151 | 152 | # Helper to assign sanitizer flags for TARGET. 153 | function (saitizer_add_flags TARGET NAME PREFIX) 154 | # Get list of compilers used by target and check, if sanitizer is available 155 | # for this target. Other compiler checks like check for conflicting 156 | # compilers will be done in add_sanitizers function. 157 | sanitizer_target_compilers(${TARGET} TARGET_COMPILER) 158 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) 159 | if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") 160 | return() 161 | endif() 162 | 163 | # Set compile- and link-flags for target. 164 | set_property(TARGET ${TARGET} APPEND_STRING 165 | PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 166 | set_property(TARGET ${TARGET} APPEND_STRING 167 | PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") 168 | set_property(TARGET ${TARGET} APPEND_STRING 169 | PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 170 | endfunction () 171 | -------------------------------------------------------------------------------- /include/nanosnap/fft.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// @brief FFT module. 3 | /// 4 | 5 | /* 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2019 - Present Light Transport Entertainment, Inc. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | #ifndef NANOSNAP_FFT_H_ 29 | #define NANOSNAP_FFT_H_ 30 | 31 | #include 32 | #include 33 | 34 | namespace nanosnap { 35 | 36 | /// 37 | /// @brief Apply forward 1D FFT for real-typed array of 1D signal 38 | /// 39 | /// Apply 1D FFT with length `fft_size` for each `nrows` of `nframes` input 40 | /// signals. 41 | /// 42 | /// @code 43 | /// Input 44 | /// 45 | /// <--- nframes -----> 46 | /// +-------------------+ 47 | /// | sample 0 | 48 | /// +-------------------+ 49 | /// | sample 1 | 50 | /// +-------------------+ 51 | /// ... 52 | /// +-------------------+ 53 | /// | sample (nrows-1) | 54 | /// +-------------------+ 55 | /// 56 | /// 57 | /// Output 58 | /// <--- 2 * ((nfft_size / 2) + 1) -----> 59 | /// +-----------------------------------+ 60 | /// | real, img, real, img, .. . | sample 0 61 | /// +-----------------------------------+ 62 | /// | real, img, real, img, ... | sample 1 63 | /// +-----------------------------------+ 64 | /// ... 65 | /// +-----------------------------------+ 66 | /// | real, img, real, img, ... | sample (nrows-1) 67 | /// +-----------------------------------+ 68 | /// 69 | /// @endcode 70 | /// 71 | /// 72 | /// @param[in] signal Input signal(real-value). The number of elements are 73 | /// `nframes * nrows` 74 | /// @param[in] nframes The number of frames. 75 | /// @param[in] nrows The number of rows 76 | /// @param[in] fft_size FFT length. 77 | /// @param[out] output Output signal(complex-value). The number of complex-value 78 | /// elements are 79 | /// `(fft_size/2 + 1) * nrows`. 80 | /// @param[in] normalize Normalization mode(default is false. true = normalize 81 | /// by `1/sqrt(n`) 82 | /// @return true upon success. 83 | /// 84 | bool rfft(const float *signal, const size_t nframes, const size_t nrows, 85 | const size_t fft_size, std::vector> *output, 86 | const bool normalize = false); 87 | 88 | /// 89 | /// Double precision version. 90 | /// 91 | bool rfft(const double *signal, const size_t nframes, const size_t nrows, 92 | const size_t fft_size, std::vector> *output, 93 | const bool normalize = false); 94 | 95 | /// 96 | /// @brief Inverse FFT 97 | /// 98 | /// @param[in] input Input array(complex-value). The number of elements are 99 | /// `nframes * nrows` 100 | /// @param[in] ncolumns The number of columns in `a`. 101 | /// @param[in] nrows The number of rows in `a`. 102 | /// @param[in] n Length of the transformed axis of the output. 103 | /// @param[out] output Output signal(complex-value). 104 | /// @return true upon success. 105 | /// 106 | bool ifft(const std::complex *input, const size_t ncolumns, const size_t nrows, const size_t n, 107 | std::vector> *output); 108 | 109 | /// 110 | /// @brief Apply STFT for 1D signal 111 | /// 112 | /// This is an implementation of librosa.stft 113 | /// 114 | /// https://librosa.github.io/librosa/generated/librosa.core.stft.html 115 | /// 116 | /// Assume window function is 'hann' and pad_mode is 'reflect' 117 | /// 118 | /// TODO(LTE): Support other 'pad' mode. 119 | /// TODO(LTE): Support other window function. 120 | /// 121 | /// @param[in] signal Input signal(real-value). 122 | /// @param[in] nsamples The number of samples in input signal. 123 | /// @param[in] n_fft FFT length. 124 | /// @param[in] hop_length Hop length. Default n_fft / 4. 125 | /// @param[in] win_length Window length. Default n_fft. 126 | /// @param[out] output Output signal(complex-value). The number of rows are 127 | /// calculated by `output.size() / n_fft`. 128 | /// @param[in] center Optional. Centerize input signal. Default true. 129 | /// @return true upon success. 130 | /// 131 | bool stft(const float *signal, const size_t nsamples, const size_t n_fft, 132 | const size_t hop_length, const size_t win_length, 133 | std::vector> *output, const bool center = true); 134 | 135 | /// 136 | /// @brief Inverse STFT 137 | /// 138 | /// This is an implementation of librosa.istft 139 | /// 140 | /// https://librosa.github.io/librosa/generated/librosa.core.istft.html 141 | /// 142 | /// Assume window function is 'hann' 143 | /// 144 | /// TODO(LTE): Support other window function. 145 | /// 146 | /// @param[in] stft Input STFT matrix as 1D array(complex-value). 147 | /// @param[in] ncolumns The number of columns in stft matrix(`1 + n_fft /2`). 148 | /// @param[in] nrows The number of rows in stft matrix(`t`). 149 | /// @param[in] hop_length Hop length. Default n_fft / 4. 150 | /// @param[in] win_length Window length. Default n_fft(=(ncolums-1)*2). 151 | /// @param[out] output Output signal(real-value). 152 | /// @param[in] center Optional. Centerize input signal. Default true. 153 | /// @param[in] length Optional. When > 0, set output length to `length`(zero-padded or clipped) 154 | /// @return true upon success. 155 | /// 156 | bool istft(const std::complex *stft, const size_t ncolumns, 157 | const size_t nrows, const size_t hop_length, const size_t win_length, 158 | std::vector *output, const bool center = true, const int length = 0); 159 | 160 | } // namespace nanosnap 161 | 162 | #endif // NANOSNAP_FFT_H_ 163 | -------------------------------------------------------------------------------- /scripts/bootstrap-linux.sh: -------------------------------------------------------------------------------- 1 | rm -rf build 2 | 3 | CXX=clang++ CC=clang cmake -Bbuild -H. -DSANITIZE_ADDRESS=On 4 | -------------------------------------------------------------------------------- /src/audio_wav.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/nanosnap.h" 25 | 26 | #ifdef NANOSNAP_NO_STDIO 27 | #ifndef DR_WAV_NO_STDIO 28 | #define DR_WAV_NO_STDIO 29 | #endif 30 | #endif 31 | 32 | #ifdef __clang__ 33 | #pragma clang diagnostic push 34 | #pragma clang diagnostic ignored "-Weverything" 35 | #endif 36 | 37 | #ifdef __GNUC__ 38 | #pragma GCC diagnostic push 39 | #pragma GCC diagnostic ignored "-Wredundant-decls" 40 | #pragma GCC diagnostic ignored "-Wold-style-cast" 41 | #pragma GCC diagnostic ignored "-Wsign-conversion" 42 | #pragma GCC diagnostic ignored "-Wmissing-declarations" 43 | #endif 44 | 45 | #define DR_WAV_IMPLEMENTATION 46 | #include "dr_wav.h" 47 | 48 | #ifdef __clang__ 49 | #pragma clang diagnostic pop 50 | #endif 51 | 52 | #ifdef __GNUC__ 53 | #pragma GCC diagnostic pop 54 | #endif 55 | 56 | namespace nanosnap { 57 | 58 | bool wav_read(const std::string &filename, uint32_t *rate, std::string *dtype, 59 | uint32_t *channels, uint64_t *samples, std::vector *data, 60 | std::string *err) { 61 | #ifdef NANOSNAP_NO_STDIO 62 | (void)filename; 63 | (void)rate; 64 | (void)dtype; 65 | (void)channels; 66 | (void)data; 67 | 68 | if (err) { 69 | (*err) += 70 | "IO is disabled in this build. Use `wav_read_from_buffer` instead.\n"; 71 | } 72 | 73 | return false; 74 | #else 75 | 76 | if (!rate) { 77 | if (err) { 78 | (*err) += "nullptr is set to `rate` parameter.\n"; 79 | } 80 | return false; 81 | } 82 | 83 | if (!channels) { 84 | if (err) { 85 | (*err) += "nullptr is set to `channels` parameter.\n"; 86 | } 87 | return false; 88 | } 89 | 90 | if (!dtype) { 91 | if (err) { 92 | (*err) += "nullptr is set to `dtype` parameter.\n"; 93 | } 94 | return false; 95 | } 96 | 97 | if (!data) { 98 | if (err) { 99 | (*err) += "nullptr is set to `data` parameter.\n"; 100 | } 101 | return false; 102 | } 103 | 104 | drwav *pwav = drwav_open_file(filename.c_str()); 105 | 106 | if (!pwav) { 107 | if (err) { 108 | (*err) += "Error opening WAV file. File not found or not a WAV file? : " + 109 | filename + "\n"; 110 | } 111 | return false; 112 | } 113 | 114 | if (pwav->bitsPerSample == 8) { 115 | (*dtype) = "uint8"; 116 | } else if (pwav->bitsPerSample == 16) { 117 | (*dtype) = "int16"; 118 | } else if (pwav->bitsPerSample == 32) { 119 | if (pwav->fmt.formatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { 120 | (*dtype) = "float32"; 121 | } else { 122 | (*dtype) = "float32"; 123 | } 124 | } else if ((pwav->bitsPerSample == 64) && 125 | (pwav->fmt.formatTag == DR_WAVE_FORMAT_IEEE_FLOAT)) { 126 | (*dtype) = "float64"; 127 | } else { 128 | if (err) { 129 | (*err) = "Unsupported format type. bitsPerSample = " + 130 | std::to_string(int(pwav->bitsPerSample)) + 131 | ", format = " + std::to_string(int(pwav->fmt.formatTag)) + "\n"; 132 | } 133 | 134 | drwav_close(pwav); 135 | 136 | return false; 137 | } 138 | 139 | size_t data_len = size_t(pwav->totalPCMFrameCount * pwav->channels * 140 | (pwav->bitsPerSample / 8)); 141 | data->resize(data_len); 142 | drwav_uint64 frame_bytes_read = drwav_read_pcm_frames( 143 | pwav, pwav->totalPCMFrameCount, reinterpret_cast(data->data())); 144 | 145 | if (frame_bytes_read != pwav->totalPCMFrameCount) { 146 | if (err) { 147 | (*err) = "The number of frames read(" + std::to_string(frame_bytes_read) + 148 | ") does not match PCM frames(" + 149 | std::to_string(pwav->totalPCMFrameCount) + ")\n"; 150 | } 151 | 152 | drwav_close(pwav); 153 | 154 | return false; 155 | } 156 | 157 | (*channels) = pwav->channels; 158 | (*rate) = pwav->sampleRate; 159 | (*samples) = pwav->totalPCMFrameCount; 160 | 161 | drwav_close(pwav); 162 | 163 | return true; 164 | 165 | #endif // NANOSNAP_NO_STDIO 166 | } 167 | 168 | bool wav_write(const std::string &filename, const uint32_t rate, 169 | const std::string &dtype, const uint32_t channels, 170 | const uint64_t samples, const uint8_t *data, std::string *err) { 171 | #ifdef NANOSNAP_NO_STDIO 172 | (void)filename; 173 | (void)rate; 174 | (void)dtype; 175 | (void)channels; 176 | (void)data; 177 | 178 | if (err) { 179 | (*err) += 180 | "IO is disabled in this build. Use `wav_write_to_buffer` instead.\n"; 181 | } 182 | 183 | return false; 184 | #else 185 | 186 | drwav_uint32 bps = 0; 187 | if (dtype.compare("float32") == 0) { 188 | bps = 32; 189 | } else if (dtype.compare("int32") == 0) { 190 | bps = 32; 191 | } else if (dtype.compare("int16") == 0) { 192 | bps = 16; 193 | } else if (dtype.compare("uint8") == 0) { 194 | bps = 8; 195 | } 196 | 197 | assert(bps > 0); 198 | 199 | drwav_data_format data_format; 200 | data_format.container = drwav_container_riff; 201 | data_format.format = DR_WAVE_FORMAT_PCM; 202 | data_format.channels = channels; 203 | data_format.sampleRate = rate; 204 | data_format.bitsPerSample = bps; 205 | 206 | drwav *pwav = drwav_open_file_write(filename.c_str(), &data_format); 207 | if (!pwav) { 208 | if (err) { 209 | (*err) += 210 | "Failed to open WAV file to write. WAV format(channels/rate) is " 211 | "invalid or cannot write to disk : " + 212 | filename + "\n"; 213 | } 214 | return false; 215 | } 216 | 217 | drwav_uint64 sz = drwav_write_pcm_frames(pwav, samples, reinterpret_cast(data)); 218 | 219 | if (sz == 0) { 220 | if (err) { 221 | (*err) += "Failed to write PCM frames.\n"; 222 | } 223 | return false; 224 | } 225 | 226 | drwav_close(pwav); 227 | 228 | return true; 229 | 230 | #endif // !NANOSNAP_NO_STDIO 231 | } 232 | 233 | } // namespace nanosnap 234 | -------------------------------------------------------------------------------- /src/fft.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/fft.h" 25 | #include "nanosnap/nanosnap.h" 26 | 27 | #include "pocketfft.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | //#include // dbg 37 | 38 | namespace nanosnap { 39 | 40 | namespace { 41 | 42 | static bool pad_center(const std::vector &data, const size_t n, std::vector *output) 43 | { 44 | if (data.size() > n) { 45 | return false; 46 | } 47 | 48 | const size_t pad_width = (n - data.size()) / 2; 49 | 50 | bool ret = pad_constant(data.data(), data.size(), pad_width, pad_width, output, /* pad constant value */0.0f); 51 | 52 | return ret; 53 | } 54 | 55 | // librosa.utils.frame 56 | // 1D signal input only 57 | // output will have shape [out_rows][frame_length] 58 | static bool frame_sig(const std::vector &y, 59 | std::vector *output, 60 | size_t *out_rows, 61 | const size_t frame_length = 2048, 62 | const size_t hop_length = 512) { 63 | if (y.size() < frame_length) { 64 | return false; 65 | } 66 | 67 | if (hop_length < 1) { 68 | return false; 69 | } 70 | 71 | if (hop_length > frame_length) { 72 | return false; 73 | } 74 | 75 | // Compute the number of frames that will fit. The end may get truncated. 76 | const size_t n_frames = 1 + ((y.size() - frame_length) / hop_length); 77 | 78 | // Vertical stride is one sample 79 | // Horizontal stride is `hop_length` samples 80 | // y_frames = as_strided(y, shape=(frame_length, n_frames), 81 | // strides=(y.itemsize, hop_length * y.itemsize)) 82 | 83 | output->resize(n_frames * frame_length); 84 | for (size_t j = 0; j < frame_length; j++) { 85 | for (size_t i = 0; i < n_frames; i++) { 86 | (*output)[j * n_frames + i] = y[i * hop_length + j]; 87 | } 88 | } 89 | 90 | (*out_rows) = n_frames; 91 | 92 | return true; 93 | } 94 | 95 | // librosa.window_sumsquare 96 | // 'hann' window only. norm = 'None' 97 | bool hann_window_sumsquare( 98 | const size_t n_frames, const size_t hop_length, const size_t win_length, const size_t n_fft, 99 | std::vector *output) 100 | { 101 | const size_t n = n_fft + hop_length * (n_frames - 1); 102 | std::vector x(n, 0.0f); 103 | 104 | // Compute the squared window at the desired length 105 | std::vector win_sq; 106 | { 107 | std::vector _win_sq; 108 | bool ret = get_window("hann", win_length, &_win_sq); 109 | if (!ret) { 110 | return false; 111 | } 112 | 113 | // abs(x)^2 114 | for (size_t i = 0; i < _win_sq.size(); i++) { 115 | _win_sq[i] = _win_sq[i] * _win_sq[i]; 116 | } 117 | 118 | // pad_center 119 | ret = pad_center(_win_sq, n_fft, &win_sq); 120 | if (!ret) { 121 | return false; 122 | } 123 | } 124 | 125 | // Fill the envelope 126 | // __window_ss_fill(x, win_sq, n_frames, hop_length) 127 | { 128 | for (size_t i = 0; i < n_frames; i++) { 129 | size_t sample = i * hop_length; 130 | size_t end_idx = (std::min)(x.size(), sample + n_fft); 131 | 132 | // x[sample:min(n, sample + n_fft)] += win_sq[:max(0, min(n_fft, n - sample))] 133 | for (size_t k = sample; k < end_idx; k++) { 134 | // clamp for safety 135 | size_t win_idx = (std::min)(n_fft - 1, k - sample); 136 | x[k] += win_sq[win_idx]; 137 | } 138 | } 139 | } 140 | 141 | (*output) = x; // copy 142 | 143 | return true; 144 | } 145 | 146 | 147 | } // namespace 148 | 149 | // 1D real fft. 150 | bool rfft(const float *signal, const size_t nframes, const size_t nrows, 151 | const size_t fft_size, std::vector> *output, 152 | const bool normalize) { 153 | if (signal == nullptr) { 154 | return false; 155 | } 156 | 157 | if ((nframes < 1) || (nrows < 1)) { 158 | return false; 159 | } 160 | 161 | // TODO(LTE): Support fft_size != (nframes-1). 162 | assert(fft_size == (nframes - 1)); 163 | 164 | // to double. 165 | std::vector dsignal; 166 | dsignal.resize(nframes * nrows); 167 | 168 | for (size_t i = 0; i < nframes * nrows; i++) { 169 | dsignal[i] = double(signal[i]); 170 | } 171 | 172 | std::vector dout; // (real, img), (real, img), ... 173 | size_t output_nframes = (fft_size / 2) + 1; 174 | // 2x is for considering complex-type 175 | dout.resize(2 * output_nframes * nrows); 176 | memset(reinterpret_cast(dout.data()), 0, 177 | sizeof(double) * 2 * output_nframes * nrows); 178 | 179 | float norm_factor = 1.0f; 180 | if (normalize) { 181 | norm_factor = 1.0f / std::sqrt(float(nframes)); 182 | } 183 | 184 | int n = rfft_forward_1d_array(dsignal.data(), int(fft_size), int(nframes), 185 | int(nrows), norm_factor, dout.data()); 186 | 187 | if (n != int(nrows)) { 188 | return false; 189 | } 190 | 191 | // Cast from double to float. 192 | output->resize(output_nframes * nrows); 193 | for (size_t j = 0; j < nrows; j++) { 194 | for (size_t i = 0; i < output_nframes; i++) { 195 | (*output)[j * output_nframes + i] = 196 | std::complex(float(dout[2 * (j * output_nframes + i) + 0]), 197 | float(dout[2 * (j * output_nframes + i) + 1])); 198 | } 199 | } 200 | 201 | return true; 202 | } 203 | 204 | // 1D ifft 205 | bool ifft(const std::complex *input, const size_t ncolumns, const size_t nrows, 206 | const size_t n, std::vector> *output) { 207 | if (input == nullptr) { 208 | return false; 209 | } 210 | 211 | if ((ncolumns < 1) || (nrows < 1)) { 212 | return false; 213 | } 214 | 215 | size_t output_n = n; 216 | 217 | // to pair of doubles. 218 | std::vector dinput; 219 | dinput.resize(2 * output_n * nrows); 220 | 221 | // clear with zeros. 222 | memset(dinput.data(), 0, sizeof(double) * dinput.size()); 223 | 224 | // Create an array of pair of doubles. 225 | // Also resize columns 226 | for (size_t j = 0; j < nrows; j++) { 227 | for (size_t i = 0; i < output_n; i++) { 228 | const size_t src_idx = j * ncolumns + i; 229 | dinput[2 * (j * output_n + i) + 0] = double(input[src_idx].real()); 230 | dinput[2 * (j * output_n + i) + 1] = double(input[src_idx].imag()); 231 | } 232 | } 233 | 234 | std::vector dout; // (real, img), (real, img), ... 235 | // 2x is for considering complex-type 236 | dout.resize(2 * output_n * nrows); 237 | memset(reinterpret_cast(dout.data()), 0, 238 | sizeof(double) * 2 * output_n * nrows); 239 | 240 | float norm_factor = 1.0f / float(n); 241 | 242 | // TODO(LTE): Implement norm = "ortho" 243 | // if (normalize) { 244 | // norm_factor = 1.0f / sqrt(n); 245 | // } 246 | 247 | (void)norm_factor; 248 | 249 | int m = cfft_backward_1d_array(dinput.data(), int(output_n), int(nrows), norm_factor, dout.data()); 250 | 251 | if (m != int(nrows)) { 252 | return false; 253 | } 254 | 255 | // Cast from double to float. 256 | output->resize(output_n * nrows); 257 | for (size_t j = 0; j < nrows; j++) { 258 | for (size_t i = 0; i < output_n; i++) { 259 | (*output)[j * output_n + i] = 260 | std::complex(float(dout[2 * (j * output_n + i) + 0]), 261 | float(dout[2 * (j * output_n + i) + 1])); 262 | } 263 | } 264 | 265 | return true; 266 | } 267 | 268 | 269 | // librosa.stft(1D input only) 270 | bool stft(const float *signal, const size_t sig_len, const size_t n_fft, 271 | const size_t hop_length, const size_t win_length, 272 | std::vector> *output, const bool center) { 273 | 274 | // NOTE(LTE): librosa's stft implementation uses Fortran order of array. 275 | // Need to consider flipping row and columns in appropriate place. 276 | // 277 | // TODO(LTE): Rewrite stft without transposing shape to avoid confusion. 278 | 279 | std::vector y; 280 | 281 | if (center) { 282 | // Pad the time series 283 | // y = np.pad(y, int(n_fft // 2), mode=pad_mode) 284 | bool ret = pad_reflect(signal, sig_len, n_fft / 2, n_fft / 2, &y); 285 | if (!ret) { 286 | return false; 287 | } 288 | } else { 289 | y.resize(sig_len); 290 | memcpy(y.data(), signal, sig_len * sizeof(float)); 291 | } 292 | 293 | std::vector _window; 294 | { 295 | bool ret = get_window("hann", win_length, &_window, /* periodic */true); 296 | if (!ret) { 297 | return false; 298 | } 299 | } 300 | 301 | // Pad the window out to n_fft size 302 | std::vector window; 303 | { 304 | bool ret= pad_center(_window, n_fft, &window); 305 | if (!ret) { 306 | return false; 307 | } 308 | } 309 | 310 | std::vector y_frames; 311 | size_t n_rows = 0; 312 | { 313 | bool ret = frame_sig(y, &y_frames, &n_rows, n_fft, hop_length); 314 | if (!ret) { 315 | return false; 316 | } 317 | } 318 | 319 | // Flip dimension to match numpy(librosa)'s Fortran order. 320 | 321 | size_t frame_length = n_rows; 322 | size_t nframes = n_fft; 323 | 324 | //std::cout << "window.size = [" << window.size() << "\n"; 325 | //std::cout << "nframes = " << nframes << "\n"; 326 | //std::cout << "frame_length = [[" << frame_length << "\n"; 327 | //for (size_t i = 0; i < y_frames.size(); i++) { 328 | // std::cout << "y_frames[" << i << "] = " << y_frames[i] << "\n"; 329 | //} 330 | 331 | std::vector y_modulated(y_frames.size()); 332 | 333 | // Apply window function. 334 | for (size_t j = 0; j < nframes; j++) { 335 | for (size_t i = 0; i < frame_length; i++) { 336 | //y_modulated[j * frame_length + i] = y_frames[j * frame_length + i] * window[j]; 337 | 338 | // transpose y_modulated 339 | y_modulated[i * nframes + j] = y_frames[j * frame_length + i] * window[j]; 340 | } 341 | } 342 | 343 | //for (size_t i = 0; i < y_modulated.size(); i++) { 344 | // std::cout << "modulated y_frames[" << i << "] = " << y_modulated[i] << "\n"; 345 | //} 346 | 347 | //std::cout << "nframes = " << nframes << std::endl; 348 | //std::cout << "frame_len = " << frame_length << std::endl; 349 | 350 | // transpose frame_len and num_frames 351 | bool ret = rfft(y_modulated.data(), /* frame len */nframes, /* num frames */frame_length, /* fft size */nframes, output); 352 | 353 | //for (size_t i = 0; i < output->size(); i++) { 354 | // std::cout << "output[" << i << "] = " << (*output)[i] << std::endl; 355 | //} 356 | 357 | return ret; 358 | } 359 | 360 | bool istft(const std::complex *stft, const size_t ncolumns, 361 | const size_t nrows, const size_t hop_length, const size_t win_length, 362 | std::vector *output, const bool center, const int length) 363 | { 364 | size_t n_fft = 2 * (ncolumns -1); 365 | 366 | //std::cout << "win_length = " << win_length << std::endl; 367 | //std::cout << "n_fft = " << n_fft << std::endl; 368 | 369 | std::vector _ifft_window; 370 | { 371 | bool ret = get_window("hann", win_length, &_ifft_window, /* periodic */true); 372 | if (!ret) { 373 | return false; 374 | } 375 | } 376 | 377 | // Pad out to match n_fft 378 | std::vector ifft_window; 379 | { 380 | bool ret = pad_center(_ifft_window, n_fft, &ifft_window); 381 | if (!ret) { 382 | return false; 383 | } 384 | } 385 | 386 | size_t n_frames = nrows; 387 | size_t expected_signal_len = n_fft + hop_length * (n_frames - 1); 388 | 389 | // y = np.zeros(expected_signal_len, dtype=dtype) 390 | std::vector y(expected_signal_len, 0.0f); 391 | 392 | /* 393 | for i in range(n_frames): 394 | sample = i * hop_length 395 | spec = stft_matrix[:, i].flatten() 396 | spec = np.concatenate((spec, spec[-2:0:-1].conj()), 0) 397 | ytmp = ifft_window * fft.ifft(spec).real 398 | 399 | y[sample:(sample + n_fft)] = y[sample:(sample + n_fft)] + ytmp 400 | */ 401 | for (size_t i = 0; i < n_frames; i++) { 402 | size_t sample = i * hop_length; 403 | 404 | // spec = stft_matrix[:, i].flatten() 405 | // => extract each row 406 | 407 | // spec = np.concatenate((spec, spec[-2:0:-1].conj()), 0) 408 | // => reflect with conjugate. 409 | // e.g. spec [a, b, c, d, e] 410 | // 411 | // np.concatenate((spec, spec[-2:0:-1].conj()), 0) 412 | // 413 | // => [a, b, c, d, e, d.conj(), c.conj(), b.conj()] 414 | 415 | std::vector> spec(n_fft); 416 | 417 | // spec = stft_matrix[:, i].flatten() 418 | for (size_t k = 0; k < ncolumns; k++) { 419 | spec[k] = stft[i * ncolumns + k]; 420 | } 421 | 422 | // concat: spec[-2:0:-1].conj 423 | for (size_t k = 0; k < ncolumns - 2; k++) { 424 | spec[ncolumns + k] = std::conj(spec[ncolumns - 2 - k]); 425 | } 426 | 427 | // ytmp = ifft_window * fft.ifft(spec).real 428 | 429 | std::vector ytemp(n_fft); 430 | std::vector> ifft_spec; 431 | 432 | bool ret = ifft(spec.data(), n_fft, /* 1D */1, /* n */n_fft, &ifft_spec); 433 | 434 | if (!ret) { 435 | return false; 436 | } 437 | 438 | 439 | for (size_t k = 0; k < n_fft; k++) { 440 | ytemp[k] = ifft_window[k] * ifft_spec[k].real(); 441 | } 442 | 443 | // y[sample:(sample + n_fft)] = y[sample:(sample + n_fft)] + ytmp 444 | for (size_t k = 0; k < n_fft; k++) { 445 | y[sample + k] += ytemp[k]; 446 | } 447 | } 448 | 449 | // Normalize by sum of squared window 450 | std::vector ifft_window_sum; 451 | { 452 | bool ret = hann_window_sumsquare(n_frames, hop_length, win_length, n_fft, &ifft_window_sum); 453 | if (!ret) { 454 | return false; 455 | } 456 | } 457 | 458 | // approx_nonzero_indices = ifft_window_sum > util.tiny(ifft_window_sum) 459 | // y[approx_nonzero_indices] /= ifft_window_sum[approx_nonzero_indices] 460 | assert(y.size() == ifft_window_sum.size()); 461 | 462 | for (size_t i = 0; i < y.size(); i++) { 463 | if (y[i] > std::numeric_limits::min()) { 464 | y[i] /= ifft_window_sum[i]; 465 | } 466 | } 467 | 468 | // if length is None: 469 | // # If we don't need to control length, just do the usual center trimming 470 | // # to eliminate padded data 471 | // if center: 472 | // y = y[int(n_fft // 2):-int(n_fft // 2)] 473 | 474 | // TODO(LTE): Support `length` parameter. 475 | if (center) { 476 | // eliminate padded data. 477 | const size_t s_idx = n_fft / 2; 478 | const size_t e_idx = size_t(int64_t(y.size()) - (int64_t(n_fft) / 2)); 479 | 480 | output->resize(e_idx - s_idx); 481 | for (size_t i = s_idx; i < e_idx; i++) { 482 | (*output)[i - s_idx] = y[i]; 483 | } 484 | } else { 485 | (*output) = y; 486 | } 487 | 488 | return true; 489 | } 490 | 491 | } // namespace nanosnap 492 | -------------------------------------------------------------------------------- /src/image.cc: -------------------------------------------------------------------------------- 1 | #ifdef __clang__ 2 | #pragma clang diagnostic push 3 | #pragma clang diagnostic ignored "-Weverything" 4 | #endif 5 | 6 | #define STB_IMAGE_IMPLEMENTATION 7 | #include "stb_image.h" 8 | 9 | #define STB_IMAGE_WRITE_IMPLEMENTATION 10 | #include "stb_image_write.h" 11 | 12 | #define STB_IMAGE_RESIZE_IMPLEMENTATION 13 | #include "stb_image_resize.h" 14 | 15 | 16 | #ifdef __clang__ 17 | #pragma clang diagnostic pop 18 | #endif 19 | 20 | #include "nanosnap/nanosnap.h" 21 | 22 | #include 23 | #include // std::tolower 24 | 25 | namespace nanosnap { 26 | 27 | namespace { 28 | 29 | std::string GetFileExtension(const std::string &filename) { 30 | if (filename.find_last_of(".") != std::string::npos) 31 | return filename.substr(filename.find_last_of(".") + 1); 32 | return ""; 33 | } 34 | 35 | // chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html 36 | // Fast and efficient sRGB -> Linear conversion. Error is small(abs diff <= 0.0018) 37 | inline float sRGBToLinearFast(const float &sRGB) { 38 | const float Linear = sRGB * (sRGB * (sRGB * 0.305306011f + 0.682171111f) + 0.012522878f); 39 | return Linear; 40 | } 41 | 42 | /* 43 | * sRGB transform (C++) 44 | * 45 | * Copyright (c) 2017 Project Nayuki. (MIT License) 46 | * https://www.nayuki.io/page/srgb-transform-library 47 | */ 48 | const float SRGB_8BIT_TO_LINEAR_FLOAT[1 << 8] = { 49 | 0.0f, 3.03527e-4f, 6.07054e-4f, 9.10581e-4f, 50 | 0.001214108f, 0.001517635f, 0.001821162f, 0.0021246888f, 51 | 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465358f, 52 | 0.0036765074f, 0.004024717f, 0.004391442f, 0.0047769537f, 53 | 0.005181517f, 0.005605392f, 0.0060488335f, 0.006512091f, 54 | 0.0069954107f, 0.007499032f, 0.008023193f, 0.008568126f, 55 | 0.009134059f, 0.009721218f, 0.010329823f, 0.010960095f, 56 | 0.011612245f, 0.012286489f, 0.0129830325f, 0.013702083f, 57 | 0.014443845f, 0.015208516f, 0.015996294f, 0.016807377f, 58 | 0.017641956f, 0.018500222f, 0.019382363f, 0.020288564f, 59 | 0.021219011f, 0.022173885f, 0.023153368f, 0.024157634f, 60 | 0.025186861f, 0.026241222f, 0.027320893f, 0.02842604f, 61 | 0.029556835f, 0.030713445f, 0.031896032f, 0.033104766f, 62 | 0.034339808f, 0.035601314f, 0.036889452f, 0.038204372f, 63 | 0.039546236f, 0.0409152f, 0.04231141f, 0.04373503f, 64 | 0.045186203f, 0.046665087f, 0.048171826f, 0.049706567f, 65 | 0.051269464f, 0.05286065f, 0.05448028f, 0.056128494f, 66 | 0.057805438f, 0.059511244f, 0.06124606f, 0.06301002f, 67 | 0.06480327f, 0.066625945f, 0.068478175f, 0.0703601f, 68 | 0.07227185f, 0.07421357f, 0.07618539f, 0.07818743f, 69 | 0.08021983f, 0.082282715f, 0.084376216f, 0.086500466f, 70 | 0.08865559f, 0.09084172f, 0.093058966f, 0.09530747f, 71 | 0.097587354f, 0.09989873f, 0.10224174f, 0.10461649f, 72 | 0.107023105f, 0.10946172f, 0.111932434f, 0.11443538f, 73 | 0.11697067f, 0.119538434f, 0.122138776f, 0.12477182f, 74 | 0.12743768f, 0.13013647f, 0.13286832f, 0.13563333f, 75 | 0.13843162f, 0.14126329f, 0.14412847f, 0.14702727f, 76 | 0.14995979f, 0.15292616f, 0.15592647f, 0.15896083f, 77 | 0.16202939f, 0.1651322f, 0.1682694f, 0.17144111f, 78 | 0.1746474f, 0.17788842f, 0.18116425f, 0.18447499f, 79 | 0.18782078f, 0.19120169f, 0.19461784f, 0.19806932f, 80 | 0.20155625f, 0.20507874f, 0.20863687f, 0.21223076f, 81 | 0.21586053f, 0.21952623f, 0.22322798f, 0.2269659f, 82 | 0.23074007f, 0.23455061f, 0.2383976f, 0.24228115f, 83 | 0.24620135f, 0.2501583f, 0.25415212f, 0.25818288f, 84 | 0.2622507f, 0.26635563f, 0.27049783f, 0.27467734f, 85 | 0.2788943f, 0.28314877f, 0.28744087f, 0.29177067f, 86 | 0.2961383f, 0.3005438f, 0.30498734f, 0.30946895f, 87 | 0.31398875f, 0.3185468f, 0.32314324f, 0.32777813f, 88 | 0.33245155f, 0.33716366f, 0.34191445f, 0.3467041f, 89 | 0.35153264f, 0.35640016f, 0.36130682f, 0.36625263f, 90 | 0.3712377f, 0.37626216f, 0.38132605f, 0.38642946f, 91 | 0.3915725f, 0.39675525f, 0.4019778f, 0.40724024f, 92 | 0.41254264f, 0.4178851f, 0.4232677f, 0.42869052f, 93 | 0.43415368f, 0.4396572f, 0.44520122f, 0.45078582f, 94 | 0.45641103f, 0.46207702f, 0.4677838f, 0.4735315f, 95 | 0.4793202f, 0.48514995f, 0.4910209f, 0.496933f, 96 | 0.5028865f, 0.50888133f, 0.5149177f, 0.5209956f, 97 | 0.52711517f, 0.53327644f, 0.5394795f, 0.5457245f, 98 | 0.55201143f, 0.55834043f, 0.5647115f, 0.57112485f, 99 | 0.57758045f, 0.58407843f, 0.59061885f, 0.5972018f, 100 | 0.60382736f, 0.61049557f, 0.6172066f, 0.62396044f, 101 | 0.63075715f, 0.6375969f, 0.6444797f, 0.65140563f, 102 | 0.65837485f, 0.66538733f, 0.67244315f, 0.6795425f, 103 | 0.6866853f, 0.6938718f, 0.7011019f, 0.7083758f, 104 | 0.71569353f, 0.7230551f, 0.73046076f, 0.73791045f, 105 | 0.74540424f, 0.7529422f, 0.7605245f, 0.76815116f, 106 | 0.7758222f, 0.7835378f, 0.791298f, 0.7991027f, 107 | 0.8069523f, 0.8148466f, 0.82278574f, 0.8307699f, 108 | 0.838799f, 0.8468732f, 0.8549926f, 0.8631572f, 109 | 0.8713671f, 0.8796224f, 0.8879231f, 0.8962694f, 110 | 0.9046612f, 0.91309863f, 0.92158186f, 0.9301109f, 111 | 0.9386857f, 0.9473065f, 0.9559733f, 0.9646863f, 112 | 0.9734453f, 0.9822506f, 0.9911021f, 1.0f, 113 | }; 114 | 115 | inline int linearToSrgb8bit(float x) { 116 | if (x <= 0.0f) 117 | return 0; 118 | if (x >= 1.0f) 119 | return 255; 120 | const float *TABLE = SRGB_8BIT_TO_LINEAR_FLOAT; 121 | int y = 0; 122 | for (int i = 128; i != 0; i >>= 1) { 123 | if (TABLE[y + i] <= x) 124 | y += i; 125 | } 126 | if (x - TABLE[y] <= TABLE[y + 1] - x) 127 | return y; 128 | else 129 | return y + 1; 130 | } 131 | 132 | 133 | } // namespace 134 | 135 | bool resize_bilinear(const float *src, const int32_t src_width, 136 | const int32_t src_width_stride, const int32_t src_height, 137 | const int32_t channels, const int32_t dst_width, 138 | const int32_t dst_width_stride, const int32_t dst_height, 139 | std::vector *dst) { 140 | if (!src) { 141 | return false; 142 | } 143 | 144 | if ((src_width < 1) || (src_width_stride < 1) || (src_height < 1)) { 145 | return false; 146 | } 147 | 148 | // Up to RGBA 149 | if ((channels < 1) || (channels > 4)) { 150 | return false; 151 | } 152 | 153 | if ((dst_width < 1) || (dst_width_stride < 1) || (dst_height < 1)) { 154 | return false; 155 | } 156 | 157 | dst->resize(size_t(dst_width_stride * dst_height * channels)); 158 | 159 | int n = stbir_resize_float( 160 | src, int(src_width), int(src_height), int(src_width_stride), dst->data(), 161 | int(dst_width), int(dst_height), int(dst_width_stride), int(channels)); 162 | 163 | if (n < 1) { 164 | return false; 165 | } 166 | 167 | return true; 168 | } 169 | 170 | bool imread(const std::string &filename, std::vector *image, int32_t *width, int32_t *height, int32_t *channels, const bool srgb_to_linear) 171 | { 172 | if (!image) { 173 | return false; 174 | } 175 | 176 | int image_width; 177 | int image_height; 178 | int n; 179 | 180 | unsigned char *data = stbi_load(filename.c_str(), &image_width, &image_height, 181 | &n, STBI_default); 182 | 183 | if (!data) { 184 | return false; 185 | } 186 | 187 | image->resize(size_t(image_width * image_height * n)); 188 | 189 | const float inv_scale = 1.0f / 255.0f; 190 | 191 | for (size_t i = 0; i < size_t(image_width * image_height); i++) { 192 | for (size_t c = 0; c < size_t(n); c++) { 193 | 194 | float value = data[size_t(n) * i + c] * inv_scale; 195 | 196 | // do not apply degamma for alpha channel. 197 | if (srgb_to_linear && (c < 4)) { 198 | value = sRGBToLinearFast(value); 199 | } 200 | (*image)[size_t(n) * i + c] = value; 201 | } 202 | } 203 | 204 | stbi_image_free(data); 205 | 206 | if (width) { 207 | (*width) = image_width; 208 | } 209 | 210 | if (height) { 211 | (*height) = image_height; 212 | } 213 | 214 | if (channels) { 215 | (*channels) = n; 216 | } 217 | 218 | return true; 219 | } 220 | 221 | bool imsave(const std::string &filename, std::vector &image, const int32_t width, const int32_t height, const int32_t channels, const bool linear_to_srgb) { 222 | 223 | std::string ext = GetFileExtension(filename); 224 | 225 | std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) -> unsigned char { 226 | return static_cast(std::tolower(c)); 227 | }); 228 | 229 | std::vector buf(image.size()); 230 | 231 | for (size_t i = 0; i < size_t(width * height); i++) { 232 | for (size_t c = 0; c < size_t(channels); c++) { 233 | 234 | const float src = image[size_t(channels) * i + c]; 235 | 236 | int value; 237 | 238 | // do not apply sRGB conversion for alpha channel. 239 | if (linear_to_srgb && (c < 4)) { 240 | value = linearToSrgb8bit(src); 241 | } else { 242 | value = int(src * 255.0f); 243 | } 244 | 245 | buf[size_t(channels) * i + c] = static_cast(std::max(0, std::min(255, value))); 246 | } 247 | } 248 | 249 | if ((ext.compare("jpg") == 0) || (ext.compare("jpeg") == 0)) { 250 | int ret = stbi_write_jpg(filename.c_str(), width, height, channels, reinterpret_cast(buf.data()), /* quality */100); 251 | 252 | if (ret < 1) { 253 | return false; 254 | } 255 | } else { // save as PNG 256 | int ret = stbi_write_png(filename.c_str(), width, height, channels, reinterpret_cast(buf.data()), /* stride */0); 257 | 258 | if (ret < 1) { 259 | return false; 260 | } 261 | } 262 | 263 | return true; 264 | 265 | } 266 | 267 | 268 | } // namespace nanosnap 269 | -------------------------------------------------------------------------------- /src/mel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // #include // DBG 5 | 6 | #include "nanosnap/nanosnap.h" 7 | 8 | namespace nanosnap { 9 | 10 | namespace { 11 | 12 | template 13 | inline T safe_div(const T a, const T b) { 14 | if (std::fabs(b) < std::numeric_limits::epsilon()) { 15 | return static_cast(0.0); 16 | } else { 17 | return a / b; 18 | } 19 | } 20 | 21 | // numpy.linspace in C++ 22 | static std::vector linspace(const float start, const float stop, 23 | const size_t num = 50, 24 | const bool end_point = true) { 25 | std::vector w(num); 26 | 27 | int denom = end_point ? (int(num) - 1) : int(num); 28 | 29 | float step = safe_div(stop - start, float(denom)); 30 | 31 | for (size_t i = 0; i < num; i++) { 32 | w[i] = i * step; 33 | } 34 | 35 | return w; 36 | } 37 | 38 | std::vector fft_frequencies(const float sr, const int n_fft) { 39 | return linspace(/* start */ 0.0f, /* end */ sr / 2.0f, 40 | /* num */ size_t(1 + n_fft / 2), /* endpoint */ true); 41 | } 42 | 43 | float hz_to_mel(const float freq, bool htk = false) { 44 | if (htk) { 45 | return hz2mel(freq); 46 | } 47 | 48 | // Fill in the linear part 49 | const float f_min = 0.0f; 50 | const float f_sp = 200.0f / 3.0f; 51 | 52 | float mels = (freq - f_min) / f_sp; 53 | 54 | // Fill in the log-scale part 55 | 56 | const float min_log_hz = 1000.0f; // beginning of log region (Hz) 57 | const float min_log_mel = (min_log_hz - f_min) / f_sp; // same (Mels) 58 | const float logstep = std::log(6.4f) / 27.0f; // step size for log region 59 | 60 | if (freq >= min_log_hz) { 61 | mels = min_log_mel + std::log(freq / min_log_hz) / logstep; 62 | } 63 | 64 | return mels; 65 | } 66 | 67 | float mel_to_hz(const float mel, bool htk = false) { 68 | if (htk) { 69 | return mel2hz(mel); 70 | } 71 | 72 | // Fill in the linear scale 73 | const float f_min = 0.0f; 74 | const float f_sp = 200.0f / 3.0f; 75 | float freqs = f_min + f_sp * mel; 76 | 77 | // And now the nonlinear scale 78 | const float min_log_hz = 1000.0f; // beginning of log region (Hz) 79 | const float min_log_mel = (min_log_hz - f_min) / f_sp; // same (Mels) 80 | const float logstep = std::log(6.4f) / 27.0f; // step size for log region 81 | 82 | if (mel >= min_log_mel) { 83 | freqs = min_log_hz * std::exp(logstep * (mel - min_log_mel)); 84 | } 85 | 86 | return freqs; 87 | } 88 | 89 | std::vector mel_frequencies(const int n_mels = 128, 90 | const float fmin = 0.0f, 91 | const float fmax = 11025.0f, 92 | const bool htk = false) { 93 | // 'Center freqs' of mel bands - uniformly spaced between limits 94 | const float min_mel = hz_to_mel(fmin, htk); 95 | const float max_mel = hz_to_mel(fmax, htk); 96 | 97 | std::vector mels = linspace(min_mel, max_mel, size_t(n_mels)); 98 | 99 | std::transform(mels.begin(), mels.end(), mels.begin(), 100 | [htk](float mel) { return mel_to_hz(mel, htk); }); 101 | 102 | return mels; 103 | } 104 | 105 | } // namespace 106 | 107 | bool mel_filter(const float sample_rate, const int n_fft, std::vector *M, 108 | const int n_mels, const float fmin, const float _fmax, 109 | const bool htk, const bool norm) { 110 | float fmax = _fmax; 111 | if (fmax < 0.0f) { 112 | fmax = sample_rate / 2.0f; 113 | } 114 | 115 | if (n_mels < 1) { 116 | return false; 117 | } 118 | 119 | size_t height = size_t(n_mels); 120 | size_t width = size_t(1 + n_fft / 2); 121 | 122 | if (width < 2) { 123 | // TOO short 124 | return false; 125 | } 126 | 127 | std::vector weights(width * height); 128 | 129 | // # Center freqs of each FFT bin. 1D 130 | const std::vector fftfreqs = fft_frequencies(sample_rate, n_fft); 131 | 132 | // # 'Center freqs' of mel bands - uniformly spaced between limits. 1D 133 | const std::vector mel_f = mel_frequencies(n_mels + 2, fmin, fmax, htk); 134 | 135 | // fdif = np.diff(mel_f). 1D 136 | std::vector fdiff(mel_f.size() - 1); 137 | 138 | for (size_t x = 0; x < fdiff.size(); x++) { 139 | fdiff[x] = mel_f[(x + 1)] - mel_f[x]; 140 | } 141 | 142 | // ramps = np.subtract.outer(mel_f, fftfreqs) 143 | std::vector ramps(mel_f.size() * fftfreqs.size()); // 2D 144 | 145 | //std::cout << "fftfreqs..size" << fftfreqs.size() << ", width = " << width << "\n"; 146 | for (size_t i = 0; i < mel_f.size(); i++) { 147 | for (size_t j = 0; j < fftfreqs.size(); j++) { 148 | ramps[i * fftfreqs.size() + j] = mel_f[i] - fftfreqs[j]; 149 | } 150 | } 151 | 152 | for (size_t y = 0; y < height; y++) { 153 | // lowwer and upper slopes for all bins. 154 | for (size_t x = 0; x < width; x++) { 155 | const float lower = -ramps[y * width + x] / fdiff[y]; 156 | const float upper = ramps[(y + 2) * width + x] / 157 | fdiff[y + 1]; // +2 is safe since we create `mel_f` 158 | // with `n_mels + 2` size 159 | 160 | weights[y * width + x] = std::max(0.0f, std::min(lower, upper)); 161 | } 162 | } 163 | 164 | if (norm) { 165 | // Slaney-style mel is scaled to be approx constant energy per channel 166 | // enorm = 2.0 / (mel_f[2:n_mels+2] - mel_f[:n_mels]) 167 | for (size_t i = 0; i < size_t(n_mels); i++) { 168 | float enorm = 2.0f / (mel_f[i + 2] - mel_f[i]); 169 | // std::cout << "[" << i << "] enorm = " << enorm << "\n"; 170 | 171 | for (size_t x = 0; x < width; x++) { 172 | weights[i * width + x] *= enorm; 173 | } 174 | } 175 | } 176 | 177 | // only check weights if f_mel[0] is positive 178 | { 179 | // if not np.all((mel_f[:-2] == 0) | (weights.max(axis=1) > 0)) 180 | for (size_t y = 0; y < height; y++) { 181 | float maxval = weights[y * width]; 182 | for (size_t x = 1; x < width; x++) { 183 | maxval = std::max(weights[y * width + x], maxval); 184 | } 185 | 186 | if ((maxval > 0.0f) || 187 | (std::fabs(mel_f[y]) < std::numeric_limits::epsilon())) { 188 | // ok 189 | } else { 190 | // TODO(LTE): print warn 191 | // warnings.warn('Empty filters detected in mel frequency basis. ' 192 | // 'Some channels will produce empty responses. ' 193 | // 'Try increasing your sampling rate (and fmax) or ' 194 | // 'reducing n_mels.') 195 | break; 196 | } 197 | } 198 | } 199 | 200 | (*M) = std::move(weights); 201 | 202 | return true; 203 | } 204 | 205 | } // namespace nanosnap 206 | -------------------------------------------------------------------------------- /src/ndarray.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/fft.h" 25 | #include "nanosnap/nanosnap.h" 26 | 27 | #include "pocketfft.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include // dbg 35 | 36 | namespace nanosnap { 37 | 38 | bool pad_constant(const float *input, const size_t n, const size_t pad_len_left, const size_t pad_len_right, std::vector *output, const float pad_constant_value) { 39 | 40 | if (n < 1) { 41 | return false; 42 | } 43 | 44 | size_t output_length = n + pad_len_left + pad_len_right; 45 | 46 | if ((pad_len_left == 0) && (pad_len_right == 0)) { 47 | // just return input 48 | 49 | output->resize(output_length); 50 | 51 | // broadcast input[0] 52 | for (size_t i = 0; i < output_length; i++) { 53 | (*output)[i] = input[i]; 54 | } 55 | 56 | return true; 57 | } 58 | 59 | output->resize(output_length); 60 | 61 | // left 62 | for (size_t i = 0; i < pad_len_left; i++) { 63 | output->push_back(pad_constant_value); 64 | } 65 | 66 | // input 67 | for (size_t i = 0; i < n; i++) { 68 | output->push_back(input[i]); 69 | } 70 | 71 | // right 72 | for (size_t i = 0; i < pad_len_right; i++) { 73 | output->push_back(pad_constant_value); 74 | } 75 | 76 | return true; 77 | } 78 | 79 | bool pad_reflect(const float *input, const size_t n, const size_t pad_len_left, const size_t pad_len_right, std::vector *output) { 80 | 81 | // 82 | // in [1, 2, 3, 4, 5, 6] 83 | // pad = 3, 'reflect' gives, 84 | // 85 | // out [4, 3, 2, 1, 2, 3, 4, 5, 6, 5, 4, 3] 86 | // 87 | 88 | if (n < 1) { 89 | return false; 90 | } 91 | 92 | size_t output_length = n + pad_len_left + pad_len_right; 93 | 94 | if ((pad_len_left == 0) && (pad_len_right == 0)) { 95 | // just return input 96 | 97 | output->resize(output_length); 98 | 99 | // broadcast input[0] 100 | for (size_t i = 0; i < output_length; i++) { 101 | (*output)[i] = input[i]; 102 | } 103 | 104 | return true; 105 | } 106 | 107 | if (n == 1) { 108 | output->resize(output_length); 109 | 110 | // broadcast input[0] 111 | for (size_t i = 0; i < output_length; i++) { 112 | (*output)[i] = input[0]; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | // TODO(LTE): Optimize code. 119 | std::deque buf; 120 | 121 | // left 122 | if (pad_len_left > 0) { 123 | int dir = 1; // 1 or -1 124 | size_t idx = 1; 125 | for (size_t i = 1; i <= pad_len_left; i++) { 126 | if ((i % (n - 1)) == 0) { 127 | // reflect direction 128 | dir *= -1; 129 | } 130 | 131 | buf.push_front(input[idx]); 132 | 133 | if (dir > 0) { 134 | idx++; 135 | } else { 136 | idx--; 137 | } 138 | } 139 | } 140 | 141 | // input 142 | for (size_t i = 0; i < n; i++) { 143 | buf.push_back(input[i]); 144 | } 145 | 146 | // right 147 | if (pad_len_right > 0) { 148 | int dir = -1; // 1 or -1 149 | size_t idx = n - 2; 150 | for (size_t i = 1; i <= pad_len_right; i++) { 151 | if ((i % (n - 1)) == 0) { 152 | // reflect direction 153 | dir *= -1; 154 | } 155 | 156 | buf.push_back(input[idx]); 157 | 158 | if (dir > 0) { 159 | idx++; 160 | } else { 161 | idx--; 162 | } 163 | } 164 | } 165 | 166 | output->resize(output_length); 167 | for (size_t i = 0; i < output_length; i++) { 168 | (*output)[i] = buf[i]; 169 | } 170 | 171 | return true; 172 | } 173 | 174 | bool reshape_with_strides(const float *x, const size_t n, const size_t shape[2], const size_t strides[2], 175 | std::vector *output) { 176 | 177 | output->clear(); 178 | 179 | const uint8_t *src = reinterpret_cast(x); 180 | 181 | for (size_t j = 0; j < shape[1]; j++) { 182 | for (size_t i = 0; i < shape[0]; i++) { 183 | 184 | const size_t offset = j * strides[1] + i * strides[0]; 185 | if (offset >= (n * sizeof(float))) { 186 | // out-of-bounds access. 187 | return false; 188 | } 189 | float buf; 190 | 191 | // Use memcpy() for potential unaligned access 192 | // In some platform(e.g. SPARC, old ARM), unaligend access is not supported. 193 | // https://blog.quarkslab.com/unaligned-accesses-in-cc-what-why-and-solutions-to-do-it-properly.html 194 | memcpy(&buf, src + offset, sizeof(float)); 195 | 196 | output->push_back(buf); 197 | } 198 | } 199 | 200 | 201 | return true; 202 | } 203 | 204 | } // namespace nanosnap 205 | -------------------------------------------------------------------------------- /src/pocketfft.h: -------------------------------------------------------------------------------- 1 | #ifndef NANOSNAP_POCKETFFT_H_ 2 | #define NANOSNAP_POCKETFFT_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /// 9 | /// Apply forward 1D FFT for real-typed array of 1D signal 10 | /// Repeat 1D FFT `nrows` times. Assume input signal has a shape of [nrows * 11 | /// nsamples] 12 | /// 13 | /// @param[in] input Input signal(real-value) 14 | /// @param[in] fft_len FFT length 15 | /// @param[in] nsamples The number of samples 16 | /// @param[in] nrows The number of rows 17 | /// @param[in] norm_factor Normalization factor(usually 1.0 or 18 | /// `1/sqrt(nsamples)` ) 19 | /// @param[out] output Output signal(complex-value). The layout of elemens are: 20 | /// `nrows * ((fft_len / 2) + 1) * 2(real, img)` 21 | /// @return The number of FFTs processed(i.e. nrows = success). Zero or negative 22 | /// value = error. 23 | /// 24 | int rfft_forward_1d_array(const double *input, const int fft_len, 25 | const int nsamples, const int nrows, 26 | const float norm_factor, double *output); 27 | 28 | /// 29 | /// Apply backword 1D FFT for complex-typed array 30 | /// Repeat 1D IFFT `m` times. Assume input signal has a shape of [nrows * 31 | /// nsamples] 32 | /// 33 | /// @param[in] input Input signal(complex-value) 34 | /// @param[in] nsamples The number of samples 35 | /// @param[in] nrows The number of rows 36 | /// @param[in] norm_factor Normalization factor(usually `1/nsamples` ) 37 | /// @param[out] output Output signal(complex-value). The shape of elements are 38 | /// same as input. 39 | /// @return The number of FFTs processed(i.e. nrows = success). Zero or negative 40 | /// value = error. 41 | /// 42 | int cfft_backward_1d_array(const double *input, const int nsamples, 43 | const int nrows, const float norm_factor, 44 | double *output); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif // NANOSNAP_POCKETFFT_H_ 51 | -------------------------------------------------------------------------------- /src/rng.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/nanosnap.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // TODO(LTE): Use PCG32 for faster random number genreation. 32 | 33 | namespace nanosnap { 34 | 35 | std::vector random_uniform(const float lowval, const float maxval, const size_t n, const uint32_t seed) 36 | { 37 | // We only allow deterministic random number generation. 38 | // App user must care abount how to handle seed value. 39 | std::mt19937 rand(seed); 40 | 41 | std::uniform_real_distribution dist(lowval, maxval); 42 | 43 | std::vector r; 44 | r.resize(n); 45 | 46 | for (size_t i = 0; i < n; i++) { 47 | r[i] = dist(rand); 48 | } 49 | 50 | return r; 51 | } 52 | 53 | std::vector random_normal(const float mean, const float stddev, const size_t n, const uint32_t seed) 54 | { 55 | // We only allow deterministic random number generation. 56 | // App user must care abount how to handle seed value. 57 | std::mt19937 rand(seed); 58 | 59 | std::normal_distribution dist(mean, stddev); 60 | 61 | std::vector r; 62 | r.resize(n); 63 | 64 | for (size_t i = 0; i < n; i++) { 65 | r[i] = dist(rand); 66 | } 67 | 68 | return r; 69 | } 70 | 71 | 72 | std::vector random_shuffle(const float *x, const size_t n, const uint32_t seed) 73 | { 74 | // We only allow deterministic random number generation. 75 | // App user must care abount how to handle seed value. 76 | std::mt19937 engine(seed); 77 | 78 | std::vector r; 79 | r.resize(n); 80 | memcpy(r.data(), x, sizeof(float) * n); 81 | 82 | std::shuffle(r.begin(), r.end(), engine); 83 | 84 | return r; 85 | } 86 | 87 | } // namespace nanosnap 88 | -------------------------------------------------------------------------------- /src/signal.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/nanosnap.h" 25 | 26 | #include "stack_vector.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | //#include // dbg 33 | 34 | namespace nanosnap { 35 | 36 | namespace { 37 | 38 | constexpr float kPI = 3.141592f; 39 | 40 | // Find median value. 41 | // `a` will be modified. 42 | static inline float find_median(const size_t n, float *a) { 43 | // Sort `a`. 44 | // Simple O(n^2) selection sort. 45 | // 46 | for (size_t j = 0; j < n - 1; j++) { 47 | size_t iMin = j; 48 | 49 | /* test against elements after j to find the smallest */ 50 | 51 | for (size_t i = j + 1; i < n; i++) 52 | 53 | { 54 | /* if this element is less, then it is the new minimum */ 55 | 56 | if (a[i] < a[iMin]) 57 | 58 | { 59 | /* found new minimum; remember its index */ 60 | 61 | iMin = i; 62 | } 63 | } 64 | 65 | if (iMin != j) { 66 | std::swap(a[j], a[iMin]); 67 | } 68 | } 69 | 70 | // We know the window size is odd, thus a[n / 2] is the median value. 71 | return a[(n >> 1)]; 72 | } 73 | 74 | } // namespace 75 | 76 | std::vector window_hann(const size_t m, const bool symmetric) { 77 | std::vector win; 78 | 79 | if (m == 0) { 80 | // return empty array 81 | return win; 82 | } 83 | 84 | if (m == 1) { 85 | win.push_back(1.0f); 86 | return win; 87 | } 88 | 89 | size_t M = m; 90 | if (!symmetric) { 91 | // extend window size by 1 sample. 92 | M = M + 1; 93 | } 94 | 95 | // When !symmetric, scipy implementation(general_cosine) truncates window by 1 96 | // sample. so we don't need to resize with `M`. 97 | win.resize(m); 98 | for (size_t n = 0; n < m; n++) { 99 | // Keep in mind that denominator uses `M` 100 | float w = 0.5f - 0.5f * std::cos((2.0f * kPI * n) / float(M - 1)); 101 | win[n] = w; 102 | } 103 | 104 | return win; 105 | } 106 | 107 | bool get_window(const std::string &window_type, const size_t nx, 108 | std::vector *output, const bool periodic) { 109 | 110 | if (window_type.compare("hann") == 0) { 111 | (*output) = window_hann(nx, !periodic); 112 | return true; 113 | } 114 | 115 | return false; 116 | } 117 | 118 | bool medfilt1(const float *x, const size_t n, const int k, 119 | std::vector *y, bool include_nan, bool padding) { 120 | if ((k % 2) != 1) { 121 | // window size must be odd. 122 | return false; 123 | } 124 | 125 | // TODO(LTE): Handle these parameters. 126 | (void)padding; 127 | 128 | StackVector buf; 129 | buf->resize(size_t(k * k)); 130 | 131 | y->resize(n); 132 | 133 | // TODO(LTE): Test if k < 2 134 | 135 | int m = (k - 1) / 2; 136 | for (int64_t i = 0; i < int64_t(n); i++) { 137 | buf->clear(); 138 | for (int64_t r = -m; r <= m; r++) { 139 | int64_t j = i + r; 140 | 141 | float v; 142 | bool out_of_bounds = (j < 0) || (j >= int64_t(n)); 143 | if (out_of_bounds) { 144 | v = 0.0f; 145 | } else { 146 | v = x[size_t(j)]; 147 | } 148 | 149 | if (!include_nan) { 150 | if (std::isnan(v)) { 151 | v = 0.0f; 152 | } 153 | } 154 | 155 | buf->push_back(v); 156 | } 157 | 158 | (*y)[size_t(i)] = find_median(size_t(k), buf->data()); 159 | } 160 | 161 | return true; 162 | } 163 | 164 | bool convolve(const float *_a, const size_t _n, const float *_v, 165 | const size_t _m, std::vector *output, const int mode) { 166 | size_t m = _m, n = _n; 167 | const float *a = _a; 168 | const float *v = _v; 169 | 170 | if (_m > _n) { 171 | // swap 172 | a = _v; 173 | n = _m; 174 | 175 | v = _a; 176 | m = _n; 177 | } 178 | 179 | if ((n == 0) || (m == 0)) { 180 | return false; 181 | } 182 | 183 | if (mode == 0) { 184 | // mode 'full' 185 | // 186 | // len(a) = 5 187 | // len(v) = 3 188 | // output = 5 + 3 - 1 = 7 189 | // 190 | // +----+----+----+----+----+ 191 | // | a0 | a1 | a2 | a3 | a4 | 192 | // +----+----+----+----+----+ 193 | // 194 | // ....+----+ 195 | // n0 v2 | v1 | v0 | 196 | // ....+----+ 197 | // 198 | // ....+----+----+ 199 | // n1 v2 | v1 | v0 | 200 | // ....+----+----+ 201 | // 202 | // +----+----+----+ 203 | // n2 | v2 | v1 | v0 | 204 | // +----+----+----+ 205 | // 206 | // +----+.... 207 | // n6 | v2 | v1 | v0 208 | // +----+.... 209 | // 210 | 211 | size_t out_length = n + m + 1; 212 | output->resize(out_length); 213 | 214 | // TODO(LTE): optimize loop 215 | for (int n_idx = 0; n_idx < int(out_length); n_idx++) { 216 | float sum = 0.0f; 217 | for (int m_idx = -(int(m) - 1); m_idx <= 0; m_idx++) { 218 | int a_idx = n_idx + m_idx; 219 | int v_idx = -m_idx; 220 | // std::cout << "n = " << n_idx << ", m = " << m_idx << "a = " << a_idx 221 | // << ", v = " << v_idx << "\n"; 222 | if ((a_idx < 0) || (a_idx >= int(n))) { 223 | continue; 224 | } 225 | if ((v_idx < 0) || (v_idx >= int(m))) { 226 | continue; 227 | } 228 | // std::cout << "got it\n"; 229 | sum += a[size_t(a_idx)] * v[size_t(v_idx)]; 230 | } 231 | // std::cout << "sum[" << n_idx << "] = " << sum << std::endl; 232 | (*output)[size_t(n_idx)] = sum; 233 | } 234 | } else if (mode == 1) { 235 | // mode 'same' 236 | // 237 | // len(a) = 5 238 | // len(v) = 3 239 | // output = 5 (max(M, N)) 240 | // 241 | // +----+----+----+----+----+ 242 | // | a0 | a1 | a2 | a3 | a4 | 243 | // +----+----+----+----+----+ 244 | // 245 | // ....+----+----+ 246 | // n0 v2 | v1 | v0 | 247 | // ....+----+----+ 248 | // 249 | // +----+----+----+ 250 | // n2 | v2 | v1 | v0 | 251 | // +----+----+----+ 252 | // 253 | // +----+----+.... 254 | // n4 | v2 | v1 | v0 255 | // +----+----+.... 256 | // 257 | 258 | size_t out_length = n; 259 | output->resize(out_length); 260 | 261 | // TODO(LTE): Verify this offset calculation is correct. 262 | int a_offset = int(m) / 2; 263 | 264 | // TODO(LTE): optimize loop 265 | for (int n_idx = 0; n_idx < int(out_length); n_idx++) { 266 | float sum = 0.0f; 267 | for (int m_idx = -(int(m) - 1); m_idx <= 0; m_idx++) { 268 | int a_idx = n_idx + m_idx + a_offset; 269 | int v_idx = -m_idx; 270 | // std::cout << "n = " << n_idx << ", m = " << m_idx << "a = " << a_idx 271 | // << ", v = " << v_idx << "\n"; 272 | if ((a_idx < 0) || (a_idx >= int(n))) { 273 | continue; 274 | } 275 | if ((v_idx < 0) || (v_idx >= int(m))) { 276 | continue; 277 | } 278 | // std::cout << "got it\n"; 279 | sum += a[size_t(a_idx)] * v[size_t(v_idx)]; 280 | } 281 | // std::cout << "sum[" << n_idx << "] = " << sum << std::endl; 282 | (*output)[size_t(n_idx)] = sum; 283 | } 284 | 285 | } else if (mode == 2) { 286 | // mode 'valid' 287 | // 288 | // len(a) = 5 289 | // len(v) = 3 290 | // output = 5 - 3 + 1 291 | // 292 | // +----+----+----+----+----+ 293 | // | a0 | a1 | a2 | a3 | a4 | 294 | // +----+----+----+----+----+ 295 | // 296 | // +----+----+----+ 297 | // n0 | v2 | v1 | v0 | 298 | // +----+----+----+ 299 | // 300 | // +----+----+----+ 301 | // n1 | v2 | v1 | v0 | 302 | // +----+----+----+ 303 | // 304 | // +----+----+----+ 305 | // n2 | v2 | v1 | v0 | 306 | // +----+----+----+ 307 | // 308 | // 309 | 310 | size_t out_length = n - m + 1; 311 | output->resize(out_length); 312 | 313 | int a_offset = int(m) - 1; 314 | 315 | // TODO(LTE): optimize loop 316 | for (int n_idx = 0; n_idx < int(out_length); n_idx++) { 317 | float sum = 0.0f; 318 | for (int m_idx = -(int(m) - 1); m_idx <= 0; m_idx++) { 319 | int a_idx = n_idx + m_idx + a_offset; 320 | int v_idx = -m_idx; 321 | // std::cout << "n = " << n_idx << ", m = " << m_idx << "a = " << a_idx 322 | // << ", v = " << v_idx << "\n"; 323 | if ((a_idx < 0) || (a_idx >= int(n))) { 324 | continue; 325 | } 326 | if ((v_idx < 0) || (v_idx >= int(m))) { 327 | continue; 328 | } 329 | // std::cout << "got it\n"; 330 | sum += a[size_t(a_idx)] * v[size_t(v_idx)]; 331 | } 332 | // std::cout << "sum[" << n_idx << "] = " << sum << std::endl; 333 | (*output)[size_t(n_idx)] = sum; 334 | } 335 | 336 | } else { 337 | return false; 338 | } 339 | 340 | return true; 341 | } 342 | 343 | bool lfilter(const float *b, const size_t nb, const float *a, const size_t na, 344 | const float *x, const size_t nx, const size_t mx) { 345 | std::vector b_normalized(nb); 346 | memcpy(b_normalized.data(), b, sizeof(float) * nb); 347 | 348 | // normalize `b' by a[0] 349 | for (size_t i = 0; i < nb; i++) { 350 | b_normalized[i] /= a[0]; 351 | } 352 | 353 | // TODO(LTE): Implement 354 | (void)na; 355 | 356 | /* 357 | ind = out_full.ndim * [slice(None)] 358 | if zi is not None: 359 | ind[axis] = slice(zi.shape[axis]) 360 | out_full[ind] += zi 361 | 362 | ind[axis] = slice(out_full.shape[axis] - len(b) + 1) 363 | out = out_full[ind] 364 | */ 365 | 366 | // out_full = np.apply_along_axis(lambda y: np.convolve(b, y), axis, x) 367 | // Apply convolve for each row(axis = -1 behavior in scipy.signal.lfilter). 368 | for (size_t j = 0; j < mx; j++) { 369 | std::vector output; 370 | bool ret = convolve(b, nb, &x[j * nx], nx, &output, /* mode */ 0); 371 | if (!ret) { 372 | return false; 373 | } 374 | } 375 | 376 | return false; 377 | } 378 | 379 | } // namespace nanosnap 380 | -------------------------------------------------------------------------------- /src/speech_features.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include "nanosnap/nanosnap.h" 26 | 27 | #include "stack_vector.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include // dbg 37 | 38 | namespace nanosnap { 39 | 40 | namespace { 41 | 42 | constexpr float kPI = 3.141592f; 43 | 44 | #if 0 45 | 46 | // samplerate : [Hz] 47 | // winlen : [s] 48 | size_t calcualte_nfft(float samplerate, const float winlen) { 49 | (void)samplerate; 50 | (void)winlen; 51 | return 0; 52 | } 53 | #endif 54 | 55 | static std::vector preemphasis(const float *signal, size_t sig_len, 56 | float coeff) { 57 | std::vector preemph; 58 | preemph.resize(sig_len); 59 | 60 | for (size_t i = sig_len - 1; i >= 1; i--) { 61 | preemph[i] = signal[i] - signal[i - 1] * coeff; 62 | } 63 | preemph[0] = signal[0]; 64 | 65 | return preemph; 66 | } 67 | 68 | static std::vector framesig( 69 | const float *signal, const int sig_len, const int frame_len, 70 | const int padded_frame_len, const int frame_step, 71 | std::function winfunc = fIdentityWindowingFunction) { 72 | // Based on c_speech_features 73 | int frame_width = (std::max)(padded_frame_len, frame_len); 74 | 75 | int nframes; 76 | if (sig_len > frame_len) { 77 | nframes = 1 + int(std::ceil((sig_len - frame_len) / float(frame_step))); 78 | } else { 79 | nframes = 1; 80 | } 81 | 82 | std::vector indices; 83 | indices.resize(size_t(nframes * frame_len)); 84 | 85 | for (int i = 0, idx = 0; i < nframes; i++) { 86 | int base = i * frame_step; 87 | for (int j = 0; j < frame_len; j++, idx++) { 88 | indices[size_t(idx)] = base + j; 89 | } 90 | } 91 | 92 | std::vector frames; 93 | frames.resize(size_t(nframes * frame_width)); 94 | 95 | for (int i = 0, idx = 0, iidx = 0; i < nframes; i++) { 96 | for (int j = 0; j < frame_len; j++, idx++, iidx++) { 97 | int index = indices[size_t(iidx)]; 98 | frames[size_t(idx)] = index < sig_len ? signal[size_t(index)] : 0.0f; 99 | 100 | // apply windowing function 101 | frames[size_t(idx)] *= winfunc(j); 102 | } 103 | for (int j = frame_len; j < padded_frame_len; j++, idx++) { 104 | frames[size_t(idx)] = 0.0; 105 | } 106 | } 107 | 108 | return frames; 109 | } 110 | 111 | // Input is a 2D array. frames[nrows][nframes] 112 | bool magspec(const float *frames, const size_t nframes, const size_t nrows, 113 | const size_t NFFT, std::vector *output) { 114 | /* 115 | """Compute the magnitude spectrum of each frame in frames. If frames is an 116 | NxD matrix, output will be Nx(NFFT/2+1). 117 | 118 | :param frames: the array of frames. Each row is a frame. 119 | :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are 120 | zero-padded. :returns: If frames is an NxD matrix, output will be 121 | Nx(NFFT/2+1). Each row will be the magnitude spectrum of the corresponding 122 | frame. 123 | """ 124 | if numpy.shape(frames)[1] > NFFT: 125 | logging.warn( 126 | 'frame length (%d) is greater than FFT size (%d), frame will be 127 | truncated. Increase NFFT to avoid.', numpy.shape(frames)[1], NFFT) 128 | complex_spec = numpy.fft.rfft(frames, NFFT) 129 | return numpy.absolute(complex_spec) 130 | */ 131 | 132 | if (nframes > NFFT) { 133 | // TODO(LTE): Use zero-adding and continue 134 | return false; 135 | } 136 | 137 | std::vector> complex_output; 138 | 139 | bool ret = rfft(frames, NFFT, nframes, nrows, &complex_output); 140 | if (!ret) { 141 | return false; 142 | } 143 | 144 | output->resize(complex_output.size()); 145 | 146 | // Take an absolute of complex value. 147 | for (size_t i = 0; i < complex_output.size(); i++) { 148 | (*output)[i] = std::abs(complex_output[i]); 149 | } 150 | 151 | return true; 152 | } 153 | 154 | bool powspec(const float *frames, const size_t nframes, const size_t nrows, 155 | const size_t NFFT, std::vector *output) { 156 | /* 157 | """Compute the power spectrum of each frame in frames. If frames is an NxD 158 | matrix, output will be Nx(NFFT/2+1). 159 | 160 | :param frames: the array of frames. Each row is a frame. 161 | :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are 162 | zero-padded. :returns: If frames is an NxD matrix, output will be 163 | Nx(NFFT/2+1). Each row will be the power spectrum of the corresponding frame. 164 | """ 165 | return 1.0 / NFFT * numpy.square(magspec(frames, NFFT)) 166 | */ 167 | 168 | bool ret = magspec(frames, nframes, nrows, NFFT, output); 169 | 170 | if (!ret) { 171 | return false; 172 | } 173 | 174 | // Scale by `1 / NFFT` 175 | const float k = 1.0f / float(NFFT); 176 | for (size_t i = 0; i < output->size(); i++) { 177 | (*output)[i] *= k; 178 | } 179 | 180 | return true; 181 | } 182 | 183 | static std::vector get_filterbanks(const int nfilt, const int nfft, 184 | const float samplerate, 185 | const float lowfreq, 186 | const float highfreq) { 187 | // Based on c_speech_features. 188 | int feat_width = nfft / 2 + 1; 189 | float lowmel = hz2mel(lowfreq); 190 | float highmel = hz2mel((highfreq <= lowfreq) ? samplerate / 2.0f : highfreq); 191 | StackVector bin; 192 | bin->resize(size_t(nfilt + 2)); 193 | 194 | std::vector fbank(size_t(nfilt * feat_width)); 195 | 196 | for (size_t i = 0; i < size_t(nfilt + 2); i++) { 197 | const float melpoint = ((highmel - lowmel) / float(nfilt + 1) * i) + lowmel; 198 | bin[i] = int(std::floor(((nfft + 1) * mel2hz(melpoint) / samplerate))); 199 | } 200 | 201 | for (size_t i = 0, idx = 0; i < size_t(nfilt); 202 | i++, idx += size_t(feat_width)) { 203 | int start = std::min(bin[i], bin[i + 1]); 204 | int end = std::max(bin[i], bin[i + 1]); 205 | for (int j = start; j < end; j++) { 206 | fbank[idx + size_t(j)] = (j - bin[i]) / float(bin[i + 1] - bin[i]); 207 | } 208 | start = std::min(bin[i + 1], bin[i + 2]); 209 | end = std::max(bin[i + 1], bin[i + 2]); 210 | for (int j = start; j < end; j++) { 211 | fbank[idx + size_t(j)] = 212 | (bin[i + 2] - j) / float(bin[i + 2] - bin[i + 1]); 213 | } 214 | } 215 | 216 | return fbank; 217 | } 218 | 219 | } // namespace 220 | 221 | bool lifter(const float *cepstra, const size_t nframes, const size_t ncoeff, 222 | std::vector *output, const int L) { 223 | // """Apply a cepstral lifter the the matrix of cepstra. This has the effect 224 | // of increasing the magnitude of the high frequency DCT coeffs. 225 | 226 | // :param cepstra: the matrix of mel-cepstra, will be numframes * numcep in 227 | // size. :param L: the liftering coefficient to use. Default is 22. L <= 0 228 | // disables lifter. 229 | // """ 230 | // if L > 0: 231 | // nframes,ncoeff = numpy.shape(cepstra) 232 | // n = numpy.arange(ncoeff) 233 | // lift = 1 + (L/2.)*numpy.sin(numpy.pi*n/L) 234 | // return lift*cepstra 235 | // else: 236 | // # values of L <= 0, do nothing 237 | // return cepstra 238 | 239 | if (ncoeff == 0) { 240 | return false; 241 | } 242 | 243 | if (nframes == 0) { 244 | return false; 245 | } 246 | 247 | output->resize(nframes * ncoeff); 248 | 249 | if (L <= 0) { 250 | // Do nothing. Simply copy `cepstra` 251 | memcpy(output->data(), cepstra, sizeof(float) * nframes * ncoeff); 252 | return true; 253 | } 254 | 255 | StackVector lift; 256 | lift->resize(ncoeff); 257 | 258 | for (size_t i = 0; i < ncoeff; i++) { 259 | float n = float(i); 260 | lift[i] = 1.0f + (float(L) / 2.0f) * std::sin(kPI * n / float(L)); 261 | } 262 | 263 | for (size_t f = 0; f < nframes; f++) { 264 | for (size_t i = 0; i < ncoeff; i++) { 265 | (*output)[f * ncoeff + i] = lift[i] * cepstra[f * ncoeff + i]; 266 | } 267 | } 268 | 269 | return true; 270 | } 271 | 272 | int64_t fbank(const float *_signal, const size_t sig_len, 273 | const float samplerate, const float winlen, const float winstep, 274 | const std::function winfunc, const int nfilt, 275 | const int nfft, const float lowfreq, const float highfreq, 276 | const float preemph, std::vector *features, 277 | std::vector *energies) { 278 | /* 279 | highfreq= highfreq or samplerate/2 280 | signal = sigproc.preemphasis(signal,preemph) 281 | frames = sigproc.framesig(signal, winlen*samplerate, winstep*samplerate, 282 | winfunc) pspec = sigproc.powspec(frames,nfft) energy = numpy.sum(pspec,1) # 283 | this stores the total energy in each frame energy = numpy.where(energy == 284 | 0,numpy.finfo(float).eps,energy) # if energy is zero, we get problems with 285 | log 286 | 287 | fb = get_filterbanks(nfilt,nfft,samplerate,lowfreq,highfreq) 288 | feat = numpy.dot(pspec,fb.T) # compute the filterbank energies 289 | feat = numpy.where(feat == 0,numpy.finfo(float).eps,feat) # if feat is zero, 290 | we get problems with log 291 | 292 | return feat,energy 293 | */ 294 | if (samplerate <= 0.0f) { 295 | // invalid parameter 296 | return -1; 297 | } 298 | 299 | if (!features) { 300 | return -2; 301 | } 302 | 303 | // input signal is 1D with length `nframes`. 304 | // signal = sigproc.preemphasis(signal,preemph) 305 | std::vector signal; 306 | { 307 | // y[0] = x[0] 308 | // y[n] = x[n] - coeff * x[n-1] for n > 0 309 | signal.resize(sig_len); 310 | 311 | signal[0] = _signal[0]; 312 | for (size_t i = 1; i < sig_len; i++) { 313 | signal[i] = _signal[i] - preemph * signal[i - 1]; 314 | } 315 | } 316 | 317 | int frame_len = int(std::round(winlen * samplerate)); 318 | int frame_step = int(std::round(winstep * samplerate)); 319 | 320 | // frames = sigproc.framesig(signal, winlen*samplerate, winstep*samplerate, 321 | // winfunc) 322 | std::vector frames = 323 | framesig(signal.data(), int(sig_len), frame_len, 324 | /* padded framelen */ nfft, frame_step, winfunc); 325 | 326 | size_t nframes = frames.size(); 327 | 328 | // pspec = sigproc.powspec(frames,nfft) 329 | std::vector pspec; 330 | { 331 | bool ret = 332 | powspec(frames.data(), nframes, /* nrows */ 1, size_t(nfft), &pspec); 333 | if (!ret) { 334 | return false; 335 | } 336 | } 337 | 338 | const size_t feature_width = size_t((nfft / 2) + 1); 339 | 340 | // energy = numpy.sum(pspec,1) # this stores the total energy in each frame 341 | if (energies) { 342 | energies->resize(nframes); 343 | { 344 | for (size_t j = 0; j < nframes; j++) { 345 | float energy = 0.0f; 346 | for (size_t i = 0; i < feature_width; i++) { 347 | energy += pspec[j * feature_width + i]; 348 | } 349 | 350 | // energy = numpy.where(energy == 0,numpy.finfo(float).eps,energy) 351 | (*energies)[j] = std::max(energy, std::numeric_limits::min()); 352 | } 353 | } 354 | } 355 | 356 | // fb = get_filterbanks(nfilt,nfft,samplerate,lowfreq,highfreq) 357 | std::vector fb = 358 | get_filterbanks(nfilt, nfft, samplerate, lowfreq, highfreq); 359 | 360 | // feat = numpy.dot(pspec,fb.T) # compute the filterbank energies 361 | { 362 | for (size_t i = 0, idx = 0, pidx = 0; i < size_t(nframes); 363 | i++, idx += size_t(nfilt), pidx += feature_width) { 364 | for (size_t j = 0, fidx = 0; j < size_t(nfilt); j++) { 365 | float feat = 0.0f; 366 | for (size_t k = 0; k < feature_width; k++, fidx++) { 367 | feat += pspec[pidx + k] * fb[fidx]; 368 | } 369 | 370 | // avoid zero 371 | (*features)[idx + j] = 372 | std::max(feat, std::numeric_limits::min()); 373 | } 374 | } 375 | } 376 | 377 | return int64_t(nframes); 378 | } 379 | 380 | bool mfcc(const float *signal, const size_t sig_len, const float samplerate, 381 | const float winlen, const float winstep, const size_t ncep, 382 | const size_t nfilt, const size_t nfft, const float low_freq, 383 | const float high_freq, const float preemph, const size_t cep_lifter, 384 | const bool append_energy, const std::function winfunc, 385 | std::vector *out_mfcc) { 386 | // 387 | // nfft = nfft or calculate_nfft(samplerate, winlen) 388 | // feat,energy = 389 | // fbank(signal,samplerate,winlen,winstep,nfilt,nfft,lowfreq,highfreq,preemph,winfunc) 390 | // feat = numpy.log(feat) 391 | // feat = dct(feat, type=2, axis=1, norm='ortho')[:,:numcep] 392 | // feat = lifter(feat,ceplifter) 393 | // if appendEnergy: feat[:,0] = numpy.log(energy) # replace first cepstral 394 | // coefficient with log of frame energy return feat 395 | 396 | std::vector feat; 397 | std::vector energy; 398 | 399 | int64_t nframes = fbank(signal, sig_len, samplerate, winlen, winstep, winfunc, 400 | int(nfilt), int(nfft), low_freq, high_freq, preemph, 401 | &feat, append_energy ? &energy : nullptr); 402 | 403 | if (nframes <= 0) { 404 | return false; 405 | } 406 | 407 | // DCT is based on c_speech_features code. 408 | 409 | // Allocate an array so we can calculate the inner loop multipliers 410 | // in the DCT-II just one time. 411 | std::vector dct2f; 412 | dct2f.resize(nfilt * ncep); 413 | 414 | // Perform DCT-II 415 | float sf1 = std::sqrt(1 / (4 * float(nfilt))); 416 | float sf2 = std::sqrt(1 / (2 * float(nfilt))); 417 | 418 | std::vector mfcc; 419 | mfcc.resize(size_t(nframes) * ncep); 420 | 421 | for (size_t i = 0, idx = 0, fidx = 0; i < size_t(nframes); 422 | i++, idx += ncep, fidx += nfilt) { 423 | for (size_t j = 0, didx = 0; j < ncep; j++) { 424 | float sum = 0.0; 425 | for (size_t k = 0; k < nfilt; k++, didx++) { 426 | if (i == 0) { 427 | dct2f[didx] = std::cos(kPI * j * (2 * k + 1) / float(2 * nfilt)); 428 | } 429 | sum += float(feat[fidx + k]) * dct2f[didx]; 430 | } 431 | mfcc[idx + j] = float(sum * 2.0f * ((i == 0 && j == 0) ? sf1 : sf2)); 432 | } 433 | } 434 | 435 | // Apply a cepstral lifter 436 | if (cep_lifter > 0) { 437 | bool ret = lifter(mfcc.data(), size_t(nframes), size_t(ncep), out_mfcc, 438 | int(cep_lifter)); 439 | if (!ret) { 440 | return false; 441 | } 442 | } else { 443 | (*out_mfcc) = mfcc; 444 | } 445 | 446 | // Append energies 447 | if (append_energy) { 448 | for (size_t i = 0, idx = 0; i < size_t(nframes); i++, idx += ncep) { 449 | (*out_mfcc)[idx] = std::log(energy[i]); 450 | } 451 | } 452 | 453 | return true; 454 | } 455 | 456 | int64_t ssc(const float *signal, const size_t sig_len, const int samplerate, 457 | const float winlen, const float winstep, const int nfilt, 458 | const int nfft, const int low_freq, const int high_freq, 459 | const float preemph_coeff, std::function winfunc, 460 | std::vector *features) { 461 | // based on c_speech_features 462 | std::vector preemph = preemphasis(signal, sig_len, preemph_coeff); 463 | 464 | int frame_len = int(std::round(winlen * samplerate)); 465 | int frame_step = int(std::round(winstep * samplerate)); 466 | int feat_width = nfft / 2 + 1; 467 | 468 | // Frame the signal into overlapping frames 469 | std::vector frames = framesig(preemph.data(), int(sig_len), frame_len, 470 | nfft, frame_step, winfunc); 471 | 472 | size_t nframes = frames.size(); 473 | 474 | // Compute the power spectrum of the frames 475 | std::vector pspec; 476 | { 477 | if (!powspec(frames.data(), nframes, /* nrows */ 1, size_t(nfft), &pspec)) { 478 | return -1; 479 | } 480 | } 481 | 482 | // Make sure there are no zeroes in the power spectrum 483 | for (size_t i = 0, idx = 0; i < nframes; i++) { 484 | for (size_t j = 0; j < size_t(feat_width); j++, idx++) { 485 | pspec[idx] = std::max(pspec[idx], std::numeric_limits::min()); 486 | } 487 | } 488 | 489 | // Compute the filter-bank energies 490 | std::vector fbank = 491 | get_filterbanks(nfilt, nfft, float(samplerate), float(low_freq), float(high_freq)); 492 | std::vector feat; 493 | feat.resize(nframes * size_t(nfilt)); 494 | 495 | for (size_t i = 0, idx = 0, pidx = 0; i < nframes; 496 | i++, idx += size_t(nfilt), pidx += size_t(feat_width)) { 497 | for (size_t j = 0, fidx = 0; j < size_t(nfilt); j++) { 498 | for (size_t k = 0; k < size_t(feat_width); k++, fidx++) { 499 | feat[idx + j] += pspec[pidx + k] * fbank[fidx]; 500 | } 501 | } 502 | } 503 | 504 | // Calculate Spectral Sub-band Centroid features 505 | std::vector ssc; 506 | ssc.resize(nframes * size_t(nfilt)); 507 | 508 | const float r = ((samplerate / 2) - 1) / float(feat_width - 1); 509 | for (size_t i = 0, idx = 0, pidx = 0; i < nframes; 510 | i++, idx += size_t(nfilt), pidx += size_t(feat_width)) { 511 | for (size_t j = 0, fidx = 0; j < size_t(nfilt); j++) { 512 | float R = 1; 513 | for (size_t k = 0; k < size_t(feat_width); k++, fidx++) { 514 | ssc[idx + j] += pspec[pidx + k] * R * fbank[fidx]; 515 | R += r; 516 | } 517 | ssc[idx + j] /= feat[idx + j]; 518 | } 519 | } 520 | 521 | (*features) = std::move(ssc); 522 | 523 | return int64_t(nframes); 524 | } 525 | 526 | } // namespace nanosnap 527 | -------------------------------------------------------------------------------- /src/stack_vector.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Small vector class useful for multi-threaded environment. 3 | // 4 | // stack_container.h 5 | // 6 | // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 7 | // Use of this source code is governed by a BSD-style license that can be 8 | // found in the LICENSE file. 9 | 10 | // This allocator can be used with STL containers to provide a stack buffer 11 | // from which to allocate memory and overflows onto the heap. This stack buffer 12 | // would be allocated on the stack and allows us to avoid heap operations in 13 | // some situations. 14 | // 15 | // STL likes to make copies of allocators, so the allocator itself can't hold 16 | // the data. Instead, we make the creator responsible for creating a 17 | // StackAllocator::Source which contains the data. Copying the allocator 18 | // merely copies the pointer to this shared source, so all allocators created 19 | // based on our allocator will share the same stack buffer. 20 | // 21 | // This stack buffer implementation is very simple. The first allocation that 22 | // fits in the stack buffer will use the stack buffer. Any subsequent 23 | // allocations will not use the stack buffer, even if there is unused room. 24 | // This makes it appropriate for array-like containers, but the caller should 25 | // be sure to reserve() in the container up to the stack buffer size. Otherwise 26 | // the container will allocate a small array which will "use up" the stack 27 | // buffer. 28 | 29 | #ifdef __GNUC__ 30 | #pragma GCC diagnostic push 31 | #pragma GCC diagnostic ignored "-Wextra" 32 | #endif 33 | 34 | template 35 | class StackAllocator : public std::allocator { 36 | public: 37 | typedef typename std::allocator::pointer pointer; 38 | typedef typename std::allocator::size_type size_type; 39 | 40 | // Backing store for the allocator. The container owner is responsible for 41 | // maintaining this for as long as any containers using this allocator are 42 | // live. 43 | struct Source { 44 | Source() : used_stack_buffer_(false) {} 45 | 46 | // Casts the buffer in its right type. 47 | T *stack_buffer() { return reinterpret_cast(stack_buffer_); } 48 | const T *stack_buffer() const { 49 | return reinterpret_cast(stack_buffer_); 50 | } 51 | 52 | // 53 | // IMPORTANT: Take care to ensure that stack_buffer_ is aligned 54 | // since it is used to mimic an array of T. 55 | // Be careful while declaring any unaligned types (like bool) 56 | // before stack_buffer_. 57 | // 58 | 59 | // The buffer itself. It is not of type T because we don't want the 60 | // constructors and destructors to be automatically called. Define a POD 61 | // buffer of the right size instead. 62 | char stack_buffer_[sizeof(T[stack_capacity])]; 63 | 64 | // Set when the stack buffer is used for an allocation. We do not track 65 | // how much of the buffer is used, only that somebody is using it. 66 | bool used_stack_buffer_; 67 | }; 68 | 69 | // Used by containers when they want to refer to an allocator of type U. 70 | template 71 | struct rebind { 72 | typedef StackAllocator other; 73 | }; 74 | 75 | // For the straight up copy c-tor, we can share storage. 76 | StackAllocator(const StackAllocator &rhs) 77 | : source_(rhs.source_) {} 78 | 79 | // ISO C++ requires the following constructor to be defined, 80 | // and std::vector in VC++2008SP1 Release fails with an error 81 | // in the class _Container_base_aux_alloc_real (from ) 82 | // if the constructor does not exist. 83 | // For this constructor, we cannot share storage; there's 84 | // no guarantee that the Source buffer of Ts is large enough 85 | // for Us. 86 | // TODO(Google): If we were fancy pants, perhaps we could share storage 87 | // iff sizeof(T) == sizeof(U). 88 | template 89 | StackAllocator(const StackAllocator &other) 90 | : source_(nullptr) { 91 | (void)other; 92 | } 93 | 94 | explicit StackAllocator(Source *source) : source_(source) {} 95 | 96 | // Actually do the allocation. Use the stack buffer if nobody has used it yet 97 | // and the size requested fits. Otherwise, fall through to the standard 98 | // allocator. 99 | pointer allocate(size_type n, void *hint = nullptr) { 100 | if (source_ != nullptr && !source_->used_stack_buffer_ && 101 | n <= stack_capacity) { 102 | source_->used_stack_buffer_ = true; 103 | return source_->stack_buffer(); 104 | } else { 105 | return std::allocator::allocate(n, hint); 106 | } 107 | } 108 | 109 | // Free: when trying to free the stack buffer, just mark it as free. For 110 | // non-stack-buffer pointers, just fall though to the standard allocator. 111 | void deallocate(pointer p, size_type n) { 112 | if (source_ != nullptr && p == source_->stack_buffer()) 113 | source_->used_stack_buffer_ = false; 114 | else 115 | std::allocator::deallocate(p, n); 116 | } 117 | 118 | private: 119 | Source *source_; 120 | }; 121 | 122 | // A wrapper around STL containers that maintains a stack-sized buffer that the 123 | // initial capacity of the vector is based on. Growing the container beyond the 124 | // stack capacity will transparently overflow onto the heap. The container must 125 | // support reserve(). 126 | // 127 | // WATCH OUT: the ContainerType MUST use the proper StackAllocator for this 128 | // type. This object is really intended to be used only internally. You'll want 129 | // to use the wrappers below for different types. 130 | template 131 | class StackContainer { 132 | public: 133 | typedef TContainerType ContainerType; 134 | typedef typename ContainerType::value_type ContainedType; 135 | typedef StackAllocator Allocator; 136 | 137 | // Allocator must be constructed before the container! 138 | StackContainer() : allocator_(&stack_data_), container_(allocator_) { 139 | // Make the container use the stack allocation by reserving our buffer size 140 | // before doing anything else. 141 | container_.reserve(stack_capacity); 142 | } 143 | 144 | // Getters for the actual container. 145 | // 146 | // Danger: any copies of this made using the copy constructor must have 147 | // shorter lifetimes than the source. The copy will share the same allocator 148 | // and therefore the same stack buffer as the original. Use std::copy to 149 | // copy into a "real" container for longer-lived objects. 150 | ContainerType &container() { return container_; } 151 | const ContainerType &container() const { return container_; } 152 | 153 | // Support operator-> to get to the container. This allows nicer syntax like: 154 | // StackContainer<...> foo; 155 | // std::sort(foo->begin(), foo->end()); 156 | ContainerType *operator->() { return &container_; } 157 | const ContainerType *operator->() const { return &container_; } 158 | 159 | #ifdef UNIT_TEST 160 | // Retrieves the stack source so that that unit tests can verify that the 161 | // buffer is being used properly. 162 | const typename Allocator::Source &stack_data() const { return stack_data_; } 163 | #endif 164 | 165 | protected: 166 | typename Allocator::Source stack_data_; 167 | unsigned char pad_[7]; 168 | Allocator allocator_; 169 | ContainerType container_; 170 | 171 | // DISALLOW_EVIL_CONSTRUCTORS(StackContainer); 172 | StackContainer(const StackContainer &); 173 | void operator=(const StackContainer &); 174 | }; 175 | 176 | // StackVector 177 | // 178 | // Example: 179 | // StackVector foo; 180 | // foo->push_back(22); // we have overloaded operator-> 181 | // foo[0] = 10; // as well as operator[] 182 | template 183 | class StackVector 184 | : public StackContainer >, 185 | stack_capacity> { 186 | public: 187 | StackVector() 188 | : StackContainer >, 189 | stack_capacity>() {} 190 | 191 | // We need to put this in STL containers sometimes, which requires a copy 192 | // constructor. We can't call the regular copy constructor because that will 193 | // take the stack buffer from the original. Here, we create an empty object 194 | // and make a stack buffer of its own. 195 | StackVector(const StackVector &other) 196 | : StackContainer >, 197 | stack_capacity>() { 198 | this->container().assign(other->begin(), other->end()); 199 | } 200 | 201 | StackVector &operator=( 202 | const StackVector &other) { 203 | this->container().assign(other->begin(), other->end()); 204 | return *this; 205 | } 206 | 207 | // Vectors are commonly indexed, which isn't very convenient even with 208 | // operator-> (using "->at()" does exception stuff we don't want). 209 | T &operator[](size_t i) { return this->container().operator[](i); } 210 | const T &operator[](size_t i) const { 211 | return this->container().operator[](i); 212 | } 213 | }; 214 | 215 | #ifdef __GNUC__ 216 | #pragma GCC diagnostic pop 217 | #endif 218 | 219 | -------------------------------------------------------------------------------- /src/text-load-save.cc: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Light Transport Entertainment, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | #include "nanosnap/nanosnap.h" 25 | 26 | #define NANOCSV_IMPLEMENTATION 27 | #include "nanocsv.h" 28 | 29 | namespace nanosnap { 30 | 31 | bool loadtxt(const std::string &filename, std::vector *values, int *n, int *m, std::string *err) 32 | { 33 | nanocsv::ParseOption option; 34 | std::string warn; 35 | 36 | nanocsv::CSV csv; 37 | 38 | bool ret = nanocsv::ParseCSVFromFile(filename, option, &csv, &warn, err); 39 | 40 | if (!ret) { 41 | return false; 42 | } 43 | 44 | (*n) = int(csv.num_fields); 45 | (*m) = int(csv.num_records); 46 | (*values) = std::move(csv.values); 47 | 48 | return true; 49 | 50 | } 51 | 52 | bool savetxt(const std::string &filename, const float *values, const int n, const int m, std::string *err) 53 | { 54 | std::ofstream ofs(filename); 55 | 56 | if (!ofs) { 57 | if (err) { 58 | (*err) += "Failed to open file " + filename + " to write.\n"; 59 | } 60 | return false; 61 | } 62 | 63 | // use ' ' as delimiter 64 | char delimiter = ' '; 65 | // TODO(LTE): Set precision 66 | 67 | for (size_t j = 0; j < size_t(m); j++) { 68 | for (size_t i = 0; i < size_t(n); i++) { 69 | ofs << values[j * size_t(n) + i]; 70 | if (i != (size_t(n) - 1)) { 71 | ofs << delimiter; 72 | } 73 | } 74 | ofs << "\n"; 75 | } 76 | 77 | return true; 78 | 79 | } 80 | 81 | 82 | } // namespace nanosnap 83 | -------------------------------------------------------------------------------- /tests/assets/8k16bitpcm.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lighttransport/nanosnap/e25c5d2a54debc4ed31966acd80c757f231a266c/tests/assets/8k16bitpcm.wav -------------------------------------------------------------------------------- /tests/assets/8k8bitpcm.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lighttransport/nanosnap/e25c5d2a54debc4ed31966acd80c757f231a266c/tests/assets/8k8bitpcm.wav -------------------------------------------------------------------------------- /tests/assets/README.md: -------------------------------------------------------------------------------- 1 | 8k16bitpcm.wav 2 | 8k8bitpcm.wav 3 | 4 | Audio files are grabbed from https://en.wikipedia.org/wiki/WAV 5 | I guess `.wav` are permissively licensed under some kind of Createive Commons license. 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/gen/README.md: -------------------------------------------------------------------------------- 1 | 2 | Need to install following python packages to generate testvector. 3 | 4 | - numpy 5 | - python_speech_features 6 | -------------------------------------------------------------------------------- /tests/gen/common_util.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | # NOTE(LTE): We cannot use numpy.iscomplex() whether input value is complex-value, 4 | # since it will return False for complex-value whose imaginary part is zero. 5 | # 6 | # arr : numpy 1D or 2D array 7 | def print_c_array(arr): 8 | c_arr = [] 9 | 10 | if numpy.isfortran(arr): 11 | arr = numpy.transpose(arr) 12 | 13 | if len(arr.shape) == 1: 14 | for i in arr: 15 | if isinstance(i, complex) or isinstance(i, numpy.complex) or isinstance(i, numpy.complex64): 16 | c_arr.append(str(float(i.real)) + 'f') 17 | c_arr.append(str(float(i.imag)) + 'f') 18 | else: 19 | c_arr.append(str(float(i)) + 'f') 20 | 21 | c_str = ', '.join(c_arr) 22 | elif len(arr.shape) == 2: 23 | for row in arr: 24 | for i in row: 25 | if isinstance(i, complex) or isinstance(i, numpy.complex) or isinstance(i, numpy.complex64): 26 | c_arr.append(str(float(i.real)) + 'f') 27 | c_arr.append(str(float(i.imag)) + 'f') 28 | else: 29 | c_arr.append(str(float(i)) + 'f') 30 | 31 | c_str = ', '.join(c_arr) 32 | else: 33 | # Unsupported. 34 | raise 35 | 36 | return c_str 37 | 38 | -------------------------------------------------------------------------------- /tests/gen/gen_convolve_full.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | 5 | from common_util import print_c_array 6 | 7 | def gen(): 8 | n = 5 9 | m = 3 10 | 11 | seed = 42 12 | numpy.random.seed(seed) 13 | a = numpy.random.rand(n).astype(numpy.float32) 14 | v = numpy.random.rand(m).astype(numpy.float32) 15 | c = numpy.convolve(a, v, mode='full') 16 | 17 | assert len(c) == (n + m - 1) 18 | 19 | print('const float g_a[] = {' + print_c_array(a) + '};') 20 | print('const float g_v[] = {' + print_c_array(v) + '};') 21 | print('const float g_reference[] = {' + print_c_array(c) + '};') 22 | print('const size_t k_n = {};'.format(n)) 23 | print('const size_t k_m = {};'.format(m)) 24 | print('const size_t k_outnum = {};'.format(len(c))) 25 | 26 | gen() 27 | -------------------------------------------------------------------------------- /tests/gen/gen_convolve_same.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | 5 | from common_util import print_c_array 6 | 7 | def gen(): 8 | n = 5 9 | m = 3 10 | 11 | seed = 42 12 | numpy.random.seed(seed) 13 | a = numpy.random.rand(n).astype(numpy.float32) 14 | v = numpy.random.rand(m).astype(numpy.float32) 15 | c = numpy.convolve(a, v, mode='same') 16 | 17 | assert len(c) == n 18 | 19 | print('const float g_a[] = {' + print_c_array(a) + '};') 20 | print('const float g_v[] = {' + print_c_array(v) + '};') 21 | print('const float g_reference[] = {' + print_c_array(c) + '};') 22 | print('const size_t k_n = {};'.format(n)) 23 | print('const size_t k_m = {};'.format(m)) 24 | print('const size_t k_outnum = {};'.format(len(c))) 25 | 26 | gen() 27 | -------------------------------------------------------------------------------- /tests/gen/gen_convolve_valid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | 5 | from common_util import print_c_array 6 | 7 | def gen(): 8 | n = 5 9 | m = 3 10 | 11 | seed = 42 12 | numpy.random.seed(seed) 13 | a = numpy.random.rand(n).astype(numpy.float32) 14 | v = numpy.random.rand(m).astype(numpy.float32) 15 | c = numpy.convolve(a, v, mode='valid') 16 | 17 | assert len(c) == (n - m + 1) 18 | 19 | print('const float g_a[] = {' + print_c_array(a) + '};') 20 | print('const float g_v[] = {' + print_c_array(v) + '};') 21 | print('const float g_reference[] = {' + print_c_array(c) + '};') 22 | print('const size_t k_n = {};'.format(n)) 23 | print('const size_t k_m = {};'.format(m)) 24 | print('const size_t k_outnum = {};'.format(len(c))) 25 | 26 | gen() 27 | -------------------------------------------------------------------------------- /tests/gen/gen_ifft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | from python_speech_features import * 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | nframes = 16 10 | nrows = 4 11 | 12 | numpy.random.seed(42) 13 | volume = numpy.random.rand(nrows, nframes).astype(numpy.float32) 14 | 15 | fft_len = nframes-1 16 | f = numpy.fft.rfft(volume, fft_len) 17 | #print(len(y)) 18 | #print(numpy.absolute(y)) 19 | 20 | #a = numpy.absolute(y) 21 | #print(a.shape) 22 | 23 | #print('sum = ', numpy.sum(a, 1)) 24 | 25 | n = 6 26 | y = numpy.fft.ifft(f, n) 27 | 28 | print('const float g_input[] = {' + print_c_array(f) + '};') 29 | print('const float g_reference[] = {' + print_c_array(y) + '};') 30 | print('const size_t k_n = {};'.format(n)) 31 | print('const size_t k_ncolumns = {};'.format(f.shape[1])) 32 | print('const size_t k_nrows = {};'.format(f.shape[0])) 33 | 34 | gen() 35 | -------------------------------------------------------------------------------- /tests/gen/gen_librosa_filters_mel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | import librosa 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | sr = 22050 10 | n_fft = 2048 11 | M = librosa.filters.mel(sr, n_fft) 12 | 13 | if numpy.isfortran(M): 14 | M = numpy.transpose(M) 15 | 16 | print('const float g_reference[] = {' + print_c_array(M) + '};') 17 | print('const size_t k_sr = {};'.format(sr)) 18 | print('const size_t k_nfft = {};'.format(n_fft)) 19 | 20 | gen() 21 | -------------------------------------------------------------------------------- /tests/gen/gen_librosa_istft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | import librosa 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | nframes = 128 10 | numpy.random.seed(42) 11 | y = numpy.random.rand(nframes).astype('float32') 12 | n_fft = 64 13 | win_length = n_fft # by default win_length = n_fft 14 | hop_length = win_length // 4 # default hop length is win_length / 4 15 | # window function = 'hann' 16 | D = librosa.stft(y, n_fft=n_fft, hop_length=hop_length, win_length=win_length) 17 | #print(D.shape) 18 | 19 | S = librosa.istft(D) 20 | #print("S.shape", S.shape) 21 | #print("S,", S) 22 | 23 | # NOTE: librosa uses Fortran order for stft matrix. 24 | if numpy.isfortran(D): 25 | D = numpy.transpose(D) 26 | if numpy.isfortran(S): 27 | S = numpy.transpose(S) 28 | 29 | print('const float g_input[] = {' + print_c_array(D) + '};') 30 | print('const float g_reference[] = {' + print_c_array(S) + '};') 31 | print('const size_t k_ncolumns = {};'.format(D.shape[1])) 32 | print('const size_t k_nrows = {};'.format(D.shape[0])) 33 | print('const size_t k_hop_length = {};'.format(hop_length)) 34 | print('const size_t k_win_length = {};'.format(win_length)) 35 | 36 | gen() 37 | -------------------------------------------------------------------------------- /tests/gen/gen_librosa_stft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | import librosa 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | nframes = 128 10 | numpy.random.seed(42) 11 | y = numpy.random.rand(nframes).astype('float32') 12 | n_fft = 64 13 | win_length = n_fft # by default win_length = n_fft 14 | hop_length = win_length // 4 # default hop length is win_length / 4 15 | # window function = 'hann' 16 | D = librosa.stft(y, n_fft=n_fft, hop_length=hop_length, win_length=win_length) 17 | #print(D.shape) 18 | 19 | # NOTE: librosa uses Fortran order for stft matrix. 20 | if numpy.isfortran(D): 21 | D = numpy.transpose(D) 22 | 23 | print('const float g_input[] = {' + print_c_array(y) + '};') 24 | print('const float g_reference[] = {' + print_c_array(D) + '};') 25 | print('const size_t k_n_fft = {};'.format(n_fft)) 26 | print('const size_t k_nframes = {};'.format(nframes)) 27 | print('const size_t k_out_dim0 = {};'.format(D.shape[0])) 28 | print('const size_t k_out_dim1 = {};'.format(D.shape[1])) 29 | #print('const size_t k_nrows = {};'.format(1)) 30 | print('const size_t k_hop_length = {};'.format(hop_length)) 31 | print('const size_t k_win_length = {};'.format(win_length)) 32 | 33 | gen() 34 | -------------------------------------------------------------------------------- /tests/gen/gen_lifter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | from python_speech_features import * 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | nframes = 16 10 | ncoeffs = 5 11 | 12 | numpy.random.seed(42) 13 | volume = numpy.random.rand(nframes, ncoeffs).astype(numpy.float32) 14 | 15 | y = lifter(volume) 16 | 17 | print('const float g_input[] = {' + print_c_array(volume) + '};') 18 | print('const float g_reference[] = {' + print_c_array(y) + '};') 19 | print('const size_t k_nframes = {};'.format(nframes)) 20 | print('const size_t k_ncoeffs = {};'.format(ncoeffs)) 21 | 22 | gen() 23 | -------------------------------------------------------------------------------- /tests/gen/gen_medfilt1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import scipy.signal 4 | import numpy 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | n = 32 10 | ksize = 3 11 | numpy.random.seed(42) 12 | volume = numpy.random.rand(n).astype(numpy.float32) 13 | out = scipy.signal.medfilt(volume, kernel_size=ksize) 14 | 15 | print('const float g_input[] = {' + print_c_array(volume) + '};') 16 | print('const float g_reference[] = {' + print_c_array(out) + '};') 17 | print('const size_t k_input_n = {};'.format(n)) 18 | print('const size_t k_window_size = {};'.format(ksize)) 19 | 20 | gen() 21 | -------------------------------------------------------------------------------- /tests/gen/gen_random_normal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | 5 | from common_util import print_c_array 6 | 7 | def gen(): 8 | n = 32 9 | seed = 42 10 | numpy.random.seed(seed) 11 | volume = numpy.random.normal(0.0, 1.0, n).astype(numpy.float32) 12 | 13 | print('const float g_reference[] = {' + print_c_array(volume) + '};') 14 | print('const size_t k_n = {};'.format(n)) 15 | print('const size_t k_seed = {};'.format(seed)) 16 | 17 | gen() 18 | -------------------------------------------------------------------------------- /tests/gen/gen_random_uniform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | 5 | from common_util import print_c_array 6 | 7 | def gen(): 8 | n = 32 9 | seed = 42 10 | numpy.random.seed(seed) 11 | volume = numpy.random.rand(n).astype(numpy.float32) 12 | 13 | print('const float g_reference[] = {' + print_c_array(volume) + '};') 14 | print('const size_t k_n = {};'.format(n)) 15 | print('const size_t k_seed = {};'.format(seed)) 16 | 17 | gen() 18 | -------------------------------------------------------------------------------- /tests/gen/gen_rfft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | from python_speech_features import * 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | nframes = 16 10 | nrows = 4 11 | 12 | numpy.random.seed(42) 13 | volume = numpy.random.rand(nrows, nframes).astype(numpy.float32) 14 | 15 | fft_len = nframes-1 16 | y = numpy.fft.rfft(volume, fft_len) 17 | #print(len(y)) 18 | #print(numpy.absolute(y)) 19 | 20 | #a = numpy.absolute(y) 21 | #print(a.shape) 22 | 23 | #print('sum = ', numpy.sum(a, 1)) 24 | 25 | print('const float g_input[] = {' + print_c_array(volume) + '};') 26 | print('const float g_reference[] = {' + print_c_array(y) + '};') 27 | print('const size_t k_fft_len = {};'.format(fft_len)) 28 | print('const size_t k_nframes = {};'.format(nframes)) 29 | print('const size_t k_nrows = {};'.format(nrows)) 30 | 31 | gen() 32 | -------------------------------------------------------------------------------- /tests/gen/gen_signal_get_window_hann.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy 4 | import scipy.signal 5 | 6 | from common_util import print_c_array 7 | 8 | def gen(): 9 | 10 | win_length = 64 11 | y = scipy.signal.get_window('hann', win_length) # fftbins=True = peridoc 12 | 13 | print('const float g_reference[] = {' + print_c_array(y) + '};') 14 | print('const size_t k_win_length = {};'.format(win_length)) 15 | 16 | gen() 17 | -------------------------------------------------------------------------------- /tests/gen/run_all.sh: -------------------------------------------------------------------------------- 1 | python gen_medfilt1.py > ../testvector/medfilt1.inc 2 | python gen_lifter.py > ../testvector/lifter.inc 3 | python gen_rfft.py > ../testvector/rfft.inc 4 | python gen_ifft.py > ../testvector/ifft.inc 5 | python gen_librosa_stft.py > ../testvector/librosa_stft.inc 6 | python gen_librosa_istft.py > ../testvector/librosa_istft.inc 7 | python gen_librosa_filters_mel.py > ../testvector/librosa_filters_mel.inc 8 | python gen_random_uniform.py > ../testvector/random_uniform.inc 9 | python gen_random_normal.py > ../testvector/random_normal.inc 10 | python gen_convolve_full.py > ../testvector/convolve_full.inc 11 | python gen_convolve_same.py > ../testvector/convolve_same.inc 12 | python gen_convolve_valid.py > ../testvector/convolve_valid.inc 13 | 14 | python gen_signal_get_window_hann.py > ../testvector/signal_get_window_hann.inc 15 | -------------------------------------------------------------------------------- /tests/main.cc: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include "doctest/doctest.h" 3 | -------------------------------------------------------------------------------- /tests/test_audio.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | 7 | TEST_CASE("wav_read_16bit") { 8 | const std::string &filename = "../tests/assets/8k16bitpcm.wav"; 9 | 10 | uint32_t rate; 11 | std::string dtype; 12 | uint32_t channels; 13 | uint64_t samples; 14 | std::vector data; 15 | 16 | std::string err; 17 | 18 | bool ret = nanosnap::wav_read(filename, &rate, &dtype, &channels, &samples, &data, &err); 19 | 20 | if (!err.empty()) 21 | { 22 | std::cerr << "ERR: " << err << std::endl; 23 | } 24 | 25 | std::cout << "rate = " << rate << ", dtype = " << dtype << "\n"; 26 | std::cout << "channels = " << channels << ", samples = " << samples << "\n"; 27 | std::cout << "data.size = " << data.size() << "\n"; 28 | 29 | 30 | CHECK(ret == true); 31 | CHECK(err.empty()); 32 | CHECK(channels == 1); 33 | CHECK(dtype.compare("int16") == 0); 34 | } 35 | 36 | TEST_CASE("wav_read_8bit") { 37 | const std::string &filename = "../tests/assets/8k8bitpcm.wav"; 38 | 39 | uint32_t rate; 40 | std::string dtype; 41 | uint32_t channels; 42 | uint64_t samples; 43 | std::vector data; 44 | 45 | std::string err; 46 | 47 | bool ret = nanosnap::wav_read(filename, &rate, &dtype, &channels, &samples, &data, &err); 48 | 49 | if (!err.empty()) 50 | { 51 | std::cerr << "ERR: " << err << std::endl; 52 | } 53 | 54 | std::cout << "rate = " << rate << ", dtype = " << dtype << "\n"; 55 | std::cout << "channels = " << channels << ", samples = " << samples << "\n"; 56 | std::cout << "data.size = " << data.size() << "\n"; 57 | 58 | 59 | CHECK(ret == true); 60 | CHECK(err.empty()); 61 | CHECK(channels == 1); 62 | CHECK(dtype.compare("uint8") == 0); 63 | } 64 | -------------------------------------------------------------------------------- /tests/test_convolve.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("convolve1d_full") { 11 | #include "testvector/convolve_full.inc" 12 | 13 | std::vector result(k_outnum); 14 | bool ret = 15 | nanosnap::convolve(g_a, k_n, g_v, k_m, &result, /* mode 0 = full */0); 16 | 17 | CHECK(ret == true); 18 | 19 | std::cout << "convolve(full): len = " << sizeof(g_reference) / sizeof(g_reference[0]) << std::endl; 20 | 21 | for (size_t i = 0; i < k_outnum; i++) { 22 | CHECK(g_reference[i] == Approx(result[i])); 23 | } 24 | } 25 | 26 | TEST_CASE("convolve1d_same") { 27 | #include "testvector/convolve_same.inc" 28 | 29 | std::vector result(k_outnum); 30 | bool ret = 31 | nanosnap::convolve(g_a, k_n, g_v, k_m, &result, /* mode 1 = same */1); 32 | 33 | CHECK(ret == true); 34 | 35 | std::cout << "convolve(same): len = " << sizeof(g_reference) / sizeof(g_reference[0]) << std::endl; 36 | 37 | for (size_t i = 0; i < k_outnum; i++) { 38 | CHECK(g_reference[i] == Approx(result[i])); 39 | } 40 | } 41 | 42 | TEST_CASE("convolve1d_valid") { 43 | #include "testvector/convolve_valid.inc" 44 | 45 | std::vector result(k_outnum); 46 | bool ret = 47 | nanosnap::convolve(g_a, k_n, g_v, k_m, &result, /* mode 2 = valid */2); 48 | 49 | CHECK(ret == true); 50 | 51 | std::cout << "convolve(valid): len = " << sizeof(g_reference) / sizeof(g_reference[0]) << std::endl; 52 | 53 | for (size_t i = 0; i < k_outnum; i++) { 54 | CHECK(g_reference[i] == Approx(result[i])); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/test_ifft.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("ifft") { 11 | #include "testvector/ifft.inc" 12 | 13 | 14 | size_t input_len = sizeof(g_input) / sizeof(g_input[0]); 15 | std::cout << "len = " << input_len << std::endl; 16 | 17 | std::vector> input; 18 | for (size_t i = 0; i < input_len / 2; i++) { 19 | input.push_back(std::complex(g_input[2 * i + 0], g_input[2 * i + 1])); 20 | } 21 | 22 | std::vector> result; 23 | 24 | bool ret = 25 | nanosnap::ifft(input.data(), k_ncolumns, k_nrows, k_n, &result); 26 | 27 | CHECK(ret == true); 28 | CHECK(result.size() == (k_n * k_nrows)); 29 | 30 | //std::cout << "result = \n"; 31 | //for (size_t j = 0; j < k_nrows; j++) { 32 | // for (size_t i = 0; i < k_n; i++) { 33 | // std::cout << "[" << j << "][" << i 34 | // << "] = " << result[j * k_n + i].real() << ", " 35 | // << result[j * k_n + i].imag() << "\n"; 36 | // } 37 | //} 38 | 39 | //std::cout << "\nreference = \n"; 40 | //for (size_t j = 0; j < k_nrows; j++) { 41 | // for (size_t i = 0; i < out_npoints; i++) { 42 | // std::cout << "[" << j << "][" << i 43 | // << "] = " << g_reference[2 * (j * out_npoints + i) + 0] << ", " 44 | // << g_reference[2 * (j * out_npoints + i) + 1] << "\n"; 45 | // } 46 | //} 47 | 48 | for (size_t i = 0; i < k_n * k_nrows; i++) { 49 | CHECK(g_reference[2 * i + 0] == Approx(result[i].real())); 50 | CHECK(g_reference[2 * i + 1] == Approx(result[i].imag())); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/test_librosa_filters_mel.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("librosa_filters_mel") { 11 | #include "testvector/librosa_filters_mel.inc" 12 | 13 | std::vector result; 14 | 15 | std::cout << "k_sr = " << k_sr << std::endl; 16 | std::cout << "k_nfft = " << k_nfft << std::endl; 17 | bool ret = nanosnap::mel_filter(k_sr, k_nfft, &result); 18 | 19 | CHECK(ret == true); 20 | 21 | const size_t out_len = sizeof(g_reference) / sizeof(g_reference[0]); 22 | CHECK(result.size() == out_len); 23 | 24 | std::cout << "librosa_filters_mel:result = \n"; 25 | for (size_t i = 0; i < result.size(); i++) { 26 | std::cout << "[" << i << "] " << result[i] << "\n"; 27 | } 28 | 29 | std::cout << "\nlibrosa_filters_mel:reference = \n"; 30 | for (size_t i = 0; i < result.size(); i++) { 31 | std::cout << "[" << i << "] = " << g_reference[i] << "\n"; 32 | } 33 | 34 | for (size_t i = 0; i < result.size(); i++) { 35 | if (g_reference[i] != Approx(result[i])) { 36 | std::cout << "librosa_filters_mel: diff at " << i << "\n"; 37 | } 38 | CHECK(g_reference[i] == Approx(result[i])); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/test_librosa_istft.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("librosa_istft") { 11 | #include "testvector/librosa_istft.inc" 12 | 13 | // Build an array of complex values; 14 | const size_t input_len = sizeof(g_input) / sizeof(g_input[0]); 15 | 16 | std::vector> input; 17 | 18 | for (size_t i = 0; i < input_len / 2; i++) { 19 | input.push_back(std::complex(g_input[2 * i + 0], g_input[2 * i + 1])); 20 | } 21 | 22 | std::vector result; 23 | 24 | std::cout << "k_ncolumns = " << k_ncolumns << std::endl; 25 | std::cout << "k_nrows = " << k_nrows << std::endl; 26 | bool ret = nanosnap::istft(input.data(), k_ncolumns, k_nrows, k_hop_length, k_win_length, &result); 27 | 28 | CHECK(ret == true); 29 | 30 | const size_t out_len = sizeof(g_reference) / sizeof(g_reference[0]); 31 | CHECK(result.size() == out_len); 32 | 33 | std::cout << "result = \n"; 34 | for (size_t i = 0; i < result.size(); i++) { 35 | std::cout << "[" << i << "] " << result[i] << "\n"; 36 | } 37 | 38 | std::cout << "\nreference = \n"; 39 | for (size_t i = 0; i < result.size(); i++) { 40 | std::cout << "[" << i << "] = " << g_reference[i] << "\n"; 41 | } 42 | 43 | for (size_t i = 0; i < result.size(); i++) { 44 | CHECK(g_reference[i] == Approx(result[i])); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/test_librosa_stft.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("librosa_stft") { 11 | #include "testvector/librosa_stft.inc" 12 | 13 | size_t out_npoints = k_n_fft / 2 + 1; 14 | std::vector> result; 15 | std::cout << "input len = " << sizeof(g_input) / sizeof(g_input[0]) << "\n"; 16 | std::cout << "nframes = " << k_nframes << "\n"; 17 | 18 | bool ret = 19 | nanosnap::stft(g_input, k_nframes, k_n_fft, k_hop_length, k_win_length, &result); 20 | 21 | CHECK(ret == true); 22 | 23 | //std::cout << "result = \n"; 24 | //for (size_t j = 0; j < k_nrows; j++) { 25 | // for (size_t i = 0; i < out_npoints; i++) { 26 | // std::cout << "[" << j << "][" << i 27 | // << "] = " << result[j * out_npoints + i].real() << ", " 28 | // << result[j * out_npoints + i].imag() << "\n"; 29 | // } 30 | //} 31 | 32 | //std::cout << "\nreference = \n"; 33 | //for (size_t j = 0; j < k_nrows; j++) { 34 | // for (size_t i = 0; i < out_npoints; i++) { 35 | // std::cout << "[" << j << "][" << i 36 | // << "] = " << g_reference[2 * (j * out_npoints + i) + 0] << ", " 37 | // << g_reference[2 * (j * out_npoints + i) + 1] << "\n"; 38 | // } 39 | //} 40 | 41 | std::cout << "reference len = " << sizeof(g_reference) / sizeof(g_reference[0]) << std::endl; 42 | std::cout << "n = " << out_npoints << std::endl; 43 | std::cout << "result len = " << result.size() << std::endl; 44 | 45 | size_t nrows = result.size() / out_npoints; 46 | 47 | CHECK(out_npoints == k_out_dim1); 48 | CHECK(nrows == k_out_dim0); 49 | 50 | CHECK((2 * result.size()) == (sizeof(g_reference) / sizeof(g_reference[0]))); 51 | 52 | for (size_t i = 0; i < nrows * out_npoints; i++) { 53 | CHECK(g_reference[2 * i + 0] == Approx(result[i].real())); 54 | CHECK(g_reference[2 * i + 1] == Approx(result[i].imag())); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/test_medfilt1.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | 7 | using namespace doctest; 8 | 9 | TEST_CASE("medfilt1") { 10 | 11 | #include "testvector/medfilt1.inc" 12 | 13 | std::vector result; 14 | bool ret = nanosnap::medfilt1(g_input, k_input_n, k_window_size, &result); 15 | 16 | CHECK(ret == true); 17 | 18 | for (size_t i = 0; i < k_input_n; i++) { 19 | CHECK(g_reference[i] == Approx(result[i])); 20 | } 21 | 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /tests/test_random_uniform.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | 7 | using namespace doctest; 8 | 9 | TEST_CASE("random_uniform") { 10 | #include "testvector/random_uniform.inc" 11 | 12 | std::vector result = nanosnap::random_uniform(k_n, k_seed); 13 | 14 | for (size_t i = 0; i < k_n; i++) { 15 | CHECK(g_reference[i] == Approx(result[i])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/test_rfft.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("rfft") { 11 | #include "testvector/rfft.inc" 12 | 13 | size_t out_npoints = (k_fft_len / 2) + 1; 14 | std::vector> result; 15 | std::cout << "input len = " << sizeof(g_input) / sizeof(g_input[0]) << "\n"; 16 | std::cout << "nframes = " << k_nframes << "\n"; 17 | std::cout << "nrows = " << k_nrows << "\n"; 18 | 19 | bool ret = 20 | nanosnap::rfft(g_input, k_nframes, k_nrows, k_fft_len, &result); 21 | 22 | CHECK(ret == true); 23 | 24 | //std::cout << "result = \n"; 25 | //for (size_t j = 0; j < k_nrows; j++) { 26 | // for (size_t i = 0; i < out_npoints; i++) { 27 | // std::cout << "[" << j << "][" << i 28 | // << "] = " << result[j * out_npoints + i].real() << ", " 29 | // << result[j * out_npoints + i].imag() << "\n"; 30 | // } 31 | //} 32 | 33 | //std::cout << "\nreference = \n"; 34 | //for (size_t j = 0; j < k_nrows; j++) { 35 | // for (size_t i = 0; i < out_npoints; i++) { 36 | // std::cout << "[" << j << "][" << i 37 | // << "] = " << g_reference[2 * (j * out_npoints + i) + 0] << ", " 38 | // << g_reference[2 * (j * out_npoints + i) + 1] << "\n"; 39 | // } 40 | //} 41 | 42 | std::cout << "len = " << sizeof(g_reference) / sizeof(g_reference[0]) << std::endl; 43 | std::cout << "n = " << k_nrows * out_npoints << std::endl; 44 | 45 | for (size_t i = 0; i < k_nrows * out_npoints; i++) { 46 | CHECK(g_reference[2 * i + 0] == Approx(result[i].real())); 47 | CHECK(g_reference[2 * i + 1] == Approx(result[i].imag())); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/test_signal_get_window_hann.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace doctest; 9 | 10 | TEST_CASE("signal_get_window_hann") { 11 | #include "testvector/signal_get_window_hann.inc" 12 | 13 | std::vector window; 14 | bool ret = nanosnap::get_window("hann", k_win_length, &window, /* periodic */true); 15 | CHECK(ret == true); 16 | 17 | for (size_t i = 0; i < window.size(); i++) { 18 | CHECK(g_reference[i] == Approx(window[i])); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/test_speech_features.cc: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | 3 | #include "nanosnap/nanosnap.h" 4 | 5 | #include 6 | 7 | using namespace doctest; 8 | 9 | TEST_CASE("lifter") { 10 | 11 | #include "testvector/lifter.inc" 12 | 13 | size_t n = k_nframes * k_ncoeffs; 14 | 15 | std::vector result; 16 | 17 | bool ret = nanosnap::lifter(g_input, k_nframes, k_ncoeffs, &result); 18 | CHECK(ret == true); 19 | 20 | for (size_t i = 0; i < n; i++) { 21 | CHECK(g_reference[i] == Approx(result[i])); 22 | } 23 | 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/testvector/convolve_full.inc: -------------------------------------------------------------------------------- 1 | const float g_a[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f}; 2 | const float g_v[] = {0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f}; 3 | const float g_reference[] = {0.058426205068826675f, 0.17006085813045502f, 0.49382567405700684f, 0.9593902826309204f, 0.6931459307670593f, 0.5276058316230774f, 0.13513962924480438f}; 4 | const size_t k_n = 5; 5 | const size_t k_m = 3; 6 | const size_t k_outnum = 7; 7 | -------------------------------------------------------------------------------- /tests/testvector/convolve_same.inc: -------------------------------------------------------------------------------- 1 | const float g_a[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f}; 2 | const float g_v[] = {0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f}; 3 | const float g_reference[] = {0.17006085813045502f, 0.49382567405700684f, 0.9593902826309204f, 0.6931459307670593f, 0.5276058316230774f}; 4 | const size_t k_n = 5; 5 | const size_t k_m = 3; 6 | const size_t k_outnum = 5; 7 | -------------------------------------------------------------------------------- /tests/testvector/convolve_valid.inc: -------------------------------------------------------------------------------- 1 | const float g_a[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f}; 2 | const float g_v[] = {0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f}; 3 | const float g_reference[] = {0.49382567405700684f, 0.9593902826309204f, 0.6931459307670593f}; 4 | const size_t k_n = 5; 5 | const size_t k_m = 3; 6 | const size_t k_outnum = 3; 7 | -------------------------------------------------------------------------------- /tests/testvector/ifft.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {7.41846838966012f, 0.0f, 0.22224115715680573f, 0.5425364262236541f, 0.26344064053925176f, -1.5131044848315307f, -1.6230507255254234f, -1.4857967909206413f, 1.0769683651868798f, -0.8502811632343243f, 0.14846202358603477f, 0.3767258661954804f, -0.7083856347294607f, 0.4203700253072771f, -0.2798591183198825f, -1.414976492610436f, 6.163590081036091f, 0.0f, -0.03150154630836788f, 0.29712066728231945f, 0.11018681343558623f, -0.6820362533568072f, -0.0930733862538107f, 0.28958648870364045f, 0.5288958324009976f, -0.4680109758903722f, 0.3160148225724697f, 0.34657709651092894f, -1.3801968847196333f, 0.9635910733481529f, -0.2503037918688287f, 0.09601784503985078f, 7.10857529938221f, 0.0f, 0.9388985318274892f, -0.6378091158537578f, -0.5003902991906976f, -0.8597478337366097f, -1.3091489210566853f, -1.4029915065733682f, -0.8645458069436571f, 0.4907337794336797f, -0.08682939037680626f, 0.01369295028348677f, -1.7523581661441947f, -0.7729818361865324f, 0.5079733488418061f, -0.9730055406095484f, 7.974179528653622f, 0.0f, 0.4298659194650052f, -2.380630574179803f, -0.38519723967064984f, 1.1416157521072363f, -0.32672339593027777f, 0.14112314679675503f, 0.3058361587346089f, 1.0230522996053675f, -0.23048493638634682f, 0.6444686945889215f, 0.056545901195752285f, 1.5923368485242841f, 0.2633947239789035f, -0.5352135260199884f}; 2 | const float g_reference[] = {1.2510883084339446f, -0.48832002442789363f, 1.4978486467029564f, 0.4144132814794719f, 0.7037072631626873f, 0.0007825278453349275f, 1.668537490028139f, -0.29947519159405805f, 0.9429132604707161f, -0.2553608988777619f, 1.3543734208616762f, 0.6279603055749068f, 1.165685436147161f, -0.03612716279171509f, 1.051260105655675f, -0.00938077384714377f, 0.9110329884144056f, 0.10073597749443053f, 1.1018721394770639f, -0.34722191362401134f, 0.9585399228295733f, 0.08018442964910477f, 0.9751994885122119f, 0.21180944311933483f, 0.8810932356069754f, -0.39935362107442823f, 1.8766659280789295f, 0.413185801596955f, 0.9084209693685006f, -0.05558131321315061f, 1.0334531621423095f, 0.27634893630678486f, 1.1101989841872861f, -0.2465608189991053f, 1.2987430199982084f, 0.011961015382944232f, 1.2945793391443268f, 0.09493821981974626f, 1.8262346350812808f, -0.3530183289588129f, 1.7183229932004145f, 0.18286719253273456f, 1.3370268100948668f, 0.6266177974177883f, 0.8108257340169303f, -0.2072438389541033f, 0.9871900171158022f, -0.34416104185735286f}; 3 | const size_t k_n = 6; 4 | const size_t k_ncolumns = 8; 5 | const size_t k_nrows = 4; 6 | -------------------------------------------------------------------------------- /tests/testvector/librosa_istft.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {15.127864837646484f, 0.0f, -8.46943187713623f, -1.6653345369377348e-16f, 1.2745327949523926f, 9.524208030952926e-18f, -0.1934017837047577f, 5.551115123125783e-17f, 0.2618129551410675f, 5.412337245047638e-16f, -1.7684640884399414f, -1.6653345369377348e-16f, 3.041776180267334f, 1.7605766420626825e-16f, -3.1098506450653076f, -4.163336342344337e-17f, 1.4269992113113403f, -0.0f, -0.06825567781925201f, -1.5265566588595902e-16f, 0.6715459227561951f, 4.0680943695682874e-16f, -0.3449842929840088f, 5.551115123125783e-17f, -1.6804810762405396f, -3.608224830031759e-16f, 3.230522632598877f, 2.7755575615628914e-16f, -3.1008658409118652f, 5.455873150349733e-16f, 0.8266358375549316f, -6.106226635438361e-16f, 1.3840386867523193f, 0.0f, -1.1185752153396606f, -2.7755575615628914e-16f, -0.07223274558782578f, 1.2054651297501042e-16f, 1.2164442539215088f, 1.6653345369377348e-16f, -1.7205184698104858f, 3.0531133177191805e-16f, 0.8250223994255066f, 4.996003610813204e-16f, 0.4161289632320404f, 3.727978281940123e-17f, -0.3065255582332611f, 1.5265566588595902e-16f, -1.4978749752044678f, 0.0f, 1.5881668329238892f, -4.0245584642661925e-16f, -0.5009416937828064f, 4.3456501257245765e-16f, -0.15241272747516632f, 5.551115123125783e-17f, 1.2153269052505493f, -5.689893001203927e-16f, -0.7598091959953308f, 1.6653345369377348e-16f, -1.1675606966018677f, 2.1252039441253654e-16f, 2.612276792526245f, -5.551115123125783e-17f, -3.0459537506103516f, 0.0f, 14.375269889831543f, 0.0f, -6.590682029724121f, -0.7545922994613647f, -1.055687665939331f, 0.6712188124656677f, 0.33069416880607605f, -0.3221714198589325f, -0.03539302572607994f, 0.2909367084503174f, 1.3474011421203613f, -0.9603245854377747f, -1.587969422340393f, 0.19176653027534485f, -0.31820571422576904f, 1.9915574789047241f, 0.6550431847572327f, -1.9857500791549683f, 0.5688869953155518f, 0.4965772032737732f, -0.523764431476593f, -0.08560370653867722f, 0.4308584928512573f, 0.7815452218055725f, -1.426485538482666f, -1.5893300771713257f, 0.0019518034532666206f, 1.2549421787261963f, 2.5224881172180176f, -0.22993293404579163f, -1.8847662210464478f, 0.04327170550823212f, 0.8700533509254456f, 0.49728503823280334f, -0.8908606171607971f, -0.9052624702453613f, 0.40355589985847473f, 0.24825705587863922f, 0.8708437085151672f, -0.23958678543567657f, -1.5781919956207275f, 0.28082913160324097f, 0.7515044212341309f, 0.003527677385136485f, 0.13108114898204803f, -0.3084527254104614f, 0.22528085112571716f, 1.2012773752212524f, -1.7713499069213867f, -1.7090799808502197f, 1.6095327138900757f, 0.6024768352508545f, 0.1369958221912384f, 0.3686818480491638f, -0.8176153898239136f, -0.2710931897163391f, 1.1031544208526611f, 0.37632033228874207f, -0.8441156148910522f, -0.4901861548423767f, 0.648871660232544f, 1.120017170906067f, 0.3414151966571808f, -1.4617338180541992f, -1.6243213415145874f, 0.0f, 14.56569766998291f, 0.0f, -7.007680892944336f, 0.9447317719459534f, 0.18407347798347473f, -0.06981422752141953f, -1.306267499923706f, -0.3124689757823944f, 0.45407000184059143f, -0.9947559237480164f, 0.17539837956428528f, 1.2477387189865112f, 0.5589256882667542f, -1.1147269010543823f, 0.44570401310920715f, 2.0800061225891113f, -0.6796132922172546f, -1.9334112405776978f, -0.49252596497535706f, 1.0034632682800293f, 0.3278498351573944f, -0.6381726861000061f, 0.7306457161903381f, 0.9703041315078735f, -1.092358112335205f, -1.6342873573303223f, 1.139155626296997f, 1.0886679887771606f, -1.9401911497116089f, -0.9369967579841614f, 1.665429949760437f, 0.9113833904266357f, -0.5729420781135559f, 0.6238041520118713f, 0.5317192077636719f, -0.9421029090881348f, -0.7116326689720154f, 0.46657034754753113f, 0.7889355421066284f, -0.8242992162704468f, -0.9133171439170837f, 0.5270411968231201f, 0.3949715197086334f, 0.21043415367603302f, -0.3943552076816559f, -0.41607463359832764f, 1.3490588665008545f, 0.889778733253479f, -1.2153526544570923f, -1.9953665733337402f, 0.5238877534866333f, 2.6226627826690674f, -1.1839895248413086f, -1.6444121599197388f, 0.6347455382347107f, -0.34851884841918945f, 1.1359689235687256f, 1.132315754890442f, -0.857933759689331f, -0.05443352460861206f, 0.2759222686290741f, -1.0983672142028809f, 0.24393047392368317f, 0.8152329325675964f, -0.9501631855964661f, 0.0f, 15.656485557556152f, 0.0f, -8.42627239227295f, 0.13057668507099152f, 1.338409423828125f, -0.5947919487953186f, -1.3712878227233887f, 1.9393540620803833f, 0.9859256744384766f, -2.4101667404174805f, -0.060542527586221695f, 1.4427621364593506f, -1.683583378791809f, -0.1850171983242035f, 2.856182098388672f, -0.01323987077921629f, -1.6559516191482544f, 0.16279034316539764f, -0.38853535056114197f, -0.7832066416740417f, 0.11510468274354935f, 0.46847009658813477f, 1.0183560848236084f, 0.025208426639437675f, -0.47015756368637085f, -1.0277721881866455f, -0.5068453550338745f, 0.9722727537155151f, 0.7684547901153564f, 0.9363120794296265f, 0.19692985713481903f, -1.4263888597488403f, -1.239068627357483f, 1.0806405544281006f, 0.29769110679626465f, -0.7488762140274048f, 0.9855167269706726f, -0.04827433452010155f, -0.4061298668384552f, -0.1864081770181656f, -0.2870284914970398f, 0.44636186957359314f, 0.23360145092010498f, -0.04918382316827774f, -0.2511419951915741f, 0.8281019926071167f, 0.39278167486190796f, -0.6022027730941772f, -0.19100511074066162f, -0.9553259015083313f, -0.8805977702140808f, -0.3037765920162201f, 1.8432866334915161f, 2.476627826690674f, -2.387824535369873f, -1.9290086030960083f, 1.6608823537826538f, 0.7871016263961792f, -0.25887250900268555f, -1.1179546117782593f, -0.12630923092365265f, 1.021419882774353f, 0.9440017938613892f, 0.008236227557063103f, -1.7484261989593506f, 0.0f, 15.439499855041504f, 0.0f, -7.3903632164001465f, -0.3923853039741516f, -1.1686044931411743f, -0.2700342833995819f, 1.4737553596496582f, 1.7406373023986816f, -0.03433895483613014f, -1.5143119096755981f, -1.6276142597198486f, 0.2528674900531769f, 1.5194220542907715f, 0.8032265305519104f, 0.019141700118780136f, -1.5757465362548828f, -1.3571873903274536f, 0.8279022574424744f, 2.026916027069092f, -0.2271241396665573f, -1.2875661849975586f, 1.6112964153289795f, -0.7159297466278076f, -1.6488032341003418f, 1.3951590061187744f, -0.3733276426792145f, -0.5990731120109558f, 1.1374022960662842f, 0.012613246217370033f, -0.9235551953315735f, 0.08022090792655945f, 0.23840749263763428f, -0.9715112447738647f, 0.05148446187376976f, 2.0653672218322754f, 0.09298215061426163f, -1.6736351251602173f, 0.4652140438556671f, 0.5436675548553467f, -0.7116110920906067f, 0.08039559423923492f, 0.6749694347381592f, -0.5595993995666504f, -0.0791427493095398f, 1.0504924058914185f, -0.5521528720855713f, -1.0065946578979492f, 0.9576502442359924f, 0.09549643099308014f, -1.351135492324829f, 1.0659763813018799f, 1.164675235748291f, -0.5106009840965271f, -1.9070203304290771f, -1.51253342628479f, 2.2055301666259766f, 1.5899581909179688f, -1.2144818305969238f, 0.36770278215408325f, 1.3069241046905518f, -1.333899736404419f, -0.89107745885849f, 1.2740076780319214f, -0.48101097345352173f, -1.261981725692749f, 0.0f, 15.243585586547852f, 0.0f, -7.9514055252075195f, 0.19402354955673218f, -0.1931990385055542f, -0.09587167203426361f, 1.6795213222503662f, -0.41365230083465576f, -1.0104525089263916f, 0.9484491944313049f, -0.13005755841732025f, -0.7857146263122559f, -0.4506785273551941f, -0.2765459716320038f, 0.3482154905796051f, -0.4793684184551239f, 0.37835076451301575f, 0.6152461171150208f, -1.2239192724227905f, 1.5637694597244263f, 2.1266613006591797f, -2.3875057697296143f, -2.393404006958008f, 1.8153574466705322f, 1.9258278608322144f, -1.2058360576629639f, -0.8153762817382812f, 0.08434797823429108f, 0.03526346758008003f, 0.8473537564277649f, -0.0011135147651657462f, -0.6803033947944641f, 0.20806069672107697f, -0.6223580837249756f, -0.6585227251052856f, 1.7567012310028076f, 1.3007309436798096f, -1.1179333925247192f, -0.7670462727546692f, 0.22054703533649445f, -0.3766621947288513f, 0.6302412748336792f, 0.37931057810783386f, -1.2068129777908325f, -0.4326469600200653f, 0.29966601729393005f, 0.331156462430954f, 0.9943992495536804f, 0.38185763359069824f, -2.0339725017547607f, -0.28208547830581665f, 1.276145577430725f, -0.4684085249900818f, 0.35806795954704285f, 0.30495691299438477f, 0.47002723813056946f, 0.8895699977874756f, -1.2171133756637573f, -1.6773892641067505f, 0.03193039819598198f, 1.7724354267120361f, 0.947238564491272f, -0.9524959921836853f, -0.9470030665397644f, 0.2023036628961563f, 0.0f, 15.217596054077148f, 0.0f, -7.125387668609619f, -0.2531067728996277f, -0.24137455224990845f, 1.5118569135665894f, -0.2542422413825989f, -1.7687504291534424f, -1.0124930143356323f, 1.0315710306167603f, 1.4546130895614624f, -1.310428500175476f, 0.10202603042125702f, 1.9337987899780273f, -1.497254490852356f, -1.6247752904891968f, 1.6188490390777588f, 0.6926945447921753f, -0.15771538019180298f, -1.3199396133422852f, -1.1518778800964355f, 1.6077183485031128f, 0.3594363033771515f, 0.8051890134811401f, 0.9767069816589355f, -1.4772316217422485f, -0.6021702289581299f, 0.7343721389770508f, -0.0724407359957695f, -0.5183552503585815f, -0.4992843568325043f, -0.03613632544875145f, 1.4036649465560913f, 0.04015156626701355f, -1.228305697441101f, -0.0925367921590805f, -0.2714783847332001f, -0.03163623437285423f, 0.9381487369537354f, 0.37101879715919495f, -1.2094374895095825f, -0.3423338234424591f, 1.8034299612045288f, 0.09207195788621902f, -0.88663250207901f, 0.9320982098579407f, -0.6818090677261353f, -0.2640230357646942f, 1.2556750774383545f, -1.538971185684204f, -1.149613618850708f, 1.1836647987365723f, 0.6842570900917053f, -0.5314778685569763f, -0.14588366448879242f, 0.7240946888923645f, 0.31777524948120117f, -0.395994633436203f, 0.25728604197502136f, 0.11930612474679947f, -1.1518206596374512f, -0.5916019678115845f, 0.1650265008211136f, 0.4140322506427765f, 0.7870568633079529f, 0.0f, 16.3973445892334f, 0.0f, -8.301376342773438f, 1.3921542167663574f, 0.9190059900283813f, -1.7168506383895874f, -0.9477383494377136f, 1.2064414024353027f, -0.44224709272384644f, -0.8187872171401978f, 1.0579586029052734f, 1.9434236288070679f, -0.5568656921386719f, -2.409271001815796f, -0.9883224368095398f, 0.685625433921814f, 2.317107677459717f, 0.30506253242492676f, -1.4718111753463745f, 1.7264904975891113f, -0.43127748370170593f, -2.4826736450195312f, 0.8570032119750977f, 0.7776591181755066f, 0.3663090467453003f, -0.14546701312065125f, -0.9143816828727722f, -0.3068501651287079f, 0.6503768563270569f, 0.5498145222663879f, -0.9358937740325928f, 0.03292904794216156f, 1.013374924659729f, 0.15271002054214478f, -0.3798579275608063f, -0.7522398233413696f, 0.08351734280586243f, 0.8852012753486633f, 0.15113350749015808f, -0.5763111114501953f, -0.34957098960876465f, -0.35977303981781006f, -0.8016862273216248f, 1.509504795074463f, 1.3573514223098755f, -2.126422166824341f, -0.9929434061050415f, 1.974360704421997f, 1.2492095232009888f, -1.5806905031204224f, -0.36666131019592285f, 0.4222898781299591f, -0.7937326431274414f, 0.5921651124954224f, 0.6042671799659729f, -0.24500346183776855f, -0.07217034697532654f, 0.039713405072689056f, -0.6377639770507812f, -0.3231410086154938f, 0.8462148904800415f, 0.5737519860267639f, -0.8070881962776184f, -0.6063241362571716f, 1.0397725105285645f, 0.0f, 17.64320945739746f, 0.0f, -9.308979034423828f, -0.09497420489788055f, -0.5299174189567566f, -0.25844717025756836f, 1.9056460857391357f, 0.5672109127044678f, -0.7845551371574402f, -0.21017839014530182f, -1.4158135652542114f, -0.9128528237342834f, 1.5310827493667603f, 0.8659438490867615f, -0.3503185212612152f, -0.29329514503479004f, 1.4173864126205444f, 1.6468437910079956f, -2.5427215099334717f, -3.13273549079895f, 1.9385576248168945f, 2.7410802841186523f, -0.7216293811798096f, -1.1170438528060913f, 0.17288847267627716f, 0.49863216280937195f, -0.1679350733757019f, -0.4200337827205658f, -0.06375698000192642f, -0.6986592411994934f, 0.1419513076543808f, 1.1478649377822876f, -0.0799521878361702f, -0.048120155930519104f, -0.04219522699713707f, -0.17328546941280365f, 0.15248824656009674f, -0.6511729955673218f, -0.09438119828701019f, 0.4558165669441223f, 0.11280001699924469f, -0.21936899423599243f, 0.6010715961456299f, -0.8200600743293762f, -1.526708722114563f, 2.243004083633423f, 0.2569247782230377f, -0.6642544269561768f, 1.2618194818496704f, -1.2379958629608154f, -1.0824211835861206f, 0.9506871700286865f, 0.7668206095695496f, -0.5160090327262878f, -0.2795478105545044f, 0.21007297933101654f, -0.310122013092041f, 0.11434147506952286f, 0.8245198130607605f, -0.21033991873264313f, -0.60224449634552f, 0.18137940764427185f, -0.8124065399169922f, -0.00039693614235147834f, 1.6200891733169556f, 0.0f}; 2 | const float g_reference[] = {0.3745401203632355f, 0.9507142305374146f, 0.7319939136505127f, 0.598658561706543f, 0.15601865947246552f, 0.15599451959133148f, 0.05808362737298012f, 0.866176187992096f, 0.6011149883270264f, 0.7080724835395813f, 0.020584505051374435f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391330242157f, 0.18182498216629028f, 0.1834045797586441f, 0.30424225330352783f, 0.5247564315795898f, 0.43194499611854553f, 0.29122912883758545f, 0.6118528246879578f, 0.1394938826560974f, 0.29214468598365784f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142343640327454f, 0.5924145579338074f, 0.0464504174888134f, 0.6075448393821716f, 0.17052407562732697f, 0.0650515928864479f, 0.948885440826416f, 0.9656320214271545f, 0.8083972930908203f, 0.30461379885673523f, 0.09767212718725204f, 0.6842329502105713f, 0.44015243649482727f, 0.12203822284936905f, 0.49517694115638733f, 0.034388527274131775f, 0.9093204140663147f, 0.25877994298934937f, 0.6625222563743591f, 0.3117111027240753f, 0.5200679898262024f, 0.5467102527618408f, 0.1848544329404831f, 0.9695846438407898f, 0.7751328349113464f, 0.9394989013671875f, 0.8948273658752441f, 0.5978999733924866f, 0.9218742251396179f, 0.0884924829006195f, 0.19598285853862762f, 0.04522727429866791f, 0.32533034682273865f, 0.3886772692203522f, 0.2713490426540375f, 0.8287374973297119f, 0.35675331950187683f, 0.28093448281288147f, 0.542695939540863f, 0.14092421531677246f, 0.8021969199180603f, 0.07455063611268997f, 0.9868867993354797f, 0.7722446918487549f, 0.1987156718969345f, 0.00552211282774806f, 0.8154613971710205f, 0.7068572640419006f, 0.7290071845054626f, 0.7712702751159668f, 0.07404465228319168f, 0.3584657609462738f, 0.11586905270814896f, 0.8631033897399902f, 0.6232980489730835f, 0.3308979570865631f, 0.06355834007263184f, 0.3109823167324066f, 0.32518330216407776f, 0.7296061515808105f, 0.6375574469566345f, 0.8872127532958984f, 0.472214937210083f, 0.11959421634674072f, 0.7132448554039001f, 0.7607850432395935f, 0.5612772107124329f, 0.7709671854972839f, 0.49379563331604004f, 0.5227327942848206f, 0.42754101753234863f, 0.025419121608138084f, 0.10789143294095993f, 0.03142915293574333f, 0.6364104151725769f, 0.3143559396266937f, 0.508570671081543f, 0.907566487789154f, 0.24929223954677582f, 0.4103828966617584f, 0.7555511593818665f, 0.22879813611507416f, 0.07697992771863937f, 0.28975144028663635f, 0.16122126579284668f, 0.929697573184967f, 0.8081203699111938f, 0.6334037184715271f, 0.8714606165885925f, 0.8036720752716064f, 0.18657010793685913f, 0.8925589323043823f, 0.5393422245979309f, 0.8074401617050171f, 0.8960912823677063f, 0.31800347566604614f, 0.1100519597530365f, 0.22793515026569366f, 0.4271078109741211f, 0.8180147409439087f, 0.8607305288314819f}; 3 | const size_t k_ncolumns = 33; 4 | const size_t k_nrows = 9; 5 | const size_t k_hop_length = 16; 6 | const size_t k_win_length = 64; 7 | -------------------------------------------------------------------------------- /tests/testvector/librosa_stft.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f, 0.6011149883270264f, 0.7080726027488708f, 0.02058449387550354f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391181230545f, 0.1818249672651291f, 0.18340450525283813f, 0.30424225330352783f, 0.5247564315795898f, 0.4319450259208679f, 0.29122912883758545f, 0.6118528842926025f, 0.13949386775493622f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142344236373901f, 0.5924145579338074f, 0.0464504137635231f, 0.6075448393821716f, 0.17052412033081055f, 0.0650515928864479f, 0.9488855600357056f, 0.9656320214271545f, 0.8083973526954651f, 0.30461376905441284f, 0.09767211228609085f, 0.6842330098152161f, 0.44015249609947205f, 0.12203823775053024f, 0.49517691135406494f, 0.03438851982355118f, 0.9093204140663147f, 0.25877997279167175f, 0.6625222563743591f, 0.31171107292175293f, 0.5200680494308472f, 0.5467102527618408f, 0.18485446274280548f, 0.9695846438407898f, 0.7751328349113464f, 0.9394989609718323f, 0.8948273658752441f, 0.5978999733924866f, 0.9218742251396179f, 0.0884925052523613f, 0.19598285853862762f, 0.0452272891998291f, 0.32533031702041626f, 0.38867729902267456f, 0.2713490426540375f, 0.8287374973297119f, 0.35675331950187683f, 0.28093451261520386f, 0.5426960587501526f, 0.14092423021793365f, 0.8021969795227051f, 0.07455064356327057f, 0.9868869185447693f, 0.7722447514533997f, 0.1987156867980957f, 0.005522117018699646f, 0.8154614567756653f, 0.7068573236465454f, 0.7290071845054626f, 0.7712703347206116f, 0.07404465228319168f, 0.3584657311439514f, 0.11586906015872955f, 0.863103449344635f, 0.6232981085777283f, 0.3308980166912079f, 0.06355834752321243f, 0.3109823167324066f, 0.32518333196640015f, 0.7296061515808105f, 0.6375574469566345f, 0.8872127532958984f, 0.472214937210083f, 0.11959424614906311f, 0.7132447957992554f, 0.7607850432395935f, 0.5612772107124329f, 0.7709671854972839f, 0.49379560351371765f, 0.5227328538894653f, 0.42754101753234863f, 0.025419127196073532f, 0.10789142549037933f, 0.03142918646335602f, 0.6364104151725769f, 0.3143559694290161f, 0.508570671081543f, 0.907566487789154f, 0.24929222464561462f, 0.4103829264640808f, 0.7555511593818665f, 0.22879816591739655f, 0.07697991281747818f, 0.28975144028663635f, 0.16122128069400787f, 0.9296976327896118f, 0.8081203699111938f, 0.6334037780761719f, 0.8714606165885925f, 0.8036720752716064f, 0.18657006323337555f, 0.8925589919090271f, 0.5393422245979309f, 0.8074401617050171f, 0.8960912823677063f, 0.31800347566604614f, 0.11005192250013351f, 0.22793516516685486f, 0.4271077811717987f, 0.8180147409439087f, 0.8607305884361267f}; 2 | const float g_reference[] = {15.127864837646484f, 0.0f, -8.46943187713623f, -1.6653345369377348e-16f, 1.2745327949523926f, 9.524208030952926e-18f, -0.1934017837047577f, 5.551115123125783e-17f, 0.2618129551410675f, 5.412337245047638e-16f, -1.7684640884399414f, -1.6653345369377348e-16f, 3.041776180267334f, 1.7605766420626825e-16f, -3.1098506450653076f, -4.163336342344337e-17f, 1.4269992113113403f, -0.0f, -0.06825567781925201f, -1.5265566588595902e-16f, 0.6715459227561951f, 4.0680943695682874e-16f, -0.3449842929840088f, 5.551115123125783e-17f, -1.6804810762405396f, -3.608224830031759e-16f, 3.230522632598877f, 2.7755575615628914e-16f, -3.1008658409118652f, 5.455873150349733e-16f, 0.8266358375549316f, -6.106226635438361e-16f, 1.3840386867523193f, 0.0f, -1.1185752153396606f, -2.7755575615628914e-16f, -0.07223274558782578f, 1.2054651297501042e-16f, 1.2164442539215088f, 1.6653345369377348e-16f, -1.7205184698104858f, 3.0531133177191805e-16f, 0.8250223994255066f, 4.996003610813204e-16f, 0.4161289632320404f, 3.727978281940123e-17f, -0.3065255582332611f, 1.5265566588595902e-16f, -1.4978749752044678f, 0.0f, 1.5881668329238892f, -4.0245584642661925e-16f, -0.5009416937828064f, 4.3456501257245765e-16f, -0.15241272747516632f, 5.551115123125783e-17f, 1.2153269052505493f, -5.689893001203927e-16f, -0.7598091959953308f, 1.6653345369377348e-16f, -1.1675606966018677f, 2.1252039441253654e-16f, 2.612276792526245f, -5.551115123125783e-17f, -3.0459537506103516f, 0.0f, 14.375269889831543f, 0.0f, -6.590682029724121f, -0.7545922994613647f, -1.055687665939331f, 0.6712188124656677f, 0.33069416880607605f, -0.3221714198589325f, -0.03539302572607994f, 0.2909367084503174f, 1.3474011421203613f, -0.9603245854377747f, -1.587969422340393f, 0.19176653027534485f, -0.31820571422576904f, 1.9915574789047241f, 0.6550431847572327f, -1.9857500791549683f, 0.5688869953155518f, 0.4965772032737732f, -0.523764431476593f, -0.08560370653867722f, 0.4308584928512573f, 0.7815452218055725f, -1.426485538482666f, -1.5893300771713257f, 0.0019518034532666206f, 1.2549421787261963f, 2.5224881172180176f, -0.22993293404579163f, -1.8847662210464478f, 0.04327170550823212f, 0.8700533509254456f, 0.49728503823280334f, -0.8908606171607971f, -0.9052624702453613f, 0.40355589985847473f, 0.24825705587863922f, 0.8708437085151672f, -0.23958678543567657f, -1.5781919956207275f, 0.28082913160324097f, 0.7515044212341309f, 0.003527677385136485f, 0.13108114898204803f, -0.3084527254104614f, 0.22528085112571716f, 1.2012773752212524f, -1.7713499069213867f, -1.7090799808502197f, 1.6095327138900757f, 0.6024768352508545f, 0.1369958221912384f, 0.3686818480491638f, -0.8176153898239136f, -0.2710931897163391f, 1.1031544208526611f, 0.37632033228874207f, -0.8441156148910522f, -0.4901861548423767f, 0.648871660232544f, 1.120017170906067f, 0.3414151966571808f, -1.4617338180541992f, -1.6243213415145874f, 0.0f, 14.56569766998291f, 0.0f, -7.007680892944336f, 0.9447317719459534f, 0.18407347798347473f, -0.06981422752141953f, -1.306267499923706f, -0.3124689757823944f, 0.45407000184059143f, -0.9947559237480164f, 0.17539837956428528f, 1.2477387189865112f, 0.5589256882667542f, -1.1147269010543823f, 0.44570401310920715f, 2.0800061225891113f, -0.6796132922172546f, -1.9334112405776978f, -0.49252596497535706f, 1.0034632682800293f, 0.3278498351573944f, -0.6381726861000061f, 0.7306457161903381f, 0.9703041315078735f, -1.092358112335205f, -1.6342873573303223f, 1.139155626296997f, 1.0886679887771606f, -1.9401911497116089f, -0.9369967579841614f, 1.665429949760437f, 0.9113833904266357f, -0.5729420781135559f, 0.6238041520118713f, 0.5317192077636719f, -0.9421029090881348f, -0.7116326689720154f, 0.46657034754753113f, 0.7889355421066284f, -0.8242992162704468f, -0.9133171439170837f, 0.5270411968231201f, 0.3949715197086334f, 0.21043415367603302f, -0.3943552076816559f, -0.41607463359832764f, 1.3490588665008545f, 0.889778733253479f, -1.2153526544570923f, -1.9953665733337402f, 0.5238877534866333f, 2.6226627826690674f, -1.1839895248413086f, -1.6444121599197388f, 0.6347455382347107f, -0.34851884841918945f, 1.1359689235687256f, 1.132315754890442f, -0.857933759689331f, -0.05443352460861206f, 0.2759222686290741f, -1.0983672142028809f, 0.24393047392368317f, 0.8152329325675964f, -0.9501631855964661f, 0.0f, 15.656485557556152f, 0.0f, -8.42627239227295f, 0.13057668507099152f, 1.338409423828125f, -0.5947919487953186f, -1.3712878227233887f, 1.9393540620803833f, 0.9859256744384766f, -2.4101667404174805f, -0.060542527586221695f, 1.4427621364593506f, -1.683583378791809f, -0.1850171983242035f, 2.856182098388672f, -0.01323987077921629f, -1.6559516191482544f, 0.16279034316539764f, -0.38853535056114197f, -0.7832066416740417f, 0.11510468274354935f, 0.46847009658813477f, 1.0183560848236084f, 0.025208426639437675f, -0.47015756368637085f, -1.0277721881866455f, -0.5068453550338745f, 0.9722727537155151f, 0.7684547901153564f, 0.9363120794296265f, 0.19692985713481903f, -1.4263888597488403f, -1.239068627357483f, 1.0806405544281006f, 0.29769110679626465f, -0.7488762140274048f, 0.9855167269706726f, -0.04827433452010155f, -0.4061298668384552f, -0.1864081770181656f, -0.2870284914970398f, 0.44636186957359314f, 0.23360145092010498f, -0.04918382316827774f, -0.2511419951915741f, 0.8281019926071167f, 0.39278167486190796f, -0.6022027730941772f, -0.19100511074066162f, -0.9553259015083313f, -0.8805977702140808f, -0.3037765920162201f, 1.8432866334915161f, 2.476627826690674f, -2.387824535369873f, -1.9290086030960083f, 1.6608823537826538f, 0.7871016263961792f, -0.25887250900268555f, -1.1179546117782593f, -0.12630923092365265f, 1.021419882774353f, 0.9440017938613892f, 0.008236227557063103f, -1.7484261989593506f, 0.0f, 15.439499855041504f, 0.0f, -7.3903632164001465f, -0.3923853039741516f, -1.1686044931411743f, -0.2700342833995819f, 1.4737553596496582f, 1.7406373023986816f, -0.03433895483613014f, -1.5143119096755981f, -1.6276142597198486f, 0.2528674900531769f, 1.5194220542907715f, 0.8032265305519104f, 0.019141700118780136f, -1.5757465362548828f, -1.3571873903274536f, 0.8279022574424744f, 2.026916027069092f, -0.2271241396665573f, -1.2875661849975586f, 1.6112964153289795f, -0.7159297466278076f, -1.6488032341003418f, 1.3951590061187744f, -0.3733276426792145f, -0.5990731120109558f, 1.1374022960662842f, 0.012613246217370033f, -0.9235551953315735f, 0.08022090792655945f, 0.23840749263763428f, -0.9715112447738647f, 0.05148446187376976f, 2.0653672218322754f, 0.09298215061426163f, -1.6736351251602173f, 0.4652140438556671f, 0.5436675548553467f, -0.7116110920906067f, 0.08039559423923492f, 0.6749694347381592f, -0.5595993995666504f, -0.0791427493095398f, 1.0504924058914185f, -0.5521528720855713f, -1.0065946578979492f, 0.9576502442359924f, 0.09549643099308014f, -1.351135492324829f, 1.0659763813018799f, 1.164675235748291f, -0.5106009840965271f, -1.9070203304290771f, -1.51253342628479f, 2.2055301666259766f, 1.5899581909179688f, -1.2144818305969238f, 0.36770278215408325f, 1.3069241046905518f, -1.333899736404419f, -0.89107745885849f, 1.2740076780319214f, -0.48101097345352173f, -1.261981725692749f, 0.0f, 15.243585586547852f, 0.0f, -7.9514055252075195f, 0.19402354955673218f, -0.1931990385055542f, -0.09587167203426361f, 1.6795213222503662f, -0.41365230083465576f, -1.0104525089263916f, 0.9484491944313049f, -0.13005755841732025f, -0.7857146263122559f, -0.4506785273551941f, -0.2765459716320038f, 0.3482154905796051f, -0.4793684184551239f, 0.37835076451301575f, 0.6152461171150208f, -1.2239192724227905f, 1.5637694597244263f, 2.1266613006591797f, -2.3875057697296143f, -2.393404006958008f, 1.8153574466705322f, 1.9258278608322144f, -1.2058360576629639f, -0.8153762817382812f, 0.08434797823429108f, 0.03526346758008003f, 0.8473537564277649f, -0.0011135147651657462f, -0.6803033947944641f, 0.20806069672107697f, -0.6223580837249756f, -0.6585227251052856f, 1.7567012310028076f, 1.3007309436798096f, -1.1179333925247192f, -0.7670462727546692f, 0.22054703533649445f, -0.3766621947288513f, 0.6302412748336792f, 0.37931057810783386f, -1.2068129777908325f, -0.4326469600200653f, 0.29966601729393005f, 0.331156462430954f, 0.9943992495536804f, 0.38185763359069824f, -2.0339725017547607f, -0.28208547830581665f, 1.276145577430725f, -0.4684085249900818f, 0.35806795954704285f, 0.30495691299438477f, 0.47002723813056946f, 0.8895699977874756f, -1.2171133756637573f, -1.6773892641067505f, 0.03193039819598198f, 1.7724354267120361f, 0.947238564491272f, -0.9524959921836853f, -0.9470030665397644f, 0.2023036628961563f, 0.0f, 15.217596054077148f, 0.0f, -7.125387668609619f, -0.2531067728996277f, -0.24137455224990845f, 1.5118569135665894f, -0.2542422413825989f, -1.7687504291534424f, -1.0124930143356323f, 1.0315710306167603f, 1.4546130895614624f, -1.310428500175476f, 0.10202603042125702f, 1.9337987899780273f, -1.497254490852356f, -1.6247752904891968f, 1.6188490390777588f, 0.6926945447921753f, -0.15771538019180298f, -1.3199396133422852f, -1.1518778800964355f, 1.6077183485031128f, 0.3594363033771515f, 0.8051890134811401f, 0.9767069816589355f, -1.4772316217422485f, -0.6021702289581299f, 0.7343721389770508f, -0.0724407359957695f, -0.5183552503585815f, -0.4992843568325043f, -0.03613632544875145f, 1.4036649465560913f, 0.04015156626701355f, -1.228305697441101f, -0.0925367921590805f, -0.2714783847332001f, -0.03163623437285423f, 0.9381487369537354f, 0.37101879715919495f, -1.2094374895095825f, -0.3423338234424591f, 1.8034299612045288f, 0.09207195788621902f, -0.88663250207901f, 0.9320982098579407f, -0.6818090677261353f, -0.2640230357646942f, 1.2556750774383545f, -1.538971185684204f, -1.149613618850708f, 1.1836647987365723f, 0.6842570900917053f, -0.5314778685569763f, -0.14588366448879242f, 0.7240946888923645f, 0.31777524948120117f, -0.395994633436203f, 0.25728604197502136f, 0.11930612474679947f, -1.1518206596374512f, -0.5916019678115845f, 0.1650265008211136f, 0.4140322506427765f, 0.7870568633079529f, 0.0f, 16.3973445892334f, 0.0f, -8.301376342773438f, 1.3921542167663574f, 0.9190059900283813f, -1.7168506383895874f, -0.9477383494377136f, 1.2064414024353027f, -0.44224709272384644f, -0.8187872171401978f, 1.0579586029052734f, 1.9434236288070679f, -0.5568656921386719f, -2.409271001815796f, -0.9883224368095398f, 0.685625433921814f, 2.317107677459717f, 0.30506253242492676f, -1.4718111753463745f, 1.7264904975891113f, -0.43127748370170593f, -2.4826736450195312f, 0.8570032119750977f, 0.7776591181755066f, 0.3663090467453003f, -0.14546701312065125f, -0.9143816828727722f, -0.3068501651287079f, 0.6503768563270569f, 0.5498145222663879f, -0.9358937740325928f, 0.03292904794216156f, 1.013374924659729f, 0.15271002054214478f, -0.3798579275608063f, -0.7522398233413696f, 0.08351734280586243f, 0.8852012753486633f, 0.15113350749015808f, -0.5763111114501953f, -0.34957098960876465f, -0.35977303981781006f, -0.8016862273216248f, 1.509504795074463f, 1.3573514223098755f, -2.126422166824341f, -0.9929434061050415f, 1.974360704421997f, 1.2492095232009888f, -1.5806905031204224f, -0.36666131019592285f, 0.4222898781299591f, -0.7937326431274414f, 0.5921651124954224f, 0.6042671799659729f, -0.24500346183776855f, -0.07217034697532654f, 0.039713405072689056f, -0.6377639770507812f, -0.3231410086154938f, 0.8462148904800415f, 0.5737519860267639f, -0.8070881962776184f, -0.6063241362571716f, 1.0397725105285645f, 0.0f, 17.64320945739746f, 0.0f, -9.308979034423828f, -0.09497420489788055f, -0.5299174189567566f, -0.25844717025756836f, 1.9056460857391357f, 0.5672109127044678f, -0.7845551371574402f, -0.21017839014530182f, -1.4158135652542114f, -0.9128528237342834f, 1.5310827493667603f, 0.8659438490867615f, -0.3503185212612152f, -0.29329514503479004f, 1.4173864126205444f, 1.6468437910079956f, -2.5427215099334717f, -3.13273549079895f, 1.9385576248168945f, 2.7410802841186523f, -0.7216293811798096f, -1.1170438528060913f, 0.17288847267627716f, 0.49863216280937195f, -0.1679350733757019f, -0.4200337827205658f, -0.06375698000192642f, -0.6986592411994934f, 0.1419513076543808f, 1.1478649377822876f, -0.0799521878361702f, -0.048120155930519104f, -0.04219522699713707f, -0.17328546941280365f, 0.15248824656009674f, -0.6511729955673218f, -0.09438119828701019f, 0.4558165669441223f, 0.11280001699924469f, -0.21936899423599243f, 0.6010715961456299f, -0.8200600743293762f, -1.526708722114563f, 2.243004083633423f, 0.2569247782230377f, -0.6642544269561768f, 1.2618194818496704f, -1.2379958629608154f, -1.0824211835861206f, 0.9506871700286865f, 0.7668206095695496f, -0.5160090327262878f, -0.2795478105545044f, 0.21007297933101654f, -0.310122013092041f, 0.11434147506952286f, 0.8245198130607605f, -0.21033991873264313f, -0.60224449634552f, 0.18137940764427185f, -0.8124065399169922f, -0.00039693614235147834f, 1.6200891733169556f, 0.0f}; 3 | const size_t k_n_fft = 64; 4 | const size_t k_nframes = 128; 5 | const size_t k_out_dim0 = 9; 6 | const size_t k_out_dim1 = 33; 7 | const size_t k_hop_length = 16; 8 | const size_t k_win_length = 64; 9 | -------------------------------------------------------------------------------- /tests/testvector/lifter.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f, 0.6011149883270264f, 0.7080726027488708f, 0.02058449387550354f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391181230545f, 0.1818249672651291f, 0.18340450525283813f, 0.30424225330352783f, 0.5247564315795898f, 0.4319450259208679f, 0.29122912883758545f, 0.6118528842926025f, 0.13949386775493622f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142344236373901f, 0.5924145579338074f, 0.0464504137635231f, 0.6075448393821716f, 0.17052412033081055f, 0.0650515928864479f, 0.9488855600357056f, 0.9656320214271545f, 0.8083973526954651f, 0.30461376905441284f, 0.09767211228609085f, 0.6842330098152161f, 0.44015249609947205f, 0.12203823775053024f, 0.49517691135406494f, 0.03438851982355118f, 0.9093204140663147f, 0.25877997279167175f, 0.6625222563743591f, 0.31171107292175293f, 0.5200680494308472f, 0.5467102527618408f, 0.18485446274280548f, 0.9695846438407898f, 0.7751328349113464f, 0.9394989609718323f, 0.8948273658752441f, 0.5978999733924866f, 0.9218742251396179f, 0.0884925052523613f, 0.19598285853862762f, 0.0452272891998291f, 0.32533031702041626f, 0.38867729902267456f, 0.2713490426540375f, 0.8287374973297119f, 0.35675331950187683f, 0.28093451261520386f, 0.5426960587501526f, 0.14092423021793365f, 0.8021969795227051f, 0.07455064356327057f, 0.9868869185447693f, 0.7722447514533997f, 0.1987156867980957f, 0.005522117018699646f, 0.8154614567756653f, 0.7068573236465454f, 0.7290071845054626f, 0.7712703347206116f, 0.07404465228319168f, 0.3584657311439514f, 0.11586906015872955f}; 2 | const float g_reference[] = {0.3745401203632355f, 2.43902254504441f, 3.000485599386873f, 3.3342675258797465f, 1.0838691675040915f, 0.15599451959133148f, 0.14901137153962477f, 3.5505062969691297f, 3.347949085933531f, 4.9190150611975545f, 0.02058449387550354f, 2.4882680396126733f, 3.412230772458926f, 1.18263655079793f, 1.2631469555617523f, 0.18340450525283813f, 0.7805223111262334f, 2.151007114646519f, 2.4057459600700604f, 2.0231830259355563f, 0.6118528842926025f, 0.3578663872811827f, 1.197517926670144f, 2.040476225475169f, 3.1683404676923974f, 0.7851759791374207f, 0.5122557561302025f, 2.1078767924970396f, 3.29949147208618f, 0.32269330011440367f, 0.6075448393821716f, 0.4374733590031192f, 0.26665026038202194f, 5.284879939890589f, 6.708292961109612f, 0.8083973526954651f, 0.7814754211211533f, 0.40036366547719043f, 3.810880321171002f, 3.0577609543592152f, 0.12203823775053024f, 1.2703581539702695f, 0.1409605415982451f, 5.0645192820209415f, 1.7977571491351656f, 0.6625222563743591f, 0.799683293161119f, 2.131789163705411f, 3.0449383671144123f, 1.2841930090662477f, 0.9695846438407898f, 1.9885747793592805f, 3.851060849640902f, 4.983799305999835f, 4.15364040748002f, 0.9218742251396179f, 0.22702426755962526f, 0.8033451287036053f, 0.25189633344068696f, 2.2600856509274885f, 0.38867729902267456f, 0.6961359889841584f, 3.397043172133452f, 1.986960852954598f, 1.9516658226847146f, 0.5426960587501526f, 0.36153592957271036f, 3.288252046968146f, 0.41521466577975596f, 6.855951772705847f, 0.7722447514533997f, 0.5097977859174891f, 0.022635478634113717f, 4.541765705134667f, 4.910572457734731f, 0.7290071845054626f, 1.9786656771788211f, 0.30351333357315186f, 1.9964982411467993f, 0.8049480375810305f}; 3 | const size_t k_nframes = 16; 4 | const size_t k_ncoeffs = 5; 5 | -------------------------------------------------------------------------------- /tests/testvector/medfilt1.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f, 0.6011149883270264f, 0.7080726027488708f, 0.02058449387550354f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391181230545f, 0.1818249672651291f, 0.18340450525283813f, 0.30424225330352783f, 0.5247564315795898f, 0.4319450259208679f, 0.29122912883758545f, 0.6118528842926025f, 0.13949386775493622f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142344236373901f, 0.5924145579338074f, 0.0464504137635231f, 0.6075448393821716f, 0.17052412033081055f}; 2 | const float g_reference[] = {0.3745401203632355f, 0.7319939136505127f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.15599451959133148f, 0.6011149883270264f, 0.7080726027488708f, 0.6011149883270264f, 0.7080726027488708f, 0.8324426412582397f, 0.8324426412582397f, 0.2123391181230545f, 0.18340450525283813f, 0.18340450525283813f, 0.30424225330352783f, 0.4319450259208679f, 0.4319450259208679f, 0.4319450259208679f, 0.29122912883758545f, 0.29214465618133545f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.4560699760913849f, 0.5142344236373901f, 0.5142344236373901f, 0.5142344236373901f, 0.5924145579338074f, 0.17052412033081055f, 0.17052412033081055f}; 3 | const size_t k_input_n = 32; 4 | const size_t k_window_size = 3; 5 | -------------------------------------------------------------------------------- /tests/testvector/random_normal.inc: -------------------------------------------------------------------------------- 1 | const float g_reference[] = {0.49671414494514465f, -0.13826429843902588f, 0.6476885676383972f, 1.5230298042297363f, -0.2341533750295639f, -0.23413695394992828f, 1.5792127847671509f, 0.7674347162246704f, -0.4694743752479553f, 0.5425600409507751f, -0.4634176790714264f, -0.4657297432422638f, 0.241962268948555f, -1.9132802486419678f, -1.7249178886413574f, -0.5622875094413757f, -1.0128310918807983f, 0.31424733996391296f, -0.9080240726470947f, -1.4123036861419678f, 1.4656487703323364f, -0.2257762998342514f, 0.06752820312976837f, -1.424748182296753f, -0.5443827509880066f, 0.11092258989810944f, -1.1509935855865479f, 0.3756980299949646f, -0.6006386876106262f, -0.2916937470436096f, -0.6017066240310669f, 1.852278232574463f}; 2 | const size_t k_n = 32; 3 | const size_t k_seed = 42; 4 | -------------------------------------------------------------------------------- /tests/testvector/random_uniform.inc: -------------------------------------------------------------------------------- 1 | const float g_reference[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f, 0.6011149883270264f, 0.7080726027488708f, 0.02058449387550354f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391181230545f, 0.1818249672651291f, 0.18340450525283813f, 0.30424225330352783f, 0.5247564315795898f, 0.4319450259208679f, 0.29122912883758545f, 0.6118528842926025f, 0.13949386775493622f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142344236373901f, 0.5924145579338074f, 0.0464504137635231f, 0.6075448393821716f, 0.17052412033081055f}; 2 | const size_t k_n = 32; 3 | const size_t k_seed = 42; 4 | -------------------------------------------------------------------------------- /tests/testvector/rfft.inc: -------------------------------------------------------------------------------- 1 | const float g_input[] = {0.3745401203632355f, 0.9507142901420593f, 0.7319939136505127f, 0.5986585021018982f, 0.15601864457130432f, 0.15599451959133148f, 0.058083612471818924f, 0.8661761283874512f, 0.6011149883270264f, 0.7080726027488708f, 0.02058449387550354f, 0.9699098467826843f, 0.8324426412582397f, 0.2123391181230545f, 0.1818249672651291f, 0.18340450525283813f, 0.30424225330352783f, 0.5247564315795898f, 0.4319450259208679f, 0.29122912883758545f, 0.6118528842926025f, 0.13949386775493622f, 0.29214465618133545f, 0.3663618564605713f, 0.4560699760913849f, 0.7851759791374207f, 0.19967378675937653f, 0.5142344236373901f, 0.5924145579338074f, 0.0464504137635231f, 0.6075448393821716f, 0.17052412033081055f, 0.0650515928864479f, 0.9488855600357056f, 0.9656320214271545f, 0.8083973526954651f, 0.30461376905441284f, 0.09767211228609085f, 0.6842330098152161f, 0.44015249609947205f, 0.12203823775053024f, 0.49517691135406494f, 0.03438851982355118f, 0.9093204140663147f, 0.25877997279167175f, 0.6625222563743591f, 0.31171107292175293f, 0.5200680494308472f, 0.5467102527618408f, 0.18485446274280548f, 0.9695846438407898f, 0.7751328349113464f, 0.9394989609718323f, 0.8948273658752441f, 0.5978999733924866f, 0.9218742251396179f, 0.0884925052523613f, 0.19598285853862762f, 0.0452272891998291f, 0.32533031702041626f, 0.38867729902267456f, 0.2713490426540375f, 0.8287374973297119f, 0.35675331950187683f}; 2 | const float g_reference[] = {7.41846838966012f, 0.0f, 0.22224115715680573f, 0.5425364262236541f, 0.26344064053925176f, -1.5131044848315307f, -1.6230507255254234f, -1.4857967909206413f, 1.0769683651868798f, -0.8502811632343243f, 0.14846202358603477f, 0.3767258661954804f, -0.7083856347294607f, 0.4203700253072771f, -0.2798591183198825f, -1.414976492610436f, 6.163590081036091f, 0.0f, -0.03150154630836788f, 0.29712066728231945f, 0.11018681343558623f, -0.6820362533568072f, -0.0930733862538107f, 0.28958648870364045f, 0.5288958324009976f, -0.4680109758903722f, 0.3160148225724697f, 0.34657709651092894f, -1.3801968847196333f, 0.9635910733481529f, -0.2503037918688287f, 0.09601784503985078f, 7.10857529938221f, 0.0f, 0.9388985318274892f, -0.6378091158537578f, -0.5003902991906976f, -0.8597478337366097f, -1.3091489210566853f, -1.4029915065733682f, -0.8645458069436571f, 0.4907337794336797f, -0.08682939037680626f, 0.01369295028348677f, -1.7523581661441947f, -0.7729818361865324f, 0.5079733488418061f, -0.9730055406095484f, 7.974179528653622f, 0.0f, 0.4298659194650052f, -2.380630574179803f, -0.38519723967064984f, 1.1416157521072363f, -0.32672339593027777f, 0.14112314679675503f, 0.3058361587346089f, 1.0230522996053675f, -0.23048493638634682f, 0.6444686945889215f, 0.056545901195752285f, 1.5923368485242841f, 0.2633947239789035f, -0.5352135260199884f}; 3 | const size_t k_fft_len = 15; 4 | const size_t k_nframes = 16; 5 | const size_t k_nrows = 4; 6 | -------------------------------------------------------------------------------- /tests/testvector/signal_get_window_hann.inc: -------------------------------------------------------------------------------- 1 | const float g_reference[] = {0.0f, 0.002407636663901591f, 0.009607359798384785f, 0.021529832133895588f, 0.03806023374435663f, 0.05903936782582253f, 0.08426519384872733f, 0.1134947733186315f, 0.14644660940672627f, 0.1828033579181773f, 0.22221488349019902f, 0.26430163158700115f, 0.30865828381745514f, 0.3548576613727689f, 0.4024548389919359f, 0.45099142983521967f, 0.5f, 0.5490085701647804f, 0.5975451610080642f, 0.6451423386272311f, 0.6913417161825449f, 0.735698368412999f, 0.7777851165098011f, 0.8171966420818227f, 0.8535533905932737f, 0.8865052266813684f, 0.9157348061512727f, 0.9409606321741775f, 0.9619397662556434f, 0.9784701678661045f, 0.9903926402016152f, 0.9975923633360985f, 1.0f, 0.9975923633360985f, 0.9903926402016152f, 0.9784701678661045f, 0.9619397662556434f, 0.9409606321741775f, 0.9157348061512727f, 0.8865052266813684f, 0.8535533905932737f, 0.8171966420818229f, 0.7777851165098011f, 0.735698368412999f, 0.6913417161825451f, 0.6451423386272311f, 0.5975451610080642f, 0.5490085701647802f, 0.5f, 0.4509914298352199f, 0.4024548389919358f, 0.3548576613727689f, 0.30865828381745497f, 0.26430163158700115f, 0.22221488349019902f, 0.18280335791817715f, 0.14644660940672627f, 0.11349477331863167f, 0.08426519384872733f, 0.05903936782582253f, 0.03806023374435674f, 0.021529832133895588f, 0.009607359798384785f, 0.0024076366639015356f}; 2 | const size_t k_win_length = 64; 3 | -------------------------------------------------------------------------------- /vcsetup.bat: -------------------------------------------------------------------------------- 1 | rmdir /q /s build 2 | 3 | cmake -G "Visual Studio 15 2017" -A x64 -Bbuild -H. 4 | --------------------------------------------------------------------------------