From 26e11eebfc33869c6ae47aaa4133ecdcef9d1db0 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 7 Nov 2024 11:08:52 +0100 Subject: [PATCH 01/35] feat: added periodic wave cpp files --- .../react-native-audio-api/common/cpp/core/PeriodicWave.cpp | 1 + .../react-native-audio-api/common/cpp/core/PeriodicWave.h | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp create mode 100644 packages/react-native-audio-api/common/cpp/core/PeriodicWave.h diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp new file mode 100644 index 00000000..f8bc5fa0 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -0,0 +1 @@ +#include "PeriodicWave.h" diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h new file mode 100644 index 00000000..48149319 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -0,0 +1,5 @@ +#pragma once + +class PeriodicWave { + +}; From d75ddeefb6d14eb4085d98dc96ce4a7518ac6cda Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 7 Nov 2024 12:06:43 +0100 Subject: [PATCH 02/35] feat: added props --- .../common/cpp/core/PeriodicWave.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 48149319..b5975ad0 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -1,5 +1,18 @@ #pragma once -class PeriodicWave { +namespace audioapi { + class PeriodicWave { -}; + private: + explicit PeriodicWave(unsigned sampleRate); + + // determines the time resolution of the waveform. + unsigned sampleRate_; + // determines number of frequency segments (or bands) the signal is divided. + unsigned numberOfRanges_; + // the lowest frequency (in hertz) where playback will include all of the partials. + float lowestFundamentalFrequency; + // scaling factor used to adjust size of period of waveform to the sample rate. + float rateScale_; + }; +} // namespace audioapi From 436a5eb9c4145d55c2f8ff19d4973537ef4c335b Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 7 Nov 2024 17:13:30 +0100 Subject: [PATCH 03/35] refactor: enums refactoring --- .../src/examples/Oscillator/Oscillator.tsx | 8 +- .../android/CMakeLists.txt | 12 +- .../common/cpp/core/AudioContext.cpp | 2 +- .../common/cpp/core/AudioNode.h | 55 ++++----- .../common/cpp/core/BaseAudioContext.cpp | 2 +- .../common/cpp/core/BaseAudioContext.h | 33 +++-- .../common/cpp/core/BiquadFilterNode.cpp | 22 ++-- .../common/cpp/core/BiquadFilterNode.h | 113 ++++++++---------- .../common/cpp/core/OscillatorNode.h | 106 ++++++++-------- .../common/cpp/types/BiquadFilterType.h | 20 ++++ .../common/cpp/types/ChannelCountMode.h | 10 ++ .../common/cpp/types/ChannelInterpretation.h | 10 ++ .../common/cpp/types/ContextState.h | 10 ++ .../common/cpp/types/OscillatorType.h | 17 +++ .../src/core/AudioScheduledSourceNode.ts | 2 + .../src/core/BiquadFilterNode.ts | 6 +- .../src/core/OscillatorNode.ts | 6 +- .../react-native-audio-api/src/core/types.ts | 4 +- packages/react-native-audio-api/src/index.ts | 4 +- .../react-native-audio-api/src/interfaces.ts | 8 +- 20 files changed, 244 insertions(+), 206 deletions(-) create mode 100644 packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h create mode 100644 packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h create mode 100644 packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h create mode 100644 packages/react-native-audio-api/common/cpp/types/ContextState.h create mode 100644 packages/react-native-audio-api/common/cpp/types/OscillatorType.h diff --git a/apps/common-app/src/examples/Oscillator/Oscillator.tsx b/apps/common-app/src/examples/Oscillator/Oscillator.tsx index e6055693..658c7ff2 100644 --- a/apps/common-app/src/examples/Oscillator/Oscillator.tsx +++ b/apps/common-app/src/examples/Oscillator/Oscillator.tsx @@ -6,7 +6,7 @@ import { GainNode, OscillatorNode, StereoPannerNode, - type WaveType, + type OscillatorType, } from 'react-native-audio-api'; import { Container, Slider, Spacer, Button } from '../../components'; @@ -26,7 +26,7 @@ const Oscillator: FC = () => { const [frequency, setFrequency] = useState(INITIAL_FREQUENCY); const [detune, setDetune] = useState(INITIAL_DETUNE); const [pan, setPan] = useState(INITIAL_PAN); - const [oscillatorType, setOscillatorType] = useState('sine'); + const [oscillatorType, setOscillatorType] = useState('sine'); const audioContextRef = useRef(null); const oscillatorRef = useRef(null); @@ -97,7 +97,7 @@ const Oscillator: FC = () => { setIsPlaying((prev) => !prev); }; - const handleOscillatorTypeChange = (type: WaveType) => { + const handleOscillatorTypeChange = (type: OscillatorType) => { setOscillatorType(type); if (oscillatorRef.current) { oscillatorRef.current.type = type; @@ -159,7 +159,7 @@ const Oscillator: FC = () => { /> - {OSCILLATOR_TYPES.map((type: WaveType) => ( + {OSCILLATOR_TYPES.map((type: OscillatorType) => ( [ diff --git a/packages/react-native-audio-api/android/CMakeLists.txt b/packages/react-native-audio-api/android/CMakeLists.txt index b91d27fe..b16d4e14 100644 --- a/packages/react-native-audio-api/android/CMakeLists.txt +++ b/packages/react-native-audio-api/android/CMakeLists.txt @@ -32,6 +32,7 @@ file(GLOB_RECURSE SOURCE_FILES "../common/cpp/HostObjects/*.h" "../common/cpp/utils/*.cpp" "../common/cpp/utils/*.h" + "../common/cpp/types/*.h" ) add_library(react-native-audio-api SHARED ${SOURCE_FILES}) @@ -51,17 +52,6 @@ find_package(ReactAndroid REQUIRED CONFIG) find_package(fbjni REQUIRED CONFIG) find_package (oboe REQUIRED CONFIG) -# set(LINK_LIBRARIES -# ReactAndroid::reactnative -# ReactAndroid::jsi -# fbjni::fbjni -# android -# log -# oboe::oboe -# ) - -# target_link_libraries(react-native-audio-api ${LINK_LIBRARIES}) - set(LINK_LIBRARIES ReactAndroid::jsi fbjni::fbjni diff --git a/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp index 9c92567d..41873ce9 100644 --- a/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp @@ -5,7 +5,7 @@ namespace audioapi { AudioContext::AudioContext() : BaseAudioContext() {} void AudioContext::close() { - state_ = State::CLOSED; + state_ = ContextState::CLOSED; if (audioPlayer_) { audioPlayer_->stop(); diff --git a/packages/react-native-audio-api/common/cpp/core/AudioNode.h b/packages/react-native-audio-api/common/cpp/core/AudioNode.h index 071d4f67..8be8ce42 100644 --- a/packages/react-native-audio-api/common/cpp/core/AudioNode.h +++ b/packages/react-native-audio-api/common/cpp/core/AudioNode.h @@ -4,6 +4,8 @@ #include #include #include "Constants.h" +#include "ChannelCountMode.h" +#include "ChannelInterpretation.h" // channelCount always equal to 2 @@ -26,35 +28,6 @@ class AudioNode : public std::enable_shared_from_this { // Change public to protected virtual bool processAudio(float *audioData, int32_t numFrames); - protected: - enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT }; - - static std::string toString(ChannelCountMode mode) { - switch (mode) { - case ChannelCountMode::MAX: - return "max"; - case ChannelCountMode::CLAMPED_MAX: - return "clamped-max"; - case ChannelCountMode::EXPLICIT: - return "explicit"; - default: - throw std::invalid_argument("Unknown channel count mode"); - } - } - - enum class ChannelInterpretation { SPEAKERS, DISCRETE }; - - static std::string toString(ChannelInterpretation interpretation) { - switch (interpretation) { - case ChannelInterpretation::SPEAKERS: - return "speakers"; - case ChannelInterpretation::DISCRETE: - return "discrete"; - default: - throw std::invalid_argument("Unknown channel interpretation"); - } - } - protected: BaseAudioContext *context_; int numberOfInputs_ = 1; @@ -68,6 +41,30 @@ class AudioNode : public std::enable_shared_from_this { std::vector> outputNodes_ = {}; private: + static std::string toString(ChannelCountMode mode) { + switch (mode) { + case ChannelCountMode::MAX: + return "max"; + case ChannelCountMode::CLAMPED_MAX: + return "clamped-max"; + case ChannelCountMode::EXPLICIT: + return "explicit"; + default: + throw std::invalid_argument("Unknown channel count mode"); + } + } + + static std::string toString(ChannelInterpretation interpretation) { + switch (interpretation) { + case ChannelInterpretation::SPEAKERS: + return "speakers"; + case ChannelInterpretation::DISCRETE: + return "discrete"; + default: + throw std::invalid_argument("Unknown channel interpretation"); + } + } + void cleanup(); }; diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp index d2cb745b..3f2b19e4 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp @@ -70,7 +70,7 @@ std::shared_ptr BaseAudioContext::createBuffer( } std::function BaseAudioContext::renderAudio() { - if (state_ == State::CLOSED) { + if (state_ == ContextState::CLOSED) { return [](float *, int) {}; } diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h index d19b1933..9af2570c 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h @@ -15,6 +15,7 @@ #include "GainNode.h" #include "OscillatorNode.h" #include "StereoPannerNode.h" +#include "ContextState.h" #ifdef ANDROID #include "AudioPlayer.h" @@ -41,22 +42,6 @@ class BaseAudioContext { createBuffer(int numberOfChannels, int length, int sampleRate); std::function renderAudio(); - protected: - enum class State { SUSPENDED, RUNNING, CLOSED }; - - static std::string toString(State state) { - switch (state) { - case State::SUSPENDED: - return "suspended"; - case State::RUNNING: - return "running"; - case State::CLOSED: - return "closed"; - default: - throw std::invalid_argument("Unknown context state"); - } - } - protected: std::shared_ptr destination_; #ifdef ANDROID @@ -64,9 +49,23 @@ class BaseAudioContext { #else std::shared_ptr audioPlayer_; #endif - State state_ = State::RUNNING; + ContextState state_ = ContextState::RUNNING; int sampleRate_; double contextStartTime_; + +private: + static std::string toString(ContextState state) { + switch (state) { + case ContextState::SUSPENDED: + return "suspended"; + case ContextState::RUNNING: + return "running"; + case ContextState::CLOSED: + return "closed"; + default: + throw std::invalid_argument("Unknown context state"); + } + } }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp index bc27886a..8592687a 100644 --- a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp @@ -16,10 +16,10 @@ BiquadFilterNode::BiquadFilterNode(BaseAudioContext *context) std::make_shared(context, 1.0, -MAX_FILTER_Q, MAX_FILTER_Q); gainParam_ = std::make_shared( context, 0.0, MIN_FILTER_GAIN, MAX_FILTER_GAIN); - type_ = FilterType::LOWPASS; + type_ = BiquadFilterType::LOWPASS; } -std::string BiquadFilterNode::getType() const { +std::string BiquadFilterNode::getType() { return BiquadFilterNode::toString(type_); } @@ -58,8 +58,6 @@ void BiquadFilterNode::getFrequencyResponse( applyFilter(); auto frequencyArraySize = frequencyArray.size(); - auto magResponseOutputSize = magResponseOutput.size(); - auto phaseResponseOutputSize = phaseResponseOutput.size(); float b0 = b0_; float b1 = b1_; @@ -312,37 +310,37 @@ void BiquadFilterNode::applyFilter() { } switch (type_) { - case FilterType::LOWPASS: + case BiquadFilterType::LOWPASS: setLowpassCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; - case FilterType::HIGHPASS: + case BiquadFilterType::HIGHPASS: setHighpassCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; - case FilterType::BANDPASS: + case BiquadFilterType::BANDPASS: setBandpassCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; - case FilterType::LOWSHELF: + case BiquadFilterType::LOWSHELF: setLowshelfCoefficients( normalizedFrequency, gainParam_->getValueAtTime(currentTime)); break; - case FilterType::HIGHSHELF: + case BiquadFilterType::HIGHSHELF: setHighshelfCoefficients( normalizedFrequency, gainParam_->getValueAtTime(currentTime)); break; - case FilterType::PEAKING: + case BiquadFilterType::PEAKING: setPeakingCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime), gainParam_->getValueAtTime(currentTime)); break; - case FilterType::NOTCH: + case BiquadFilterType::NOTCH: setNotchCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; - case FilterType::ALLPASS: + case BiquadFilterType::ALLPASS: setAllpassCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; diff --git a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h index d1f504d6..a413772b 100644 --- a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h +++ b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h @@ -10,6 +10,7 @@ #include "AudioNode.h" #include "AudioParam.h" +#include "BiquadFilterType.h" namespace audioapi { @@ -17,7 +18,7 @@ class BiquadFilterNode : public AudioNode { public: explicit BiquadFilterNode(BaseAudioContext *context); - [[nodiscard]] std::string getType() const; + [[nodiscard]] std::string getType(); void setType(const std::string &type); [[nodiscard]] std::shared_ptr getFrequencyParam() const; [[nodiscard]] std::shared_ptr getDetuneParam() const; @@ -31,72 +32,12 @@ class BiquadFilterNode : public AudioNode { protected: bool processAudio(float *audioData, int32_t numFrames) override; - private: - enum class FilterType { - LOWPASS, - HIGHPASS, - BANDPASS, - LOWSHELF, - HIGHSHELF, - PEAKING, - NOTCH, - ALLPASS - }; - - static FilterType fromString(const std::string &type) { - std::string lowerType = type; - std::transform( - lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); - - if (lowerType == "lowpass") - return FilterType::LOWPASS; - if (lowerType == "highpass") - return FilterType::HIGHPASS; - if (lowerType == "bandpass") - return FilterType::BANDPASS; - if (lowerType == "lowshelf") - return FilterType::LOWSHELF; - if (lowerType == "highshelf") - return FilterType::HIGHSHELF; - if (lowerType == "peaking") - return FilterType::PEAKING; - if (lowerType == "notch") - return FilterType::NOTCH; - if (lowerType == "allpass") - return FilterType::ALLPASS; - - throw std::invalid_argument("Invalid filter type: " + type); - } - - static std::string toString(FilterType type) { - switch (type) { - case FilterType::LOWPASS: - return "lowpass"; - case FilterType::HIGHPASS: - return "highpass"; - case FilterType::BANDPASS: - return "bandpass"; - case FilterType::LOWSHELF: - return "lowshelf"; - case FilterType::HIGHSHELF: - return "highshelf"; - case FilterType::PEAKING: - return "peaking"; - case FilterType::NOTCH: - return "notch"; - case FilterType::ALLPASS: - return "allpass"; - default: - throw std::invalid_argument("Unknown filter type"); - } - } - private: std::shared_ptr frequencyParam_; std::shared_ptr detuneParam_; std::shared_ptr QParam_; std::shared_ptr gainParam_; - FilterType type_; + audioapi::BiquadFilterType type_; // delayed samples float x1_ = 0; @@ -111,6 +52,54 @@ class BiquadFilterNode : public AudioNode { float a1_ = 1.0; float a2_ = 0; + static BiquadFilterType fromString(const std::string &type) { + std::string lowerType = type; + std::transform( + lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); + + if (lowerType == "lowpass") + return BiquadFilterType::LOWPASS; + if (lowerType == "highpass") + return BiquadFilterType::HIGHPASS; + if (lowerType == "bandpass") + return BiquadFilterType::BANDPASS; + if (lowerType == "lowshelf") + return BiquadFilterType::LOWSHELF; + if (lowerType == "highshelf") + return BiquadFilterType::HIGHSHELF; + if (lowerType == "peaking") + return BiquadFilterType::PEAKING; + if (lowerType == "notch") + return BiquadFilterType::NOTCH; + if (lowerType == "allpass") + return BiquadFilterType::ALLPASS; + + throw std::invalid_argument("Invalid filter type: " + type); + } + + static std::string toString(BiquadFilterType type) { + switch (type) { + case BiquadFilterType::LOWPASS: + return "lowpass"; + case BiquadFilterType::HIGHPASS: + return "highpass"; + case BiquadFilterType::BANDPASS: + return "bandpass"; + case BiquadFilterType::LOWSHELF: + return "lowshelf"; + case BiquadFilterType::HIGHSHELF: + return "highshelf"; + case BiquadFilterType::PEAKING: + return "peaking"; + case BiquadFilterType::NOTCH: + return "notch"; + case BiquadFilterType::ALLPASS: + return "allpass"; + default: + throw std::invalid_argument("Unknown filter type"); + } + } + void resetCoefficients(); void setNormalizedCoefficients( float b0, diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h index b9688ff3..c9ee4ad2 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h @@ -6,6 +6,7 @@ #include "AudioParam.h" #include "AudioScheduledSourceNode.h" +#include "OscillatorType.h" namespace audioapi { @@ -22,7 +23,6 @@ class OscillatorNode : public AudioScheduledSourceNode { bool processAudio(float *audioData, int32_t numFrames) override; private: - enum class WaveType { SINE, SQUARE, SAWTOOTH, TRIANGLE, CUSTOM }; static float sineWave(double wavePhase) { return static_cast(std::sin(wavePhase)); @@ -48,65 +48,61 @@ class OscillatorNode : public AudioScheduledSourceNode { 1.0); } - static float getWaveValue(double wavePhase, WaveType type) { - switch (type) { - case WaveType::SINE: - return sineWave(wavePhase); - case WaveType::SQUARE: - return squareWave(wavePhase); - case WaveType::SAWTOOTH: - return sawtoothWave(wavePhase); - case WaveType::TRIANGLE: - return triangleWave(wavePhase); - default: - throw std::invalid_argument("Unknown wave type"); - } - } - - static WaveType fromString(const std::string &type) { - std::string lowerType = type; - std::transform( - lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); - - if (lowerType == "sine") - return WaveType::SINE; - if (lowerType == "square") - return WaveType::SQUARE; - if (lowerType == "sawtooth") - return WaveType::SAWTOOTH; - if (lowerType == "triangle") - return WaveType::TRIANGLE; - if (lowerType == "custom") - return WaveType::CUSTOM; - - throw std::invalid_argument("Unknown wave type: " + type); - } - - static std::string toString(WaveType type) { - switch (type) { - case WaveType::SINE: - return "sine"; - case WaveType::SQUARE: - return "square"; - case WaveType::SAWTOOTH: - return "sawtooth"; - case WaveType::TRIANGLE: - return "triangle"; - case WaveType::CUSTOM: - return "custom"; - default: - throw std::invalid_argument("Unknown wave type"); - } - } - - static float getWaveBufferElement(double wavePhase, WaveType waveType) { - return getWaveValue(wavePhase, waveType); + static float getWaveBufferElement(double wavePhase,OscillatorType type) { + switch (type) { + case OscillatorType::SINE: + return sineWave(wavePhase); + case OscillatorType::SQUARE: + return squareWave(wavePhase); + case OscillatorType::SAWTOOTH: + return sawtoothWave(wavePhase); + case OscillatorType::TRIANGLE: + return triangleWave(wavePhase); + default: + throw std::invalid_argument("Unknown wave type"); + } } private: std::shared_ptr frequencyParam_; std::shared_ptr detuneParam_; - WaveType type_ = WaveType::SINE; + OscillatorType type_ = OscillatorType::SINE; float phase_ = 0.0; + + static OscillatorType fromString(const std::string &type) { + std::string lowerType = type; + std::transform( + lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); + + if (lowerType == "sine") + return OscillatorType::SINE; + if (lowerType == "square") + return OscillatorType::SQUARE; + if (lowerType == "sawtooth") + return OscillatorType::SAWTOOTH; + if (lowerType == "triangle") + return OscillatorType::TRIANGLE; + if (lowerType == "custom") + return OscillatorType::CUSTOM; + + throw std::invalid_argument("Unknown oscillator type: " + type); + } + + static std::string toString(OscillatorType type) { + switch (type) { + case OscillatorType::SINE: + return "sine"; + case OscillatorType::SQUARE: + return "square"; + case OscillatorType::SAWTOOTH: + return "sawtooth"; + case OscillatorType::TRIANGLE: + return "triangle"; + case OscillatorType::CUSTOM: + return "custom"; + default: + throw std::invalid_argument("Unknown oscillator type"); + } + } }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h new file mode 100644 index 00000000..90ab7dae --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include + +namespace audioapi { + +enum class BiquadFilterType { + LOWPASS, + HIGHPASS, + BANDPASS, + LOWSHELF, + HIGHSHELF, + PEAKING, + NOTCH, + ALLPASS +}; + +} diff --git a/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h b/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h new file mode 100644 index 00000000..8cead63a --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace audioapi { + + enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT }; + +} diff --git a/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h b/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h new file mode 100644 index 00000000..fbfdfa2d --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace audioapi { + + enum class ChannelInterpretation { SPEAKERS, DISCRETE }; + +} diff --git a/packages/react-native-audio-api/common/cpp/types/ContextState.h b/packages/react-native-audio-api/common/cpp/types/ContextState.h new file mode 100644 index 00000000..e677a09a --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/types/ContextState.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace audioapi { + + enum class ContextState { SUSPENDED, RUNNING, CLOSED }; + +} diff --git a/packages/react-native-audio-api/common/cpp/types/OscillatorType.h b/packages/react-native-audio-api/common/cpp/types/OscillatorType.h new file mode 100644 index 00000000..6198a91e --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/types/OscillatorType.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace audioapi { + + enum class OscillatorType { + SINE, + SQUARE, + SAWTOOTH, + TRIANGLE, + CUSTOM + }; + +} // namespace audioapi diff --git a/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts b/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts index 09817403..59e04cae 100644 --- a/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts +++ b/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts @@ -21,6 +21,8 @@ export default class AudioScheduledSourceNode extends AudioNode { throw new InvalidStateError('Cannot call start more than once'); } + this.hasBeenStarted = true; + (this.node as IAudioScheduledSourceNode).start(when); } diff --git a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts b/packages/react-native-audio-api/src/core/BiquadFilterNode.ts index 1a512a4f..1bb303c0 100644 --- a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts +++ b/packages/react-native-audio-api/src/core/BiquadFilterNode.ts @@ -3,7 +3,7 @@ import { IBiquadFilterNode } from '../interfaces'; import AudioNode from './AudioNode'; import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; -import { FilterType } from './types'; +import { BiquadFilterType } from './types'; export default class BiquadFilterNode extends AudioNode { readonly frequency: AudioParam; @@ -19,11 +19,11 @@ export default class BiquadFilterNode extends AudioNode { this.gain = new AudioParam(biquadFilter.gain); } - public get type(): FilterType { + public get type(): BiquadFilterType { return (this.node as IBiquadFilterNode).type; } - public set type(value: FilterType) { + public set type(value: BiquadFilterType) { (this.node as IBiquadFilterNode).type = value; } diff --git a/packages/react-native-audio-api/src/core/OscillatorNode.ts b/packages/react-native-audio-api/src/core/OscillatorNode.ts index adbab645..f74fbb2b 100644 --- a/packages/react-native-audio-api/src/core/OscillatorNode.ts +++ b/packages/react-native-audio-api/src/core/OscillatorNode.ts @@ -1,5 +1,5 @@ import { IOscillatorNode } from '../interfaces'; -import { WaveType } from './types'; +import { OscillatorType } from './types'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; @@ -15,11 +15,11 @@ export default class OscillatorNode extends AudioScheduledSourceNode { this.type = node.type; } - public get type(): WaveType { + public get type(): OscillatorType { return (this.node as IOscillatorNode).type; } - public set type(value: WaveType) { + public set type(value: OscillatorType) { (this.node as IOscillatorNode).type = value; } } diff --git a/packages/react-native-audio-api/src/core/types.ts b/packages/react-native-audio-api/src/core/types.ts index 4d750601..bfa4dbaa 100644 --- a/packages/react-native-audio-api/src/core/types.ts +++ b/packages/react-native-audio-api/src/core/types.ts @@ -2,7 +2,7 @@ export type ChannelCountMode = 'max' | 'clamped-max' | 'explicit'; export type ChannelInterpretation = 'speakers' | 'discrete'; -export type FilterType = +export type BiquadFilterType = | 'lowpass' | 'highpass' | 'bandpass' @@ -14,4 +14,4 @@ export type FilterType = export type ContextState = 'running' | 'closed'; -export type WaveType = 'sine' | 'square' | 'sawtooth' | 'triangle'; +export type OscillatorType = 'sine' | 'square' | 'sawtooth' | 'triangle'; diff --git a/packages/react-native-audio-api/src/index.ts b/packages/react-native-audio-api/src/index.ts index b89a73ee..e276dfde 100644 --- a/packages/react-native-audio-api/src/index.ts +++ b/packages/react-native-audio-api/src/index.ts @@ -17,8 +17,8 @@ export { default as GainNode } from './core/GainNode'; export { default as OscillatorNode } from './core/OscillatorNode'; export { default as StereoPannerNode } from './core/StereoPannerNode'; export { - WaveType, - FilterType, + OscillatorType, + BiquadFilterType, ChannelCountMode, ChannelInterpretation, ContextState, diff --git a/packages/react-native-audio-api/src/interfaces.ts b/packages/react-native-audio-api/src/interfaces.ts index 696ee52a..f1511038 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/interfaces.ts @@ -1,7 +1,7 @@ import { ContextState, - FilterType, - WaveType, + BiquadFilterType, + OscillatorType, ChannelCountMode, ChannelInterpretation, } from './core/types'; @@ -51,7 +51,7 @@ export interface IBiquadFilterNode extends IAudioNode { readonly detune: AudioParam; readonly Q: AudioParam; readonly gain: AudioParam; - type: FilterType; + type: BiquadFilterType; getFrequencyResponse( frequencyArray: number[], magResponseOutput: number[], @@ -69,7 +69,7 @@ export interface IAudioScheduledSourceNode extends IAudioNode { export interface IOscillatorNode extends IAudioScheduledSourceNode { readonly frequency: IAudioParam; readonly detune: IAudioParam; - type: WaveType; + type: OscillatorType; } export interface IAudioBufferSourceNode extends IAudioScheduledSourceNode { From 1b5807177d9b0d131d82ddcccff1aff0dfba701d Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 7 Nov 2024 17:44:04 +0100 Subject: [PATCH 04/35] feat: declared different constructor of PeriodicWave --- .../common/cpp/core/PeriodicWave.cpp | 73 +++++++++++++++++++ .../common/cpp/core/PeriodicWave.h | 54 +++++++++++++- 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index f8bc5fa0..08073e48 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -1 +1,74 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "PeriodicWave.h" + +// The number of bands per octave. Each octave will have this many entries in the wave tables. +constexpr unsigned NumberOfOctaveBands = 3; + +constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands; + +namespace audioapi { + PeriodicWave::PeriodicWave(int sampleRate): sampleRate_(sampleRate) { + numberOfRanges_ = lround(NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); + auto nyquistFrequency = sampleRate_ / 2; + lowestFundamentalFrequency_ = static_cast(nyquistFrequency) / static_cast(getMaxNumberOfPartials()); + rateScale_ = static_cast(getPeriodicWaveSize()) / static_cast(sampleRate_); + waveTable_ = new float[getPeriodicWaveSize()]; + } + + PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type): PeriodicWave(sampleRate) { + //get waveTable for type + } + + PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary): PeriodicWave(sampleRate) { + //get waveTable for real and imaginary + } + + int PeriodicWave::getPeriodicWaveSize() const { + if(sampleRate_ <= 24000) { + return 2048; + } + + if(sampleRate_ <= 88200) { + return 4096; + } + + return 16384; + } + + void PeriodicWave::generateBasicWaveForm(OscillatorType type) { + auto n = getPeriodicWaveSize(); + + + } + + int PeriodicWave::getMaxNumberOfPartials() const { + return getPeriodicWaveSize() / 2; + } +} diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index b5975ad0..0b2bdb73 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -1,18 +1,64 @@ +/* +* Copyright (C) 2012 Google Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of Apple Inc. ("Apple") nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #pragma once +#include +#include + +#include "OscillatorType.h" + namespace audioapi { class PeriodicWave { + public: + explicit PeriodicWave(int sampleRate, OscillatorType type); + explicit PeriodicWave(int sampleRate, float *real, float *imaginary); + + int getPeriodicWaveSize() const; private: - explicit PeriodicWave(unsigned sampleRate); + explicit PeriodicWave(int sampleRate); + + int getMaxNumberOfPartials() const; + + void generateBasicWaveForm(OscillatorType type); // determines the time resolution of the waveform. - unsigned sampleRate_; + int sampleRate_; // determines number of frequency segments (or bands) the signal is divided. - unsigned numberOfRanges_; + int numberOfRanges_; // the lowest frequency (in hertz) where playback will include all of the partials. - float lowestFundamentalFrequency; + float lowestFundamentalFrequency_; // scaling factor used to adjust size of period of waveform to the sample rate. float rateScale_; + + float *waveTable_; + //float **bandLimitedTables_; + }; } // namespace audioapi From e5d5ea59a4aa4aff8d437658b3d622a22225d794 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 7 Nov 2024 17:47:47 +0100 Subject: [PATCH 05/35] ci: yarn format --- .../common/cpp/core/AudioNode.h | 42 ++++---- .../common/cpp/core/BaseAudioContext.h | 26 ++--- .../common/cpp/core/BiquadFilterNode.cpp | 2 +- .../common/cpp/core/BiquadFilterNode.h | 86 ++++++++--------- .../common/cpp/core/OscillatorNode.h | 93 +++++++++--------- .../common/cpp/core/PeriodicWave.cpp | 66 +++++++------ .../common/cpp/core/PeriodicWave.h | 95 ++++++++++--------- .../common/cpp/types/BiquadFilterType.h | 18 ++-- .../common/cpp/types/ChannelCountMode.h | 2 +- .../common/cpp/types/ChannelInterpretation.h | 2 +- .../common/cpp/types/ContextState.h | 2 +- .../common/cpp/types/OscillatorType.h | 10 +- 12 files changed, 221 insertions(+), 223 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/AudioNode.h b/packages/react-native-audio-api/common/cpp/core/AudioNode.h index 8be8ce42..0b331dc2 100644 --- a/packages/react-native-audio-api/common/cpp/core/AudioNode.h +++ b/packages/react-native-audio-api/common/cpp/core/AudioNode.h @@ -3,9 +3,9 @@ #include #include #include -#include "Constants.h" #include "ChannelCountMode.h" #include "ChannelInterpretation.h" +#include "Constants.h" // channelCount always equal to 2 @@ -41,29 +41,29 @@ class AudioNode : public std::enable_shared_from_this { std::vector> outputNodes_ = {}; private: - static std::string toString(ChannelCountMode mode) { - switch (mode) { - case ChannelCountMode::MAX: - return "max"; - case ChannelCountMode::CLAMPED_MAX: - return "clamped-max"; - case ChannelCountMode::EXPLICIT: - return "explicit"; - default: - throw std::invalid_argument("Unknown channel count mode"); - } + static std::string toString(ChannelCountMode mode) { + switch (mode) { + case ChannelCountMode::MAX: + return "max"; + case ChannelCountMode::CLAMPED_MAX: + return "clamped-max"; + case ChannelCountMode::EXPLICIT: + return "explicit"; + default: + throw std::invalid_argument("Unknown channel count mode"); } + } - static std::string toString(ChannelInterpretation interpretation) { - switch (interpretation) { - case ChannelInterpretation::SPEAKERS: - return "speakers"; - case ChannelInterpretation::DISCRETE: - return "discrete"; - default: - throw std::invalid_argument("Unknown channel interpretation"); - } + static std::string toString(ChannelInterpretation interpretation) { + switch (interpretation) { + case ChannelInterpretation::SPEAKERS: + return "speakers"; + case ChannelInterpretation::DISCRETE: + return "discrete"; + default: + throw std::invalid_argument("Unknown channel interpretation"); } + } void cleanup(); }; diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h index 9af2570c..b01adac6 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h @@ -12,10 +12,10 @@ #include "AudioScheduledSourceNode.h" #include "BiquadFilterNode.h" #include "Constants.h" +#include "ContextState.h" #include "GainNode.h" #include "OscillatorNode.h" #include "StereoPannerNode.h" -#include "ContextState.h" #ifdef ANDROID #include "AudioPlayer.h" @@ -53,19 +53,19 @@ class BaseAudioContext { int sampleRate_; double contextStartTime_; -private: - static std::string toString(ContextState state) { - switch (state) { - case ContextState::SUSPENDED: - return "suspended"; - case ContextState::RUNNING: - return "running"; - case ContextState::CLOSED: - return "closed"; - default: - throw std::invalid_argument("Unknown context state"); - } + private: + static std::string toString(ContextState state) { + switch (state) { + case ContextState::SUSPENDED: + return "suspended"; + case ContextState::RUNNING: + return "running"; + case ContextState::CLOSED: + return "closed"; + default: + throw std::invalid_argument("Unknown context state"); } + } }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp index 8592687a..e658b70c 100644 --- a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp @@ -340,7 +340,7 @@ void BiquadFilterNode::applyFilter() { setNotchCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; - case BiquadFilterType::ALLPASS: + case BiquadFilterType::ALLPASS: setAllpassCoefficients( normalizedFrequency, QParam_->getValueAtTime(currentTime)); break; diff --git a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h index a413772b..ac55d1da 100644 --- a/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h +++ b/packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.h @@ -52,53 +52,53 @@ class BiquadFilterNode : public AudioNode { float a1_ = 1.0; float a2_ = 0; - static BiquadFilterType fromString(const std::string &type) { - std::string lowerType = type; - std::transform( - lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); + static BiquadFilterType fromString(const std::string &type) { + std::string lowerType = type; + std::transform( + lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); - if (lowerType == "lowpass") - return BiquadFilterType::LOWPASS; - if (lowerType == "highpass") - return BiquadFilterType::HIGHPASS; - if (lowerType == "bandpass") - return BiquadFilterType::BANDPASS; - if (lowerType == "lowshelf") - return BiquadFilterType::LOWSHELF; - if (lowerType == "highshelf") - return BiquadFilterType::HIGHSHELF; - if (lowerType == "peaking") - return BiquadFilterType::PEAKING; - if (lowerType == "notch") - return BiquadFilterType::NOTCH; - if (lowerType == "allpass") - return BiquadFilterType::ALLPASS; + if (lowerType == "lowpass") + return BiquadFilterType::LOWPASS; + if (lowerType == "highpass") + return BiquadFilterType::HIGHPASS; + if (lowerType == "bandpass") + return BiquadFilterType::BANDPASS; + if (lowerType == "lowshelf") + return BiquadFilterType::LOWSHELF; + if (lowerType == "highshelf") + return BiquadFilterType::HIGHSHELF; + if (lowerType == "peaking") + return BiquadFilterType::PEAKING; + if (lowerType == "notch") + return BiquadFilterType::NOTCH; + if (lowerType == "allpass") + return BiquadFilterType::ALLPASS; - throw std::invalid_argument("Invalid filter type: " + type); - } + throw std::invalid_argument("Invalid filter type: " + type); + } - static std::string toString(BiquadFilterType type) { - switch (type) { - case BiquadFilterType::LOWPASS: - return "lowpass"; - case BiquadFilterType::HIGHPASS: - return "highpass"; - case BiquadFilterType::BANDPASS: - return "bandpass"; - case BiquadFilterType::LOWSHELF: - return "lowshelf"; - case BiquadFilterType::HIGHSHELF: - return "highshelf"; - case BiquadFilterType::PEAKING: - return "peaking"; - case BiquadFilterType::NOTCH: - return "notch"; - case BiquadFilterType::ALLPASS: - return "allpass"; - default: - throw std::invalid_argument("Unknown filter type"); - } + static std::string toString(BiquadFilterType type) { + switch (type) { + case BiquadFilterType::LOWPASS: + return "lowpass"; + case BiquadFilterType::HIGHPASS: + return "highpass"; + case BiquadFilterType::BANDPASS: + return "bandpass"; + case BiquadFilterType::LOWSHELF: + return "lowshelf"; + case BiquadFilterType::HIGHSHELF: + return "highshelf"; + case BiquadFilterType::PEAKING: + return "peaking"; + case BiquadFilterType::NOTCH: + return "notch"; + case BiquadFilterType::ALLPASS: + return "allpass"; + default: + throw std::invalid_argument("Unknown filter type"); } + } void resetCoefficients(); void setNormalizedCoefficients( diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h index c9ee4ad2..17776288 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h @@ -23,7 +23,6 @@ class OscillatorNode : public AudioScheduledSourceNode { bool processAudio(float *audioData, int32_t numFrames) override; private: - static float sineWave(double wavePhase) { return static_cast(std::sin(wavePhase)); } @@ -48,19 +47,19 @@ class OscillatorNode : public AudioScheduledSourceNode { 1.0); } - static float getWaveBufferElement(double wavePhase,OscillatorType type) { - switch (type) { - case OscillatorType::SINE: - return sineWave(wavePhase); - case OscillatorType::SQUARE: - return squareWave(wavePhase); - case OscillatorType::SAWTOOTH: - return sawtoothWave(wavePhase); - case OscillatorType::TRIANGLE: - return triangleWave(wavePhase); - default: - throw std::invalid_argument("Unknown wave type"); - } + static float getWaveBufferElement(double wavePhase, OscillatorType type) { + switch (type) { + case OscillatorType::SINE: + return sineWave(wavePhase); + case OscillatorType::SQUARE: + return squareWave(wavePhase); + case OscillatorType::SAWTOOTH: + return sawtoothWave(wavePhase); + case OscillatorType::TRIANGLE: + return triangleWave(wavePhase); + default: + throw std::invalid_argument("Unknown wave type"); + } } private: @@ -69,40 +68,40 @@ class OscillatorNode : public AudioScheduledSourceNode { OscillatorType type_ = OscillatorType::SINE; float phase_ = 0.0; - static OscillatorType fromString(const std::string &type) { - std::string lowerType = type; - std::transform( - lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); - - if (lowerType == "sine") - return OscillatorType::SINE; - if (lowerType == "square") - return OscillatorType::SQUARE; - if (lowerType == "sawtooth") - return OscillatorType::SAWTOOTH; - if (lowerType == "triangle") - return OscillatorType::TRIANGLE; - if (lowerType == "custom") - return OscillatorType::CUSTOM; - - throw std::invalid_argument("Unknown oscillator type: " + type); - } + static OscillatorType fromString(const std::string &type) { + std::string lowerType = type; + std::transform( + lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower); + + if (lowerType == "sine") + return OscillatorType::SINE; + if (lowerType == "square") + return OscillatorType::SQUARE; + if (lowerType == "sawtooth") + return OscillatorType::SAWTOOTH; + if (lowerType == "triangle") + return OscillatorType::TRIANGLE; + if (lowerType == "custom") + return OscillatorType::CUSTOM; + + throw std::invalid_argument("Unknown oscillator type: " + type); + } - static std::string toString(OscillatorType type) { - switch (type) { - case OscillatorType::SINE: - return "sine"; - case OscillatorType::SQUARE: - return "square"; - case OscillatorType::SAWTOOTH: - return "sawtooth"; - case OscillatorType::TRIANGLE: - return "triangle"; - case OscillatorType::CUSTOM: - return "custom"; - default: - throw std::invalid_argument("Unknown oscillator type"); - } + static std::string toString(OscillatorType type) { + switch (type) { + case OscillatorType::SINE: + return "sine"; + case OscillatorType::SQUARE: + return "square"; + case OscillatorType::SAWTOOTH: + return "sawtooth"; + case OscillatorType::TRIANGLE: + return "triangle"; + case OscillatorType::CUSTOM: + return "custom"; + default: + throw std::invalid_argument("Unknown oscillator type"); } + } }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 08073e48..3ad68011 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -28,47 +28,51 @@ #include "PeriodicWave.h" -// The number of bands per octave. Each octave will have this many entries in the wave tables. +// The number of bands per octave. Each octave will have this many entries in +// the wave tables. constexpr unsigned NumberOfOctaveBands = 3; constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands; namespace audioapi { - PeriodicWave::PeriodicWave(int sampleRate): sampleRate_(sampleRate) { - numberOfRanges_ = lround(NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); - auto nyquistFrequency = sampleRate_ / 2; - lowestFundamentalFrequency_ = static_cast(nyquistFrequency) / static_cast(getMaxNumberOfPartials()); - rateScale_ = static_cast(getPeriodicWaveSize()) / static_cast(sampleRate_); - waveTable_ = new float[getPeriodicWaveSize()]; - } - - PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type): PeriodicWave(sampleRate) { - //get waveTable for type - } +PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { + numberOfRanges_ = lround( + NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); + auto nyquistFrequency = sampleRate_ / 2; + lowestFundamentalFrequency_ = static_cast(nyquistFrequency) / + static_cast(getMaxNumberOfPartials()); + rateScale_ = static_cast(getPeriodicWaveSize()) / + static_cast(sampleRate_); + waveTable_ = new float[getPeriodicWaveSize()]; +} - PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary): PeriodicWave(sampleRate) { - //get waveTable for real and imaginary - } +PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type) + : PeriodicWave(sampleRate) { + // get waveTable for type +} - int PeriodicWave::getPeriodicWaveSize() const { - if(sampleRate_ <= 24000) { - return 2048; - } +PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary) + : PeriodicWave(sampleRate) { + // get waveTable for real and imaginary +} - if(sampleRate_ <= 88200) { - return 4096; - } +int PeriodicWave::getPeriodicWaveSize() const { + if (sampleRate_ <= 24000) { + return 2048; + } - return 16384; - } + if (sampleRate_ <= 88200) { + return 4096; + } - void PeriodicWave::generateBasicWaveForm(OscillatorType type) { - auto n = getPeriodicWaveSize(); + return 16384; +} - - } +void PeriodicWave::generateBasicWaveForm(OscillatorType type) { + auto n = getPeriodicWaveSize(); +} - int PeriodicWave::getMaxNumberOfPartials() const { - return getPeriodicWaveSize() / 2; - } +int PeriodicWave::getMaxNumberOfPartials() const { + return getPeriodicWaveSize() / 2; } +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 0b2bdb73..55d868fb 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -1,30 +1,30 @@ /* -* Copyright (C) 2012 Google Inc. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of Apple Inc. ("Apple") nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #pragma once @@ -34,31 +34,32 @@ #include "OscillatorType.h" namespace audioapi { - class PeriodicWave { - public: - explicit PeriodicWave(int sampleRate, OscillatorType type); - explicit PeriodicWave(int sampleRate, float *real, float *imaginary); +class PeriodicWave { + public: + explicit PeriodicWave(int sampleRate, OscillatorType type); + explicit PeriodicWave(int sampleRate, float *real, float *imaginary); - int getPeriodicWaveSize() const; + int getPeriodicWaveSize() const; - private: - explicit PeriodicWave(int sampleRate); + private: + explicit PeriodicWave(int sampleRate); - int getMaxNumberOfPartials() const; + int getMaxNumberOfPartials() const; - void generateBasicWaveForm(OscillatorType type); + void generateBasicWaveForm(OscillatorType type); - // determines the time resolution of the waveform. - int sampleRate_; - // determines number of frequency segments (or bands) the signal is divided. - int numberOfRanges_; - // the lowest frequency (in hertz) where playback will include all of the partials. - float lowestFundamentalFrequency_; - // scaling factor used to adjust size of period of waveform to the sample rate. - float rateScale_; + // determines the time resolution of the waveform. + int sampleRate_; + // determines number of frequency segments (or bands) the signal is divided. + int numberOfRanges_; + // the lowest frequency (in hertz) where playback will include all of the + // partials. + float lowestFundamentalFrequency_; + // scaling factor used to adjust size of period of waveform to the sample + // rate. + float rateScale_; - float *waveTable_; - //float **bandLimitedTables_; - - }; + float *waveTable_; + // float **bandLimitedTables_; +}; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h index 90ab7dae..d9401584 100644 --- a/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h +++ b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h @@ -1,20 +1,20 @@ #pragma once +#include #include #include -#include namespace audioapi { enum class BiquadFilterType { - LOWPASS, - HIGHPASS, - BANDPASS, - LOWSHELF, - HIGHSHELF, - PEAKING, - NOTCH, - ALLPASS + LOWPASS, + HIGHPASS, + BANDPASS, + LOWSHELF, + HIGHSHELF, + PEAKING, + NOTCH, + ALLPASS }; } diff --git a/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h b/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h index 8cead63a..e2b54975 100644 --- a/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h +++ b/packages/react-native-audio-api/common/cpp/types/ChannelCountMode.h @@ -5,6 +5,6 @@ namespace audioapi { - enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT }; +enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT }; } diff --git a/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h b/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h index fbfdfa2d..244d17ec 100644 --- a/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h +++ b/packages/react-native-audio-api/common/cpp/types/ChannelInterpretation.h @@ -5,6 +5,6 @@ namespace audioapi { - enum class ChannelInterpretation { SPEAKERS, DISCRETE }; +enum class ChannelInterpretation { SPEAKERS, DISCRETE }; } diff --git a/packages/react-native-audio-api/common/cpp/types/ContextState.h b/packages/react-native-audio-api/common/cpp/types/ContextState.h index e677a09a..3dd6806f 100644 --- a/packages/react-native-audio-api/common/cpp/types/ContextState.h +++ b/packages/react-native-audio-api/common/cpp/types/ContextState.h @@ -5,6 +5,6 @@ namespace audioapi { - enum class ContextState { SUSPENDED, RUNNING, CLOSED }; +enum class ContextState { SUSPENDED, RUNNING, CLOSED }; } diff --git a/packages/react-native-audio-api/common/cpp/types/OscillatorType.h b/packages/react-native-audio-api/common/cpp/types/OscillatorType.h index 6198a91e..6dccb995 100644 --- a/packages/react-native-audio-api/common/cpp/types/OscillatorType.h +++ b/packages/react-native-audio-api/common/cpp/types/OscillatorType.h @@ -1,17 +1,11 @@ #pragma once +#include #include #include -#include namespace audioapi { - enum class OscillatorType { - SINE, - SQUARE, - SAWTOOTH, - TRIANGLE, - CUSTOM - }; +enum class OscillatorType { SINE, SQUARE, SAWTOOTH, TRIANGLE, CUSTOM }; } // namespace audioapi From daa2387fb44aef660c327a42fe03a5e9ef18551f Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 8 Nov 2024 16:32:17 +0100 Subject: [PATCH 06/35] feat: added generating coeffs for basic wave forms function --- .../common/cpp/core/PeriodicWave.cpp | 66 ++++++++++++++++++- .../common/cpp/core/PeriodicWave.h | 4 +- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 3ad68011..23eb3c57 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -69,7 +69,71 @@ int PeriodicWave::getPeriodicWaveSize() const { } void PeriodicWave::generateBasicWaveForm(OscillatorType type) { - auto n = getPeriodicWaveSize(); + auto fftSize = getPeriodicWaveSize(); + /* + * For real-valued time-domain signals, the FFT outputs a Hermitian symmetric sequence + * (where the positive frequencies are the complex conjugate of the negative ones). + * This symmetry implies that real signals have mirrored frequency components. + * In such scenarios, all 'real' frequency information is contained in the first half of the transform, + * and altering parts such as real and imag can finely shape which harmonic content is retained or discarded. + */ + auto halfSize = fftSize / 2; + + auto *real = new float[halfSize]; + auto *imaginary = new float[halfSize]; + + // Reset Direct Current (DC) component. First element of frequency domain representation - c0. + // https://math24.net/complex-form-fourier-series.html + real[0] = 0.0f; + imaginary[0] = 0.0f; + + if (type == OscillatorType::SAWTOOTH) { + real[0] = 1.0f; + } + + for(int i = 1; i < halfSize; i++) { + // All waveforms are odd functions with a positive slope at time 0. + // Hence the coefficients for cos() are always 0. + + // Formulas for Fourier coefficients: + // https://mathworld.wolfram.com/FourierSeries.html + + // Coefficient for sin() + float b; + + auto piFactor = static_cast(1.0f / (i * M_PI)); + + switch(type) { + case OscillatorType::SINE: + b = (i == 1) ? 1.0f : 0.0f; + break; + + case OscillatorType::SQUARE: + // https://mathworld.wolfram.com/FourierSeriesSquareWave.html + b = (i % 2 == 1) ? 4 * piFactor : 0.0f; + break; + case OscillatorType::SAWTOOTH: + // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html + b = - piFactor; + break; + case OscillatorType::TRIANGLE: + // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html + if (i % 2 == 1) { + b = 8.0f * piFactor * piFactor * (i % 4 == 1 ? 1.0f : -1.0f); + } else { + b = 0.0f; + } + break; + case OscillatorType::CUSTOM: + throw std::invalid_argument("Custom waveforms are not supported."); + } + + real[i] = 0.0f; + imaginary[i] = b; + } + + // call creating waveTable from real and imaginary + // createBandLimitedTables(real, imaginary, halfSize); } int PeriodicWave::getMaxNumberOfPartials() const { diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 55d868fb..4a2b6873 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -39,12 +39,12 @@ class PeriodicWave { explicit PeriodicWave(int sampleRate, OscillatorType type); explicit PeriodicWave(int sampleRate, float *real, float *imaginary); - int getPeriodicWaveSize() const; + [[nodiscard]] int getPeriodicWaveSize() const; private: explicit PeriodicWave(int sampleRate); - int getMaxNumberOfPartials() const; + [[nodiscard]] int getMaxNumberOfPartials() const; void generateBasicWaveForm(OscillatorType type); From 8165ba4bcdb92a52548109fd6e7587a0a649275e Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Wed, 13 Nov 2024 17:01:17 +0100 Subject: [PATCH 07/35] feat: added fft implementation for ios --- .../common/cpp/utils/FFTFrame.cpp | 36 +++++++++++ .../common/cpp/utils/FFTFrame.h | 64 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp create mode 100644 packages/react-native-audio-api/common/cpp/utils/FFTFrame.h diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp new file mode 100644 index 00000000..2868effc --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -0,0 +1,36 @@ +#include "FFTFrame.h" + +namespace audioapi { + FFTFrame::FFTFrame(int size) { + size_ = size; + log2Size_ = static_cast(log2(size)); + realData_ = new float[size]; + imaginaryData_ = new float[size]; + #if defined(HAVE_ACCELERATE) + fftSetup_ = vDSP_create_fftsetup(log2Size_, FFT_RADIX2); + frame_.realp = realData_; + frame_.imagp = imaginaryData_; + #endif + } + +#if defined(HAVE_ACCELERATE) + void FFTFrame::forward(float *data) { + vDSP_ctoz(reinterpret_cast(data), 2, &frame_, 1, size_ / 2); + vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_FORWARD); + + // Scale the FFT data, beacuse of + // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 + VectorMath::multiplyByScalar(realData_, 0.5f, realData_, halfSize); + VectorMath::multiplyByScalar(imaginaryData_, 0.5f, imaginaryData_, halfSize); + } + + void FFTFrame::inverse(float *data) { + vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE); + vDSP_ztoc(&frame_, 1, (DSPComplex*)data, 2, size_ / 2); + + // Scale the FFT data, beacuse of + // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 + VectorMath::multiplyByScalar(data, 1.0f / static_cast(size_), data, size_); + } +#endif +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h new file mode 100644 index 00000000..c3e107a4 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if defined(HAVE_ACCELERATE) +#include +#endif + +#include + +namespace audioapi { + +class FFTFrame { + +public: + FFTFrame(int size); + FFTFrame(const FFTFrame& frame); + ~FFTFrame(); + + float *getRealData() const { return realData_; } + float *getImaginaryData() const { return imaginaryData_; } + + void forward(float *data); + void inverse(float *data); + +private: + int size_; + int log2Size_; + float *realData_; + float *imaginaryData_; + +#if defined(HAVE_ACCELERATE) + FFTSetup fftSetup_; + DSPSplitComplex frame_; +#endif +}; + +} // namespace audioapi From 7767c6cc0935c630c90b90654451b4a418122cb7 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Wed, 13 Nov 2024 17:01:45 +0100 Subject: [PATCH 08/35] feat: added creating band limited tables --- apps/fabric-example/ios/Podfile.lock | 4 +- .../common/cpp/core/PeriodicWave.cpp | 81 +++++++++++++++---- .../common/cpp/core/PeriodicWave.h | 9 ++- 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/apps/fabric-example/ios/Podfile.lock b/apps/fabric-example/ios/Podfile.lock index 5d32f569..827e612c 100644 --- a/apps/fabric-example/ios/Podfile.lock +++ b/apps/fabric-example/ios/Podfile.lock @@ -2063,8 +2063,8 @@ SPEC CHECKSUMS: RNReanimated: 77242c6d67416988a2fd9f5cf574bb3e60016362 RNScreens: e389d6a6a66a4f0d3662924ecae803073ccce8ec SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: 1d66db49f38fd9e576a1d7c3b081e46ab4c28b9e + Yoga: f8ec45ce98bba1bc93dd28f2ee37215180e6d2b6 PODFILE CHECKSUM: 75ad38075e71875257a2590065853ea6a608b897 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 23eb3c57..7a10cb31 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -39,16 +39,19 @@ PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { numberOfRanges_ = lround( NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); auto nyquistFrequency = sampleRate_ / 2; + lowestFundamentalFrequency_ = static_cast(nyquistFrequency) / static_cast(getMaxNumberOfPartials()); + rateScale_ = static_cast(getPeriodicWaveSize()) / static_cast(sampleRate_); - waveTable_ = new float[getPeriodicWaveSize()]; + + bandLimitedTables_ = new float *[numberOfRanges_]; } PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type) : PeriodicWave(sampleRate) { - // get waveTable for type + this->generateBasicWaveForm(type); } PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary) @@ -68,6 +71,26 @@ int PeriodicWave::getPeriodicWaveSize() const { return 16384; } +int PeriodicWave::getMaxNumberOfPartials() const { + return getPeriodicWaveSize() / 2; +} + +int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const { + // Number of cents below nyquist where we cull partials. + auto centsToCull = static_cast(rangeIndex) * CentsPerRange; + + // A value from 0 -> 1 representing what fraction of the partials to keep. + auto cullingScale = std::powf(2, -centsToCull / 1200); + + // The very top range will have all the partials culled. + int numberOfPartials = floor(static_cast(getMaxNumberOfPartials()) * cullingScale); + + return numberOfPartials; +} + +// This function generates real and imaginary parts of the waveTable, +// real and imaginary arrays represent the coefficients of the harmonic components in the frequency domain, +// specifically as part of a complex representation used by Fourier Transform methods to describe signals. void PeriodicWave::generateBasicWaveForm(OscillatorType type) { auto fftSize = getPeriodicWaveSize(); /* @@ -87,10 +110,6 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { real[0] = 0.0f; imaginary[0] = 0.0f; - if (type == OscillatorType::SAWTOOTH) { - real[0] = 1.0f; - } - for(int i = 1; i < halfSize; i++) { // All waveforms are odd functions with a positive slope at time 0. // Hence the coefficients for cos() are always 0. @@ -106,15 +125,17 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { switch(type) { case OscillatorType::SINE: b = (i == 1) ? 1.0f : 0.0f; - break; - + break; case OscillatorType::SQUARE: // https://mathworld.wolfram.com/FourierSeriesSquareWave.html b = (i % 2 == 1) ? 4 * piFactor : 0.0f; break; case OscillatorType::SAWTOOTH: - // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - b = - piFactor; + // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our function differs from this one, + // but coefficients calculation looks similar. + // our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) + 0.5))); + // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B + b = 2 * piFactor * (i % 2 == 1 ? 1.0f : -1.0f); break; case OscillatorType::TRIANGLE: // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html @@ -132,11 +153,43 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { imaginary[i] = b; } - // call creating waveTable from real and imaginary - // createBandLimitedTables(real, imaginary, halfSize); + createBandLimitedTables(real, imaginary, halfSize); } -int PeriodicWave::getMaxNumberOfPartials() const { - return getPeriodicWaveSize() / 2; +void PeriodicWave::createBandLimitedTables(const float *realData, const float *imaginaryData, int size) { + auto fftSize = getPeriodicWaveSize(); + auto halfSize = fftSize / 2; + + size = std::min(size, halfSize); + + for(int rangeIndex = 0; rangeIndex < numberOfRanges_; rangeIndex++) { + FFTFrame fftFrame(fftSize); + + auto *realFFTFrameData = fftFrame.getRealData(); + auto *imaginaryFFTFrameData = fftFrame.getImaginaryData(); + + // copy real and imaginary data to the FFT frame and scale it + VectorMath::multiplyByScalar(realData, static_cast(fftSize), realFFTFrameData, size); + VectorMath::multiplyByScalar(imaginaryData, -static_cast(fftSize), imaginaryFFTFrameData, size); + + // Find the starting bin where we should start culling. + // We need to clear out the highest frequencies to band-limit the waveform. + auto numberOfPartials = getNumberOfPartialsPerRange(rangeIndex); + + // Clamp the size to the number of partials. + auto clampedSize = std::min(size, numberOfPartials); + if(clampedSize < halfSize) { + // Zero out the higher frequencies for certain range. + std::fill(realFFTFrameData + clampedSize, realFFTFrameData + halfSize, 0.0f); + std::fill(imaginaryFFTFrameData + clampedSize, imaginaryFFTFrameData + halfSize, 0.0f); + } + + // Zero out the nquist and DC components. + realFFTFrameData[0] = 0.0f; + imaginaryFFTFrameData[0] = 0.0f; + + bandLimitedTables_[rangeIndex] = new float[fftSize]; + fftFrame.inverse(bandLimitedTables_[rangeIndex]); + } } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 4a2b6873..1eee2d40 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -32,6 +32,8 @@ #include #include "OscillatorType.h" +#include "FFTFrame.h" +#include "VectorMath.h" namespace audioapi { class PeriodicWave { @@ -46,8 +48,12 @@ class PeriodicWave { [[nodiscard]] int getMaxNumberOfPartials() const; + [[nodiscard]] int getNumberOfPartialsPerRange(int rangeIndex) const; + void generateBasicWaveForm(OscillatorType type); + void createBandLimitedTables(const float *real, const float *imaginary, int size); + // determines the time resolution of the waveform. int sampleRate_; // determines number of frequency segments (or bands) the signal is divided. @@ -59,7 +65,6 @@ class PeriodicWave { // rate. float rateScale_; - float *waveTable_; - // float **bandLimitedTables_; + float **bandLimitedTables_; }; } // namespace audioapi From 68608c5e9cc716f54ccaff6aa61a19ee4698da3b Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Wed, 13 Nov 2024 17:30:38 +0100 Subject: [PATCH 09/35] feat: defined preprocessor macro for using Accelerate on ios --- apps/fabric-example/ios/Podfile.lock | 2 +- packages/react-native-audio-api/RNAudioAPI.podspec | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/fabric-example/ios/Podfile.lock b/apps/fabric-example/ios/Podfile.lock index 827e612c..4648dbd8 100644 --- a/apps/fabric-example/ios/Podfile.lock +++ b/apps/fabric-example/ios/Podfile.lock @@ -2058,7 +2058,7 @@ SPEC CHECKSUMS: React-utils: d9624101245ebaab39c9f1bd786132da0b4f27ff ReactCodegen: dbfef1fef26f42c900bb1884fa149d49d501d64d ReactCommon: 429ca28cd813c31359c73ffac6dc24f93347d522 - RNAudioAPI: c2c7e844f9245985fca7b1ae9c872d23e7528837 + RNAudioAPI: a4068f739b4e80e636ac6110d70858ea89ac4835 RNGestureHandler: fc5ce5bf284640d3af6431c3a5c3bc121e98d045 RNReanimated: 77242c6d67416988a2fd9f5cf574bb3e60016362 RNScreens: e389d6a6a66a4f0d3662924ecae803073ccce8ec diff --git a/packages/react-native-audio-api/RNAudioAPI.podspec b/packages/react-native-audio-api/RNAudioAPI.podspec index 0081b5fe..5f4a409a 100644 --- a/packages/react-native-audio-api/RNAudioAPI.podspec +++ b/packages/react-native-audio-api/RNAudioAPI.podspec @@ -16,6 +16,11 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm}", "common/cpp/**/*.{hpp,cpp,c,h}" + s.ios.frameworks = 'Accelerate' + s.xcconfig = { + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) HAVE_ACCELERATE=1' + } + # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79. if respond_to?(:install_modules_dependencies, true) From 76dcdc8ba83810f94ec1a94a86c0fa3a65903289 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Wed, 13 Nov 2024 19:22:30 +0100 Subject: [PATCH 10/35] feat: implemented getWaveDataTableForFundamentalFrequency function and fixed some nitpicks --- .../common/cpp/core/PeriodicWave.cpp | 27 +++++++++++++++++-- .../common/cpp/core/PeriodicWave.h | 4 ++- .../common/cpp/utils/FFTFrame.cpp | 4 +-- .../common/cpp/utils/FFTFrame.h | 7 ++--- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 7a10cb31..86a3da99 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -54,9 +54,9 @@ PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type) this->generateBasicWaveForm(type); } -PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary) +PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary, int size) : PeriodicWave(sampleRate) { - // get waveTable for real and imaginary + createBandLimitedTables(real, imaginary, size); } int PeriodicWave::getPeriodicWaveSize() const { @@ -71,6 +71,29 @@ int PeriodicWave::getPeriodicWaveSize() const { return 16384; } +void PeriodicWave::getWaveDataForFundamentalFrequency(float fundamentalFrequency, float *&lowerWaveData, float *&higherWaveData,float &interpolationFactor) { + // negative frequencies are allowed and will be treated as positive. + fundamentalFrequency = std::fabs(fundamentalFrequency); + + // calculating lower and higher range index for the given fundamental frequency. + float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / lowestFundamentalFrequency_ : 0.5f; + float centsAboveLowestFrequency = log2f(ratio) * 1200; + + float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange; + + pitchRange = std::clamp(pitchRange, 0.0f, static_cast(numberOfRanges_ - 1)); + + int lowerRangeIndex = static_cast(pitchRange); + int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1 ? lowerRangeIndex + 1 : lowerRangeIndex; + + // get the wave data for the lower and higher range index. + lowerWaveData = bandLimitedTables_[lowerRangeIndex]; + higherWaveData = bandLimitedTables_[higherRangeIndex]; + + // calculate the interpolation factor between the lower and higher range data. + interpolationFactor = pitchRange - static_cast(lowerRangeIndex); +} + int PeriodicWave::getMaxNumberOfPartials() const { return getPeriodicWaveSize() / 2; } diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 1eee2d40..96de4981 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -39,10 +39,12 @@ namespace audioapi { class PeriodicWave { public: explicit PeriodicWave(int sampleRate, OscillatorType type); - explicit PeriodicWave(int sampleRate, float *real, float *imaginary); + explicit PeriodicWave(int sampleRate, float *real, float *imaginary, int size); [[nodiscard]] int getPeriodicWaveSize() const; + void getWaveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData, float& interpolationFactor); + private: explicit PeriodicWave(int sampleRate); diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index 2868effc..58c02755 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -20,8 +20,8 @@ namespace audioapi { // Scale the FFT data, beacuse of // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 - VectorMath::multiplyByScalar(realData_, 0.5f, realData_, halfSize); - VectorMath::multiplyByScalar(imaginaryData_, 0.5f, imaginaryData_, halfSize); + VectorMath::multiplyByScalar(realData_, 0.5f, realData_, size_ / 2); + VectorMath::multiplyByScalar(imaginaryData_, 0.5f, imaginaryData_, size_ /2); } void FFTFrame::inverse(float *data) { diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h index c3e107a4..26a56d32 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -33,15 +33,16 @@ #endif #include +#include "VectorMath.h" namespace audioapi { class FFTFrame { public: - FFTFrame(int size); - FFTFrame(const FFTFrame& frame); - ~FFTFrame(); + explicit FFTFrame(int size); +// FFTFrame(const FFTFrame& frame); +// ~FFTFrame(); float *getRealData() const { return realData_; } float *getImaginaryData() const { return imaginaryData_; } From a434d603d7ce118d52b172cc3553a2463061d138 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 10:29:42 +0100 Subject: [PATCH 11/35] feat: implemented interpolation and gettingSample --- .../common/cpp/core/PeriodicWave.cpp | 129 +++++++++++++++--- .../common/cpp/core/PeriodicWave.h | 8 +- .../common/cpp/utils/FFTFrame.cpp | 8 ++ .../common/cpp/utils/FFTFrame.h | 4 +- 4 files changed, 125 insertions(+), 24 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 86a3da99..20eba4f8 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -34,6 +34,9 @@ constexpr unsigned NumberOfOctaveBands = 3; constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands; +constexpr float interpolate2Point = 0.3; +constexpr float interpolate3Point = 0.16; + namespace audioapi { PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { numberOfRanges_ = lround( @@ -71,27 +74,13 @@ int PeriodicWave::getPeriodicWaveSize() const { return 16384; } -void PeriodicWave::getWaveDataForFundamentalFrequency(float fundamentalFrequency, float *&lowerWaveData, float *&higherWaveData,float &interpolationFactor) { - // negative frequencies are allowed and will be treated as positive. - fundamentalFrequency = std::fabs(fundamentalFrequency); - - // calculating lower and higher range index for the given fundamental frequency. - float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / lowestFundamentalFrequency_ : 0.5f; - float centsAboveLowestFrequency = log2f(ratio) * 1200; +float PeriodicWave::getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement) { + float *lowerWaveData = nullptr; + float *higherWaveData = nullptr; - float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange; + auto interpolationFactor = getWaveDataForFundamentalFrequency(fundamentalFrequency, lowerWaveData, higherWaveData); - pitchRange = std::clamp(pitchRange, 0.0f, static_cast(numberOfRanges_ - 1)); - - int lowerRangeIndex = static_cast(pitchRange); - int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1 ? lowerRangeIndex + 1 : lowerRangeIndex; - - // get the wave data for the lower and higher range index. - lowerWaveData = bandLimitedTables_[lowerRangeIndex]; - higherWaveData = bandLimitedTables_[higherRangeIndex]; - - // calculate the interpolation factor between the lower and higher range data. - interpolationFactor = pitchRange - static_cast(lowerRangeIndex); + return doInterpolation(bufferIndex, phaseIncrement, interpolationFactor, lowerWaveData, higherWaveData); } int PeriodicWave::getMaxNumberOfPartials() const { @@ -121,7 +110,7 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { * (where the positive frequencies are the complex conjugate of the negative ones). * This symmetry implies that real signals have mirrored frequency components. * In such scenarios, all 'real' frequency information is contained in the first half of the transform, - * and altering parts such as real and imag can finely shape which harmonic content is retained or discarded. + * and altering parts such as real and imaginary can finely shape which harmonic content is retained or discarded. */ auto halfSize = fftSize / 2; @@ -215,4 +204,104 @@ void PeriodicWave::createBandLimitedTables(const float *realData, const float *i fftFrame.inverse(bandLimitedTables_[rangeIndex]); } } + +float PeriodicWave::getWaveDataForFundamentalFrequency(float fundamentalFrequency, float *&lowerWaveData, float *&higherWaveData) { + // negative frequencies are allowed and will be treated as positive. + fundamentalFrequency = std::fabs(fundamentalFrequency); + + // calculating lower and higher range index for the given fundamental frequency. + float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / lowestFundamentalFrequency_ : 0.5f; + float centsAboveLowestFrequency = log2f(ratio) * 1200; + + float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange; + + pitchRange = std::clamp(pitchRange, 0.0f, static_cast(numberOfRanges_ - 1)); + + int lowerRangeIndex = static_cast(pitchRange); + int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1 ? lowerRangeIndex + 1 : lowerRangeIndex; + + // get the wave data for the lower and higher range index. + lowerWaveData = bandLimitedTables_[lowerRangeIndex]; + higherWaveData = bandLimitedTables_[higherRangeIndex]; + + // calculate the interpolation factor between the lower and higher range data. + return pitchRange - static_cast(lowerRangeIndex); +} + +float PeriodicWave::doInterpolation(float bufferIndex, float phaseIncrement, float waveTableInterpolationFactor, + const float *lowerWaveData, const float *higherWaveData) const { + float lowerWaveDataSample = 0; + float higherWaveDataSample = 0; + + // Consider a typical sample rate of 44100 Hz and max periodic wave + // size of 4096. The relationship between |phaseIncrement| and the frequency + // of the oscillator is |phaseIncrement| = freq * 4096/44100. Or freq = + // |phaseIncrement|*44100/4096 = 10.8*|phaseIncrement|. + // + // For the |phaseIncrement| thresholds below, this means that we use linear + // interpolation for all freq >= 3.2 Hz, 3-point Lagrange + // for freq >= 1.7 Hz and 5-point Lagrange for every thing else. + // + // We use Lagrange interpolation because it's relatively simple to + // implement and fairly inexpensive, and the interpolator always + // passes through known points. + // https://dlmf.nist.gov/3.3#ii + + int index = static_cast(bufferIndex); + auto factor = bufferIndex - static_cast(index); + + if (phaseIncrement >= interpolate2Point) { + int indices[2]; + + for (int i = 0; i < 2; i++) { + indices[i] = (index + i) % getPeriodicWaveSize(); + } + + auto lowerWaveDataSample1 = lowerWaveData[indices[0]]; + auto lowerWaveDataSample2 = lowerWaveData[indices[1]]; + auto higherWaveDataSample1 = higherWaveData[indices[0]]; + auto higherWaveDataSample2 = higherWaveData[indices[1]]; + + lowerWaveDataSample = (1 - factor) * lowerWaveDataSample1 + factor * lowerWaveDataSample2; + higherWaveDataSample = (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2; + } else if (phaseIncrement >= interpolate3Point) { + int indices[3]; + + for (int i = 0; i < 3; i++) { + indices[i] = (index + i - 1 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + } + + float A[3]; + + A[0] = factor * (factor - 1) / 2; + A[1] = 1 - factor * factor; + A[2] = factor * (factor + 1) / 2; + + for (int i = 0; i < 3; i++) { + lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; + higherWaveDataSample += higherWaveData[indices[i]] * A[i]; + } + } else { + int indices[5]; + + for (int i = 0; i < 5; i++) { + indices[i] = (index + i - 2 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + } + + float A[5]; + + A[0] = factor * (factor * factor - 1) * (factor - 2) / 24; + A[1] = - factor * (factor - 1) * (factor * factor - 4) / 6; + A[2] = (factor * factor - 1) * (factor * factor - 4) / 4; + A[3] = - factor * (factor + 1) * (factor * factor - 4) / 6; + A[4] = factor * (factor * factor - 1) * (factor + 2) / 24; + + for (int i = 0; i < 5; i++) { + lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; + higherWaveDataSample += higherWaveData[indices[i]] * A[i]; + } + } + + return (1 - waveTableInterpolationFactor) * higherWaveDataSample + waveTableInterpolationFactor * lowerWaveDataSample; +} } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 96de4981..c737c408 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -43,7 +43,7 @@ class PeriodicWave { [[nodiscard]] int getPeriodicWaveSize() const; - void getWaveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData, float& interpolationFactor); + float getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement); private: explicit PeriodicWave(int sampleRate); @@ -56,6 +56,10 @@ class PeriodicWave { void createBandLimitedTables(const float *real, const float *imaginary, int size); + float getWaveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData); + + float doInterpolation(float bufferIndex, float phaseIncrement, float waveTableInterpolationFactor, const float* lowerWaveData, const float* higherWaveData) const; + // determines the time resolution of the waveform. int sampleRate_; // determines number of frequency segments (or bands) the signal is divided. @@ -66,7 +70,7 @@ class PeriodicWave { // scaling factor used to adjust size of period of waveform to the sample // rate. float rateScale_; - + // array of band-limited waveforms. float **bandLimitedTables_; }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index 58c02755..3c4bcabf 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -13,6 +13,14 @@ namespace audioapi { #endif } + void FFTFrame::forward(float *data) { + + } + + void FFTFrame::inverse(float *data) { + + } + #if defined(HAVE_ACCELERATE) void FFTFrame::forward(float *data) { vDSP_ctoz(reinterpret_cast(data), 2, &frame_, 1, size_ / 2); diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h index 26a56d32..a26d2ad4 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -44,8 +44,8 @@ class FFTFrame { // FFTFrame(const FFTFrame& frame); // ~FFTFrame(); - float *getRealData() const { return realData_; } - float *getImaginaryData() const { return imaginaryData_; } + [[nodiscard]] float *getRealData() const { return realData_; } + [[nodiscard]] float *getImaginaryData() const { return imaginaryData_; } void forward(float *data); void inverse(float *data); From bfaedc68488955fdc3bf94843a19e16944ad1e73 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 12:40:54 +0100 Subject: [PATCH 12/35] feat: added getRateScale --- .../common/cpp/core/PeriodicWave.cpp | 4 ++++ .../common/cpp/core/PeriodicWave.h | 1 + .../common/cpp/utils/FFTFrame.cpp | 16 ++++++++-------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 20eba4f8..2678e4e3 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -74,6 +74,10 @@ int PeriodicWave::getPeriodicWaveSize() const { return 16384; } +float PeriodicWave::getRateScale() const { + return rateScale_; +} + float PeriodicWave::getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement) { float *lowerWaveData = nullptr; float *higherWaveData = nullptr; diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index c737c408..c3df2de4 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -42,6 +42,7 @@ class PeriodicWave { explicit PeriodicWave(int sampleRate, float *real, float *imaginary, int size); [[nodiscard]] int getPeriodicWaveSize() const; + [[nodiscard]] float getRateScale() const; float getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement); diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index 3c4bcabf..e25d2e0b 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -13,14 +13,6 @@ namespace audioapi { #endif } - void FFTFrame::forward(float *data) { - - } - - void FFTFrame::inverse(float *data) { - - } - #if defined(HAVE_ACCELERATE) void FFTFrame::forward(float *data) { vDSP_ctoz(reinterpret_cast(data), 2, &frame_, 1, size_ / 2); @@ -40,5 +32,13 @@ namespace audioapi { // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 VectorMath::multiplyByScalar(data, 1.0f / static_cast(size_), data, size_); } +#else + void FFTFrame::forward(float *data) { + + } + + void FFTFrame::inverse(float *data) { + + } #endif } // namespace audioapi From 9a1e39fb51fbcd8ffcef958c195cf1c69c79e3a6 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 12:53:39 +0100 Subject: [PATCH 13/35] feat: introduced PeriodicWave into OscillatorNode --- .../common/cpp/core/OscillatorNode.cpp | 22 +- .../common/cpp/core/OscillatorNode.h | 44 +- .../common/cpp/core/PeriodicWave.cpp | 416 ++++++++++-------- .../common/cpp/core/PeriodicWave.h | 28 +- .../common/cpp/utils/FFTFrame.cpp | 67 ++- .../common/cpp/utils/FFTFrame.h | 35 +- 6 files changed, 322 insertions(+), 290 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp index b8e6806c..a0b5b40e 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp @@ -9,6 +9,9 @@ OscillatorNode::OscillatorNode(BaseAudioContext *context) context, 444.0, -NYQUIST_FREQUENCY, NYQUIST_FREQUENCY); detuneParam_ = std::make_shared(context, 0.0, -MAX_DETUNE, MAX_DETUNE); + type_ = OscillatorType::SINE; + periodicWave_ = + std::make_shared(context_->getSampleRate(), type_); } std::shared_ptr OscillatorNode::getFrequencyParam() const { @@ -25,6 +28,8 @@ std::string OscillatorNode::getType() { void OscillatorNode::setType(const std::string &type) { type_ = OscillatorNode::fromString(type); + periodicWave_ = + std::make_shared(context_->getSampleRate(), type_); } bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { @@ -39,24 +44,19 @@ bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f); auto detunedFrequency = round(frequencyParam_->getValueAtTime(time) * detuneRatio); - auto phaseIncrement = static_cast( - 2 * M_PI * detunedFrequency / context_->getSampleRate()); + auto phaseIncrement = detunedFrequency * periodicWave_->getRateScale(); - float value = OscillatorNode::getWaveBufferElement(phase_, type_); + float sample = periodicWave_->getWaveTableElement( + detunedFrequency, phase_, phaseIncrement); for (int j = 0; j < channelCount_; j++) { - audioData[i * channelCount_ + j] = value; + audioData[i * channelCount_ + j] = sample; } phase_ += phaseIncrement; - time += deltaTime; - if (phase_ >= 2 * M_PI) { - phase_ -= 2 * M_PI; - } - - if (phase_ < 0) { - phase_ += 2 * M_PI; + if (phase_ >= static_cast(periodicWave_->getPeriodicWaveSize())) { + phase_ -= static_cast(periodicWave_->getPeriodicWaveSize()); } } diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h index 17776288..4a59347c 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h @@ -7,6 +7,7 @@ #include "AudioParam.h" #include "AudioScheduledSourceNode.h" #include "OscillatorType.h" +#include "PeriodicWave.h" namespace audioapi { @@ -22,51 +23,12 @@ class OscillatorNode : public AudioScheduledSourceNode { protected: bool processAudio(float *audioData, int32_t numFrames) override; - private: - static float sineWave(double wavePhase) { - return static_cast(std::sin(wavePhase)); - } - - static float squareWave(double wavePhase) { - return static_cast(std::sin(wavePhase) >= 0 ? 1.0 : -1.0); - } - - static float sawtoothWave(double wavePhase) { - return static_cast( - 2.0 * - (wavePhase / (2 * M_PI) - std::floor(wavePhase / (2 * M_PI) + 0.5))); - } - - static float triangleWave(double wavePhase) { - return static_cast( - 2.0 * - std::abs( - 2.0 * - (wavePhase / (2 * M_PI) - - std::floor(wavePhase / (2 * M_PI) + 0.5))) - - 1.0); - } - - static float getWaveBufferElement(double wavePhase, OscillatorType type) { - switch (type) { - case OscillatorType::SINE: - return sineWave(wavePhase); - case OscillatorType::SQUARE: - return squareWave(wavePhase); - case OscillatorType::SAWTOOTH: - return sawtoothWave(wavePhase); - case OscillatorType::TRIANGLE: - return triangleWave(wavePhase); - default: - throw std::invalid_argument("Unknown wave type"); - } - } - private: std::shared_ptr frequencyParam_; std::shared_ptr detuneParam_; - OscillatorType type_ = OscillatorType::SINE; + OscillatorType type_; float phase_ = 0.0; + std::shared_ptr periodicWave_; static OscillatorType fromString(const std::string &type) { std::string lowerType = type; diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 2678e4e3..2c96248e 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -54,12 +54,16 @@ PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type) : PeriodicWave(sampleRate) { - this->generateBasicWaveForm(type); + this->generateBasicWaveForm(type); } -PeriodicWave::PeriodicWave(int sampleRate, float *real, float *imaginary, int size) +PeriodicWave::PeriodicWave( + int sampleRate, + float *real, + float *imaginary, + int size) : PeriodicWave(sampleRate) { - createBandLimitedTables(real, imaginary, size); + createBandLimitedTables(real, imaginary, size); } int PeriodicWave::getPeriodicWaveSize() const { @@ -75,237 +79,287 @@ int PeriodicWave::getPeriodicWaveSize() const { } float PeriodicWave::getRateScale() const { - return rateScale_; + return rateScale_; } -float PeriodicWave::getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement) { - float *lowerWaveData = nullptr; - float *higherWaveData = nullptr; - - auto interpolationFactor = getWaveDataForFundamentalFrequency(fundamentalFrequency, lowerWaveData, higherWaveData); - - return doInterpolation(bufferIndex, phaseIncrement, interpolationFactor, lowerWaveData, higherWaveData); +float PeriodicWave::getWaveTableElement( + float fundamentalFrequency, + float bufferIndex, + float phaseIncrement) { + float *lowerWaveData = nullptr; + float *higherWaveData = nullptr; + + auto interpolationFactor = getWaveDataForFundamentalFrequency( + fundamentalFrequency, lowerWaveData, higherWaveData); + + return doInterpolation( + bufferIndex, + phaseIncrement, + interpolationFactor, + lowerWaveData, + higherWaveData); } int PeriodicWave::getMaxNumberOfPartials() const { - return getPeriodicWaveSize() / 2; + return getPeriodicWaveSize() / 2; } int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const { - // Number of cents below nyquist where we cull partials. - auto centsToCull = static_cast(rangeIndex) * CentsPerRange; + // Number of cents below nyquist where we cull partials. + auto centsToCull = static_cast(rangeIndex) * CentsPerRange; - // A value from 0 -> 1 representing what fraction of the partials to keep. - auto cullingScale = std::powf(2, -centsToCull / 1200); + // A value from 0 -> 1 representing what fraction of the partials to keep. + auto cullingScale = std::powf(2, -centsToCull / 1200); - // The very top range will have all the partials culled. - int numberOfPartials = floor(static_cast(getMaxNumberOfPartials()) * cullingScale); + // The very top range will have all the partials culled. + int numberOfPartials = + floor(static_cast(getMaxNumberOfPartials()) * cullingScale); - return numberOfPartials; + return numberOfPartials; } // This function generates real and imaginary parts of the waveTable, -// real and imaginary arrays represent the coefficients of the harmonic components in the frequency domain, -// specifically as part of a complex representation used by Fourier Transform methods to describe signals. +// real and imaginary arrays represent the coefficients of the harmonic +// components in the frequency domain, specifically as part of a complex +// representation used by Fourier Transform methods to describe signals. void PeriodicWave::generateBasicWaveForm(OscillatorType type) { auto fftSize = getPeriodicWaveSize(); /* - * For real-valued time-domain signals, the FFT outputs a Hermitian symmetric sequence - * (where the positive frequencies are the complex conjugate of the negative ones). - * This symmetry implies that real signals have mirrored frequency components. - * In such scenarios, all 'real' frequency information is contained in the first half of the transform, - * and altering parts such as real and imaginary can finely shape which harmonic content is retained or discarded. - */ + * For real-valued time-domain signals, the FFT outputs a Hermitian symmetric + * sequence (where the positive frequencies are the complex conjugate of the + * negative ones). This symmetry implies that real signals have mirrored + * frequency components. In such scenarios, all 'real' frequency information + * is contained in the first half of the transform, and altering parts such as + * real and imaginary can finely shape which harmonic content is retained or + * discarded. + */ auto halfSize = fftSize / 2; auto *real = new float[halfSize]; auto *imaginary = new float[halfSize]; - // Reset Direct Current (DC) component. First element of frequency domain representation - c0. - // https://math24.net/complex-form-fourier-series.html + // Reset Direct Current (DC) component. First element of frequency domain + // representation - c0. https://math24.net/complex-form-fourier-series.html real[0] = 0.0f; imaginary[0] = 0.0f; - for(int i = 1; i < halfSize; i++) { - // All waveforms are odd functions with a positive slope at time 0. - // Hence the coefficients for cos() are always 0. - - // Formulas for Fourier coefficients: - // https://mathworld.wolfram.com/FourierSeries.html - - // Coefficient for sin() - float b; - - auto piFactor = static_cast(1.0f / (i * M_PI)); - - switch(type) { - case OscillatorType::SINE: - b = (i == 1) ? 1.0f : 0.0f; - break; - case OscillatorType::SQUARE: - // https://mathworld.wolfram.com/FourierSeriesSquareWave.html - b = (i % 2 == 1) ? 4 * piFactor : 0.0f; - break; - case OscillatorType::SAWTOOTH: - // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our function differs from this one, - // but coefficients calculation looks similar. - // our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) + 0.5))); - // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B - b = 2 * piFactor * (i % 2 == 1 ? 1.0f : -1.0f); - break; - case OscillatorType::TRIANGLE: - // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html - if (i % 2 == 1) { - b = 8.0f * piFactor * piFactor * (i % 4 == 1 ? 1.0f : -1.0f); - } else { - b = 0.0f; - } - break; - case OscillatorType::CUSTOM: - throw std::invalid_argument("Custom waveforms are not supported."); - } - - real[i] = 0.0f; - imaginary[i] = b; + for (int i = 1; i < halfSize; i++) { + // All waveforms are odd functions with a positive slope at time 0. + // Hence the coefficients for cos() are always 0. + + // Formulas for Fourier coefficients: + // https://mathworld.wolfram.com/FourierSeries.html + + // Coefficient for sin() + float b; + + auto piFactor = static_cast(1.0f / (i * M_PI)); + + switch (type) { + case OscillatorType::SINE: + b = (i == 1) ? 1.0f : 0.0f; + break; + case OscillatorType::SQUARE: + // https://mathworld.wolfram.com/FourierSeriesSquareWave.html + b = (i % 2 == 1) ? 4 * piFactor : 0.0f; + break; + case OscillatorType::SAWTOOTH: + // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our + // function differs from this one, but coefficients calculation looks + // similar. our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) + + // 0.5))); + // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B + b = 2 * piFactor * (i % 2 == 1 ? 1.0f : -1.0f); + break; + case OscillatorType::TRIANGLE: + // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html + if (i % 2 == 1) { + b = 8.0f * piFactor * piFactor * (i % 4 == 1 ? 1.0f : -1.0f); + } else { + b = 0.0f; + } + break; + case OscillatorType::CUSTOM: + throw std::invalid_argument("Custom waveforms are not supported."); + } + + real[i] = 0.0f; + imaginary[i] = b; } createBandLimitedTables(real, imaginary, halfSize); } -void PeriodicWave::createBandLimitedTables(const float *realData, const float *imaginaryData, int size) { - auto fftSize = getPeriodicWaveSize(); - auto halfSize = fftSize / 2; - - size = std::min(size, halfSize); - - for(int rangeIndex = 0; rangeIndex < numberOfRanges_; rangeIndex++) { - FFTFrame fftFrame(fftSize); - - auto *realFFTFrameData = fftFrame.getRealData(); - auto *imaginaryFFTFrameData = fftFrame.getImaginaryData(); - - // copy real and imaginary data to the FFT frame and scale it - VectorMath::multiplyByScalar(realData, static_cast(fftSize), realFFTFrameData, size); - VectorMath::multiplyByScalar(imaginaryData, -static_cast(fftSize), imaginaryFFTFrameData, size); +void PeriodicWave::createBandLimitedTables( + const float *realData, + const float *imaginaryData, + int size) { + auto fftSize = getPeriodicWaveSize(); + auto halfSize = fftSize / 2; - // Find the starting bin where we should start culling. - // We need to clear out the highest frequencies to band-limit the waveform. - auto numberOfPartials = getNumberOfPartialsPerRange(rangeIndex); + size = std::min(size, halfSize); + + for (int rangeIndex = 0; rangeIndex < numberOfRanges_; rangeIndex++) { + FFTFrame fftFrame(fftSize); + + auto *realFFTFrameData = fftFrame.getRealData(); + auto *imaginaryFFTFrameData = fftFrame.getImaginaryData(); + + // copy real and imaginary data to the FFT frame and scale it + VectorMath::multiplyByScalar( + realData, static_cast(fftSize), realFFTFrameData, size); + VectorMath::multiplyByScalar( + imaginaryData, + -static_cast(fftSize), + imaginaryFFTFrameData, + size); + + // Find the starting bin where we should start culling. + // We need to clear out the highest frequencies to band-limit the waveform. + auto numberOfPartials = getNumberOfPartialsPerRange(rangeIndex); + + // Clamp the size to the number of partials. + auto clampedSize = std::min(size, numberOfPartials); + if (clampedSize < halfSize) { + // Zero out the higher frequencies for certain range. + std::fill( + realFFTFrameData + clampedSize, realFFTFrameData + halfSize, 0.0f); + std::fill( + imaginaryFFTFrameData + clampedSize, + imaginaryFFTFrameData + halfSize, + 0.0f); + } - // Clamp the size to the number of partials. - auto clampedSize = std::min(size, numberOfPartials); - if(clampedSize < halfSize) { - // Zero out the higher frequencies for certain range. - std::fill(realFFTFrameData + clampedSize, realFFTFrameData + halfSize, 0.0f); - std::fill(imaginaryFFTFrameData + clampedSize, imaginaryFFTFrameData + halfSize, 0.0f); - } + // Zero out the nquist and DC components. + realFFTFrameData[0] = 0.0f; + imaginaryFFTFrameData[0] = 0.0f; - // Zero out the nquist and DC components. - realFFTFrameData[0] = 0.0f; - imaginaryFFTFrameData[0] = 0.0f; + bandLimitedTables_[rangeIndex] = new float[fftSize]; + fftFrame.inverse(bandLimitedTables_[rangeIndex]); - bandLimitedTables_[rangeIndex] = new float[fftSize]; - fftFrame.inverse(bandLimitedTables_[rangeIndex]); - } + VectorMath::multiplyByScalar( + bandLimitedTables_[rangeIndex], + 0.5f, + bandLimitedTables_[rangeIndex], + fftSize); + } } -float PeriodicWave::getWaveDataForFundamentalFrequency(float fundamentalFrequency, float *&lowerWaveData, float *&higherWaveData) { - // negative frequencies are allowed and will be treated as positive. - fundamentalFrequency = std::fabs(fundamentalFrequency); +float PeriodicWave::getWaveDataForFundamentalFrequency( + float fundamentalFrequency, + float *&lowerWaveData, + float *&higherWaveData) { + // negative frequencies are allowed and will be treated as positive. + fundamentalFrequency = std::fabs(fundamentalFrequency); - // calculating lower and higher range index for the given fundamental frequency. - float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / lowestFundamentalFrequency_ : 0.5f; - float centsAboveLowestFrequency = log2f(ratio) * 1200; + // calculating lower and higher range index for the given fundamental + // frequency. + float ratio = fundamentalFrequency > 0 + ? fundamentalFrequency / lowestFundamentalFrequency_ + : 0.5f; + float centsAboveLowestFrequency = log2f(ratio) * 1200; - float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange; + float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange; - pitchRange = std::clamp(pitchRange, 0.0f, static_cast(numberOfRanges_ - 1)); + pitchRange = + std::clamp(pitchRange, 0.0f, static_cast(numberOfRanges_ - 1)); - int lowerRangeIndex = static_cast(pitchRange); - int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1 ? lowerRangeIndex + 1 : lowerRangeIndex; + int lowerRangeIndex = static_cast(pitchRange); + int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1 + ? lowerRangeIndex + 1 + : lowerRangeIndex; - // get the wave data for the lower and higher range index. - lowerWaveData = bandLimitedTables_[lowerRangeIndex]; - higherWaveData = bandLimitedTables_[higherRangeIndex]; + // get the wave data for the lower and higher range index. + lowerWaveData = bandLimitedTables_[lowerRangeIndex]; + higherWaveData = bandLimitedTables_[higherRangeIndex]; - // calculate the interpolation factor between the lower and higher range data. - return pitchRange - static_cast(lowerRangeIndex); + // calculate the interpolation factor between the lower and higher range data. + return pitchRange - static_cast(lowerRangeIndex); } -float PeriodicWave::doInterpolation(float bufferIndex, float phaseIncrement, float waveTableInterpolationFactor, - const float *lowerWaveData, const float *higherWaveData) const { - float lowerWaveDataSample = 0; - float higherWaveDataSample = 0; - - // Consider a typical sample rate of 44100 Hz and max periodic wave - // size of 4096. The relationship between |phaseIncrement| and the frequency - // of the oscillator is |phaseIncrement| = freq * 4096/44100. Or freq = - // |phaseIncrement|*44100/4096 = 10.8*|phaseIncrement|. - // - // For the |phaseIncrement| thresholds below, this means that we use linear - // interpolation for all freq >= 3.2 Hz, 3-point Lagrange - // for freq >= 1.7 Hz and 5-point Lagrange for every thing else. - // - // We use Lagrange interpolation because it's relatively simple to - // implement and fairly inexpensive, and the interpolator always - // passes through known points. - // https://dlmf.nist.gov/3.3#ii - - int index = static_cast(bufferIndex); - auto factor = bufferIndex - static_cast(index); - - if (phaseIncrement >= interpolate2Point) { - int indices[2]; - - for (int i = 0; i < 2; i++) { - indices[i] = (index + i) % getPeriodicWaveSize(); - } - - auto lowerWaveDataSample1 = lowerWaveData[indices[0]]; - auto lowerWaveDataSample2 = lowerWaveData[indices[1]]; - auto higherWaveDataSample1 = higherWaveData[indices[0]]; - auto higherWaveDataSample2 = higherWaveData[indices[1]]; - - lowerWaveDataSample = (1 - factor) * lowerWaveDataSample1 + factor * lowerWaveDataSample2; - higherWaveDataSample = (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2; - } else if (phaseIncrement >= interpolate3Point) { - int indices[3]; +float PeriodicWave::doInterpolation( + float bufferIndex, + float phaseIncrement, + float waveTableInterpolationFactor, + const float *lowerWaveData, + const float *higherWaveData) const { + float lowerWaveDataSample = 0; + float higherWaveDataSample = 0; + + // Consider a typical sample rate of 44100 Hz and max periodic wave + // size of 4096. The relationship between |phaseIncrement| and the frequency + // of the oscillator is |phaseIncrement| = freq * 4096/44100. Or freq = + // |phaseIncrement|*44100/4096 = 10.8*|phaseIncrement|. + // + // For the |phaseIncrement| thresholds below, this means that we use linear + // interpolation for all freq >= 3.2 Hz, 3-point Lagrange + // for freq >= 1.7 Hz and 5-point Lagrange for every thing else. + // + // We use Lagrange interpolation because it's relatively simple to + // implement and fairly inexpensive, and the interpolator always + // passes through known points. + // https://dlmf.nist.gov/3.3#ii + + int index = static_cast(bufferIndex); + auto factor = bufferIndex - static_cast(index); + + if (phaseIncrement >= interpolate2Point) { + int indices[2]; + + for (int i = 0; i < 2; i++) { + indices[i] = (index + i) % getPeriodicWaveSize(); + } - for (int i = 0; i < 3; i++) { - indices[i] = (index + i - 1 + getPeriodicWaveSize()) % getPeriodicWaveSize(); - } + auto lowerWaveDataSample1 = lowerWaveData[indices[0]]; + auto lowerWaveDataSample2 = lowerWaveData[indices[1]]; + auto higherWaveDataSample1 = higherWaveData[indices[0]]; + auto higherWaveDataSample2 = higherWaveData[indices[1]]; + + lowerWaveDataSample = + (1 - factor) * lowerWaveDataSample1 + factor * lowerWaveDataSample2; + higherWaveDataSample = + (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2; + } else if (phaseIncrement >= interpolate3Point) { + int indices[3]; + + for (int i = 0; i < 3; i++) { + indices[i] = + (index + i - 1 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + } - float A[3]; + float A[3]; - A[0] = factor * (factor - 1) / 2; - A[1] = 1 - factor * factor; - A[2] = factor * (factor + 1) / 2; + A[0] = factor * (factor - 1) / 2; + A[1] = 1 - factor * factor; + A[2] = factor * (factor + 1) / 2; - for (int i = 0; i < 3; i++) { - lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; - higherWaveDataSample += higherWaveData[indices[i]] * A[i]; - } - } else { - int indices[5]; + for (int i = 0; i < 3; i++) { + lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; + higherWaveDataSample += higherWaveData[indices[i]] * A[i]; + } + } else { + int indices[5]; - for (int i = 0; i < 5; i++) { - indices[i] = (index + i - 2 + getPeriodicWaveSize()) % getPeriodicWaveSize(); - } + for (int i = 0; i < 5; i++) { + indices[i] = + (index + i - 2 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + } - float A[5]; + float A[5]; - A[0] = factor * (factor * factor - 1) * (factor - 2) / 24; - A[1] = - factor * (factor - 1) * (factor * factor - 4) / 6; - A[2] = (factor * factor - 1) * (factor * factor - 4) / 4; - A[3] = - factor * (factor + 1) * (factor * factor - 4) / 6; - A[4] = factor * (factor * factor - 1) * (factor + 2) / 24; + A[0] = factor * (factor * factor - 1) * (factor - 2) / 24; + A[1] = -factor * (factor - 1) * (factor * factor - 4) / 6; + A[2] = (factor * factor - 1) * (factor * factor - 4) / 4; + A[3] = -factor * (factor + 1) * (factor * factor - 4) / 6; + A[4] = factor * (factor * factor - 1) * (factor + 2) / 24; - for (int i = 0; i < 5; i++) { - lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; - higherWaveDataSample += higherWaveData[indices[i]] * A[i]; - } + for (int i = 0; i < 5; i++) { + lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; + higherWaveDataSample += higherWaveData[indices[i]] * A[i]; } + } - return (1 - waveTableInterpolationFactor) * higherWaveDataSample + waveTableInterpolationFactor * lowerWaveDataSample; + return (1 - waveTableInterpolationFactor) * higherWaveDataSample + + waveTableInterpolationFactor * lowerWaveDataSample; } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index c3df2de4..af01128e 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -31,20 +31,27 @@ #include #include -#include "OscillatorType.h" #include "FFTFrame.h" +#include "OscillatorType.h" #include "VectorMath.h" namespace audioapi { class PeriodicWave { public: explicit PeriodicWave(int sampleRate, OscillatorType type); - explicit PeriodicWave(int sampleRate, float *real, float *imaginary, int size); + explicit PeriodicWave( + int sampleRate, + float *real, + float *imaginary, + int size); [[nodiscard]] int getPeriodicWaveSize() const; [[nodiscard]] float getRateScale() const; - float getWaveTableElement(float fundamentalFrequency, float bufferIndex, float phaseIncrement); + float getWaveTableElement( + float fundamentalFrequency, + float bufferIndex, + float phaseIncrement); private: explicit PeriodicWave(int sampleRate); @@ -55,11 +62,20 @@ class PeriodicWave { void generateBasicWaveForm(OscillatorType type); - void createBandLimitedTables(const float *real, const float *imaginary, int size); + void + createBandLimitedTables(const float *real, const float *imaginary, int size); - float getWaveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData); + float getWaveDataForFundamentalFrequency( + float fundamentalFrequency, + float *&lowerWaveData, + float *&higherWaveData); - float doInterpolation(float bufferIndex, float phaseIncrement, float waveTableInterpolationFactor, const float* lowerWaveData, const float* higherWaveData) const; + float doInterpolation( + float bufferIndex, + float phaseIncrement, + float waveTableInterpolationFactor, + const float *lowerWaveData, + const float *higherWaveData) const; // determines the time resolution of the waveform. int sampleRate_; diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index e25d2e0b..fa117fa4 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -1,44 +1,41 @@ #include "FFTFrame.h" namespace audioapi { - FFTFrame::FFTFrame(int size) { - size_ = size; - log2Size_ = static_cast(log2(size)); - realData_ = new float[size]; - imaginaryData_ = new float[size]; - #if defined(HAVE_ACCELERATE) - fftSetup_ = vDSP_create_fftsetup(log2Size_, FFT_RADIX2); - frame_.realp = realData_; - frame_.imagp = imaginaryData_; - #endif - } - +FFTFrame::FFTFrame(int size) { + size_ = size; + log2Size_ = static_cast(log2(size)); + realData_ = new float[size]; + imaginaryData_ = new float[size]; #if defined(HAVE_ACCELERATE) - void FFTFrame::forward(float *data) { - vDSP_ctoz(reinterpret_cast(data), 2, &frame_, 1, size_ / 2); - vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_FORWARD); - - // Scale the FFT data, beacuse of - // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 - VectorMath::multiplyByScalar(realData_, 0.5f, realData_, size_ / 2); - VectorMath::multiplyByScalar(imaginaryData_, 0.5f, imaginaryData_, size_ /2); - } - - void FFTFrame::inverse(float *data) { - vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE); - vDSP_ztoc(&frame_, 1, (DSPComplex*)data, 2, size_ / 2); + fftSetup_ = vDSP_create_fftsetup(log2Size_, FFT_RADIX2); + frame_.realp = realData_; + frame_.imagp = imaginaryData_; +#endif +} - // Scale the FFT data, beacuse of - // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 - VectorMath::multiplyByScalar(data, 1.0f / static_cast(size_), data, size_); - } +#if defined(HAVE_ACCELERATE) +void FFTFrame::forward(float *data) { + vDSP_ctoz(reinterpret_cast(data), 2, &frame_, 1, size_ / 2); + vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_FORWARD); + + // Scale the FFT data, beacuse of + // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 + VectorMath::multiplyByScalar(realData_, 0.5f, realData_, size_ / 2); + VectorMath::multiplyByScalar(imaginaryData_, 0.5f, imaginaryData_, size_ / 2); +} + +void FFTFrame::inverse(float *data) { + vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE); + vDSP_ztoc(&frame_, 1, (DSPComplex *)data, 2, size_ / 2); + + // Scale the FFT data, beacuse of + // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 + VectorMath::multiplyByScalar( + data, 1.0f / static_cast(size_), data, size_); +} #else - void FFTFrame::forward(float *data) { - - } - - void FFTFrame::inverse(float *data) { +void FFTFrame::forward(float *data) {} - } +void FFTFrame::inverse(float *data) {} #endif } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h index a26d2ad4..6c988725 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -38,27 +38,30 @@ namespace audioapi { class FFTFrame { + public: + explicit FFTFrame(int size); + // FFTFrame(const FFTFrame& frame); + // ~FFTFrame(); -public: - explicit FFTFrame(int size); -// FFTFrame(const FFTFrame& frame); -// ~FFTFrame(); + [[nodiscard]] float *getRealData() const { + return realData_; + } + [[nodiscard]] float *getImaginaryData() const { + return imaginaryData_; + } - [[nodiscard]] float *getRealData() const { return realData_; } - [[nodiscard]] float *getImaginaryData() const { return imaginaryData_; } + void forward(float *data); + void inverse(float *data); - void forward(float *data); - void inverse(float *data); - -private: - int size_; - int log2Size_; - float *realData_; - float *imaginaryData_; + private: + int size_; + int log2Size_; + float *realData_; + float *imaginaryData_; #if defined(HAVE_ACCELERATE) - FFTSetup fftSetup_; - DSPSplitComplex frame_; + FFTSetup fftSetup_; + DSPSplitComplex frame_; #endif }; From f77f54ae562ec35be8ae56940ce32b083c43c198 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 18:47:43 +0100 Subject: [PATCH 14/35] feat: added caching for periodicWave --- .../common/cpp/core/BaseAudioContext.cpp | 29 +++++++++++++++++++ .../common/cpp/core/BaseAudioContext.h | 9 ++++++ .../common/cpp/core/OscillatorNode.cpp | 8 ++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp index 3f2b19e4..8136bf78 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp @@ -78,4 +78,33 @@ std::function BaseAudioContext::renderAudio() { destination_->renderAudio(data, frames); }; } + +std::shared_ptr BaseAudioContext::getBasicWaveForm( + OscillatorType type) { + switch (type) { + case OscillatorType::SINE: + if (cachedSineWave_ == nullptr) { + cachedSineWave_ = std::make_shared(sampleRate_, type); + } + return cachedSineWave_; + case OscillatorType::SQUARE: + if (cachedSquareWave_ == nullptr) { + cachedSquareWave_ = std::make_shared(sampleRate_, type); + } + return cachedSquareWave_; + case OscillatorType::SAWTOOTH: + if (cachedSawtoothWave_ == nullptr) { + cachedSawtoothWave_ = std::make_shared(sampleRate_, type); + } + return cachedSawtoothWave_; + case OscillatorType::TRIANGLE: + if (cachedTriangleWave_ == nullptr) { + cachedTriangleWave_ = std::make_shared(sampleRate_, type); + } + return cachedTriangleWave_; + case OscillatorType::CUSTOM: + throw std::invalid_argument("You can't get a custom wave form. You need to create it."); + break; + } +} } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h index b01adac6..2cb45a91 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h @@ -16,6 +16,8 @@ #include "GainNode.h" #include "OscillatorNode.h" #include "StereoPannerNode.h" +#include "PeriodicWave.h" +#include "OscillatorType.h" #ifdef ANDROID #include "AudioPlayer.h" @@ -40,7 +42,9 @@ class BaseAudioContext { std::shared_ptr createBufferSource(); static std::shared_ptr createBuffer(int numberOfChannels, int length, int sampleRate); + std::function renderAudio(); + std::shared_ptr getBasicWaveForm(OscillatorType type); protected: std::shared_ptr destination_; @@ -54,6 +58,11 @@ class BaseAudioContext { double contextStartTime_; private: + std::shared_ptr cachedSineWave_ = nullptr; + std::shared_ptr cachedSquareWave_ = nullptr; + std::shared_ptr cachedSawtoothWave_ = nullptr; + std::shared_ptr cachedTriangleWave_ = nullptr; + static std::string toString(ContextState state) { switch (state) { case ContextState::SUSPENDED: diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp index a0b5b40e..15395f00 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp @@ -10,8 +10,7 @@ OscillatorNode::OscillatorNode(BaseAudioContext *context) detuneParam_ = std::make_shared(context, 0.0, -MAX_DETUNE, MAX_DETUNE); type_ = OscillatorType::SINE; - periodicWave_ = - std::make_shared(context_->getSampleRate(), type_); + periodicWave_ = context_->getBasicWaveForm(type_); } std::shared_ptr OscillatorNode::getFrequencyParam() const { @@ -28,8 +27,7 @@ std::string OscillatorNode::getType() { void OscillatorNode::setType(const std::string &type) { type_ = OscillatorNode::fromString(type); - periodicWave_ = - std::make_shared(context_->getSampleRate(), type_); + periodicWave_ = context_->getBasicWaveForm(type_); } bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { @@ -58,6 +56,8 @@ bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { if (phase_ >= static_cast(periodicWave_->getPeriodicWaveSize())) { phase_ -= static_cast(periodicWave_->getPeriodicWaveSize()); } + + time += deltaTime; } return true; From 456713e6bd1a2cf71910e3346a598857850762a7 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:15:42 +0100 Subject: [PATCH 15/35] feat: added createPeriodicWave BaseAudioContext method --- .../BaseAudioContextHostObject.cpp | 39 +++++++++++++++++++ .../HostObjects/BaseAudioContextHostObject.h | 1 + .../common/cpp/core/BaseAudioContext.cpp | 16 ++++++-- .../common/cpp/core/BaseAudioContext.h | 17 +++++--- .../cpp/wrappers/BaseAudioContextWrapper.cpp | 31 ++++++++++----- .../cpp/wrappers/BaseAudioContextWrapper.h | 12 ++++-- 6 files changed, 94 insertions(+), 22 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.cpp b/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.cpp index 128b47f9..d7d820ab 100644 --- a/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.cpp @@ -28,6 +28,8 @@ std::vector BaseAudioContextHostObject::getPropertyNames( propertyNames.push_back( jsi::PropNameID::forUtf8(runtime, "createBufferSource")); propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "createBuffer")); + propertyNames.push_back( + jsi::PropNameID::forUtf8(runtime, "createPeriodicWave")); return propertyNames; } @@ -161,6 +163,43 @@ jsi::Value BaseAudioContextHostObject::get( }); } + if (propName == "createPeriodicWave") { + return jsi::Function::createFromHostFunction( + runtime, + propNameId, + 3, + [this]( + jsi::Runtime &runtime, + const jsi::Value &thisValue, + const jsi::Value *arguments, + size_t count) -> jsi::Value { + auto real = arguments[0].getObject(runtime).getArray(runtime); + auto imag = arguments[1].getObject(runtime).getArray(runtime); + auto disableNormalization = arguments[2].getBool(); + auto length = + static_cast(real.getProperty(runtime, "length").asNumber()); + + auto *realData = new float[length]; + auto *imagData = new float[length]; + + for (size_t i = 0; i < real.length(runtime); i++) { + realData[i] = static_cast( + real.getValueAtIndex(runtime, i).getNumber()); + } + for (size_t i = 0; i < imag.length(runtime); i++) { + realData[i] = static_cast( + imag.getValueAtIndex(runtime, i).getNumber()); + } + + auto periodicWave = wrapper_->createPeriodicWave( + realData, imagData, disableNormalization, length); + auto periodicWaveHostObject = + PeriodicWaveHostObject::createFromWrapper(periodicWave); + return jsi::Object::createFromHostObject( + runtime, periodicWaveHostObject); + }); + } + throw std::runtime_error("Not yet implemented!"); } diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.h b/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.h index 1c591488..e70851bd 100644 --- a/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.h +++ b/packages/react-native-audio-api/common/cpp/HostObjects/BaseAudioContextHostObject.h @@ -12,6 +12,7 @@ #include "BiquadFilterNodeHostObject.h" #include "GainNodeHostObject.h" #include "OscillatorNodeHostObject.h" +#include "PeriodicWaveHostObject.h" #include "StereoPannerNodeHostObject.h" namespace audioapi { diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp index 8136bf78..dad8f3de 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp @@ -69,6 +69,15 @@ std::shared_ptr BaseAudioContext::createBuffer( return std::make_shared(numberOfChannels, length, sampleRate); } +std::shared_ptr BaseAudioContext::createPeriodicWave( + float *real, + float *imag, + bool disableNormalization, + int length) { + // add normalization + return std::make_shared(sampleRate_, real, imag, length); +} + std::function BaseAudioContext::renderAudio() { if (state_ == ContextState::CLOSED) { return [](float *, int) {}; @@ -102,9 +111,10 @@ std::shared_ptr BaseAudioContext::getBasicWaveForm( cachedTriangleWave_ = std::make_shared(sampleRate_, type); } return cachedTriangleWave_; - case OscillatorType::CUSTOM: - throw std::invalid_argument("You can't get a custom wave form. You need to create it."); - break; + case OscillatorType::CUSTOM: + throw std::invalid_argument( + "You can't get a custom wave form. You need to create it."); + break; } } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h index 2cb45a91..86f53201 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h @@ -15,9 +15,9 @@ #include "ContextState.h" #include "GainNode.h" #include "OscillatorNode.h" -#include "StereoPannerNode.h" -#include "PeriodicWave.h" #include "OscillatorType.h" +#include "PeriodicWave.h" +#include "StereoPannerNode.h" #ifdef ANDROID #include "AudioPlayer.h" @@ -42,6 +42,11 @@ class BaseAudioContext { std::shared_ptr createBufferSource(); static std::shared_ptr createBuffer(int numberOfChannels, int length, int sampleRate); + std::shared_ptr createPeriodicWave( + float *real, + float *imag, + bool disableNormalization, + int length); std::function renderAudio(); std::shared_ptr getBasicWaveForm(OscillatorType type); @@ -58,10 +63,10 @@ class BaseAudioContext { double contextStartTime_; private: - std::shared_ptr cachedSineWave_ = nullptr; - std::shared_ptr cachedSquareWave_ = nullptr; - std::shared_ptr cachedSawtoothWave_ = nullptr; - std::shared_ptr cachedTriangleWave_ = nullptr; + std::shared_ptr cachedSineWave_ = nullptr; + std::shared_ptr cachedSquareWave_ = nullptr; + std::shared_ptr cachedSawtoothWave_ = nullptr; + std::shared_ptr cachedTriangleWave_ = nullptr; static std::string toString(ContextState state) { switch (state) { diff --git a/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.cpp b/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.cpp index 479e8591..7ce5578b 100644 --- a/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.cpp +++ b/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.cpp @@ -14,6 +14,18 @@ BaseAudioContextWrapper::getDestination() const { return destination_; } +std::string BaseAudioContextWrapper::getState() const { + return context_->getState(); +} + +int BaseAudioContextWrapper::getSampleRate() const { + return context_->getSampleRate(); +} + +double BaseAudioContextWrapper::getCurrentTime() const { + return context_->getCurrentTime(); +} + std::shared_ptr BaseAudioContextWrapper::createOscillator() const { auto oscillator = context_->createOscillator(); @@ -51,15 +63,14 @@ std::shared_ptr BaseAudioContextWrapper::createBuffer( return std::make_shared(buffer); } -std::string BaseAudioContextWrapper::getState() const { - return context_->getState(); -} - -int BaseAudioContextWrapper::getSampleRate() const { - return context_->getSampleRate(); -} - -double BaseAudioContextWrapper::getCurrentTime() const { - return context_->getCurrentTime(); +std::shared_ptr +BaseAudioContextWrapper::createPeriodicWave( + float *real, + float *imag, + bool disableNormalization, + int length) { + auto periodicWave = + context_->createPeriodicWave(real, imag, disableNormalization, length); + return std::make_shared(periodicWave); } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.h b/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.h index 0be08009..58d6350e 100644 --- a/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.h +++ b/packages/react-native-audio-api/common/cpp/wrappers/BaseAudioContextWrapper.h @@ -11,6 +11,7 @@ #include "BiquadFilterNodeWrapper.h" #include "GainNodeWrapper.h" #include "OscillatorNodeWrapper.h" +#include "PeriodicWaveWrapper.h" #include "StereoPannerNodeWrapper.h" namespace audioapi { @@ -22,6 +23,9 @@ class BaseAudioContextWrapper { [[nodiscard]] std::shared_ptr getDestination() const; + [[nodiscard]] std::string getState() const; + [[nodiscard]] int getSampleRate() const; + [[nodiscard]] double getCurrentTime() const; [[nodiscard]] std::shared_ptr createOscillator() const; [[nodiscard]] std::shared_ptr createGain() const; [[nodiscard]] std::shared_ptr createStereoPanner() @@ -32,9 +36,11 @@ class BaseAudioContextWrapper { createBufferSource() const; [[nodiscard]] std::shared_ptr createBuffer(int numberOfChannels, int length, int sampleRate) const; - [[nodiscard]] std::string getState() const; - [[nodiscard]] int getSampleRate() const; - [[nodiscard]] double getCurrentTime() const; + [[nodiscard]] std::shared_ptr createPeriodicWave( + float *real, + float *imag, + bool disableNormalization, + int length); protected: std::shared_ptr destination_; From 01d898a6a417be8b3c6895fad7ba81d497817641 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:16:08 +0100 Subject: [PATCH 16/35] feat: implemented setPeriodicWave method --- .../HostObjects/OscillatorNodeHostObject.cpp | 21 +++++++++++++++++++ .../HostObjects/OscillatorNodeHostObject.h | 1 + .../common/cpp/core/OscillatorNode.cpp | 8 ++++++- .../common/cpp/core/OscillatorNode.h | 1 + .../cpp/wrappers/OscillatorNodeWrapper.cpp | 6 ++++++ .../cpp/wrappers/OscillatorNodeWrapper.h | 3 +++ 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.cpp index 29fdce63..44d1695c 100644 --- a/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.cpp @@ -24,6 +24,8 @@ std::vector OscillatorNodeHostObject::getPropertyNames( propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "frequency")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "detune")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "type")); + propertyNames.push_back( + jsi::PropNameID::forAscii(runtime, "setPeriodicWave")); return propertyNames; } @@ -46,6 +48,25 @@ jsi::Value OscillatorNodeHostObject::get( return jsi::String::createFromUtf8(runtime, waveType); } + if (propName == "setPeriodicWave") { + return jsi::Function::createFromHostFunction( + runtime, + propNameId, + 1, + [this]( + jsi::Runtime &rt, + const jsi::Value &thisVal, + const jsi::Value *args, + size_t count) -> jsi::Value { + auto wrapper = getOscillatorNodeWrapperFromAudioNodeWrapper(); + auto periodicWaveHostObject = + args[0].getObject(rt).asHostObject(rt); + + wrapper->setPeriodicWave(periodicWaveHostObject->wrapper_); + return jsi::Value::undefined(); + }); + } + return AudioScheduledSourceNodeHostObject::get(runtime, propNameId); } diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.h b/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.h index 00251b32..31084ffb 100644 --- a/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/HostObjects/OscillatorNodeHostObject.h @@ -7,6 +7,7 @@ #include "AudioParamHostObject.h" #include "AudioScheduledSourceNodeHostObject.h" #include "OscillatorNodeWrapper.h" +#include "PeriodicWaveHostObject.h" namespace audioapi { using namespace facebook; diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp index 15395f00..704ea730 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp @@ -30,6 +30,12 @@ void OscillatorNode::setType(const std::string &type) { periodicWave_ = context_->getBasicWaveForm(type_); } +void OscillatorNode::setPeriodicWave( + const std::shared_ptr &periodicWave) { + periodicWave_ = periodicWave; + type_ = OscillatorType::CUSTOM; +} + bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { if (!isPlaying_) { return false; @@ -57,7 +63,7 @@ bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { phase_ -= static_cast(periodicWave_->getPeriodicWaveSize()); } - time += deltaTime; + time += deltaTime; } return true; diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h index 4a59347c..2e04a9fe 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.h @@ -19,6 +19,7 @@ class OscillatorNode : public AudioScheduledSourceNode { [[nodiscard]] std::shared_ptr getDetuneParam() const; [[nodiscard]] std::string getType(); void setType(const std::string &type); + void setPeriodicWave(const std::shared_ptr &periodicWave); protected: bool processAudio(float *audioData, int32_t numFrames) override; diff --git a/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.cpp b/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.cpp index 5cb4babb..f85841af 100644 --- a/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.cpp +++ b/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.cpp @@ -35,4 +35,10 @@ void OscillatorNodeWrapper::setType(const std::string &type) { auto oscillatorNode_ = getOscillatorNodeFromAudioNode(); oscillatorNode_->setType(type); } + +void OscillatorNodeWrapper::setPeriodicWave( + const std::shared_ptr &periodicWave) { + auto oscillatorNode_ = getOscillatorNodeFromAudioNode(); + oscillatorNode_->setPeriodicWave(periodicWave->periodicWave_); +} } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.h b/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.h index e00f80bb..a37aea07 100644 --- a/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.h +++ b/packages/react-native-audio-api/common/cpp/wrappers/OscillatorNodeWrapper.h @@ -6,6 +6,7 @@ #include "AudioParamWrapper.h" #include "AudioScheduledSourceNodeWrapper.h" #include "OscillatorNode.h" +#include "PeriodicWaveWrapper.h" namespace audioapi { @@ -18,6 +19,8 @@ class OscillatorNodeWrapper : public AudioScheduledSourceNodeWrapper { [[nodiscard]] std::shared_ptr getDetuneParam() const; std::string getType(); void setType(const std::string &type); + void setPeriodicWave( + const std::shared_ptr &periodicWave); private: std::shared_ptr frequencyParam_; From d104c5a3e1ce541bb1794c639ac2f5329380ef93 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:16:33 +0100 Subject: [PATCH 17/35] feat: implemented PeriodicWave wrapper and HostObject --- .../HostObjects/PeriodicWaveHostObject.cpp | 33 +++++++++++++++++++ .../cpp/HostObjects/PeriodicWaveHostObject.h | 33 +++++++++++++++++++ .../common/cpp/core/PeriodicWave.cpp | 4 +-- .../common/cpp/core/PeriodicWave.h | 2 +- .../common/cpp/wrappers/PeriodicWaveWrapper.h | 17 ++++++++++ 5 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.cpp create mode 100644 packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.h create mode 100644 packages/react-native-audio-api/common/cpp/wrappers/PeriodicWaveWrapper.h diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.cpp b/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.cpp new file mode 100644 index 00000000..79b6c80b --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.cpp @@ -0,0 +1,33 @@ +#include "PeriodicWaveHostObject.h" + +namespace audioapi { +using namespace facebook; + +PeriodicWaveHostObject::PeriodicWaveHostObject( + const std::shared_ptr &wrapper) + : wrapper_(wrapper) {} + +std::vector PeriodicWaveHostObject::getPropertyNames( + jsi::Runtime &runtime) { + std::vector propertyNames; + return propertyNames; +} + +jsi::Value PeriodicWaveHostObject::get( + jsi::Runtime &runtime, + const jsi::PropNameID &propNameId) { + auto propName = propNameId.utf8(runtime); + + throw std::runtime_error("Not yet implemented!"); +} + +void PeriodicWaveHostObject::set( + jsi::Runtime &runtime, + const jsi::PropNameID &propNameId, + const jsi::Value &value) { + auto propName = propNameId.utf8(runtime); + + throw std::runtime_error("Not yet implemented!"); +} + +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.h b/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.h new file mode 100644 index 00000000..b4a252da --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/HostObjects/PeriodicWaveHostObject.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#include "PeriodicWaveWrapper.h" + +namespace audioapi { +using namespace facebook; + +class PeriodicWaveHostObject : public jsi::HostObject { + public: + std::shared_ptr wrapper_; + + explicit PeriodicWaveHostObject( + const std::shared_ptr &wrapper); + + jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override; + + void set( + jsi::Runtime &runtime, + const jsi::PropNameID &name, + const jsi::Value &value) override; + + std::vector getPropertyNames(jsi::Runtime &rt) override; + + static std::shared_ptr createFromWrapper( + const std::shared_ptr &wrapper) { + return std::make_shared(wrapper); + } +}; +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 2c96248e..b3a1a89e 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -61,9 +61,9 @@ PeriodicWave::PeriodicWave( int sampleRate, float *real, float *imaginary, - int size) + int length) : PeriodicWave(sampleRate) { - createBandLimitedTables(real, imaginary, size); + createBandLimitedTables(real, imaginary, length); } int PeriodicWave::getPeriodicWaveSize() const { diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index af01128e..64c6edc0 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -43,7 +43,7 @@ class PeriodicWave { int sampleRate, float *real, float *imaginary, - int size); + int length); [[nodiscard]] int getPeriodicWaveSize() const; [[nodiscard]] float getRateScale() const; diff --git a/packages/react-native-audio-api/common/cpp/wrappers/PeriodicWaveWrapper.h b/packages/react-native-audio-api/common/cpp/wrappers/PeriodicWaveWrapper.h new file mode 100644 index 00000000..a381e537 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/wrappers/PeriodicWaveWrapper.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "PeriodicWave.h" + +namespace audioapi { + +class PeriodicWaveWrapper { + public: + explicit PeriodicWaveWrapper( + const std::shared_ptr &periodicWave) + : periodicWave_(periodicWave) {} + + std::shared_ptr periodicWave_; +}; +} // namespace audioapi From 7389e47cdb55abecc03afa68a6854a1c8bdb1961 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:16:44 +0100 Subject: [PATCH 18/35] feat: updated interfaces --- .../src/core/BaseAudioContext.ts | 18 +++++++++++++++++- .../src/core/OscillatorNode.ts | 12 ++++++++++++ .../src/core/PeriodicWave.ts | 10 ++++++++++ .../react-native-audio-api/src/core/types.ts | 11 ++++++++++- .../react-native-audio-api/src/interfaces.ts | 14 ++++++++++++++ 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 packages/react-native-audio-api/src/core/PeriodicWave.ts diff --git a/packages/react-native-audio-api/src/core/BaseAudioContext.ts b/packages/react-native-audio-api/src/core/BaseAudioContext.ts index 78c86f8e..524b05e8 100644 --- a/packages/react-native-audio-api/src/core/BaseAudioContext.ts +++ b/packages/react-native-audio-api/src/core/BaseAudioContext.ts @@ -1,5 +1,5 @@ import { IBaseAudioContext } from '../interfaces'; -import { ContextState } from './types'; +import { ContextState, PeriodicWaveConstraints } from './types'; import AudioDestinationNode from './AudioDestinationNode'; import OscillatorNode from './OscillatorNode'; import GainNode from './GainNode'; @@ -75,4 +75,20 @@ export default class BaseAudioContext { this.context.createBuffer(numOfChannels, length, sampleRate) ); } + + createPeriodicWave( + real: number[], + imag: number[], + constraints?: PeriodicWaveConstraints + ): PeriodicWave { + if (real.length !== imag.length) { + throw new RangeError( + `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays are different` + ); + } + + const disableNormalization = constraints?.disableNormalization ?? false; + + return this.context.createPeriodicWave(real, imag, disableNormalization); + } } diff --git a/packages/react-native-audio-api/src/core/OscillatorNode.ts b/packages/react-native-audio-api/src/core/OscillatorNode.ts index f74fbb2b..e53e6b4f 100644 --- a/packages/react-native-audio-api/src/core/OscillatorNode.ts +++ b/packages/react-native-audio-api/src/core/OscillatorNode.ts @@ -3,6 +3,8 @@ import { OscillatorType } from './types'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; +import PeriodicWave from './PeriodicWave'; +import { InvalidStateError } from '../errors'; export default class OscillatorNode extends AudioScheduledSourceNode { readonly frequency: AudioParam; @@ -20,6 +22,16 @@ export default class OscillatorNode extends AudioScheduledSourceNode { } public set type(value: OscillatorType) { + if (value === 'custom') { + throw new InvalidStateError( + "The type can't be set to custom. You need to call setPeriodicWave() instead in order to define a custom waveform." + ); + } + (this.node as IOscillatorNode).type = value; } + + public setPeriodicWave(wave: PeriodicWave): void { + (this.node as IOscillatorNode).setPeriodicWave(wave.periodicWave); + } } diff --git a/packages/react-native-audio-api/src/core/PeriodicWave.ts b/packages/react-native-audio-api/src/core/PeriodicWave.ts new file mode 100644 index 00000000..b00c4505 --- /dev/null +++ b/packages/react-native-audio-api/src/core/PeriodicWave.ts @@ -0,0 +1,10 @@ +import { IPeriodicWave } from '../interfaces'; + +export default class PeriodicWave { + /** @internal */ + public readonly periodicWave: IPeriodicWave; + + constructor(periodicWave: IPeriodicWave) { + this.periodicWave = periodicWave; + } +} diff --git a/packages/react-native-audio-api/src/core/types.ts b/packages/react-native-audio-api/src/core/types.ts index bfa4dbaa..40be56f4 100644 --- a/packages/react-native-audio-api/src/core/types.ts +++ b/packages/react-native-audio-api/src/core/types.ts @@ -14,4 +14,13 @@ export type BiquadFilterType = export type ContextState = 'running' | 'closed'; -export type OscillatorType = 'sine' | 'square' | 'sawtooth' | 'triangle'; +export type OscillatorType = + | 'sine' + | 'square' + | 'sawtooth' + | 'triangle' + | 'custom'; + +export interface PeriodicWaveConstraints { + disableNormalization: boolean; +} diff --git a/packages/react-native-audio-api/src/interfaces.ts b/packages/react-native-audio-api/src/interfaces.ts index f1511038..366f0e29 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/interfaces.ts @@ -11,6 +11,7 @@ export interface IBaseAudioContext { readonly state: ContextState; readonly sampleRate: number; readonly currentTime: number; + createOscillator(): IOscillatorNode; createGain(): IGainNode; createStereoPanner(): IStereoPannerNode; @@ -21,6 +22,11 @@ export interface IBaseAudioContext { length: number, sampleRate: number ) => IAudioBuffer; + createPeriodicWave: ( + real: number[], + imag: number[], + disableNormalization: boolean + ) => IPeriodicWave; } export interface IAudioContext extends IBaseAudioContext { @@ -34,6 +40,7 @@ export interface IAudioNode { readonly channelCount: number; readonly channelCountMode: ChannelCountMode; readonly channelInterpretation: ChannelInterpretation; + connect: (node: IAudioNode) => void; disconnect: (node: IAudioNode) => void; } @@ -52,6 +59,7 @@ export interface IBiquadFilterNode extends IAudioNode { readonly Q: AudioParam; readonly gain: AudioParam; type: BiquadFilterType; + getFrequencyResponse( frequencyArray: number[], magResponseOutput: number[], @@ -70,6 +78,8 @@ export interface IOscillatorNode extends IAudioScheduledSourceNode { readonly frequency: IAudioParam; readonly detune: IAudioParam; type: OscillatorType; + + setPeriodicWave(periodicWave: IPeriodicWave): void; } export interface IAudioBufferSourceNode extends IAudioScheduledSourceNode { @@ -82,6 +92,7 @@ export interface IAudioBuffer { readonly duration: number; readonly sampleRate: number; readonly numberOfChannels: number; + getChannelData(channel: number): number[]; copyFromChannel( destination: number[], @@ -100,7 +111,10 @@ export interface IAudioParam { defaultValue: number; minValue: number; maxValue: number; + setValueAtTime: (value: number, startTime: number) => void; linearRampToValueAtTime: (value: number, endTime: number) => void; exponentialRampToValueAtTime: (value: number, endTime: number) => void; } + +export interface IPeriodicWave {} From fdd503520ba7e211473f96dea88ccddcc1f72612 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:24:54 +0100 Subject: [PATCH 19/35] docs: updated API coverage --- docs/web-audio-coverage.md | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/docs/web-audio-coverage.md b/docs/web-audio-coverage.md index b1581671..4bcc9c69 100644 --- a/docs/web-audio-coverage.md +++ b/docs/web-audio-coverage.md @@ -7,7 +7,7 @@ Some of the noticeable implementation details that are still in progress or not - Support of different number of channels (current approach in most of the audio-graph nodes assumes working with two channel audio) - Multi-input for each node and input mixing (Although specification suggests that most of the nodes can cave only one input or output, common use-cases proves otherwise). Only node that mixes multiple inputs is `DestinationNode`. -## ✅ Completed (**7** out of 33) +## ✅ Completed (**9** out of 33)
AudioBuffer @@ -27,11 +27,17 @@ Some of the noticeable implementation details that are still in progress or not
GainNode
+
+ OscillatorNode +
+
+ PeriodicWave +
StereoPannerNode
-## 🚧 In Progress (**5** out of 33) +## 🚧 In Progress (**4** out of 33)
AudioContext @@ -123,7 +129,7 @@ Some of the noticeable implementation details that are still in progress or not | 🔘 createIIRFilter | ❌ | | 🔘 createOscillator | ✅ | | 🔘 createPanner | ❌ | -| 🔘 createPeriodicWave | ❌ | +| 🔘 createPeriodicWave | ✅ | | 🔘 createStereoPanner | ✅ | | 🔘 createWaveShaper | ❌ | | 🔘 decodeAudioData | ❌ | @@ -132,23 +138,7 @@ Some of the noticeable implementation details that are still in progress or not
-
- OscillatorNode - -
- -| Property 🔹/ Method 🔘 | state | -| ---------------------- | ----- | -| 🔹 frequency | ✅ | -| 🔹 detune | ✅ | -| 🔹 type | ✅ | -| 🔘 setPeriodicWave | ❌ | - -
- -
- -## ❌ Not yet available (**21** out of 33) +## ❌ Not yet available (**20** out of 33)
AudioParamMap @@ -174,9 +164,6 @@ Some of the noticeable implementation details that are still in progress or not
WaveShaperNode
-
- PeriodicWave -
IIRFilterNode
From 9dce295edc3eb6967902ccd6c434e77a6ab006ce Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:26:55 +0100 Subject: [PATCH 20/35] ci: spell-checker checks only .md files --- .github/actions/spelling/only.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/actions/spelling/only.txt b/.github/actions/spelling/only.txt index 3138990c..cfa27f7b 100644 --- a/.github/actions/spelling/only.txt +++ b/.github/actions/spelling/only.txt @@ -1,4 +1 @@ -\.ts$ -\.tsx$ - \.md$ From a63d7105be549c551364463aa34d800689755671 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:29:03 +0100 Subject: [PATCH 21/35] ci: added rnaa to allowed words --- .github/actions/spelling/allow.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 8b812f17..9769f48e 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -24,6 +24,7 @@ shopify skia swm swmansion +rnaa tada vec From 4b3c1cca3a806b6f3309d622d88e271797d8fc9d Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Thu, 14 Nov 2024 19:32:37 +0100 Subject: [PATCH 22/35] refactor: yarn lint fixes --- packages/react-native-audio-api/common/cpp/core/PeriodicWave.h | 1 + .../react-native-audio-api/common/cpp/types/BiquadFilterType.h | 3 +-- packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp | 2 +- packages/react-native-audio-api/common/cpp/utils/FFTFrame.h | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 64c6edc0..0b6fca28 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -30,6 +30,7 @@ #include #include +#include #include "FFTFrame.h" #include "OscillatorType.h" diff --git a/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h index d9401584..a7e763e4 100644 --- a/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h +++ b/packages/react-native-audio-api/common/cpp/types/BiquadFilterType.h @@ -16,5 +16,4 @@ enum class BiquadFilterType { NOTCH, ALLPASS }; - -} +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index fa117fa4..a0dc4e28 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -26,7 +26,7 @@ void FFTFrame::forward(float *data) { void FFTFrame::inverse(float *data) { vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE); - vDSP_ztoc(&frame_, 1, (DSPComplex *)data, 2, size_ / 2); + vDSP_ztoc(&frame_, 1, reinterpret_castdata, 2, size_ / 2); // Scale the FFT data, beacuse of // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h index 6c988725..e94438a1 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -33,6 +33,8 @@ #endif #include +#include + #include "VectorMath.h" namespace audioapi { From f1fa8238750a29c108a1ac7273385bc8f3eeeada Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 15 Nov 2024 11:23:46 +0100 Subject: [PATCH 23/35] refactor: enhanced modulo operation, fixed small nitpicks and added comments --- .../common/cpp/core/OscillatorNode.cpp | 44 ++++++------- .../common/cpp/core/PeriodicWave.cpp | 66 +++++++------------ .../common/cpp/core/PeriodicWave.h | 29 ++++++-- .../common/cpp/utils/FFTFrame.cpp | 2 +- 4 files changed, 72 insertions(+), 69 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp index 704ea730..92e61156 100644 --- a/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp @@ -39,34 +39,34 @@ void OscillatorNode::setPeriodicWave( bool OscillatorNode::processAudio(float *audioData, int32_t numFrames) { if (!isPlaying_) { return false; - } else { - auto time = context_->getCurrentTime(); - auto deltaTime = 1.0 / context_->getSampleRate(); - - for (int i = 0; i < numFrames; ++i) { - auto detuneRatio = - std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f); - auto detunedFrequency = - round(frequencyParam_->getValueAtTime(time) * detuneRatio); - auto phaseIncrement = detunedFrequency * periodicWave_->getRateScale(); - - float sample = periodicWave_->getWaveTableElement( - detunedFrequency, phase_, phaseIncrement); + } - for (int j = 0; j < channelCount_; j++) { - audioData[i * channelCount_ + j] = sample; - } + auto time = context_->getCurrentTime(); + auto deltaTime = 1.0 / context_->getSampleRate(); - phase_ += phaseIncrement; + for (int i = 0; i < numFrames; ++i) { + auto detuneRatio = + std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f); + auto detunedFrequency = + round(frequencyParam_->getValueAtTime(time) * detuneRatio); + auto phaseIncrement = detunedFrequency * periodicWave_->getScale(); - if (phase_ >= static_cast(periodicWave_->getPeriodicWaveSize())) { - phase_ -= static_cast(periodicWave_->getPeriodicWaveSize()); - } + float sample = + periodicWave_->getSample(detunedFrequency, phase_, phaseIncrement); - time += deltaTime; + for (int j = 0; j < channelCount_; j++) { + audioData[i * channelCount_ + j] = sample; } - return true; + phase_ += phaseIncrement; + phase_ -= + floor( + phase_ / static_cast(periodicWave_->getPeriodicWaveSize())) * + static_cast(periodicWave_->getPeriodicWaveSize()); + + time += deltaTime; } + + return true; } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index b3a1a89e..002418d2 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -28,12 +28,8 @@ #include "PeriodicWave.h" -// The number of bands per octave. Each octave will have this many entries in -// the wave tables. constexpr unsigned NumberOfOctaveBands = 3; - constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands; - constexpr float interpolate2Point = 0.3; constexpr float interpolate3Point = 0.16; @@ -42,13 +38,10 @@ PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { numberOfRanges_ = lround( NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); auto nyquistFrequency = sampleRate_ / 2; - lowestFundamentalFrequency_ = static_cast(nyquistFrequency) / static_cast(getMaxNumberOfPartials()); - - rateScale_ = static_cast(getPeriodicWaveSize()) / + scale_ = static_cast(getPeriodicWaveSize()) / static_cast(sampleRate_); - bandLimitedTables_ = new float *[numberOfRanges_]; } @@ -78,11 +71,11 @@ int PeriodicWave::getPeriodicWaveSize() const { return 16384; } -float PeriodicWave::getRateScale() const { - return rateScale_; +float PeriodicWave::getScale() const { + return scale_; } -float PeriodicWave::getWaveTableElement( +float PeriodicWave::getSample( float fundamentalFrequency, float bufferIndex, float phaseIncrement) { @@ -118,10 +111,6 @@ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const { return numberOfPartials; } -// This function generates real and imaginary parts of the waveTable, -// real and imaginary arrays represent the coefficients of the harmonic -// components in the frequency domain, specifically as part of a complex -// representation used by Fourier Transform methods to describe signals. void PeriodicWave::generateBasicWaveForm(OscillatorType type) { auto fftSize = getPeriodicWaveSize(); /* @@ -161,20 +150,20 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { break; case OscillatorType::SQUARE: // https://mathworld.wolfram.com/FourierSeriesSquareWave.html - b = (i % 2 == 1) ? 4 * piFactor : 0.0f; + b = ((i & 1) == 1) ? 4 * piFactor : 0.0f; break; case OscillatorType::SAWTOOTH: // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our - // function differs from this one, but coefficients calculation looks + // Function differs from this one, but coefficients calculation looks // similar. our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) + // 0.5))); // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B - b = 2 * piFactor * (i % 2 == 1 ? 1.0f : -1.0f); + b = 2 * piFactor * ((i & 1) == 1 ? 1.0f : -1.0f); break; case OscillatorType::TRIANGLE: // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html - if (i % 2 == 1) { - b = 8.0f * piFactor * piFactor * (i % 4 == 1 ? 1.0f : -1.0f); + if ((i & 1) == 1) { + b = 8.0f * piFactor * piFactor * ((i & 3) == 1 ? 1.0f : -1.0f); } else { b = 0.0f; } @@ -214,7 +203,7 @@ void PeriodicWave::createBandLimitedTables( imaginaryFFTFrameData, size); - // Find the starting bin where we should start culling. + // Find the starting partial where we should start culling. // We need to clear out the highest frequencies to band-limit the waveform. auto numberOfPartials = getNumberOfPartialsPerRange(rangeIndex); @@ -235,6 +224,9 @@ void PeriodicWave::createBandLimitedTables( imaginaryFFTFrameData[0] = 0.0f; bandLimitedTables_[rangeIndex] = new float[fftSize]; + + // Perform the inverse FFT to get the time domain representation of the + // band-limited waveform. fftFrame.inverse(bandLimitedTables_[rangeIndex]); VectorMath::multiplyByScalar( @@ -286,28 +278,19 @@ float PeriodicWave::doInterpolation( float lowerWaveDataSample = 0; float higherWaveDataSample = 0; - // Consider a typical sample rate of 44100 Hz and max periodic wave - // size of 4096. The relationship between |phaseIncrement| and the frequency - // of the oscillator is |phaseIncrement| = freq * 4096/44100. Or freq = - // |phaseIncrement|*44100/4096 = 10.8*|phaseIncrement|. - // - // For the |phaseIncrement| thresholds below, this means that we use linear - // interpolation for all freq >= 3.2 Hz, 3-point Lagrange - // for freq >= 1.7 Hz and 5-point Lagrange for every thing else. - // - // We use Lagrange interpolation because it's relatively simple to - // implement and fairly inexpensive, and the interpolator always - // passes through known points. - // https://dlmf.nist.gov/3.3#ii + // We use linear, 3-point Lagrange, or 5-point Lagrange interpolation based on + // the value of phase increment. https://dlmf.nist.gov/3.3#ii int index = static_cast(bufferIndex); auto factor = bufferIndex - static_cast(index); - if (phaseIncrement >= interpolate2Point) { + if (phaseIncrement >= interpolate2Point) { // linear interpolation int indices[2]; for (int i = 0; i < 2; i++) { - indices[i] = (index + i) % getPeriodicWaveSize(); + indices[i] = (index + i) & + (getPeriodicWaveSize() - + 1); // more efficient alternative to % getPeriodicWaveSize() } auto lowerWaveDataSample1 = lowerWaveData[indices[0]]; @@ -319,12 +302,12 @@ float PeriodicWave::doInterpolation( (1 - factor) * lowerWaveDataSample1 + factor * lowerWaveDataSample2; higherWaveDataSample = (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2; - } else if (phaseIncrement >= interpolate3Point) { + } else if (phaseIncrement >= interpolate3Point) { // 3-point Lagrange + // interpolation int indices[3]; for (int i = 0; i < 3; i++) { - indices[i] = - (index + i - 1 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + indices[i] = (index + i - 1) & (getPeriodicWaveSize() - 1); } float A[3]; @@ -337,12 +320,11 @@ float PeriodicWave::doInterpolation( lowerWaveDataSample += lowerWaveData[indices[i]] * A[i]; higherWaveDataSample += higherWaveData[indices[i]] * A[i]; } - } else { + } else { // 5-point Lagrange interpolation int indices[5]; for (int i = 0; i < 5; i++) { - indices[i] = - (index + i - 2 + getPeriodicWaveSize()) % getPeriodicWaveSize(); + indices[i] = (index + i - 2) & (getPeriodicWaveSize() - 1); } float A[5]; diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 0b6fca28..adaee9ce 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -28,9 +28,9 @@ #pragma once +#include #include #include -#include #include "FFTFrame.h" #include "OscillatorType.h" @@ -47,9 +47,9 @@ class PeriodicWave { int length); [[nodiscard]] int getPeriodicWaveSize() const; - [[nodiscard]] float getRateScale() const; + [[nodiscard]] float getScale() const; - float getWaveTableElement( + float getSample( float fundamentalFrequency, float bufferIndex, float phaseIncrement); @@ -57,20 +57,41 @@ class PeriodicWave { private: explicit PeriodicWave(int sampleRate); + // Partial is any frequency component of a sound. + // Both harmonics(fundamentalFrequency * k) and overtones are partials. [[nodiscard]] int getMaxNumberOfPartials() const; + // Returns the number of partials to keep for a given range. + // Controlling the number of partials in each range allows for a more + // efficient representation of the waveform and prevents aliasing. [[nodiscard]] int getNumberOfPartialsPerRange(int rangeIndex) const; + // This function generates real and imaginary parts of the waveTable, + // real and imaginary arrays represent the coefficients of the harmonic + // components in the frequency domain, specifically as part of a complex + // representation used by Fourier Transform methods to describe signals. void generateBasicWaveForm(OscillatorType type); + // This function creates band-limited tables for the given real and + // imaginary data. The tables are created for each range of the partials. + // The higher frequencies are culled to band-limit the waveform. + // For each range, the inverse FFT is performed to get the time domain + // representation of the band-limited waveform. void createBandLimitedTables(const float *real, const float *imaginary, int size); + // This function returns the interpolation factor between the lower and higher + // range data and sets the lower and higher wave data for the given + // fundamental frequency. float getWaveDataForFundamentalFrequency( float fundamentalFrequency, float *&lowerWaveData, float *&higherWaveData); + // This function performs interpolation between the lower and higher range + // data based on the interpolation factor and current buffer index. Type of + // interpolation is determined by the phase increment. Returns the + // interpolated sample. float doInterpolation( float bufferIndex, float phaseIncrement, @@ -87,7 +108,7 @@ class PeriodicWave { float lowestFundamentalFrequency_; // scaling factor used to adjust size of period of waveform to the sample // rate. - float rateScale_; + float scale_; // array of band-limited waveforms. float **bandLimitedTables_; }; diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp index a0dc4e28..a75be51f 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.cpp @@ -26,7 +26,7 @@ void FFTFrame::forward(float *data) { void FFTFrame::inverse(float *data) { vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE); - vDSP_ztoc(&frame_, 1, reinterpret_castdata, 2, size_ / 2); + vDSP_ztoc(&frame_, 1, reinterpret_cast(data), 2, size_ / 2); // Scale the FFT data, beacuse of // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892 From dbd512c31a916ce46e6dde8c12a4e8661d1c8988 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 15 Nov 2024 11:46:36 +0100 Subject: [PATCH 24/35] fix: fixed interfaces and errors connected with PeriodicWave --- .../src/core/BaseAudioContext.ts | 11 +++++++---- .../react-native-audio-api/src/core/OscillatorNode.ts | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/react-native-audio-api/src/core/BaseAudioContext.ts b/packages/react-native-audio-api/src/core/BaseAudioContext.ts index 524b05e8..d3ff524a 100644 --- a/packages/react-native-audio-api/src/core/BaseAudioContext.ts +++ b/packages/react-native-audio-api/src/core/BaseAudioContext.ts @@ -7,7 +7,8 @@ import StereoPannerNode from './StereoPannerNode'; import BiquadFilterNode from './BiquadFilterNode'; import AudioBufferSourceNode from './AudioBufferSourceNode'; import AudioBuffer from './AudioBuffer'; -import { RangeError } from '../errors'; +import PeriodicWave from './PeriodicWave'; +import { InvalidAccessError } from '../errors'; export default class BaseAudioContext { readonly destination: AudioDestinationNode; @@ -82,13 +83,15 @@ export default class BaseAudioContext { constraints?: PeriodicWaveConstraints ): PeriodicWave { if (real.length !== imag.length) { - throw new RangeError( - `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays are different` + throw new InvalidAccessError( + `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays must match.` ); } const disableNormalization = constraints?.disableNormalization ?? false; - return this.context.createPeriodicWave(real, imag, disableNormalization); + return new PeriodicWave( + this.context.createPeriodicWave(real, imag, disableNormalization) + ); } } diff --git a/packages/react-native-audio-api/src/core/OscillatorNode.ts b/packages/react-native-audio-api/src/core/OscillatorNode.ts index e53e6b4f..3122ab98 100644 --- a/packages/react-native-audio-api/src/core/OscillatorNode.ts +++ b/packages/react-native-audio-api/src/core/OscillatorNode.ts @@ -24,7 +24,7 @@ export default class OscillatorNode extends AudioScheduledSourceNode { public set type(value: OscillatorType) { if (value === 'custom') { throw new InvalidStateError( - "The type can't be set to custom. You need to call setPeriodicWave() instead in order to define a custom waveform." + "'type' cannot be set directly to 'custom'. Use setPeriodicWave() to create a custom Oscillator type." ); } From c14d4c803a10425fc1926109aadce45e7a48c69b Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 15 Nov 2024 12:01:29 +0100 Subject: [PATCH 25/35] feat: added disableNormalization PeriodicWave constraint --- .../common/cpp/core/BaseAudioContext.cpp | 15 +++++++---- .../common/cpp/core/PeriodicWave.cpp | 27 ++++++++++++++----- .../common/cpp/core/PeriodicWave.h | 12 ++++++--- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp index dad8f3de..43e01e38 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp @@ -75,7 +75,8 @@ std::shared_ptr BaseAudioContext::createPeriodicWave( bool disableNormalization, int length) { // add normalization - return std::make_shared(sampleRate_, real, imag, length); + return std::make_shared( + sampleRate_, real, imag, length, disableNormalization); } std::function BaseAudioContext::renderAudio() { @@ -93,22 +94,26 @@ std::shared_ptr BaseAudioContext::getBasicWaveForm( switch (type) { case OscillatorType::SINE: if (cachedSineWave_ == nullptr) { - cachedSineWave_ = std::make_shared(sampleRate_, type); + cachedSineWave_ = + std::make_shared(sampleRate_, type, false); } return cachedSineWave_; case OscillatorType::SQUARE: if (cachedSquareWave_ == nullptr) { - cachedSquareWave_ = std::make_shared(sampleRate_, type); + cachedSquareWave_ = + std::make_shared(sampleRate_, type, false); } return cachedSquareWave_; case OscillatorType::SAWTOOTH: if (cachedSawtoothWave_ == nullptr) { - cachedSawtoothWave_ = std::make_shared(sampleRate_, type); + cachedSawtoothWave_ = + std::make_shared(sampleRate_, type, false); } return cachedSawtoothWave_; case OscillatorType::TRIANGLE: if (cachedTriangleWave_ == nullptr) { - cachedTriangleWave_ = std::make_shared(sampleRate_, type); + cachedTriangleWave_ = + std::make_shared(sampleRate_, type, false); } return cachedTriangleWave_; case OscillatorType::CUSTOM: diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 002418d2..75e61514 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -34,7 +34,8 @@ constexpr float interpolate2Point = 0.3; constexpr float interpolate3Point = 0.16; namespace audioapi { -PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { +PeriodicWave::PeriodicWave(int sampleRate, bool disableNormalization) + : sampleRate_(sampleRate), disableNormalization_(disableNormalization) { numberOfRanges_ = lround( NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))); auto nyquistFrequency = sampleRate_ / 2; @@ -45,8 +46,11 @@ PeriodicWave::PeriodicWave(int sampleRate) : sampleRate_(sampleRate) { bandLimitedTables_ = new float *[numberOfRanges_]; } -PeriodicWave::PeriodicWave(int sampleRate, audioapi::OscillatorType type) - : PeriodicWave(sampleRate) { +PeriodicWave::PeriodicWave( + int sampleRate, + audioapi::OscillatorType type, + bool disableNormalization) + : PeriodicWave(sampleRate, disableNormalization) { this->generateBasicWaveForm(type); } @@ -54,8 +58,9 @@ PeriodicWave::PeriodicWave( int sampleRate, float *real, float *imaginary, - int length) - : PeriodicWave(sampleRate) { + int length, + bool disableNormalization) + : PeriodicWave(sampleRate, disableNormalization) { createBandLimitedTables(real, imaginary, length); } @@ -183,6 +188,8 @@ void PeriodicWave::createBandLimitedTables( const float *realData, const float *imaginaryData, int size) { + float normalizationFactor = 0.5f; + auto fftSize = getPeriodicWaveSize(); auto halfSize = fftSize / 2; @@ -229,9 +236,17 @@ void PeriodicWave::createBandLimitedTables( // band-limited waveform. fftFrame.inverse(bandLimitedTables_[rangeIndex]); + if (!disableNormalization_ && rangeIndex == 0) { + float maxValue = + VectorMath::maximumMagnitude(bandLimitedTables_[rangeIndex], fftSize); + if (maxValue != 0) { + normalizationFactor = 1.0f / maxValue; + } + } + VectorMath::multiplyByScalar( bandLimitedTables_[rangeIndex], - 0.5f, + normalizationFactor, bandLimitedTables_[rangeIndex], fftSize); } diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index adaee9ce..90bd3119 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -39,12 +39,16 @@ namespace audioapi { class PeriodicWave { public: - explicit PeriodicWave(int sampleRate, OscillatorType type); + explicit PeriodicWave( + int sampleRate, + OscillatorType type, + bool disableNormalization); explicit PeriodicWave( int sampleRate, float *real, float *imaginary, - int length); + int length, + bool disableNormalization); [[nodiscard]] int getPeriodicWaveSize() const; [[nodiscard]] float getScale() const; @@ -55,7 +59,7 @@ class PeriodicWave { float phaseIncrement); private: - explicit PeriodicWave(int sampleRate); + explicit PeriodicWave(int sampleRate, bool disableNormalization); // Partial is any frequency component of a sound. // Both harmonics(fundamentalFrequency * k) and overtones are partials. @@ -111,5 +115,7 @@ class PeriodicWave { float scale_; // array of band-limited waveforms. float **bandLimitedTables_; + // if true, the waveTable is not normalized. + bool disableNormalization_; }; } // namespace audioapi From 869dd64b9fe5d07ec9fd7be1f868919573121f6b Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 15 Nov 2024 12:06:45 +0100 Subject: [PATCH 26/35] fix: removed commented code --- packages/react-native-audio-api/common/cpp/utils/FFTFrame.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h index e94438a1..1c4bc7bb 100644 --- a/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h +++ b/packages/react-native-audio-api/common/cpp/utils/FFTFrame.h @@ -42,8 +42,6 @@ namespace audioapi { class FFTFrame { public: explicit FFTFrame(int size); - // FFTFrame(const FFTFrame& frame); - // ~FFTFrame(); [[nodiscard]] float *getRealData() const { return realData_; From 4b41abff127df72f39a4fe3d5e5e9b567cb0eeff Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 15 Nov 2024 14:19:56 +0100 Subject: [PATCH 27/35] refactor: changed bufferIndex param name to phase --- .../common/cpp/core/PeriodicWave.cpp | 10 +++++----- .../common/cpp/core/PeriodicWave.h | 6 ++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp index 75e61514..ace8d2e5 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.cpp @@ -82,7 +82,7 @@ float PeriodicWave::getScale() const { float PeriodicWave::getSample( float fundamentalFrequency, - float bufferIndex, + float phase, float phaseIncrement) { float *lowerWaveData = nullptr; float *higherWaveData = nullptr; @@ -91,7 +91,7 @@ float PeriodicWave::getSample( fundamentalFrequency, lowerWaveData, higherWaveData); return doInterpolation( - bufferIndex, + phase, phaseIncrement, interpolationFactor, lowerWaveData, @@ -285,7 +285,7 @@ float PeriodicWave::getWaveDataForFundamentalFrequency( } float PeriodicWave::doInterpolation( - float bufferIndex, + float phase, float phaseIncrement, float waveTableInterpolationFactor, const float *lowerWaveData, @@ -296,8 +296,8 @@ float PeriodicWave::doInterpolation( // We use linear, 3-point Lagrange, or 5-point Lagrange interpolation based on // the value of phase increment. https://dlmf.nist.gov/3.3#ii - int index = static_cast(bufferIndex); - auto factor = bufferIndex - static_cast(index); + int index = static_cast(phase); + auto factor = phase - static_cast(index); if (phaseIncrement >= interpolate2Point) { // linear interpolation int indices[2]; diff --git a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h index 90bd3119..620179f5 100644 --- a/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/core/PeriodicWave.h @@ -53,10 +53,8 @@ class PeriodicWave { [[nodiscard]] int getPeriodicWaveSize() const; [[nodiscard]] float getScale() const; - float getSample( - float fundamentalFrequency, - float bufferIndex, - float phaseIncrement); + float + getSample(float fundamentalFrequency, float phase, float phaseIncrement); private: explicit PeriodicWave(int sampleRate, bool disableNormalization); From 11543f58ed7e6662c8c0459700cd6573e52ac701 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Fri, 22 Nov 2024 12:18:27 +0100 Subject: [PATCH 28/35] feat: added kfr lib but it does not work --- .gitignore | 3 +- .../android/CMakeLists.txt | 11 +- .../android/src/main/include/kfr/all.hpp | 67 + .../android/src/main/include/kfr/base.hpp | 46 + .../include/kfr/base/basic_expressions.hpp | 1078 ++++++++ .../src/main/include/kfr/base/conversion.hpp | 287 +++ .../src/main/include/kfr/base/endianness.hpp | 47 + .../src/main/include/kfr/base/expression.hpp | 946 +++++++ .../src/main/include/kfr/base/filter.hpp | 149 ++ .../src/main/include/kfr/base/fraction.hpp | 152 ++ .../src/main/include/kfr/base/generators.hpp | 332 +++ .../src/main/include/kfr/base/handle.hpp | 412 +++ .../include/kfr/base/impl/static_array.hpp | 237 ++ .../main/include/kfr/base/inline_vector.hpp | 131 + .../include/kfr/base/math_expressions.hpp | 516 ++++ .../src/main/include/kfr/base/memory.hpp | 29 + .../android/src/main/include/kfr/base/npy.hpp | 494 ++++ .../src/main/include/kfr/base/random.hpp | 242 ++ .../src/main/include/kfr/base/random_bits.hpp | 127 + .../src/main/include/kfr/base/reduce.hpp | 423 ++++ .../src/main/include/kfr/base/shape.hpp | 943 +++++++ .../include/kfr/base/simd_expressions.hpp | 489 ++++ .../main/include/kfr/base/small_buffer.hpp | 115 + .../main/include/kfr/base/state_holder.hpp | 67 + .../src/main/include/kfr/base/tensor.hpp | 1005 ++++++++ .../src/main/include/kfr/base/transpose.hpp | 644 +++++ .../src/main/include/kfr/base/univector.hpp | 714 ++++++ .../android/src/main/include/kfr/capi.h | 718 ++++++ .../android/src/main/include/kfr/cident.h | 756 ++++++ .../android/src/main/include/kfr/cometa.hpp | 2250 +++++++++++++++++ .../src/main/include/kfr/cometa/array.hpp | 77 + .../src/main/include/kfr/cometa/cstring.hpp | 166 ++ .../src/main/include/kfr/cometa/ctti.hpp | 121 + .../src/main/include/kfr/cometa/function.hpp | 157 ++ .../src/main/include/kfr/cometa/memory.hpp | 302 +++ .../src/main/include/kfr/cometa/named_arg.hpp | 35 + .../src/main/include/kfr/cometa/numeric.hpp | 191 ++ .../src/main/include/kfr/cometa/range.hpp | 72 + .../src/main/include/kfr/cometa/result.hpp | 52 + .../src/main/include/kfr/cometa/string.hpp | 700 +++++ .../src/main/include/kfr/cometa/tuple.hpp | 46 + .../android/src/main/include/kfr/config.h | 0 .../android/src/main/include/kfr/dft.hpp | 30 + .../src/main/include/kfr/dft/cache.hpp | 172 ++ .../src/main/include/kfr/dft/convolution.hpp | 151 ++ .../android/src/main/include/kfr/dft/fft.hpp | 821 ++++++ .../main/include/kfr/dft/reference_dft.hpp | 205 ++ .../android/src/main/include/kfr/dsp.hpp | 44 + .../src/main/include/kfr/dsp/biquad.hpp | 516 ++++ .../main/include/kfr/dsp/biquad_design.hpp | 249 ++ .../src/main/include/kfr/dsp/dcremove.hpp | 41 + .../src/main/include/kfr/dsp/delay.hpp | 220 ++ .../android/src/main/include/kfr/dsp/ebu.hpp | 364 +++ .../android/src/main/include/kfr/dsp/fir.hpp | 429 ++++ .../src/main/include/kfr/dsp/fir_design.hpp | 222 ++ .../src/main/include/kfr/dsp/goertzel.hpp | 140 + .../android/src/main/include/kfr/dsp/iir.hpp | 28 + .../src/main/include/kfr/dsp/iir_design.hpp | 1262 +++++++++ .../src/main/include/kfr/dsp/mixdown.hpp | 81 + .../src/main/include/kfr/dsp/oscillators.hpp | 284 +++ .../kfr/dsp/sample_rate_conversion.hpp | 342 +++ .../src/main/include/kfr/dsp/speaker.hpp | 97 + .../src/main/include/kfr/dsp/special.hpp | 88 + .../src/main/include/kfr/dsp/units.hpp | 206 ++ .../src/main/include/kfr/dsp/waveshaper.hpp | 96 + .../src/main/include/kfr/dsp/weighting.hpp | 136 + .../src/main/include/kfr/dsp/window.hpp | 644 +++++ .../android/src/main/include/kfr/except.hpp | 97 + .../android/src/main/include/kfr/io.hpp | 30 + .../src/main/include/kfr/io/audiofile.hpp | 276 ++ .../android/src/main/include/kfr/io/file.hpp | 307 +++ .../src/main/include/kfr/io/python_plot.hpp | 184 ++ .../src/main/include/kfr/io/tostring.hpp | 178 ++ .../android/src/main/include/kfr/kfr.h | 117 + .../android/src/main/include/kfr/math.hpp | 38 + .../src/main/include/kfr/math/asin_acos.hpp | 53 + .../src/main/include/kfr/math/atan.hpp | 74 + .../src/main/include/kfr/math/compiletime.hpp | 84 + .../main/include/kfr/math/complex_math.hpp | 339 +++ .../src/main/include/kfr/math/gamma.hpp | 81 + .../src/main/include/kfr/math/hyperbolic.hpp | 79 + .../main/include/kfr/math/impl/asin_acos.hpp | 58 + .../src/main/include/kfr/math/impl/atan.hpp | 227 ++ .../src/main/include/kfr/math/impl/gamma.hpp | 71 + .../main/include/kfr/math/impl/hyperbolic.hpp | 99 + .../main/include/kfr/math/impl/log_exp.hpp | 336 +++ .../include/kfr/math/impl/modzerobessel.hpp | 104 + .../main/include/kfr/math/impl/sin_cos.hpp | 310 +++ .../src/main/include/kfr/math/impl/sqrt.hpp | 72 + .../src/main/include/kfr/math/impl/tan.hpp | 152 ++ .../main/include/kfr/math/interpolation.hpp | 74 + .../src/main/include/kfr/math/log_exp.hpp | 133 + .../main/include/kfr/math/modzerobessel.hpp | 41 + .../src/main/include/kfr/math/sin_cos.hpp | 195 ++ .../src/main/include/kfr/math/sqrt.hpp | 44 + .../android/src/main/include/kfr/math/tan.hpp | 47 + .../android/src/main/include/kfr/multiarch.h | 196 ++ .../android/src/main/include/kfr/runtime.hpp | 26 + .../src/main/include/kfr/runtime/cpuid.hpp | 313 +++ .../main/include/kfr/runtime/cpuid_auto.hpp | 69 + .../android/src/main/include/kfr/simd.hpp | 45 + .../android/src/main/include/kfr/simd/abs.hpp | 45 + .../src/main/include/kfr/simd/clamp.hpp | 51 + .../src/main/include/kfr/simd/comparison.hpp | 116 + .../src/main/include/kfr/simd/complex.hpp | 348 +++ .../main/include/kfr/simd/complex_type.hpp | 64 + .../src/main/include/kfr/simd/constants.hpp | 163 ++ .../main/include/kfr/simd/digitreverse.hpp | 118 + .../src/main/include/kfr/simd/horizontal.hpp | 155 ++ .../src/main/include/kfr/simd/impl/abs.hpp | 138 + .../main/include/kfr/simd/impl/backend.hpp | 79 + .../include/kfr/simd/impl/backend_clang.hpp | 195 ++ .../include/kfr/simd/impl/backend_generic.hpp | 1944 ++++++++++++++ .../kfr/simd/impl/basicoperators_clang.hpp | 184 ++ .../kfr/simd/impl/basicoperators_complex.hpp | 113 + .../kfr/simd/impl/basicoperators_generic.hpp | 1642 ++++++++++++ .../src/main/include/kfr/simd/impl/clamp.hpp | 55 + .../main/include/kfr/simd/impl/function.hpp | 335 +++ .../main/include/kfr/simd/impl/intrinsics.h | 55 + .../main/include/kfr/simd/impl/logical.hpp | 286 +++ .../main/include/kfr/simd/impl/min_max.hpp | 236 ++ .../main/include/kfr/simd/impl/operators.hpp | 97 + .../main/include/kfr/simd/impl/read_write.hpp | 402 +++ .../src/main/include/kfr/simd/impl/round.hpp | 282 +++ .../main/include/kfr/simd/impl/saturation.hpp | 205 ++ .../src/main/include/kfr/simd/impl/select.hpp | 331 +++ .../src/main/include/kfr/simd/impl/simd.hpp | 132 + .../kfr/simd/impl/specialconstants.hpp | 101 + .../include/kfr/simd/impl/specializations.hpp | 115 + .../src/main/include/kfr/simd/logical.hpp | 54 + .../src/main/include/kfr/simd/mask.hpp | 62 + .../src/main/include/kfr/simd/min_max.hpp | 75 + .../src/main/include/kfr/simd/operators.hpp | 651 +++++ .../src/main/include/kfr/simd/platform.hpp | 297 +++ .../src/main/include/kfr/simd/read_write.hpp | 321 +++ .../src/main/include/kfr/simd/round.hpp | 108 + .../src/main/include/kfr/simd/saturation.hpp | 51 + .../src/main/include/kfr/simd/select.hpp | 49 + .../src/main/include/kfr/simd/shuffle.hpp | 660 +++++ .../src/main/include/kfr/simd/sort.hpp | 103 + .../src/main/include/kfr/simd/types.hpp | 418 +++ .../android/src/main/include/kfr/simd/vec.hpp | 1638 ++++++++++++ .../src/main/include/kfr/testo/assert.hpp | 117 + .../src/main/include/kfr/testo/comparison.hpp | 249 ++ .../main/include/kfr/testo/console_colors.hpp | 166 ++ .../main/include/kfr/testo/double_double.hpp | 171 ++ .../src/main/include/kfr/testo/testo.hpp | 449 ++++ .../android/src/main/include/kfr/version.hpp | 40 + .../lib/cmake/kfr/KFRConfig-release.cmake | 239 ++ .../src/main/lib/cmake/kfr/KFRConfig.cmake | 285 +++ .../main/lib/cmake/kfr/KFRConfigVersion.cmake | 85 + .../android/src/main/lib/libkfr_dft_avx.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_avx2.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_avx512.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_neon.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_neon64.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_sse.a | Bin 0 -> 1332272 bytes .../android/src/main/lib/libkfr_dft_sse2.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_sse3.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_sse41.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_sse42.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dft_ssse3.a | Bin 0 -> 1290736 bytes .../android/src/main/lib/libkfr_dsp_avx.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_avx2.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_avx512.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_neon.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_neon64.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_sse.a | Bin 0 -> 1220096 bytes .../android/src/main/lib/libkfr_dsp_sse2.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_sse3.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_sse41.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_sse42.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_dsp_ssse3.a | Bin 0 -> 1120704 bytes .../android/src/main/lib/libkfr_io.a | Bin 0 -> 288144 bytes .../common/cpp/utils/FFTFrame.h | 2 + .../common/cpp/utils/android/FFTFrame.cpp | 66 + .../common/cpp/utils/{ => ios}/FFTFrame.cpp | 21 +- yarn.lock | 2058 +++------------ 178 files changed, 41425 insertions(+), 1763 deletions(-) create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/all.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/basic_expressions.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/conversion.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/endianness.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/expression.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/filter.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/fraction.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/generators.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/handle.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/impl/static_array.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/inline_vector.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/math_expressions.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/memory.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/npy.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/random.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/random_bits.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/reduce.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/shape.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/simd_expressions.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/small_buffer.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/state_holder.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/tensor.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/transpose.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/base/univector.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/capi.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cident.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/array.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/cstring.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/ctti.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/function.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/memory.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/named_arg.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/numeric.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/range.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/result.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/string.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/cometa/tuple.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/config.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dft.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dft/cache.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dft/convolution.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dft/fft.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dft/reference_dft.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad_design.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/dcremove.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/delay.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/ebu.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir_design.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/goertzel.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir_design.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/mixdown.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/oscillators.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/sample_rate_conversion.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/speaker.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/special.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/units.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/waveshaper.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/weighting.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/dsp/window.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/except.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/io.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/io/audiofile.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/io/file.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/io/python_plot.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/io/tostring.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/kfr.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/asin_acos.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/atan.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/compiletime.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/complex_math.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/gamma.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/hyperbolic.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/asin_acos.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/atan.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/gamma.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/hyperbolic.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/log_exp.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/modzerobessel.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sin_cos.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sqrt.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/impl/tan.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/interpolation.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/log_exp.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/modzerobessel.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/sin_cos.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/sqrt.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/math/tan.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/multiarch.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/runtime.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid_auto.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/abs.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/clamp.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/comparison.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/complex.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/complex_type.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/constants.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/digitreverse.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/horizontal.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/abs.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_clang.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_generic.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_clang.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_complex.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_generic.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/clamp.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/function.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/intrinsics.h create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/logical.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/min_max.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/operators.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/read_write.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/round.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/saturation.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/select.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/simd.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specialconstants.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specializations.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/logical.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/mask.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/min_max.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/operators.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/platform.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/read_write.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/round.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/saturation.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/select.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/shuffle.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/sort.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/types.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/simd/vec.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/testo/assert.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/testo/comparison.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/testo/console_colors.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/testo/double_double.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/testo/testo.hpp create mode 100644 packages/react-native-audio-api/android/src/main/include/kfr/version.hpp create mode 100644 packages/react-native-audio-api/android/src/main/lib/cmake/kfr/KFRConfig-release.cmake create mode 100644 packages/react-native-audio-api/android/src/main/lib/cmake/kfr/KFRConfig.cmake create mode 100644 packages/react-native-audio-api/android/src/main/lib/cmake/kfr/KFRConfigVersion.cmake create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_avx.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_avx2.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_avx512.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_neon.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_neon64.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_sse.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_sse2.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_sse3.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_sse41.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_sse42.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dft_ssse3.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_avx.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_avx2.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_avx512.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_neon.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_neon64.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_sse.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_sse2.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_sse3.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_sse41.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_sse42.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_dsp_ssse3.a create mode 100644 packages/react-native-audio-api/android/src/main/lib/libkfr_io.a create mode 100644 packages/react-native-audio-api/common/cpp/utils/android/FFTFrame.cpp rename packages/react-native-audio-api/common/cpp/utils/{ => ios}/FFTFrame.cpp (84%) diff --git a/.gitignore b/.gitignore index 98c802ac..4c060467 100644 --- a/.gitignore +++ b/.gitignore @@ -77,8 +77,7 @@ android/keystores/debug.keystore # Turborepo .turbo/ -# generated by bob -lib/ +packages/react-native-audio-api/lib # Android .kotlin diff --git a/packages/react-native-audio-api/android/CMakeLists.txt b/packages/react-native-audio-api/android/CMakeLists.txt index b16d4e14..eea6ed52 100644 --- a/packages/react-native-audio-api/android/CMakeLists.txt +++ b/packages/react-native-audio-api/android/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9.0) +cmake_minimum_required(VERSION 3.12.0) project(react-native-audio-api) set(CMAKE_VERBOSE_MAKEFILE ON) @@ -19,6 +19,8 @@ endif() include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake") add_compile_options(${folly_FLAGS}) +set(KFR_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/main/lib/cmake/kfr") + file(GLOB_RECURSE SOURCE_FILES "src/main/cpp/*.cpp" "src/main/cpp/*.h" @@ -50,7 +52,8 @@ target_include_directories( find_package(ReactAndroid REQUIRED CONFIG) find_package(fbjni REQUIRED CONFIG) -find_package (oboe REQUIRED CONFIG) +find_package(oboe REQUIRED CONFIG) +find_package(KFR REQUIRED) set(LINK_LIBRARIES ReactAndroid::jsi @@ -58,6 +61,9 @@ set(LINK_LIBRARIES android log oboe::oboe + KFR::kfr + KFR::kfr_dsp + KFR::kfr_dft ) if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76) @@ -73,4 +79,3 @@ else() endif() target_link_libraries(react-native-audio-api ${LINK_LIBRARIES} ${RN_VERSION_LINK_LIBRARIES}) - diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/all.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/all.hpp new file mode 100644 index 00000000..fde533d0 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/all.hpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ + +#include "base.hpp" +#include "dft.hpp" +#include "dsp.hpp" +#include "io.hpp" + +/** @defgroup cometa Cometa + * @brief Metaprogramming + */ + +/** @defgroup types Types + * @brief Core types + */ + +/** @defgroup expressions Expressions + * @brief Expressions + */ + +/** @defgroup shuffle Shuffle + * @brief Vector shuffle functions + */ + +/** @defgroup utility Utility + * @brief Utility classes and functions + */ + +/** @defgroup dft DFT + * @brief Fast Fourier Transform & Direct Fourier Transform + */ + +/** @defgroup dsp DSP + * @brief Filters and other DSP-related functions + */ + +/** @defgroup io IO + * @brief Input & Output + */ + +/** @defgroup math Math + * @brief Mathematical functions + */ + +/** @defgroup cpuid CPUID + * @brief CPU detection + */ diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base.hpp new file mode 100644 index 00000000..b6438081 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base.hpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "math.hpp" + +#include "base/basic_expressions.hpp" +#include "base/conversion.hpp" +#include "base/endianness.hpp" +#include "base/expression.hpp" +#include "base/filter.hpp" +#include "base/fraction.hpp" +#include "base/generators.hpp" +#include "base/handle.hpp" +#include "base/math_expressions.hpp" +#include "base/memory.hpp" +#include "base/random.hpp" +#include "base/random_bits.hpp" +#include "base/reduce.hpp" +#include "base/shape.hpp" +#include "base/simd_expressions.hpp" +#include "base/small_buffer.hpp" +#include "base/state_holder.hpp" +#include "base/tensor.hpp" +#include "base/transpose.hpp" +#include "base/univector.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/basic_expressions.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/basic_expressions.hpp new file mode 100644 index 00000000..51be7980 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/basic_expressions.hpp @@ -0,0 +1,1078 @@ +/** @addtogroup expressions + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "expression.hpp" + +namespace kfr +{ +// ---------------------------------------------------------------------------- + +template +struct expression_scalar +{ + T value; +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = 0; + + constexpr static shape<0> get_shape(const expression_scalar& self) { return {}; } + constexpr static shape<0> get_shape() { return {}; } +}; + +template +KFR_INTRINSIC expression_scalar scalar(T value) +{ + return { std::move(value) }; +} + +template +KFR_INTRINSIC expression_scalar zeros() +{ + return { static_cast(0) }; +} + +template +KFR_INTRINSIC expression_scalar ones() +{ + return { static_cast(1) }; +} + +inline namespace CMT_ARCH_NAME +{ +template +KFR_INTRINSIC vec get_elements(const expression_scalar& self, const shape<0>& index, + const axis_params&) +{ + return self.value; +} +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_counter +{ + T start; + T steps[Dims]; + + T back() const { return steps[Dims - 1]; } + T front() const { return steps[0]; } +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + + constexpr static shape get_shape(const expression_counter& self) + { + return shape(infinite_size); + } + constexpr static shape get_shape() { return shape(infinite_size); } +}; + +template +KFR_INTRINSIC expression_counter counter(T start = 0) +{ + return { static_cast(std::move(start)), { static_cast(1) } }; +} + +template > +KFR_INTRINSIC expression_counter counter(T start, Arg step, Args... steps) +{ + return { static_cast(std::move(start)), + { static_cast(std::move(step)), static_cast(std::move(steps))... } }; +} + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const expression_counter& self, const shape<1>& index, + const axis_params&) +{ + T acc = self.start; + acc += static_cast(index.back()) * self.back(); + return acc + enumerate(vec_shape(), self.back()); +} +template +KFR_INTRINSIC vec get_elements(const expression_counter& self, const shape& index, + const axis_params&) +{ + T acc = self.start; + vec tindices = cast(to_vec(index)); + cfor(csize<0>, csize, [&](auto i) CMT_INLINE_LAMBDA { acc += tindices[i] * self.steps[i]; }); + return acc + enumerate(vec_shape(), self.steps[Axis]); +} +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_slice : public expression_with_arguments +{ + constexpr static index_t dims = expression_dims; + static_assert(dims > 0); + shape start; + shape size; + + KFR_MEM_INTRINSIC expression_slice(Arg&& arg, shape start, shape size) + : expression_with_arguments{ std::forward(arg) }, start(start), size(size) + { + } +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = ArgTraits::dims; + constexpr static bool random_access = ArgTraits::random_access; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_slice& self) + { + return min(sub_shape(ArgTraits::get_shape(self.first()), self.start), self.size); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return shape(undefined_size); } +}; + +template > +KFR_INTRINSIC expression_slice slice(Arg&& arg, identity> start, + identity> size = shape(infinite_size)) +{ + static_assert(Dims > 0); + return { std::forward(arg), start, size }; +} + +template > +KFR_INTRINSIC expression_slice truncate(Arg&& arg, identity> size) +{ + static_assert(Dims > 0); + return { std::forward(arg), shape{ 0 }, size }; +} + +inline namespace CMT_ARCH_NAME +{ + +template >::value_type> +KFR_INTRINSIC vec get_elements(const expression_slice& self, const shape& index, + const axis_params& sh) +{ + return static_cast>(get_elements(self.first(), index.add(self.start), sh)); +} + +template * = nullptr, + typename T = typename expression_traits>::value_type> +KFR_INTRINSIC void set_elements(const expression_slice& self, const shape& index, + const axis_params& sh, const identity>& value) +{ + set_elements(self.first(), index.add(self.start), sh, value); +} +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_cast : public expression_with_arguments +{ + using expression_with_arguments::expression_with_arguments; +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = T; + constexpr static size_t dims = ArgTraits::dims; + constexpr static bool random_access = ArgTraits::random_access; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_cast& self) + { + return ArgTraits::get_shape(self.first()); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return ArgTraits::get_shape(); } +}; + +template +KFR_INTRINSIC expression_cast cast(Arg&& arg) +{ + return { std::forward(arg) }; +} + +template +KFR_INTRINSIC expression_cast cast(Arg&& arg, ctype_t) +{ + return { std::forward(arg) }; +} + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const expression_cast& self, const shape& index, + const axis_params& sh) +{ + return static_cast>(get_elements(self.first(), index, sh)); +} + +template +KFR_INTRINSIC void set_elements(const expression_cast& self, const shape& index, + const axis_params& sh, const identity>& value) +{ + set_elements(self.first(), index, sh, value); +} +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_lambda +{ + Fn fn; +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static inline bool random_access = Rnd; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_lambda& self) + { + return shape(infinite_size); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return shape(infinite_size); } +}; + +template +KFR_INTRINSIC expression_lambda lambda(Fn&& fn, cbool_t = {}) +{ + return { std::forward(fn) }; +} +template +KFR_INTRINSIC expression_lambda lambda_generator(Fn&& fn) +{ + return { std::forward(fn) }; +} + +template > +KFR_INTRINSIC auto sequence(const Ts&... list) +{ + return lambda([seq = std::array{ { static_cast(list)... } }](index_t index) { // + return seq[index % seq.size()]; + }); +} + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const expression_lambda& self, + const shape& index, const axis_params& sh) +{ + if constexpr (std::is_invocable_v, axis_params>) + return self.fn(index, sh); + else if constexpr (std::is_invocable_v, csize_t>) + return self.fn(index, csize); + else if constexpr (std::is_invocable_v>) + { + portable_vec result; + shape cur_index = index; + for (index_t i = 0; i < N; ++i) + { + result[i] = self.fn(cur_index); + ++cur_index.back(); + } + return result; + } + else if constexpr (std::is_invocable_v) + return apply(self.fn); + else + { + static_assert(std::is_invocable_v, axis_params> || + std::is_invocable_v, csize_t> || + std::is_invocable_v> || std::is_invocable_v, + "Lambda must be callable"); + return czeros; + } +} + +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_padded : public expression_with_arguments +{ + using ArgTraits = typename expression_with_arguments::first_arg_traits; + typename ArgTraits::value_type fill_value; + shape input_shape; + + KFR_MEM_INTRINSIC expression_padded(Arg&& arg, typename ArgTraits::value_type fill_value) + : expression_with_arguments{ std::forward(arg) }, fill_value(std::move(fill_value)), + input_shape(ArgTraits::get_shape(this->first())) + { + } +}; + +template > +KFR_INTRINSIC expression_padded padded(Arg&& arg, T fill_value = T{}) +{ + static_assert(expression_dims >= 1); + return { std::forward(arg), std::move(fill_value) }; +} + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = ArgTraits::dims; + constexpr static bool random_access = ArgTraits::random_access; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_padded& self) + { + return shape(infinite_size); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return shape(infinite_size); } +}; + +inline namespace CMT_ARCH_NAME +{ + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC vec get_elements(const expression_padded& self, const shape& index, + const axis_params& sh) +{ + if (index.ge(self.input_shape)) + { + return self.fill_value; + } + else if (CMT_LIKELY(index.add(N).le(self.input_shape))) + { + return get_elements(self.first(), index, sh); + } + else + { + vec x = self.fill_value; + for (size_t i = 0; i < N; i++) + { + shape ish = index.add(i); + if (ish.back() < self.input_shape.back()) + x[i] = get_elements(self.first(), ish, axis_params_v).front(); + } + return x; + } +} + +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_reverse : public expression_with_arguments +{ + using ArgTraits = typename expression_with_arguments::first_arg_traits; + shape input_shape; + + KFR_MEM_INTRINSIC expression_reverse(Arg&& arg) + : expression_with_arguments{ std::forward(arg) }, + input_shape(ArgTraits::get_shape(this->first())) + { + } +}; + +template +KFR_INTRINSIC expression_reverse reverse(Arg&& arg) +{ + static_assert(expression_dims >= 1); + return { std::forward(arg) }; +} + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = ArgTraits::dims; + static_assert(ArgTraits::random_access, "expression_reverse requires an expression with random access"); + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_reverse& self) + { + return ArgTraits::get_shape(self.first()); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return ArgTraits::get_shape(); } +}; + +inline namespace CMT_ARCH_NAME +{ + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC vec get_elements(const expression_reverse& self, const shape& index, + const axis_params& sh) +{ + return reverse(get_elements(self.first(), self.input_shape.sub(index).sub(shape(N)), sh)); +} + +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct fixed_shape_t +{ + constexpr fixed_shape_t() = default; + constexpr static shape get() { return { Values... }; } +}; + +template +constexpr inline fixed_shape_t fixed_shape{}; + +template +struct expression_fixshape : public expression_with_arguments +{ + using ArgTraits = typename expression_with_arguments::first_arg_traits; + + KFR_MEM_INTRINSIC expression_fixshape(Arg&& arg) + : expression_with_arguments{ std::forward(arg) } + { + } +}; + +template +KFR_INTRINSIC expression_fixshape> fixshape( + Arg&& arg, const fixed_shape_t&) +{ + return { std::forward(arg) }; +} + +template +struct expression_traits>> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = sizeof...(ShapeValues); // ArgTraits::dims; + constexpr static bool random_access = ArgTraits::random_access; + + KFR_MEM_INTRINSIC constexpr static shape get_shape( + const expression_fixshape>& self) + { + return fixed_shape_t::get(); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() + { + return fixed_shape_t::get(); + } +}; + +inline namespace CMT_ARCH_NAME +{ + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC vec get_elements(const expression_fixshape& self, + const shape& index, const axis_params& sh) +{ + using ArgTraits = expression_traits; + return get_elements(self.first(), index.template trim(), sh); +} + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC void set_elements(expression_fixshape& self, const shape& index, + const axis_params& sh, const identity>& value) +{ + using ArgTraits = expression_traits; + if constexpr (is_output_expression) + { + set_elements(self.first(), index.template trim(), sh, value); + } + else + { + } +} + +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_reshape : public expression_with_arguments +{ + using ArgTraits = typename expression_with_arguments::first_arg_traits; + shape in_shape; + shape out_shape; + + KFR_MEM_INTRINSIC expression_reshape(Arg&& arg, const shape& out_shape) + : expression_with_arguments{ std::forward(arg) }, in_shape(ArgTraits::get_shape(arg)), + out_shape(out_shape) + { + } +}; + +template +KFR_INTRINSIC expression_reshape reshape(Arg&& arg, const shape& out_shape) +{ + return { std::forward(arg), out_shape }; +} + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits = expression_traits; + + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = OutDims; + constexpr static bool random_access = ArgTraits::random_access; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const expression_reshape& self) + { + return self.out_shape; + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return shape{ undefined_size }; } +}; + +inline namespace CMT_ARCH_NAME +{ + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC vec get_elements(const expression_reshape& self, + const shape& index, const axis_params& sh) +{ + using ArgTraits = typename Traits::ArgTraits; + constexpr index_t indims = ArgTraits::dims; + if constexpr (N == 1) + { + const shape idx = self.in_shape.from_flat(self.out_shape.to_flat(index)); + return get_elements(self.first(), idx, axis_params{}); + } + else + { + const shape first_idx = self.in_shape.from_flat(self.out_shape.to_flat(index)); + const shape last_idx = + self.in_shape.from_flat(self.out_shape.to_flat(index.add_at(N - 1, cindex))); + + const shape diff_idx = last_idx.sub(first_idx); + + vec result; + bool done = false; + + if (diff_idx.sum() == N - 1) + { + cforeach(cvalseq_t{}, + [&](auto n) CMT_INLINE_LAMBDA + { + constexpr index_t axis = val_of({}); + if (!done && diff_idx[axis] == N - 1) + { + result = get_elements(self.first(), first_idx, axis_params{}); + done = true; + } + }); + } + + if (!done) + { + portable_vec tmp; + CMT_LOOP_NOUNROLL + for (size_t i = 0; i < N; ++i) + { + shape idx = index.add_at(i, cindex); + tmp[i] = get_elements(self.first(), self.in_shape.from_flat(self.out_shape.to_flat(idx)), + axis_params{}) + .front(); + } + result = tmp; + } + return result; + } +} + +template >, + typename T = typename Traits::value_type> +KFR_INTRINSIC void set_elements(expression_reshape& self, const shape& index, + const axis_params& sh, const identity>& value) +{ + using ArgTraits = typename Traits::ArgTraits; + constexpr index_t indims = ArgTraits::dims; + if constexpr (N == 1) + { + const shape idx = self.in_shape.from_flat(self.out_shape.to_flat(index)); + set_elements(self.first(), idx, axis_params{}, value); + } + else + { + const shape first_idx = self.in_shape.from_flat(self.out_shape.to_flat(index)); + const shape last_idx = + self.in_shape.from_flat(self.out_shape.to_flat(index.add_at(N - 1, cindex))); + + const shape diff_idx = last_idx.sub(first_idx); + + bool done = false; + + cforeach(cvalseq_t{}, + [&](auto n) CMT_INLINE_LAMBDA + { + constexpr index_t axis = val_of({}); + if (!done && diff_idx[axis] == N - 1) + { + set_elements(self.first(), first_idx, axis_params{}, value); + done = true; + } + }); + + if (!done) + { + CMT_LOOP_NOUNROLL + for (size_t i = 0; i < N; ++i) + { + set_elements(self.first(), + self.in_shape.from_flat(self.out_shape.to_flat(index.add_at(i, cindex))), + axis_params{}, vec{ value[i] }); + } + } + } +} + +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +struct symmetric_linspace_t +{ +}; +constexpr inline const symmetric_linspace_t symmetric_linspace{}; + +template +struct expression_linspace +{ + T start; + T stop; + index_t size; + bool endpoint; + T invsize; + + expression_linspace(T start, T stop, size_t size, bool endpoint = false) + : start(start), stop(stop), size(size), invsize(T(1.0) / T(endpoint ? size - 1 : size)) + { + } + + expression_linspace(symmetric_linspace_t, T symsize, size_t size, bool endpoint = false) + : expression_linspace(-symsize, +symsize, size, endpoint) + { + } +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = 1; + + constexpr static shape get_shape(const expression_linspace& self) + { + return shape(truncated ? self.size : infinite_size); + } + constexpr static shape get_shape() + { + return shape(truncated ? undefined_size : infinite_size); + } +}; + +/** @brief Returns evenly spaced numbers over a specified interval. + * + * @param start The starting value of the sequence + * @param stop The end value of the sequence. if ``endpoint`` is ``false``, the last value is excluded + * @param size Number of samples to generate + * @param endpoint If ``true``, ``stop`` is the last sample. Otherwise, it is not included + * @tparam truncated If ``true``, linspace returns exactly size elements, otherwise, returns infinite sequence + * @tparam precise No longer used since KFR5, calculations are always precise + */ +template >>> +KFR_INTRINSIC expression_linspace linspace(T1 start, T2 stop, size_t size, + bool endpoint = false, cbool_t = {}) +{ + return { static_cast(start), static_cast(stop), size, endpoint }; +} + +/** @brief Returns evenly spaced numbers over a specified interval. + * + * @param symsize The sequence will have interval [-symsize..symsize] + * @param size Number of samples to generate + * @tparam truncated If ``true``, linspace returns exactly size elements, otherwise, returns infinite sequence + * @tparam precise No longer used since KFR5, calculations are always precise + */ +template > +KFR_INTRINSIC expression_linspace symmlinspace(T symsize, size_t size, + cbool_t = {}) +{ + return { symmetric_linspace, static_cast(symsize), size, true }; +} + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const expression_linspace& self, const shape<1>& index, + const axis_params<0, N>&) +{ + using TI = itype; + return mix((enumerate(vec_shape()) + static_cast(static_cast(index.front()))) * self.invsize, + self.start, self.stop); +} +} // namespace CMT_ARCH_NAME + +// ---------------------------------------------------------------------------- + +template +struct expression_concatenate : public expression_with_arguments +{ + static_assert(expression_dims == expression_dims); + static_assert(std::is_same_v, expression_value_type>); + constexpr static index_t dims = expression_dims; + shape size1; + + KFR_MEM_INTRINSIC expression_concatenate(Arg1&& arg1, Arg2&& arg2) + : expression_with_arguments{ std::forward(arg1), std::forward(arg2) }, + size1(expression_traits::get_shape(arg1)) + { + } +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using ArgTraits1 = expression_traits; + using ArgTraits2 = expression_traits; + + using value_type = typename ArgTraits1::value_type; + constexpr static size_t dims = ArgTraits1::dims; + constexpr static bool random_access = ArgTraits1::random_access && ArgTraits2::random_access; + + KFR_INTRINSIC static shape concat_shape(const shape& sh1, const shape& sh2) + { + shape result = min(sh1, sh2); + shape sum = add_shape_undef(sh1, sh2); + result[ConcatAxis] = sum[ConcatAxis]; + return result; + } + + KFR_MEM_INTRINSIC constexpr static shape get_shape( + const expression_concatenate& self) + { + return concat_shape(ArgTraits1::get_shape(std::get<0>(self.args)), + ArgTraits2::get_shape(std::get<1>(self.args))); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() + { + return concat_shape(ArgTraits1::get_shape(), ArgTraits2::get_shape()); + } +}; + +template +KFR_INTRINSIC expression_concatenate concatenate(Arg1&& arg1, Arg2&& arg2) +{ + return { std::forward(arg1), std::forward(arg2) }; +} + +template +KFR_INTRINSIC expression_concatenate, ConcatAxis> +concatenate(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3) +{ + return { std::forward(arg1), { std::forward(arg2), std::forward(arg3) } }; +} + +inline namespace CMT_ARCH_NAME +{ + +template >::value_type> +KFR_INTRINSIC vec get_elements(const expression_concatenate& self, + const shape& index, const axis_params& sh) +{ + const shape size1 = self.size1; + constexpr index_t Naxis = ConcatAxis == Axis ? N : 1; + if (index[ConcatAxis] >= size1[ConcatAxis]) + { + shape index1 = index; + index1[ConcatAxis] -= size1[ConcatAxis]; + return get_elements(std::get<1>(self.args), index1, sh); + } + else if (CMT_LIKELY(index[ConcatAxis] + Naxis <= size1[ConcatAxis])) + { + return get_elements(std::get<0>(self.args), index, sh); + } + else // (index < size1) && (index + N > size1) + { + vec result; + // Here Axis == ConcatAxis + shape index1 = index; + for (index_t i = 0; i < size1[ConcatAxis] - index[ConcatAxis]; ++i) + { + result[i] = get_elements(std::get<0>(self.args), index1, axis_params{})[0]; + ++index1[ConcatAxis]; + } + index1[ConcatAxis] -= size1[ConcatAxis]; + for (index_t i = size1[ConcatAxis] - index[ConcatAxis]; i < N; ++i) + { + result[i] = get_elements(std::get<1>(self.args), index1, axis_params{})[0]; + ++index1[ConcatAxis]; + } + return result; + } +} + +// ---------------------------------------------------------------------------- + +template +using expression_pack = expression_make_function; + +template +KFR_INTRINSIC expression_pack pack(Args&&... args) +{ + return { std::forward(args)... }; +} + +namespace internal +{ +template >, size_t... Indices> +KFR_INTRINSIC void set_elements_packed(expression_function& self, + shape index, axis_params sh, + const vec& x, csizes_t) +{ + constexpr size_t count = sizeof...(Args); + using ST = subtype; + const vec, count> xx = vec, count>::from_flatten(transpose(flatten(x))); + (set_elements(std::get(self.args), index, sh, xx[Indices]), ...); +} +} // namespace internal + +template >> +KFR_INTRINSIC void set_elements(expression_function& self, shape index, + axis_params sh, const identity>& x) +{ + internal::set_elements_packed(self, index, sh, x, csizeseq); +} + +// ---------------------------------------------------------------------------- + +template +struct expression_unpack : expression_with_arguments, expression_traits_defaults +{ + constexpr static size_t count = sizeof...(E); + + using first_arg_traits = typename expression_with_arguments::first_arg_traits; + + constexpr static index_t dims = first_arg_traits::dims; + using first_value_type = typename first_arg_traits::value_type; + + using value_type = vec; + + static_assert(((expression_dims == dims) && ...)); + static_assert(((std::is_same_v, first_value_type>)&&...)); + + constexpr static shape get_shape(const expression_unpack& self) + { + return first_arg_traits::get_shape(self.first()); + } + constexpr static shape get_shape() { return first_arg_traits::get_shape(); } + + expression_unpack(E&&... e) : expression_with_arguments(std::forward(e)...) {} + + template + KFR_INTRINSIC friend void set_elements(expression_unpack& self, shape index, + axis_params sh, const identity>& x) + { + self.output(index, sh, x, csizeseq); + } + + template + KFR_MEM_INTRINSIC expression_unpack& operator=(Input&& input) + { + process(*this, std::forward(input)); + return *this; + } + +private: + template + KFR_MEM_INTRINSIC void output(shape index, axis_params sh, const vec& x, + csizes_t) + { + const vec, count> xx = + vec, count>::from_flatten(transpose(flatten(x))); + (set_elements(std::get(this->args), index, sh, xx[indices]), ...); + } +}; + +// ---------------------------------------------------------------------------- + +template * = nullptr> +KFR_FUNCTION expression_unpack unpack(E&&... e) +{ + return { std::forward(e)... }; +} + +// ---------------------------------------------------------------------------- + +template +struct expression_adjacent : expression_with_traits +{ + using value_type = typename expression_with_traits::value_type; + constexpr static inline index_t dims = expression_with_traits::dims; + constexpr static inline bool random_access = false; + + expression_adjacent(Fn&& fn, E&& e) + : expression_with_traits(std::forward(e)), fn(std::forward(fn)) + { + } + + template + KFR_INTRINSIC friend vec get_elements(const expression_adjacent& self, shape index, + axis_params sh) + { + const vec in = get_elements(self.first(), index, sh); + const vec delayed = insertleft(self.data, in); + self.data = in.back(); + return self.fn(in, delayed); + } + Fn fn; + mutable value_type data = value_type(0); +}; + +/** + * @brief Returns template expression that returns the result of calling \f$ fn(x_i, x_{i-1}) \f$ + */ +template +KFR_INTRINSIC expression_adjacent adjacent(Fn&& fn, E1&& e1) +{ + return { std::forward(fn), std::forward(e1) }; +} + +// ---------------------------------------------------------------------------- + +template +struct expression_trace : public expression_with_traits +{ + using expression_with_traits::expression_with_traits; + using value_type = typename expression_with_traits::value_type; + constexpr static inline index_t dims = expression_with_traits::dims; + + template + KFR_INTRINSIC friend vec get_elements(const expression_trace& self, shape index, + axis_params sh) + { + const vec in = get_elements(self.first(), index, sh); + println("[", cometa::fmt<'s', 16>(array_to_string(dims, index.data(), INT_MAX, INT_MAX, ",", "", "")), + "] = ", in); + return in; + } +}; + +/** + * @brief Returns template expression that prints all processed values for debug + */ +template +KFR_INTRINSIC expression_trace trace(E1&& e1) +{ + return { std::forward(e1) }; +} + +// ---------------------------------------------------------------------------- + +template +struct expression_dimensions : public expression_with_traits +{ + using expression_with_traits::expression_with_traits; + using value_type = typename expression_with_traits::value_type; + constexpr static inline index_t in_dims = expression_with_traits::dims; + constexpr static inline index_t dims = Dims; + using first_arg_traits = typename expression_with_traits::first_arg_traits; + + constexpr static shape get_shape(const expression_dimensions& self) + { + return first_arg_traits::get_shape(self.first()).template extend(infinite_size); + } + constexpr static shape get_shape() + { + return first_arg_traits::get_shape().template extend(infinite_size); + } + + template + KFR_INTRINSIC friend vec get_elements(const expression_dimensions& self, shape index, + axis_params sh) + { + shape inindex = index.template trim(); + if constexpr (VecAxis >= in_dims) + { + return repeat(get_elements(self.first(), inindex, axis_params_v<0, 1>)); + } + else + { + return get_elements(self.first(), inindex, sh); + } + } +}; + +/** + * @brief Returns template expression with gien number of dimensions + */ +template +KFR_INTRINSIC expression_dimensions dimensions(E1&& e1) +{ + static_assert(Dims >= expression_dims, "Number of dimensions must be greater or equal"); + return { std::forward(e1) }; +} + +// ---------------------------------------------------------------------------- + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/conversion.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/conversion.hpp new file mode 100644 index 00000000..32f1b805 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/conversion.hpp @@ -0,0 +1,287 @@ +/** @addtogroup conversion + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/clamp.hpp" +#include "../simd/types.hpp" +#include "../simd/vec.hpp" +#include "univector.hpp" + +namespace kfr +{ + +enum class audio_sample_type +{ + unknown, + i8, + i16, + i24, + i32, + i64, + f32, + f64, + + first_float = f32 +}; + +inline constexpr size_t audio_sample_sizeof(audio_sample_type type) +{ + switch (type) + { + case audio_sample_type::i8: + return 1; + case audio_sample_type::i16: + return 2; + case audio_sample_type::i24: + return 3; + case audio_sample_type::i32: + case audio_sample_type::f32: + return 4; + case audio_sample_type::i64: + case audio_sample_type::f64: + return 8; + default: + return 0; + } +} + +inline constexpr size_t audio_sample_bit_depth(audio_sample_type type) +{ + return audio_sample_sizeof(type) * 8; +} + +inline namespace CMT_ARCH_NAME +{ + +using audio_sample_type_clist = + cvals_t; + +template +struct audio_sample_get_type; + +template <> +struct audio_sample_get_type +{ + using type = i8; +}; +template <> +struct audio_sample_get_type +{ + using type = i16; +}; +template <> +struct audio_sample_get_type +{ + using type = i24; +}; +template <> +struct audio_sample_get_type +{ + using type = i32; +}; +template <> +struct audio_sample_get_type +{ + using type = i64; +}; +template <> +struct audio_sample_get_type +{ + using type = f32; +}; +template <> +struct audio_sample_get_type +{ + using type = f64; +}; + +template +struct audio_sample_traits; + +template <> +struct audio_sample_traits +{ + constexpr static f32 scale = 127.f; + constexpr static audio_sample_type type = audio_sample_type::i8; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f32 scale = 32767.f; + constexpr static audio_sample_type type = audio_sample_type::i16; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f32 scale = 8388607.f; + constexpr static audio_sample_type type = audio_sample_type::i24; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f64 scale = 2147483647.0; + constexpr static audio_sample_type type = audio_sample_type::i32; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f64 scale = 9223372036854775807.0; + constexpr static audio_sample_type type = audio_sample_type::i64; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f32 scale = 1; + constexpr static audio_sample_type type = audio_sample_type::f32; +}; + +template <> +struct audio_sample_traits +{ + constexpr static f64 scale = 1; + constexpr static audio_sample_type type = audio_sample_type::f64; +}; + +template , + typename Tin_traits = audio_sample_traits, KFR_ENABLE_IF(std::is_same_v)> +inline Tout convert_sample(const Tin& in) +{ + return in; +} + +template , + typename Tin_traits = audio_sample_traits, KFR_ENABLE_IF(!std::is_same_v)> +inline Tout convert_sample(const Tin& in) +{ + constexpr auto scale = Tout_traits::scale / Tin_traits::scale; + return broadcastto(clamp(in * scale, -Tout_traits::scale, +Tout_traits::scale)); +} + +/// @brief Deinterleaves and converts audio samples +template , + typename Tin_traits = audio_sample_traits> +void deinterleave(Tout* out[], const Tin* in, size_t channels, size_t size) +{ + for (size_t i = 0; i < size; ++i) + { + for (size_t ch = 0; ch < channels; ++ch) + out[ch][i] = convert_sample(in[i * channels + ch]); + } +} + +/// @brief Deinterleaves and converts audio samples +template +void deinterleave(univector2d& out, const univector& in) +{ + if (CMT_UNLIKELY(in.empty() || out.empty())) + return; + std::vector ptrs(out.size()); + for (size_t i = 0; i < out.size(); ++i) + { + ptrs[i] = out[i].data(); + } + return deinterleave(ptrs.data(), in.data(), out.size(), in.size() / out.size()); +} + +/// @brief Interleaves and converts audio samples +template , + typename Tin_traits = audio_sample_traits> +void interleave(Tout* out, const Tin* in[], size_t channels, size_t size) +{ + for (size_t i = 0; i < size; ++i) + { + for (size_t ch = 0; ch < channels; ++ch) + out[i * channels + ch] = convert_sample(in[ch][i]); + } +} + +/// @brief Interleaves and converts audio samples +template +void interleave(univector& out, const univector2d& in) +{ + if (CMT_UNLIKELY(in.empty() || out.empty())) + return; + std::vector ptrs(in.size()); + for (size_t i = 0; i < in.size(); ++i) + { + ptrs[i] = in[i].data(); + } + return interleave(out.data(), ptrs.data(), in.size(), out.size() / in.size()); +} + +/// @brief Interleaves and converts audio samples +template +univector interleave(const univector2d& in) +{ + if (CMT_UNLIKELY(in.empty())) + return {}; + univector result(in.size() * in[0].size()); + interleave(result, in); + return result; +} + +/// @brief Converts audio samples (both formats are known at compile time) +template , + typename Tin_traits = audio_sample_traits> +void convert(Tout* out, const Tin* in, size_t size) +{ + for (size_t i = 0; i < size; ++i) + { + out[i] = convert_sample(in[i]); + } +} + +/// @brief Converts audio samples (input format is known at runtime) +template > +void convert(Tout* out, const void* in, audio_sample_type in_type, size_t size) +{ + cswitch(audio_sample_type_clist{}, in_type, + [&](auto t) + { + using type = typename audio_sample_get_type::type; + convert(out, reinterpret_cast(in), size); + }); +} + +/// @brief Converts audio samples (output format is known at runtime) +template > +void convert(void* out, audio_sample_type out_type, const Tin* in, size_t size) +{ + cswitch(audio_sample_type_clist{}, out_type, + [&](auto t) + { + using type = typename audio_sample_get_type::type; + convert(reinterpret_cast(out), in, size); + }); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/endianness.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/endianness.hpp new file mode 100644 index 00000000..8b10e72e --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/endianness.hpp @@ -0,0 +1,47 @@ +/** @addtogroup shuffle + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/operators.hpp" +#include "../simd/read_write.hpp" +#include "expression.hpp" + +namespace kfr +{ + +template +void convert_endianess(T* data, size_t size) +{ + block_process(size, csizes<2 * vector_width, 1>, + [&](size_t i, auto w) + { + constexpr size_t width = CMT_CVAL(w); + vec value = read(data + i); + value = swapbyteorder(value); + write(data + i, value); + }); +} +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/expression.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/expression.hpp new file mode 100644 index 00000000..34aea3e2 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/expression.hpp @@ -0,0 +1,946 @@ +/** @addtogroup expressions + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/platform.hpp" +#include "../simd/read_write.hpp" +#include "../simd/shuffle.hpp" +#include "../simd/types.hpp" +#include "../simd/vec.hpp" +#include "shape.hpp" + +#include +#include + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wparentheses") + +namespace kfr +{ + +#ifndef KFR_CUSTOM_COMPLEX +template +using complex = std::complex; +#endif + +template +struct expression_traits; + +template +using expression_value_type = typename expression_traits::value_type; + +template +constexpr inline size_t expression_dims = expression_traits::dims; + +template +constexpr inline shape> get_shape(T&& expr) +{ + return expression_traits::get_shape(expr); +} +template +constexpr inline shape> get_shape() +{ + return expression_traits::get_shape(); +} + +template +struct expression_traits>> : expression_traits +{ +}; +template +struct expression_traits>> : expression_traits +{ +}; +template +struct expression_traits>> : expression_traits +{ +}; +template +struct expression_traits>> : expression_traits +{ +}; +template +struct expression_traits::value_type>> + : expression_traits +{ +}; + +// This allows old style expressions+traits +template +struct expression_traits> +{ + using value_type = typename T::value_type; + constexpr static size_t dims = T::dims; + constexpr static shape get_shape(const T& self) { return T::get_shape(self); } + constexpr static shape get_shape() { return T::get_shape(); } + + constexpr static inline bool explicit_operand = T::explicit_operand; + constexpr static inline bool random_access = T::random_access; +}; + +struct expression_traits_defaults +{ + // using value_type = /* ... */; + // constexpr static size_t dims = 0; + // constexpr static shape get_shape(const T&); + // constexpr static shape get_shape(); + + constexpr static inline bool explicit_operand = true; + constexpr static inline bool random_access = true; +}; + +template +constexpr inline bool has_expression_traits = false; + +template +constexpr inline bool has_expression_traits::value_type>> = true; + +namespace internal_generic +{ +template +using expressions_condition = std::void_t...>; +template +using expressions_check = std::enable_if_t<(expression_traits::explicit_operand || ...)>; +} // namespace internal_generic + +template +using enable_if_input_expression = + std::void_t, + decltype(get_elements(std::declval(), shape::dims>(), + axis_params<0, 1>{}))>; + +template +using enable_if_output_expression = + std::void_t, + decltype(set_elements(std::declval(), shape::dims>(), + axis_params<0, 1>{}, + vec::value_type, 1>{}))>; + +template +using enable_if_input_output_expression = + std::void_t, enable_if_output_expression>; + +template +using enable_if_input_expressions = std::void_t...>; + +template +using enable_if_output_expressions = std::void_t...>; + +template +using enable_if_input_output_expressions = std::void_t...>; + +template +constexpr inline bool is_input_expression = false; + +template +constexpr inline bool is_input_expression> = true; + +template +constexpr inline bool is_output_expression = false; + +template +constexpr inline bool is_output_expression> = true; + +template +constexpr inline bool is_input_output_expression = false; + +template +constexpr inline bool is_input_output_expression> = true; + +#define KFR_ACCEPT_EXPRESSIONS(...) internal_generic::expressions_check<__VA_ARGS__>* = nullptr + +#define KFR_ACCEPT_ASGN_EXPRESSIONS(E1, E2) \ + KFR_ENABLE_IF(is_input_output_expression&& is_input_expression) + +template +constexpr inline bool is_expr_element = std::is_same_v, T> && is_vec_element; + +template +constexpr inline bool is_infinite = expression_traits::get_shape().has_infinity(); + +template +struct expression_traits>> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = 0; + constexpr static inline bool explicit_operand = false; + + KFR_MEM_INTRINSIC constexpr static shape<0> get_shape(const T& self) { return {}; } + KFR_MEM_INTRINSIC constexpr static shape<0> get_shape() { return {}; } +}; + +template * = nullptr, index_t Dims = expression_dims> +inline expression_value_type get_element(E&& expr, shape index) +{ + return get_elements(expr, index, axis_params_v<0, 1>).front(); +} + +template +inline vec indices(const shape& index, axis_params) +{ + if constexpr (Axis == VecAxis) + return index[Axis] + enumerate(); + else + return index[Axis]; +} + +namespace internal_generic +{ +struct anything +{ + template + constexpr anything(Expr&&) + { + } +}; +} // namespace internal_generic + +inline namespace CMT_ARCH_NAME +{ + +template > +KFR_INTRINSIC vec to_vec(const shape& sh) +{ + return read(reinterpret_cast(sh.data())); +} + +namespace internal +{ +template +KFR_INTRINSIC void block_process_impl(size_t& i, size_t size, Fn&& fn) +{ + CMT_LOOP_NOUNROLL + for (; i < size / width * width; i += width) + fn(i, csize_t()); +} +} // namespace internal + +template +KFR_INTRINSIC void block_process(size_t size, csizes_t, Fn&& fn) +{ + size_t i = 0; + swallow{ (internal::block_process_impl(i, size, std::forward(fn)), 0)... }; +} + +template +KFR_INTRINSIC void begin_pass(const internal_generic::anything&, shape start, shape stop) +{ +} +template +KFR_INTRINSIC void end_pass(const internal_generic::anything&, shape start, shape stop) +{ +} + +template >)> +KFR_INTRINSIC vec, N> get_elements(T&& self, const shape<0>& index, + const axis_params&) +{ + return self; +} +template >)> +KFR_INTRINSIC void set_elements(T& self, const shape<0>& index, const axis_params&, + const identity>& val) +{ + static_assert(N == 1); + static_assert(!std::is_const_v); + self = val.front(); +} + +template +constexpr inline bool is_arg = is_numeric_or_bool>; + +template +using arg = std::conditional_t, std::decay_t, T>; + +template +struct expression_with_arguments +{ + constexpr static size_t count = sizeof...(Args); + + using type_list = ctypes_t; + + template + using nth = typename type_list::template nth; + + using first_arg = typename type_list::template nth<0>; + + template + using nth_trait = expression_traits>; + + using first_arg_traits = expression_traits; + + std::tuple args; + std::array masks; + + KFR_INTRINSIC auto& first() { return std::get<0>(args); } + KFR_INTRINSIC const auto& first() const { return std::get<0>(args); } + + template + KFR_INTRINSIC dimset getmask(csize_t = {}) const + { + static_assert(idx < count); + using Traits = expression_traits>; + if constexpr (sizeof...(Args) <= 1 || Traits::dims == 0) + { + return dimset(-1); + } + else + { + if constexpr (Traits::get_shape().product() > 0) + { + return Traits::get_shape().tomask(); + } + else + { + return std::get(masks); + } + } + } + + template + KFR_INTRINSIC constexpr auto fold(Fn&& fn) const + { + return fold_impl(std::forward(fn), csizeseq); + } + template + KFR_INTRINSIC constexpr static auto fold_idx(Fn&& fn) + { + return fold_idx_impl(std::forward(fn), csizeseq); + } + + KFR_INTRINSIC expression_with_arguments(arg... args) : args{ std::forward(args)... } + { + cforeach(csizeseq, + [&](auto idx_) CMT_INLINE_LAMBDA + { + constexpr size_t idx = val_of(decltype(idx_)()); + shape sh = expression_traits>::get_shape(std::get(this->args)); + masks[idx] = sh.tomask(); + }); + } + +private: + template + KFR_INTRINSIC constexpr auto fold_impl(Fn&& fn, csizes_t) const + { + return fn(std::get(args)...); + } + template + KFR_INTRINSIC constexpr static auto fold_idx_impl(Fn&& fn, csizes_t) + { + return fn(csize...); + } +}; + +template +struct expression_with_arguments +{ + constexpr static size_t count = 1; + + using type_list = ctypes_t; + + template + using nth = Arg; + + using first_arg = Arg; + + template + using nth_trait = expression_traits; + + using first_arg_traits = expression_traits; + + std::tuple args; + + KFR_MEM_INTRINSIC auto& first() { return std::get<0>(args); } + KFR_MEM_INTRINSIC const auto& first() const { return std::get<0>(args); } + + template + KFR_MEM_INTRINSIC dimset getmask(csize_t = {}) const + { + return dimset(-1); + } + + template + KFR_MEM_INTRINSIC constexpr auto fold(Fn&& fn) const + { + return fold_impl(std::forward(fn), csizeseq); + } + template + KFR_INTRINSIC constexpr static auto fold_idx(Fn&& fn) + { + return fold_idx_impl(std::forward(fn), csizeseq); + } + + KFR_MEM_INTRINSIC expression_with_arguments(Arg&& arg) : args{ std::forward(arg) } {} + +private: + template + KFR_MEM_INTRINSIC constexpr auto fold_impl(Fn&& fn, csizes_t) const + { + return fn(std::get(args)...); + } + template + KFR_INTRINSIC constexpr static auto fold_idx_impl(Fn&& fn, csizes_t) + { + return fn(csize...); + } +}; + +template +expression_with_arguments(Args&&... args) -> expression_with_arguments; + +template +struct expression_with_traits : expression_with_arguments +{ + constexpr static inline bool explicit_operand = true; + constexpr static inline bool random_access = true; + + using first_arg_traits = expression_traits; + using value_type = typename first_arg_traits::value_type; + constexpr static size_t dims = first_arg_traits::dims; + constexpr static shape get_shape(const expression_with_traits& self) + { + return first_arg_traits::get_shape(self.first()); + } + constexpr static shape get_shape() { return first_arg_traits::get_shape(); } + + using expression_with_arguments::expression_with_arguments; +}; + +template +struct expression_function : expression_with_arguments, expression_traits_defaults +{ + using value_type = + typename std::invoke_result_t::value_type, 1>...>::value_type; + constexpr static size_t dims = const_max(expression_traits::dims...); + +#if defined CMT_COMPILER_IS_MSVC || defined CMT_COMPILER_GCC + struct lambda_get_shape + { + template + constexpr auto operator()(csize_t...) const + { + return internal_generic::common_shape( + expression_traits>::get_shape()...); + } + }; + struct lambda_get_shape_self + { + const expression_function& self; + template + constexpr auto operator()(const TArgs&... args) const + { + return internal_generic::common_shape(expression_traits::get_shape(args)...); + } + }; + constexpr static shape get_shape(const expression_function& self) + { + return self.fold(lambda_get_shape_self{ self }); + } + constexpr static shape get_shape() { return expression_function::fold_idx(lambda_get_shape{}); } +#else + constexpr static shape get_shape(const expression_function& self) + { + return self.fold( + [&](auto&&... args) CMT_INLINE_LAMBDA constexpr -> auto { + return internal_generic::common_shape( + expression_traits::get_shape(args)...); + }); + } + constexpr static shape get_shape() + { + return expression_function::fold_idx( + [&](auto... args) CMT_INLINE_LAMBDA constexpr -> auto + { + return internal_generic::common_shape( + expression_traits>:: + get_shape()...); + }); + } +#endif + + constexpr static inline bool random_access = (expression_traits::random_access && ...); + + Fn fn; + + KFR_MEM_INTRINSIC expression_function(expression_with_arguments args, Fn&& fn) + : expression_with_arguments{ std::move(args) }, fn(std::forward(fn)) + { + } + KFR_MEM_INTRINSIC expression_function(Fn&& fn, arg... args) + : expression_with_arguments{ std::forward(args)... }, fn(std::forward(fn)) + { + } + KFR_MEM_INTRINSIC expression_function(arg... args) + : expression_with_arguments{ std::forward(args)... }, fn{} + { + } + + template * = nullptr> + expression_function& operator=(In&& in) + { + static_assert(is_output_expression); + process(*this, std::forward(in)); + return *this; + } +}; + +template +expression_function(const expression_with_arguments& args, Fn&& fn) + -> expression_function; +template +expression_function(expression_with_arguments&& args, Fn&& fn) -> expression_function; +template +expression_function(expression_with_arguments& args, Fn&& fn) -> expression_function; + +template +using expression_make_function = expression_function...>; + +namespace internal +{ + +template +KFR_INTRINSIC void begin_pass_args(const expression_with_arguments& self, shape start, + shape stop, csizes_t) +{ + (begin_pass(std::get(self.args), start, stop), ...); +} + +template +KFR_INTRINSIC void end_pass_args(const expression_with_arguments& self, shape start, + shape stop, csizes_t) +{ + (end_pass(std::get(self.args), start, stop), ...); +} + +template ::template nth>> +KFR_MEM_INTRINSIC vec get_arg(const expression_function& self, + const shape& index, + const axis_params& sh, csize_t) +{ + if constexpr (Traits::dims == 0) + { + return repeat(get_elements(std::get(self.args), {}, axis_params<0, 1>{})); + } + else + { + constexpr size_t NewVecAxis = Traits::dims - (Dims - VecAxis); + auto indices = internal_generic::adapt(index, self.getmask(csize)); + constexpr index_t last_dim = Traits::get_shape().back(); + if constexpr (last_dim != undefined_size) + { + constexpr index_t last_dim_pot = prev_poweroftwo(last_dim); + return repeat(N))>( + get_elements(std::get(self.args), indices, + axis_params(N))>{})); + } + else + { + if constexpr (sizeof...(Args) > 1 && N > 1) + { + if (CMT_UNLIKELY(self.masks[idx].back() == 0)) + return get_elements(std::get(self.args), indices, axis_params{}) + .front(); + else + return get_elements(std::get(self.args), indices, axis_params{}); + } + else + { + return get_elements(std::get(self.args), indices, axis_params{}); + } + } + } +} +} // namespace internal + +template +KFR_INTRINSIC void begin_pass(const expression_with_arguments& self, shape start, + shape stop) +{ + internal::begin_pass_args(self, start, stop, indicesfor); +} + +template +KFR_INTRINSIC void end_pass(const expression_with_arguments& self, shape start, + shape stop) +{ + internal::end_pass_args(self, start, stop, indicesfor); +} + +template >, + typename T = typename Tr::value_type> +KFR_INTRINSIC vec get_elements(const expression_function& self, const shape& index, + const axis_params& sh) +{ + return self.fold_idx([&](auto... idx) CMT_INLINE_LAMBDA -> vec + { return self.fn(internal::get_arg(self, index, sh, idx)...); }); +} + +template +KFR_INTRINSIC static void tprocess_body(Out&& out, In&& in, size_t start, size_t stop, size_t insize, + shape outidx, shape inidx) +{ + if constexpr (indims == 0) + { + size_t x = start; + const vec val = get_elements(in, inidx, axis_params_v<0, 1>); + if constexpr (w > gw) + { + CMT_LOOP_NOUNROLL + for (; x < stop / w * w; x += w) + { + outidx[OutAxis] = x; + set_elements(out, outidx, axis_params_v, repeat(val)); + } + } + CMT_LOOP_NOUNROLL + for (; x < stop / gw * gw; x += gw) + { + outidx[OutAxis] = x; + set_elements(out, outidx, axis_params_v, repeat(val)); + } + } + else + { + constexpr index_t InAxis = OutAxis + indims - outdims; + size_t x = start; + if constexpr (w > gw) + { + CMT_LOOP_NOUNROLL + for (; x < stop / w * w; x += w) + { + outidx[OutAxis] = x; + inidx[InAxis] = std::min(x, insize - 1); + auto v = get_elements(in, inidx, axis_params_v); + // println("## i=", x, "\n", v); + set_elements(out, outidx, axis_params_v, v); + } + } + CMT_LOOP_NOUNROLL + for (; x < stop / gw * gw; x += gw) + { + outidx[OutAxis] = x; + inidx[InAxis] = std::min(x, insize - 1); + set_elements(out, outidx, axis_params_v, + get_elements(in, inidx, axis_params_v)); + } + } +} + +template ::dims == 0)> +static auto process(Out&& out, In&& in, shape<0> = {}, shape<0> = {}, csize_t = {}) -> shape<0> +{ + static_assert(is_input_expression, "In must be an input expression"); + static_assert(is_output_expression, "Out must be an output expression"); + static_assert(expression_traits::dims == 0); + begin_pass(out, shape{}, shape{}); + begin_pass(in, shape{}, shape{}); + set_elements(out, shape<0>{}, axis_params_v<0, 1>, get_elements(in, shape<0>{}, axis_params_v<0, 1>)); + end_pass(in, shape{}, shape{}); + end_pass(out, shape{}, shape{}); + return {}; +} + +namespace internal +{ + +constexpr KFR_INTRINSIC size_t select_process_width(size_t width, size_t vec_width, index_t last_dim_size) +{ + if (width != 0) + return width; + if (last_dim_size == 0) + return vec_width; + + return std::min(vec_width, static_cast(last_dim_size)); +} + +constexpr KFR_INTRINSIC index_t select_axis(index_t ndims, index_t axis) +{ + if (axis >= ndims) + return ndims - 1; + return axis; +} + +template +KFR_INTRINSIC index_t axis_start(const shape& sh) +{ + static_assert(VecAxis < outdims); + static_assert(LoopAxis < outdims); + if constexpr (VecAxis == LoopAxis) + return 0; + else + return sh[LoopAxis]; +} +template +KFR_INTRINSIC index_t axis_stop(const shape& sh) +{ + static_assert(VecAxis < outdims); + static_assert(LoopAxis < outdims); + if constexpr (VecAxis == LoopAxis) + return 1; + else + return sh[LoopAxis]; +} + +} // namespace internal + +template , CMT_ENABLE_IF(expression_dims > 0)> +static auto process(Out&& out, In&& in, shape start = shape(0), + shape size = shape(infinite_size), csize_t = {}) -> shape +{ + static_assert(is_input_expression, "In must be an input expression"); + static_assert(is_output_expression, "Out must be an output expression"); + + using Trin = expression_traits; + using Trout = expression_traits; + using Tin = typename Trin::value_type; + + using internal::axis_start; + using internal::axis_stop; + + constexpr index_t indims = expression_dims; + static_assert(outdims >= indims); + + constexpr index_t last_dim_size = prev_poweroftwo(Trout::get_shape().back()); + +#ifdef NDEBUG + constexpr size_t vec_width = maximum_vector_size; +#else + constexpr size_t vec_width = vector_width; +#endif + + constexpr size_t w = internal::select_process_width(width, vec_width, last_dim_size); + + constexpr index_t out_axis = internal::select_axis(outdims, Axis); + constexpr index_t in_axis = out_axis + indims - outdims; + + const shape outshape = Trout::get_shape(out); + const shape inshape = Trin::get_shape(in); + if (CMT_UNLIKELY(!internal_generic::can_assign_from(outshape, inshape))) + return shape{ 0 }; + shape stop = min(min(add_shape(start, size), outshape), inshape.template extend()); + + index_t in_size = 0; + if constexpr (indims > 0) + in_size = inshape[in_axis]; + + begin_pass(out, start, stop); + begin_pass(in, inshape.adapt(start), inshape.adapt(stop, ctrue)); + + shape outidx; + if constexpr (outdims == 1) + { + outidx = shape{ 0 }; + tprocess_body( + std::forward(out), std::forward(in), start[out_axis], stop[out_axis], in_size, outidx, + inshape.adapt(outidx)); + } + else if constexpr (outdims == 2) + { + for (index_t i0 = axis_start(start); i0 < axis_stop(stop); ++i0) + { + for (index_t i1 = axis_start(start); i1 < axis_stop(stop); ++i1) + { + outidx = shape{ i0, i1 }; + tprocess_body( + std::forward(out), std::forward(in), start[out_axis], stop[out_axis], in_size, + outidx, inshape.adapt(outidx)); + } + } + } + else if constexpr (outdims == 3) + { + for (index_t i0 = axis_start(start); i0 < axis_stop(stop); ++i0) + { + for (index_t i1 = axis_start(start); i1 < axis_stop(stop); ++i1) + { + for (index_t i2 = axis_start(start); i2 < axis_stop(stop); ++i2) + { + outidx = shape{ i0, i1, i2 }; + tprocess_body( + std::forward(out), std::forward(in), start[out_axis], stop[out_axis], + in_size, outidx, inshape.adapt(outidx)); + } + } + } + } + else if constexpr (outdims == 4) + { + for (index_t i0 = axis_start(start); i0 < axis_stop(stop); ++i0) + { + for (index_t i1 = axis_start(start); i1 < axis_stop(stop); ++i1) + { + for (index_t i2 = axis_start(start); i2 < axis_stop(stop); ++i2) + { + for (index_t i3 = axis_start(start); i3 < axis_stop(stop); ++i3) + { + outidx = shape{ i0, i1, i2, i3 }; + tprocess_body( + std::forward(out), std::forward(in), start[out_axis], stop[out_axis], + in_size, outidx, inshape.adapt(outidx)); + } + } + } + } + } + else + { + shape outidx = start; + if (CMT_UNLIKELY(!internal_generic::compare_indices(outidx, stop))) + return stop; + do + { + tprocess_body( + std::forward(out), std::forward(in), start[out_axis], stop[out_axis], in_size, + outidx, inshape.adapt(outidx)); + outidx[out_axis] = stop[out_axis] - 1; + } while (internal_generic::increment_indices(outidx, start, stop)); + } + end_pass(in, inshape.adapt(start), inshape.adapt(stop, ctrue)); + end_pass(out, start, stop); + return stop; +} + +template +struct expression_discard : public expression_traits_defaults +{ + using value_type = Tin; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_discard&) { return shape(infinite_size); } + constexpr static shape get_shape() { return shape(infinite_size); } + + template + friend KFR_INTRINSIC void set_elements(const expression_discard& self, shape, + axis_params, const identity>& x) + { + } +}; + +/// @brief Read the expression @c expr through the whole range. +/// @param expr the input expression +/// @return the input expression is returned +template > +KFR_FUNCTION const E& sink(E&& expr) +{ + static_assert(!Traits::get_shape().has_infinity()); + process(expression_discard, expression_dims>{}, expr); + return expr; +} + +template +KFR_FUNCTION expression_function, Args...> bind_expression(Fn&& fn, Args&&... args) +{ + return expression_function, Args...>(std::forward(fn), std::forward(args)...); +} +/** + * @brief Construct a new expression using the same function as in @c e and new arguments + * @param e an expression + * @param args new arguments for the function + */ +template +KFR_FUNCTION expression_function rebind(const expression_function& e, + NewArgs&&... args) +{ + return expression_function(Fn{ e.fn }, std::forward(args)...); +} +template +KFR_FUNCTION expression_function rebind(expression_function&& e, + NewArgs&&... args) +{ + return expression_function(std::move(e.fn), std::forward(args)...); +} + +#ifdef KFR_TESTING +namespace internal +{ +template +inline vec get_fn_value(size_t index, Fn&& fn) +{ + return apply(fn, enumerate() + index); +} +} // namespace internal + +template )> +void test_expression(const E& expr, size_t size, Fn&& fn, const char* expression = nullptr, + const char* file = nullptr, int line = 0) +{ + static_assert(expression_dims == 1, "CHECK_EXPRESSION supports only 1-dim expressions"); + using T = expression_value_type; + size_t expr_size = get_shape(expr).front(); + ::testo::test_case* test = ::testo::active_test(); + auto&& c = ::testo::make_comparison(); + test->check(c <= expr_size == size, expression, file, line); + if (expr_size != size) + return; + size = min(shape<1>(size), shape<1>(200)).front(); + constexpr size_t maxsize = 2 + ilog2(vector_width * 2); + size_t g = 1; + for (size_t i = 0; i < size;) + { + const size_t next_size = std::min(prev_poweroftwo(size - i), g); + g *= 2; + if (g > (1 << (maxsize - 1))) + g = 1; + + cswitch(csize<1> << csizeseq, next_size, + [&](auto x) + { + constexpr size_t nsize = val_of(decltype(x)()); + ::testo::scope s(as_string("i = ", i, " width = ", nsize)); + test->check(c <= get_elements(expr, shape<1>(i), axis_params_v<0, nsize>) == + internal::get_fn_value(i, fn), + expression, file, line); + }); + i += next_size; + } +} + +template > +void test_expression(const E& expr, std::initializer_list> list, + const char* expression = nullptr, const char* file = nullptr, int line = 0) +{ + test_expression( + expr, list.size(), [&](size_t i) { return list.begin()[i]; }, expression, file, line); +} +#define TESTO_CHECK_EXPRESSION(expr, ...) ::kfr::test_expression(expr, __VA_ARGS__, #expr, __FILE__, __LINE__) + +#ifndef TESTO_NO_SHORT_MACROS +#define CHECK_EXPRESSION TESTO_CHECK_EXPRESSION +#endif +#endif + +} // namespace CMT_ARCH_NAME + +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/filter.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/filter.hpp new file mode 100644 index 00000000..3a662b6f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/filter.hpp @@ -0,0 +1,149 @@ +/** @addtogroup filter + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "basic_expressions.hpp" +#include "expression.hpp" +#include "handle.hpp" +#include "univector.hpp" + +namespace kfr +{ + +/// @brief Abstract base class for filters with one argument. Mainly for DSP +template +class filter +{ +public: + virtual ~filter() {} + + /// @brief Resets internal state (such as delay line) + virtual void reset() {} + + /// @brief Applies filter to a static array + template + void apply(T (&buffer)[Size]) + { + process_buffer(buffer, buffer, Size); + } + + /// @brief Applies filter to a static array and writes the result to another array + template + void apply(T (&dest)[Size], T (&src)[Size]) + { + process_buffer(dest, src, Size); + } + + /// @brief Applies filter to a univector + template + void apply(univector& buffer) + { + process_buffer(buffer.data(), buffer.data(), buffer.size()); + } + + /// @brief Applies filter to a univector and writes the result to another univector + template + void apply(univector& dest, const univector& src) + { + if (dest.empty()) + dest.resize(src.size()); + process_buffer(dest.data(), src.data(), std::min(dest.size(), src.size())); + } + + void apply(T* buffer, size_t size) { process_buffer(buffer, buffer, size); } + + void apply(T* dest, const T* src, size_t size) { process_buffer(dest, src, size); } + + template + void apply(univector& dest, const expression_handle& src) + { + process_expression(dest.data(), src, size_min(dest.size(), src.size())); + } + + void apply(T* dest, const expression_handle& src, size_t size) + { + process_expression(dest, src, size_min(size, src.size())); + } + + template )> + void apply(univector& dest, const Expr& src) + { + static_assert(expression_dims == 1); + process_expression(dest.data(), to_handle(src), size_min(dest.size(), get_shape(src).front())); + } + + template )> + void apply(T* dest, const Expr& src, size_t size) + { + process_expression(dest, to_handle(src), size_min(size, src.size())); + } + +protected: + virtual void process_buffer(T* dest, const T* src, size_t size) = 0; + virtual void process_expression(T* dest, const expression_handle& src, size_t size) = 0; +}; + +template +class expression_filter : public filter +{ +public: + explicit expression_filter(expression_handle filter_expr) : filter_expr(std::move(filter_expr)) {} + +protected: + expression_filter() = default; + void process_buffer(T* dest, const T* src, size_t size) override + { + substitute(filter_expr, to_handle(make_univector(src, size))); + process(make_univector(dest, size), filter_expr, shape<1>(0), shape<1>(size)); + } + void process_expression(T* dest, const expression_handle& src, size_t size) override + { + substitute(filter_expr, src); + process(make_univector(dest, size), filter_expr, shape<1>(0), shape<1>(size)); + } + + expression_handle filter_expr; +}; + +inline namespace CMT_ARCH_NAME +{ + +/// @brief Converts expression with placeholder to filter. Placeholder and filter must have the same type +template > +KFR_INTRINSIC expression_filter to_filter(E&& e) +{ + return expression_filter(to_handle(std::move(e))); +} +} // namespace CMT_ARCH_NAME + +/// @brief Converts expression with placeholder to filter. Placeholder and filter must have the same type +template +KFR_INTRINSIC expression_filter to_filter(expression_handle&& e) +{ + return expression_filter(std::move(e)); +} + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/fraction.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/fraction.hpp new file mode 100644 index 00000000..3397e330 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/fraction.hpp @@ -0,0 +1,152 @@ +/** @addtogroup base + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../cometa/string.hpp" +#include "../simd/types.hpp" + +namespace kfr +{ + +struct fraction +{ + fraction(i64 num = 0, i64 den = 1) : numerator(num), denominator(den) { normalize(); } + void normalize() + { + if (CMT_UNLIKELY(denominator < 0)) + { + denominator = -denominator; + numerator = -numerator; + } + const i64 z = gcd(std::abs(numerator), std::abs(denominator)); + numerator /= z; + denominator /= z; + } + + i64 numerator; + i64 denominator; + + fraction operator+() const { return *this; } + fraction operator-() const { return fraction(-numerator, denominator); } + + explicit operator bool() const { return numerator != 0; } + explicit operator double() const { return static_cast(numerator) / denominator; } + explicit operator float() const { return static_cast(numerator) / denominator; } + explicit operator i64() const { return static_cast(numerator) / denominator; } + + friend fraction operator+(const fraction& x, const fraction& y) + { + return fraction(x.numerator * y.denominator + y.numerator * x.denominator, + x.denominator * y.denominator); + } + friend fraction operator-(const fraction& x, const fraction& y) + { + return fraction(x.numerator * y.denominator - y.numerator * x.denominator, + x.denominator * y.denominator); + } + friend fraction operator*(const fraction& x, const fraction& y) + { + return fraction(x.numerator * y.numerator, x.denominator * y.denominator); + } + friend fraction operator/(const fraction& x, const fraction& y) + { + return fraction(x.numerator * y.denominator, x.denominator * y.numerator); + } + + friend bool operator==(const fraction& x, const fraction& y) + { + return x.numerator == y.numerator && x.denominator == y.denominator; + } + friend bool operator!=(const fraction& x, const fraction& y) { return !(operator==(x, y)); } + friend bool operator<(const fraction& x, const fraction& y) + { + return x.numerator * y.denominator < y.numerator * x.denominator; + } + friend bool operator<=(const fraction& x, const fraction& y) + { + return x.numerator * y.denominator <= y.numerator * x.denominator; + } + friend bool operator>(const fraction& x, const fraction& y) + { + return x.numerator * y.denominator > y.numerator * x.denominator; + } + friend bool operator>=(const fraction& x, const fraction& y) + { + return x.numerator * y.denominator >= y.numerator * x.denominator; + } + + fraction& operator+=(const fraction& y) + { + *this = *this + y; + return *this; + } + fraction& operator-=(const fraction& y) + { + *this = *this - y; + return *this; + } + fraction& operator*=(const fraction& y) + { + *this = *this * y; + return *this; + } + fraction& operator/=(const fraction& y) + { + *this = *this / y; + return *this; + } + +private: + static i64 gcd(i64 a, i64 b) + { + i64 r; + while (b > 0) + { + r = a % b; + a = b; + b = r; + } + return a; + } + static i64 lcm(i64 a, i64 b) { return std::abs(a * b) / gcd(a, b); } +}; +} // namespace kfr + +namespace cometa +{ +template <> +struct representation +{ + using type = std::string; + static std::string get(const kfr::fraction& value) + { + if (value.denominator == 1) + return as_string(value.numerator); + else + return as_string(value.numerator, "/", value.denominator); + } +}; +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/generators.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/generators.hpp new file mode 100644 index 00000000..bc68e0b1 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/generators.hpp @@ -0,0 +1,332 @@ +/** @addtogroup generators + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../math/log_exp.hpp" +#include "../math/sin_cos.hpp" +#include "../simd/complex.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/select.hpp" +#include "../simd/vec.hpp" +#include "expression.hpp" +#include "shape.hpp" + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ +template +constexpr size_t generator_width(size_t divisor) +{ + return const_max(1, vector_capacity> / 8 / divisor); +} +} // namespace internal + +template +struct generator : public expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = 1; + constexpr static shape<1> get_shape(const Class&) { return infinite_size; } + constexpr static shape<1> get_shape() { return infinite_size; } + + constexpr static inline bool random_access = false; + + constexpr static size_t width = VecWidth; + + void resync(T start) const { ptr_cast(this)->sync(start); } + + template + KFR_MEM_INTRINSIC vec generate() const + { + if constexpr (N < width) + { + const vec result = narrow(call_get_value()); + const vec oldvalue = value; + call_next(); + value = slice(oldvalue, value); + return result; + } + else if constexpr (N > width) + { + constexpr size_t Nlow = prev_poweroftwo(N - 1); + const vec lo = generate(); + const vec hi = generate(); + return concat(lo, hi); + } + else // N == width + { + const vec result = call_get_value(); + call_next(); + return result; + } + } + mutable vec value; + + template + friend KFR_INTRINSIC vec get_elements(const generator& self, const shape<1>& index, + const axis_params<0, N>&) + { + return self.template generate(); + } + +private: + KFR_MEM_INTRINSIC void call_next() const { ptr_cast(this)->next(); } + + KFR_MEM_INTRINSIC vec call_get_value() const { return ptr_cast(this)->get_value(); } + + template )> + KFR_MEM_INTRINSIC vec get_value() const + { + return value; + } +}; + +template (1)> +struct generator_linear : public generator> +{ + generator_linear(T start, T step) CMT_NOEXCEPT : vstep{ step * VecWidth } { sync(start); } + + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT + { + this->value = start + enumerate(vec_shape{}, vstep / VecWidth); + } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT { this->value += vstep; } + + T vstep; +}; + +template (1)> +struct generator_exp : public generator> +{ + generator_exp(T start, T step) CMT_NOEXCEPT : step{ step }, + vstep{ exp(make_vector(step * VecWidth)).front() - 1 } + { + this->resync(start); + } + + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT + { + this->value = exp(start + enumerate() * step); + } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT { this->value += this->value * vstep; } + +protected: + T step; + T vstep; +}; + +template (2)> +struct generator_expj : public generator> +{ + using ST = deep_subtype; + static_assert(std::is_same_v>, T>, "generator_expj requires complex type"); + + generator_expj(ST start_, ST step_) + : step(step_), alpha(2 * sqr(sin(VecWidth * step / 2))), beta(-sin(VecWidth * step)) + { + this->resync(T(start_)); + } + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT { this->value = init_cossin(step, start.real()); } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT + { + this->value = ccomp(cdecom(this->value) - + subadd(alpha * cdecom(this->value), beta * swap<2>(cdecom(this->value)))); + } + +protected: + ST step; + ST alpha; + ST beta; + CMT_NOINLINE static vec init_cossin(ST w, ST phase) + { + return ccomp(cossin(dup(phase + enumerate() * w))); + } +}; + +template (1)> +struct generator_exp2 : public generator> +{ + generator_exp2(T start, T step) CMT_NOEXCEPT : step{ step }, + vstep{ exp2(make_vector(step * VecWidth))[0] - 1 } + { + this->resync(start); + } + + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT + { + this->value = exp2(start + enumerate(vec_shape{}, step)); + } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT { this->value += this->value * vstep; } + +protected: + T step; + T vstep; +}; + +template (1)> +struct generator_cossin : public generator> +{ + static_assert(VecWidth % 2 == 0); + generator_cossin(T start, T step) + : step(step), alpha(2 * sqr(sin(VecWidth / 2 * step / 2))), beta(-sin(VecWidth / 2 * step)) + { + this->resync(start); + } + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT { this->value = init_cossin(step, start); } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT + { + this->value = this->value - subadd(alpha * this->value, beta * swap<2>(this->value)); + } + +protected: + T step; + T alpha; + T beta; + CMT_NOINLINE static vec init_cossin(T w, T phase) + { + return cossin(dup(phase + enumerate(vec_shape{}, w))); + } +}; + +template (2)> +struct generator_sin : public generator, vec> +{ + generator_sin(T start, T step) + : step(step), alpha(2 * sqr(sin(VecWidth * step / 2))), beta(sin(VecWidth * step)) + { + this->resync(start); + } + KFR_MEM_INTRINSIC void sync(T start) const CMT_NOEXCEPT + { + const vec cs = cossin(dup(start + enumerate(vec_shape{}, step))); + this->value = vec, VecWidth>::from_flatten(cs); + } + + KFR_MEM_INTRINSIC void next() const CMT_NOEXCEPT + { + vec cs = flatten(this->value); + + cs = cs - addsub(alpha * cs, beta * swap<2>(cs)); + + this->value = vec, VecWidth>::from_flatten(cs); + } + KFR_MEM_INTRINSIC vec get_value() const { return odd(flatten(this->value)); } + +protected: + T step; + T alpha; + T beta; +}; + +/** + * @brief Returns template expression that generates values starting from the start and using the step as the + * increment between numbers. + * + * \f[ + x_i = start + i \cdot step + \f] + */ +template >> +KFR_FUNCTION generator_linear gen_linear(T1 start, T2 step) +{ + return generator_linear(start, step); +} + +/** + * @brief Returns template expression that generates values using the following formula: + * \f[ + x_i = e^{ start + i \cdot step } + \f] + */ +template >> +KFR_FUNCTION generator_exp gen_exp(T1 start, T2 step) +{ + return generator_exp(start, step); +} + +/** + * @brief Returns template expression that generates values using the following formula: + * \f[ + x_i = e^{ j ( start + i \cdot step ) } + \f] + */ +template >>> +KFR_FUNCTION generator_expj gen_expj(T1 start, T2 step) +{ + return generator_expj(start, step); +} + +/** + * @brief Returns template expression that generates values using the following formula: + * \f[ + x_i = 2^{ start + i \cdot step } + \f] + */ +template >> +KFR_FUNCTION generator_exp2 gen_exp2(T1 start, T2 step) +{ + return generator_exp2(start, step); +} + +/** + * @brief Returns template expression that generates values using the following formula: + * \f[ + x_i= + \begin{cases} + \cos(start + i \cdot step), & \text{if } i \text{ is even}\\ + \sin(start + i \cdot step), & \text{otherwise} + \end{cases} + \f] + */ +template >> +KFR_FUNCTION generator_cossin gen_cossin(T1 start, T2 step) +{ + return generator_cossin(start, step); +} + +/** + * @brief Returns template expression that generates values using the following formula: + * \f[ + x_i = \sin( start + i \cdot step ) + \f] + */ +template >> +KFR_FUNCTION generator_sin gen_sin(T1 start, T2 step) +{ + return generator_sin(start, step); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/handle.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/handle.hpp new file mode 100644 index 00000000..7ecd09a1 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/handle.hpp @@ -0,0 +1,412 @@ +/** @addtogroup base + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../cometa/memory.hpp" +#include "../simd/vec.hpp" +#include "basic_expressions.hpp" +#include + +namespace kfr +{ + +template +struct expression_handle; + +template +constexpr size_t maximum_expression_width = vector_width_for * 2; + +template typename Tpl, typename Pack> +struct expand_cvals; + +template typename Tpl, T... vals> +struct expand_cvals> +{ + using type = Tpl; +}; + +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ + +template +KFR_INTRINSIC bool invoke_substitute(Expression& expr, expression_handle new_handle, + csize_t = {}); +} +} // namespace CMT_ARCH_NAME + +template +struct expression_vtable +{ + constexpr static const size_t Nsizes = 1 + ilog2(maximum_expression_width); + constexpr static const size_t Nmax = 1 << Nsizes; + + using func_get = void (*)(void*, shape, T*); + using func_set = void (*)(void*, shape, const T*); + using func_shapeof = void (*)(void*, shape&); + using func_substitute = bool (*)(void*, expression_handle); + using func_pass = void (*)(void*, shape, shape); + + func_shapeof fn_shapeof; + func_substitute fn_substitute; + func_pass fn_begin_pass; + func_pass fn_end_pass; + std::array, Dims> fn_get_elements; + std::array, Dims> fn_set_elements; + + template + KFR_MEM_INTRINSIC expression_vtable(ctype_t t) + { + fn_shapeof = &static_shapeof; + fn_substitute = &static_substitute; + fn_begin_pass = &static_begin_pass; + fn_end_pass = &static_end_pass; + cforeach(csizeseq, + [&](auto size_) CMT_INLINE_LAMBDA + { + cforeach(csizeseq, + [&](auto axis_) CMT_INLINE_LAMBDA + { + constexpr size_t size = decltype(size_)::value; + constexpr size_t axis = decltype(axis_)::value; + fn_get_elements[axis][size] = + &static_get_elements; + fn_set_elements[axis][size] = + &static_set_elements; + }); + }); + } + + template + static void static_get_elements(void* instance, shape index, T* dest) + { + if constexpr (is_input_expression) + { + write(dest, get_elements(*static_cast(instance), index, axis_params_v)); + } + else + { + } + } + template + static void static_set_elements(void* instance, shape index, const T* src) + { + if constexpr (is_output_expression) + { + set_elements(*static_cast(instance), index, axis_params_v, read(src)); + } + else + { + } + } + template + static void static_shapeof(void* instance, shape& result) + { + result = expression_traits::get_shape(*static_cast(instance)); + } + template + static bool static_substitute(void* instance, expression_handle ptr) + { + return internal::invoke_substitute(*static_cast(instance), std::move(ptr)); + } + template + static void static_begin_pass(void* instance, shape start, shape stop) + { + begin_pass(*static_cast(instance), start, stop); + } + template + static void static_end_pass(void* instance, shape start, shape stop) + { + end_pass(*static_cast(instance), start, stop); + } +}; + +struct expression_resource +{ + virtual ~expression_resource() {} + virtual void* instance() { return nullptr; } +}; + +template +struct expression_resource_impl : expression_resource +{ + expression_resource_impl(E&& e) CMT_NOEXCEPT : e(std::move(e)) {} + virtual ~expression_resource_impl() {} + KFR_INTRINSIC virtual void* instance() override final { return &e; } + +public: +#ifdef __cpp_aligned_new + static void operator delete(void* p, std::align_val_t al) noexcept { details::aligned_release(p); } +#endif + +private: + E e; +}; + +template +KFR_INTRINSIC std::shared_ptr make_resource(E&& e) +{ + using T = expression_resource_impl>; + return std::static_pointer_cast(std::shared_ptr( + new (aligned_allocate()) T(std::move(e)), [](T* pi) { aligned_deallocate(pi); })); +} + +template +struct expression_handle +{ + void* instance; + const expression_vtable* vtable; + std::shared_ptr resource; + + expression_handle() CMT_NOEXCEPT : instance(nullptr), vtable(nullptr) {} + expression_handle(const void* instance, const expression_vtable* vtable, + std::shared_ptr resource = nullptr) + : instance(const_cast(instance)), vtable(vtable), resource(std::move(resource)) + { + } + + explicit operator bool() const { return instance != nullptr; } + + bool substitute(expression_handle new_handle) + { + return vtable->fn_substitute(instance, std::move(new_handle)); + } +}; + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_handle& self) + { + shape result; + self.vtable->fn_shapeof(self.instance, result); + return result; + } + constexpr static shape get_shape() { return shape(undefined_size); } + + constexpr static inline bool random_access = false; +}; + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC void begin_pass(const expression_handle& self, shape start, shape stop) +{ + self.vtable->fn_begin_pass(self.instance, start, stop); +} +template +KFR_INTRINSIC void end_pass(const expression_handle& self, shape start, shape stop) +{ + self.vtable->fn_end_pass(self.instance, start, stop); +} + +template +KFR_INTRINSIC vec get_elements(const expression_handle& self, const shape& index, + const axis_params& sh) +{ + static_assert(is_poweroftwo(N) && N >= 1); + constexpr size_t Nsize = ilog2(N); + if constexpr (Nsize >= expression_vtable::Nsizes) + { + constexpr size_t Nhalf = N / 2; + auto low = get_elements(self, index, axis_params_v); + auto high = get_elements(self, index.add_at(Nhalf, cval), axis_params_v); + return concat(low, high); + } + else + { + portable_vec result; + self.vtable->fn_get_elements[Axis][Nsize](self.instance, index, result.elem); + return result; + } +} + +template +KFR_INTRINSIC void set_elements(const expression_handle& self, const shape& index, + const axis_params& sh, const identity>& value) +{ + static_assert(is_poweroftwo(N) && N >= 1); + constexpr size_t Nsize = ilog2(N); + if constexpr (Nsize >= expression_vtable::Nsizes) + { + constexpr size_t Nhalf = N / 2; + set_elements(self, index, axis_params_v, slice<0, Nhalf>(value)); + set_elements(self, index.add_at(Nhalf, cval), axis_params_v, + slice(value)); + } + else + { + self.vtable->fn_set_elements[Axis][Nsize](self.instance, index, &value.front()); + } +} +} // namespace CMT_ARCH_NAME + +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ + +template +KFR_INTRINSIC expression_vtable* make_expression_vtable() +{ + static expression_vtable vtable{ ctype_t>{} }; + return &vtable; +} +} // namespace internal + +} // namespace CMT_ARCH_NAME + +/** @brief Converts the given expression into an opaque object. + * This overload takes reference to the expression. + * @warning Use with caution with local variables. + */ +template , index_t Dims = expression_dims> +KFR_INTRINSIC expression_handle to_handle(E& expr) +{ + return expression_handle(std::addressof(expr), internal::make_expression_vtable()); +} + +/** @brief Converts the given expression into an opaque object. + * This overload takes ownership of the expression (Move semantics). + * @note Use std::move to force use of this overload. + */ +template , index_t Dims = expression_dims> +KFR_INTRINSIC expression_handle to_handle(E&& expr) +{ + std::shared_ptr ptr = make_resource(std::move(expr)); + void* instance = ptr->instance(); + return expression_handle(instance, internal::make_expression_vtable(), + std::move(ptr)); +} + +template +struct expression_placeholder +{ +public: + using value_type = T; + expression_placeholder() CMT_NOEXCEPT = default; + expression_handle handle; +}; + +template +struct expression_traits> : public expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_placeholder& self) + { + return self.handle ? ::kfr::get_shape(self.handle) : shape(infinite_size); + } + constexpr static shape get_shape() { return shape(undefined_size); } +}; + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const expression_placeholder& self, shape index, + axis_params sh) +{ + return self.handle ? get_elements(self.handle, index, sh) : 0; +} +} // namespace CMT_ARCH_NAME + +template +KFR_INTRINSIC expression_placeholder placeholder(csize_t = csize_t{}) +{ + return expression_placeholder(); +} + +template +KFR_INTRINSIC bool substitute(const internal_generic::anything&, Args&&...) +{ + return false; +} + +inline namespace CMT_ARCH_NAME +{ +namespace internal +{ +template +KFR_INTRINSIC bool substitute_helper(expression_with_arguments& expr, + expression_handle new_handle, csize_t, + csizes_t); +} +} // namespace CMT_ARCH_NAME + +template +KFR_INTRINSIC bool substitute(expression_placeholder& expr, + expression_handle new_handle, csize_t = csize_t{}) +{ + expr.handle = std::move(new_handle); + return true; +} + +template +KFR_INTRINSIC bool substitute(expression_with_arguments& expr, expression_handle new_handle, + csize_t = csize_t{}) +{ + return internal::substitute_helper(expr, std::move(new_handle), csize_t{}, indicesfor_t{}); +} + +template +KFR_INTRINSIC bool substitute(expression_handle& expr, expression_handle new_handle, + csize_t = csize_t{}) +{ + static_assert(Key == 0, "expression_handle supports only Key = 0"); + return expr.substitute(std::move(new_handle)); +} + +inline namespace CMT_ARCH_NAME +{ +namespace internal +{ + +template +KFR_INTRINSIC bool substitute_helper(expression_with_arguments& expr, + expression_handle new_handle, csize_t, + csizes_t) +{ + return (substitute(std::get(expr.args), std::move(new_handle), csize_t()) || ...); +} + +template +KFR_INTRINSIC bool invoke_substitute(Expression& expr, expression_handle new_handle, csize_t) +{ + return kfr::substitute(expr, std::move(new_handle), csize_t{}); +} + +} // namespace internal + +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/impl/static_array.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/impl/static_array.hpp new file mode 100644 index 00000000..7fd46a35 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/impl/static_array.hpp @@ -0,0 +1,237 @@ +/** @addtogroup expressions + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../cometa.hpp" +#include "../../kfr.h" + +namespace kfr +{ +using namespace cometa; + +template +using type_for = T; + +template +struct static_array_base; + +template +using static_array_of_size = static_array_base>; + +template +struct static_array_base> +{ + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + using iterator = pointer; + using const_reference = const value_type&; + using const_pointer = const value_type*; + using const_iterator = const_pointer; + + constexpr static size_t static_size = sizeof...(indices); + + constexpr static_array_base() noexcept : array{ (static_cast(indices), 0)... } {} + constexpr static_array_base(const static_array_base&) noexcept = default; + constexpr static_array_base(static_array_base&&) noexcept = default; + + KFR_MEM_INTRINSIC constexpr static_array_base(type_for... args) noexcept + : array{ args... } + { + } + + template + friend struct static_array_base; + + template + KFR_MEM_INTRINSIC constexpr static_array_base( + const static_array_base>& first, + const static_array_base>& second) noexcept + : array{ (indices >= sizeof...(idx1) ? second.array[indices - sizeof...(idx1)] + : first.array[indices])... } + { + static_assert(sizeof...(idx1) + sizeof...(idx2) == static_size); + } + + template + constexpr static_array_base> shuffle(csizes_t) const noexcept + { + return static_array_base>{ array[idx]... }; + } + template + constexpr static_array_base> shuffle(csizes_t, + T filler) const noexcept + { + return static_array_base>{ (idx >= static_size ? filler + : array[idx])... }; + } + + template + constexpr static_array_base> slice() const noexcept + { + return shuffle(csizeseq); + } + + constexpr static_array_base& operator=(const static_array_base&) = default; + constexpr static_array_base& operator=(static_array_base&&) = default; + + template + constexpr static value_type just_value(value_type value) + { + // Workaround for MSVC2019 Internal compiler error + return value; + } + + template 1)> + KFR_MEM_INTRINSIC constexpr explicit static_array_base(value_type value) noexcept + : array{ just_value(value)... } + { + } + + KFR_MEM_INTRINSIC constexpr const value_type* data() const noexcept { return std::data(array); } + KFR_MEM_INTRINSIC constexpr value_type* data() noexcept { return std::data(array); } + + KFR_MEM_INTRINSIC constexpr const_iterator begin() const noexcept { return std::begin(array); } + KFR_MEM_INTRINSIC constexpr iterator begin() noexcept { return std::begin(array); } + KFR_MEM_INTRINSIC constexpr const_iterator cbegin() const noexcept { return std::begin(array); } + + KFR_MEM_INTRINSIC constexpr const_iterator end() const noexcept { return std::end(array); } + KFR_MEM_INTRINSIC constexpr iterator end() noexcept { return std::end(array); } + KFR_MEM_INTRINSIC constexpr const_iterator cend() const noexcept { return std::end(array); } + + KFR_MEM_INTRINSIC constexpr const_reference operator[](size_t index) const noexcept + { + return array[index]; + } + KFR_MEM_INTRINSIC constexpr reference operator[](size_t index) noexcept { return array[index]; } + + KFR_MEM_INTRINSIC constexpr const_reference front() const noexcept { return array[0]; } + KFR_MEM_INTRINSIC constexpr reference front() noexcept { return array[0]; } + + KFR_MEM_INTRINSIC constexpr const_reference back() const noexcept { return array[static_size - 1]; } + KFR_MEM_INTRINSIC constexpr reference back() noexcept { return array[static_size - 1]; } + + KFR_MEM_INTRINSIC constexpr bool empty() const noexcept { return false; } + + KFR_MEM_INTRINSIC constexpr size_t size() const noexcept { return std::size(array); } + + KFR_MEM_INTRINSIC constexpr bool operator==(const static_array_base& other) const noexcept + { + return ((array[indices] == other.array[indices]) && ...); + } + KFR_MEM_INTRINSIC constexpr bool operator!=(const static_array_base& other) const noexcept + { + return !operator==(other); + } + constexpr T minof() const noexcept + { + T result = std::numeric_limits::max(); + (static_cast(result = std::min(result, array[indices])), ...); + return result; + } + constexpr T maxof() const noexcept + { + T result = std::numeric_limits::lowest(); + (static_cast(result = std::max(result, array[indices])), ...); + return result; + } + constexpr T sum() const noexcept + { + T result = 0; + (static_cast(result += array[indices]), ...); + return result; + } + constexpr T product() const noexcept + { + T result = 1; + (static_cast(result *= array[indices]), ...); + return result; + } + + constexpr static_array_base min(const static_array_base& y) const noexcept + { + return static_array_base{ std::min(array[indices], y.array[indices])... }; + } + constexpr static_array_base max(const static_array_base& y) const noexcept + { + return static_array_base{ std::max(array[indices], y.array[indices])... }; + } + template + constexpr static_array_base bin(const static_array_base& y, Fn&& fn) const noexcept + { + return static_array_base{ fn(array[indices], y.array[indices])... }; + } + template + constexpr static_array_base un(Fn&& fn) const noexcept + { + return static_array_base{ fn(array[indices])... }; + } + template + constexpr static_array_base> cast() const noexcept + { + return static_array_base>{ static_cast(array[indices])... }; + } + + constexpr static_array_base operator+(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] + y.array[indices])... }; + } + constexpr static_array_base operator-(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] - y.array[indices])... }; + } + constexpr static_array_base operator*(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] * y.array[indices])... }; + } + constexpr static_array_base operator&(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] & y.array[indices])... }; + } + constexpr static_array_base operator|(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] | y.array[indices])... }; + } + constexpr static_array_base operator^(const static_array_base& y) const noexcept + { + return static_array_base{ (array[indices] ^ y.array[indices])... }; + } + constexpr static_array_base operator+(const T& y) const noexcept + { + return static_array_base{ (array[indices] + y)... }; + } + constexpr static_array_base operator-(const T& y) const noexcept + { + return static_array_base{ (array[indices] - y)... }; + } + constexpr T dot(const static_array_base& y) const noexcept { return (operator*(y)).sum(); } + +private: + T array[static_size]; +}; +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/inline_vector.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/inline_vector.hpp new file mode 100644 index 00000000..b559c2f5 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/inline_vector.hpp @@ -0,0 +1,131 @@ +/** @addtogroup expressions + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include +#include +#include +#include + +namespace kfr +{ + +template +struct inline_vector +{ + static_assert(N > 0 && N <= INT32_MAX); + static_assert(std::is_trivially_copy_constructible_v); + // it's ok for T to be non-trivially default constructible as long as it's trivial in any other aspect + static_assert(std::is_trivially_copy_assignable_v); + static_assert(std::is_trivially_move_assignable_v); + static_assert(std::is_trivially_move_constructible_v); + static_assert(std::is_trivially_destructible_v); + + using size_type = size_t; + using stored_size_type = std::conditional_t<(N >= UINT16_MAX), uint32_t, + std::conditional_t<(N >= UINT8_MAX), uint16_t, uint8_t>>; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using iterator = pointer; + using const_iterator = const_pointer; + + constexpr inline_vector() noexcept : m_size(0) {} + constexpr inline_vector(const inline_vector&) noexcept = default; + constexpr inline_vector(inline_vector&&) noexcept = default; + constexpr inline_vector& operator=(const inline_vector&) noexcept = default; + constexpr inline_vector& operator=(inline_vector&&) noexcept = default; + + constexpr inline_vector(size_type initial_size) : m_size(initial_size) + { + KFR_LOGIC_CHECK(initial_size <= N, "inline_vector: invalid initial_size"); + } + constexpr inline_vector(size_type initial_size, T initial_value) : m_size(initial_size) + { + KFR_LOGIC_CHECK(initial_size <= N, "inline_vector: invalid initial_size"); + std::fill_n(begin(), initial_size, initial_value); + } + constexpr inline_vector(std::initializer_list list) : inline_vector(list.begin(), list.end()) {} + + template + constexpr inline_vector(Iter first, Iter last) + { + iterator dest = begin(); + size_t i = 0; + for (; i < N && first != last; ++i) + *dest++ = *first++; + KFR_LOGIC_CHECK(first == last, "inline_vector: too many items"); + m_size = i; + } + + constexpr const_reference at(size_type index) const + { + KFR_LOGIC_CHECK(index < m_size, "inline_vector: invalid index"); + return m_values[index]; + } + constexpr reference at(size_type index) + { + KFR_LOGIC_CHECK(index < m_size, "inline_vector: invalid index"); + return m_values[index]; + } + + constexpr const_reference operator[](size_type index) const noexcept { return m_values[index]; } + constexpr reference operator[](size_type index) noexcept { return m_values[index]; } + + constexpr size_type size() const noexcept { return m_size; } + constexpr pointer data() noexcept { return m_values; } + constexpr const_pointer data() const noexcept { return m_values; } + constexpr bool empty() const noexcept { return m_size == 0; } + constexpr iterator begin() noexcept { return m_values; } + constexpr iterator end() noexcept { return m_values + m_size; } + constexpr const_iterator begin() const noexcept { return m_values; } + constexpr const_iterator end() const noexcept { return m_values + m_size; } + constexpr const_iterator cbegin() const noexcept { return m_values; } + constexpr const_iterator cend() const noexcept { return m_values + m_size; } + + constexpr reference front() noexcept { return m_values[0]; } + constexpr reference back() noexcept { return m_values[m_size - 1]; } + constexpr const_reference front() const noexcept { return m_values[0]; } + constexpr const_reference back() const noexcept { return m_values[m_size - 1]; } + + constexpr void push_back(T value) + { + KFR_LOGIC_CHECK(m_size < N, "inline_vector: vector is full"); + m_values[m_size++] = value; + } + + constexpr bool operator==(const inline_vector& other) const + { + return std::equal(begin(), end(), other.begin()); + } + constexpr bool operator!=(const inline_vector& other) const { return !operator==(other); } + + T m_values[N]; + stored_size_type m_size; +}; +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/math_expressions.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/math_expressions.hpp new file mode 100644 index 00000000..77e5dc59 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/math_expressions.hpp @@ -0,0 +1,516 @@ +/** @addtogroup base + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../math.hpp" +#include "basic_expressions.hpp" +#include "expression.hpp" + +namespace kfr +{ + +/** + * @brief Returns the trigonometric sine of x. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function sin(E1&& x) +{ + return { fn::sin(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric cosine of x. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function cos(E1&& x) +{ + return { fn::cos(), std::forward(x) }; +} + +/** + * @brief Returns an approximation of the trigonometric sine of x. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function fastsin(E1&& x) +{ + return { fn::fastsin(), std::forward(x) }; +} + +/** + * @brief Returns an approximation of the trigonometric cosine of x. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function fastcos(E1&& x) +{ + return { fn::fastcos(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric sine of the even elements of the x and + * cosine of the odd elements. x must be a vector. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function sincos(E1&& x) +{ + return { fn::sincos(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric cosine of the even elements of the x and + * sine of the odd elements. x must be a vector. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function cossin(E1&& x) +{ + return { fn::cossin(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric sine of the x (expressed in degrees). Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function sindeg(E1&& x) +{ + return { fn::sindeg(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric cosine of the x (expressed in degrees). Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function cosdeg(E1&& x) +{ + return { fn::cosdeg(), std::forward(x) }; +} + +/** + * @brief Returns an approximation of the trigonometric sine of the x + * (expressed in degrees). Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function fastsindeg(E1&& x) +{ + return { fn::fastsindeg(), std::forward(x) }; +} + +/** + * @brief Returns an approximation of the trigonometric cosine of the x + * (expressed in degrees). Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function fastcosdeg(E1&& x) +{ + return { fn::fastcosdeg(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric sine of the even elements of the x and + * cosine of the odd elements. x must be expressed in degrees. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function sincosdeg(E1&& x) +{ + return { fn::sincosdeg(), std::forward(x) }; +} + +/** + * @brief Returns the trigonometric cosine of the even elements of the x and + * sine of the odd elements. x must be expressed in degrees. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function cossindeg(E1&& x) +{ + return { fn::cossindeg(), std::forward(x) }; +} + +/** + * @brief Returns the sinc function of x. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function sinc(E1&& x) +{ + return { fn::sinc(), std::forward(x) }; +} + +/// @brief Creates expression that returns the approximate gamma function of an argument +template +KFR_FUNCTION expression_make_function gamma(E1&& x) +{ + return { fn::gamma(), std::forward(x) }; +} + +/// @brief Creates expression that returns the approximate factorial of an argument +template +KFR_FUNCTION expression_make_function factorial_approx(E1&& x) +{ + return { fn::factorial_approx(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the positive square root of the x. \f$\sqrt{x}\f$ + */ +template +KFR_FUNCTION expression_make_function sqrt(E1&& x) +{ + return { fn::sqrt(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function tan(E1&& x) +{ + return { fn::tan(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function tandeg(E1&& x) +{ + return { fn::tandeg(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the arc sine of x. + */ +template +KFR_INTRINSIC expression_make_function asin(E1&& x) +{ + return { fn::asin(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the arc cosine of x. + */ +template +KFR_INTRINSIC expression_make_function acos(E1&& x) +{ + return { fn::acos(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the sine of the the complex value x +template +KFR_FUNCTION expression_make_function csin(E1&& x) +{ + return { fn::csin(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic sine of the complex number x +template +KFR_FUNCTION expression_make_function csinh(E1&& x) +{ + return { fn::csinh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the cosine of the the complex value x +template +KFR_FUNCTION expression_make_function ccos(E1&& x) +{ + return { fn::ccos(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic cosine of the the complex value x +template +KFR_FUNCTION expression_make_function ccosh(E1&& x) +{ + return { fn::ccosh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the squared absolute value (magnitude squared) of the +/// complex number x +template +KFR_FUNCTION expression_make_function cabssqr(E1&& x) +{ + return { fn::cabssqr(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the absolute value (magnitude) of the complex number x +template +KFR_FUNCTION expression_make_function cabs(E1&& x) +{ + return { fn::cabs(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the phase angle (argument) of the complex number x +template +KFR_FUNCTION expression_make_function carg(E1&& x) +{ + return { fn::carg(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the natural logarithm of the complex number x +template +KFR_FUNCTION expression_make_function clog(E1&& x) +{ + return { fn::clog(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the binary (base-2) logarithm of the complex number x +template +KFR_FUNCTION expression_make_function clog2(E1&& x) +{ + return { fn::clog2(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the common (base-10) logarithm of the complex number x +template +KFR_FUNCTION expression_make_function clog10(E1&& x) +{ + return { fn::clog10(), std::forward(x) }; +} + +/// @brief Returns template expression that returns \f$e\f$ raised to the complex number x +template +KFR_FUNCTION expression_make_function cexp(E1&& x) +{ + return { fn::cexp(), std::forward(x) }; +} + +/// @brief Returns template expression that returns 2 raised to the complex number x +template +KFR_FUNCTION expression_make_function cexp2(E1&& x) +{ + return { fn::cexp2(), std::forward(x) }; +} + +/// @brief Returns template expression that returns 10 raised to the complex number x +template +KFR_FUNCTION expression_make_function cexp10(E1&& x) +{ + return { fn::cexp10(), std::forward(x) }; +} + +/// @brief Returns template expression that converts complex number to polar +template +KFR_FUNCTION expression_make_function polar(E1&& x) +{ + return { fn::polar(), std::forward(x) }; +} + +/// @brief Returns template expression that converts complex number to cartesian +template +KFR_FUNCTION expression_make_function cartesian(E1&& x) +{ + return { fn::cartesian(), std::forward(x) }; +} + +/// @brief Returns template expression that returns square root of the complex number x +template +KFR_FUNCTION expression_make_function csqrt(E1&& x) +{ + return { fn::csqrt(), std::forward(x) }; +} + +/// @brief Returns template expression that returns square of the complex number x +template +KFR_FUNCTION expression_make_function csqr(E1&& x) +{ + return { fn::csqr(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the arc tangent of x. + */ +template +KFR_FUNCTION expression_make_function atan(E1&& x) +{ + return { fn::atan(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the arc tangent of the x, expressed in degrees. + */ +template +KFR_FUNCTION expression_make_function atandeg(E1&& x) +{ + return { fn::atandeg(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns the arc tangent of y/x. + */ +template +KFR_FUNCTION expression_make_function atan2(E1&& x, E2&& y) +{ + return { fn::atan2(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns template expression that returns the arc tangent of y/x (expressed in degrees). + */ +template +KFR_FUNCTION expression_make_function atan2deg(E1&& x, E2&& y) +{ + return { fn::atan2deg(), std::forward(x), std::forward(y) }; +} + +template +KFR_FUNCTION expression_make_function modzerobessel(E1&& x) +{ + return { fn::modzerobessel(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic sine of the x +template +KFR_FUNCTION expression_make_function sinh(E1&& x) +{ + return { fn::sinh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic cosine of the x +template +KFR_FUNCTION expression_make_function cosh(E1&& x) +{ + return { fn::cosh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic tangent of the x +template +KFR_FUNCTION expression_make_function tanh(E1&& x) +{ + return { fn::tanh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic cotangent of the x +template +KFR_FUNCTION expression_make_function coth(E1&& x) +{ + return { fn::coth(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic sine of the even elements of the x and the +/// hyperbolic cosine of the odd elements of the x +template +KFR_FUNCTION expression_make_function sinhcosh(E1&& x) +{ + return { fn::sinhcosh(), std::forward(x) }; +} + +/// @brief Returns template expression that returns the hyperbolic cosine of the even elements of the x and +/// the hyperbolic sine of the odd elements of the x +template +KFR_FUNCTION expression_make_function coshsinh(E1&& x) +{ + return { fn::coshsinh(), std::forward(x) }; +} + +/// @brief Returns e raised to the given power x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function exp(E1&& x) +{ + return { fn::exp(), std::forward(x) }; +} + +/// @brief Returns 2 raised to the given power x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function exp2(E1&& x) +{ + return { fn::exp2(), std::forward(x) }; +} + +/// @brief Returns 10 raised to the given power x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function exp10(E1&& x) +{ + return { fn::exp10(), std::forward(x) }; +} + +/// @brief Returns the natural logarithm of the x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function log(E1&& x) +{ + return { fn::log(), std::forward(x) }; +} + +/// @brief Returns the binary (base-2) logarithm of the x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function log2(E1&& x) +{ + return { fn::log2(), std::forward(x) }; +} + +/// @brief Returns the common (base-10) logarithm of the x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function log10(E1&& x) +{ + return { fn::log10(), std::forward(x) }; +} + +/// @brief Returns the rounded binary (base-2) logarithm of the x. Version that accepts and returns +/// expressions. +template +KFR_FUNCTION expression_make_function logb(E1&& x) +{ + return { fn::logb(), std::forward(x) }; +} + +/// @brief Returns the logarithm of the x with base y. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function logn(E1&& x, E2&& y) +{ + return { fn::logn(), std::forward(x), std::forward(y) }; +} + +/// @brief Returns log(x) * y. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function logm(E1&& x, E2&& y) +{ + return { fn::logm(), std::forward(x), std::forward(y) }; +} + +/// @brief Returns exp(x * m + a). Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function exp_fmadd(E1&& x, E2&& y, E3&& z) +{ + return { fn::exp_fmadd(), std::forward(x), std::forward(y), std::forward(z) }; +} + +/// @brief Returns log(x) * m + a. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function log_fmadd(E1&& x, E2&& y, E3&& z) +{ + return { fn::log_fmadd(), std::forward(x), std::forward(y), std::forward(z) }; +} + +/// @brief Returns the x raised to the given power y. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function pow(E1&& x, E2&& y) +{ + return { fn::pow(), std::forward(x), std::forward(y) }; +} + +/// @brief Returns the real nth root of the x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function root(E1&& x, E2&& y) +{ + return { fn::root(), std::forward(x), std::forward(y) }; +} + +/// @brief Returns the cube root of the x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function cbrt(E1&& x) +{ + return { fn::cbrt(), std::forward(x) }; +} + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/memory.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/memory.hpp new file mode 100644 index 00000000..f4aa474e --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/memory.hpp @@ -0,0 +1,29 @@ +/** @addtogroup base + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../cometa/memory.hpp" +#include "../simd/types.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/npy.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/npy.hpp new file mode 100644 index 00000000..3e1d6ca9 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/npy.hpp @@ -0,0 +1,494 @@ +/** @addtogroup tensor + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "tensor.hpp" +#include +#include +#include + +namespace kfr +{ + +namespace internal_generic +{ +template +std::string_view npy_format() +{ + using namespace cometa; + static_assert(is_poweroftwo(sizeof(T)) && is_between(sizeof(T), 1, 16)); + if constexpr (std::is_floating_point_v) + { + const std::string_view fmts[] = { "|f1", " && std::is_unsigned_v) + { + const std::string_view fmts[] = { "|u1", " && std::is_signed_v) + { + const std::string_view fmts[] = { "|i1", ") + { + const std::string_view fmts[] = { "|c1", ") + { + return "|b1"; + } + else + { + static_assert("Cannot save type to python"); + return ""; + } +} +template +std::string npy_shape(shape sh) +{ + std::string result = "("; + for (index_t i : sh) + { + if (result.size() > 1) + result += ", "; + result += std::to_string(i); + } + if (Dim == 1) + result += ","; + return result + ")"; +} + +template +struct npy_writer +{ + Fn&& fn; + size_t written = 0; + + void operator()(const void* d, size_t size) + { + fn(d, size); + written += size; + } + void operator()(std::string_view s) { operator()(s.data(), s.size()); } + void operator()(std::initializer_list b) { operator()(&*b.begin(), b.size()); } + + template + void operator()(cometa::ctype_t, cometa::identity n) + { + operator()(&n, sizeof(Num)); + } + template + void operator()(cometa::ctype_t, const Num* n, size_t count) + { + operator()(n, sizeof(Num) * count); + } +}; + +template +struct npy_reader +{ + Fn&& fn; + + bool operator()(void* d, size_t size) { return fn(d, size); } + + template + Num operator()(cometa::ctype_t) + { + Num result; + if (!operator()(&result, sizeof(Num))) + return {}; + return result; + } + template + bool operator()(cometa::ctype_t, Num& n) + { + return operator()(&n, sizeof(Num)); + } + template + bool operator()(cometa::ctype_t, Num* n, size_t count) + { + return operator()(n, sizeof(Num) * count); + } + + std::string operator()(cometa::ctype_t, size_t count) + { + std::string result(count, ' '); + if (!operator()(cometa::ctype, result.data(), count)) + return {}; + return result; + } +}; + +struct npy_header +{ + std::string descr; + bool fortran_order = false; + std::vector shape; +}; + +inline bool npy_skip_whitespace(std::string_view& data) +{ + while (!data.empty() && uint8_t(data[0]) <= uint8_t(' ')) + data = data.substr(1); + return !data.empty(); +} +inline bool npy_parse_string(std::string_view& data, std::string& content, char q = '\'') +{ + if (data.empty() || data[0] != q) + return false; + data = data.substr(1); + while (!data.empty() && data[0] != q) + { + if (data[0] == '\\') + { + data = data.substr(1); + if (data.empty()) + return false; + } + content += data[0]; + data = data.substr(1); + } + if (data.empty()) + return false; + data = data.substr(1); + return true; +} + +inline bool npy_skip_value(std::string_view& data, char close = '}', std::string context = {}) +{ + std::string dummy; + while (!data.empty()) + { + switch (data[0]) + { + case '\'': + case '"': + if (!npy_parse_string(data, dummy, data[0])) + return false; + break; + case '(': + case '[': + case '{': + context += data[0]; + break; + case ')': + case ']': + case '}': + if (context.empty()) + return data[0] == close; + if (context.back() == data[0]) + context.pop_back(); + break; + case ',': + if (context.empty()) + return true; + else + data = data.substr(1); + break; + default: + data = data.substr(1); + break; + } + } + return false; +} + +inline bool npy_parse_bool(std::string_view& data, bool& content) +{ + if (data.size() >= 5 && data.substr(0, 5) == "False") + { + content = false; + data = data.substr(5); + return true; + } + if (data.size() >= 4 && data.substr(0, 4) == "True") + { + content = true; + data = data.substr(4); + return true; + } + return false; +} +inline bool npy_parse_integer(std::string_view& data, index_t& content) +{ + const char* orig = data.data(); + if (data[0] < '0' || data[0] > '9') + return false; + + while (data[0] >= '0' && data[0] <= '9') + data = data.substr(1); + content = std::stoll(std::string(orig, data.data() - orig)); + return true; +} +inline bool npy_parse_shape(std::string_view& data, std::vector& content) +{ + if (data[0] != '(') + return false; + data = data.substr(1); + if (!npy_skip_whitespace(data)) + return false; + for (;;) + { + index_t num; + if (!npy_parse_integer(data, num)) + return false; + content.push_back(num); + if (!npy_skip_whitespace(data)) + return false; + if (data[0] == ')') + { + data = data.substr(1); + return true; + } + if (data[0] != ',') + return false; + data = data.substr(1); + if (!npy_skip_whitespace(data)) + return false; + if (data[0] == ')') + { + data = data.substr(1); + return true; + } + } +} + +inline bool npy_decode_field(std::string_view& data, npy_header& hdr) +{ + if (!npy_skip_whitespace(data)) + return false; + std::string name; + if (!npy_parse_string(data, name)) + return false; + if (!npy_skip_whitespace(data)) + return false; + if (data.empty() || data[0] != ':') + return false; + data = data.substr(1); + if (!npy_skip_whitespace(data)) + return false; + if (data.empty()) + return false; + + if (name == "descr") + { + return npy_parse_string(data, hdr.descr); + } + else if (name == "fortran_order") + { + return npy_parse_bool(data, hdr.fortran_order); + } + else if (name == "shape") + { + return npy_parse_shape(data, hdr.shape); + } + else + { + return npy_skip_value(data); + } + + if (!npy_skip_whitespace(data)) + return false; + if (data.empty() || data[0] != ',') + return false; + data = data.substr(1); + return true; +} + +inline bool npy_decode_dict(std::string_view data, npy_header& hdr) +{ + if (data.size() < 10 || data[0] != '{') + return false; + data = data.substr(1); + while (!data.empty() && data[0] != '}') + { + if (!npy_decode_field(data, hdr)) + { + return false; + } + if (data[0] == '}') + return true; + if (data.empty() || data[0] != ',') + return false; + data = data.substr(1); + if (!npy_skip_whitespace(data)) + return false; + } + return !data.empty() && data[0] == '}'; +} + +inline std::string_view npy_magic = "\x93NUMPY"; + +} // namespace internal_generic + +template +void save_to_npy(const tensor& t, Fn&& write_callback) +{ + using namespace internal_generic; + + npy_writer wr{ write_callback }; + wr(internal_generic::npy_magic); + wr(ctype, 0x0001); + + std::string header = std::string("{'descr': '") + std::string(npy_format()) + + "', 'fortran_order': False, 'shape': " + npy_shape(t.shape()) + ", }"; + + std::string_view padding = " "; + + size_t total_header = cometa::align_up(wr.written + 2 + header.size() + 1, 64); + header += padding.substr(0, total_header - (wr.written + 2 + header.size() + 1)); + header += '\n'; + uint16_t header_len = header.size(); + wr(cometa::ctype, header_len); + wr(header); + if (t.is_contiguous()) + { + wr(cometa::ctype, t.data(), t.size()); + } + else + { + tensor copy = t.copy(); + wr(cometa::ctype, copy.data(), copy.size()); + } +} + +enum class npy_decode_result +{ + ok, + cannot_read, + invalid_header, + invalid_type, + invalid_shape, +}; + +template +npy_decode_result load_from_npy(tensor& result, Fn&& read_callback) +{ + using namespace internal_generic; + + npy_reader rd{ read_callback }; + + if (std::string s = rd(ctype, internal_generic::npy_magic.size()); s != internal_generic::npy_magic) + return npy_decode_result::cannot_read; + uint16_t v; + if (v = rd(ctype); v != 1 && v != 2 && v != 3) + return npy_decode_result::cannot_read; + uint32_t header_len; + if (v >= 2) + { + if (!rd(ctype, header_len)) + return npy_decode_result::cannot_read; + } + else + { + uint16_t header_len16; + if (!rd(ctype, header_len16)) + return npy_decode_result::cannot_read; + header_len = header_len16; + } + std::string header = rd(ctype, header_len); + + npy_header hdr; + if (!npy_decode_dict(header, hdr)) + return npy_decode_result::invalid_header; + + std::string_view tfmt = npy_format(); + bool convert_endianness = false; + if (hdr.descr != tfmt) + { + if (hdr.descr.size() > 1 && hdr.descr[0] != tfmt[0] && hdr.descr.substr(1) == tfmt.substr(1)) + { + convert_endianness = hdr.descr[0] == '>'; + } + else + { + return npy_decode_result::invalid_type; + } + } + if (hdr.shape.size() != Dims) + return npy_decode_result::invalid_shape; + + shape sh; + std::copy(hdr.shape.begin(), hdr.shape.end(), sh.begin()); + if (sh.product() == 0) + return npy_decode_result::invalid_shape; + + tensor buffer(shape<1>{ sh.product() }); + + rd(ctype, buffer.data(), buffer.size()); + if (convert_endianness) + { + convert_endianess(buffer.data(), buffer.size()); + } + if (hdr.fortran_order) + { + result = tensor(buffer.data(), sh, internal_generic::strides_for_shape(sh), + buffer.finalizer()); + } + else + { + result = tensor(buffer.data(), sh, internal_generic::strides_for_shape(sh), + buffer.finalizer()); + } + + return npy_decode_result::ok; +} +} // namespace kfr + +namespace cometa +{ +template <> +struct representation +{ + using type = std::string; + static std::string get(kfr::npy_decode_result value) + { + switch (value) + { + case kfr::npy_decode_result::ok: + return "ok"; + case kfr::npy_decode_result::cannot_read: + return "cannot_read"; + case kfr::npy_decode_result::invalid_header: + return "invalid_header"; + case kfr::npy_decode_result::invalid_type: + return "invalid_type"; + case kfr::npy_decode_result::invalid_shape: + return "invalid_shape"; + default: + return "(unknown)"; + } + } +}; +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/random.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/random.hpp new file mode 100644 index 00000000..e8fa61b8 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/random.hpp @@ -0,0 +1,242 @@ +/** @addtogroup random + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../math/log_exp.hpp" +#include "../math/sin_cos.hpp" +#include "../math/sqrt.hpp" +#include "random_bits.hpp" +#include "state_holder.hpp" + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +template )> +KFR_INTRINSIC vec random_uniform(random_state& state) +{ + return bitcast(random_bits(state)); +} + +template )> +KFR_INTRINSIC vec randommantissa(random_state& state) +{ + return bitcast((random_uniform(state) & u32(0x7FFFFFu)) | u32(0x3f800000u)) + 0.0f; +} + +template )> +KFR_INTRINSIC vec randommantissa(random_state& state) +{ + return bitcast((random_uniform(state) & u64(0x000FFFFFFFFFFFFFull)) | + u64(0x3FF0000000000000ull)) + + 0.0; +} + +template )> +KFR_INTRINSIC vec random_uniform(random_state& state) +{ + return randommantissa(state) - 1.f; +} + +template )> +KFR_INTRINSIC vec random_range(random_state& state, T min, T max) +{ + return mix(random_uniform(state), min, max); +} + +template )> +KFR_INTRINSIC vec random_range(random_state& state, T min, T max) +{ + using big_type = findinttype::min()), sqr(std::numeric_limits::max())>; + + vec u = random_uniform(state); + const vec tmp = u; + return (tmp * (max - min) + min) >> typebits::bits; +} + +template +KFR_INTRINSIC vec random_normal(random_state& state, T mu, T sigma) +{ + static_assert(std::is_floating_point_v, "random_normal requires floating point type"); + + constexpr size_t M = align_up(N, 2); // round up to 2 + + vec u = random_uniform(state); + + vec mag = sigma * sqrt(T(-2.0) * log(even(u))); + vec z = dup(mag) * cossin(c_pi * dupodd(u)) + mu; + return slice<0, N>(z); +} + +template +struct expression_random_uniform : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_random_uniform&) + { + return shape(infinite_size); + } + constexpr static shape get_shape() { return shape(infinite_size); } + + mutable state_holder state; + + template + friend KFR_INTRINSIC vec get_elements(const expression_random_uniform& self, shape, + axis_params) + { + return random_uniform(*self.state); + } +}; + +template +struct expression_random_range : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_random_range&) + { + return shape(infinite_size); + } + constexpr static shape get_shape() { return shape(infinite_size); } + + mutable state_holder state; + T min; + T max; + + template + friend KFR_INTRINSIC vec get_elements(const expression_random_range& self, shape, + axis_params) + { + return random_range(*self.state, self.min, self.max); + } +}; + +template +struct expression_random_normal : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_random_normal&) + { + return shape(infinite_size); + } + constexpr static shape get_shape() { return shape(infinite_size); } + + mutable state_holder state; + T sigma{ 1 }; + T mu{ 0 }; + + template + friend KFR_INTRINSIC vec get_elements(const expression_random_normal& self, shape, + axis_params) + { + return random_normal(*self.state, self.mu, self.sigma); + } +}; + +/// @brief Returns expression that returns pseudorandom values. Copies the given generator +template +KFR_FUNCTION expression_random_uniform gen_random_uniform(const random_state& state) +{ + return { {}, state }; +} + +/// @brief Returns expression that returns pseudorandom values. References the given +/// generator. Use std::ref(gen) to force this overload +template +KFR_FUNCTION expression_random_range gen_random_uniform( + std::reference_wrapper state) +{ + return { {}, state }; +} + +#ifndef KFR_DISABLE_READCYCLECOUNTER +/// @brief Returns expression that returns pseudorandom values +template +KFR_FUNCTION expression_random_range gen_random_uniform() +{ + return expression_random_uniform{ random_init() }; +} +#endif + +/// @brief Returns expression that returns pseudorandom values of the given range. Copies the given generator +template +KFR_FUNCTION expression_random_range gen_random_range(const random_state& state, T min, T max) +{ + return { {}, state, min, max }; +} + +/// @brief Returns expression that returns pseudorandom values of the given range. References the given +/// generator. Use std::ref(gen) to force this overload +template +KFR_FUNCTION expression_random_range gen_random_range( + std::reference_wrapper state, T min, T max) +{ + return { {}, state, min, max }; +} + +#ifndef KFR_DISABLE_READCYCLECOUNTER +/// @brief Returns expression that returns pseudorandom values of the given range +template +KFR_FUNCTION expression_random_range gen_random_range(T min, T max) +{ + return { {}, random_init(), min, max }; +} +#endif + +/// @brief Returns expression that returns pseudorandom values from normal (gaussian) distribution. Copies the +/// given generator +template +KFR_FUNCTION expression_random_normal gen_random_normal(const random_state& state, T sigma = 1, + T mu = 0) +{ + return { {}, state, sigma, mu }; +} + +/// @brief Returns expression that returns pseudorandom values from normal (gaussian) distribution. References +/// the given generator. Use std::ref(gen) to force this overload +template +KFR_FUNCTION expression_random_normal gen_random_normal( + std::reference_wrapper state, T sigma = 1, T mu = 0) +{ + return { {}, state, sigma, mu }; +} + +#ifndef KFR_DISABLE_READCYCLECOUNTER +/// @brief Returns expression that returns pseudorandom values from normal (gaussian) distribution +template +KFR_FUNCTION expression_random_normal gen_random_normal(T sigma = 1, T mu = 0) +{ + return { {}, random_init(), sigma, mu }; +} +#endif + +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/random_bits.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/random_bits.hpp new file mode 100644 index 00000000..c8905012 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/random_bits.hpp @@ -0,0 +1,127 @@ +/** @addtogroup random + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/impl/function.hpp" +#include "../simd/operators.hpp" +#include "../simd/shuffle.hpp" +#include "../simd/vec.hpp" +#include "expression.hpp" +#include + +#ifdef CMT_ARCH_ARM +#define KFR_DISABLE_READCYCLECOUNTER +#endif + +namespace kfr +{ + +#ifndef KFR_DISABLE_READCYCLECOUNTER +struct seed_from_rdtsc_t +{ +}; + +constexpr seed_from_rdtsc_t seed_from_rdtsc{}; +#endif + +struct random_state +{ + constexpr random_state() : v{ 0, 0, 0, 0 } {} + constexpr random_state(random_state&&) = default; + constexpr random_state(const random_state&) = default; + constexpr random_state& operator=(random_state&&) = default; + constexpr random_state& operator=(const random_state&) = default; + // internal field + portable_vec v; +}; + +#ifndef KFR_DISABLE_READCYCLECOUNTER +#ifdef CMT_COMPILER_CLANG +#define KFR_builtin_readcyclecounter() \ + static_cast(__builtin_readcyclecounter()) // Intel C++ requires cast here +#else +#define KFR_builtin_readcyclecounter() static_cast(__rdtsc()) +#endif +#endif + +static_assert(sizeof(random_state) == 16, "sizeof(random_state) == 16"); + +inline namespace CMT_ARCH_NAME +{ + +KFR_INTRINSIC void random_next(random_state& state) +{ + constexpr static portable_vec mul{ 214013u, 17405u, 214013u, 69069u }; + constexpr static portable_vec add{ 2531011u, 10395331u, 13737667u, 1u }; + state.v = bitcast(rotateright<3>( + bitcast(fmadd(static_cast(state.v), static_cast(mul), static_cast(add))))); +} + +#ifndef KFR_DISABLE_READCYCLECOUNTER +KFR_INTRINSIC random_state random_init() +{ + random_state state; + state.v = portable_vec{ bitcast(make_vector( + KFR_builtin_readcyclecounter(), (KFR_builtin_readcyclecounter() << 11) ^ 0x710686d615e2257bull)) }; + random_next(state); + return state; +} +#endif + +KFR_INTRINSIC random_state random_init(u32 x0, u32 x1, u32 x2, u32 x3) +{ + random_state state; + state.v = portable_vec{ x0, x1, x2, x3 }; + random_next(state); + return state; +} + +KFR_INTRINSIC random_state random_init(u64 x0, u64 x1) +{ + random_state state; + state.v = portable_vec{ static_cast(x0), static_cast(x0 >> 32), static_cast(x1), + static_cast(x1 >> 32) }; + random_next(state); + return state; +} + +template +KFR_INTRINSIC vec random_bits(random_state& state) +{ + random_next(state); + return narrow(bitcast(u32x4(state.v))); +} + +template sizeof(random_state))> +KFR_INTRINSIC vec random_bits(random_state& state) +{ + constexpr size_t N2 = prev_poweroftwo(N - 1); + const vec bits1 = random_bits(state); + const vec bits2 = random_bits(state); + return concat(bits1, bits2); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/reduce.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/reduce.hpp new file mode 100644 index 00000000..67ba03ab --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/reduce.hpp @@ -0,0 +1,423 @@ +/** @addtogroup reducing + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/horizontal.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/min_max.hpp" +#include "../simd/operators.hpp" +#include "../simd/vec.hpp" +#include "basic_expressions.hpp" +#include "simd_expressions.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC T final_mean(T value, size_t size) +{ + return value / T(size); +} +KFR_FN(final_mean) + +template +KFR_INTRINSIC T final_rootmean(T value, size_t size) +{ + return sqrt(value / T(size)); +} +KFR_FN(final_rootmean) + +template )> +KFR_INTRINSIC auto reduce_call_final(FinalFn&& finalfn, size_t size, T value) +{ + return finalfn(value, size); +} +template )> +KFR_INTRINSIC auto reduce_call_final(FinalFn&& finalfn, size_t, T value) +{ + return finalfn(value); +} + +template +struct expression_reduce : public expression_traits_defaults +{ + using value_type = Tin; + constexpr static size_t dims = Dims; + constexpr static shape get_shape(const expression_reduce&) { return shape(infinite_size); } + constexpr static shape get_shape() { return shape(infinite_size); } + + constexpr static size_t width = vector_width * bitness_const(1, 2); + + expression_reduce(ReduceFn&& reducefn, TransformFn&& transformfn, FinalFn&& finalfn) + : counter(0), reducefn(std::move(reducefn)), transformfn(std::move(transformfn)), + finalfn(std::move(finalfn)), value(resize(make_vector(reducefn(initialvalue{})))) + { + } + + KFR_MEM_INTRINSIC Tout get() { return reduce_call_final(finalfn, counter, horizontal(value, reducefn)); } + + template + friend KFR_INTRINSIC void set_elements(expression_reduce& self, shape, axis_params, + const identity>& x) + { + self.counter += N; + self.process(x); + } + +protected: + void reset() { counter = 0; } + KFR_MEM_INTRINSIC void process(const vec& x) const + { + value = reducefn(transformfn(x), value); + } + + template + KFR_MEM_INTRINSIC void process(const vec& x) const + { + value = combine(value, reducefn(transformfn(x), narrow(value))); + } + + template width)> + KFR_MEM_INTRINSIC void process(const vec& x) const + { + process(low(x)); + process(high(x)); + } + + mutable size_t counter; + ReduceFn reducefn; + TransformFn transformfn; + FinalFn finalfn; + mutable vec value; +}; + +template , + typename Twork = std::decay_t()(std::declval()))>, + typename Tout = std::decay_t(), std::declval(), std::declval()))>, + KFR_ENABLE_IF(is_input_expression)> +KFR_INTRINSIC Tout reduce(const E1& e1, ReduceFn&& reducefn, + TransformFn&& transformfn = fn_generic::pass_through(), + FinalFn&& finalfn = fn_generic::pass_through()) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + using reducer_t = expression_reduce, Twork, Tin, std::decay_t, + std::decay_t, std::decay_t>; + reducer_t red(std::forward(reducefn), std::forward(transformfn), + std::forward(finalfn)); + process(red, e1); + + return red.get(); +} + +template , + typename Twork = std::decay_t()(std::declval()))>, + typename Tout = std::decay_t(), std::declval(), std::declval()))>, + KFR_ENABLE_IF(!is_input_expression)> +KFR_INTRINSIC Tout reduce(const E1& e1, ReduceFn&& reducefn, + TransformFn&& transformfn = fn_generic::pass_through(), + FinalFn&& finalfn = fn_generic::pass_through()) +{ + Twork result = reducefn(initialvalue()); + size_t counter = 0; + for (const Tin& in : e1) + { + result = reducefn(result, transformfn(in)); + ++counter; + } + return reduce_call_final(finalfn, counter, result); +} + +template +struct histogram_data +{ + using vector_type = univector; + + KFR_MEM_INTRINSIC histogram_data(size_t steps) + { + if constexpr (Bins == 0) + { + m_values = vector_type(2 + steps, 0); + } + } + + KFR_MEM_INTRINSIC TCount operator[](size_t n) const + { + KFR_LOGIC_CHECK(n < size(), "n is outside histogram size"); + return m_values[1 + n]; + } + KFR_MEM_INTRINSIC TCount below() const { return m_values.front(); } + KFR_MEM_INTRINSIC TCount above() const { return m_values.back(); } + KFR_MEM_INTRINSIC size_t size() const { return m_values.size() - 2; } + KFR_MEM_INTRINSIC univector_ref values() const { return m_values.slice(1, size()); } + KFR_MEM_INTRINSIC uint64_t total() const { return m_total; } + + template + KFR_MEM_INTRINSIC void put(const vec& value) + { + vec indices; + if constexpr (is_f_class) + { + const vec x = value * size(); + indices = cast(round(clamp(x, 0, size() - 1))); + indices = select(value < 0, 0, select(value > 1, size() + 1, 1 + indices)); + } + else + { + const vec x = 1 + value; + indices = cast(clamp(x, T(0), T(size() + 1))); + } + CMT_LOOP_UNROLL + for (size_t i = 0; i < N; ++i) + ++m_values[indices[i]]; + m_total += N; + } + template + KFR_MEM_INTRINSIC void put(T value) + { + put(vec{ value }); + } + +private: + vector_type m_values{}; + uint64_t m_total = 0; +}; + +template +struct expression_histogram : public expression_with_traits +{ + mutable histogram_data data{}; + + using expression_with_traits::expression_with_traits; + + KFR_MEM_INTRINSIC expression_histogram(E&& e, size_t steps) + : expression_with_traits{ std::forward(e) }, data(steps) + { + } + + using value_type = typename expression_with_traits::value_type; + + template + friend KFR_INTRINSIC vec get_elements(const expression_histogram& self, + const shape::dims>& index, + const axis_params& sh) + { + vec v = get_elements(self.first(), index, sh); + self.data.put(v); + return v; + } +}; + +/** + * @brief Returns the sum of all the elements in x. + * + * x must have its size and type specified. + * \f[ + * x_0 + x_1 + \ldots + x_{N-1} + * \f] + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T sum(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::add()); +} + +/** + * @brief Returns the arithmetic mean of all the elements in x. + * + * x must have its size and type specified. + * \f[ + * \frac{1}{N}(x_0 + x_1 + \ldots + x_{N-1}) + * \f] + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T mean(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::add(), fn_generic::pass_through(), fn::final_mean()); +} + +/** + * @brief Returns the smallest of all the elements in x. + * + * x must have its size and type specified. + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T minof(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::min()); +} + +/** + * @brief Returns the greatest of all the elements in x. + * + * x must have its size and type specified. + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T maxof(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::max()); +} + +/** + * @brief Returns the smallest in magnitude of all the elements in x. + * + * x must have its size and type specified. + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T absminof(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::absmin()); +} + +/** + * @brief Returns the greatest in magnitude of all the elements in x. + * + * x must have its size and type specified. + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T absmaxof(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::absmax()); +} + +/** + * @brief Returns the dot product of two vectors. + * + * x and y must have their sizes and types specified. + * \f[ + * x_0y_0 + x_1y_1 + \ldots + x_{N-1}y_{N-1} + * \f] + */ +template () * std::declval())>, + KFR_ACCEPT_EXPRESSIONS(E1, E2)> +KFR_FUNCTION T dotproduct(E1&& x, E2&& y) +{ + auto m = std::forward(x) * std::forward(y); + using E12 = decltype(m); + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(std::move(m), fn::add()); +} + +/** + * @brief Returns the root mean square of all the elements in x. + * + * x must have its size and type specified. + * \f[ + \sqrt{\frac{1}{N}( x_0^2 + x_1^2 + \ldots + x_{N-1}^2)} + \f] + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T rms(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::add(), fn::sqr(), fn::final_rootmean()); +} + +/** + * @brief Returns the sum of squares of all the elements in x. + * + * x must have its size and type specified. + * \f[ + x_0^2 + x_1^2 + \ldots + x_{N-1}^2 + \f] + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T sumsqr(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::add(), fn::sqr()); +} + +/** + * @brief Returns the product of all the elements in x. + * + * x must have its size and type specified. + * \f[ + x_0 \cdot x_1 \cdot \ldots \cdot x_{N-1} + \f] + */ +template , KFR_ENABLE_IF(is_input_expression)> +KFR_FUNCTION T product(const E1& x) +{ + static_assert(!is_infinite, "e1 must be a sized expression (use slice())"); + return reduce(x, fn::mul()); +} + +/** + * @brief Returns expression that computes histogram as data flows through it. + * Number of bins defined at runtime + */ +template +KFR_FUNCTION expression_histogram<0, E, TCount> histogram_expression(E&& expr, size_t bins) +{ + return { std::forward(expr), bins }; +} + +/** + * @brief Returns expression that computes histogram as data flows through it. + * Number of bins defined at compile time + */ +template +KFR_FUNCTION expression_histogram histogram_expression(E&& expr) +{ + return { std::forward(expr), Bins }; +} + +/** + * @brief Returns histogram of the expression data. + * Number of bins defined at runtime + */ +template +KFR_FUNCTION histogram_data<0, TCount> histogram(E&& expr, size_t bins) +{ + return sink(histogram_expression(std::forward(expr), bins)).data; +} + +/** + * @brief Returns histogram of the expression data. + * Number of bins defined at compile time + */ +template +KFR_FUNCTION histogram_data histogram(E&& expr) +{ + return sink(histogram_expression(std::forward(expr))).data; +} + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/shape.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/shape.hpp new file mode 100644 index 00000000..2a957575 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/shape.hpp @@ -0,0 +1,943 @@ +/** @addtogroup types + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../except.hpp" +#include "impl/static_array.hpp" + +#include "../cometa/string.hpp" +#include "../simd/logical.hpp" +#include "../simd/min_max.hpp" +#include "../simd/shuffle.hpp" +#include "../simd/types.hpp" + +#include +#include + +namespace kfr +{ + +#ifndef KFR_32BIT_INDICES +#if SIZE_MAX == UINT64_MAX +using index_t = uint64_t; +using signed_index_t = int64_t; +#else +using index_t = uint32_t; +using signed_index_t = int32_t; +#endif +#else +using index_t = uint32_t; +using signed_index_t = int32_t; +#endif +constexpr inline index_t max_index_t = std::numeric_limits::max(); +constexpr inline signed_index_t max_sindex_t = std::numeric_limits::max(); + +template +using cindex_t = cval_t; + +template +constexpr inline cindex_t cindex{}; + +constexpr inline index_t infinite_size = max_index_t; + +constexpr inline index_t undefined_size = 0; + +constexpr inline index_t maximum_dims = 16; + +CMT_INTRINSIC constexpr size_t size_add(size_t x, size_t y) +{ + return (x == infinite_size || y == infinite_size) ? infinite_size : x + y; +} + +CMT_INTRINSIC constexpr size_t size_sub(size_t x, size_t y) +{ + return (x == infinite_size || y == infinite_size) ? infinite_size : (x > y ? x - y : 0); +} + +CMT_INTRINSIC constexpr size_t size_min(size_t x) CMT_NOEXCEPT { return x; } + +template +CMT_INTRINSIC constexpr size_t size_min(size_t x, size_t y, Ts... rest) CMT_NOEXCEPT +{ + return size_min(x < y ? x : y, rest...); +} + +using dimset = static_array_of_size; // std::array; + +template +struct shape; + +namespace internal_generic +{ +template +KFR_INTRINSIC bool increment_indices(shape& indices, const shape& start, const shape& stop, + index_t dim = dims - 1); +} // namespace internal_generic + +template +struct shape : static_array_base> +{ + static_assert(Dims <= 256, "Too many dimensions"); + using base = static_array_base>; + + using base::base; + + constexpr shape(const base& a) : base(a) {} + + static_assert(Dims <= maximum_dims); + + static constexpr size_t dims() { return base::static_size; } + + template + operator index_t() const + { + return this->front(); + } + + template + static constexpr shape from_std_array(const std::array& a) + { + shape result; + std::copy(a.begin(), a.end(), result.begin()); + return result; + } + + template + constexpr std::array to_std_array() const + { + std::array result{}; + std::copy(this->begin(), this->end(), result.begin()); + return result; + } + + bool ge(const shape& other) const + { + if constexpr (Dims == 1) + { + return this->front() >= other.front(); + } + else + { + return all(**this >= *other); + } + } + + index_t trailing_zeros() const + { + for (index_t i = 0; i < Dims; ++i) + { + if (revindex(i) != 0) + return i; + } + return Dims; + } + + bool le(const shape& other) const + { + if constexpr (Dims == 1) + { + return this->front() <= other.front(); + } + else + { + return all(**this <= *other); + } + } + + constexpr shape add(index_t value) const + { + shape result = *this; + result.back() += value; + return result; + } + template + constexpr shape add_at(index_t value, cval_t = {}) const + { + shape result = *this; + result[Axis] += value; + return result; + } + constexpr shape add(const shape& other) const { return **this + *other; } + constexpr shape sub(const shape& other) const { return **this - *other; } + constexpr index_t sum() const { return (*this)->sum(); } + + constexpr bool has_infinity() const + { + for (index_t i = 0; i < Dims; ++i) + { + if (CMT_UNLIKELY(this->operator[](i) == infinite_size)) + return true; + } + return false; + } + + friend constexpr shape add_shape(const shape& lhs, const shape& rhs) + { + return lhs.bin(rhs, [](index_t x, index_t y) { return std::max(std::max(x, y), x + y); }); + } + friend constexpr shape sub_shape(const shape& lhs, const shape& rhs) + { + return lhs.bin(rhs, [](index_t x, index_t y) + { return std::max(x, y) == infinite_size ? infinite_size : x - y; }); + } + friend constexpr shape add_shape_undef(const shape& lhs, const shape& rhs) + { + return lhs.bin(rhs, + [](index_t x, index_t y) + { + bool inf = std::max(x, y) == infinite_size; + bool undef = std::min(x, y) == undefined_size; + return inf ? infinite_size : undef ? undefined_size : x + y; + }); + } + friend constexpr shape sub_shape_undef(const shape& lhs, const shape& rhs) + { + return lhs.bin(rhs, + [](index_t x, index_t y) + { + bool inf = std::max(x, y) == infinite_size; + bool undef = std::min(x, y) == undefined_size; + return inf ? infinite_size : undef ? undefined_size : x - y; + }); + } + + friend constexpr shape min(const shape& x, const shape& y) { return x->min(*y); } + + constexpr const base& operator*() const { return static_cast(*this); } + + constexpr const base* operator->() const { return static_cast(this); } + + KFR_MEM_INTRINSIC constexpr size_t to_flat(const shape& indices) const + { + if constexpr (Dims == 1) + { + return indices[0]; + } + else if constexpr (Dims == 2) + { + return (*this)[1] * indices[0] + indices[1]; + } + else + { + size_t result = 0; + size_t scale = 1; + CMT_LOOP_UNROLL + for (size_t i = 0; i < Dims; ++i) + { + result += scale * indices[Dims - 1 - i]; + scale *= (*this)[Dims - 1 - i]; + } + return result; + } + } + KFR_MEM_INTRINSIC constexpr shape from_flat(size_t index) const + { + if constexpr (Dims == 1) + { + return { static_cast(index) }; + } + else if constexpr (Dims == 2) + { + index_t sz = (*this)[1]; + return { static_cast(index / sz), static_cast(index % sz) }; + } + else + { + shape indices; + CMT_LOOP_UNROLL + for (size_t i = 0; i < Dims; ++i) + { + size_t sz = (*this)[Dims - 1 - i]; + indices[Dims - 1 - i] = index % sz; + index /= sz; + } + return indices; + } + } + + KFR_MEM_INTRINSIC constexpr index_t dot(const shape& other) const { return (*this)->dot(*other); } + + template + KFR_MEM_INTRINSIC constexpr shape adapt(const shape& other, cbool_t = {}) const + { + static_assert(indims >= Dims); + if constexpr (stop) + return other.template trim()->min(**this); + else + return other.template trim()->min(**this - 1); + } + + KFR_MEM_INTRINSIC constexpr index_t product() const { return (*this)->product(); } + + KFR_MEM_INTRINSIC constexpr dimset tomask() const + { + dimset result(0); + for (index_t i = 0; i < Dims; ++i) + { + result[i + maximum_dims - Dims] = this->operator[](i) == 1 ? 0 : -1; + } + return result; + } + + template + constexpr KFR_MEM_INTRINSIC shape extend(index_t value = infinite_size) const + { + static_assert(new_dims >= Dims); + if constexpr (new_dims == Dims) + return *this; + else + return shape{ shape(value), *this }; + } + + template + constexpr shape trim() const + { + static_assert(odims <= Dims); + if constexpr (odims > 0) + { + return this->template slice(); + } + else + { + return {}; + } + } + + // 0,1,2,3 -> 1,2,3,0 + constexpr KFR_MEM_INTRINSIC shape rotate_left() const + { + return this->shuffle(csizeseq % csize); + } + + // 0,1,2,3 -> 3,0,1,2 + constexpr KFR_MEM_INTRINSIC shape rotate_right() const + { + return this->shuffle(csizeseq % csize); + } + + constexpr KFR_MEM_INTRINSIC shape remove_back() const + { + if constexpr (Dims > 1) + { + return this->template slice<0, Dims - 1>(); + } + else + { + return {}; + } + } + constexpr KFR_MEM_INTRINSIC shape remove_front() const + { + if constexpr (Dims > 1) + { + return this->template slice<1, Dims - 1>(); + } + else + { + return {}; + } + } + + constexpr KFR_MEM_INTRINSIC shape trunc() const { return remove_back(); } + + KFR_MEM_INTRINSIC constexpr index_t revindex(size_t index) const + { + return index < Dims ? this->operator[](Dims - 1 - index) : 1; + } + KFR_MEM_INTRINSIC constexpr void set_revindex(size_t index, index_t val) + { + if (CMT_LIKELY(index < Dims)) + this->operator[](Dims - 1 - index) = val; + } + + KFR_MEM_INTRINSIC constexpr shape transpose() const + { + return this->shuffle(csizeseq); + } +}; + +template <> +struct shape<0> +{ + static constexpr size_t static_size = 0; + + static constexpr size_t size() { return static_size; } + + static constexpr size_t dims() { return static_size; } + + constexpr shape() = default; + constexpr shape(index_t value) {} + + constexpr bool has_infinity() const { return false; } + + KFR_MEM_INTRINSIC size_t to_flat(const shape<0>& indices) const { return 0; } + KFR_MEM_INTRINSIC shape<0> from_flat(size_t index) const { return {}; } + + template + KFR_MEM_INTRINSIC shape<0> adapt(const shape& other, cbool_t = {}) const + { + return {}; + } + + index_t trailing_zeros() const { return 0; } + + KFR_MEM_INTRINSIC index_t dot(const shape& other) const { return 0; } + + KFR_MEM_INTRINSIC index_t product() const { return 0; } + + KFR_MEM_INTRINSIC dimset tomask() const { return dimset(-1); } + + template + constexpr KFR_MEM_INTRINSIC shape extend(index_t value = infinite_size) const + { + if constexpr (new_dims == 0) + return *this; + else + return shape{ value }; + } + + template + constexpr shape trim() const + { + static_assert(new_dims == 0); + return {}; + } + + KFR_MEM_INTRINSIC constexpr bool operator==(const shape<0>& other) const { return true; } + KFR_MEM_INTRINSIC constexpr bool operator!=(const shape<0>& other) const { return false; } + + KFR_MEM_INTRINSIC constexpr index_t revindex(size_t index) const { return 1; } + KFR_MEM_INTRINSIC void set_revindex(size_t index, index_t val) {} +}; + +constexpr inline size_t dynamic_shape = std::numeric_limits::max(); + +template <> +struct shape : protected std::vector +{ + using std::vector::vector; + + using std::vector::begin; + using std::vector::end; + using std::vector::data; + using std::vector::size; + using std::vector::front; + using std::vector::back; + using std::vector::operator[]; + + template + shape(shape sh) : shape(sh.begin(), sh.end()) + { + } + + size_t dims() const { return size(); } + + KFR_MEM_INTRINSIC index_t product() const + { + if (std::vector::empty()) + return 0; + index_t p = this->front(); + for (size_t i = 1; i < size(); ++i) + { + p *= this->operator[](i); + } + return p; + } + + // 0,1,2,3 -> 1,2,3,0 + KFR_MEM_INTRINSIC shape rotate_left() const + { + shape result = *this; + if (result.size() > 1) + std::rotate(result.begin(), result.begin() + 1, result.end()); + return result; + } + + // 0,1,2,3 -> 3,0,1,2 + KFR_MEM_INTRINSIC shape rotate_right() const + { + shape result = *this; + if (result.size() > 1) + std::rotate(result.begin(), result.end() - 1, result.end()); + return result; + } + + KFR_MEM_INTRINSIC shape remove_back() const + { + shape result = *this; + if (!result.empty()) + result.erase(result.end() - 1); + return result; + } + KFR_MEM_INTRINSIC shape remove_front() const + { + shape result = *this; + if (!result.empty()) + { + result.erase(result.begin()); + } + return result; + } +}; + +template +shape(Args&&... args) -> shape; + +namespace internal_generic +{ + +template +KFR_MEM_INTRINSIC shape adapt(const shape& in, const dimset& set) +{ + static_assert(indims >= outdims); + if constexpr (outdims == 0) + { + return {}; + } + else + { + const static_array_of_size eset = set.template cast(); + return in->template slice() & + eset.template slice(); + } +} +template +KFR_MEM_INTRINSIC shape adapt(const shape<0>& in, const dimset& set) +{ + static_assert(outdims == 0); + return {}; +} +} // namespace internal_generic + +template +struct cursor +{ + shape current; + shape minimum; + shape maximum; +}; + +using opt_index_t = std::optional; + +struct tensor_range +{ + opt_index_t start; + opt_index_t stop; + opt_index_t step; +}; + +constexpr KFR_INTRINSIC tensor_range trange(std::optional start = std::nullopt, + std::optional stop = std::nullopt, + std::optional step = std::nullopt) +{ + return { start, stop, step }; +} + +constexpr KFR_INTRINSIC tensor_range tall() { return trange(); } +constexpr KFR_INTRINSIC tensor_range tstart(signed_index_t start, signed_index_t step = 1) +{ + return trange(start, std::nullopt, step); +} +constexpr KFR_INTRINSIC tensor_range tstop(signed_index_t stop, signed_index_t step = 1) +{ + return trange(std::nullopt, stop, step); +} +constexpr KFR_INTRINSIC tensor_range tstep(signed_index_t step = 1) +{ + return trange(std::nullopt, std::nullopt, step); +} + +namespace internal_generic +{ + +constexpr inline index_t null_index = max_index_t; + +template +constexpr KFR_INTRINSIC shape strides_for_shape(const shape& sh, index_t stride = 1) +{ + shape strides; + if constexpr (dims > 0) + { + index_t n = stride; + for (index_t i = 0; i < dims; ++i) + { + strides[fortran_order ? i : dims - 1 - i] = n; + n *= sh[fortran_order ? i : dims - 1 - i]; + } + } + return strides; +} + +template +constexpr KFR_INTRINSIC shape compact_shape(const shape& in) +{ + shape result; + constexpr std::array flags{ ranges... }; + size_t j = 0; + for (size_t i = 0; i < dims; ++i) + { + if (CMT_LIKELY(i >= flags.size() || flags[i])) + { + result[j++] = in[i]; + } + } + return result; +} + +template +constexpr bool can_assign_from(const shape& dst_shape, const shape& src_shape) +{ + if constexpr (dims2 == 0) + { + return true; + } + else + { + for (size_t i = 0; i < outdims; ++i) + { + index_t dst_size = dst_shape.revindex(i); + index_t src_size = src_shape.revindex(i); + if (CMT_LIKELY(src_size == 1 || src_size == infinite_size || src_size == dst_size || + dst_size == infinite_size)) + { + } + else + { + return false; + } + } + return true; + } +} + +template +constexpr shape common_shape(const shape& shape) +{ + return shape; +} + +template +KFR_MEM_INTRINSIC constexpr shape common_shape(const shape& shape1, + const shape& shape2) +{ + shape result; + for (size_t i = 0; i < outdims; ++i) + { + index_t size1 = shape1.revindex(i); + index_t size2 = shape2.revindex(i); + if (CMT_UNLIKELY(!size1 || !size2)) + { + result[outdims - 1 - i] = 0; + continue; + } + + if (CMT_UNLIKELY(size1 == infinite_size)) + { + if (CMT_UNLIKELY(size2 == infinite_size)) + { + result[outdims - 1 - i] = infinite_size; + } + else + { + result[outdims - 1 - i] = size2 == 1 ? infinite_size : size2; + } + } + else + { + if (CMT_UNLIKELY(size2 == infinite_size)) + { + result[outdims - 1 - i] = size1 == 1 ? infinite_size : size1; + } + else + { + if (CMT_LIKELY(size1 == 1 || size2 == 1 || size1 == size2)) + { + result[outdims - 1 - i] = std::max(size1, size2); + } + else + { + // broadcast failed + if constexpr (checked) + { + KFR_LOGIC_CHECK(false, "invalid or incompatible shapes: ", shape1, " and ", shape2); + } + else + { + result = shape(0); + return result; + } + } + } + } + } + return result; +} + +template +KFR_MEM_INTRINSIC constexpr shape<0> common_shape(const shape<0>& shape1, const shape<0>& shape2) +{ + return {}; +} + +template +KFR_MEM_INTRINSIC constexpr shape common_shape(const shape& shape1, + const shape& shape2, + const shape&... shapes) +{ + return common_shape(shape1, common_shape(shape2, shapes...)); +} + +template +KFR_MEM_INTRINSIC bool same_layout(const shape& x, const shape& y) +{ + for (index_t i = 0, j = 0;;) + { + while (i < dims1 && x[i] == 1) + ++i; + while (j < dims2 && y[j] == 1) + ++j; + if (i == dims1 && j == dims2) + { + return true; + } + if (i < dims1 && j < dims2) + { + if (x[i] != y[j]) + return false; + } + else + { + return false; + } + ++i; + ++j; + } +} + +#ifdef KFR_VEC_INDICES +template +KFR_INTRINSIC vec increment_indices(vec indices, + const vec& start, + const vec& stop) +{ + indices = indices + make_vector(cconcat(cvalseq, cvalseq, + cvalseq)); + + if constexpr (step + 1 < dims) + { + vec, dims> mask = indices >= stop; + if (CMT_LIKELY(!any(mask))) + return indices; + indices = blend(indices, start, cconcat(csizeseq, csizeseq)); + + return increment_indices(indices, stop); + } + else + { + return indices; + } +} +#endif + +template +KFR_INTRINSIC bool compare_indices(const shape& indices, const shape& stop, + index_t dim = dims - 1) +{ + CMT_LOOP_UNROLL + for (int i = static_cast(dim); i >= 0; --i) + { + if (CMT_UNLIKELY(indices[i] >= stop[i])) + return false; + } + return true; +} + +template +KFR_INTRINSIC bool increment_indices(shape& indices, const shape& start, const shape& stop, + index_t dim) +{ +#ifdef KFR_VEC_INDICES + vec idx = increment_indices<0>(*indices, *start, *stop); + indices = idx; + if (any(idx == *stop)) + return false; + return true; +#else + if constexpr (dims > 0) + { + indices[dim] += 1; + CMT_LOOP_UNROLL + for (int i = static_cast(dim); i >= 0;) + { + if (CMT_LIKELY(indices[i] < stop[i])) + return true; + // carry + indices[i] = start[i]; + --i; + if (i < 0) + { + return false; + } + indices[i] += 1; + } + return true; + } + else + { + return false; + } +#endif +} + +template +KFR_INTRINSIC shape increment_indices_return(const shape& indices, const shape& start, + const shape& stop, index_t dim = dims - 1) +{ + shape result = indices; + if (CMT_LIKELY(increment_indices(result, start, stop, dim))) + { + return result; + } + else + { + return shape(null_index); + } +} + +template +constexpr KFR_INTRINSIC size_t count_dimensions() +{ + return ((std::is_same_v, tensor_range> ? 1 : 0) + ...); +} + +template +struct type_of_list +{ + using value_type = U; +}; + +template +struct type_of_list> +{ + using value_type = typename type_of_list::value_type; +}; + +template +using type_of_list_t = typename type_of_list::value_type; + +template +constexpr KFR_INTRINSIC shape<1> shape_of_list(const std::initializer_list& list) +{ + return list.size(); +} + +template +constexpr KFR_INTRINSIC auto shape_of_list(const std::initializer_list>& list) +{ + return shape_of_list(*list.begin()); +} + +template +constexpr KFR_INTRINSIC U list_get(const std::initializer_list& list, const shape<1>& idx) +{ + return list[idx.front()]; +} + +template +constexpr KFR_INTRINSIC auto list_get(const std::initializer_list>& list, + const shape& idx) +{ + return list_get(list[idx[0]], idx.template trim()); +} + +template +KFR_FUNCTION T* list_copy_recursively(const std::initializer_list& list, T* dest) +{ + for (const auto& value : list) + *dest++ = static_cast(value); + return dest; +} + +template +KFR_FUNCTION T* list_copy_recursively(const std::initializer_list>& list, T* dest) +{ + for (const auto& sublist : list) + dest = list_copy_recursively(sublist, dest); + return dest; +} + +} // namespace internal_generic + +template +constexpr KFR_INTRINSIC index_t size_of_shape(const shape& shape) +{ + index_t n = 1; + if constexpr (dims > 0) + { + for (index_t i = 0; i < dims; ++i) + { + n *= shape[i]; + } + } + return n; +} + +template +struct axis_params +{ + constexpr static index_t axis = Axis; + constexpr static index_t width = N; + constexpr static index_t value = N; + + constexpr axis_params() = default; +}; + +template +constexpr inline const axis_params axis_params_v{}; + +} // namespace kfr + +namespace cometa +{ +template +struct representation> +{ + using type = std::string; + static std::string get(const kfr::shape& value) + { + if constexpr (dims == 0) + { + return "shape{}"; + } + else + { + return "shape" + array_to_string(dims, value.data()); + } + } +}; + +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/simd_expressions.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/simd_expressions.hpp new file mode 100644 index 00000000..7a14c910 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/simd_expressions.hpp @@ -0,0 +1,489 @@ +/** @addtogroup expressions + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/abs.hpp" +#include "../simd/clamp.hpp" +#include "../simd/comparison.hpp" +#include "../simd/complex.hpp" +#include "../simd/min_max.hpp" +#include "../simd/operators.hpp" +#include "../simd/round.hpp" +#include "../simd/saturation.hpp" +#include "../simd/select.hpp" +#include "../simd/vec.hpp" +#include "expression.hpp" +#include "univector.hpp" +#include + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns template expression that returns sum of all the arguments passed to a function. + */ +template +KFR_INTRINSIC expression_make_function add(E&&... x) +{ + return { fn::add(), std::forward(x)... }; +} + +template +KFR_INTRINSIC expression_make_function sub(E1&& x, E2&& y) +{ + return { fn::sub(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns template expression that returns product of all the arguments passed to a function. + */ +template +KFR_INTRINSIC expression_make_function mul(E&&... x) +{ + return { fn::mul(), std::forward(x)... }; +} + +template +KFR_INTRINSIC expression_make_function ipow(E1&& x, E2&& b) +{ + return { fn::ipow(), std::forward(x), std::forward(b) }; +} + +template +KFR_INTRINSIC expression_make_function mix(E1&& c, E2&& x, E3&& y) +{ + return { fn::mix(), std::forward(c), std::forward(x), std::forward(y) }; +} + +template +KFR_INTRINSIC expression_make_function mixs(E1&& c, E2&& x, E3&& y) +{ + return { fn::mixs(), std::forward(c), std::forward(x), std::forward(y) }; +} + +template +KFR_INTRINSIC expression_make_function horner(E&&... x) +{ + return { fn::horner(), std::forward(x)... }; +} + +template +KFR_INTRINSIC expression_make_function horner_even(E&&... x) +{ + return { fn::horner_even(), std::forward(x)... }; +} + +template +KFR_INTRINSIC expression_make_function horner_odd(E&&... x) +{ + return { fn::horner_odd(), std::forward(x)... }; +} + +template +KFR_INTRINSIC expression_make_function operator+(E1&& e1, E2&& e2) +{ + return { fn::add(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator-(E1&& e1, E2&& e2) +{ + return { fn::sub(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator*(E1&& e1, E2&& e2) +{ + return { fn::mul(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator/(E1&& e1, E2&& e2) +{ + return { fn::div(), std::forward(e1), std::forward(e2) }; +} +template +KFR_INTRINSIC expression_make_function operator%(E1&& e1, E2&& e2) +{ + return { fn::mod(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator&(E1&& e1, E2&& e2) +{ + return { fn::bitwiseand(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator|(E1&& e1, E2&& e2) +{ + return { fn::bitwiseor(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator^(E1&& e1, E2&& e2) +{ + return { fn::bitwisexor(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator<<(E1&& e1, E2&& e2) +{ + return { fn::shl(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator>>(E1&& e1, E2&& e2) +{ + return { fn::shr(), std::forward(e1), std::forward(e2) }; +} + +/** + * @brief Returns template expression that returns square of x. + */ +template +KFR_INTRINSIC expression_make_function sqr(E1&& x) +{ + return { fn::sqr(), std::forward(x) }; +} + +/** + * @brief Returns template expression that returns cube of x. + */ +template +KFR_INTRINSIC expression_make_function cub(E1&& x) +{ + return { fn::cub(), std::forward(x) }; +} + +template +KFR_INTRINSIC expression_make_function pow2(E1&& x) +{ + return { fn::pow2(), std::forward(x) }; +} +template +KFR_INTRINSIC expression_make_function pow3(E1&& x) +{ + return { fn::pow3(), std::forward(x) }; +} +template +KFR_INTRINSIC expression_make_function pow4(E1&& x) +{ + return { fn::pow4(), std::forward(x) }; +} +template +KFR_INTRINSIC expression_make_function pow5(E1&& x) +{ + return { fn::pow5(), std::forward(x) }; +} + +template +KFR_INTRINSIC expression_make_function operator-(E1&& e1) +{ + return { fn::neg(), std::forward(e1) }; +} + +template +KFR_INTRINSIC expression_make_function operator~(E1&& e1) +{ + return { fn::bitwisenot(), std::forward(e1) }; +} + +/// @brief Constructs complex value from real and imaginary parts +template +KFR_INTRINSIC expression_make_function make_complex(E1&& re, E2&& im) +{ + return { fn::make_complex{}, std::forward(re), std::forward(im) }; +} + +template +KFR_INTRINSIC expression_make_function operator==(E1&& e1, E2&& e2) +{ + return { fn::equal(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator!=(E1&& e1, E2&& e2) +{ + return { fn::notequal(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator<(E1&& e1, E2&& e2) +{ + return { fn::less(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator>(E1&& e1, E2&& e2) +{ + return { fn::greater(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator<=(E1&& e1, E2&& e2) +{ + return { fn::lessorequal(), std::forward(e1), std::forward(e2) }; +} + +template +KFR_INTRINSIC expression_make_function operator>=(E1&& e1, E2&& e2) +{ + return { fn::greaterorequal(), std::forward(e1), std::forward(e2) }; +} + +/// @brief Returns the real part of the complex value +template +KFR_INTRINSIC expression_make_function real(E1&& x) +{ + return { fn::real{}, std::forward(x) }; +} + +/// @brief Returns the imaginary part of the complex value +template +KFR_INTRINSIC expression_make_function imag(E1&& x) +{ + return { fn::imag{}, std::forward(x) }; +} + +/// @brief Returns template expression that returns the complex conjugate of the complex number x +template +KFR_FUNCTION expression_make_function cconj(E1&& x) +{ + return { fn::cconj(), std::forward(x) }; +} + +template +CMT_INTRINSIC expression_make_function interleave(E1&& x, E2&& y) +{ + return { fn::interleave(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns template expression that returns x if m is true, otherwise return y. Order of the arguments + * is same as in ternary operator. + */ +template +KFR_FUNCTION expression_make_function select(E1&& m, E2&& x, E3&& y) +{ + return { fn::select(), std::forward(m), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns template expression that returns the absolute value of x. + */ +template +KFR_FUNCTION expression_make_function abs(E1&& x) +{ + return { fn::abs(), std::forward(x) }; +} + +/** + * @brief Returns the smaller of two values. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function min(E1&& x, E2&& y) +{ + return { fn::min(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns the greater of two values. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function max(E1&& x, E2&& y) +{ + return { fn::max(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns the smaller in magnitude of two values. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function absmin(E1&& x, E2&& y) +{ + return { fn::absmin(), std::forward(x), std::forward(y) }; +} + +/** + * @brief Returns the greater in magnitude of two values. Accepts and returns expressions. + */ +template +KFR_FUNCTION expression_make_function absmax(E1&& x, E2&& y) +{ + return { fn::absmax(), std::forward(x), std::forward(y) }; +} + +/// @brief Returns the largest integer value not greater than x. Accepts and returns expressions. +template +KFR_FUNCTION expression_make_function floor(E1&& x) +{ + return { fn::floor(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function ceil(E1&& x) +{ + return { fn::ceil(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function round(E1&& x) +{ + return { fn::round(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function trunc(E1&& x) +{ + return { fn::trunc(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function fract(E1&& x) +{ + return { fn::fract(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function ifloor(E1&& x) +{ + return { fn::ifloor(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function iceil(E1&& x) +{ + return { fn::iceil(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function iround(E1&& x) +{ + return { fn::iround(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_make_function itrunc(E1&& x) +{ + return { fn::itrunc(), std::forward(x) }; +} + +/// @brief Creates an expression that returns the first argument clamped to a range [lo, hi] +template +KFR_FUNCTION expression_make_function clamp(E1&& x, E2&& lo, E3&& hi) +{ + return { fn::clamp(), std::forward(x), std::forward(lo), std::forward(hi) }; +} + +/// @brief Creates an expression that returns the first argument clamped to a range [0, hi] +template +KFR_FUNCTION expression_make_function clamp(E1&& x, E2&& hi) +{ + return { fn::clamp(), std::forward(x), std::forward(hi) }; +} + +/// @brief Creates an expression that adds two arguments using saturation +template +KFR_INTRINSIC expression_make_function satadd(E1&& x, E2&& y) +{ + return { fn::satadd(), std::forward(x), std::forward(y) }; +} + +/// @brief Creates an expression that subtracts two arguments using saturation +template +KFR_INTRINSIC expression_make_function satsub(E1&& x, E2&& y) +{ + return { fn::satsub(), std::forward(x), std::forward(y) }; +} + +template +KFR_INTRINSIC E1& operator+=(E1&& e1, E2&& e2) +{ + process(e1, operator+(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator-=(E1&& e1, E2&& e2) +{ + process(e1, operator-(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator*=(E1&& e1, E2&& e2) +{ + process(e1, operator*(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator/=(E1&& e1, E2&& e2) +{ + process(e1, operator/(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator%=(E1&& e1, E2&& e2) +{ + process(e1, operator%(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator|=(E1&& e1, E2&& e2) +{ + process(e1, operator|(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator&=(E1&& e1, E2&& e2) +{ + process(e1, operator&(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator^=(E1&& e1, E2&& e2) +{ + process(e1, operator^(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator<<=(E1&& e1, E2&& e2) +{ + process(e1, operator<<(e1, e2)); + return e1; +} +template +KFR_INTRINSIC E1& operator>>=(E1&& e1, E2&& e2) +{ + process(e1, operator>>(e1, e2)); + return e1; +} + +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/small_buffer.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/small_buffer.hpp new file mode 100644 index 00000000..eff8da65 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/small_buffer.hpp @@ -0,0 +1,115 @@ +/** @addtogroup types + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "memory.hpp" +#include +#include + +namespace kfr +{ +template +struct small_buffer +{ +public: + small_buffer() CMT_NOEXCEPT : m_size(0), m_data(m_preallocated) {} + + small_buffer(std::size_t size) : small_buffer() { resize(size); } + + friend void swap(small_buffer& first, small_buffer& second) CMT_NOEXCEPT + { + using std::swap; + + swap(first.m_size, second.m_size); + swap(first.m_data, second.m_data); + swap(first.m_preallocated, second.m_preallocated); + first.m_data = first.m_size <= Capacity ? first.m_preallocated : first.m_data; + second.m_data = second.m_size <= Capacity ? second.m_preallocated : second.m_data; + } + small_buffer(small_buffer&& other) : small_buffer() { swap(other, *this); } + + small_buffer(const small_buffer& other) : small_buffer() { assign(other); } + small_buffer& operator=(small_buffer other) + { + swap(other, *this); + return *this; + } + + ~small_buffer() { clear(); } + + void assign(const small_buffer& other) + { + resize(other.m_size); + std::copy_n(other.m_data, m_size, m_data); + } + + void resize(std::size_t newsize) + { + T* m_newdata; + if (newsize <= Capacity) + { + m_newdata = m_preallocated; + } + else + { + m_newdata = aligned_allocate(newsize); + } + std::copy_n(std::make_move_iterator(m_data), std::min(newsize, m_size), m_newdata); + if (m_data != m_preallocated) + aligned_deallocate(m_data); + m_data = m_newdata; + m_size = newsize; + } + bool empty() const { return !size(); } + std::size_t size() const { return m_size; } + const T* begin() const { return m_data; } + const T* end() const { return m_data + m_size; } + const T* cbegin() const { return m_data; } + const T* cend() const { return m_data + m_size; } + T* begin() { return m_data; } + T* end() { return m_data + m_size; } + void clear() { resize(0); } + const T& front() const { return m_data[0]; } + const T& back() const { return m_data[m_size - 1]; } + T& front() { return m_data[0]; } + T& back() { return m_data[m_size - 1]; } + void pop_back() { resize(m_size - 1); } + T* data() { return m_data; } + const T* data() const { return m_data; } + T& operator[](std::size_t i) { return m_data[i]; } + const T& operator[](std::size_t i) const { return m_data[i]; } + void push_back(const T& value) + { + resize(m_size + 1); + m_data[m_size - 1] = value; + } + +protected: + T m_preallocated[Capacity]; + std::size_t m_size; + T* m_data; +}; +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/state_holder.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/state_holder.hpp new file mode 100644 index 00000000..e2d6a05c --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/state_holder.hpp @@ -0,0 +1,67 @@ +/** @addtogroup filter + * @{ + */ +/** + * KFR (https://www.kfrlib.com) + * Copyright (C) 2016-2023 Dan Cazarin + * See LICENSE.txt for details + */ +#pragma once + +#include "../cident.h" +#include + +namespace kfr +{ + +template +struct state_holder; + +template +struct state_holder +{ + static_assert(!std::is_const_v, "state_holder: T must not be const"); + + constexpr state_holder() = delete; + constexpr state_holder(const state_holder&) = default; + constexpr state_holder(state_holder&&) = default; + constexpr state_holder(T state) CMT_NOEXCEPT : s(std::move(state)) {} + constexpr state_holder(std::reference_wrapper state) = delete; + constexpr state_holder(std::reference_wrapper state) = delete; + constexpr state_holder(state_holder stateless) : s(*stateless) {} + T s; + + const T* operator->() const { return &s; } + T* operator->() { return &s; } + const T& operator*() const { return s; } + T& operator*() { return s; } +}; + +template +struct state_holder +{ + static_assert(!std::is_const_v, "state_holder: T must not be const"); + + constexpr state_holder() = delete; + constexpr state_holder(const state_holder&) = default; + constexpr state_holder(state_holder&&) = default; + constexpr state_holder(T state) CMT_NOEXCEPT = delete; + constexpr state_holder(const T& state) CMT_NOEXCEPT = delete; + constexpr state_holder(T& state) CMT_NOEXCEPT = delete; + constexpr state_holder(T&& state) CMT_NOEXCEPT = delete; + constexpr state_holder(std::reference_wrapper state) CMT_NOEXCEPT : s(&state.get()) {} + T* s; + + const T* operator->() const { return s; } + T* operator->() { return s; } + const T& operator*() const { return *s; } + T& operator*() { return *s; } +}; + +static_assert(std::is_copy_constructible_v>); +static_assert(std::is_copy_constructible_v>); + +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/tensor.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/tensor.hpp new file mode 100644 index 00000000..a0fdacc3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/tensor.hpp @@ -0,0 +1,1005 @@ +/** @addtogroup tensor + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include + +#include "../cometa/array.hpp" + +#include "../simd/horizontal.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/logical.hpp" +#include "../simd/min_max.hpp" +#include "../simd/read_write.hpp" +#include "../simd/types.hpp" +#include "expression.hpp" +#include "memory.hpp" +#include "shape.hpp" +#include "transpose.hpp" + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4324)) + +namespace kfr +{ + +namespace internal_generic +{ +struct memory_finalizer_base +{ + virtual ~memory_finalizer_base() {} +}; +template +struct memory_finalizer_data : public memory_finalizer_base +{ + constexpr KFR_INTRINSIC memory_finalizer_data(Data&& data) : data(std::move(data)) {} + Data data; +}; +template +struct memory_finalizer_func : public memory_finalizer_data +{ + using memory_finalizer_data::memory_finalizer_data; + KFR_INTRINSIC ~memory_finalizer_func() { this->data(); } +}; +} // namespace internal_generic + +using memory_finalizer = std::shared_ptr; + +template +memory_finalizer KFR_INTRINSIC make_memory_finalizer(Fn&& fn) +{ + return memory_finalizer(new internal_generic::memory_finalizer_func{ std::move(fn) }); +} + +template +struct tensor_subscript; + +template +struct tensor_subscript> +{ + constexpr static inline size_t dims = sizeof...(Dims); + + using reference = T&; + using const_reference = const T&; + + reference KFR_MEM_INTRINSIC operator()(type_for... idx) const + { + return static_cast(*this).access(shape{ idx... }); + } +}; + +/// @brief tensor holds or references multidimensional data and +/// provides a way to access individual elements and perform complex operations on the data. +/// +/// The number of elements in each axis of the array is defined by its shape. +/// @tparam T element type +/// @tparam NDims number of dimensions +template +struct tensor : public tensor_subscript, std::make_integer_sequence> +{ +public: + using value_type = T; + using pointer = T* CMT_RESTRICT; + using const_pointer = const T* CMT_RESTRICT; + using reference = T&; + using const_reference = const T&; + using size_type = index_t; + + constexpr static inline index_t dims = NDims; + + using shape_type = kfr::shape; + + /// @brief Tensor iterator. Iterates through flattened array + struct tensor_iterator + { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + + const tensor* src; + shape_type indices; + + KFR_MEM_INTRINSIC intptr_t flat_index() const { return src->calc_index(indices); } + + KFR_MEM_INTRINSIC bool is_end() const { return indices.front() == internal_generic::null_index; } + + KFR_MEM_INTRINSIC T& operator*() { return src->m_data[flat_index()]; } + KFR_MEM_INTRINSIC T* operator->() { return &operator*(); } + + // prefix + KFR_MEM_INTRINSIC tensor_iterator& operator++() + { + if (!internal_generic::increment_indices(indices, shape_type(0), src->m_shape)) + { + indices = shape_type(internal_generic::null_index); + } + return *this; + } + + // postfix + KFR_MEM_INTRINSIC tensor_iterator operator++(int) + { + tensor_iterator temp = *this; + ++*this; + return temp; + } + + KFR_MEM_INTRINSIC bool operator==(const tensor_iterator& it) const + { + return src == it.src && indices == it.indices; + } + KFR_MEM_INTRINSIC bool operator!=(const tensor_iterator& it) const { return !operator==(it); } + }; + + using iterator = tensor_iterator; + using const_iterator = tensor_iterator; + + using contiguous_iterator = pointer; + using const_contiguous_iterator = pointer; + + /// @brief Default constructor. Creates tensor with null shape + KFR_MEM_INTRINSIC constexpr tensor() + : m_data(0), m_size(0), m_is_contiguous(false), m_shape{}, m_strides{} + { + } + + /// @brief Construct from external pointer, shape, strides and finalizer + KFR_MEM_INTRINSIC tensor(T* data, const shape_type& shape, const shape_type& strides, + memory_finalizer finalizer) + : m_data(data), m_size(size_of_shape(shape)), + m_is_contiguous(strides == internal_generic::strides_for_shape(shape)), m_shape(shape), + m_strides(strides), m_finalizer(std::move(finalizer)) + { + } + + /// @brief Construct from external pointer, shape and finalizer with default strides + KFR_MEM_INTRINSIC tensor(T* data, const shape_type& shape, memory_finalizer finalizer) + : m_data(data), m_size(size_of_shape(shape)), m_is_contiguous(true), m_shape(shape), + m_strides(internal_generic::strides_for_shape(shape)), m_finalizer(std::move(finalizer)) + { + } + + KFR_INTRINSIC static T* allocate(size_t size) { return aligned_allocate(size, 64); } + + KFR_INTRINSIC static void deallocate(T* ptr) { aligned_deallocate(ptr); } + + /// @brief Construct from shape and allocate memory + KFR_INTRINSIC explicit tensor(const shape_type& shape) + : m_size(size_of_shape(shape)), m_is_contiguous(true), m_shape(shape), + m_strides(internal_generic::strides_for_shape(shape)) + { + T* ptr = allocate(m_size); + m_data = ptr; + m_finalizer = make_memory_finalizer([ptr]() { deallocate(ptr); }); + } + + /// @brief Construct from shape, strides and allocate memory + KFR_INTRINSIC tensor(const shape_type& shape, const shape_type& strides) + : m_size(size_of_shape(shape)), + m_is_contiguous(strides == internal_generic::strides_for_shape(shape)), m_shape(shape), + m_strides(strides) + { + T* ptr = allocate(m_size); + m_data = ptr; + m_finalizer = make_memory_finalizer([ptr]() { deallocate(ptr); }); + } + + /// @brief Construct from shape, allocate memory and fill with value + KFR_INTRINSIC tensor(const shape_type& shape, T value) : tensor(shape) + { + std::fill(contiguous_begin_unsafe(), contiguous_end_unsafe(), value); + } + + /// @brief Construct from shape, strides, allocate memory and fill with value + KFR_INTRINSIC tensor(const shape_type& shape, const shape_type& strides, T value) : tensor(shape, strides) + { + std::fill(begin(), end(), value); + } + + /// @brief Construct from shape, allocate memory and fill with flat list + KFR_INTRINSIC tensor(const shape_type& shape, const std::initializer_list& values) : tensor(shape) + { + if (values.size() != m_size) + KFR_REPORT_LOGIC_ERROR("Invalid initializer provided for kfr::tensor"); + std::copy(values.begin(), values.end(), contiguous_begin_unsafe()); + } + + /// @brief Initialize with braced list. Defined for 1D tensor only + template && dims == 1)> + KFR_INTRINSIC tensor(const std::initializer_list& values) : tensor(shape_type(values.size())) + { + internal_generic::list_copy_recursively(values, contiguous_begin_unsafe()); + } + + /// @brief Initialize with braced list. Defined for 2D tensor only + template && dims == 2)> + KFR_INTRINSIC tensor(const std::initializer_list>& values) + : tensor(shape_type(values.size(), values.begin()->size())) + { + internal_generic::list_copy_recursively(values, contiguous_begin_unsafe()); + } + + /// @brief Initialize with braced list. Defined for 3D tensor only + template && dims == 3)> + KFR_INTRINSIC tensor(const std::initializer_list>>& values) + : tensor(shape_type(values.size(), values.begin()->size(), values.begin()->begin()->size())) + { + internal_generic::list_copy_recursively(values, contiguous_begin_unsafe()); + } + + /// @brief Initialize with braced list. Defined for 4D tensor only + template && dims == 4)> + KFR_INTRINSIC tensor( + const std::initializer_list>>>& + values) + : tensor(shape_type(values.size(), values.begin()->size(), values.begin()->begin()->size(), + values.begin()->begin()->begin()->size())) + { + internal_generic::list_copy_recursively(values, contiguous_begin_unsafe()); + } + + KFR_INTRINSIC tensor(const shape_type& shape, const shape_type& strides, std::initializer_list values) + : tensor(shape, strides) + { + if (values.size() != m_size) + KFR_REPORT_LOGIC_ERROR("Invalid initializer provided for kfr::tensor"); + std::copy(values.begin(), values.end(), begin()); + } + + template + KFR_MEM_INTRINSIC tensor(Input&& input) : tensor(get_shape(input)) + { + static_assert(expression_traits::dims == dims); + process(*this, input); + } + + KFR_INTRINSIC pointer data() const { return m_data; } + + KFR_INTRINSIC size_type size() const { return m_size; } + + KFR_INTRINSIC bool empty() const { return m_size == 0; } + + KFR_INTRINSIC tensor_iterator begin() const + { + if (empty()) + return tensor_iterator{ this, shape_type(internal_generic::null_index) }; + else + return tensor_iterator{ this, shape_type(0) }; + } + KFR_INTRINSIC tensor_iterator end() const + { + return tensor_iterator{ this, shape_type(internal_generic::null_index) }; + } + + KFR_INTRINSIC void require_contiguous() const + { + if (!m_is_contiguous) + KFR_REPORT_LOGIC_ERROR("Contiguous array is required"); + } + + KFR_INTRINSIC contiguous_iterator contiguous_begin() const + { + require_contiguous(); + return m_data; + } + KFR_INTRINSIC contiguous_iterator contiguous_end() const + { + require_contiguous(); + return m_data + m_size; + } + + KFR_INTRINSIC contiguous_iterator contiguous_begin_unsafe() const { return m_data; } + KFR_INTRINSIC contiguous_iterator contiguous_end_unsafe() const { return m_data + m_size; } + + KFR_MEM_INTRINSIC intptr_t calc_index(const shape_type& indices) const + { + return static_cast(static_cast(indices.dot(m_strides))); + } + + KFR_MEM_INTRINSIC reference access(const shape_type& indices) const + { + return m_data[calc_index(indices)]; + } + + KFR_MEM_INTRINSIC reference operator[](index_t flat_index) const { return m_data[flat_index]; } + + KFR_MEM_INTRINSIC tensor operator()(const shape_type& start, const shape_type& stop) const + { + return tensor{ + m_data + calc_index(start), + stop - start, + m_strides, + m_finalizer, + }; + } + +#if defined(CMT_COMPILER_IS_MSVC) + tensor(const tensor& other) + : m_data(other.m_data), m_size(other.m_size), m_is_contiguous(other.m_is_contiguous), + m_shape(other.m_shape), m_strides(other.m_strides), m_finalizer(other.m_finalizer) + { + } + tensor(tensor&& other) + : m_data(other.m_data), m_size(other.m_size), m_is_contiguous(other.m_is_contiguous), + m_shape(other.m_shape), m_strides(other.m_strides), m_finalizer(std::move(other.m_finalizer)) + { + } + tensor(tensor& other) : tensor(const_cast(other)) {} + tensor(const tensor&& other) : tensor(static_cast(other)) {} +#else + tensor(const tensor&) = default; + tensor(tensor&&) = default; + tensor(tensor& other) : tensor(const_cast(other)) {} + tensor(const tensor&& other) : tensor(static_cast(other)) {} +#endif + +#if defined(CMT_COMPILER_IS_MSVC) || true + tensor& operator=(const tensor& src) & + { + this->~tensor(); + new (this) tensor(src); + return *this; + } + tensor& operator=(tensor&& src) & + { + this->~tensor(); + new (this) tensor(std::move(src)); + return *this; + } +#else + tensor& operator=(const tensor& src) & = default; + tensor& operator=(tensor&& src) & = default; +#endif + + KFR_MEM_INTRINSIC const tensor& operator=(const tensor& src) const& + { + assign(src); + return *this; + } + KFR_MEM_INTRINSIC tensor& operator=(const tensor& src) && + { + assign(src); + return *this; + } + KFR_MEM_INTRINSIC const tensor& operator=(const T& scalar) const& + { + assign(scalar); + return *this; + } + KFR_MEM_INTRINSIC tensor& operator=(const T& scalar) && + { + assign(scalar); + return *this; + } + + KFR_MEM_INTRINSIC void assign(const tensor& src) const + { + if (src.shape() != m_shape) + KFR_REPORT_LOGIC_ERROR("Tensors must have same shape"); + std::copy(src.begin(), src.end(), begin()); + } + KFR_MEM_INTRINSIC void assign(const T& scalar) const { std::fill(begin(), end(), scalar); } + + template + static constexpr bool has_tensor_range = (std::is_same_v || ...); + + KFR_MEM_INTRINSIC static void get_range(index_t& start, index_t& shape, index_t& step, + signed_index_t tsize, index_t iidx) + { + signed_index_t tstart = iidx; + tstart = tstart < 0 ? tsize + tstart : tstart; + start = tstart; + shape = tstart < tsize ? 1 : 0; + step = 1; + } + + KFR_MEM_INTRINSIC static void get_range(index_t& start, index_t& shape, index_t& step, + signed_index_t tsize, const tensor_range& iidx) + { + signed_index_t tstep = iidx.step.value_or(1); + signed_index_t tstart; + signed_index_t tstop; + if (tstep >= 0) + { + tstart = iidx.start.value_or(0); + tstop = iidx.stop.value_or(tsize); + } + else + { + tstart = iidx.start ? *iidx.start + 1 : tsize; + tstop = iidx.stop ? *iidx.stop + 1 : 0; + } + tstart = tstart < 0 ? tsize + tstart : tstart; + tstart = std::max(std::min(tstart, tsize), signed_index_t(0)); + if (tstep == 0) + { + start = tstart; + shape = tstop - tstart; + step = 0; + } + else + { + tstop = tstop < 0 ? tsize + tstop : tstop; + tstop = std::max(std::min(tstop, tsize), signed_index_t(0)); + if (tstep >= 0) + { + tstop = std::max(tstop, tstart); + start = tstart; + shape = (tstop - tstart + tstep - 1) / tstep; + step = tstep; + } + else + { + tstart = std::max(tstart, tstop); + shape = (tstart - tstop + -tstep - 1) / -tstep; + start = tstart - 1; + step = tstep; + } + } + } + + template + KFR_MEM_INTRINSIC void get_ranges(shape_type& start, shape_type& shape, shape_type& step, + cvals_t indices, const std::tuple& idx) const + { + cforeach(indices, + [&](auto i_) CMT_INLINE_LAMBDA + { + constexpr index_t i = val_of(decltype(i_)()); + signed_index_t tsize = static_cast(m_shape[i]); + if constexpr (i < sizeof...(Index)) + { + get_range(start[i], shape[i], step[i], tsize, std::get(idx)); + } + else + { + start[i] = 0; + shape[i] = tsize; + step[i] = 1; + } + }); + } + + template () + (dims - sizeof...(Index)), + std::enable_if_t || (sizeof...(Index) < dims)>* = nullptr> + KFR_MEM_INTRINSIC tensor operator()(const Index&... idx) const + { + shape_type start; + shape_type shape; + shape_type step; + get_ranges(start, shape, step, cvalseq, std::make_tuple(idx...)); + shape_type strides = *step * *m_strides; + // shape_type absstep = abs(*step); + + T* data = m_data + calc_index(start); + // shape_type shape = ((*stop - *start) + (*absstep - 1)) / *absstep; + + return tensor{ + data, + internal_generic::compact_shape...>(shape), + internal_generic::compact_shape...>(strides), + m_finalizer, + }; + } + + using tensor_subscript, std::make_integer_sequence>::operator(); + + KFR_MEM_INTRINSIC tensor transpose() const + { + if constexpr (dims <= 1) + { + return *this; + } + else + { + return tensor{ + m_data, + m_shape.transpose(), + m_strides.transpose(), + m_finalizer, + }; + } + } + + template + KFR_MEM_INTRINSIC tensor reshape_may_copy(const kfr::shape& new_shape, + bool allow_copy = true) const + { + if (size_of_shape(new_shape) != m_size) + { + KFR_REPORT_LOGIC_ERROR("Invalid shape provided"); + } + /* + TODO: reshape must be possible with non-contiguous arrays: + [256, 256, 1] -> [256, 256] + [256, 256] -> [256, 256, 1] + [256, 256] -> [256, 1, 256] + */ + if (!is_contiguous()) + { + if (allow_copy) + { + tensor result(new_shape); + std::copy(begin(), end(), result.contiguous_begin()); + return result; + } + else + { + KFR_REPORT_LOGIC_ERROR("reshape requires contiguous array"); + } + } + return tensor{ + m_data, + new_shape, + internal_generic::strides_for_shape(new_shape), + m_finalizer, + }; + } + + template + KFR_MEM_INTRINSIC tensor reshape(const kfr::shape& new_shape) const + { + return reshape_may_copy(new_shape, false); + } + + KFR_MEM_INTRINSIC tensor flatten() const { return reshape(kfr::shape<1>{ m_size }); } + + KFR_MEM_INTRINSIC tensor flatten_may_copy(bool allow_copy = true) const + { + return reshape_may_copy(kfr::shape<1>{ m_size }, allow_copy); + } + + KFR_MEM_INTRINSIC tensor copy() const + { + tensor result(m_shape); + std::copy(begin(), end(), result.contiguous_begin()); + return result; + } + + KFR_MEM_INTRINSIC void copy_from(const tensor& other) { std::copy(other.begin(), other.end(), begin()); } + + template + KFR_MEM_INTRINSIC void iterate(Fn&& fn) const + { + auto it = begin(); + while (it != end()) + { + fn(*it, it.indices); + ++it; + } + } + + template > + KFR_MEM_INTRINSIC tensor map(Fn&& fn) const + { + return unary(std::forward(fn)); + } + + template > + KFR_MEM_INTRINSIC tensor unary(Fn&& fn) const + { + tensor result(m_shape); + auto dst = result.contiguous_begin_unsafe(); + if (is_contiguous()) + { + auto src = contiguous_begin_unsafe(); + while (src != contiguous_end_unsafe()) + { + *dst = fn(*src); + ++src; + ++dst; + } + } + else + { + auto src = begin(); + while (src != end()) + { + *dst = fn(*src); + ++src; + ++dst; + } + } + return result; + } + + template + KFR_MEM_INTRINSIC const tensor& unary_inplace(Fn&& fn) const + { + if (is_contiguous()) + { + auto it = contiguous_begin_unsafe(); + while (it != contiguous_end_unsafe()) + { + *it = fn(*it); + ++it; + } + } + else + { + auto it = begin(); + while (it != end()) + { + *it = fn(*it); + ++it; + } + } + return *this; + } + + template + KFR_MEM_INTRINSIC T reduce(Fn&& fn, T initial = T{}) const + { + T result = initial; + if (is_contiguous()) + { + auto src = contiguous_begin_unsafe(); + while (src != contiguous_end_unsafe()) + { + result = fn(*src, result); + ++src; + } + } + else + { + auto src = begin(); + while (src != end()) + { + result = fn(*src, result); + ++src; + } + } + return result; + } + + template > + KFR_MEM_INTRINSIC tensor binary(const tensor& rhs, Fn&& fn) const + { + tensor result(m_shape); + if (is_contiguous() && rhs.is_contiguous()) + { + auto src1 = contiguous_begin_unsafe(); + auto src2 = rhs.contiguous_begin_unsafe(); + auto dst = result.contiguous_begin_unsafe(); + while (src1 != contiguous_end_unsafe()) + { + *dst = fn(*src1, *src2); + ++src1; + ++src2; + ++dst; + } + } + else + { + auto src1 = begin(); + auto src2 = rhs.begin(); + auto dst = result.contiguous_begin(); + while (src1 != end()) + { + *dst = fn(*src1, *src2); + ++src1; + ++src2; + ++dst; + } + } + return result; + } + + template + KFR_MEM_INTRINSIC const tensor& binary_inplace(const tensor& rhs, Fn&& fn) const + { + if (is_contiguous() && rhs.is_contiguous()) + { + auto it = contiguous_begin_unsafe(); + auto src2 = rhs.contiguous_begin_unsafe(); + while (it != contiguous_end_unsafe()) + { + *it = fn(*it, *src2); + ++it; + ++src2; + } + } + else + { + auto it = begin(); + auto src2 = rhs.begin(); + while (it != end()) + { + *it = fn(*it, *src2); + ++it; + ++src2; + } + } + return *this; + } + + template + KFR_MEM_INTRINSIC tensor astype() const + { + return unary([](T value) { return static_cast(value); }); + } + + template + KFR_MEM_INTRINSIC std::array to_array() const + { + if (m_size != Nout) + KFR_REPORT_LOGIC_ERROR("Nout != m_size"); + std::array result; + if (is_contiguous()) + std::copy(contiguous_begin(), contiguous_end(), result.begin()); + else + std::copy(begin(), end(), result.begin()); + return result; + } + struct nested_iterator_t + { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = tensor; + using pointer = const value_type*; + using reference = const value_type&; + + const tensor* src; + size_t index; + + KFR_MEM_INTRINSIC value_type operator*() { return src->operator()(index); } + KFR_MEM_INTRINSIC pointer operator->() { return &operator*(); } + + // prefix + KFR_MEM_INTRINSIC nested_iterator_t& operator++() + { + ++index; + return *this; + } + + // postfix + KFR_MEM_INTRINSIC nested_iterator_t operator++(int) + { + nested_iterator_t temp = *this; + ++*this; + return temp; + } + + KFR_MEM_INTRINSIC bool operator==(const nested_iterator_t& it) const + { + return src == it.src && index == it.index; + } + KFR_MEM_INTRINSIC bool operator!=(const nested_iterator_t& it) const { return !operator==(it); } + }; + + using nested_iterator = std::conditional_t; + + KFR_MEM_INTRINSIC nested_iterator nested_begin() const + { + if constexpr (dims == 1) + return begin(); + else + return { this, 0 }; + } + KFR_MEM_INTRINSIC nested_iterator nested_end() const + { + if constexpr (dims == 1) + return end(); + else + return { this, m_shape[0] }; + } + + KFR_MEM_INTRINSIC memory_finalizer finalizer() const { return m_finalizer; } + + template + KFR_MEM_INTRINSIC const tensor& operator=(Input&& input) const& + { + process(*this, input); + return *this; + } + template + KFR_MEM_INTRINSIC tensor& operator=(Input&& input) && + { + process(*this, input); + return *this; + } + template + KFR_MEM_INTRINSIC tensor& operator=(Input&& input) & + { + process(*this, input); + return *this; + } + + bool operator==(const tensor& other) const + { + return shape() == other.shape() && std::equal(begin(), end(), other.begin()); + } + bool operator!=(const tensor& other) const { return !operator==(other); } + + KFR_MEM_INTRINSIC const shape_type& shape() const { return m_shape; } + KFR_MEM_INTRINSIC const shape_type& strides() const { return m_strides; } + + KFR_MEM_INTRINSIC bool is_contiguous() const { return m_is_contiguous; } + + KFR_MEM_INTRINSIC bool is_last_contiguous() const { return m_strides.back() == 1; } + + template + std::string to_string(int max_columns = 16, int max_dimensions = INT_MAX, std::string separator = ", ", + std::string open = "{", std::string close = "}") const + { + if constexpr (dims == 0) + { + if (empty()) + return {}; + else + return as_string(wrap_fmt(access(shape_type{}), cometa::ctype)); + } + else + { + return cometa::array_to_string( + m_shape.template to_std_array(), + [this](std::array index) CMT_INLINE_LAMBDA + { return access(shape_type::from_std_array(index)); }, + max_columns, max_dimensions, std::move(separator), std::move(open), std::move(close)); + } + } + +private: + template + KFR_MEM_INTRINSIC void assign_expr(Input&& input) const + { + process(*this, std::forward(input)); + } + + T* m_data; + const index_t m_size; + const bool m_is_contiguous; + const shape_type m_shape; + const shape_type m_strides; + memory_finalizer m_finalizer; +}; + +template +struct tensor +{ + // Not implemented yet +}; + +// template +// struct tensor +// { +// private: +// }; + +template ), + typename T = typename Container::value_type> +KFR_INTRINSIC tensor tensor_from_container(Container container) +{ + using container_finalizer = internal_generic::memory_finalizer_data; + memory_finalizer mem = memory_finalizer(new container_finalizer{ std::move(container) }); + + Container* ptr = &static_cast(mem.get())->data; + + return tensor(ptr->data(), shape<1>(ptr->size()), std::move(mem)); +} + +template +struct expression_traits> : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = Dims; + + KFR_MEM_INTRINSIC constexpr static shape get_shape(const tensor& self) + { + return self.shape(); + } + KFR_MEM_INTRINSIC constexpr static shape get_shape() { return shape{ undefined_size }; } +}; + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec get_elements(const tensor& self, const shape& index, + const axis_params&) +{ + static_assert(Axis < NDims || NDims == 0); + const T* data = self.data() + self.calc_index(index); + if constexpr (NDims == 0) + { + static_assert(N == 1); + return *data; + } + else + { + if (self.strides()[Axis] == 1) + return read(data); + return gather_stride(data, self.strides()[Axis]); + } +} + +template +KFR_INTRINSIC void set_elements(const tensor& self, const shape& index, + const axis_params&, const identity>& value) +{ + static_assert(Axis < NDims || NDims == 0); + T* data = self.data() + self.calc_index(index); + if constexpr (NDims == 0) + { + static_assert(N == 1); + *data = value.front(); + } + else + { + if (self.strides()[Axis] == 1) + return write(data, value); + scatter_stride(data, value, self.strides()[Axis]); + } +} + +template > +tensor trender(const E& expr) +{ + static_assert(!Traits::get_shape().has_infinity()); + shape sh = Traits::get_shape(expr); + tensor result(sh); + process(result, expr); + return result; +} + +template > +tensor trender(const E& expr, shape size) +{ + shape sh = min(Traits::get_shape(expr), size); + tensor result(sh); + process(result, expr, shape{ 0 }, sh); + return result; +} + +} // namespace CMT_ARCH_NAME + +} // namespace kfr + +namespace cometa +{ +template +struct representation> +{ + using type = std::string; + static std::string get(const kfr::tensor& value) { return value.to_string(); } +}; + +template +struct representation, t, width, prec>> +{ + using type = std::string; + static std::string get(const fmt_t, t, width, prec>& value) + { + return array_to_string>(value.value.size(), value.value.data()); + } +}; + +} // namespace cometa + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/transpose.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/transpose.hpp new file mode 100644 index 00000000..cccc1761 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/transpose.hpp @@ -0,0 +1,644 @@ +/** @addtogroup tensor + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/read_write.hpp" +#include "../simd/types.hpp" +#include "expression.hpp" +#include "memory.hpp" +#include "shape.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ + +template +void matrix_transpose(vec* out, const vec* in, shape tshape); + +template +void matrix_transpose_block_one(vec* out, const vec* in, size_t i, size_t stride) +{ + if constexpr (width == 1) + { + write(ptr_cast(out + i), kfr::read(ptr_cast(in + i))); + } + else + { + vec vi = read_group(ptr_cast(in + i), stride); + vi = transpose(vi); + write_group(ptr_cast(out + i), stride, vi); + } +} + +template +void matrix_transpose_block_two(vec* out, const vec* in, size_t i, size_t j, size_t stride) +{ + if constexpr (width == 1) + { + vec vi = kfr::read(ptr_cast(in + i)); + vec vj = kfr::read(ptr_cast(in + j)); + write(ptr_cast(out + i), vj); + write(ptr_cast(out + j), vi); + } + else + { + vec vi = read_group(ptr_cast(in + i), stride); + vec vj = read_group(ptr_cast(in + j), stride); + vi = transpose(vi); + vj = transpose(vj); + write_group(ptr_cast(out + i), stride, vj); + write_group(ptr_cast(out + j), stride, vi); + } +} + +template +void matrix_transpose_square_small(vec* out, const vec* in, size_t n) +{ + cswitch(csizeseq<6, 1>, n, // 1, 2, 3, 4, 5 or 6 + [&](auto n_) CMT_INLINE_LAMBDA + { + constexpr size_t n = CMT_CVAL(n_); + write(ptr_cast(out), transpose(kfr::read(ptr_cast(in)))); + }); +} + +template +void matrix_transpose_square(vec* out, const vec* in, size_t n, size_t stride) +{ +#if 1 + constexpr size_t width = 4; + const size_t nw = align_down(n, width); + const size_t wstride = width * stride; + + size_t i = 0; + size_t istridei = 0; + CMT_LOOP_NOUNROLL + for (; i < nw; i += width) + { + matrix_transpose_block_one(out, in, istridei, stride); + + size_t j = i + width; + size_t istridej = istridei + width; + size_t jstridei = istridei + wstride; + CMT_LOOP_NOUNROLL + for (; j < nw; j += width) + { + matrix_transpose_block_two(out, in, istridej, jstridei, stride); + istridej += width; + jstridei += wstride; + } + CMT_LOOP_NOUNROLL + for (; j < n; ++j) + { + CMT_LOOP_NOUNROLL + for (size_t ii = i; ii < i + width; ++ii) + { + matrix_transpose_block_two(out, in, istridej, jstridei, stride); + istridej += stride; + jstridei += 1; + } + istridej = istridej - stride * width + 1; + jstridei = jstridei - width + stride; + } + istridei += width * (stride + 1); + } + + CMT_LOOP_NOUNROLL + for (; i < n; ++i) + { + matrix_transpose_block_one(out, in, i * stride + i, stride); + CMT_LOOP_NOUNROLL + for (size_t j = i + 1; j < n; ++j) + { + matrix_transpose_block_two(out, in, i * stride + j, j * stride + i, stride); + } + } +#else + constexpr size_t width = 4; + const size_t nw = align_down(n, width); + + size_t i = 0; + CMT_LOOP_NOUNROLL + for (; i < nw; i += width) + { + matrix_transpose_block_one(out, in, i * stride + i, stride); + + size_t j = i + width; + CMT_LOOP_NOUNROLL + for (; j < nw; j += width) + { + matrix_transpose_block_two(out, in, i * stride + j, j * stride + i, stride); + } + CMT_LOOP_NOUNROLL + for (; j < n; ++j) + { + CMT_LOOP_NOUNROLL + for (size_t ii = i; ii < i + width; ++ii) + { + matrix_transpose_block_two(out, in, ii * stride + j, j * stride + ii, stride); + } + } + } + + CMT_LOOP_NOUNROLL + for (; i < n; ++i) + { + matrix_transpose_block_one(out, in, i * stride + i, stride); + CMT_LOOP_NOUNROLL + for (size_t j = i + 1; j < n; ++j) + { + matrix_transpose_block_two(out, in, i * stride + j, j * stride + i, stride); + } + } +#endif +} + +template +CMT_ALWAYS_INLINE void do_reverse(vec* first, vec* last) +{ + constexpr size_t width = vector_capacity / 4 / N; + for (; first + width - 1 < last - width; first += width, last -= width) + { + vec a = read(first); + vec b = read(last - width); + write(first, reverse(b)); + write(last - width, reverse(a)); + } + for (; first < last; first += 1, last -= 1) + { + vec a = read(ptr_cast(first)); + vec b = read(ptr_cast(last - 1)); + write(ptr_cast(first), b); + write(ptr_cast(last - 1), a); + } +} + +template +CMT_ALWAYS_INLINE void ranges_swap(vec* x, vec* y, size_t size) +{ + block_process(size, csizes / 4 / N, 2), 1>, + [x, y](size_t index, auto w) CMT_INLINE_LAMBDA + { + constexpr size_t width = CMT_CVAL(w); + vec xx = read(ptr_cast(x + index)); + vec yy = read(ptr_cast(y + index)); + write(ptr_cast(x + index), yy); + write(ptr_cast(y + index), xx); + }); +} + +template +CMT_ALWAYS_INLINE void do_swap(T* arr, size_t a, size_t b, size_t k) +{ + ranges_swap(arr + a, arr + b, k); +} +template +CMT_ALWAYS_INLINE void do_block_swap(T* arr, size_t k, size_t n) +{ + if (k == 0 || k == n) + return; + + for (;;) + { + if (k == n - k) + { + do_swap(arr, 0, n - k, k); + return; + } + else if (k < n - k) + { + do_swap(arr, 0, n - k, k); + n = n - k; + } + else + { + do_swap(arr, 0, k, n - k); + arr += n - k; + const size_t newk = 2 * k - n; + n = k; + k = newk; + } + } +} + +template +CMT_ALWAYS_INLINE void range_rotate(vec* first, vec* middle, vec* last) +{ +#ifndef KFR_T_REV + do_block_swap(first, middle - first, last - first); +#else + do_reverse(first, middle); + do_reverse(middle, last); + do_reverse(first, last); +#endif +} + +struct matrix_size +{ + size_t rows; + size_t cols; +}; + +template +void matrix_transpose_copy(vec* out, const vec* in, matrix_size size, matrix_size done) +{ + if (size.cols != done.cols) + { + for (size_t r = 0; r < size.rows; ++r) + builtin_memcpy(out + r * size.cols + done.cols, // + in + r * size.cols + done.cols, // + (size.cols - done.cols) * N * sizeof(T)); + } + + for (size_t r = done.rows; r < size.rows; ++r) + builtin_memcpy(out + r * size.cols, // + in + r * size.cols, // + (size.cols) * N * sizeof(T)); +} + +template +void matrix_transpose_shift_rows(vec* out, size_t done, matrix_size size) +{ + const size_t remaining = size.cols - done; + vec* p = out + done; + for (size_t r = 1; r < size.rows; ++r) + { + range_rotate(p, p + r * remaining, p + done + r * remaining); + p += done; + } +} + +template +void matrix_transpose_shift_cols(vec* out, size_t done, matrix_size size) +{ + const size_t remaining = size.rows - done; + vec* p = out + done * (size.cols - 1); + for (size_t c = size.cols - 1; c >= 1; --c) + { + range_rotate(p, p + done, p + done + c * remaining); + p -= done; + } +} + +class matrix_cycles +{ +public: + matrix_cycles(const matrix_cycles&) = delete; + matrix_cycles(matrix_cycles&&) = delete; + matrix_cycles& operator=(const matrix_cycles&) = delete; + matrix_cycles& operator=(matrix_cycles&&) = delete; + + CMT_INLINE_MEMBER explicit matrix_cycles(shape<2> size) : size(size), flat_size(size.product()) + { + size_t bits = (flat_size + 1) / 2; + size_t words = (bits + word_bits - 1) / word_bits; + if (words <= std::size(on_stack)) + data = on_stack; + else + data = new word_t[words]; + builtin_memset(data, 0, sizeof(word_t) * words); + } + + ~matrix_cycles() + { + if (data != on_stack) + delete data; + } + + size_t next_cycle_origin(size_t origin = 0) + { + for (; origin < (flat_size + 1) / 2; ++origin) + { + if (!test_and_set(origin)) + return origin; + } + return static_cast(-1); + } + + template + void iterate(size_t origin, Start&& start, Iterate&& iterate, Stop&& stop, bool skip_fixed = false) + { + shape<2> transposed_size = size.transpose(); + size_t next = transposed_size.to_flat(size.from_flat(origin).transpose()); + if (next == origin) + { + bool is_fixed = next != flat_size - 1 - next; + if (!(is_fixed && skip_fixed)) + { + start(origin, flat_size - 1 - origin, is_fixed); + stop(next != flat_size - 1 - next); + } + } + else + { + size_t inv_next = flat_size - 1 - next; + size_t min_next = std::min(next, inv_next); + if (min_next == origin) + { + bool is_fixed = next == origin; + if (!(is_fixed && skip_fixed)) + { + start(origin, flat_size - 1 - origin, next == origin); + stop(next == origin); + } + } + else + { + start(origin, flat_size - 1 - origin, false); + for (;;) + { + if constexpr (first_pass) + { + set(min_next); + } + iterate(next, inv_next); + next = transposed_size.to_flat(size.from_flat(next).transpose()); + inv_next = flat_size - 1 - next; + min_next = std::min(next, inv_next); + if (min_next == origin) + { + stop(next == origin); + break; + } + } + } + } + } + +private: + using word_t = uint32_t; + constexpr static size_t word_bits = sizeof(word_t) * 8; + shape<2> size; + size_t flat_size; + word_t* data; +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wattributes") + [[maybe_unused]] uint8_t cache_line__[64]; +CMT_PRAGMA_GNU(GCC diagnostic pop) + alignas(16) word_t on_stack[1024]; + + CMT_INLINE_MEMBER void set(size_t index) + { + word_t& word = data[index / word_bits]; + word_t mask = 1u << (index % word_bits); + word |= mask; + } + + CMT_INLINE_MEMBER bool test_and_set(size_t index) + { + word_t& word = data[index / word_bits]; + word_t mask = 1u << (index % word_bits); + if (word & mask) + return true; + word |= mask; + return false; + } +}; + +template +CMT_INTRINSIC void matrix_merge_squares_fast(vec* out, size_t side, size_t squares, matrix_size size, + size_t stride, cbool_t) +{ + if constexpr (!horizontal) + { + stride = stride * side; + } + for (size_t i = 0; i < side; ++i) + { + for (size_t j = i + 1; j < side; ++j) + { + size_t index1 = i * stride + j * side; + size_t index2 = j * stride + i * side; + ranges_swap(out + index1, out + index2, side); + } + } +} + +static CMT_INTRINSIC size_t matrix_offset(size_t flat_index, size_t side, size_t stride1, size_t stride2) +{ + size_t i = flat_index / side; + size_t j = flat_index % side; + return i * stride1 + j * stride2; +} + +template +void matrix_merge_squares(vec* out, size_t side, size_t squares, matrix_size size, size_t stride, + cbool_t) +{ + if (side == squares) + { + return matrix_merge_squares_fast(out, side, squares, size, stride, cbool); + } + if constexpr (!horizontal) + { + stride = stride * side; + } + shape sh = horizontal ? shape{ squares, side } : shape{ side, squares }; + size_t flat_side = sh[0]; + matrix_cycles cycles(sh); + + size_t origin = 0; + do + { + block_process( + side, csizes / 8 / N), 1>, + [&](size_t offset, auto width_) + { + constexpr size_t width = CMT_CVAL(width_); + + vec temp; + vec temp_inv; + size_t previous; + size_t previous_inv; + cycles.iterate( + origin, + [&](size_t origin, size_t origin_inv, bool /* fixed */) CMT_INLINE_LAMBDA + { +#ifdef CMT_COMPILER_IS_MSVC + constexpr size_t width = CMT_CVAL(width_); +#endif + temp = read( + ptr_cast(out + matrix_offset(origin, flat_side, stride, side) + offset)); + temp_inv = read( + ptr_cast(out + matrix_offset(origin_inv, flat_side, stride, side) + offset)); + previous = origin; + previous_inv = origin_inv; + }, + [&](size_t current, size_t current_inv) CMT_INLINE_LAMBDA + { +#ifdef CMT_COMPILER_IS_MSVC + constexpr size_t width = CMT_CVAL(width_); +#endif + vec val = read( + ptr_cast(out + matrix_offset(current, flat_side, stride, side) + offset)); + vec val_inv = read( + ptr_cast(out + matrix_offset(current_inv, flat_side, stride, side) + offset)); + write(ptr_cast(out + matrix_offset(previous, flat_side, stride, side) + offset), + val); + write( + ptr_cast(out + matrix_offset(previous_inv, flat_side, stride, side) + offset), + val_inv); + previous = current; + previous_inv = current_inv; + }, + [&](bool symmetric) CMT_INLINE_LAMBDA + { + if (!symmetric) + std::swap(temp, temp_inv); + write(ptr_cast(out + matrix_offset(previous, flat_side, stride, side) + offset), + temp); + write( + ptr_cast(out + matrix_offset(previous_inv, flat_side, stride, side) + offset), + temp_inv); + }, + true); + }); + origin = cycles.next_cycle_origin(origin + 1); + } while (origin != static_cast(-1)); +} + +template +void matrix_transpose_any(vec* out, const vec* in, matrix_size size) +{ + if (size.cols > size.rows) + { + // 1. transpose square sub-matrices + const size_t side = size.rows; + const size_t squares = size.cols / side; + for (size_t i = 0; i < squares; ++i) + { + matrix_transpose_square(out + i * side, in + i * side, side, size.cols); + } + if (squares > 1) + matrix_merge_squares(out, side, squares, size, size.cols, ctrue); + const size_t done = side * squares; + if (in != out) + matrix_transpose_copy(out, in, size, { side, done }); + + const size_t remaining = size.cols - done; + if (remaining == 0) + return; + + // 2. shift rows + matrix_transpose_shift_rows(out, done, size); + + // 3. transpose remainder + internal::matrix_transpose(out + done * size.rows, out + done * size.rows, + shape{ size.rows, remaining }); + } + else // if (cols < rows) + { + // 1. transpose square sub-matrices + const size_t side = size.cols; + const size_t squares = size.rows / side; + for (size_t i = 0; i < squares; ++i) + { + matrix_transpose_square(out + i * side * side, in + i * side * side, side, size.cols); + } + if (squares > 1) + matrix_merge_squares(out, side, squares, size, size.cols, cfalse); + const size_t done = side * squares; + if (in != out) + matrix_transpose_copy(out, in, size, { done, side }); + + const size_t remaining = size.rows - done; + if (remaining == 0) + return; + + // 2. transpose remainder + internal::matrix_transpose(out + done * size.cols, out + done * size.cols, + shape{ remaining, size.cols }); + + // 3. shift cols + matrix_transpose_shift_cols(out, done, size); + } +} + +template +KFR_INTRINSIC void matrix_transpose_noop(T* out, const T* in, size_t total) +{ + if (out == in) + return; + builtin_memcpy(out, in, total * sizeof(T)); +} + +template +void matrix_transpose(vec* out, const vec* in, shape tshape) +{ + if constexpr (Dims <= 1) + { + return internal::matrix_transpose_noop(out, in, tshape.product()); + } + else if constexpr (Dims == 2) + { + const index_t rows = tshape[0]; + const index_t cols = tshape[1]; + if (cols == 1 || rows == 1) + { + return internal::matrix_transpose_noop(out, in, tshape.product()); + } + // TODO: special cases for tall or wide matrices + if (cols == rows) + { + if (cols <= 6) + return internal::matrix_transpose_square_small(out, in, cols); + return internal::matrix_transpose_square(out, in, cols, cols); + } + return internal::matrix_transpose_any(out, in, { rows, cols }); + } + else + { + shape x = tshape.template slice<0, Dims - 1>(); + index_t xproduct = x.product(); + index_t y = tshape.back(); + internal::matrix_transpose(out, in, shape<2>{ xproduct, y }); + for (index_t i = 0; i < y; ++i) + { + internal::matrix_transpose(out, out, x); + out += xproduct; + } + } +} +} // namespace internal + +/// @brief Matrix transpose. +/// Accepts vec, complex and other compound types +template +void matrix_transpose(T* out, const T* in, shape shape) +{ + using U = typename compound_type_traits::deep_subtype; + constexpr size_t width = compound_type_traits::deep_width; + return internal::matrix_transpose(ptr_cast>(out), + ptr_cast>(in), shape); +} + +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/base/univector.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/base/univector.hpp new file mode 100644 index 00000000..945412d3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/base/univector.hpp @@ -0,0 +1,714 @@ +/** @addtogroup univector + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../cometa/array.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/read_write.hpp" +#include "../simd/types.hpp" +#include "expression.hpp" +#include "memory.hpp" + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4324)) + +namespace kfr +{ + +using univector_tag = size_t; + +enum : size_t +{ + tag_array_ref = 0, + tag_dynamic_vector = max_size_t, +}; + +template +struct abstract_vector; + +template +struct abstract_vector : std::array +{ + using std::array::array; +}; + +template +struct abstract_vector : std::vector> +{ + using std::vector>::vector; +}; + +template +struct abstract_vector : array_ref +{ + using array_ref::array_ref; +}; + +/** + * @brief Class that represent data in KFR. Many KFR functions can take this class as an argument. + * Can inherit from std::vector, std::array or keep only reference to data and its size. + * + * univector is inherited from std::vector + * univector is inherited from std::array + * univector contains only reference to data + * + * To convert a plain pointer to univector, call make_univector: + * @code + * double* buffer; + * size_t size; + * univector v = make_univector(buffer, size); + * // or pass result vector directly to a function: + * some_function(make_univector(buffer, size)); + * @endcode + */ +template +struct univector; + +/// @brief Base class for all univector specializations. +template +struct univector_base; + +template +struct univector_base +{ + template + KFR_MEM_INTRINSIC Class& operator=(Input&& input) + { + constexpr index_t dims = expression_dims; + static_assert(dims <= 1, "univector accepts only expressions with dims <= 1"); + assign_expr(std::forward(input)); + return *derived_cast(this); + } + + /// @brief Returns subrange of the vector. + /// If start is greater or equal to this->size, returns empty univector + /// If requested size is greater than this->size, returns only available elements + univector slice(size_t start = 0, size_t size = max_size_t) + { + T* data = derived_cast(this)->data(); + const size_t this_size = derived_cast(this)->size(); + return array_ref(data + start, std::min(size, start < this_size ? this_size - start : 0)); + } + + /// @brief Returns subrange of the vector. + /// If start is greater or equal to this->size, returns empty univector + /// If requested size is greater than this->size, returns only available elements + univector slice(size_t start = 0, size_t size = max_size_t) const + { + const T* data = derived_cast(this)->data(); + const size_t this_size = derived_cast(this)->size(); + return array_ref(data + start, std::min(size, start < this_size ? this_size - start : 0)); + } + + /// @brief Returns subrange of the vector starting from 0. + /// If requested size is greater than this->size, returns only available elements + univector truncate(size_t size = max_size_t) + { + T* data = derived_cast(this)->data(); + const size_t this_size = derived_cast(this)->size(); + return array_ref(data, std::min(size, this_size)); + } + + /// @brief Returns subrange of the vector starting from 0. + /// If requested size is greater than this->size, returns only available elements + univector truncate(size_t size = max_size_t) const + { + const T* data = derived_cast(this)->data(); + const size_t this_size = derived_cast(this)->size(); + return array_ref(data, std::min(size, this_size)); + } + + array_ref ref() + { + T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + array_ref ref() const + { + const T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + array_ref cref() const + { + const T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + + void ringbuf_write(size_t& cursor, const T* src, size_t srcsize) + { + if (CMT_UNLIKELY(srcsize == 0)) + return; + // skip redundant data + const size_t size = get_size(); + T* data = get_data(); + if (srcsize > size) + { + src = src + srcsize / size; + srcsize = srcsize % size; + } + const size_t fsize = size - cursor; + // one fragment + if (CMT_LIKELY(srcsize <= fsize)) + { + copy(data + cursor, src, srcsize); + } + else // two fragments + { + copy(data + cursor, src, fsize); + copy(data, src + fsize, srcsize - fsize); + } + ringbuf_step(cursor, srcsize); + } + template + void ringbuf_write(size_t& cursor, const vec& x) + { + ringbuf_write(cursor, ptr_cast(&x), N); + } + void ringbuf_write(size_t& cursor, const T& value) + { + T* data = get_data(); + data[cursor] = value; + ringbuf_step(cursor, 1); + } + void ringbuf_step(size_t& cursor, size_t step) const + { + const size_t size = get_size(); + cursor = cursor + step; + cursor = cursor >= size ? cursor - size : cursor; + } + void ringbuf_read(size_t& cursor, T& value) + { + T* data = get_data(); + value = data[cursor]; + ringbuf_step(cursor, 1); + } + template + void ringbuf_read(size_t& cursor, vec& x) + { + ringbuf_read(cursor, ptr_cast(&x), N); + } + void ringbuf_read(size_t& cursor, T* dest, size_t destsize) const + { + if (CMT_UNLIKELY(destsize == 0)) + return; + // skip redundant data + const size_t size = get_size(); + const T* data = get_data(); + if (destsize > size) + { + dest = dest + destsize / size; + destsize = destsize % size; + } + const size_t fsize = size - cursor; + // one fragment + if (CMT_LIKELY(destsize <= fsize)) + { + copy(dest, data + cursor, destsize); + } + else // two fragments + { + copy(dest, data + cursor, fsize); + copy(dest + fsize, data, destsize - fsize); + } + ringbuf_step(cursor, destsize); + } + +protected: + template + KFR_MEM_INTRINSIC void assign_expr(Input&& input) + { + process(*derived_cast(this), std::forward(input)); + } + +private: + KFR_MEM_INTRINSIC size_t get_size() const { return derived_cast(this)->size(); } + KFR_MEM_INTRINSIC const T* get_data() const { return derived_cast(this)->data(); } + KFR_MEM_INTRINSIC T* get_data() { return derived_cast(this)->data(); } + + static void copy(T* dest, const T* src, size_t size) + { + for (size_t i = 0; i < size; ++i) + *dest++ = *src++; + } +}; + +template +struct univector_base +{ + array_ref ref() + { + T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + array_ref ref() const + { + const T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + array_ref cref() const + { + const T* data = get_data(); + const size_t size = get_size(); + return array_ref(data, size); + } + + template + KFR_MEM_INTRINSIC Class& operator=(Input&& input) + { + static_assert(sizeof(Input) == 0, "Can't assign expression to non-expression"); + return *derived_cast(this); + } + +private: + KFR_MEM_INTRINSIC size_t get_size() const { return derived_cast(this)->size(); } + KFR_MEM_INTRINSIC const T* get_data() const { return derived_cast(this)->data(); } + KFR_MEM_INTRINSIC T* get_data() { return derived_cast(this)->data(); } +}; + +template +struct alignas(platform<>::maximum_vector_alignment) univector + : std::array, + univector_base, is_vec_element> +{ + static_assert(!std::is_const_v, "Static vector doesn't allow T to be const"); + + using std::array::size; + using size_type = size_t; +#if !defined CMT_COMPILER_MSVC || defined CMT_COMPILER_CLANG + univector(univector& v) : univector(const_cast(v)) {} +#endif + univector(const univector& v) = default; + univector(univector&&) noexcept = default; + template + univector(Input&& input) + { + this->assign_expr(std::forward(input)); + } + template + constexpr univector(const T& x, const Args&... args) CMT_NOEXCEPT + : std::array{ { x, static_cast(args)... } } + { + } + + constexpr univector() CMT_NOEXCEPT_SPEC(noexcept(std::array())) = default; + constexpr univector(size_t, const T& value) { std::fill(this->begin(), this->end(), value); } + constexpr static bool size_known = true; + constexpr static size_t static_size = Size; + constexpr static bool is_array = true; + constexpr static bool is_array_ref = false; + constexpr static bool is_vector = false; + constexpr static bool is_aligned = true; + using value_type = T; + + value_type get(size_t index, value_type fallback_value) const CMT_NOEXCEPT + { + return index < this->size() ? this->operator[](index) : fallback_value; + } + using univector_base>::operator=; + + void resize(size_t) CMT_NOEXCEPT {} +}; + +template +struct univector : array_ref, + univector_base, is_vec_element> +{ + using array_ref::size; + using array_ref::array_ref; + using size_type = size_t; +#if !defined CMT_COMPILER_MSVC || defined CMT_COMPILER_CLANG + univector(univector& v) : univector(const_cast(v)) {} +#endif + univector(const univector& v) = default; + univector(univector&&) noexcept = default; + constexpr univector(const array_ref& other) : array_ref(other) {} + constexpr univector(array_ref&& other) : array_ref(std::move(other)) {} + + template + constexpr univector(const univector& other) : array_ref(other.data(), other.size()) + { + } + template + constexpr univector(univector& other) : array_ref(other.data(), other.size()) + { + } + template , U>&& std::is_const_v)> + constexpr univector(const univector& other) : array_ref(other.data(), other.size()) + { + } + template , U>&& std::is_const_v)> + constexpr univector(univector& other) : array_ref(other.data(), other.size()) + { + } + template , U>&& std::is_const_v)> + constexpr univector(univector&& other) : array_ref(other.data(), other.size()) + { + } + void resize(size_t) CMT_NOEXCEPT {} + constexpr static bool size_known = false; + constexpr static bool is_array = false; + constexpr static bool is_array_ref = true; + constexpr static bool is_vector = false; + constexpr static bool is_aligned = false; + using value_type = std::remove_const_t; + + value_type get(size_t index, value_type fallback_value) const CMT_NOEXCEPT + { + return index < this->size() ? this->operator[](index) : fallback_value; + } + using univector_base>::operator=; + + univector& ref() && { return *this; } +}; + +template +struct univector + : std::vector>, + univector_base, is_vec_element> +{ + static_assert(!std::is_const_v, "Dynamic vector doesn't allow T to be const"); + + using std::vector>::size; + using std::vector>::vector; + using size_type = size_t; +#if !defined CMT_COMPILER_IS_MSVC + univector(univector& v) : univector(const_cast(v)) {} +#endif + univector(const univector& v) = default; + univector(univector&&) noexcept = default; + template + univector(Input&& input) + { + static_assert(!is_infinite, "Dynamically sized vector requires finite input expression"); + constexpr index_t dims = expression_dims; + static_assert(dims <= 1, "univector accepts only expressions with dims <= 1"); + if constexpr (dims > 0) + { + this->resize(get_shape(input).front()); + } + this->assign_expr(std::forward(input)); + } + constexpr univector() CMT_NOEXCEPT_SPEC(noexcept(std::vector>())) = default; + constexpr univector(const std::vector>& other) + : std::vector>(other) + { + } + constexpr univector(std::vector>&& other) + : std::vector>(std::move(other)) + { + } + constexpr univector(const array_ref& other) + : std::vector>(other.begin(), other.end()) + { + } + constexpr univector(const array_ref& other) + : std::vector>(other.begin(), other.end()) + { + } + template + constexpr univector(const std::vector&) = delete; + template + constexpr univector(std::vector&&) = delete; + constexpr static bool size_known = false; + constexpr static bool is_array = false; + constexpr static bool is_array_ref = false; + constexpr static bool is_vector = true; + constexpr static bool is_aligned = true; + using value_type = T; + + value_type get(size_t index, value_type fallback_value) const CMT_NOEXCEPT + { + return index < this->size() ? this->operator[](index) : fallback_value; + } + using univector_base>::operator=; +#ifdef CMT_COMPILER_IS_MSVC + univector& operator=(const univector& other) + { + this->~univector(); + new (this) univector(other); + return *this; + } + univector& operator=(univector&& other) + { + this->~univector(); + new (this) univector(std::move(other)); + return *this; + } +#else + univector& operator=(const univector&) = default; + univector& operator=(univector&&) = default; +#endif + KFR_MEM_INTRINSIC univector& operator=(univector& other) { return operator=(std::as_const(other)); } + template + KFR_MEM_INTRINSIC univector& operator=(Input&& input) + { + constexpr index_t dims = expression_dims; + static_assert(dims <= 1, "univector accepts only expressions with dims <= 1"); + if constexpr (dims > 0) + { + if (get_shape(input).front() != infinite_size) + this->resize(get_shape(input).front()); + } + this->assign_expr(std::forward(input)); + return *this; + } +}; + +template +struct expression_traits> : public expression_traits_defaults +{ + using value_type = std::remove_const_t; + constexpr static size_t dims = 1; + constexpr static shape get_shape(const univector& u) { return shape<1>(u.size()); } + constexpr static shape get_shape() + { + if constexpr (univector::size_known) + return shape<1>{ univector::static_size }; + else + return shape<1>{ undefined_size }; + } +}; + +template +KFR_FUNCTION bool operator==(const univector& x, const univector& y) +{ + return std::equal(x.begin(), x.end(), y.begin(), y.end()); +} +template +KFR_FUNCTION bool operator!=(const univector& x, const univector& y) +{ + return !operator==(x, y); +} + +/// @brief Alias for ``univector``; +template +using univector_ref = univector; + +/// @brief Alias for ``univector``; +template +using univector_dyn = univector; + +template +using univector2d = abstract_vector, Size1>; + +template +using univector3d = abstract_vector, Size2>, Size1>; + +/// @brief Creates univector from data and size +template +KFR_INTRINSIC univector_ref make_univector(T* data, size_t size) +{ + return univector_ref(data, size); +} + +/// @brief Creates univector from data and size +template +KFR_INTRINSIC univector_ref make_univector(const T* data, size_t size) +{ + return univector_ref(data, size); +} + +/// @brief Creates univector from a container (must have data() and size() methods) +template ), + typename T = value_type_of> +KFR_INTRINSIC univector_ref make_univector(const Container& container) +{ + return univector_ref(container.data(), container.size()); +} + +/// @brief Creates univector from a container (must have data() and size() methods) +template ), + typename T = value_type_of> +KFR_INTRINSIC univector_ref make_univector(Container& container) +{ + return univector_ref(container.data(), container.size()); +} + +/// @brief Creates univector from a sized array +template +KFR_INTRINSIC univector_ref make_univector(T (&arr)[N]) +{ + return univector_ref(arr, N); +} + +/// @brief Creates univector from a sized array +template +KFR_INTRINSIC univector_ref make_univector(const T (&arr)[N]) +{ + return univector_ref(arr, N); +} + +/// @brief Single producer single consumer lock-free ring buffer +template +struct lockfree_ring_buffer +{ + lockfree_ring_buffer() : front(0), tail(0) {} + + size_t size() const + { + return tail.load(std::memory_order_relaxed) - front.load(std::memory_order_relaxed); + } + + template + size_t try_enqueue(const T* source, size_t size, univector& buffer, bool partial = false) + { + const size_t cur_tail = tail.load(std::memory_order_relaxed); + const size_t avail_size = buffer.size() - (cur_tail - front.load(std::memory_order_relaxed)); + if (size > avail_size) + { + if (!partial) + return 0; + size = std::min(size, avail_size); + } + std::atomic_thread_fence(std::memory_order_acquire); + + const size_t real_tail = cur_tail % buffer.size(); + const size_t first_size = std::min(buffer.size() - real_tail, size); + builtin_memcpy(buffer.data() + real_tail, source, first_size * sizeof(T)); + builtin_memcpy(buffer.data(), source + first_size, (size - first_size) * sizeof(T)); + + std::atomic_thread_fence(std::memory_order_release); + + tail.store(cur_tail + size, std::memory_order_relaxed); + return size; + } + + template + size_t try_dequeue(T* dest, size_t size, const univector& buffer, bool partial = false) + { + const size_t cur_front = front.load(std::memory_order_relaxed); + const size_t avail_size = tail.load(std::memory_order_relaxed) - cur_front; + if (size > avail_size) + { + if (!partial) + return 0; + size = std::min(size, avail_size); + } + std::atomic_thread_fence(std::memory_order_acquire); + + const size_t real_front = cur_front % buffer.size(); + const size_t first_size = std::min(buffer.size() - real_front, size); + builtin_memcpy(dest, buffer.data() + real_front, first_size * sizeof(T)); + builtin_memcpy(dest + first_size, buffer.data(), (size - first_size) * sizeof(T)); + + std::atomic_thread_fence(std::memory_order_release); + + front.store(cur_front + size, std::memory_order_relaxed); + return size; + } + +private: + std::atomic front; + char cacheline_filler[64 - sizeof(std::atomic)]; + std::atomic tail; +}; +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec, N> get_elements(const univector& self, + const shape<1>& index, const axis_params<0, N>&) +{ + const T* data = self.data(); + return read(ptr_cast(data) + index.front()); +} + +template )> +KFR_INTRINSIC void set_elements(univector& self, const shape<1>& index, const axis_params<0, N>&, + const identity>& value) +{ + T* data = self.data(); + write(ptr_cast(data) + index.front(), value); +} + +/// @brief Converts an expression to univector +template > +KFR_INTRINSIC univector render(Expr&& expr) +{ + static_assert(expression_dims == 1); + static_assert(!is_infinite, + "render: Can't process infinite expressions. Pass size as a second argument to render."); + univector result; + result.resize(get_shape(expr).front()); + result = expr; + return result; +} + +/// @brief Converts an expression to univector +template > +KFR_INTRINSIC univector render(Expr&& expr, size_t size, size_t offset = 0) +{ + univector result; + result.resize(size); + result = slice(expr, offset, size); + return result; +} + +/// @brief Converts an expression to univector +template > +KFR_INTRINSIC univector render(Expr&& expr, csize_t) +{ + univector result; + result = expr; + return result; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr + +namespace cometa +{ +template +struct representation> +{ + using type = std::string; + static std::string get(const kfr::univector& value) + { + return array_to_string(value.size(), value.data()); + } +}; + +template +struct representation, t, width, prec>> +{ + using type = std::string; + static std::string get(const fmt_t, t, width, prec>& value) + { + return array_to_string>(value.value.size(), value.value.data()); + } +}; + +} // namespace cometa + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/capi.h b/packages/react-native-audio-api/android/src/main/include/kfr/capi.h new file mode 100644 index 00000000..fd510b8f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/capi.h @@ -0,0 +1,718 @@ +/** @addtogroup capi + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include +#include + +#if defined __STDC_IEC_559_COMPLEX__ && !defined KFR_NO_C_COMPLEX_TYPES +#include +#endif + +// Architecture detection +#if defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) +#define KFR_ARCH_IS_X86 1 +#elif defined(__arm__) || defined(__arm64__) || defined(_M_ARM) || defined(__aarch64__) +#define KFR_ARCH_IS_ARM 1 +#endif + +// Calling convention definition +#if defined(_M_X64) || defined(__x86_64__) +#define KFR_CDECL +#else +#ifdef _WIN32 +#define KFR_CDECL __cdecl +#elif defined KFR_ARCH_IS_X86 +#define KFR_CDECL __attribute__((__cdecl__)) +#else +#define KFR_CDECL +#endif +#endif + +// DLL export/import macros +#ifdef _WIN32 +#ifdef KFR_BUILDING_DLL +#define KFR_API_SPEC KFR_CDECL __declspec(dllexport) +#else +#define KFR_API_SPEC KFR_CDECL __declspec(dllimport) +#endif +#else +#ifdef KFR_BUILDING_DLL +#define KFR_API_SPEC KFR_CDECL __attribute__((visibility("default"))) +#else +#define KFR_API_SPEC KFR_CDECL +#endif +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/// Supported architectures enumeration +enum +{ + KFR_ARCH_X86 = 0, + KFR_ARCH_SSE2 = 1, + KFR_ARCH_SSE3 = 2, + KFR_ARCH_SSSE3 = 3, + KFR_ARCH_SSE41 = 4, + KFR_ARCH_SSE42 = 5, + KFR_ARCH_AVX = 6, + KFR_ARCH_AVX2 = 7, + KFR_ARCH_AVX512 = 8, +}; + +/// Library version definitions +#define KFR_HEADERS_VERSION 60000 + +/// @brief Returns the library version as a string. +KFR_API_SPEC const char* kfr_version_string(); + +/// @brief Returns the library version as an integer. +KFR_API_SPEC uint32_t kfr_version(); + +/// @brief Returns the list of enabled architectures as a string. +KFR_API_SPEC const char* kfr_enabled_archs(); + +/// @brief Returns the current architecture in use. +KFR_API_SPEC int kfr_current_arch(); + +/// @brief Returns the last error message. +KFR_API_SPEC const char* kfr_last_error(); + +/// Typedefs for single and double precision floating points +typedef float kfr_f32; +typedef double kfr_f64; + +#if defined __STDC_IEC_559_COMPLEX__ && !defined KFR_NO_C_COMPLEX_TYPES +typedef float _Complex kfr_c32; +typedef double _Complex kfr_c64; +#define KFR_COMPLEX_SIZE_MULTIPLIER 1 +#else +typedef float kfr_c32; +typedef double kfr_c64; +#define KFR_COMPLEX_SIZE_MULTIPLIER 2 +#endif + +typedef size_t kfr_size_t; +typedef int32_t kfr_int32_t; + +/// Macro to define opaque structures for different DFT, DCT, and filter plans +#define KFR_OPAQUE_STRUCT(NAME) \ + typedef struct NAME \ + { \ + int opaque; \ + } NAME; + +KFR_OPAQUE_STRUCT(KFR_DFT_PLAN_F32) +KFR_OPAQUE_STRUCT(KFR_DFT_PLAN_F64) + +KFR_OPAQUE_STRUCT(KFR_DFT_REAL_PLAN_F32) +KFR_OPAQUE_STRUCT(KFR_DFT_REAL_PLAN_F64) + +KFR_OPAQUE_STRUCT(KFR_DCT_PLAN_F32) +KFR_OPAQUE_STRUCT(KFR_DCT_PLAN_F64) + +KFR_OPAQUE_STRUCT(KFR_FILTER_F32) +KFR_OPAQUE_STRUCT(KFR_FILTER_F64) + +KFR_OPAQUE_STRUCT(KFR_FILTER_C32) +KFR_OPAQUE_STRUCT(KFR_FILTER_C64) + +/// Default memory alignment +#define KFR_DEFAULT_ALIGNMENT 64 + +/// @brief Allocates memory of specified size. +KFR_API_SPEC void* kfr_allocate(size_t size); + +/// @brief Allocates aligned memory of specified size and alignment. +KFR_API_SPEC void* kfr_allocate_aligned(size_t size, size_t alignment); + +/// @brief Reallocates memory to new size. +KFR_API_SPEC void* kfr_reallocate(void* ptr, size_t new_size); + +/// @brief Reallocates aligned memory to new size and alignment. +KFR_API_SPEC void* kfr_reallocate_aligned(void* ptr, size_t new_size, size_t alignment); + +/// @brief Adds a reference to the allocated memory. +KFR_API_SPEC void* kfr_add_ref(void* ptr); + +/// @brief Releases a reference to the allocated memory. +KFR_API_SPEC void kfr_release(void* ptr); + +/// @brief Deallocates memory. +KFR_API_SPEC void kfr_deallocate(void* ptr); + +/// @brief Returns allocated memory size. +KFR_API_SPEC size_t kfr_allocated_size(void* ptr); + +/// Enumeration for DFT packing format. See https://www.kfr.dev/docs/latest/dft_format/ for details +typedef enum KFR_DFT_PACK_FORMAT +{ + Perm = 0, + CCs = 1 +} KFR_DFT_PACK_FORMAT; + +/** + * @brief Create a complex DFT plan (Single precision). + * @param size Size of the DFT. + * @return Pointer to the created DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_plan_f32(size_t size); + +/** + * @brief Create a 2D complex DFT plan (Single precision). + * @param size1 Size of the first dimension. + * @param size2 Size of the second dimension. + * @return Pointer to the created 2D DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_2d_plan_f32(size_t size1, size_t size2); + +/** + * @brief Create a 3D complex DFT plan (Single precision). + * @param size1 Size of the first dimension. + * @param size2 Size of the second dimension. + * @param size3 Size of the third dimension. + * @return Pointer to the created 3D DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_3d_plan_f32(size_t size1, size_t size2, size_t size3); + +/** + * @brief Create an N-dimensional complex DFT plan (Single precision). + * @param dims Number of dimensions. + * @param shape Array of sizes for each dimension. + * @return Pointer to the created N-dimensional DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_md_plan_f32(size_t dims, const unsigned* shape); + +/** + * @brief Create a complex DFT plan (Double precision). + * @param size Size of the DFT. + * @return Pointer to the created DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_plan_f64(size_t size); + +/** + * @brief Create a 2D complex DFT plan (Double precision). + * @param size1 Size of the first dimension. + * @param size2 Size of the second dimension. + * @return Pointer to the created 2D DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_2d_plan_f64(size_t size1, size_t size2); + +/** + * @brief Create a 3D complex DFT plan (Double precision). + * @param size1 Size of the first dimension. + * @param size2 Size of the second dimension. + * @param size3 Size of the third dimension. + * @return Pointer to the created 3D DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_3d_plan_f64(size_t size1, size_t size2, size_t size3); + +/** + * @brief Create an N-dimensional complex DFT plan (Double precision). + * @param dims Number of dimensions. + * @param shape Array of sizes for each dimension. + * @return Pointer to the created N-dimensional DFT plan. Use `kfr_dft_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_md_plan_f64(size_t dims, const unsigned* shape); + +/** + * @brief Dump details of the DFT plan to stdout for inspection. + * @param plan Pointer to the DFT plan. + */ +KFR_API_SPEC void kfr_dft_dump_f32(KFR_DFT_PLAN_F32* plan); + +/** + * @brief Dump details of the DFT plan to stdout for inspection. + * @param plan Pointer to the DFT plan. + */ +KFR_API_SPEC void kfr_dft_dump_f64(KFR_DFT_PLAN_F64* plan); + +/** + * @brief Get the size of the DFT plan, in complex numbers. + * @param plan Pointer to the DFT plan. + * @return Size of the DFT plan as passed to kfr_dft_create_plan_f**. + */ +KFR_API_SPEC size_t kfr_dft_get_size_f32(KFR_DFT_PLAN_F32* plan); + +/** + * @brief Get the size of the DFT plan, in complex numbers. + * @param plan Pointer to the DFT plan. + * @return Size of the DFT plan as passed to kfr_dft_create_plan_f**. + */ +KFR_API_SPEC size_t kfr_dft_get_size_f64(KFR_DFT_PLAN_F64* plan); + +/** + * @brief Get temporary (scratch) buffer size for DFT plan. + * @param plan Pointer to the DFT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dft_execute_f**` + * and `kfr_dft_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dft_get_temp_size_f32(KFR_DFT_PLAN_F32* plan); + +/** + * @brief Get temporary (scratch) buffer size for DFT plan. + * @param plan Pointer to the DFT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dft_execute_f**` + * and `kfr_dft_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dft_get_temp_size_f64(KFR_DFT_PLAN_F64* plan); + +/** + * @brief Execute the complex forward DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to the output data. + * @param in Pointer to the input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size `kfr_dft_get_temp_size_f**(plan)` + * will be allocated on stack or heap. + * @note No scaling is applied. This function reads $N$ complex values from `in` and writes $N$ complex values + * to `out`, where $N$ is the size passed to `kfr_dft_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_execute_f32(KFR_DFT_PLAN_F32* plan, kfr_c32* out, const kfr_c32* in, uint8_t* temp); + +/** + * @brief Execute the complex forward DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to the output data (frequency domain). May point to the same memory as `in` for in-place + * execution. + * @param in Pointer to the input data (time domain). + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size `kfr_dft_get_temp_size_f**(plan)` + * will be allocated on stack or heap. + * @note No scaling is applied. This function reads $N$ complex values from `in` and writes $N$ complex values + * to `out`, where $N$ is the size passed to `kfr_dft_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_execute_f64(KFR_DFT_PLAN_F64* plan, kfr_c64* out, const kfr_c64* in, uint8_t* temp); + +/** + * @brief Execute the inverse complex DFT on `in` and write the result to `out` for in-place execution. + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data (time domain). May point to the same memory as `in` for in-place + * execution. + * @param in Pointer to input data (frequency domain). + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size `kfr_dft_get_temp_size_f**(plan)` + * will be allocated on stack or heap. + * @note No scaling is applied. This function reads $N$ complex values from `in` and writes $N$ complex values + * to `out`, where $N$ is the size passed to `kfr_dft_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_execute_inverse_f32(KFR_DFT_PLAN_F32* plan, kfr_c32* out, const kfr_c32* in, + uint8_t* temp); + +/** + * @brief Execute the inverse complex DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data (time domain). + * @param in Pointer to input data (frequency domain). + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size `kfr_dft_get_temp_size_f**(plan)` + * will be allocated on stack or heap. + * @note No scaling is applied. This function reads $N$ complex values from `in` and writes $N$ complex values + * to `out`, where $N$ is the size passed to `kfr_dft_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_execute_inverse_f64(KFR_DFT_PLAN_F64* plan, kfr_c64* out, const kfr_c64* in, + uint8_t* temp); + +/** + * @brief Delete a complex DFT plan. + * @param plan Pointer to the DFT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dft_delete_plan_f32(KFR_DFT_PLAN_F32* plan); + +/** + * @brief Delete a complex DFT plan. + * @param plan Pointer to the DFT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dft_delete_plan_f64(KFR_DFT_PLAN_F64* plan); + +/** + * @brief Create a real DFT plan (Single precision). + * @param size Size of the real DFT. Must be even. + * @param pack_format Packing format for the DFT. + * @return Pointer to the created DFT plan. Use `kfr_dft_real_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_plan_f32(size_t size, + KFR_DFT_PACK_FORMAT pack_format); + +KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_2d_plan_f32(size_t size1, size_t size2, + bool real_out_is_enough); +KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_3d_plan_f32(size_t size1, size_t size2, size_t size3, + bool real_out_is_enough); +KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_md_plan_f32(size_t dims, const unsigned* shape, + bool real_out_is_enough); + +/** + * @brief Create a real DFT plan (Double precision). + * @param size Size of the real DFT. Must be even. + * @param pack_format Packing format for the DFT. + * @return Pointer to the created DFT plan. Use `kfr_dft_real_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_DFT_REAL_PLAN_F64* kfr_dft_real_create_plan_f64(size_t size, + KFR_DFT_PACK_FORMAT pack_format); + +KFR_API_SPEC KFR_DFT_REAL_PLAN_F64* kfr_dft_real_create_2d_plan_f64(size_t size1, size_t size2, + bool real_out_is_enough); +KFR_API_SPEC KFR_DFT_REAL_PLAN_F64* kfr_dft_real_create_3d_plan_f64(size_t size1, size_t size2, size_t size3, + bool real_out_is_enough); +KFR_API_SPEC KFR_DFT_REAL_PLAN_F64* kfr_dft_real_create_md_plan_f64(size_t dims, const unsigned* shape, + bool real_out_is_enough); + +/** + * @brief Dump details of the real DFT plan to stdout for inspection. + * @param plan Pointer to the DFT plan. + */ +KFR_API_SPEC void kfr_dft_real_dump_f32(KFR_DFT_REAL_PLAN_F32* plan); + +/** + * @brief Dump details of the real DFT plan to stdout for inspection. + * @param plan Pointer to the DFT plan. + */ +KFR_API_SPEC void kfr_dft_real_dump_f64(KFR_DFT_REAL_PLAN_F64* plan); + +/** + * @brief Get the size of a real DFT plan. + * @param plan Pointer to the DFT plan. + * @return Size of the DFT as passed to `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC size_t kfr_dft_real_get_size_f32(KFR_DFT_REAL_PLAN_F32* plan); + +/** + * @brief Get the size of a real DFT plan. + * @param plan Pointer to the DFT plan. + * @return Size of the DFT as passed to `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC size_t kfr_dft_real_get_size_f64(KFR_DFT_REAL_PLAN_F64* plan); + +/** + * @brief Get temporary (scratch) buffer size for real DFT plan (Single precision). + * @param plan Pointer to the DFT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dft_execute_f**` + * and `kfr_dft_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dft_real_get_temp_size_f32(KFR_DFT_REAL_PLAN_F32* plan); + +/** + * @brief Get temporary (scratch) buffer size for real DFT plan (Double precision). + * @param plan Pointer to the DFT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dft_execute_f**` + * and `kfr_dft_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dft_real_get_temp_size_f64(KFR_DFT_REAL_PLAN_F64* plan); + +/** + * @brief Execute real DFT on `in` and write the result to `out` + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data. May point to the same memory as `in` for in-place execution. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dft_real_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note This function reads $N$ real values from `in` and writes $\frac{N}{2}$ (`Perm` format) or + * $\frac{N}{2}+1$ (`CCs` format) complex values to `out`, where $N$ is the size passed to + * `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_real_execute_f32(KFR_DFT_REAL_PLAN_F32* plan, kfr_c32* out, const kfr_f32* in, + uint8_t* temp); + +/** + * @brief Execute real DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data. May point to the same memory as `in` for in-place execution. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dft_real_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note This function reads $N$ real values from `in` and writes $\frac{N}{2}$ (`Perm` format) or + * $\frac{N}{2}+1$ (`CCs` format) complex values to `out`, where $N$ is the size passed to + * `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_real_execute_f64(KFR_DFT_REAL_PLAN_F64* plan, kfr_c64* out, const kfr_f64* in, + uint8_t* temp); + +/** + * @brief Execute inverse real DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data. May point to the same memory as `in` for in-place execution. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dft_real_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note This function reads $\frac{N}{2}$ (`Perm` format) or $\frac{N}{2}+1$ (`CCs` format) complex values + * from `in` and writes $N$ real values to `out`, where $N$ is the size passed to + * `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_real_execute_inverse_f32(KFR_DFT_REAL_PLAN_F32* plan, kfr_f32* out, + const kfr_c32* in, uint8_t* temp); + +/** + * @brief Execute inverse real DFT on `in` and write the result to `out`. + * @param plan Pointer to the DFT plan. + * @param out Pointer to output data. May point to the same memory as `in` for in-place execution. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dft_real_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note This function reads $\frac{N}{2}$ (`Perm` format) or $\frac{N}{2}+1$ (`CCs` format) complex values + * from `in` and writes $N$ real values to `out`, where $N$ is the size passed to + * `kfr_dft_real_create_plan_f**`. + */ +KFR_API_SPEC void kfr_dft_real_execute_inverse_f64(KFR_DFT_REAL_PLAN_F64* plan, kfr_f64* out, + const kfr_c64* in, uint8_t* temp); + +/** + * @brief Delete a real DFT plan. + * @param plan Pointer to the DFT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dft_real_delete_plan_f32(KFR_DFT_REAL_PLAN_F32* plan); + +/** + * @brief Delete a real DFT plan. + * @param plan Pointer to the DFT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dft_real_delete_plan_f64(KFR_DFT_REAL_PLAN_F64* plan); + +/** + * @brief Create a DCT-II plan (Single precision). + * @param size Size of the DCT. Must be even. + * @return Pointer to the created DCT plan. + */ +KFR_API_SPEC KFR_DCT_PLAN_F32* kfr_dct_create_plan_f32(size_t size); + +/** + * @brief Create a DCT-II plan (Double precision). + * @param size Size of the DCT. Must be even. + * @return Pointer to the created DCT plan. + */ +KFR_API_SPEC KFR_DCT_PLAN_F64* kfr_dct_create_plan_f64(size_t size); + +/** + * @brief Dump details of the DCT plan to stdout for inspection. + * @param plan Pointer to the DCT plan. + */ +KFR_API_SPEC void kfr_dct_dump_f32(KFR_DCT_PLAN_F32* plan); + +/** + * @brief Dump details of the DCT plan to stdout for inspection. + * @param plan Pointer to the DCT plan. + */ +KFR_API_SPEC void kfr_dct_dump_f64(KFR_DCT_PLAN_F64* plan); + +/** + * @brief Get the size of a DCT plan. + * @param plan Pointer to the DCT plan. + * @return Size of the DCT as passed to `kfr_dct_create_plan_f**`. + */ +KFR_API_SPEC size_t kfr_dct_get_size_f32(KFR_DCT_PLAN_F32* plan); + +/** + * @brief Get the size of a DCT plan. + * @param plan Pointer to the DCT plan. + * @return Size of the DCT as passed to `kfr_dct_create_plan_f**`. + */ +KFR_API_SPEC size_t kfr_dct_get_size_f64(KFR_DCT_PLAN_F64* plan); + +/** + * @brief Get temporary (scratch) buffer size for DCT plan. + * @param plan Pointer to the DCT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dct_execute_f**` + * and `kfr_dct_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dct_get_temp_size_f32(KFR_DCT_PLAN_F32* plan); + +/** + * @brief Get temporary (scratch) buffer size for DCT plan. + * @param plan Pointer to the DCT plan. + * @return Temporary buffer size in bytes. + * @note Preallocating a byte buffer of the returned size and passing its pointer to the `kfr_dct_execute_f**` + * and `kfr_dct_execute_inverse_f**` functions may improve performance. + */ +KFR_API_SPEC size_t kfr_dct_get_temp_size_f64(KFR_DCT_PLAN_F64* plan); + +/** + * @brief Execute DCT-II on `in` and write the result to `out`. + * @param plan Pointer to the DCT plan. + * @param out Pointer to output data. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dct_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note No scaling is applied. This function read $N$ values from `in` and writes $N$ values to `out`, where + * $N$ is the size passed to `kfr_dct_create_plan_f**`.. + */ +KFR_API_SPEC void kfr_dct_execute_f32(KFR_DCT_PLAN_F32* plan, kfr_f32* out, const kfr_f32* in, uint8_t* temp); + +/** + * @brief Execute DCT-II on `in` and write the result to `out`. + * @param plan Pointer to the DCT plan. + * @param out Pointer to output data. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dct_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note No scaling is applied. This function read $N$ values from `in` and writes $N$ values to `out`, where + * $N$ is the size passed to `kfr_dct_create_plan_f**`.. + */ +KFR_API_SPEC void kfr_dct_execute_f64(KFR_DCT_PLAN_F64* plan, kfr_f64* out, const kfr_f64* in, uint8_t* temp); + +/** + * @brief Execute inverse DCT-II (aka DCT-III) on `in` and write the result to `out`. + * @param plan Pointer to the DCT plan. + * @param out Pointer to output data. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dct_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note No scaling is applied. This function read $N$ values from `in` and writes $N$ values to `out`, where + * $N$ is the size passed to `kfr_dct_create_plan_f**`.. + */ +KFR_API_SPEC void kfr_dct_execute_inverse_f32(KFR_DCT_PLAN_F32* plan, kfr_f32* out, const kfr_f32* in, + uint8_t* temp); + +/** + * @brief Execute inverse DCT-II (aka DCT-III) on `in` and write the result to `out`. + * @param plan Pointer to the DCT plan. + * @param out Pointer to output data. + * @param in Pointer to input data. + * @param temp Temporary (scratch) buffer. If `NULL`, scratch buffer of size + * `kfr_dct_get_temp_size_f**(plan)` will be allocated on stack or heap. + * @note No scaling is applied. This function read $N$ values from `in` and writes $N$ values to `out`, where + * $N$ is the size passed to `kfr_dct_create_plan_f**`.. + */ +KFR_API_SPEC void kfr_dct_execute_inverse_f64(KFR_DCT_PLAN_F64* plan, kfr_f64* out, const kfr_f64* in, + uint8_t* temp); + +/** + * @brief Delete a DCT plan. + * @param plan Pointer to the DCT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dct_delete_plan_f32(KFR_DCT_PLAN_F32* plan); + +/** + * @brief Delete a DCT plan. + * @param plan Pointer to the DCT plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_dct_delete_plan_f64(KFR_DCT_PLAN_F64* plan); + +/** + * @brief Create a FIR filter plan (Single precision). + * @param taps Pointer to filter taps. + * @param size Number of filter taps. + * @return Pointer to the created FIR filter plan. Use `kfr_filter_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_fir_plan_f32(const kfr_f32* taps, size_t size); + +/** + * @brief Create a FIR filter plan (Double precision). + * @param taps Pointer to filter taps. + * @param size Number of filter taps. + * @return Pointer to the created FIR filter plan. Use `kfr_filter_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_fir_plan_f64(const kfr_f64* taps, size_t size); + +/** + * @brief Create a convolution filter plan (Single precision). + * @param taps Pointer to filter taps. + * @param size Number of filter taps. + * @param block_size Size of the processing block. Must be a power of two. + * @return Pointer to the created convolution filter plan. Use `kfr_filter_delete_plan_f**` to free. + * @note Mathematically, this produces the same result as an FIR filter, but it uses the FFT overlap-add + technique internally to improve performance with larger filter lengths. + */ +KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_convolution_plan_f32(const kfr_f32* taps, size_t size, + size_t block_size); + +/** + * @brief Create a convolution filter plan (Double precision). + * @param taps Pointer to filter taps. + * @param size Number of filter taps. + * @param block_size Size of the processing block. Must be a power of two. + * @return Pointer to the created convolution filter plan. Use `kfr_filter_delete_plan_f**` to free. + * @note Mathematically, this produces the same result as an FIR filter, but it uses the FFT overlap-add + technique internally to improve performance with larger filter lengths. + */ +KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_convolution_plan_f64(const kfr_f64* taps, size_t size, + size_t block_size); + +/** + * @brief Create a IIR filter plan (Single precision). + * @param sos Pointer to second-order sections (SOS) coefficients. + * @param sos_count Number of second-order sections. + * @return Pointer to the created IIR filter plan. Use `kfr_filter_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_iir_plan_f32(const kfr_f32* sos, size_t sos_count); + +/** + * @brief Create a IIR filter plan (Double precision). + * @param sos Pointer to second-order sections (SOS) coefficients. + * @param sos_count Number of second-order sections. + * @return Pointer to the created IIR filter plan. Use `kfr_filter_delete_plan_f**` to free. + */ +KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_iir_plan_f64(const kfr_f64* sos, size_t sos_count); + +/** + * @brief Process input data with a filter. + * @param plan Pointer to the filter plan. + * @param output Pointer to output data. May point to the same memory as `input` for in-place execution. + * @param input Pointer to input data. + * @param size Number of samples to process. + */ +KFR_API_SPEC void kfr_filter_process_f32(KFR_FILTER_F32* plan, kfr_f32* output, const kfr_f32* input, + size_t size); + +/** + * @brief Process input data with a filter. + * @param plan Pointer to the filter plan. + * @param output Pointer to output data. May point to the same memory as `input` for in-place execution. + * @param input Pointer to input data. + * @param size Number of samples to process. + */ +KFR_API_SPEC void kfr_filter_process_f64(KFR_FILTER_F64* plan, kfr_f64* output, const kfr_f64* input, + size_t size); + +/** + * @brief Reset the internal state of a filter plan, including delay line. + * @param plan Pointer to the filter plan. + */ +KFR_API_SPEC void kfr_filter_reset_f32(KFR_FILTER_F32* plan); + +/** + * @brief Reset the internal state of a filter plan, including delay line. + * @param plan Pointer to the filter plan. + */ +KFR_API_SPEC void kfr_filter_reset_f64(KFR_FILTER_F64* plan); + +/** + * @brief Delete a filter plan. + * @param plan Pointer to the filter plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_filter_delete_plan_f32(KFR_FILTER_F32* plan); + +/** + * @brief Delete a filter plan. + * @param plan Pointer to the filter plan. May be `NULL`. + */ +KFR_API_SPEC void kfr_filter_delete_plan_f64(KFR_FILTER_F64* plan); + +#ifdef __cplusplus +} +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cident.h b/packages/react-native-audio-api/android/src/main/include/kfr/cident.h new file mode 100644 index 00000000..8a7e149b --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cident.h @@ -0,0 +1,756 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#ifdef LIBC_WORKAROUND_GETS +extern char* gets(char* __s); +#endif + +#if defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) || defined(__wasm) +#define CMT_ARCH_X86 1 +#elif defined(__arm__) || defined(__arm64__) || defined(_M_ARM) || defined(__aarch64__) +#define CMT_ARCH_ARM 1 +#endif + +#ifdef CMT_ARCH_X86 +#if defined(_M_X64) || defined(__x86_64__) || defined(__wasm64) +#define CMT_ARCH_X64 1 +#define CMT_ARCH_BITNESS_NAME "64-bit" +#else +#define CMT_ARCH_X32 1 +#define CMT_ARCH_BITNESS_NAME "32-bit" +#endif + +#ifndef CMT_FORCE_GENERIC_CPU + +#if defined __AVX512F__ && !defined CMT_ARCH_AVX512 +#define CMT_ARCH_AVX512 1 +#define CMT_ARCH_AVX2 1 +#define CMT_ARCH_AVX 1 +#define CMT_ARCH_SSE4_2 1 +#define CMT_ARCH_SSE4_1 1 +#define CMT_ARCH_SSE42 1 +#define CMT_ARCH_SSE41 1 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __AVX2__ && !defined CMT_ARCH_AVX2 +#define CMT_ARCH_AVX2 1 +#define CMT_ARCH_AVX 1 +#define CMT_ARCH_SSE4_2 1 +#define CMT_ARCH_SSE4_1 1 +#define CMT_ARCH_SSE42 1 +#define CMT_ARCH_SSE41 1 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __AVX__ && !defined CMT_ARCH_AVX +#define CMT_ARCH_AVX 1 +#define CMT_ARCH_SSE4_2 1 +#define CMT_ARCH_SSE4_1 1 +#define CMT_ARCH_SSE42 1 +#define CMT_ARCH_SSE41 1 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __SSE4_2__ && !defined CMT_ARCH_SSE4_2 +#define CMT_ARCH_SSE4_2 1 +#define CMT_ARCH_SSE42 1 +#define CMT_ARCH_SSE4_1 1 +#define CMT_ARCH_SSE41 1 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __SSE4_1__ && !defined CMT_ARCH_SSE4_1 +#define CMT_ARCH_SSE4_1 1 +#define CMT_ARCH_SSE41 1 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __SSSE3__ && !defined CMT_ARCH_SSSE3 +#define CMT_ARCH_SSSE3 1 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if defined __SSE3__ && !defined CMT_ARCH_SSE3 +#define CMT_ARCH_SSE3 1 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif +#if (defined CMT_ARCH_X64 || defined __SSE2__ || (defined _M_IX86_FP && _M_IX86_FP == 2)) && \ + !defined CMT_ARCH_SSE2 +#define CMT_ARCH_SSE2 1 +#define CMT_ARCH_SSE 1 +#endif + +#if (defined CMT_ARCH_X64 || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP == 1)) && \ + !defined CMT_ARCH_SSE +#define CMT_ARCH_SSE 1 +#endif + +#if defined __FMA__ && !defined CMT_ARCH_FMA +#define CMT_ARCH_FMA 1 +#endif + +#if defined __AES__ && !defined CMT_ARCH_AES +#define CMT_ARCH_AES 1 +#endif + +#if defined __BMI__ && !defined CMT_ARCH_BMI +#define CMT_ARCH_BMI 1 +#endif + +#if defined __BMI2__ && !defined CMT_ARCH_BMI2 +#define CMT_ARCH_BMI2 1 +#endif + +#if defined __LZCNT__ && !defined CMT_ARCH_LZCNT +#define CMT_ARCH_LZCNT 1 +#endif + +#endif // CMT_FORCE_GENERIC_CPU + +#if defined CMT_ARCH_AVX512 +#define CMT_ARCH_NAME avx512 +#define CMT_ARCH_IS_AVX512 1 +#elif defined CMT_ARCH_AVX2 +#define CMT_ARCH_NAME avx2 +#define CMT_ARCH_IS_AVX2 1 +#elif defined CMT_ARCH_AVX +#define CMT_ARCH_NAME avx +#define CMT_ARCH_IS_AVX 1 +#elif defined CMT_ARCH_SSE42 +#define CMT_ARCH_NAME sse42 +#define CMT_ARCH_IS_SSE42 1 +#elif defined CMT_ARCH_SSE41 +#define CMT_ARCH_NAME sse41 +#define CMT_ARCH_IS_SSE4 1 +#elif defined CMT_ARCH_SSSE3 +#define CMT_ARCH_NAME ssse3 +#define CMT_ARCH_IS_SSSE3 1 +#elif defined CMT_ARCH_SSE3 +#define CMT_ARCH_NAME sse3 +#define CMT_ARCH_IS_SSE3 1 +#elif defined CMT_ARCH_SSE2 +#define CMT_ARCH_NAME sse2 +#define CMT_ARCH_IS_SSE2 1 +#elif defined CMT_ARCH_SSE +#define CMT_ARCH_NAME sse +#define CMT_ARCH_IS_SSE 1 +#else +#define CMT_ARCH_IS_GENERIC 1 +#endif + +#elif defined(CMT_ARCH_ARM) + +#if defined(__aarch64__) +#define CMT_ARCH_X64 1 +#define CMT_ARCH_BITNESS_NAME "64-bit" +#else +#define CMT_ARCH_X32 1 +#define CMT_ARCH_BITNESS_NAME "32-bit" +#endif + +#if defined __ARM_NEON__ || defined __ARM_NEON + +#if __ARM_ARCH >= 8 && defined(__aarch64__) +#define CMT_ARCH_NEON64 1 +#define CMT_ARCH_NEON 1 +#define CMT_ARCH_NAME neon64 +#else +#define CMT_ARCH_NEON 1 +#define CMT_ARCH_NAME neon +#define CMT_NO_NATIVE_F64 1 +#endif +#endif + +#endif + +#if defined CMT_ARCH_ARM && defined CMT_ARCH_X64 +#define CMT_ARCH_ARM64 1 +#define CMT_ARCH_AARCH64 1 +#endif + +#ifndef CMT_ARCH_NAME +#define CMT_ARCH_NAME generic +#endif + +#define CMT_ARCH_ID_GENERIC 0 + +#define CMT_ARCH_ID_SSE2 1 +#define CMT_ARCH_ID_SSE3 2 +#define CMT_ARCH_ID_SSSE3 3 +#define CMT_ARCH_ID_SSE41 4 +#define CMT_ARCH_ID_SSE42 5 +#define CMT_ARCH_ID_AVX 6 +#define CMT_ARCH_ID_AVX2 7 +#define CMT_ARCH_ID_AVX512 8 + +#define CMT_ARCH_ID_NEON 1 +#define CMT_ARCH_ID_NEON64 2 + +#ifdef CMT_ENABLE_SSE2 +#define CMT_EXPAND_IF_ARCH_sse2(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_sse2(...) +#endif + +#ifdef CMT_ENABLE_SSE3 +#define CMT_EXPAND_IF_ARCH_sse3(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_sse3(...) +#endif + +#ifdef CMT_ENABLE_SSSE3 +#define CMT_EXPAND_IF_ARCH_ssse3(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_ssse3(...) +#endif + +#ifdef CMT_ENABLE_SSE41 +#define CMT_EXPAND_IF_ARCH_sse41(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_sse41(...) +#endif + +#ifdef CMT_ENABLE_SSE41 +#define CMT_EXPAND_IF_ARCH_sse41(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_sse41(...) +#endif + +#ifdef CMT_ENABLE_SSE42 +#define CMT_EXPAND_IF_ARCH_sse42(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_sse42(...) +#endif + +#ifdef CMT_ENABLE_AVX +#define CMT_EXPAND_IF_ARCH_avx(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_avx(...) +#endif + +#ifdef CMT_ENABLE_AVX2 +#define CMT_EXPAND_IF_ARCH_avx2(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_avx2(...) +#endif + +#ifdef CMT_ENABLE_AVX512 +#define CMT_EXPAND_IF_ARCH_avx512(...) __VA_ARGS__ +#else +#define CMT_EXPAND_IF_ARCH_avx512(...) +#endif + +#ifndef CMT_NO_NATIVE_F64 +#define CMT_NATIVE_F64 1 +#endif + +#ifndef CMT_NO_NATIVE_I64 +#define CMT_NATIVE_I64 1 +#endif + +#define CMT_STRINGIFY2(x) #x +#define CMT_STRINGIFY(x) CMT_STRINGIFY2(x) + +#if defined(_WIN32) // Windows +#define CMT_OS_WIN 1 +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#define CMT_OS_IOS 1 +#define CMT_OS_MOBILE 1 +#define CMT_OS_APPLE 1 +#elif defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR +#define CMT_OS_IOS 1 +#define CMT_OS_IOS_SIMULATOR 1 +#define CMT_OS_MOBILE 1 +#define CMT_OS_APPLE 1 +#elif defined(TARGET_OS_MAC) && TARGET_OS_MAC +#define CMT_OS_MAC 1 +#define CMT_OS_MACOS 1 +#define CMT_OS_OSX 1 +#define CMT_OS_APPLE 1 +#endif +#define CMT_OS_POSIX 1 +#define CMT_OS_APPLE 1 +#endif + +#if defined(__ANDROID__) +#define CMT_OS_ANDROID 1 +#define CMT_OS_MOBILE 1 +#define CMT_OS_POSIX 1 +#endif + +#if defined(__linux__) +#define CMT_OS_LINUX 1 +#define CMT_OS_POSIX 1 +#endif + +#if defined(_MSC_VER) // Visual C/C++ +#define CMT_COMPILER_MSVC 1 +#define CMT_MSVC_ATTRIBUTES 1 +#define CMT_MSC_VER _MSC_VER +#define CMT_COMPILER_IS_MSVC 1 +#else +#define CMT_MSC_VER 0 +#endif + +#if defined(__GNUC__) || defined(__clang__) // GCC, Clang +#define CMT_COMPILER_GNU 1 + +#if !defined(__clang__) // GCC only +#define CMT_COMPILER_GCC 1 +#endif + +#define CMT_GNU_ATTRIBUTES 1 +#define CMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ +#define CMT_HAS_GXX_CXX11 1 +#endif +#else +#define CMT_GCC_VERSION 0 +#endif + +#if defined(__INTEL_COMPILER) // Intel Compiler +#define CMT_COMPILER_INTEL 1 +#define CMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +#define CMT_COMPILER_INTEL 1 +#define CMT_ICC_VERSION __ICL +#else +#define CMT_ICC_VERSION 0 +#endif + +#if defined(__clang__) // Clang +#define CMT_COMPILER_CLANG 1 +#ifndef CMT_GNU_ATTRIBUTES +#define CMT_GNU_ATTRIBUTES 1 +#endif +#endif + +#if defined _MSC_VER && !defined(__clang__) && !defined(CMT_FORCE_INLINE_MSVC) +#define CMT_NO_FORCE_INLINE 1 +#endif + +#if defined(CMT_COMPILER_INTEL) || defined(CMT_COMPILER_CLANG) +#ifdef CMT_COMPILER_IS_MSVC +#undef CMT_COMPILER_IS_MSVC +#endif +#endif + +#if defined(CMT_GNU_ATTRIBUTES) + +#define CMT_NODEBUG + +#ifndef CMT_NO_FORCE_INLINE +#define CMT_ALWAYS_INLINE __attribute__((__always_inline__)) +#else +#define CMT_ALWAYS_INLINE +#endif + +#ifdef NDEBUG +#define CMT_INLINE_IN_RELEASE CMT_ALWAYS_INLINE +#else +#define CMT_INLINE_IN_RELEASE +#endif + +#define CMT_INLINE __inline__ CMT_INLINE_IN_RELEASE +#define CMT_INLINE_MEMBER CMT_INLINE_IN_RELEASE +#if defined(CMT_COMPILER_GCC) && \ + (CMT_GCC_VERSION >= 900 && CMT_GCC_VERSION < 904 || CMT_GCC_VERSION >= 1000 && CMT_GCC_VERSION < 1002) +// Workaround for GCC 9/10 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90333 +#define CMT_INLINE_LAMBDA +#else +#define CMT_INLINE_LAMBDA CMT_INLINE_MEMBER +#endif +#define CMT_NOINLINE __attribute__((__noinline__)) +#ifndef CMT_NO_FORCE_INLINE +#define CMT_FLATTEN __attribute__((__flatten__)) +#else +#define CMT_FLATTEN +#endif +#define CMT_RESTRICT __restrict__ + +#define CMT_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1) +#define CMT_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0) + +#elif defined(CMT_MSVC_ATTRIBUTES) + +#ifndef CMT_NO_FORCE_INLINE +#if _MSC_VER >= 1927 && _MSVC_LANG >= 202002L +#define CMT_ALWAYS_INLINE [[msvc::forceinline]] +#else +#define CMT_ALWAYS_INLINE __forceinline +#endif +#else +#define CMT_ALWAYS_INLINE +#endif + +#ifdef NDEBUG +#define CMT_INLINE_IN_RELEASE CMT_ALWAYS_INLINE +#else +#define CMT_INLINE_IN_RELEASE +#endif + +#define CMT_NODEBUG +#define CMT_INLINE inline CMT_INLINE_IN_RELEASE +#define CMT_INLINE_MEMBER CMT_INLINE_IN_RELEASE +#if _MSC_VER >= 1927 && _MSVC_LANG >= 202002L +#define CMT_INLINE_LAMBDA [[msvc::forceinline]] +#else +#define CMT_INLINE_LAMBDA +#endif +#define CMT_NOINLINE __declspec(noinline) +#define CMT_FLATTEN +#define CMT_RESTRICT __restrict + +#define CMT_LIKELY(...) (__VA_ARGS__) +#define CMT_UNLIKELY(...) (__VA_ARGS__) + +#endif + +#define CMT_INTRINSIC CMT_INLINE CMT_NODEBUG +#define CMT_MEM_INTRINSIC CMT_INLINE CMT_NODEBUG + +#if defined _MSC_VER && _MSC_VER >= 1900 && \ + (!defined(__clang__) || \ + (defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 9)))) +#define CMT_EMPTY_BASES __declspec(empty_bases) +#else +#define CMT_EMPTY_BASES +#endif + +#define CMT_INLINE_STATIC CMT_INLINE static + +#define CMT_EXTERN_C extern "C" + +#define CMT_PUBLIC_C CMT_EXTERN_C CMT_NOINLINE + +#define CMT_ALWAYS_INLINE_STATIC CMT_ALWAYS_INLINE static + +#ifdef CMT_ARCH_x86 +#ifdef CMT_OS_WIN +#define CMT_CDECL __cdecl +#else +#define CMT_CDECL __attribute__((cdecl)) +#endif +#else +#define CMT_CDECL +#endif + +#ifdef CMT_OS_WIN +#if defined(CMT_MSVC_ATTRIBUTES) +#define CMT_DLL_EXPORT __declspec(dllexport) +#define CMT_DLL_IMPORT __declspec(dllimport) +#else +#define CMT_DLL_EXPORT __attribute__((dllexport)) +#define CMT_DLL_IMPORT __attribute__((dllimport)) +#endif +#else +#define CMT_DLL_EXPORT +#define CMT_DLL_IMPORT +#endif + +#ifdef __has_builtin +#define CMT_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else +#define CMT_HAS_BUILTIN(builtin) 0 +#endif + +#define CMT_NOOP \ + do \ + { \ + } while (0) + +#if CMT_HAS_BUILTIN(CMT_ASSUME) +#define CMT_ASSUME(x) __builtin_assume(x) +#else +#define CMT_ASSUME(x) CMT_NOOP +#endif + +#if CMT_HAS_BUILTIN(CMT_ASSUME) +#define CMT_ASSUME_ALIGNED(x, a) __builtin_assume_aligned(x, a) +#else +#define CMT_ASSUME_ALIGNED(x, a) x +#endif + +#ifdef __has_feature +#define CMT_HAS_FEATURE(feature) __has_feature(feature) +#else +#define CMT_HAS_FEATURE(feature) 0 +#endif + +#ifdef __has_extension +#define CMT_HAS_EXTENSION(extension) __has_extension(extension) +#else +#define CMT_HAS_EXTENSION(extension) 0 +#endif + +#ifdef __has_attribute +#define CMT_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +#define CMT_HAS_ATTRIBUTE(attribute) 0 +#endif + +#ifdef __has_warning +#define CMT_HAS_WARNING(warning) __has_warning(warning) +#else +#define CMT_HAS_WARNING(warning) 0 +#endif + +#define CMT_HAS_VARIADIC_TEMPLATES \ + (CMT_HAS_FEATURE(cxx_variadic_templates) || (CMT_GCC_VERSION >= 404 && CMT_HAS_GXX_CXX11) || \ + CMT_MSC_VER >= 1800) + +#ifdef CMT_BUILDING_DLL +#define CMT_C_API CMT_DLL_EXPORT +#else +#define CMT_C_API CMT_DLL_IMPORT +#endif + +#if __cplusplus >= 201103L || CMT_MSC_VER >= 1900 || CMT_HAS_FEATURE(cxx_constexpr) +#define CMT_HAS_CONSTEXPR 1 +#endif + +#if __cpp_constexpr >= 201304 || CMT_HAS_FEATURE(cxx_constexpr) +#define CMT_HAS_FULL_CONSTEXPR 1 +#endif + +#if CMT_HAS_CONSTEXPR +#define CMT_CONSTEXPR constexpr +#else +#define CMT_CONSTEXPR +#endif + +#if CMT_HAS_FEATURE(cxx_noexcept) || (CMT_GCC_VERSION >= 408 && CMT_HAS_GXX_CXX11) || CMT_MSC_VER >= 1900 +#define CMT_HAS_NOEXCEPT 1 +#endif + +#if CMT_HAS_NOEXCEPT +#define CMT_NOEXCEPT noexcept +#define CMT_NOEXCEPT_SPEC(...) noexcept(__VA_ARGS__) +#else +#define CMT_NOEXCEPT +#define CMT_NOEXCEPT_SPEC(...) +#endif + +#if CMT_COMPILER_GNU && !defined(__EXCEPTIONS) +#define CMT_HAS_EXCEPTIONS 0 +#endif +#if CMT_COMPILER_MSVC && !_HAS_EXCEPTIONS +#define CMT_HAS_EXCEPTIONS 0 +#endif + +#ifndef CMT_HAS_EXCEPTIONS +#define CMT_HAS_EXCEPTIONS 1 +#endif + +#if defined __has_include +#if __has_include() +#include +#define CMT_HAS_ASSERT_H 1 +#endif +#endif + +#ifndef CMT_THROW +#if CMT_HAS_EXCEPTIONS +#define CMT_THROW(x) throw x +#else +#ifdef CMT_HAS_ASSERT_H +#define CMT_THROW(x) assert(false) +#else +#define CMT_THROW(x) abort() +#endif +#endif +#endif + +#ifdef CMT_COMPILER_MSVC +#define CMT_FUNC_SIGNATURE __FUNCSIG__ +#else +#define CMT_FUNC_SIGNATURE __PRETTY_FUNCTION__ +#endif + +#if CMT_COMPILER_CLANG +#define CMT_LOOP_NOUNROLL \ + _Pragma("clang loop vectorize( disable )") _Pragma("clang loop interleave( disable )") \ + _Pragma("clang loop unroll( disable )") + +#define CMT_LOOP_UNROLL _Pragma("clang loop unroll( full )") +#define CMT_VEC_CC __attribute__((vectorcall)) +#else +#define CMT_LOOP_NOUNROLL +#define CMT_LOOP_UNROLL +#ifdef CMT_COMPILER_MSVC +#define CMT_VEC_CC __vectorcall +#endif +#endif + +#define CMT_PRAGMA(...) _Pragma(#__VA_ARGS__) + +#if defined(CMT_GNU_ATTRIBUTES) +#define CMT_FAST_CC __attribute__((fastcall)) +#define CMT_UNUSED __attribute__((unused)) +#define CMT_GNU_CONSTEXPR constexpr +#define CMT_GNU_NOEXCEPT noexcept +#define CMT_GNU_PACKED __attribute__((packed)) +#define CMT_PRAGMA_PACK_PUSH_1 +#define CMT_PRAGMA_PACK_POP +#define CMT_FP(h, d) h +#define CMT_PRAGMA_GNU(...) _Pragma(#__VA_ARGS__) +#ifdef CMT_COMPILER_CLANG +#define CMT_PRAGMA_CLANG(...) _Pragma(#__VA_ARGS__) +#else +#define CMT_PRAGMA_CLANG(...) +#endif +#ifdef CMT_COMPILER_CLANG +#define CMT_PRAGMA_GCC(...) _Pragma(#__VA_ARGS__) +#else +#define CMT_PRAGMA_GCC(...) +#endif +#define CMT_PRAGMA_MSVC(...) +#else +#define CMT_FAST_CC __fastcall +#define CMT_UNUSED +#define CMT_GNU_CONSTEXPR +#define CMT_GNU_NOEXCEPT +#define CMT_GNU_PACKED +#define CMT_PRAGMA_PACK_PUSH_1 __pragma(pack(push, 1)) +#define CMT_PRAGMA_PACK_POP __pragma(pack(pop)) +#define CMT_FP(h, d) d +#define CMT_PRAGMA_GNU(...) +#define CMT_PRAGMA_CLANG(...) +#define CMT_PRAGMA_GCC(...) +#define CMT_PRAGMA_MSVC(...) __pragma(__VA_ARGS__) +#endif + +#if defined CMT_OS_IOS +#define CMT_OS_NAME "ios" +#elif defined CMT_OS_MAC +#define CMT_OS_NAME "macos" +#elif defined CMT_OS_ANDROIS +#define CMT_OS_NAME "android" +#elif defined CMT_OS_LINUX +#define CMT_OS_NAME "linux" +#elif defined CMT_OS_WIN +#define CMT_OS_NAME "windows" +#else +#define CMT_OS_NAME "unknown" +#endif + +#if defined CMT_COMPILER_INTEL +#if defined _MSC_VER +#define CMT_COMPILER_NAME "intel-msvc" +#define CMT_COMPILER_FULL_NAME \ + "clang-msvc-" CMT_STRINGIFY(__ICL) "." CMT_STRINGIFY(__INTEL_COMPILER_UPDATE) "." CMT_STRINGIFY( \ + __INTEL_COMPILER_BUILD_DATE) +#else +#define CMT_COMPILER_NAME "intel" +#ifdef __INTEL_CLANG_COMPILER +#define CMT_COMPILER_INTEL_SPEC "-clang" +#ifdef __INTEL_LLVM_COMPILER +#define CMT_COMPILER_INTEL_SPEC "-clang-llvm" +#endif +#else +#ifdef __INTEL_LLVM_COMPILER +#define CMT_COMPILER_INTEL_SPEC "-llvm" +#else +#define CMT_COMPILER_INTEL_SPEC "" +#endif +#endif +#define CMT_COMPILER_FULL_NAME \ + "intel-" CMT_STRINGIFY(__INTEL_COMPILER) CMT_COMPILER_INTEL_SPEC \ + "." CMT_STRINGIFY(__INTEL_COMPILER_UPDATE) "." CMT_STRINGIFY(__INTEL_COMPILER_BUILD_DATE) +#endif +#elif defined CMT_COMPILER_CLANG +#if defined _MSC_VER +#define CMT_COMPILER_NAME "clang-msvc" +#define CMT_COMPILER_FULL_NAME \ + "clang-msvc-" CMT_STRINGIFY(__clang_major__) "." CMT_STRINGIFY(__clang_minor__) "." CMT_STRINGIFY( \ + __clang_patchlevel__) +#else +#define CMT_COMPILER_NAME "clang-mingw" +#define CMT_COMPILER_FULL_NAME \ + "clang-" CMT_STRINGIFY(__clang_major__) "." CMT_STRINGIFY(__clang_minor__) "." CMT_STRINGIFY( \ + __clang_patchlevel__) +#endif +#elif defined CMT_COMPILER_GCC +#define CMT_COMPILER_NAME "gcc" +#define CMT_COMPILER_FULL_NAME \ + "gcc-" CMT_STRINGIFY(__GNUC__) "." CMT_STRINGIFY(__GNUC_MINOR__) "." CMT_STRINGIFY(__GNUC_PATCHLEVEL__) +#elif defined CMT_COMPILER_MSVC +#define CMT_COMPILER_NAME "msvc" +#define CMT_COMPILER_FULL_NAME "msvc-" CMT_STRINGIFY(_MSC_VER) "." CMT_STRINGIFY(_MSC_FULL_VER) +#else +#define CMT_COMPILER_NAME "unknown" +#define CMT_COMPILER_FULL_NAME "unknown" +#endif + +#define CMT_CONCAT(a, b) a##b + +#define CMT_NARGS2(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10 +#define CMT_NARGS(...) CMT_NARGS2(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +#define CMT_IF_IS_AVX512(...) +#define CMT_IF_IS_AVX2(...) +#define CMT_IF_IS_AVX(...) +#define CMT_IF_IS_SSE42(...) +#define CMT_IF_IS_SSE41(...) +#define CMT_IF_IS_SSSE3(...) +#define CMT_IF_IS_SSE3(...) +#define CMT_IF_IS_SSE2(...) + +#if defined CMT_ARCH_AVX512 +#undef CMT_IF_IS_AVX512 +#define CMT_IF_IS_AVX512(...) __VA_ARGS__ +#elif defined CMT_ARCH_AVX2 +#undef CMT_IF_IS_AVX2 +#define CMT_IF_IS_AVX2(...) __VA_ARGS__ +#elif defined CMT_ARCH_AVX +#undef CMT_IF_IS_AVX +#define CMT_IF_IS_AVX(...) __VA_ARGS__ +#elif defined CMT_ARCH_SSE42 +#undef CMT_IF_IS_SSE42 +#define CMT_IF_IS_SSE42(...) __VA_ARGS__ +#elif defined CMT_ARCH_SSE41 +#undef CMT_IF_IS_SSE41 +#define CMT_IF_IS_SSE41(...) __VA_ARGS__ +#elif defined CMT_ARCH_SSSE3 +#undef CMT_IF_IS_SSSE3 +#define CMT_IF_IS_SSSE3(...) __VA_ARGS__ +#elif defined CMT_ARCH_SSE3 +#undef CMT_IF_IS_SSE3 +#define CMT_IF_IS_SSE3(...) __VA_ARGS__ +#elif defined CMT_ARCH_SSE2 +#undef CMT_IF_IS_SSE2 +#define CMT_IF_IS_SSE2(...) __VA_ARGS__ +#endif + +#ifdef CMT_COMPILER_GNU +#define CMT_UNREACHABLE \ + do \ + { \ + __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define CMT_UNREACHABLE \ + do \ + { \ + __assume(false); \ + } while (0) +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa.hpp new file mode 100644 index 00000000..70b7b060 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa.hpp @@ -0,0 +1,2250 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "cident.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpragmas") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wunknown-warning-option") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wmaybe-uninitialized") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wdeprecated-declarations") + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4814)) +CMT_PRAGMA_MSVC(warning(disable : 4308)) +CMT_PRAGMA_MSVC(warning(disable : 4014)) + +namespace cometa +{ + +using std::ptrdiff_t; +using std::size_t; + +template +constexpr CMT_INTRINSIC static size_t arraysize(const T (&)[N]) CMT_NOEXCEPT +{ + return N; +} + +template +constexpr CMT_INTRINSIC static std::integral_constant carraysize(const T (&)[N]) CMT_NOEXCEPT +{ + return {}; +} + +using pvoid = void*; +using pconstvoid = const void*; + +#ifdef CMT_CPP17_DEFINITIONS +template +using void_t = void; +#endif + +namespace details +{ +constexpr CMT_INTRINSIC bool args_or() { return false; } +template +constexpr CMT_INTRINSIC bool args_or(bool x, Ts... rest) +{ + return x || args_or(rest...); +} + +constexpr CMT_INTRINSIC bool args_and() { return true; } +template +constexpr CMT_INTRINSIC bool args_and(bool x, Ts... rest) +{ + return x && args_and(rest...); +} + +template +struct or_t_impl : std::false_type +{ +}; + +template +struct or_t_impl : std::integral_constant::value> +{ +}; + +template +struct and_t_impl : std::true_type +{ +}; + +template +struct and_t_impl : std::integral_constant::value> +{ +}; + +} // namespace details + +constexpr size_t max_size_t = size_t(-1); + +#ifdef CMT_CPP17_DEFINITIONS +template +using common_type = typename std::common_type::type; + +#if __cplusplus >= 201703L +template +using invoke_result = typename std::invoke_result::type; +#else +template +using invoke_result = typename std::result_of::type; +#endif + +template +using enable_if = typename std::enable_if::type; + +template +using conditional = typename std::conditional::type; + +template +using remove_reference = typename std::remove_reference::type; + +template +using remove_cv = typename std::remove_cv::type; + +template +using remove_pointer = typename std::remove_pointer::type; + +template +using remove_extent = typename std::remove_extent::type; + +template +using remove_const = typename std::remove_const::type; + +template +using underlying_type = typename std::underlying_type::type; + +template +constexpr inline bool is_class = std::is_class::value; + +template +constexpr inline bool is_const = std::is_const::value; + +template +constexpr inline bool is_pointer = std::is_pointer::value; + +template +constexpr inline bool is_array = std::is_array::value; + +template +constexpr inline bool is_void = std::is_void::value; + +template +constexpr inline bool is_floating_point = std::is_floating_point::value; + +template +constexpr inline bool is_unsigned = std::is_unsigned::value; + +template +constexpr inline bool is_signed = std::is_signed::value; + +template +constexpr inline bool is_scalar = std::is_scalar::value; + +template +constexpr inline bool is_integral = std::is_integral::value; + +template +constexpr inline bool is_same = std::is_same::value; + +template +constexpr inline bool is_base_of = std::is_base_of::value; + +template +constexpr inline bool is_convertible = std::is_convertible::value; + +template +constexpr inline bool is_constructible = std::is_constructible::value; + +template +constexpr inline bool is_template_arg = std::is_integral::value || std::is_enum::value; + +template +using decay = typename std::decay::type; + +#endif + +template +using or_type = std::conditional_t, T2, T1>; + +template +constexpr size_t typeindex() +{ + return std::is_same_v() ? 0 : 1 + typeindex(); +} + +template +struct compound_type_traits +{ + constexpr static size_t width = 1; + constexpr static size_t deep_width = width; + using subtype = T; + using deep_subtype = T; + constexpr static size_t depth = 0; + constexpr static bool is_scalar = true; + + template + using rebind = U; + template + using deep_rebind = U; + + CMT_MEM_INTRINSIC static constexpr const subtype& at(const T& value, size_t /*index*/) { return value; } +}; + +template +constexpr size_t widthof(T) +{ + return compound_type_traits::width; +} +template +constexpr size_t widthof() +{ + return compound_type_traits>::width; +} + +template +constexpr inline bool is_compound_type = !compound_type_traits>::is_scalar; + +template +using subtype = typename compound_type_traits::subtype; + +template +using deep_subtype = typename compound_type_traits::deep_subtype; + +template +struct compound_type_traits> +{ + constexpr static size_t width = 2; + constexpr static size_t deep_width = width * compound_type_traits::width; + using subtype = T; + using deep_subtype = cometa::deep_subtype; + constexpr static bool is_scalar = false; + constexpr static size_t depth = cometa::compound_type_traits::depth + 1; + + template + using rebind = std::pair; + template + using deep_rebind = std::pair::template deep_rebind, + typename compound_type_traits::template deep_rebind>; + + CMT_MEM_INTRINSIC static constexpr const subtype& at(const std::pair& value, + size_t index) + { + return index == 0 ? value.first : value.second; + } +}; + +template +struct cval_t +{ + constexpr static T value = val; + constexpr CMT_MEM_INTRINSIC cval_t() CMT_NOEXCEPT {} + constexpr CMT_MEM_INTRINSIC cval_t(const cval_t&) CMT_NOEXCEPT = default; + constexpr CMT_MEM_INTRINSIC cval_t(cval_t&&) CMT_NOEXCEPT = default; + typedef T value_type; + typedef cval_t type; + constexpr CMT_MEM_INTRINSIC operator value_type() const { return value; } + constexpr CMT_MEM_INTRINSIC value_type operator()() const { return value; } +}; + +template +constexpr CMT_INTRINSIC T val_of(cval_t) +{ + return value; +} + +template +constexpr CMT_INTRINSIC T val_of(T value) +{ + return value; +} + +#define CMT_CVAL(...) (decltype(__VA_ARGS__)::value) + +template +constexpr CMT_INTRINSIC bool is_constant_val(T) +{ + return false; +} + +template +constexpr CMT_INTRINSIC bool is_constant_val(cval_t) +{ + return true; +} + +namespace details +{ + +template +struct inherit : T +{ +}; + +template +struct is_inheritable_impl : std::false_type +{ +}; + +template +struct is_inheritable_impl>> : std::true_type +{ +}; + +template +struct is_val_impl : std::false_type +{ +}; + +template +struct is_val_impl> : std::true_type +{ +}; +} // namespace details + +template +using is_inheritable = typename details::is_inheritable_impl::type; + +template +using is_val_t = typename details::is_val_impl::type; + +template +using cbool_t = cval_t; + +template +using cint_t = cval_t; + +template +using cuint_t = cval_t; + +template +using csize_t = cval_t; + +using cfalse_t = cbool_t; +using ctrue_t = cbool_t; + +constexpr ctrue_t ctrue{}; +constexpr cfalse_t cfalse{}; + +namespace details +{ +template +struct get_nth : get_nth +{ +}; + +template +struct get_nth<0, T, first, rest...> +{ + constexpr static T value = first; +}; + +template +struct get_nth_e; + +template +struct get_nth_type; + +template +struct get_nth_type : get_nth_type +{ +}; + +template +struct get_nth_type<0, first, rest...> +{ + using type = first; +}; + +template +struct get_nth_type +{ +}; +} // namespace details + +template +struct cvals_t +{ + constexpr CMT_MEM_INTRINSIC cvals_t() CMT_NOEXCEPT = default; + + using type = cvals_t; + constexpr CMT_MEM_INTRINSIC static size_t size() { return sizeof...(values); } + template + constexpr CMT_MEM_INTRINSIC T operator[](csize_t) const + { + return get(csize_t()); + } + template + constexpr CMT_MEM_INTRINSIC static T get(csize_t = csize_t()) + { + return details::get_nth::value; + } + constexpr CMT_MEM_INTRINSIC static T front() { return get(csize_t<0>()); } + constexpr CMT_MEM_INTRINSIC static T back() { return get(csize_t()); } + + static CMT_MEM_INTRINSIC const T* begin() { return array(); } + static CMT_MEM_INTRINSIC const T* end() { return array() + size(); } + + static CMT_MEM_INTRINSIC const T* array() + { + static const T arr[] = { values... }; + return &arr[0]; + } + template + constexpr CMT_MEM_INTRINSIC cvals_t::value...> operator[]( + cvals_t) const + { + // static_assert(sizeof(T)==0, "+++++++++++++++++++++++++++++"); + return {}; + } + + // MSVC requires static_cast here: + template + constexpr CMT_MEM_INTRINSIC auto map(Fn&&) const -> cvals_t(Fn()(values))...> + { + return {}; + } + + constexpr CMT_MEM_INTRINSIC bool equal(cvals_t) const noexcept { return true; } + template + constexpr CMT_MEM_INTRINSIC bool equal(cvals_t) const noexcept + { + return false; + } + + template + constexpr CMT_MEM_INTRINSIC bool notequal(cvals_t ind) const noexcept + { + return !equal(ind); + } +}; + +template +struct cvals_t +{ + using type = cvals_t; + constexpr CMT_MEM_INTRINSIC static size_t size() { return 0; } + + static CMT_MEM_INTRINSIC const T* array() { return nullptr; } +}; + +template +constexpr cvals_t select(cvals_t, cvals_t, + cvals_t) +{ + return {}; +} + +namespace details +{ +template +struct get_nth_e> +{ + constexpr static T value = get_nth::value; +}; +} // namespace details + +template +using cbools_t = cvals_t; + +constexpr cbools_t cfalse_true{}; + +template +using cints_t = cvals_t; + +template +using cchars_t = cvals_t; + +template +using cuints_t = cvals_t; + +template +using csizes_t = cvals_t; + +template +using elements_t = cvals_t; + +template +constexpr CMT_INTRINSIC T csum(cvals_t = cvals_t()) +{ + return 0; +} + +template +constexpr CMT_INTRINSIC T csum(cvals_t = cvals_t()) +{ + return first + csum(cvals_t()); +} + +template +constexpr CMT_INTRINSIC T cprod(cvals_t) +{ + return 1; +} + +template +constexpr CMT_INTRINSIC T cprod(cvals_t) +{ + return first * cprod(cvals_t()); +} + +template +struct ctype_t +{ +#ifdef CMT_COMPILER_INTEL + constexpr ctype_t() CMT_NOEXCEPT = default; + constexpr ctype_t(const ctype_t&) CMT_NOEXCEPT = default; +#endif + using type = T; +}; + +template +using type_of = typename T::type; + +template +struct ctypes_t +{ + constexpr static size_t size() { return sizeof...(Types); } + + template + using nth = typename details::get_nth_type::type; + + template + constexpr static auto get(csize_t) -> ctype_t> + { + return {}; + } +}; + +namespace details +{ +template +struct concat_impl; + +template +struct concat_impl +{ + using type = T; +}; + +template +struct concat_impl, cvals_t> +{ + using type = cvals_t; +}; +template +struct concat_impl, ctypes_t> +{ + using type = ctypes_t; +}; + +template +struct concat_impl +{ + using type = typename concat_impl::type, T3, Ts...>::type; +}; + +#ifdef CMT_CPP17_DEFINITIONS +template +struct is_invocable_impl : std::false_type +{ +}; + +template +struct is_invocable_impl, void_t()(std::declval()...))>> + : std::true_type +{ +}; + +template +struct is_invocable_r_impl : std::false_type +{ +}; + +template +struct is_invocable_r_impl, + void_t()(std::declval()...))>> +{ + static constexpr bool value = + std::is_convertible_v()(std::declval()...)), Ret>; +}; +#endif + +} // namespace details +template +using concat_lists = typename details::concat_impl, std::decay_t...>::type; + +template +constexpr CMT_INTRINSIC concat_lists cconcat(T1, Ts...) +{ + return {}; +} + +#ifdef CMT_CPP17_DEFINITIONS +#ifdef __cpp_lib_is_invocable +template +constexpr inline bool is_invocable = std::is_invocable::value; + +template +constexpr inline bool is_invocable_r = std::is_invocable_r::value; +#else +template +constexpr inline bool is_invocable = details::is_invocable_impl>::value; + +template +constexpr inline bool is_invocable_r = details::is_invocable_r_impl>::value; +#endif +#endif + +namespace details +{ + +template +struct function_arguments_impl; + +template +struct function_arguments_impl +{ + using result = Ret; + using args = ctypes_t; +}; + +template +struct function_arguments_impl +{ + using result = Ret; + using args = ctypes_t; +}; + +template +struct function_arguments_impl +{ + using result = Ret; + using args = ctypes_t; +}; + +template +struct filter_impl; + +template +struct filter_impl, cvals_t> +{ + using type = cvals_t; +}; + +template +struct filter_impl, cvals_t> +{ + using filtered = typename filter_impl, cvals_t>::type; + using type = std::conditional_t, filtered>, filtered>; +}; +} // namespace details + +template +using function_arguments = typename details::function_arguments_impl::args; + +template +using function_result = typename details::function_arguments_impl::result; + +template +using cfilter_t = typename details::filter_impl, std::decay_t>::type; + +template , cvals_t>> +constexpr CMT_INTRINSIC Ret cfilter(cvals_t, cvals_t) +{ + return Ret{}; +} + +#define CMT_UN_OP(op) \ + template ()), (op vals1)...>> \ + constexpr CMT_INTRINSIC Ret operator op(cvals_t) \ + { \ + return Ret{}; \ + } \ + template ()), (op val1)>> \ + constexpr CMT_INTRINSIC Ret operator op(cval_t) \ + { \ + return Ret{}; \ + } + +#define CMT_BIN_OP(op) \ + template () op std::declval()), (vals1 op vals2)...>> \ + constexpr CMT_INTRINSIC Ret operator op(cvals_t, cvals_t) \ + { \ + return Ret{}; \ + } \ + template () op std::declval()), (vals1 op val2)...>> \ + constexpr CMT_INTRINSIC Ret operator op(cvals_t, cval_t) \ + { \ + return Ret{}; \ + } \ + template () op std::declval()), (val1 op vals2)...>> \ + constexpr CMT_INTRINSIC Ret operator op(cval_t, cvals_t) \ + { \ + return Ret{}; \ + } + +// clang-format off +CMT_UN_OP(-) +CMT_UN_OP(+) +CMT_UN_OP(~) +CMT_UN_OP(!) + +CMT_BIN_OP(&&) +CMT_BIN_OP(||) +CMT_BIN_OP(==) +CMT_BIN_OP(!=) +CMT_BIN_OP(<) +CMT_BIN_OP(>) +CMT_BIN_OP(<=) +CMT_BIN_OP(>=) +CMT_BIN_OP(+) +CMT_BIN_OP(-) +CMT_BIN_OP(*) +CMT_BIN_OP(/) +CMT_BIN_OP(%) +CMT_BIN_OP(<<) +CMT_BIN_OP(>>) +CMT_BIN_OP(&) +CMT_BIN_OP(|) +CMT_BIN_OP(^) +// clang-format on + +namespace details +{ + +template +struct cvalseq_impl + : concat_impl::type, + typename cvalseq_impl(Nstart + static_cast(Nsize / 2) * Nstep), + Nstep>::type> +{ +}; + +template +struct cvalseq_impl : cvals_t +{ +}; +template +struct cvalseq_impl : cvals_t +{ +}; +template +struct cvalseq_impl : cvals_t(Nstart + Nstep)> +{ +}; + +template +struct cvalseq_impl + : cvals_t(Nstart), static_cast(Nstart + Nstep), + static_cast(Nstart + Nstep + Nstep), static_cast(Nstart + Nstep + Nstep + Nstep)> +{ +}; + +template +struct scale_impl; + +template +struct scale_impl, csizes_t> +{ + constexpr static size_t count1 = sizeof...(Args1); + constexpr static size_t count2 = sizeof...(Args2); + using type = csizes_t<>; +}; + +} // namespace details + +template +using cvalseq_t = typename details::cvalseq_impl::type; + +template +using csizeseq_t = cvalseq_t; + +template +using indicesfor_t = cvalseq_t; + +template +constexpr CMT_INTRINSIC auto scale(csizes_t) CMT_NOEXCEPT +{ + using Tlist = typename details::concat_impl...>::type; + return Tlist{}; +} + +template +constexpr CMT_INTRINSIC auto scale() CMT_NOEXCEPT +{ + using Tlist = typename details::concat_impl...>::type; + return Tlist{}; +} + +namespace details +{ + +template > +struct is_returning_type_impl : std::false_type +{ +}; + +template +struct is_returning_type_impl>> + : std::is_same> +{ +}; + +template > +struct is_callable_impl : std::false_type +{ +}; + +template +struct is_callable_impl, std::void_t>> + : std::true_type +{ +}; + +template > +struct is_enabled_impl : std::true_type +{ +}; + +template +struct is_enabled_impl> : std::integral_constant +{ +}; + +template +struct unique_enum_impl +{ + enum type : int + { + value = N + }; +}; + +#if defined CMT_COMPILER_MSVC && !defined CMT_COMPILER_CLANG +#define CMT_ENABLE_IF_IMPL(N, ...) \ + bool enable_ = (__VA_ARGS__), typename enabled_ = typename ::std::enable_if::type, \ + typename cometa::details::unique_enum_impl::type dummy_ = \ + ::cometa::details::unique_enum_impl::value + +#else +#define CMT_ENABLE_IF_IMPL(N, ...) \ + typename ::std::enable_if<(__VA_ARGS__), typename ::cometa::details::unique_enum_impl::type>::type = \ + ::cometa::details::unique_enum_impl::value + +#endif +#define CMT_ENABLE_IF(...) CMT_ENABLE_IF_IMPL(__LINE__, __VA_ARGS__) +} // namespace details + +template +constexpr inline bool is_enabled = details::is_enabled_impl::value; + +#ifdef CMT_CPP17_DEFINITIONS + +template +constexpr inline bool is_callable = details::is_callable_impl>::value; + +template +constexpr inline bool is_returning_type = details::is_returning_type_impl::value; + +#endif + +namespace details +{ +template )> +CMT_INTRINSIC auto call_if_callable(Fn&& fn) +{ + return fn(); +} + +template )> +CMT_INTRINSIC auto call_if_callable(Fn&& fn) +{ + return std::forward(fn); +} +} // namespace details + +template +CMT_INTRINSIC auto bind_func(Fn&& fn, Args&&... args) +{ + return [=]() CMT_INLINE_LAMBDA { return fn(details::call_if_callable(std::forward(args))...); }; +} + +template +constexpr CMT_INTRINSIC bool is_even(T x) +{ + return (x % 2) == 0; +} + +template +constexpr CMT_INTRINSIC bool is_odd(T x) +{ + return !is_even(x); +} + +template +constexpr CMT_INTRINSIC bool is_poweroftwo(T x) +{ + return ((x != 0) && !(x & (x - 1))); +} + +template +constexpr CMT_INTRINSIC unsigned ilog2(T n, unsigned p = 0) +{ + return (n <= 1) ? p : ilog2(n / 2, p + 1); +} + +/// @brief Returns a nearest power of two that is greater or equal than n +template +constexpr CMT_INTRINSIC T next_poweroftwo(T n) +{ + return n > 2 ? T(1) << (ilog2(n - 1) + 1) : n; +} + +/// @brief Returns a nearest power of two that is less or equal than n +template +constexpr CMT_INTRINSIC T prev_poweroftwo(T n) +{ + return n > 2 ? T(1) << (ilog2(n)) : n; +} + +template +constexpr CMT_INTRINSIC bool is_divisible(T x, T divisor) +{ + return x % divisor == 0; +} + +/// @brief Greatest common divisor +template +constexpr CMT_INTRINSIC T gcd(T a) +{ + return a; +} + +/// @brief Greatest common divisor +template +constexpr inline T gcd(T a, T b) +{ + return a < b ? gcd(b, a) : ((a % b == 0) ? b : gcd(b, a % b)); +} + +/// @brief Greatest common divisor +template +constexpr CMT_INTRINSIC T gcd(T a, T b, T c, Ts... rest) +{ + return gcd(a, gcd(b, c, rest...)); +} + +/// @brief Least common multiple +template +constexpr CMT_INTRINSIC T lcm(T a) +{ + return a; +} + +/// @brief Least common multiple +template +constexpr CMT_INTRINSIC T lcm(T a, T b) +{ + return a * b / gcd(a, b); +} + +/// @brief Least common multiple +template +constexpr CMT_INTRINSIC T lcm(T a, T b, T c, Ts... rest) +{ + return lcm(a, lcm(b, c, rest...)); +} + +CMT_INTRINSIC std::lldiv_t floor_div(long long a, long long b) +{ + std::lldiv_t d = std::lldiv(a, b); + if (d.rem < 0) + { + d.rem += b; + --d.quot; + } + return d; +} + +namespace details +{ + +template +constexpr inline char typekind = std::is_floating_point_v ? 'f' + : std::is_integral_v ? (std::is_unsigned_v ? 'u' : 'i') + : '?'; + +template +struct bits_to_type_impl; + +template <> +struct bits_to_type_impl<'f', 32> +{ + using type = float; + static_assert(sizeof(type) * 8 == 32, "float must represent IEEE single precision value"); +}; +template <> +struct bits_to_type_impl<'f', 64> +{ + using type = double; + static_assert(sizeof(type) * 8 == 64, "double must represent IEEE double precision value"); +}; + +template <> +struct bits_to_type_impl<'i', 8> +{ + using type = std::int8_t; +}; +template <> +struct bits_to_type_impl<'i', 16> +{ + using type = std::int16_t; +}; +template <> +struct bits_to_type_impl<'i', 32> +{ + using type = std::int32_t; +}; +template <> +struct bits_to_type_impl<'i', 64> +{ + using type = std::int64_t; +}; + +template <> +struct bits_to_type_impl<'u', 8> +{ + using type = std::uint8_t; +}; +template <> +struct bits_to_type_impl<'u', 16> +{ + using type = std::uint16_t; +}; +template <> +struct bits_to_type_impl<'u', 32> +{ + using type = std::uint32_t; +}; +template <> +struct bits_to_type_impl<'u', 64> +{ + using type = std::uint64_t; +}; + +template +using bits_to_type = typename bits_to_type_impl::type; + +template +using bytes_to_type = typename bits_to_type_impl::type; + +template +struct findinttype_impl +{ +}; +template +struct findinttype_impl +{ + using type = + std::conditional_t<(std::numeric_limits::min() <= min && std::numeric_limits::max() >= max), T, + typename findinttype_impl::type>; +}; +template +struct findinttype_impl +{ + using type = void; +}; + +template +using is_number_impl = + std::integral_constant::value) || (std::is_floating_point::value)) && + !std::is_same::value>; +} // namespace details + +template +using float_type = typename details::bits_to_type_impl<'f', bits>::type; +template +using int_type = typename details::bits_to_type_impl<'i', bits>::type; +template +using unsigned_type = typename details::bits_to_type_impl<'u', bits>::type; + +template +using findinttype = typename details::findinttype_impl::type; + +template +constexpr inline bool is_number = details::is_number_impl>::value; + +template +constexpr inline bool is_number_or_bool = is_number || std::is_same_v, bool>; + +template +constexpr inline bool is_numbers = (details::is_number_impl>::value && ...); + +/// @brief Check if the type argument is a number or a vector of numbers +template +constexpr inline bool is_numeric = is_number>; + +/// @brief Check if the type arguments are a numbers or a vectors of numbers +template +constexpr inline bool is_numeric_args = (is_numeric && ...); + +/// @brief Check if the type argument is a number, bool or a vector of numbers of bool +template +constexpr inline bool is_numeric_or_bool = is_number_or_bool>; + +namespace details +{ +template +struct identity_impl +{ + using type = T; +}; + +template +constexpr size_t elementsize() +{ + return sizeof(T); +} + +template <> +constexpr size_t elementsize() +{ + return 1; +} +} // namespace details + +/// @brief Utility typedef used to disable type deduction +template +using identity = typename details::identity_impl::type; + +/// @brief Utility class to use in list-initialization context +struct swallow +{ + template + CMT_MEM_INTRINSIC constexpr swallow(T&&...) CMT_NOEXCEPT + { + } +}; + +template +struct carray; + +template +struct carray +{ + CMT_MEM_INTRINSIC constexpr carray() CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC constexpr carray(T val) CMT_NOEXCEPT : val(val) {} + + template >)> + CMT_MEM_INTRINSIC constexpr carray(Fn&& fn, csize_t = csize_t{}) CMT_NOEXCEPT + : val(static_cast(fn(csize_t()))) + { + } + + CMT_MEM_INTRINSIC constexpr carray(const carray&) CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC constexpr carray(carray&&) CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC static constexpr size_t size() CMT_NOEXCEPT { return 1; } + + template + CMT_MEM_INTRINSIC constexpr T& get(csize_t) CMT_NOEXCEPT + { + static_assert(index == 0, "carray: Array index is out of range"); + return val; + } + template + CMT_MEM_INTRINSIC constexpr const T& get(csize_t) const CMT_NOEXCEPT + { + static_assert(index == 0, "carray: Array index is out of range"); + return val; + } + template + CMT_MEM_INTRINSIC constexpr T& get() CMT_NOEXCEPT + { + return get(csize_t()); + } + template + CMT_MEM_INTRINSIC constexpr const T& get() const CMT_NOEXCEPT + { + return get(csize_t()); + } + CMT_MEM_INTRINSIC constexpr const T* front() const CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr T* front() CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr const T* back() const CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr T* back() CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr const T* begin() const CMT_NOEXCEPT { return &val; } + CMT_MEM_INTRINSIC constexpr const T* end() const CMT_NOEXCEPT { return &val + 1; } + CMT_MEM_INTRINSIC constexpr T* begin() CMT_NOEXCEPT { return &val; } + CMT_MEM_INTRINSIC constexpr T* end() CMT_NOEXCEPT { return &val + 1; } + CMT_MEM_INTRINSIC constexpr const T* data() const CMT_NOEXCEPT { return begin(); } + CMT_MEM_INTRINSIC constexpr T* data() CMT_NOEXCEPT { return begin(); } + CMT_MEM_INTRINSIC constexpr bool empty() const CMT_NOEXCEPT { return false; } + T val; +}; + +template +struct carray : carray +{ + template + CMT_MEM_INTRINSIC constexpr carray(T first, Ts... list) CMT_NOEXCEPT : carray(list...), + val(first) + { + static_assert(sizeof...(list) + 1 == N, "carray: Argument count is invalid"); + } + + template + CMT_MEM_INTRINSIC constexpr carray(Fn&& fn, csize_t = csize_t{}) CMT_NOEXCEPT + : carray(std::forward(fn), csize_t()), + val(static_cast(fn(csize_t()))) + { + } + + CMT_MEM_INTRINSIC constexpr carray() CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC constexpr carray(const carray&) CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC constexpr carray(carray&&) CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC static constexpr size_t size() CMT_NOEXCEPT { return N; } + CMT_MEM_INTRINSIC constexpr T& get(csize_t) CMT_NOEXCEPT { return val; } + template + CMT_MEM_INTRINSIC constexpr T& get(csize_t) CMT_NOEXCEPT + { + return carray::get(csize_t()); + } + CMT_MEM_INTRINSIC constexpr const T& get(csize_t) const CMT_NOEXCEPT { return val; } + template + CMT_MEM_INTRINSIC constexpr const T& get(csize_t) const CMT_NOEXCEPT + { + return carray::get(csize_t()); + } + template + CMT_MEM_INTRINSIC constexpr T& get() CMT_NOEXCEPT + { + return get(csize_t()); + } + template + CMT_MEM_INTRINSIC constexpr const T& get() const CMT_NOEXCEPT + { + return get(csize_t()); + } + CMT_MEM_INTRINSIC constexpr const T* front() const CMT_NOEXCEPT { return carray::front(); } + CMT_MEM_INTRINSIC constexpr T* front() CMT_NOEXCEPT { return carray::front(); } + CMT_MEM_INTRINSIC constexpr const T* back() const CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr T* back() CMT_NOEXCEPT { return val; } + CMT_MEM_INTRINSIC constexpr const T* begin() const CMT_NOEXCEPT { return carray::begin(); } + CMT_MEM_INTRINSIC constexpr const T* end() const CMT_NOEXCEPT { return &val + 1; } + CMT_MEM_INTRINSIC constexpr T* begin() CMT_NOEXCEPT { return carray::begin(); } + CMT_MEM_INTRINSIC constexpr T* end() CMT_NOEXCEPT { return &val + 1; } + CMT_MEM_INTRINSIC constexpr const T* data() const CMT_NOEXCEPT { return begin(); } + CMT_MEM_INTRINSIC constexpr T* data() CMT_NOEXCEPT { return begin(); } + CMT_MEM_INTRINSIC constexpr bool empty() const CMT_NOEXCEPT { return false; } + +private: + T val; +}; + +#define CMT_FN(fn) \ + struct fn_##fn \ + { \ + template \ + CMT_INLINE_MEMBER decltype(fn(std::declval()...)) operator()(Args&&... args) const \ + { \ + return fn(std::forward(args)...); \ + } \ + }; + +#define CMT_ESC(...) __VA_ARGS__ + +#define CMT_FN_TPL(tpl_list, tpl_args, fn) \ + template \ + struct fn_##fn \ + { \ + template \ + CMT_INLINE_MEMBER decltype(fn(std::declval()...)) operator()( \ + Args&&... args) const \ + { \ + return fn(std::forward(args)...); \ + } \ + }; + +/// @brief Function that returns its first argument +template +CMT_INTRINSIC constexpr T&& pass_through(T&& x) CMT_NOEXCEPT +{ + return std::forward(x); +} + +/// @brief Function that returns void and ignores all its arguments +template +CMT_INTRINSIC constexpr void noop(Ts&&...) CMT_NOEXCEPT +{ +} + +/// @brief Function that returns its first argument and ignores all other arguments +template +CMT_INTRINSIC constexpr T1&& get_first(T1&& x, Ts&&...) CMT_NOEXCEPT +{ + return std::forward(x); +} + +/// @brief Function that returns its second argument and ignores all other arguments +template +CMT_INTRINSIC constexpr T2&& get_second(T1, T2&& x, Ts&&...) CMT_NOEXCEPT +{ + return std::forward(x); +} + +/// @brief Function that returns its third argument and ignores all other arguments +template +CMT_INTRINSIC constexpr T3&& get_third(T1&&, T2&&, T3&& x, Ts&&...) CMT_NOEXCEPT +{ + return std::forward(x); +} + +/// @brief Function that returns value-initialization of type T and ignores all its arguments +template +CMT_INTRINSIC constexpr T returns(Ts&&...) +{ + return T(); +} + +/// @brief Function that returns constant of type T and ignores all its arguments +template +CMT_INTRINSIC constexpr T return_constant(Args&&...) +{ + return value; +} + +CMT_FN(pass_through) +CMT_FN(noop) +CMT_FN(get_first) +CMT_FN(get_second) +CMT_FN(get_third) +CMT_FN_TPL((typename T), (T), returns) + +template +struct fn_return_constant +{ + template + constexpr T operator()(Args&&...) const noexcept + { + return value; + } +}; + +template +CMT_INTRINSIC constexpr bool is_equal(const T1& x, const T2& y) +{ + return x == y; +} +template +CMT_INTRINSIC constexpr bool is_notequal(const T1& x, const T2& y) +{ + return x != y; +} +template +CMT_INTRINSIC constexpr bool is_less(const T1& x, const T2& y) +{ + return x < y; +} +template +CMT_INTRINSIC constexpr bool is_greater(const T1& x, const T2& y) +{ + return x > y; +} +template +CMT_INTRINSIC constexpr bool is_lessorequal(const T1& x, const T2& y) +{ + return x <= y; +} +template +CMT_INTRINSIC constexpr bool is_greaterorequal(const T1& x, const T2& y) +{ + return x >= y; +} +template +CMT_INTRINSIC constexpr bool is_between(T value, identity min, identity max) +{ + return value >= min && value <= max; +} +CMT_FN(is_equal) +CMT_FN(is_notequal) +CMT_FN(is_less) +CMT_FN(is_greater) +CMT_FN(is_lessorequal) +CMT_FN(is_greaterorequal) +CMT_FN(is_between) + +namespace details +{ +template +struct has_begin_end_impl : std::false_type +{ +}; + +template +struct has_begin_end_impl().begin()), decltype(std::declval().end())>> + : std::true_type +{ +}; + +template +struct has_value_type_impl : std::false_type +{ +}; + +template +struct has_value_type_impl> : std::true_type +{ +}; + +template +struct has_data_size_impl : std::false_type +{ +}; + +template +struct has_data_size_impl().size()), decltype(std::declval().data())>> + : std::true_type +{ +}; + +template +struct has_data_size_free_impl : std::false_type +{ +}; + +template +struct has_data_size_free_impl< + T, std::void_t())), decltype(std::data(std::declval()))>> + : std::true_type +{ +}; + +template +struct value_type_impl +{ + using type = Fallback; +}; + +template +struct value_type_impl> +{ + using type = typename T::value_type; +}; +} // namespace details + +template +constexpr inline bool has_begin_end = details::has_begin_end_impl>::value; + +template +constexpr inline bool has_data_size = details::has_data_size_impl>::value; + +#define CMT_HAS_DATA_SIZE(CONTAINER) \ + std::enable_if_t::value>* = nullptr + +template +using value_type_of = typename std::decay_t::value_type; + +#ifndef CMT_COMPILER_CLANG +namespace details +{ +template +void cforeach_impl(Fn&& fn) +{ + fn(cval_t()); +} +} // namespace details +#endif + +template +CMT_INTRINSIC void cforeach(cvals_t, Fn&& fn) +{ +#ifdef CMT_COMPILER_CLANG + swallow{ (fn(cval_t()), void(), 0)... }; +#else + swallow{ (details::cforeach_impl(std::forward(fn)), void(), 0)... }; +#endif +} + +template )> +CMT_INTRINSIC void cforeach(T&& list, Fn&& fn) +{ + for (const auto& v : list) + { + fn(v); + } +} + +template +CMT_INTRINSIC void cforeach(const T (&array)[N], Fn&& fn) +{ + for (size_t i = 0; i < N; i++) + { + fn(array[i]); + } +} + +namespace details +{ + +template +CMT_INTRINSIC auto get_type_arg(ctypes_t) +{ + return ctype_t::type>(); +} + +template +CMT_INTRINSIC void cforeach_types_impl(ctypes_t type_list, Fn&& fn, csizes_t) +{ + swallow{ (fn(get_type_arg(type_list)), void(), 0)... }; +} +template +CMT_INTRINSIC void cforeach_types_impl(ctypes_t<>, Fn&&, csizes_t<>) +{ +} +} // namespace details + +template +CMT_INTRINSIC void cforeach(ctypes_t types, Fn&& fn) +{ + details::cforeach_types_impl(types, std::forward(fn), csizeseq_t()); +} + +template +CMT_INTRINSIC void cforeach(A0&& a0, A1&& a1, Fn&& fn) +{ + // Default capture causes ICE in Intel C++ + cforeach(std::forward(a0), // + [&a1, &fn](auto v0) { // + cforeach(std::forward(a1), // + [&v0, &fn](auto v1) { fn(v0, v1); }); + }); +} + +template +CMT_INTRINSIC void cforeach(A0&& a0, A1&& a1, A2&& a2, Fn&& fn) +{ + // Default capture causes ICE in Intel C++ + cforeach(std::forward(a0), // + [&a1, &a2, &fn](auto v0) { // + cforeach(std::forward(a1), // + [&v0, &a2, &fn](auto v1) { // + cforeach(std::forward(a2), // + [&v0, &v1, &fn](auto v2) { // + fn(v0, v1, v2); + }); + }); + }); +} + +template +CMT_INTRINSIC void cforeach(A0&& a0, A1&& a1, A2&& a2, A3&& a3, Fn&& fn) +{ + // Default capture causes ICE in Intel C++ + cforeach(std::forward(a0), // + [&a1, &a2, &a3, &fn](auto v0) { // + cforeach(std::forward(a1), // + [&v0, &a2, &a3, &fn](auto v1) { // + cforeach(std::forward(a2), // + [&v0, &v1, &a3, &fn](auto v2) { // + cforeach(std::forward(a3), // + [&v0, &v1, &v2, &fn](auto v3) // + { fn(v0, v1, v2, v3); }); + }); + }); + }); +} + +template +CMT_INTRINSIC decltype(auto) cif(cbool_t, TrueFn&& truefn, FalseFn&& = FalseFn()) +{ + return truefn(ctrue); +} + +template +CMT_INTRINSIC decltype(auto) cif(cbool_t, TrueFn&&, FalseFn&& falsefn = FalseFn()) +{ + return falsefn(cfalse); +} + +template +CMT_INTRINSIC decltype(auto) cfor(cval_t, cval_t, BodyFn&& bodyfn) +{ + return cforeach(cvalseq_t(), std::forward(bodyfn)); +} + +template +CMT_INTRINSIC void cswitch(cvals_t, const U& value, Function&& function, + Fallback&& fallback = Fallback()) +{ + bool result = false; + swallow{ (result = result || ((vs == value) ? (function(cval_t()), void(), true) : false), void(), + 0)... }; + if (!result) + fallback(); +} + +template +CMT_INTRINSIC decltype(auto) cswitch(cvals_t, identity, Fn&&, DefFn&& deffn = DefFn(), + CmpFn&& = CmpFn()) +{ + return deffn(); +} + +template +CMT_INTRINSIC decltype(auto) cswitch(cvals_t, identity value, Fn&& fn, + DefFn&& deffn = DefFn(), CmpFn&& cmpfn = CmpFn()) +{ + if (cmpfn(value, v0)) + { + return fn(cval_t()); + } + else + { + return cswitch(cvals_t(), value, std::forward(fn), std::forward(deffn), + std::forward(cmpfn)); + } +} + +namespace details +{ +template +CMT_INTRINSIC decltype(auto) cmatch_impl(T&& value, Fn1&& first, Fn2&& second, Fns&&... rest); +template +CMT_INTRINSIC decltype(auto) cmatch_impl(T&& value, Fn&& last); + +template +CMT_INTRINSIC decltype(auto) cmatch_impl2(cbool_t, T&& value, Fn&& fn, Fns&&...) +{ + return fn(std::forward(value)); +} + +template +CMT_INTRINSIC decltype(auto) cmatch_impl2(cbool_t, T&& value, Fn&&, Fns&&... rest) +{ + return cmatch_impl(std::forward(value), std::forward(rest)...); +} + +template +CMT_INTRINSIC decltype(auto) cmatch_impl(T&& value, Fn1&& first, Fn2&& second, Fns&&... rest) +{ + using first_arg = typename function_arguments::template nth<0>; + constexpr bool is_same = std::is_same_v, std::decay_t>; + return cmatch_impl2(cbool_t(), std::forward(value), std::forward(first), + std::forward(second), std::forward(rest)...); +} + +template +CMT_INTRINSIC decltype(auto) cmatch_impl(T&& value, Fn&& last) +{ + return last(std::forward(value)); +} +} // namespace details + +template +CMT_INTRINSIC decltype(auto) cmatch(T&& value, Fn&& fn, Args... args) +{ + return details::cmatch_impl(std::forward(value), std::forward(fn), std::forward(args)...); +} + +template +CMT_INTRINSIC size_t cfind(cvals_t, identity value) +{ + static constexpr T temp[] = { values... }; + static constexpr size_t size = sizeof...(values); + for (size_t i = 0; i < size; i++) + { + if (temp[i] == value) + return i; + } + return size_t(-1); +} + +template +CMT_UNUSED CMT_NOINLINE static std::invoke_result_t noinline(Fn&& fn, Args&&... args) +{ + return fn(std::forward(args)...); +} + +template +struct fn_noinline +{ + template + CMT_MEM_INTRINSIC std::invoke_result_t operator()(Args&&... args) const + { + return noinline(Fn{}, std::forward(args)...); + } +}; // namespace cometa + +template ()(std::declval()...)), + typename NonMemFn = Ret (*)(Fn*, Args...)> +CMT_INTRINSIC NonMemFn make_nonmember(const Fn&) +{ + return [](Fn* fn, Args... args) -> Ret { return fn->operator()(std::forward(args)...); }; +} + +template +constexpr CMT_INTRINSIC T choose_const() +{ + static_assert(sizeof(T) != 0, "T not found in the list of template arguments"); + return T(); +} +template +constexpr CMT_INTRINSIC T choose_const_fallback(C1 c1) +{ + return static_cast(c1); +} + +/** + * Selects constant of the specific type + * @code + * CHECK( choose_const( 32.0f, 64.0 ) == 32.0f ); + * CHECK( choose_const( 32.0f, 64.0 ) == 64.0 ); + * @endcode + */ +template )> +constexpr CMT_INTRINSIC T choose_const(C1 c1, Cs...) +{ + return static_cast(c1); +} +template )> +constexpr CMT_INTRINSIC T choose_const(C1, Cs... constants) +{ + return choose_const(constants...); +} + +template +constexpr CMT_INTRINSIC T choose_const_fallback(C1 c1, Cs... constants) +{ + return std::is_same_v ? static_cast(c1) : choose_const_fallback(constants...); +} + +template +struct autocast_impl +{ + const Tfrom value; + template + CMT_MEM_INTRINSIC constexpr operator T() const CMT_NOEXCEPT + { + return static_cast(value); + } +}; + +template +CMT_INTRINSIC constexpr autocast_impl autocast(const Tfrom& value) CMT_NOEXCEPT +{ + return { value }; +} + +inline void stop_constexpr() {} + +namespace details +{ +template +struct signed_type_impl +{ + using type = T; +}; +template +struct signed_type_impl>>> +{ + using type = findinttype::min(), std::numeric_limits::max()>; +}; +} // namespace details + +template +using signed_type = typename details::signed_type_impl::type; + +template +constexpr CMT_INTRINSIC T align_down(T x, identity alignment) +{ + return (x) & ~(alignment - 1); +} +template +constexpr CMT_INTRINSIC T* align_down(T* x, size_t alignment) +{ + return reinterpret_cast(align_down(reinterpret_cast(x), alignment)); +} + +template +constexpr CMT_INTRINSIC T align_up(T x, identity alignment) +{ + return (x + alignment - 1) & ~(alignment - 1); +} +template +constexpr CMT_INTRINSIC T* align_up(T* x, size_t alignment) +{ + return reinterpret_cast(align_up(reinterpret_cast(x), alignment)); +} + +template +constexpr CMT_INTRINSIC T* advance(T* x, ptrdiff_t offset) +{ + return x + offset; +} +constexpr CMT_INTRINSIC void* advance(void* x, ptrdiff_t offset) +{ + return advance(static_cast(x), offset); +} + +constexpr CMT_INTRINSIC ptrdiff_t distance(const void* x, const void* y) +{ + return static_cast(x) - static_cast(y); +} + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Wundefined-reinterpret-cast") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wundefined-reinterpret-cast") +#endif + +template +CMT_INTRINSIC constexpr static T& ref_cast(U& ptr) +{ + return reinterpret_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static const T& ref_cast(const U& ptr) +{ + return reinterpret_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static T* ptr_cast(U* ptr) +{ + return reinterpret_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static const T* ptr_cast(const U* ptr) +{ + return reinterpret_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static T* ptr_cast(U* ptr, ptrdiff_t offset) +{ + return ptr_cast(ptr_cast(ptr) + offset); +} + +template +CMT_INTRINSIC constexpr static T* derived_cast(U* ptr) +{ + return static_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static const T* derived_cast(const U* ptr) +{ + return static_cast(ptr); +} + +template +CMT_INTRINSIC constexpr static T implicit_cast(U&& value) +{ + return std::forward(value); +} + +namespace details +{ +template +constexpr CMT_INTRINSIC std::true_type test_sequence(csizeseq_t) +{ + return {}; +} + +template +constexpr CMT_INTRINSIC std::false_type test_sequence(...) +{ + return {}; +} +} // namespace details + +template +constexpr CMT_INTRINSIC bool is_sequence(csizes_t) +{ + return details::test_sequence(csizes_t()).value; +} + +template +constexpr cval_t cval{}; + +template +constexpr cbool_t cbool{}; + +template +constexpr cint_t cint{}; + +template +constexpr cuint_t cuint{}; + +template +constexpr csize_t csize{}; + +template +constexpr cvals_t cvals{}; + +template +constexpr cbools_t cbools{}; + +template +constexpr cints_t cints{}; + +template +constexpr cchars_t cchars{}; + +template +constexpr cuints_t cuints{}; + +template +constexpr csizes_t csizes{}; + +template +constexpr elements_t elements{}; + +template +constexpr ctype_t ctype{}; + +template +constexpr ctypes_t ctypes{}; + +template +constexpr cvalseq_t cvalrange{}; + +template +constexpr cvalseq_t csizerange{}; + +template +constexpr cvalseq_t cintrange{}; + +template +constexpr cvalseq_t cuintrange{}; + +template +constexpr cvalseq_t cvalseq{}; + +template +constexpr cvalseq_t csizeseq{}; + +template +constexpr cvalseq_t cintseq{}; + +template +constexpr cvalseq_t cuintseq{}; +template +constexpr indicesfor_t indicesfor{}; + +template +constexpr CMT_INTRINSIC T const_max(T x) +{ + return x; +} +template +constexpr CMT_INTRINSIC std::common_type_t const_max(T1 x, T2 y, Ts... z) +{ + auto yz = const_max(y, z...); + return x > yz ? x : yz; +} + +template +constexpr CMT_INTRINSIC T const_min(T x) +{ + return x; +} +template +constexpr CMT_INTRINSIC std::common_type_t const_min(T1 x, T2 y, Ts... z) +{ + auto yz = const_min(y, z...); + return x < yz ? x : yz; +} + +template +constexpr CMT_INTRINSIC T cminof(cvals_t) +{ + return std::numeric_limits::max(); +} +template +constexpr CMT_INTRINSIC T cminof(cvals_t) +{ + T m = cminof(cvals); + return val < m ? val : m; +} +template +constexpr CMT_INTRINSIC T cmaxof(cvals_t) +{ + return std::numeric_limits::min(); +} +template +constexpr CMT_INTRINSIC T cmaxof(cvals_t) +{ + T m = cmaxof(cvals); + return val > m ? val : m; +} + +template +struct overload_priority : overload_priority +{ +}; + +template <> +struct overload_priority<0> +{ +}; + +constexpr overload_priority<> overload_auto{}; + +using overload_generic = overload_priority<0>; + +#define CMT_GEN_LIST1(m, ...) m(0, __VA_ARGS__) +#define CMT_GEN_LIST2(m, ...) CMT_GEN_LIST1(m, __VA_ARGS__), m(1, __VA_ARGS__) +#define CMT_GEN_LIST3(m, ...) CMT_GEN_LIST2(m, __VA_ARGS__), m(2, __VA_ARGS__) +#define CMT_GEN_LIST4(m, ...) CMT_GEN_LIST3(m, __VA_ARGS__), m(3, __VA_ARGS__) +#define CMT_GEN_LIST5(m, ...) CMT_GEN_LIST4(m, __VA_ARGS__), m(4, __VA_ARGS__) +#define CMT_GEN_LIST6(m, ...) CMT_GEN_LIST5(m, __VA_ARGS__), m(5, __VA_ARGS__) +#define CMT_GEN_LIST7(m, ...) CMT_GEN_LIST6(m, __VA_ARGS__), m(6, __VA_ARGS__) +#define CMT_GEN_LIST8(m, ...) CMT_GEN_LIST7(m, __VA_ARGS__), m(7, __VA_ARGS__) +#define CMT_GEN_LIST9(m, ...) CMT_GEN_LIST8(m, __VA_ARGS__), m(8, __VA_ARGS__) +#define CMT_GEN_LIST10(m, ...) CMT_GEN_LIST9(m, __VA_ARGS__), m(9, __VA_ARGS__) + +#define CMT_GEN_LIST11(m, ...) CMT_GEN_LIST10(m, __VA_ARGS__), m(10, __VA_ARGS__) +#define CMT_GEN_LIST12(m, ...) CMT_GEN_LIST11(m, __VA_ARGS__), m(11, __VA_ARGS__) +#define CMT_GEN_LIST13(m, ...) CMT_GEN_LIST12(m, __VA_ARGS__), m(12, __VA_ARGS__) +#define CMT_GEN_LIST14(m, ...) CMT_GEN_LIST13(m, __VA_ARGS__), m(13, __VA_ARGS__) +#define CMT_GEN_LIST15(m, ...) CMT_GEN_LIST14(m, __VA_ARGS__), m(14, __VA_ARGS__) +#define CMT_GEN_LIST16(m, ...) CMT_GEN_LIST15(m, __VA_ARGS__), m(15, __VA_ARGS__) +#define CMT_GEN_LIST17(m, ...) CMT_GEN_LIST16(m, __VA_ARGS__), m(16, __VA_ARGS__) +#define CMT_GEN_LIST18(m, ...) CMT_GEN_LIST17(m, __VA_ARGS__), m(17, __VA_ARGS__) +#define CMT_GEN_LIST19(m, ...) CMT_GEN_LIST18(m, __VA_ARGS__), m(18, __VA_ARGS__) +#define CMT_GEN_LIST20(m, ...) CMT_GEN_LIST19(m, __VA_ARGS__), m(19, __VA_ARGS__) + +#define CMT_GEN_LIST21(m, ...) CMT_GEN_LIST20(m, __VA_ARGS__), m(20, __VA_ARGS__) +#define CMT_GEN_LIST22(m, ...) CMT_GEN_LIST21(m, __VA_ARGS__), m(21, __VA_ARGS__) +#define CMT_GEN_LIST23(m, ...) CMT_GEN_LIST22(m, __VA_ARGS__), m(22, __VA_ARGS__) +#define CMT_GEN_LIST24(m, ...) CMT_GEN_LIST23(m, __VA_ARGS__), m(23, __VA_ARGS__) +#define CMT_GEN_LIST25(m, ...) CMT_GEN_LIST24(m, __VA_ARGS__), m(24, __VA_ARGS__) +#define CMT_GEN_LIST26(m, ...) CMT_GEN_LIST25(m, __VA_ARGS__), m(25, __VA_ARGS__) +#define CMT_GEN_LIST27(m, ...) CMT_GEN_LIST26(m, __VA_ARGS__), m(26, __VA_ARGS__) +#define CMT_GEN_LIST28(m, ...) CMT_GEN_LIST27(m, __VA_ARGS__), m(27, __VA_ARGS__) +#define CMT_GEN_LIST29(m, ...) CMT_GEN_LIST28(m, __VA_ARGS__), m(28, __VA_ARGS__) +#define CMT_GEN_LIST30(m, ...) CMT_GEN_LIST29(m, __VA_ARGS__), m(29, __VA_ARGS__) + +#define CMT_GEN_LIST31(m, ...) CMT_GEN_LIST30(m, __VA_ARGS__), m(30, __VA_ARGS__) +#define CMT_GEN_LIST32(m, ...) CMT_GEN_LIST31(m, __VA_ARGS__), m(31, __VA_ARGS__) +#define CMT_GEN_LIST33(m, ...) CMT_GEN_LIST32(m, __VA_ARGS__), m(32, __VA_ARGS__) +#define CMT_GEN_LIST34(m, ...) CMT_GEN_LIST33(m, __VA_ARGS__), m(33, __VA_ARGS__) +#define CMT_GEN_LIST35(m, ...) CMT_GEN_LIST34(m, __VA_ARGS__), m(34, __VA_ARGS__) +#define CMT_GEN_LIST36(m, ...) CMT_GEN_LIST35(m, __VA_ARGS__), m(35, __VA_ARGS__) +#define CMT_GEN_LIST37(m, ...) CMT_GEN_LIST36(m, __VA_ARGS__), m(36, __VA_ARGS__) +#define CMT_GEN_LIST38(m, ...) CMT_GEN_LIST37(m, __VA_ARGS__), m(37, __VA_ARGS__) +#define CMT_GEN_LIST39(m, ...) CMT_GEN_LIST38(m, __VA_ARGS__), m(38, __VA_ARGS__) +#define CMT_GEN_LIST40(m, ...) CMT_GEN_LIST39(m, __VA_ARGS__), m(39, __VA_ARGS__) + +#define CMT_GEN_LIST41(m, ...) CMT_GEN_LIST40(m, __VA_ARGS__), m(40, __VA_ARGS__) +#define CMT_GEN_LIST42(m, ...) CMT_GEN_LIST41(m, __VA_ARGS__), m(41, __VA_ARGS__) +#define CMT_GEN_LIST43(m, ...) CMT_GEN_LIST42(m, __VA_ARGS__), m(42, __VA_ARGS__) +#define CMT_GEN_LIST44(m, ...) CMT_GEN_LIST43(m, __VA_ARGS__), m(43, __VA_ARGS__) +#define CMT_GEN_LIST45(m, ...) CMT_GEN_LIST44(m, __VA_ARGS__), m(44, __VA_ARGS__) +#define CMT_GEN_LIST46(m, ...) CMT_GEN_LIST45(m, __VA_ARGS__), m(45, __VA_ARGS__) +#define CMT_GEN_LIST47(m, ...) CMT_GEN_LIST46(m, __VA_ARGS__), m(46, __VA_ARGS__) +#define CMT_GEN_LIST48(m, ...) CMT_GEN_LIST47(m, __VA_ARGS__), m(47, __VA_ARGS__) +#define CMT_GEN_LIST49(m, ...) CMT_GEN_LIST48(m, __VA_ARGS__), m(48, __VA_ARGS__) +#define CMT_GEN_LIST50(m, ...) CMT_GEN_LIST49(m, __VA_ARGS__), m(49, __VA_ARGS__) + +#define CMT_GEN_LIST51(m, ...) CMT_GEN_LIST50(m, __VA_ARGS__), m(50, __VA_ARGS__) +#define CMT_GEN_LIST52(m, ...) CMT_GEN_LIST51(m, __VA_ARGS__), m(51, __VA_ARGS__) +#define CMT_GEN_LIST53(m, ...) CMT_GEN_LIST52(m, __VA_ARGS__), m(52, __VA_ARGS__) +#define CMT_GEN_LIST54(m, ...) CMT_GEN_LIST53(m, __VA_ARGS__), m(53, __VA_ARGS__) +#define CMT_GEN_LIST55(m, ...) CMT_GEN_LIST54(m, __VA_ARGS__), m(54, __VA_ARGS__) +#define CMT_GEN_LIST56(m, ...) CMT_GEN_LIST55(m, __VA_ARGS__), m(55, __VA_ARGS__) +#define CMT_GEN_LIST57(m, ...) CMT_GEN_LIST56(m, __VA_ARGS__), m(56, __VA_ARGS__) +#define CMT_GEN_LIST58(m, ...) CMT_GEN_LIST57(m, __VA_ARGS__), m(57, __VA_ARGS__) +#define CMT_GEN_LIST59(m, ...) CMT_GEN_LIST58(m, __VA_ARGS__), m(58, __VA_ARGS__) +#define CMT_GEN_LIST60(m, ...) CMT_GEN_LIST59(m, __VA_ARGS__), m(59, __VA_ARGS__) + +#define CMT_GEN_LIST61(m, ...) CMT_GEN_LIST60(m, __VA_ARGS__), m(60, __VA_ARGS__) +#define CMT_GEN_LIST62(m, ...) CMT_GEN_LIST61(m, __VA_ARGS__), m(61, __VA_ARGS__) +#define CMT_GEN_LIST63(m, ...) CMT_GEN_LIST62(m, __VA_ARGS__), m(62, __VA_ARGS__) +#define CMT_GEN_LIST64(m, ...) CMT_GEN_LIST63(m, __VA_ARGS__), m(63, __VA_ARGS__) +#define CMT_GEN_LIST65(m, ...) CMT_GEN_LIST64(m, __VA_ARGS__), m(64, __VA_ARGS__) +#define CMT_GEN_LIST66(m, ...) CMT_GEN_LIST65(m, __VA_ARGS__), m(65, __VA_ARGS__) +#define CMT_GEN_LIST67(m, ...) CMT_GEN_LIST66(m, __VA_ARGS__), m(66, __VA_ARGS__) +#define CMT_GEN_LIST68(m, ...) CMT_GEN_LIST67(m, __VA_ARGS__), m(67, __VA_ARGS__) +#define CMT_GEN_LIST69(m, ...) CMT_GEN_LIST68(m, __VA_ARGS__), m(68, __VA_ARGS__) +#define CMT_GEN_LIST70(m, ...) CMT_GEN_LIST69(m, __VA_ARGS__), m(69, __VA_ARGS__) + +#define CMT_GEN_LIST(c, m, ...) CMT_GEN_LIST##c(m, __VA_ARGS__) + +template +CMT_INTRINSIC Tout bitcast_anything(const Tin& in) +{ + static_assert(sizeof(Tin) == sizeof(Tout), "Invalid arguments for bitcast_anything"); +#if defined CMT_COMPILER_INTEL + const union + { + const Tin in; + Tout out; + } u{ in }; + return u.out; +#else + union + { + Tin in; + Tout out; + } u{ in }; + return u.out; +#endif +} + +template +CMT_INTRINSIC constexpr T dont_deduce(T x) +{ + return x; +} + +template +CMT_INTRINSIC constexpr T just_value(T value) +{ + return value; +} + +template +CMT_INTRINSIC constexpr Tout pack_elements() +{ + return 0; +} + +template +CMT_INTRINSIC constexpr Tout pack_elements(Arg x, Args... args) +{ + return static_cast::type>(x) | + (pack_elements(args...) << (sizeof(Arg) * 8)); +} + +template +using value_or_ref = std::conditional_t; + +enum class special_constant +{ + default_constructed, + infinity, + neg_infinity, + min, + max, + neg_max, + lowest, + epsilon, + integer, + floating_point, + random_bits, +}; + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4700)) +CMT_PRAGMA_MSVC(warning(disable : 4146)) +struct special_value +{ + constexpr special_value(const special_value&) = default; + constexpr special_value(special_constant c) : c(c), ll(0), d(0) {} + constexpr special_value(double d) : c(special_constant::floating_point), ll(0), d(d) {} + constexpr special_value(long long ll) : c(special_constant::integer), ll(ll), d(0) {} + constexpr special_value(int i) : c(special_constant::integer), ll(i), d(0) {} + + template + constexpr T get() const CMT_NOEXCEPT + { + switch (c) + { + case special_constant::default_constructed: + return T{}; + case special_constant::infinity: + return std::numeric_limits>::infinity(); + case special_constant::neg_infinity: + { + subtype gg = std::numeric_limits>::infinity(); + return -gg; + } + case special_constant::min: + return std::numeric_limits>::min(); + case special_constant::max: + return std::numeric_limits>::max(); + case special_constant::neg_max: + return static_cast(-std::numeric_limits>::max()); + case special_constant::lowest: + return std::numeric_limits>::lowest(); + case special_constant::integer: + return static_cast(ll); + case special_constant::floating_point: + return static_cast(d); + case special_constant::random_bits: + return random_bits(); + case special_constant::epsilon: + return std::numeric_limits>::epsilon(); + // default: + // return T{}; + } + return T(); + } + + template + constexpr operator T() const CMT_NOEXCEPT + { + return get(); + } + special_constant c; + long long ll; + double d; + + static std::mt19937& random_generator() + { + static std::mt19937 rnd(1); + return rnd; + } + + template + static T random_bits() + { + union + { + uint32_t bits[(sizeof(T) + sizeof(uint32_t) - 1) / sizeof(uint32_t)]; + T value; + } u; + for (uint32_t& b : u.bits) + { + b = random_generator()(); + } + return u.value; + } +}; +CMT_PRAGMA_MSVC(warning(pop)) + +CMT_PRAGMA_GNU(GCC diagnostic pop) +} // namespace cometa + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/array.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/array.hpp new file mode 100644 index 00000000..508c627f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/array.hpp @@ -0,0 +1,77 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" +#include +#include +#include + +namespace cometa +{ + +template +using container_value_type = std::remove_pointer_t()))>; + +/// @brief Reference to array +template +struct array_ref +{ +public: + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + constexpr array_ref() CMT_NOEXCEPT : m_data(nullptr), m_size(0) {} + constexpr array_ref(const array_ref&) CMT_NOEXCEPT = default; + constexpr array_ref(array_ref&&) CMT_NOEXCEPT = default; + constexpr array_ref& operator=(const array_ref&) CMT_NOEXCEPT = default; + constexpr array_ref& operator=(array_ref&&) CMT_NOEXCEPT = default; + + template + array_ref(Container&& cont) : array_ref(std::data(cont), std::size(cont)) + { + } + + constexpr array_ref(std::initializer_list vec) CMT_NOEXCEPT : m_data(vec.begin()), m_size(vec.size()) + { + } + constexpr array_ref(T* data, size_type size) CMT_NOEXCEPT : m_data(data), m_size(size) {} + + constexpr reference front() const CMT_NOEXCEPT { return m_data[0]; } + constexpr reference back() const CMT_NOEXCEPT { return m_data[m_size - 1]; } + constexpr iterator begin() const CMT_NOEXCEPT { return m_data; } + constexpr iterator end() const CMT_NOEXCEPT { return m_data + m_size; } + constexpr const_iterator cbegin() const CMT_NOEXCEPT { return m_data; } + constexpr const_iterator cend() const CMT_NOEXCEPT { return m_data + m_size; } + constexpr pointer data() const CMT_NOEXCEPT { return m_data; } + constexpr std::size_t size() const CMT_NOEXCEPT { return m_size; } + constexpr bool empty() const CMT_NOEXCEPT { return !m_size; } + constexpr reference operator[](std::size_t index) const { return m_data[index]; } + +private: + pointer m_data; + size_type m_size; +}; + +template +inline array_ref make_array_ref(T* data, std::size_t size) +{ + return array_ref(data, size); +} + +template > +inline array_ref make_array_ref(Container&& cont) +{ + return array_ref(std::data(cont), std::size(cont)); +} +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/cstring.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/cstring.hpp new file mode 100644 index 00000000..3e25000c --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/cstring.hpp @@ -0,0 +1,166 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" +#include +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4100)) + +namespace cometa +{ + +namespace details +{ +constexpr inline size_t strlen(const char* str) { return *str ? 1 + cometa::details::strlen(str + 1) : 0; } +} // namespace details + +template +struct cstring +{ + using value_type = char; + using size_type = size_t; + + constexpr const value_type* c_str() const CMT_NOEXCEPT { return value; } + constexpr const value_type* data() const CMT_NOEXCEPT { return value; } + + const value_type value[N]; + constexpr size_type length() const CMT_NOEXCEPT { return N - 1; } + constexpr size_type size() const CMT_NOEXCEPT { return N; } + + template + constexpr cstring slice(csize_t, csize_t) const CMT_NOEXCEPT + { + return slice_impl(csizeseq); + } + + template + constexpr cstring slice(csize_t) const CMT_NOEXCEPT + { + return slice_impl(csizeseq); + } + + constexpr friend bool operator==(const cstring& left, const cstring& right) CMT_NOEXCEPT + { + for (size_t i = 0; i < 1; i++) + if (left.value[i] != right.value[i]) + return false; + return true; + } + constexpr friend bool operator!=(const cstring& left, const cstring& right) CMT_NOEXCEPT + { + return !(left == right); + } + + template + constexpr bool operator==(const cstring&) const CMT_NOEXCEPT + { + return false; + } + template + constexpr bool operator!=(const cstring&) const CMT_NOEXCEPT + { + return true; + } + constexpr char operator[](size_t index) const CMT_NOEXCEPT { return value[index]; } + +private: + template + constexpr cstring slice_impl(csizes_t) const + { + return { { value[indices]..., 0 } }; + } +}; + +namespace details +{ + +template +CMT_INLINE constexpr cstring make_cstring_impl(const char (&str)[N], csizes_t) +{ + return { { str[indices]..., 0 } }; +} + +template +CMT_INLINE constexpr cstring concat_str_impl(const cstring& str1, + const cstring& str2, + csizes_t) +{ + return { { (indices < (N1 - 1) ? str1[indices] : str2[indices - (N1 - 1)])..., 0 } }; +} +template +CMT_INLINE constexpr cstring concat_str_impl(const cstring& str1, + const cstring& str2) +{ + return concat_str_impl(str1, str2, cvalseq_t()); +} +template +CMT_INTRINSIC cstring str_replace_impl(size_t pos, const cstring& str, + const cstring&, const cstring& to, + csizes_t) +{ + if (pos == size_t(-1)) + stop_constexpr(); + return { { (indices < pos ? str[indices] + : (indices < pos + Nto - 1) ? to[indices - pos] + : str[indices - Nto + Nfrom])..., + 0 } }; +} +} // namespace details + +CMT_INTRINSIC constexpr cstring<1> concat_cstring() { return { { 0 } }; } + +template +CMT_INTRINSIC constexpr cstring concat_cstring(const cstring& str1) +{ + return str1; +} + +template +CMT_INTRINSIC constexpr auto concat_cstring(const cstring& str1, const cstring& str2, + const Args&... args) +{ + return details::concat_str_impl(str1, concat_cstring(str2, args...)); +} + +template +CMT_INTRINSIC constexpr cstring make_cstring(const char (&str)[N]) +{ + return details::make_cstring_impl(str, cvalseq_t()); +} + +template +CMT_INTRINSIC constexpr cstring make_cstring(cchars_t) +{ + return { { chars..., 0 } }; +} + +template +CMT_INTRINSIC size_t str_find(const cstring& str, const cstring& needle) +{ + size_t count = 0; + for (size_t i = 0; i < N1; i++) + { + if (str[i] == needle[count]) + count++; + else + count = 0; + if (count == Nneedle - 1) + return i + 1 - (Nneedle - 1); + } + return size_t(-1); +} + +template +CMT_INTRINSIC cstring str_replace(const cstring& str, const cstring& from, + const cstring& to) +{ + return details::str_replace_impl(str_find(str, from), str, from, to, + cvalseq_t()); +} +} // namespace cometa + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/ctti.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/ctti.hpp new file mode 100644 index 00000000..6828755c --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/ctti.hpp @@ -0,0 +1,121 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" +#include "cstring.hpp" + +namespace cometa +{ +using pconstvoid = const void*; + +struct type_id_t +{ + constexpr type_id_t(const void* id) CMT_NOEXCEPT : id(id) {} + constexpr bool operator==(type_id_t other) const { return id == other.id; } + constexpr bool operator!=(type_id_t other) const { return !(id == other.id); } + const void* const id; +}; + +namespace details +{ + +template +constexpr inline type_id_t typeident_impl() CMT_NOEXCEPT +{ + return type_id_t(pconstvoid(&typeident_impl)); +} + +#if defined CMT_COMPILER_CLANG && CMT_COMPILER_MSVC +constexpr size_t typename_prefix = sizeof("auto __cdecl cometa::ctype_name(void) [T = ") - 1; +constexpr size_t typename_postfix = sizeof("]") - 1; +#elif defined CMT_COMPILER_CLANG +constexpr size_t typename_prefix = sizeof("auto cometa::ctype_name() [T = ") - 1; +constexpr size_t typename_postfix = sizeof("]") - 1; +#elif defined CMT_COMPILER_MSVC +constexpr size_t typename_prefix = sizeof("auto __cdecl cometa::ctype_name<") - 1; +constexpr size_t typename_postfix = sizeof(">(void) noexcept") - 1; +#else // GCC +constexpr size_t typename_prefix = sizeof("constexpr auto cometa::ctype_name() [with T = ") - 1; +constexpr size_t typename_postfix = sizeof("]") - 1; +#endif + +template +constexpr cstring gettypename_impl(const char* str, csizes_t) CMT_NOEXCEPT +{ + return cstring{ { (str[indices])..., 0 } }; +} +template +constexpr cstring<1> gettypename_impl(const char*, csizes_t<>) CMT_NOEXCEPT +{ + return cstring<1>{ { 0 } }; +} +} // namespace details + +#ifdef CMT_COMPILER_MSVC +#define KFR_CALL_CONV_SPEC __cdecl +#else +#define KFR_CALL_CONV_SPEC +#endif + +template +constexpr auto KFR_CALL_CONV_SPEC ctype_name() noexcept +{ + constexpr size_t length = + sizeof(CMT_FUNC_SIGNATURE) - 1 > details::typename_prefix + details::typename_postfix + ? sizeof(CMT_FUNC_SIGNATURE) - 1 - details::typename_prefix - details::typename_postfix + : 0; + static_assert(length > 0, ""); + return details::gettypename_impl(CMT_FUNC_SIGNATURE + (length > 0 ? details::typename_prefix : 0), + csizeseq); +} + +/** + * @brief Gets the fully qualified name of the type, including namespace and + * template parameters (if any) + * @tparam T type + * @return name of the type + */ +template +inline const char* type_name() CMT_NOEXCEPT +{ + static const auto name = ctype_name(); + return name.c_str(); +} + +/** + * @brief Gets the fully qualified name of the type, including namespace and + * template parameters (if any) + * @param x value of specific type + * @return name of the type + */ +template +inline const char* type_name(T x) CMT_NOEXCEPT +{ + (void)x; + return type_name(); +} + +/** + * @brief Gets unique value associated with the type + * @tparam T type + * @return value of type that supports operator== and operator!= + */ +template +constexpr inline type_id_t ctypeid() +{ + return details::typeident_impl(); +} +/** + * @brief Gets unique value associated with the type + * @param x value of specific type + * @return value of type that supports operator== and operator!= + */ +template +constexpr inline type_id_t ctypeid(T x) +{ + (void)x; + return details::typeident_impl(); +} +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/function.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/function.hpp new file mode 100644 index 00000000..b85f6d70 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/function.hpp @@ -0,0 +1,157 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" +#include "memory.hpp" +#include +#include +#include +#include +#if CMT_HAS_EXCEPTIONS +#include +#endif + +namespace cometa +{ + +namespace details +{ + +template +struct func_filter +{ + typedef Fn type; +}; +template +struct func_filter +{ + typedef Result (*type)(Args...); +}; + +template +constexpr CMT_INTRINSIC T return_val() CMT_NOEXCEPT +{ + return {}; +} + +template <> +constexpr CMT_INTRINSIC void return_val() CMT_NOEXCEPT +{ +} +} // namespace details + +/** + * @brief std::function-like lightweight function wrapper + * @code + * function f = []( float x ){ return static_cast( x ); }; + * CHECK( f( 3.4f ) == 3 ) + * @endcode + */ +template +struct function; + +namespace details +{ +template +struct function_abstract +{ + virtual ~function_abstract() {} + virtual R operator()(Args... args) = 0; +}; +template +struct function_impl : public function_abstract +{ + inline static void* operator new(size_t size) noexcept { return aligned_allocate(size, alignof(Fn)); } + inline static void operator delete(void* ptr) noexcept { return aligned_deallocate(ptr); } + +#ifdef __cpp_aligned_new + inline static void* operator new(size_t size, std::align_val_t al) noexcept + { + return aligned_allocate(size, static_cast(al)); + } + inline static void operator delete(void* ptr, std::align_val_t al) noexcept + { + return aligned_deallocate(ptr); + } +#endif + + template + function_impl(Fn_ fn) : fn(std::forward(fn)) + { + } + ~function_impl() override {} + R operator()(Args... args) override { return fn(std::forward(args)...); } + Fn fn; +}; +} // namespace details + +template +struct function +{ + function() noexcept = default; + + function(std::nullptr_t) noexcept {} + + template && + !std::is_same_v, function>>> + function(Fn fn) : impl(new details::function_impl, R, Args...>(std::move(fn))) + { + } + + function(const function&) = default; + + function(function&&) noexcept = default; + + function& operator=(const function&) = default; + + function& operator=(function&&) noexcept = default; + + R operator()(Args... args) const + { +#if CMT_HAS_EXCEPTIONS + if (impl) + { + return impl->operator()(std::forward(args)...); + } + throw std::bad_function_call(); +#else + // With exceptions disabled let it crash. To prevent this, check first + return impl->operator()(std::forward(args)...); +#endif + } + + [[nodiscard]] explicit operator bool() const { return !!impl; } + + [[nodiscard]] bool empty() const { return !impl; } + + std::shared_ptr> impl; + + bool operator==(const function& fn) const { return impl == fn.impl; } + bool operator!=(const function& fn) const { return !operator==(fn); } +}; + +template +CMT_INLINE function cdispatch(cvals_t, identity, Fn&&, DefFn&& deffn = DefFn()) +{ + return [=](Args... args) CMT_INLINE_LAMBDA -> Ret { return deffn(std::forward(args)...); }; +} + +template +inline function cdispatch(cvals_t, identity value, Fn&& fn, + DefFn&& deffn = DefFn()) +{ + if (value == v0) + { + return [=](Args... args) CMT_INLINE_LAMBDA -> Ret + { return fn(cval_t(), std::forward(args)...); }; + } + else + { + return cdispatch(cvals_t(), value, std::forward(fn), + std::forward(deffn)); + } +} +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/memory.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/memory.hpp new file mode 100644 index 00000000..166a89af --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/memory.hpp @@ -0,0 +1,302 @@ +/** @addtogroup memory + * @{ + */ +#pragma once + +#include "numeric.hpp" +#include +#include +#include +#include + +namespace cometa +{ + +namespace details +{ + +struct memory_statistics +{ + std::atomic_uintptr_t allocation_count{ 0 }; + std::atomic_uintptr_t allocation_size{ 0 }; + std::atomic_uintptr_t deallocation_count{ 0 }; + std::atomic_uintptr_t deallocation_size{ 0 }; +}; + +inline memory_statistics& get_memory_statistics() +{ + static memory_statistics ms; + return ms; +} + +#pragma pack(push, 1) + +struct mem_header +{ + u16 offset; + u16 alignment; + unsigned int references_uint; + size_t size; + + CMT_MEM_INTRINSIC std::atomic_uint& references() + { + return reinterpret_cast(references_uint); + } +} +#ifdef CMT_GNU_ATTRIBUTES +__attribute__((__packed__)) +#endif +; + +static_assert(sizeof(mem_header) == sizeof(size_t) + 2 * sizeof(u16) + sizeof(unsigned int), + "Wrong mem_header layout"); + +#pragma pack(pop) + +inline mem_header* aligned_header(void* ptr) { return ptr_cast(ptr) - 1; } + +inline size_t aligned_size(void* ptr) { return aligned_header(ptr)->size; } + +inline void* aligned_malloc(size_t size, size_t alignment) +{ + if (alignment == 0 || alignment > 32768) + return nullptr; + get_memory_statistics().allocation_count++; + get_memory_statistics().allocation_size += size; + void* ptr = malloc(size + (alignment - 1) + sizeof(mem_header)); + if (ptr == nullptr) + return nullptr; + void* aligned_ptr = advance(ptr, sizeof(mem_header)); + aligned_ptr = align_up(aligned_ptr, alignment); + aligned_header(aligned_ptr)->alignment = static_cast(alignment); + aligned_header(aligned_ptr)->offset = static_cast(distance(aligned_ptr, ptr)); + aligned_header(aligned_ptr)->references() = 1; + aligned_header(aligned_ptr)->size = size; + return aligned_ptr; +} + +inline void aligned_force_free(void* ptr) +{ + get_memory_statistics().deallocation_count++; + get_memory_statistics().deallocation_size += aligned_size(ptr); + free(advance(ptr, -static_cast(aligned_header(ptr)->offset))); +} + +inline void aligned_add_ref(void* ptr) { aligned_header(ptr)->references()++; } + +inline void aligned_free(void* ptr) +{ + if (--aligned_header(ptr)->references() == 0) + aligned_force_free(ptr); +} + +inline void aligned_release(void* ptr) { aligned_free(ptr); } + +inline void* aligned_reallocate(void* ptr, size_t new_size, size_t alignment) +{ + if (ptr) + { + if (new_size) + { + void* new_ptr = aligned_malloc(new_size, alignment); + size_t old_size = aligned_size(ptr); + memcpy(new_ptr, ptr, std::min(old_size, new_size)); + aligned_release(ptr); + return new_ptr; + } + else + { + aligned_release(ptr); + return nullptr; + } + } + else + { + if (new_size) + { + return details::aligned_malloc(new_size, alignment); + } + else + { + return nullptr; // do nothing + } + } +} +} // namespace details + +constexpr inline size_t default_memory_alignment = 64; + +/// @brief Allocates aligned memory +template +CMT_INTRINSIC T* aligned_allocate(size_t size = 1) +{ + T* ptr = static_cast(CMT_ASSUME_ALIGNED( + details::aligned_malloc(std::max(alignment, size * details::elementsize()), alignment), + alignment)); + return ptr; +} +/// @brief Allocates aligned memory +template +CMT_INTRINSIC T* aligned_allocate(size_t size, size_t alignment) +{ + T* ptr = static_cast(CMT_ASSUME_ALIGNED( + details::aligned_malloc(std::max(alignment, size * details::elementsize()), alignment), + alignment)); + return ptr; +} + +/// @brief Deallocates aligned memory +template +CMT_INTRINSIC void aligned_deallocate(T* ptr) +{ + return details::aligned_free(ptr); +} + +namespace details +{ +template +struct aligned_deleter +{ + CMT_MEM_INTRINSIC void operator()(T* ptr) const { aligned_deallocate(ptr); } +}; +} // namespace details + +template +struct autofree +{ + CMT_MEM_INTRINSIC autofree() {} + explicit CMT_MEM_INTRINSIC autofree(size_t size) : ptr(aligned_allocate(size)) {} + autofree(const autofree&) = delete; + autofree& operator=(const autofree&) = delete; + autofree(autofree&&) CMT_NOEXCEPT = default; + autofree& operator=(autofree&&) CMT_NOEXCEPT = default; + CMT_MEM_INTRINSIC T& operator[](size_t index) CMT_NOEXCEPT { return ptr[index]; } + CMT_MEM_INTRINSIC const T& operator[](size_t index) const CMT_NOEXCEPT { return ptr[index]; } + + template + CMT_MEM_INTRINSIC U* data() CMT_NOEXCEPT + { + return ptr_cast(ptr.get()); + } + template + CMT_MEM_INTRINSIC const U* data() const CMT_NOEXCEPT + { + return ptr_cast(ptr.get()); + } + + std::unique_ptr> ptr; +}; + +#ifdef KFR_USE_STD_ALLOCATION + +template +using data_allocator = std::allocator; + +#else + +/// @brief Aligned allocator +template +struct data_allocator +{ + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + template + struct rebind + { + using other = data_allocator; + }; + constexpr data_allocator() CMT_NOEXCEPT = default; + constexpr data_allocator(const data_allocator&) CMT_NOEXCEPT = default; + template + constexpr data_allocator(const data_allocator&) CMT_NOEXCEPT + { + } + pointer allocate(size_type n) const + { + pointer result = aligned_allocate(n); + if (!result) + CMT_THROW(std::bad_alloc()); + return result; + } + void deallocate(pointer p, size_type) { aligned_deallocate(p); } +}; + +template +constexpr inline bool operator==(const data_allocator&, const data_allocator&) CMT_NOEXCEPT +{ + return true; +} +template +constexpr inline bool operator!=(const data_allocator&, const data_allocator&) CMT_NOEXCEPT +{ + return false; +} + +#endif + +struct aligned_new +{ + inline static void* operator new(size_t size) noexcept { return aligned_allocate(size); } + inline static void operator delete(void* ptr) noexcept { return aligned_deallocate(ptr); } + +#ifdef __cpp_aligned_new + inline static void* operator new(size_t size, std::align_val_t al) noexcept + { + return details::aligned_malloc(size, + std::max(size_t(default_memory_alignment), static_cast(al))); + } + inline static void operator delete(void* ptr, std::align_val_t al) noexcept + { + return details::aligned_free(ptr); + } +#endif +}; + +#define KFR_CLASS_REFCOUNT(cl) \ + \ +public: \ + void addref() const { m_refcount++; } \ + void release() const \ + { \ + if (--m_refcount == 0) \ + { \ + delete this; \ + } \ + } \ + \ +private: \ + mutable std::atomic_uintptr_t m_refcount = ATOMIC_VAR_INIT(0); + +namespace details +{ + +template +CMT_ALWAYS_INLINE static void call_with_temp_heap(size_t temp_size, Fn&& fn) +{ + autofree temp(temp_size); + fn(temp.data()); +} + +template +CMT_NOINLINE static void call_with_temp_stack(size_t temp_size, Fn&& fn) +{ + alignas(default_memory_alignment) T temp[stack_size]; + fn(&temp[0]); +} + +} // namespace details + +template +CMT_ALWAYS_INLINE static void call_with_temp(size_t temp_size, Fn&& fn) +{ + if (temp_size <= stack_size) + return details::call_with_temp_stack(temp_size, std::forward(fn)); + return details::call_with_temp_heap(temp_size, std::forward(fn)); +} +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/named_arg.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/named_arg.hpp new file mode 100644 index 00000000..6b68902a --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/named_arg.hpp @@ -0,0 +1,35 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4814)) + +namespace cometa +{ +template +struct named_arg +{ + T value; + const char* name; +}; + +struct named +{ + constexpr named(const char* name) CMT_NOEXCEPT : name(name) {} + + template + CMT_MEM_INTRINSIC constexpr named_arg operator=(T&& value) + { + return named_arg{ std::forward(value), name }; + } + const char* name; +}; + +inline named operator""_arg(const char* name, size_t) { return name; } +} // namespace cometa + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/numeric.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/numeric.hpp new file mode 100644 index 00000000..c50e7468 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/numeric.hpp @@ -0,0 +1,191 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" + +namespace cometa +{ + +/// @brief Short names for common types +using b8 = bool; +using f32 = float; +using f64 = double; +using i8 = int8_t; +using i16 = int16_t; +using i32 = int32_t; +using i64 = int64_t; +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; +using umax = uint64_t; +using imax = int64_t; +using fmax = double; +using f80 = long double; + +#if defined(CMT_BASETYPE_F32) || defined(CMT_NO_NATIVE_F64) +using fbase = float; +#else +using fbase = double; +#endif + +namespace details +{ +template +struct fix_type_impl +{ + using type = T; +}; + +template <> +struct fix_type_impl +{ + using type = i8; +}; + +template <> +struct fix_type_impl +{ +#if ULONG_MAX == ULLONG_MAX + using type = u64; +#else + using type = u32; +#endif +}; + +template <> +struct fix_type_impl +{ +#if LONG_MAX == LLONG_MAX + using type = i64; +#else + using type = i32; +#endif +}; + +template <> +struct fix_type_impl +{ + using type = u64; +}; + +template <> +struct fix_type_impl +{ + using type = i64; +}; + +} // namespace details + +template +using fix_type = typename details::fix_type_impl::type; + +/// @brief An enumeration representing data type +enum class datatype : int +{ + typebits_mask = 0xFF, + f = 0x100, // floating point + i = 0x200, // signed integer + u = 0x300, // unsigned integer + c = 0x400, // complex floating point + b = 0x500, // boolean + typeclass_mask = 0xF00, + f16 = static_cast(f) | 16, + f32 = static_cast(f) | 32, + f64 = static_cast(f) | 64, + f80 = static_cast(f) | 80, + i8 = static_cast(i) | 8, + i16 = static_cast(i) | 16, + i24 = static_cast(i) | 24, + i32 = static_cast(i) | 32, + i64 = static_cast(i) | 64, + u8 = static_cast(u) | 8, + u16 = static_cast(u) | 16, + u24 = static_cast(u) | 24, + u32 = static_cast(u) | 32, + u64 = static_cast(u) | 64, + c32 = static_cast(c) | 32, + c64 = static_cast(c) | 64, + b8 = static_cast(b) | 8 +}; + +constexpr inline datatype operator|(datatype x, datatype y) +{ + using type = std::underlying_type_t; + return static_cast(static_cast(x) | static_cast(y)); +} + +constexpr inline datatype operator&(datatype x, datatype y) +{ + using type = std::underlying_type_t; + return static_cast(static_cast(x) & static_cast(y)); +} + +template +constexpr inline datatype typeclass = + std::is_floating_point_v::subtype> ? datatype::f + : std::is_integral_v::subtype> + ? (std::is_unsigned_v::subtype> ? datatype::u : datatype::i) + : datatype(); + +template +constexpr inline bool is_f_class = typeclass == datatype::f; +template +constexpr inline bool is_u_class = typeclass == datatype::u; +template +constexpr inline bool is_i_class = typeclass == datatype::i; + +template +struct typebits +{ + constexpr static size_t bits = sizeof(typename compound_type_traits::subtype) * 8; + constexpr static size_t width = compound_type_traits::is_scalar ? 0 : compound_type_traits::width; + using subtype = typename compound_type_traits::subtype; +}; + +template +using ftype = + typename compound_type_traits::template deep_rebind>::bits>>; +template +using itype = + typename compound_type_traits::template deep_rebind>::bits>>; +template +using utype = + typename compound_type_traits::template deep_rebind>::bits>>; + +template +using uitype = std::conditional_t>, T, utype>; + +template +using fsubtype = ftype>; +template +using isubtype = itype>; +template +using usubtype = utype>; +namespace details +{ +template +struct flt_type_impl +{ + using type = std::conditional_t; +}; + +template <> +struct flt_type_impl +{ + using type = float; +}; +template <> +struct flt_type_impl +{ + using type = double; +}; +} // namespace details + +template +using flt_type = typename cometa::compound_type_traits::template deep_rebind< + typename details::flt_type_impl>::type>; + +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/range.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/range.hpp new file mode 100644 index 00000000..ebe91204 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/range.hpp @@ -0,0 +1,72 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" + +namespace cometa +{ + +/// @brief Iterable range +template +struct range +{ + using value_type = T; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using diff_type = decltype(std::declval() - std::declval()); + + constexpr range(value_type begin, value_type end, diff_type step) CMT_NOEXCEPT : min(begin), + max(end), + step(step) + { + } + + struct iterator + { + value_type value; + diff_type step; + constexpr const_reference operator*() const { return value; } + constexpr const_pointer operator->() const { return &value; } + constexpr iterator& operator++() + { + value += step; + return *this; + } + constexpr iterator operator++(int) + { + iterator copy = *this; + ++(*this); + return copy; + } + constexpr bool operator!=(const iterator& other) const + { + return step > 0 ? value < other.value : value > other.value; + } + }; + value_type min; + value_type max; + diff_type step; + constexpr iterator begin() const { return iterator{ min, step }; } + constexpr iterator end() const { return iterator{ max, step }; } + + constexpr T distance() const { return max - min; } +}; + +/// @brief Make iterable range object +template +constexpr range make_range(T begin, T end) +{ + return range(begin, end, end > begin ? 1 : -1); +} + +/// @brief Make iterable range object with step +template +constexpr range> make_range(T begin, T end, D step) +{ + return range>(begin, end, step); +} +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/result.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/result.hpp new file mode 100644 index 00000000..4b009997 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/result.hpp @@ -0,0 +1,52 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" + +namespace cometa +{ +template (0)> +struct result +{ + using value_type = Type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + + using error_type = ErrEnum; + + constexpr static error_type ok_value = OkValue; + + constexpr result(const result&) = default; + constexpr result(result&&) CMT_NOEXCEPT = default; + + constexpr result(ErrEnum error) CMT_NOEXCEPT : m_error(error) {} + + template )> + constexpr result(ValueInit&& value) CMT_NOEXCEPT : m_value(std::forward(value)), + m_error(OkValue) + { + } + + constexpr result(const Type& value) CMT_NOEXCEPT : m_value(value), m_error(OkValue) {} + constexpr result(Type&& value) CMT_NOEXCEPT : m_value(std::move(value)), m_error(OkValue) {} + + constexpr explicit operator bool() const { return m_error == OkValue; } + constexpr const_reference operator*() const { return m_value; } + constexpr reference operator*() { return m_value; } + constexpr const_pointer operator->() const { return &m_value; } + constexpr pointer operator->() { return &m_value; } + + constexpr const_reference value() const { return m_value; } + constexpr reference value() { return m_value; } + constexpr ErrEnum error() const { return m_error; } + constexpr bool ok() const { return m_error == OkValue; } + +private: + Type m_value; + ErrEnum m_error; +}; +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/string.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/string.hpp new file mode 100644 index 00000000..d91371cd --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/string.hpp @@ -0,0 +1,700 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cometa.hpp" +#include "cstring.hpp" +#include "ctti.hpp" +#include "named_arg.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpragmas") +#if CMT_HAS_WARNING("-Wformat-security") || defined CMT_COMPILER_GCC +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wformat-security") +#endif +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wused-but-marked-unused") + +namespace cometa +{ + +template +struct representation; + +template +using repr_type = typename representation::type; + +template +CMT_INLINE std::string as_string(const Args&... args); + +template (-1), int width = -1, int prec = -1> +struct fmt_t +{ + const T& value; +}; + +namespace details +{ + +template = 0 && number < 10)> +constexpr cstring<2> itoa() +{ + return cstring<2>{ { static_cast(number + '0'), 0 } }; +} +template = 10)> +constexpr auto itoa() +{ + return concat_cstring(itoa(), itoa()); +} +template +constexpr auto itoa() +{ + return concat_cstring(make_cstring("-"), itoa<-number>()); +} + +template = 0)> +CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) +{ + return concat_cstring(make_cstring("."), itoa()); +} +template = 0 && prec < 0)> +CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) +{ + return itoa(); +} +template +CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) +{ + return make_cstring(""); +} +template = 0 && prec >= 0)> +CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) +{ + return concat_cstring(itoa(), make_cstring("."), itoa()); +} + +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%ld"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%lld"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%u"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%lu"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%llu"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%g"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%g"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%Lg"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%p"); } +CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%p"); } + +template +CMT_INLINE constexpr auto value_fmt(ctype_t>) +{ + return concat_cstring(make_cstring("%s"), make_cstring(cchars_t())); +} + +template +CMT_INLINE constexpr auto value_fmt(ctype_t>) +{ + return make_cstring("%s"); +} + +template +CMT_INLINE constexpr auto value_fmt(ctype_t(-1), width, prec>> fmt) +{ + return concat_cstring(make_cstring("%"), value_fmt_arg(fmt), + value_fmt(ctype_t>()).slice(csize_t<1>())); +} +template +CMT_INLINE constexpr auto value_fmt(ctype_t> fmt) +{ + return concat_cstring(make_cstring("%"), value_fmt_arg(fmt), cstring<2>{ { t, 0 } }); +} + +template +CMT_INLINE constexpr auto value_fmt(ctype_t) +{ + return make_cstring("%s"); +} + +template +CMT_INLINE const char* pack_value(const cchars_t&) +{ + return ""; +} + +#define CMT_STANDARD_PACK(type) \ + CMT_INLINE type pack_value(type value) { return value; } + +CMT_STANDARD_PACK(char) +CMT_STANDARD_PACK(signed char) +CMT_STANDARD_PACK(unsigned char) +CMT_STANDARD_PACK(signed short) +CMT_STANDARD_PACK(unsigned short) +CMT_STANDARD_PACK(signed int) +CMT_STANDARD_PACK(unsigned int) +CMT_STANDARD_PACK(signed long) +CMT_STANDARD_PACK(unsigned long) +CMT_STANDARD_PACK(signed long long) +CMT_STANDARD_PACK(unsigned long long) +CMT_STANDARD_PACK(double) +CMT_STANDARD_PACK(char*) +CMT_STANDARD_PACK(const char*) +CMT_STANDARD_PACK(void*) +CMT_STANDARD_PACK(const void*) + +CMT_INLINE double pack_value(float value) { return static_cast(value); } +CMT_INLINE auto pack_value(bool value) { return value ? "true" : "false"; } +CMT_INLINE auto pack_value(const std::string& value) { return value.c_str(); } + +template +CMT_INLINE const char* pack_value(ctype_t) +{ + return type_name(); +} + +template +CMT_INLINE auto pack_value(const fmt_t& value) +{ + return pack_value(representation::get(value.value)); +} + +template +CMT_INLINE auto pack_value(const T&) +{ + return pack_value(type_name()); +} + +template +CMT_INLINE constexpr cstring fmt_replace_impl(const cstring& str, + const cstring& newfmt, + csizes_t) +{ + size_t start = 0; + size_t end = 0; + cstring result; + for (size_t i = 0; i < N1; i++) + { + if (str[i] == '{') + start = i; + else if (str[i] == '}') + end = i; + } + + if (end - start == 1) // {} + { + for (size_t i = 0; i < N1; i++) + { + if (i < start) + result[i] = str[i]; + else if (i == start) + result[i] = '%'; + else if (i > start && i - start - 1 < Nnew - 1) + result[i] = newfmt[i - start - 1]; + else if (i - Nnew + 3 < N1 - 1) + result[i] = str[i - Nnew + 3]; + else + result[i] = 0; + } + } + return result; +} + +template +CMT_INLINE constexpr cstring fmt_replace(const cstring& str, const cstring& newfmt) +{ + return fmt_replace_impl(str, newfmt, csizeseq); +} + +inline std::string replace_one(const std::string& str, const std::string& from, const std::string& to) +{ + std::string r = str; + size_t start_pos = 0; + if ((start_pos = r.find(from, start_pos)) != std::string::npos) + { + r.replace(start_pos, from.size(), to); + } + return r; +} + +CMT_INLINE const std::string& build_fmt(const std::string& str, ctypes_t<>) { return str; } + +template +CMT_INLINE auto build_fmt(const std::string& str, ctypes_t) +{ + constexpr auto fmt = value_fmt(ctype_t>()); + return build_fmt(replace_one(str, "{}", std::string(fmt.data())), ctypes_t()); +} +} // namespace details + +template +struct representation +{ + using type = T; + static constexpr auto get(const T& value) CMT_NOEXCEPT { return details::pack_value(value); } +}; + +template +CMT_INLINE fmt_t fmt(const T& value) +{ + return { value }; +} + +template +CMT_INLINE fmt_t(-1), width, prec> fmtwidth(const T& value) +{ + return { value }; +} + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpragmas") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wgnu-string-literal-operator-template") + +constexpr auto build_fmt_str(cchars_t<>, ctypes_t<>) { return make_cstring(""); } + +template +constexpr auto build_fmt_str(cchars_t<'@', chars...>, ctypes_t) +{ + return concat_cstring(details::value_fmt(ctype_t>()), + build_fmt_str(cchars_t(), ctypes_t())); +} + +template +constexpr auto build_fmt_str(cchars_t, ctypes_t) +{ + return concat_cstring(make_cstring(cchars_t()), + build_fmt_str(cchars_t(), ctypes_t())); +} + +template +struct format_t +{ + template + inline std::string operator()(const Args&... args) + { + constexpr auto format_str = build_fmt_str(cchars_t(), ctypes_t...>()); + + std::string result; + const int size = std::snprintf(nullptr, 0, format_str.data(), details::pack_value(args)...); + if (size <= 0) + return result; + result.resize(size_t(size + 1)); + result.resize(size_t(std::snprintf(&result[0], size_t(size + 1), format_str.data(), + details::pack_value(representation::get(args))...))); + return result; + } +}; + +template +struct print_t +{ + template + CMT_INLINE void operator()(const Args&... args) + { + constexpr auto format_str = build_fmt_str(cchars_t(), ctypes_t...>()); + + std::printf(format_str.data(), details::pack_value(args)...); + } +}; + +#if defined CMT_COMPILER_GNU && !defined(CMT_COMPILER_INTEL) + +template +constexpr format_t operator""_format() +{ + return {}; +} + +template +constexpr CMT_INLINE print_t operator""_print() +{ + return {}; +} + +#endif + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +template +CMT_INLINE void printfmt(const std::string& fmt, const Args&... args) +{ + const auto format_str = details::build_fmt(fmt, ctypes_t...>()); + std::printf(format_str.data(), details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE void fprintfmt(FILE* f, const std::string& fmt, const Args&... args) +{ + const auto format_str = details::build_fmt(fmt, ctypes_t...>()); + std::fprintf(f, format_str.data(), details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE int snprintfmt(char* str, size_t size, const std::string& fmt, const Args&... args) +{ + const auto format_str = details::build_fmt(fmt, ctypes_t...>()); + return std::snprintf(str, size, format_str.data(), + details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE std::string format(const std::string& fmt, const Args&... args) +{ + std::string result; + const auto format_str = details::build_fmt(fmt, ctypes_t...>()); + const int size = + std::snprintf(nullptr, 0, format_str.data(), details::pack_value(representation::get(args))...); + if (size <= 0) + return result; + result.resize(size_t(size + 1)); + result.resize(size_t(std::snprintf(&result[0], size_t(size + 1), format_str.data(), + details::pack_value(representation::get(args))...))); + return result; +} + +namespace details +{ +template +constexpr auto get_value_fmt() +{ + return details::value_fmt(ctype_t>>()); +} +} // namespace details + +template +CMT_INLINE void print(const Args&... args) +{ + constexpr const auto format_str = concat_cstring(details::get_value_fmt()...); + const char* str = format_str.data(); + std::printf(str, details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE void println(const Args&... args) +{ + constexpr const auto format_str = concat_cstring(details::get_value_fmt()..., make_cstring("\n")); + const char* str = format_str.data(); + std::printf(str, details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE void error(const Args&... args) +{ + constexpr const auto format_str = concat_cstring(details::get_value_fmt()...); + const char* str = format_str.data(); + std::fprintf(stderr, str, details::pack_value(representation::get(args))...); +} + +template +CMT_INLINE void errorln(const Args&... args) +{ + constexpr const auto format_str = concat_cstring(details::get_value_fmt()..., make_cstring("\n")); + const char* str = format_str.data(); + std::fprintf(stderr, str, details::pack_value(representation::get(args))...); + std::fflush(stderr); +} + +template +CMT_INLINE std::string as_string(const Args&... args) +{ + std::string result; + constexpr auto format_str = concat_cstring(details::get_value_fmt()...); + const char* str = format_str.data(); + + const int size = std::snprintf(nullptr, 0, str, details::pack_value(representation::get(args))...); + if (size <= 0) + return result; + result.resize(size_t(size + 1)); + result.resize(size_t(std::snprintf(&result[0], size_t(size + 1), str, + details::pack_value(representation::get(args))...))); + return result; +} + +inline std::string padright(size_t size, const std::string& text, char character = ' ') +{ + const size_t pad = size >= text.size() ? size - text.size() : 0; + return std::string(pad, character) + text; +} + +inline std::string padleft(size_t size, const std::string& text, char character = ' ') +{ + const size_t pad = size >= text.size() ? size - text.size() : 0; + return text + std::string(pad, character); +} + +inline std::string padcenter(size_t size, const std::string& text, char character = ' ') +{ + const size_t pad = size >= text.size() ? size - text.size() : 0; + return std::string(pad / 2, character) + text + std::string(pad - pad / 2, character); +} + +template +inline std::string q(T x) +{ + return "\"" + as_string(std::forward(x)) + "\""; +} + +template +inline std::string join(T x) +{ + return as_string(std::forward(x)); +} + +template +inline std::string join(T x, U y, Ts... rest) +{ + return format("{}, {}", x, join(std::forward(y), std::forward(rest)...)); +} + +template +struct representation> +{ + using type = std::string; + static std::string get(const named_arg& value) + { + return std::string(value.name) + " = " + as_string(value.value); + } +}; + +template +struct representation> +{ + using type = std::string; + static std::string get(const std::pair& value) + { + return "(" + as_string(value.first) + "; " + as_string(value.second) + ")"; + } +}; + +template +struct representation> +{ + using type = std::string; + static std::string get(const std::unique_ptr& value) + { + if (value) + return as_string(type_name>(), "(", *value.get(), ")"); + else + return as_string(type_name>(), "(nullptr)"); + } +}; + +template +struct representation> +{ + using type = std::string; + static std::string get(const std::weak_ptr& value) + { + std::shared_ptr sh = value.lock(); + if (sh) + return as_string(type_name>(), "(", *sh.get(), ")"); + else + return as_string(type_name>(), "(nullptr)"); + } +}; + +template +struct representation> +{ + using type = std::string; + static std::string get(const std::shared_ptr& value) + { + if (value) + return as_string(type_name>(), "(", *value.get(), ")"); + else + return as_string(type_name>(), "(nullptr)"); + } +}; + +template <> +struct representation> +{ + using type = std::string; + static std::string get(const std::shared_ptr& value) + { + if (value) + return as_string(type_name>(), "(", value.get(), ")"); + else + return as_string(type_name>(), "(nullptr)"); + } +}; + +namespace details +{ + +template +CMT_INTRINSIC size_t trailing_zeros(const std::array& indices) +{ + for (size_t i = 0; i < dims; ++i) + { + if (indices[dims - 1 - i] != 0) + return i; + } + return dims; +} + +template +CMT_INTRINSIC bool increment_indices(std::array& indices, const std::array& stop) +{ + indices[dims - 1] += 1; + CMT_PRAGMA_GNU(clang diagnostic push) +#if CMT_HAS_WARNING("-Wpass-failed") + CMT_PRAGMA_GNU(clang diagnostic ignored "-Wpass-failed") +#endif + CMT_LOOP_UNROLL + for (int i = dims - 1; i >= 0;) + { + if (CMT_LIKELY(indices[i] < stop[i])) + return true; + // carry + indices[i] = 0; + --i; + if (i < 0) + { + return false; + } + indices[i] += 1; + } + CMT_PRAGMA_GNU(clang diagnostic pop) + return true; +} +} // namespace details + +template +CMT_INTRINSIC Fmt wrap_fmt(const U& val, ctype_t) +{ + return Fmt{ val }; +} +template +CMT_INTRINSIC U wrap_fmt(const U& val, ctype_t) +{ + return val; +} + +template +std::string array_to_string(const std::array& shape, Getter&& getter, int max_columns = 16, + int max_dimensions = INT_MAX, std::string_view separator = ", ", + std::string_view open = "{", std::string_view close = "}") +{ + using shape_type = std::array; + using index_t = size_t; + + if (max_columns == 0) + max_columns = INT_MAX; + std::string ss; + for (index_t i = 0; i < Dims; ++i) + ss += open; + + bool isempty = std::accumulate(shape.begin(), shape.end(), size_t(1), std::multiplies{}) == 0; + if (!isempty) + { + shape_type index{ 0 }; + std::string open_filler(open.size(), ' '); + std::string_view separator_trimmed = separator.substr(0, 1 + separator.find_last_not_of(" \t")); + int columns = 0; + do + { + std::string str = as_string(wrap_fmt(getter(index), cometa::ctype)); + index_t z = details::trailing_zeros(index); + if ((z > 0 && columns > 0) || columns >= max_columns) + { + for (index_t i = 0; i < z; ++i) + ss += close; + + if (z > max_dimensions || columns >= max_columns) + { + if (columns > 0) + ss += separator_trimmed; + ss += "\n"; + for (index_t i = 0; i < Dims - z; ++i) + ss += open_filler; + } + else + { + if (columns > 0) + ss += separator; + } + for (index_t i = 0; i < z; ++i) + ss += open; + + columns = 0; + } + else + { + if (columns > 0) + ss += separator; + } + ss += str; + ++columns; + } while (details::increment_indices(index, shape)); + } + for (index_t i = 0; i < Dims; ++i) + ss += close; + return ss; +} + +template +std::string array_to_string(size_t size, Getter&& getter, int max_columns = 16, int max_dimensions = INT_MAX, + std::string_view separator = ", ", std::string_view open = "{", + std::string_view close = "}") +{ + return array_to_string(std::array{ size }, std::forward(getter), max_columns, + max_dimensions, std::move(separator), std::move(open), std::move(close)); +} +template +std::string array_to_string(size_t size, T* data, int max_columns = 16, int max_dimensions = INT_MAX, + std::string_view separator = ", ", std::string_view open = "{", + std::string_view close = "}") +{ + return array_to_string( + std::array{ size }, [data](std::array i) { return data[i.front()]; }, + max_columns, max_dimensions, std::move(separator), std::move(open), std::move(close)); +} + +template +struct representation> +{ + using type = std::string; + static std::string get(const std::array& value) + { + return array_to_string(value.size(), value.data()); + } +}; +template +struct representation> +{ + using type = std::string; + static std::string get(const std::vector& value) + { + return array_to_string(value.size(), value.data()); + } +}; +template <> +struct representation +{ + using type = std::string; + static std::string get(const std::string_view& value) + { + return std::string(value); + } +}; + +} // namespace cometa + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/cometa/tuple.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/tuple.hpp new file mode 100644 index 00000000..03d14f84 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/cometa/tuple.hpp @@ -0,0 +1,46 @@ +/** @addtogroup cometa + * @{ + */ +#pragma once + +#include "../cident.h" + +#include +#include + +namespace cometa +{ + +using std::ptrdiff_t; +using std::size_t; + +template +struct cvals_t; + +template +using csizes_t = cvals_t; + +struct swallow; + +namespace details +{ + +template +struct cvalseq_impl; + +template +void cforeach_tuple_impl(const std::tuple& tuple, Fn&& fn, csizes_t) +{ + swallow{ (fn(std::get(tuple)), void(), 0)... }; +} +} // namespace details + +template +void cforeach(const std::tuple& tuple, Fn&& fn) +{ + details::cforeach_tuple_impl(tuple, std::forward(fn), + typename details::cvalseq_impl::type()); +} +} // namespace cometa + +#include "../cometa.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/config.h b/packages/react-native-audio-api/android/src/main/include/kfr/config.h new file mode 100644 index 00000000..e69de29b diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dft.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dft.hpp new file mode 100644 index 00000000..771a9815 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dft.hpp @@ -0,0 +1,30 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "base.hpp" + +#include "dft/cache.hpp" +#include "dft/convolution.hpp" +#include "dft/fft.hpp" +#include "dft/reference_dft.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dft/cache.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dft/cache.hpp new file mode 100644 index 00000000..e26a4a17 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dft/cache.hpp @@ -0,0 +1,172 @@ +/** @addtogroup dft + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "fft.hpp" +#include +#include +#include + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +using dft_plan_ptr = std::shared_ptr>; + +template +using dft_plan_real_ptr = std::shared_ptr>; + +template +struct dft_cache_impl +{ + static dft_cache_impl& instance() + { + static dft_cache_impl cache; + return cache; + } + dft_plan_ptr get(ctype_t, size_t size) + { +#ifndef KFR_SINGLE_THREAD + std::lock_guard guard(mutex); +#endif + return get_or_create(cache_f32, size); + } + dft_plan_ptr get(ctype_t, size_t size) + { +#ifndef KFR_SINGLE_THREAD + std::lock_guard guard(mutex); +#endif + return get_or_create(cache_f64, size); + } + dft_plan_real_ptr getreal(ctype_t, size_t size) + { +#ifndef KFR_SINGLE_THREAD + std::lock_guard guard(mutex); +#endif + return get_or_create(cache_real_f32, size); + } + dft_plan_real_ptr getreal(ctype_t, size_t size) + { +#ifndef KFR_SINGLE_THREAD + std::lock_guard guard(mutex); +#endif + return get_or_create(cache_real_f64, size); + } + void clear() + { +#ifndef KFR_SINGLE_THREAD + std::lock_guard guard(mutex); +#endif + cache_f32.clear(); + cache_f64.clear(); + cache_real_f32.clear(); + cache_real_f64.clear(); + } + +private: + template + dft_plan_ptr get_or_create(std::vector>& cache, size_t size) + { + for (dft_plan_ptr& dft : cache) + { + if (dft->size == size) + return dft; + } + dft_plan_ptr sh = std::make_shared>(size); + cache.push_back(sh); + return sh; + } + template + dft_plan_real_ptr get_or_create(std::vector>& cache, size_t size) + { + for (dft_plan_real_ptr& dft : cache) + { + if (dft->size == size) + return dft; + } + dft_plan_real_ptr sh = std::make_shared>(size); + cache.push_back(sh); + return sh; + } + + std::vector> cache_f32; + std::vector> cache_f64; + std::vector> cache_real_f32; + std::vector> cache_real_f64; +#ifndef KFR_SINGLE_THREAD + std::mutex mutex; +#endif +}; + +using dft_cache = dft_cache_impl<>; + +/// @brief Performs Direct DFT using cached plan +template +univector> dft(const univector, Tag>& input) +{ + dft_plan_ptr dft = dft_cache::instance().get(ctype_t(), input.size()); + univector> output(input.size(), std::numeric_limits::quiet_NaN()); + univector temp(dft->temp_size); + dft->execute(output, input, temp); + return output; +} + +/// @brief Performs Inverse DFT using cached plan +template +univector> idft(const univector, Tag>& input) +{ + dft_plan_ptr dft = dft_cache::instance().get(ctype_t(), input.size()); + univector> output(input.size(), std::numeric_limits::quiet_NaN()); + univector temp(dft->temp_size); + dft->execute(output, input, temp, ctrue); + return output; +} + +/// @brief Performs Real Direct DFT using cached plan +template +univector> realdft(const univector& input) +{ + dft_plan_real_ptr dft = dft_cache::instance().getreal(ctype_t(), input.size()); + univector> output(input.size() / 2 + 1, std::numeric_limits::quiet_NaN()); + univector temp(dft->temp_size); + dft->execute(output, input, temp); + return output; +} + +/// @brief Permorms Real Inverse DFT using cached plan +template +univector irealdft(const univector, Tag>& input) +{ + dft_plan_real_ptr dft = dft_cache::instance().getreal(ctype_t(), (input.size() - 1) * 2); + univector output((input.size() - 1) * 2, std::numeric_limits::quiet_NaN()); + univector temp(dft->temp_size); + dft->execute(output, input, temp); + return output; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dft/convolution.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dft/convolution.hpp new file mode 100644 index 00000000..d172c614 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dft/convolution.hpp @@ -0,0 +1,151 @@ +/** @addtogroup convolution + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/filter.hpp" +#include "../base/memory.hpp" +#include "../simd/complex.hpp" +#include "../simd/constants.hpp" +#include "../simd/read_write.hpp" +#include "../simd/vec.hpp" + +#include "cache.hpp" +#include "fft.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") +#endif + +namespace kfr +{ + +namespace internal_generic +{ +template +univector convolve(const univector_ref& src1, const univector_ref& src2, + bool correlate = false); +} + +/// @brief Convolution +template , std::remove_const_t>)> +univector> convolve(const univector& src1, const univector& src2) +{ + return internal_generic::convolve(src1.slice(), src2.slice()); +} + +/// @brief Correlation +template , std::remove_const_t>)> +univector> correlate(const univector& src1, const univector& src2) +{ + return internal_generic::convolve(src1.slice(), src2.slice(), true); +} + +/// @brief Auto-correlation +template +univector> autocorrelate(const univector& src) +{ + univector> result = internal_generic::convolve(src.slice(), src.slice(), true); + result = result.slice(result.size() / 2); + return result; +} + +namespace internal_generic +{ +/// @brief Utility class to abstract real/complex differences +template +struct dft_conv_plan : public dft_plan_real +{ + dft_conv_plan(size_t size) : dft_plan_real(size, dft_pack_format::Perm) {} + + size_t csize() const { return this->size / 2; } +}; + +template +struct dft_conv_plan> : public dft_plan +{ + dft_conv_plan(size_t size) : dft_plan(size) {} + + size_t csize() const { return this->size; } +}; +} // namespace internal_generic + +/// @brief Convolution using Filter API +template +class convolve_filter : public filter +{ +public: + explicit convolve_filter(size_t size, size_t block_size = 1024); + explicit convolve_filter(const univector_ref& data, size_t block_size = 1024); + void set_data(const univector_ref& data); + void reset() final; + /// Apply filter to multiples of returned block size for optimal processing efficiency. + size_t input_block_size() const { return block_size; } + +protected: + void process_expression(T* dest, const expression_handle& src, size_t size) final + { + univector input = truncate(src, size); + process_buffer(dest, input.data(), input.size()); + } + void process_buffer(T* output, const T* input, size_t size) final; + + using ST = subtype; + constexpr static bool real_fft = !std::is_same_v>; + using plan_t = internal_generic::dft_conv_plan; + + // Length of filter data. + size_t data_size; + // Size of block to process. + const size_t block_size; + // FFT plan for circular convolution. + const plan_t fft; + // Temp storage for FFT. + univector temp; + // History of input segments after fwd DFT. History is circular relative to position below. + std::vector>> segments; + // Index into segments of current block. + size_t position; + // Blocks of filter/data after fwd DFT. + std::vector>> ir_segments; + // Saved input for current block. + univector saved_input; + // Index into saved_input for next input to begin. + size_t input_position; + // Pre-multiplied products of input history and delayed filter blocks. + univector> premul; + // Scratch buffer for product of filter and input for processing by reverse DFT. + univector> cscratch; + // Scratch buffers for input and output of fwd and rev DFTs. + univector scratch1, scratch2; + // Overlap saved from previous block to add into current block. + univector overlap; +}; + +} // namespace kfr +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dft/fft.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dft/fft.hpp new file mode 100644 index 00000000..3589a1bd --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dft/fft.hpp @@ -0,0 +1,821 @@ +/** @addtogroup dft + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/memory.hpp" +#include "../base/tensor.hpp" +#include "../base/univector.hpp" +#include "../math/sin_cos.hpp" +#include "../simd/complex.hpp" +#include "../simd/constants.hpp" +#include +#include + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") +#endif +#if CMT_HAS_WARNING("-Wundefined-inline") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wundefined-inline") +#endif + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4100)) + +namespace kfr +{ + +#define DFT_MAX_STAGES 32 + +using cdirect_t = cfalse_t; +using cinvert_t = ctrue_t; + +template +struct dft_stage +{ + size_t radix = 0; + size_t stage_size = 0; + size_t data_size = 0; + size_t temp_size = 0; + u8* data = nullptr; + size_t repeats = 1; + size_t out_offset = 0; + size_t blocks = 0; + size_t user = 0; + const char* name = nullptr; + bool recursion = false; + bool can_inplace = true; + bool need_reorder = true; + + void initialize(size_t size) { do_initialize(size); } + + virtual void dump() const + { + printf("%s: %zu, %zu, %zu, %zu, %zu, %zu, %zu, %d, %d\n", name ? name : "unnamed", radix, stage_size, + data_size, temp_size, repeats, out_offset, blocks, recursion, can_inplace); + } + virtual void copy_input(bool invert, complex* out, const complex* in, size_t size) + { + builtin_memcpy(out, in, sizeof(complex) * size); + } + + KFR_MEM_INTRINSIC void execute(cdirect_t, complex* out, const complex* in, u8* temp) + { + do_execute(cdirect_t(), out, in, temp); + } + KFR_MEM_INTRINSIC void execute(cinvert_t, complex* out, const complex* in, u8* temp) + { + do_execute(cinvert_t(), out, in, temp); + } + virtual ~dft_stage() {} + +protected: + virtual void do_initialize(size_t) {} + virtual void do_execute(cdirect_t, complex*, const complex*, u8* temp) = 0; + virtual void do_execute(cinvert_t, complex*, const complex*, u8* temp) = 0; +}; + +enum class dft_type +{ + both, + direct, + inverse +}; + +enum class dft_order +{ + normal, + internal, // possibly bit/digit-reversed, implementation-defined, may be faster to compute +}; + +enum class dft_pack_format +{ + Perm, // {X[0].r, X[N].r}, ... {X[i].r, X[i].i}, ... {X[N-1].r, X[N-1].i} + CCs // {X[0].r, 0}, ... {X[i].r, X[i].i}, ... {X[N-1].r, X[N-1].i}, {X[N].r, 0} +}; + +template +struct dft_plan; + +template +struct dft_plan_real; + +template +struct dft_stage; + +template +using dft_stage_ptr = std::unique_ptr>; + +namespace internal_generic +{ +template +void dft_initialize(dft_plan& plan); +template +void dft_real_initialize(dft_plan_real& plan); +template +void dft_execute(const dft_plan& plan, cbool_t, complex* out, const complex* in, u8* temp); + +template +using fn_transpose = void (*)(complex*, const complex*, shape<2>); +template +void dft_initialize_transpose(fn_transpose& transpose); + +} // namespace internal_generic + +/// @brief 1D DFT/FFT +template +struct dft_plan +{ + size_t size; + size_t temp_size; + + dft_plan() + : size(0), temp_size(0), data_size(0), arblen(false), disposition_inplace{}, disposition_outofplace{} + { + } + + dft_plan(const dft_plan&) = delete; + dft_plan(dft_plan&&) = default; + dft_plan& operator=(const dft_plan&) = delete; + dft_plan& operator=(dft_plan&&) = default; + + bool is_initialized() const { return size != 0; } + + [[deprecated("cpu parameter is deprecated. Runtime dispatch is used if built with " + "KFR_ENABLE_MULTIARCH")]] explicit dft_plan(cpu_t cpu, size_t size, + dft_order order = dft_order::normal) + : dft_plan(size, order) + { + (void)cpu; + } + explicit dft_plan(size_t size, dft_order order = dft_order::normal) + : size(size), temp_size(0), data_size(0), arblen(false) + { + internal_generic::dft_initialize(*this); + } + + void dump() const; + + KFR_MEM_INTRINSIC void execute(complex* out, const complex* in, u8* temp, + bool inverse = false) const + { + if (inverse) + execute_dft(ctrue, out, in, temp); + else + execute_dft(cfalse, out, in, temp); + } + ~dft_plan() {} + template + KFR_MEM_INTRINSIC void execute(complex* out, const complex* in, u8* temp, + cbool_t inv) const + { + execute_dft(inv, out, in, temp); + } + + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector, Tag2>& in, + univector& temp, bool inverse = false) const + { + if (inverse) + execute_dft(ctrue, out.data(), in.data(), temp.data()); + else + execute_dft(cfalse, out.data(), in.data(), temp.data()); + } + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector, Tag2>& in, + univector& temp, cbool_t inv) const + { + execute_dft(inv, out.data(), in.data(), temp.data()); + } + + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector, Tag2>& in, + u8* temp, bool inverse = false) const + { + if (inverse) + execute_dft(ctrue, out.data(), in.data(), temp); + else + execute_dft(cfalse, out.data(), in.data(), temp); + } + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector, Tag2>& in, + u8* temp, cbool_t inv) const + { + execute_dft(inv, out.data(), in.data(), temp); + } + + autofree data; + size_t data_size; + + std::vector> all_stages; + std::array*>, 2> stages; + bool arblen; + using bitset = std::bitset; + std::array disposition_inplace; + std::array disposition_outofplace; + + void calc_disposition(); + + static bitset precompute_disposition(int num_stages, bitset can_inplace_per_stage, + bool inplace_requested); + +protected: + struct noinit + { + }; + explicit dft_plan(noinit, size_t size, dft_order order = dft_order::normal) + : size(size), temp_size(0), data_size(0), arblen(false) + { + } + + template + KFR_INTRINSIC void execute_dft(cbool_t, complex* out, const complex* in, u8* temp) const + { + internal_generic::dft_execute(*this, cbool, out, in, temp); + } +}; + +/// @brief Real-to-complex and Complex-to-real 1D DFT +template +struct dft_plan_real : dft_plan +{ + size_t size; + dft_pack_format fmt; + + dft_plan_real() : size(0), fmt(dft_pack_format::CCs) {} + + dft_plan_real(const dft_plan_real&) = delete; + dft_plan_real(dft_plan_real&&) = default; + dft_plan_real& operator=(const dft_plan_real&) = delete; + dft_plan_real& operator=(dft_plan_real&&) = default; + + bool is_initialized() const { return size != 0; } + + size_t complex_size() const { return complex_size_for(size, fmt); } + constexpr static size_t complex_size_for(size_t size, dft_pack_format fmt) + { + return fmt == dft_pack_format::CCs ? size / 2 + 1 : size / 2; + } + + [[deprecated("cpu parameter is deprecated. Runtime dispatch is used if built with " + "KFR_ENABLE_MULTIARCH")]] explicit dft_plan_real(cpu_t cpu, size_t size, + dft_pack_format fmt = dft_pack_format::CCs) + : dft_plan_real(size, fmt) + { + (void)cpu; + } + + explicit dft_plan_real(size_t size, dft_pack_format fmt = dft_pack_format::CCs) + : dft_plan(typename dft_plan::noinit{}, size / 2), size(size), fmt(fmt) + { + KFR_LOGIC_CHECK(is_even(size), "dft_plan_real requires size to be even"); + internal_generic::dft_real_initialize(*this); + } + + void execute(complex*, const complex*, u8*, bool = false) const = delete; + + template + void execute(complex*, const complex*, u8*, cbool_t) const = delete; + + template + void execute(univector, Tag1>&, const univector, Tag2>&, univector&, + bool = false) const = delete; + + template + void execute(univector, Tag1>&, const univector, Tag2>&, univector&, + cbool_t) const = delete; + + template + void execute(univector, Tag1>& out, const univector, Tag2>& in, u8* temp, + bool inverse = false) const = delete; + + template + void execute(univector, Tag1>& out, const univector, Tag2>& in, u8* temp, + cbool_t inv) const = delete; + + KFR_MEM_INTRINSIC void execute(complex* out, const T* in, u8* temp, cdirect_t = {}) const + { + this->execute_dft(cfalse, out, ptr_cast>(in), temp); + } + KFR_MEM_INTRINSIC void execute(T* out, const complex* in, u8* temp, cinvert_t = {}) const + { + this->execute_dft(ctrue, ptr_cast>(out), in, temp); + } + + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector& in, + univector& temp, cdirect_t = {}) const + { + this->execute_dft(cfalse, out.data(), ptr_cast>(in.data()), temp.data()); + } + template + KFR_MEM_INTRINSIC void execute(univector& out, const univector, Tag2>& in, + univector& temp, cinvert_t = {}) const + { + this->execute_dft(ctrue, ptr_cast>(out.data()), in.data(), temp.data()); + } + + template + KFR_MEM_INTRINSIC void execute(univector, Tag1>& out, const univector& in, u8* temp, + cdirect_t = {}) const + { + this->execute_dft(cfalse, out.data(), ptr_cast>(in.data()), temp); + } + template + KFR_MEM_INTRINSIC void execute(univector& out, const univector, Tag2>& in, u8* temp, + cinvert_t = {}) const + { + this->execute_dft(ctrue, ptr_cast>(out.data()), in.data(), temp); + } +}; + +/// @brief Multidimensional DFT +template +struct dft_plan_md +{ + shape size; + size_t temp_size; + + dft_plan_md(const dft_plan_md&) = delete; + dft_plan_md(dft_plan_md&&) = default; + dft_plan_md& operator=(const dft_plan_md&) = delete; + dft_plan_md& operator=(dft_plan_md&&) = default; + + bool is_initialized() const { return size.product() != 0; } + + void dump() const + { + for (const auto& d : dfts) + { + d.dump(); + } + } + + explicit dft_plan_md(shape size) : size(std::move(size)), temp_size(0) + { + if constexpr (Dims == dynamic_shape) + { + dfts.resize(this->size.dims()); + } + for (index_t i = 0; i < this->size.dims(); ++i) + { + dfts[i] = dft_plan(this->size[i]); + temp_size = std::max(temp_size, dfts[i].temp_size); + } + internal_generic::dft_initialize_transpose(transpose); + } + + void execute(complex* out, const complex* in, u8* temp, bool inverse = false) const + { + if (inverse) + execute_dft(ctrue, out, in, temp); + else + execute_dft(cfalse, out, in, temp); + } + + template + void execute(const tensor, Dims>& out, const tensor, Dims>& in, u8* temp, + bool inverse = false) const + { + KFR_LOGIC_CHECK(in.shape() == this->size && out.shape() == this->size, + "dft_plan_md: incorrect tensor shapes"); + KFR_LOGIC_CHECK(in.is_contiguous() && out.is_contiguous(), "dft_plan_md: tensors must be contiguous"); + if (inverse) + execute_dft(ctrue, out.data(), in.data(), temp); + else + execute_dft(cfalse, out.data(), in.data(), temp); + } + template + void execute(complex* out, const complex* in, u8* temp, cbool_t = {}) const + { + execute_dft(cbool, out, in, temp); + } + +private: + template + KFR_INTRINSIC void execute_dft(cbool_t, complex* out, const complex* in, u8* temp) const + { + if (temp == nullptr && temp_size > 0) + { + return call_with_temp(temp_size, std::bind(&dft_plan_md::execute_dft, this, + cbool_t{}, out, in, std::placeholders::_1)); + } + if (size.dims() == 1) + { + dfts[0].execute(out, in, temp, cbool); + } + else + { + execute_dim(cbool, out, in, temp); + } + } + KFR_INTRINSIC void execute_dim(cfalse_t, complex* out, const complex* in, u8* temp) const + { + shape sh = size; + index_t total = size.product(); + index_t axis = size.dims() - 1; + for (;;) + { + if (size[axis] > 1) + { + for (index_t o = 0; o < total; o += sh.back()) + dfts[axis].execute(out + o, in + o, temp, cfalse); + } + else + { + builtin_memcpy(out, in, sizeof(complex) * total); + } + + transpose(out, out, shape{ sh.remove_back().product(), sh.back() }); + + if (axis == 0) + break; + + sh = sh.rotate_right(); + in = out; + --axis; + } + } + KFR_INTRINSIC void execute_dim(ctrue_t, complex* out, const complex* in, u8* temp) const + { + shape sh = size; + index_t total = size.product(); + index_t axis = 0; + for (;;) + { + transpose(out, in, shape{ sh.front(), sh.remove_front().product() }); + + if (size[axis] > 1) + { + for (index_t o = 0; o < total; o += sh.front()) + dfts[axis].execute(out + o, out + o, temp, ctrue); + } + + if (axis == size.dims() - 1) + break; + + sh = sh.rotate_left(); + in = out; + ++axis; + } + } + using dft_list = + std::conditional_t>, std::array, Dims>>; + dft_list dfts; + internal_generic::fn_transpose transpose; +}; + +/// @brief Multidimensional DFT +template +struct dft_plan_md_real +{ + shape size; + size_t temp_size; + bool real_out_is_enough; + + dft_plan_md_real(const dft_plan_md_real&) = delete; + dft_plan_md_real(dft_plan_md_real&&) = default; + dft_plan_md_real& operator=(const dft_plan_md_real&) = delete; + dft_plan_md_real& operator=(dft_plan_md_real&&) = default; + + bool is_initialized() const { return size.product() != 0; } + + void dump() const + { + for (const auto& d : dfts) + { + d.dump(); + } + dft_real.dump(); + } + + shape complex_size() const { return complex_size_for(size); } + constexpr static shape complex_size_for(shape size) + { + if (size.dims() > 0) + size.back() = dft_plan_real::complex_size_for(size.back(), dft_pack_format::CCs); + return size; + } + + size_t real_out_size() const { return real_out_size_for(size); } + constexpr static size_t real_out_size_for(shape size) + { + return complex_size_for(size).product() * 2; + } + + explicit dft_plan_md_real(shape size, bool real_out_is_enough = false) + : size(std::move(size)), temp_size(0), real_out_is_enough(real_out_is_enough) + { + if (this->size.dims() > 0) + { + if constexpr (Dims == dynamic_shape) + { + dfts.resize(this->size.dims()); + } + for (index_t i = 0; i < this->size.dims() - 1; ++i) + { + dfts[i] = dft_plan(this->size[i]); + temp_size = std::max(temp_size, dfts[i].temp_size); + } + dft_real = dft_plan_real(this->size.back()); + temp_size = std::max(temp_size, dft_real.temp_size); + } + if (!this->real_out_is_enough) + { + temp_size += complex_size().product() * sizeof(complex); + } + internal_generic::dft_initialize_transpose(transpose); + } + + void execute(complex* out, const T* in, u8* temp, cdirect_t = {}) const + { + execute_dft(cfalse, out, in, temp); + } + void execute(T* out, const complex* in, u8* temp, cinvert_t = {}) const + { + execute_dft(ctrue, out, in, temp); + } + + template + void execute(const tensor, Dims>& out, const tensor& in, u8* temp, + cdirect_t = {}) const + { + KFR_LOGIC_CHECK(in.shape() == this->size && out.shape() == complex_size(), + "dft_plan_md_real: incorrect tensor shapes"); + KFR_LOGIC_CHECK(in.is_contiguous() && out.is_contiguous(), + "dft_plan_md_real: tensors must be contiguous"); + execute_dft(cfalse, out.data(), in.data(), temp); + } + template + void execute(const tensor& out, const tensor, Dims>& in, u8* temp, + cinvert_t = {}) const + { + KFR_LOGIC_CHECK(in.shape() == complex_size() && out.shape() == this->size, + "dft_plan_md_real: incorrect tensor shapes"); + KFR_LOGIC_CHECK(in.is_contiguous() && out.is_contiguous(), + "dft_plan_md_real: tensors must be contiguous"); + execute_dft(ctrue, out.data(), in.data(), temp); + } + void execute(complex* out, const T* in, u8* temp, bool inverse) const + { + KFR_LOGIC_CHECK(inverse, "dft_plan_md_real: incorrect usage"); + execute_dft(cfalse, out, in, temp); + } + void execute(T* out, const complex* in, u8* temp, bool inverse) const + { + KFR_LOGIC_CHECK(!inverse, "dft_plan_md_real: incorrect usage"); + execute_dft(ctrue, out, in, temp); + } + +private: + template + KFR_INTRINSIC void execute_dft(cbool_t, Tout* out, const Tin* in, u8* temp) const + { + if (temp == nullptr && temp_size > 0) + { + return call_with_temp(temp_size, + std::bind(&dft_plan_md_real::execute_dft, this, + cbool_t{}, out, in, std::placeholders::_1)); + } + if (this->size.dims() == 1) + { + dft_real.execute(out, in, temp, cbool); + } + else + { + execute_dim(cbool, out, in, temp); + } + } + void expand(T* out, const T* in, size_t count, size_t last_axis) const + { + size_t last_axis_ex = dft_real.complex_size() * 2; + if (in != out) + { + builtin_memmove(out, in, last_axis * sizeof(T)); + } + in += last_axis * (count - 1); + out += last_axis_ex * (count - 1); + for (size_t i = 1; i < count; ++i) + { + builtin_memmove(out, in, last_axis * sizeof(T)); + in -= last_axis; + out -= last_axis_ex; + } +#ifdef KFR_DEBUG + for (size_t i = 0; i < count; ++i) + { + builtin_memset(out + last_axis, 0xFF, (last_axis_ex - last_axis) * sizeof(T)); + out += last_axis_ex; + } +#endif + } + void contract(T* out, const T* in, size_t count, size_t last_axis) const + { + size_t last_axis_ex = dft_real.complex_size() * 2; + if (in != out) + builtin_memmove(out, in, last_axis * sizeof(T)); + in += last_axis_ex; + out += last_axis; + for (size_t i = 1; i < count; ++i) + { + builtin_memmove(out, in, last_axis * sizeof(T)); + in += last_axis_ex; + out += last_axis; + } + } + KFR_INTRINSIC void execute_dim(cfalse_t, complex* out, const T* in_real, u8* temp) const + { + shape sh = complex_size(); + index_t total = sh.product(); + index_t axis = size.dims() - 1; + expand(ptr_cast(out), in_real, size.remove_back().product(), size.back()); + for (;;) + { + if (size[axis] > 1) + { + if (axis == size.dims() - 1) + for (index_t o = 0; o < total; o += sh.back()) + dft_real.execute(out + o, ptr_cast(out + o), temp, cfalse); + else + for (index_t o = 0; o < total; o += sh.back()) + dfts[axis].execute(out + o, out + o, temp, cfalse); + } + + transpose(out, out, shape{ sh.remove_back().product(), sh.back() }); + + if (axis == 0) + break; + + sh = sh.rotate_right(); + --axis; + } + } + KFR_INTRINSIC void execute_dim(ctrue_t, T* out_real, const complex* in, u8* temp) const + { + shape sh = complex_size(); + index_t total = sh.product(); + complex* out = real_out_is_enough + ? ptr_cast>(out_real) + : ptr_cast>(temp + temp_size - total * sizeof(complex)); + index_t axis = 0; + for (;;) + { + transpose(out, in, shape{ sh.front(), sh.remove_front().product() }); + + if (size[axis] > 1) + { + if (axis == size.dims() - 1) + for (index_t o = 0; o < total; o += sh.front()) + dft_real.execute(ptr_cast(out + o), out + o, temp, ctrue); + else + for (index_t o = 0; o < total; o += sh.front()) + dfts[axis].execute(out + o, out + o, temp, ctrue); + } + + if (axis == size.dims() - 1) + break; + + sh = sh.rotate_left(); + in = out; + ++axis; + } + contract(out_real, ptr_cast(out), size.remove_back().product(), size.back()); + } + using dft_list = std::conditional_t>, + std::array, const_max(Dims, 1) - 1>>; + dft_list dfts; + dft_plan_real dft_real; + internal_generic::fn_transpose transpose; +}; + +/// @brief DCT type 2 (unscaled) +template +struct dct_plan : dft_plan +{ + dct_plan(size_t size) : dft_plan(size) { this->temp_size += sizeof(complex) * size * 2; } + + [[deprecated("cpu parameter is deprecated. Runtime dispatch is used if built with " + "KFR_ENABLE_MULTIARCH")]] dct_plan(cpu_t cpu, size_t size) + : dct_plan(size) + { + } + + KFR_MEM_INTRINSIC void execute(T* out, const T* in, u8* temp, bool inverse = false) const + { + const size_t size = this->size; + const size_t halfSize = size / 2; + univector_ref> mirrored = make_univector( + ptr_cast>(temp + this->temp_size - sizeof(complex) * size * 2), size); + univector_ref> mirrored_dft = + make_univector(ptr_cast>(temp + this->temp_size - sizeof(complex) * size), size); + auto t = counter() * c_pi / (size * 2); + if (!inverse) + { + for (size_t i = 0; i < halfSize; i++) + { + mirrored[i] = in[i * 2]; + mirrored[size - 1 - i] = in[i * 2 + 1]; + } + if (size % 2) + { + mirrored[halfSize] = in[size - 1]; + } + dft_plan::execute(mirrored_dft.data(), mirrored.data(), temp, cfalse); + make_univector(out, size) = real(mirrored_dft) * cos(t) + imag(mirrored_dft) * sin(t); + } + else + { + mirrored = make_complex(make_univector(in, size) * cos(t), make_univector(in, size) * -sin(t)); + mirrored[0] = mirrored[0] * T(0.5); + dft_plan::execute(mirrored_dft.data(), mirrored.data(), temp, cfalse); + for (size_t i = 0; i < halfSize; i++) + { + out[i * 2 + 0] = mirrored_dft[i].real(); + out[i * 2 + 1] = mirrored_dft[size - 1 - i].real(); + } + if (size % 2) + { + out[size - 1] = mirrored_dft[halfSize].real(); + } + } + } + + template + KFR_MEM_INTRINSIC void execute(univector& out, const univector& in, + univector& temp, bool inverse = false) const + { + execute(out.data(), in.data(), temp.data(), inverse); + } +}; + +inline namespace CMT_ARCH_NAME +{ + +template +void fft_multiply(univector, Tag1>& dest, const univector, Tag2>& src1, + const univector, Tag3>& src2, dft_pack_format fmt = dft_pack_format::CCs) +{ + const complex f0(src1[0].real() * src2[0].real(), src1[0].imag() * src2[0].imag()); + + dest = src1 * src2; + + if (fmt == dft_pack_format::Perm) + dest[0] = f0; +} + +template +void fft_multiply_accumulate(univector, Tag1>& dest, const univector, Tag2>& src1, + const univector, Tag3>& src2, + dft_pack_format fmt = dft_pack_format::CCs) +{ + const complex f0(dest[0].real() + src1[0].real() * src2[0].real(), + dest[0].imag() + src1[0].imag() * src2[0].imag()); + + dest = dest + src1 * src2; + + if (fmt == dft_pack_format::Perm) + dest[0] = f0; +} +template +void fft_multiply_accumulate(univector, Tag1>& dest, const univector, Tag2>& src1, + const univector, Tag3>& src2, const univector, Tag4>& src3, + dft_pack_format fmt = dft_pack_format::CCs) +{ + const complex f0(src1[0].real() + src2[0].real() * src3[0].real(), + src1[0].imag() + src2[0].imag() * src3[0].imag()); + + dest = src1 + src2 * src3; + + if (fmt == dft_pack_format::Perm) + dest[0] = f0; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dft/reference_dft.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dft/reference_dft.hpp new file mode 100644 index 00000000..0a1a4596 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dft/reference_dft.hpp @@ -0,0 +1,205 @@ +/** @addtogroup dft + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/memory.hpp" +#include "../base/univector.hpp" +#include "../simd/complex.hpp" +#include "../simd/constants.hpp" +#include "../simd/read_write.hpp" +#include "../simd/vec.hpp" +#include +#include + +namespace kfr +{ + +namespace internal_generic +{ + +template +void reference_dft_po2_pass(size_t N, int flag, const complex* in, complex* out, complex* scratch, + size_t in_delta = 1, size_t out_delta = 1, size_t scratch_delta = 1) +{ + const T pi2 = c_pi; + const size_t N2 = N / 2; + const complex w = pi2 * complex{ 0, -T(flag) }; + + if (N != 2) + { + reference_dft_po2_pass(N2, flag, in, scratch, out, 2 * in_delta, 2 * scratch_delta, 2 * out_delta); + reference_dft_po2_pass(N2, flag, in + in_delta, scratch + scratch_delta, out + out_delta, + 2 * in_delta, 2 * scratch_delta, 2 * out_delta); + + for (size_t k = 0; k < N2; k++) + { + const T m = static_cast(k) / N; + const complex tw = std::exp(w * m); + const complex tmp = scratch[(2 * k + 1) * scratch_delta] * tw; + out[(k + N2) * out_delta] = scratch[(2 * k) * scratch_delta] - tmp; + out[(k)*out_delta] = scratch[(2 * k) * scratch_delta] + tmp; + } + } + else + { + out[out_delta] = in[0] - in[in_delta]; + out[0] = in[0] + in[in_delta]; + } +} + +template +void reference_dft_po2(complex* out, const complex* in, size_t size, bool inversion, + size_t out_delta = 1, size_t in_delta = 1) +{ + if (size < 1) + return; + if (size == 1) + { + out[0] = in[0]; + return; + } + std::vector> temp(size); + reference_dft_po2_pass(size, inversion ? -1 : +1, in, out, temp.data(), in_delta, out_delta, 1); +} + +/// @brief Performs Complex FFT using reference implementation (slow, used for testing) +template +void reference_dft_nonpo2(complex* out, const complex* in, size_t size, bool inversion, + size_t out_delta = 1, size_t in_delta = 1) +{ + constexpr T pi2 = c_pi; + const complex w = pi2 * complex{ 0, T(inversion ? +1 : -1) }; + if (size < 2) + return; + { + complex sum = 0; + for (size_t j = 0; j < size; j++) + sum += in[j * in_delta]; + out[0] = sum; + } + for (size_t i = 1; i < size; i++) + { + complex sum = in[0]; + for (size_t j = 1; j < size; j++) + { + complex tw = std::exp(w * (static_cast(i) * j / size)); + sum += tw * in[j * in_delta]; + } + out[i * out_delta] = sum; + } +} +} // namespace internal_generic + +/// @brief Performs Complex DFT using reference implementation (slow, used for testing) +template +void reference_dft(complex* out, const complex* in, size_t size, bool inversion = false, + size_t out_delta = 1, size_t in_delta = 1) +{ + if (in == out) + { + std::vector> tmpin(size); + for (int i = 0; i < size; ++i) + tmpin[i] = in[i * in_delta]; + return reference_dft(out, tmpin.data(), size, inversion, out_delta, 1); + } + if (is_poweroftwo(size)) + { + return internal_generic::reference_dft_po2(out, in, size, inversion, out_delta, in_delta); + } + else + { + return internal_generic::reference_dft_nonpo2(out, in, size, inversion, out_delta, in_delta); + } +} + +/// @brief Performs Direct Real DFT using reference implementation (slow, used for testing) +template +void reference_dft(complex* out, const T* in, size_t size, size_t out_delta = 1, size_t in_delta = 1) +{ + if (size < 1) + return; + std::vector> tmpin(size); + for (index_t i = 0; i < size; ++i) + tmpin[i] = in[i * in_delta]; + std::vector> tmpout(size); + reference_dft(tmpout.data(), tmpin.data(), size, false, 1, 1); + for (index_t i = 0; i < size / 2 + 1; i++) + out[i * out_delta] = tmpout[i]; +} + +/// @brief Performs Multidimensional Complex DFT using reference implementation (slow, used for testing) +template +void reference_dft_md(complex* out, const complex* in, shape size, + bool inversion = false, size_t out_delta = 1, size_t in_delta = 1) +{ + index_t total = size.product(); + if (total < 1) + return; + if (total == 1) + { + out[0] = in[0]; + return; + } + index_t inner = 1; + index_t outer = total; + for (int axis = size.dims() - 1; axis >= 0; --axis) + { + index_t d = size[axis]; + outer /= d; + for (index_t o = 0; o < outer; ++o) + { + for (index_t i = 0; i < inner; ++i) + { + reference_dft(out + (i + o * inner * d) * out_delta, in + (i + o * inner * d) * in_delta, d, + inversion, out_delta * inner, in_delta * inner); + } + } + in = out; + in_delta = out_delta; + inner *= d; + } +} + +/// @brief Performs Multidimensional Direct Real DFT using reference implementation (slow, used for testing) +template +void reference_dft_md(complex* out, const T* in, shape shape, bool inversion = false, + size_t out_delta = 1, size_t in_delta = 1) +{ + index_t size = shape.product(); + if (size < 1) + return; + std::vector> tmpin(size); + for (index_t i = 0; i < size; ++i) + tmpin[i] = in[i * in_delta]; + std::vector> tmpout(size); + reference_dft_md(tmpout.data(), tmpin.data(), shape, inversion, 1, 1); + index_t last = shape.back() / 2 + 1; + for (index_t i = 0; i < std::max(index_t(1), shape.remove_back().product()); ++i) + for (index_t j = 0; j < last; j++) + out[(i * last + j) * out_delta] = tmpout[i * shape.back() + j]; +} + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp.hpp new file mode 100644 index 00000000..45971ad5 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp.hpp @@ -0,0 +1,44 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "base.hpp" + +#include "dsp/biquad.hpp" +#include "dsp/biquad_design.hpp" +#include "dsp/dcremove.hpp" +#include "dsp/delay.hpp" +#include "dsp/ebu.hpp" +#include "dsp/fir.hpp" +#include "dsp/fir_design.hpp" +#include "dsp/goertzel.hpp" +#include "dsp/iir_design.hpp" +#include "dsp/mixdown.hpp" +#include "dsp/oscillators.hpp" +#include "dsp/sample_rate_conversion.hpp" +#include "dsp/speaker.hpp" +#include "dsp/special.hpp" +#include "dsp/units.hpp" +#include "dsp/waveshaper.hpp" +#include "dsp/weighting.hpp" +#include "dsp/window.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad.hpp new file mode 100644 index 00000000..48b1be8f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad.hpp @@ -0,0 +1,516 @@ +/** @addtogroup biquad + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/filter.hpp" +#include "../base/handle.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/operators.hpp" +#include "../base/state_holder.hpp" +#include "../simd/vec.hpp" +#include "../testo/assert.hpp" + +namespace kfr +{ + +constexpr inline size_t maximum_iir_order = 128; +constexpr inline size_t maximum_biquad_count = maximum_iir_order / 2; + +namespace internal_generic +{ +constexpr inline auto biquad_sizes = csize<1> << csizeseq; +} + +enum class biquad_type +{ + lowpass, + highpass, + bandpass, + bandstop, + peak, + notch, + lowshelf, + highshelf +}; + +/** + * @brief Structure for holding biquad filter coefficients. + */ +template +struct biquad_section +{ + template + constexpr biquad_section(const biquad_section& bq) CMT_NOEXCEPT : a0(static_cast(bq.a0)), + a1(static_cast(bq.a1)), + a2(static_cast(bq.a2)), + b0(static_cast(bq.b0)), + b1(static_cast(bq.b1)), + b2(static_cast(bq.b2)) + { + } + + static_assert(std::is_floating_point_v, "T must be a floating point type"); + constexpr biquad_section() CMT_NOEXCEPT : a0(1), a1(0), a2(0), b0(1), b1(0), b2(0) {} + constexpr biquad_section(T a0, T a1, T a2, T b0, T b1, T b2) CMT_NOEXCEPT : a0(a0), + a1(a1), + a2(a2), + b0(b0), + b1(b1), + b2(b2) + { + } + T a0; + T a1; + T a2; + T b0; + T b1; + T b2; + biquad_section normalized_a0() const + { + vec v{ a1, a2, b0, b1, b2 }; + v = v / a0; + return { T(1.0), v[0], v[1], v[2], v[3], v[4] }; + } + biquad_section normalized_b0() const { return { a0, a1, a2, T(1.0), b1 / b0, b2 / b0 }; } + biquad_section normalized_all() const { return normalized_a0().normalized_b0(); } +}; + +template +struct biquad_state +{ + vec s1; + vec s2; + vec out; + constexpr biquad_state() CMT_NOEXCEPT : s1(0), s2(0), out(0) {} +}; + +template +struct iir_params +{ + vec a1; + vec a2; + vec b0; + vec b1; + vec b2; + + constexpr iir_params() CMT_NOEXCEPT : a1(0), a2(0), b0(1), b1(0), b2(0) {} + CMT_GNU_CONSTEXPR iir_params(const biquad_section* bq, size_t count) + { + KFR_LOGIC_CHECK(count <= filters, "iir_params: too many biquad sections"); + count = const_min(filters, count); + for (size_t i = 0; i < count; i++) + { + a1[i] = bq[i].a1; + a2[i] = bq[i].a2; + b0[i] = bq[i].b0; + b1[i] = bq[i].b1; + b2[i] = bq[i].b2; + } + for (size_t i = count; i < filters; i++) + { + a1[i] = T(0); + a2[i] = T(0); + b0[i] = T(1); + b1[i] = T(0); + b2[i] = T(0); + } + } + + CMT_GNU_CONSTEXPR iir_params(const biquad_section& one) CMT_NOEXCEPT : iir_params(&one, 1) {} + + template + constexpr iir_params(Container&& cont) CMT_NOEXCEPT : iir_params(std::data(cont), std::size(cont)) + { + } +}; + +template +struct iir_params : public std::vector> +{ + using base = std::vector>; + + iir_params() = default; + iir_params(const iir_params&) = default; + iir_params(iir_params&&) = default; + + iir_params(size_t count) : base(count) {} + + iir_params(const biquad_section* bq, size_t count) CMT_NOEXCEPT : base(bq, bq + count) {} + + iir_params(const biquad_section& one) CMT_NOEXCEPT : iir_params(&one, 1) {} + + iir_params(std::vector>&& sections) CMT_NOEXCEPT : base(std::move(sections)) {} + + template + constexpr iir_params(Container&& cont) CMT_NOEXCEPT : iir_params(std::data(cont), std::size(cont)) + { + } + + template + iir_params(const iir_params& params) : base(filters) + { + for (size_t i = 0; i < filters; ++i) + { + this->operator[](i).a0 = T(1); + this->operator[](i).a1 = params.a1[i]; + this->operator[](i).a2 = params.a2[i]; + this->operator[](i).b0 = params.b0[i]; + this->operator[](i).b1 = params.b1[i]; + this->operator[](i).b2 = params.b2[i]; + } + } +}; + +template +iir_params(const std::array&) -> iir_params; +template +iir_params(const univector) -> iir_params; +template +iir_params(const biquad_section (&)[Size]) -> iir_params; +template +iir_params(const biquad_section&) -> iir_params; +template +iir_params(const std::vector>&) -> iir_params; +template +iir_params(std::vector>&&) -> iir_params; + +template +struct iir_state +{ + static_assert(filters >= 1 && filters <= maximum_biquad_count, "Incorrect number of biquad filters"); + + iir_params params; + + template , Args...>>* = nullptr> + iir_state(Args&&... args) : params(std::forward(args)...) + { + } + + biquad_state state; + biquad_state saved_state; + size_t block_end = 0; +}; + +template +iir_state(const iir_params&) -> iir_state; +template +iir_state(iir_params&&) -> iir_state; + +inline namespace CMT_ARCH_NAME +{ + +template +struct expression_iir_l : public expression_with_traits +{ + using value_type = T; + + expression_iir_l(E1&& e1, state_holder, Stateless> state) + : expression_with_traits(std::forward(e1)), state(std::move(state)) + { + } + + mutable state_holder, Stateless> state; +}; + +template +struct expression_iir : expression_with_traits +{ + using value_type = T; + + expression_iir(E1&& e1, state_holder, Stateless> state) + : expression_with_traits(std::forward(e1)), state(std::move(state)) + { + } + + mutable state_holder, Stateless> state; +}; + +namespace internal +{ + +template +KFR_INTRINSIC T biquad_process(vec& out, const iir_params& bq, + biquad_state& state, identity in0, + const vec& delayline) +{ + vec in = insertleft(in0, delayline); + out = bq.b0 * in + state.s1; + state.s1 = state.s2 + bq.b1 * in - bq.a1 * out; + state.s2 = bq.b2 * in - bq.a2 * out; + return out[filters - 1]; +} +template +KFR_INTRINSIC vec biquad_process(iir_state& state, const vec& in, + size_t save_state_after = static_cast(-1)) +{ + vec out; + if (CMT_LIKELY(save_state_after == static_cast(-1))) + { + CMT_LOOP_UNROLL + for (size_t i = 0; i < N; i++) + { + out[i] = biquad_process(state.state.out, state.params, state.state, in[i], state.state.out); + } + } + else + { + for (size_t i = 0; i < save_state_after; i++) + { + out[i] = biquad_process(state.state.out, state.params, state.state, in[i], state.state.out); + } + state.saved_state = state.state; + for (size_t i = save_state_after; i < N; i++) + { + out[i] = biquad_process(state.state.out, state.params, state.state, in[i], state.state.out); + } + } + return out; +} +} // namespace internal + +template +KFR_INTRINSIC vec get_elements(const expression_iir_l& self, shape<1> index, + axis_params<0, N> t) +{ + const vec in = get_elements(self.first(), index, t); + return internal::biquad_process(*self.state, in); +} + +template +KFR_INTRINSIC void begin_pass(const expression_iir<1, T, E1, Stateless>&, shape<1>, shape<1>) +{ +} +template +KFR_INTRINSIC void begin_pass(const expression_iir& self, shape<1> start, shape<1> stop) +{ + size_t size = stop.front(); + self.state->block_end = size; + vec in; + for (index_t i = 0; i < filters - 1; i++) + { + in[i] = i < size ? get_elements(self.first(), shape<1>{ i }, axis_params_v<0, 1>).front() : 0; + } + internal::biquad_process(*self.state, in); +} + +template +KFR_INTRINSIC void end_pass(const expression_iir<1, T, E1, Stateless>&, shape<1>, shape<1>) +{ +} +template +KFR_INTRINSIC void end_pass(const expression_iir& self, shape<1> start, shape<1> stop) +{ + self.state->state = self.state->saved_state; +} + +template +KFR_INTRINSIC vec get_elements(const expression_iir<1, T, E1, Stateless>& self, shape<1> index, + axis_params<0, N> t) +{ + const vec in = get_elements(self.first(), index, t); + return internal::biquad_process(*self.state, in); +} + +template +KFR_INTRINSIC vec get_elements(const expression_iir& self, shape<1> index, + axis_params<0, N> t) +{ + using internal::biquad_process; + index.front() += filters - 1; + vec out{}; + if (index.front() + N <= self.state->block_end) + { + const vec in = get_elements(self.first(), shape<1>{ index.front() }, t); + + out = biquad_process(*self.state, in); + if (index.front() + N == self.state->block_end) + self.state->saved_state = self.state->state; + } + else if (index.front() >= self.state->block_end) + { + out = biquad_process(*self.state, vec(0)); + } + else + { + size_t save_at = std::min(N, self.state->block_end - static_cast(index.front())); + vec in; + for (size_t i = 0; i < save_at; ++i) + in[i] = + get_elements(self.first(), index.add_at(i, cval), axis_params_v<0, 1>).front(); + for (size_t i = save_at; i < N; ++i) + in[i] = 0; + out = biquad_process(*self.state, in, save_at); + } + return out; +} + +/** + * @brief Returns template expressions that applies biquad filter to the input. + * @param e1 Input expression + * @param params Biquad coefficients + */ +template +KFR_FUNCTION expression_iir iir(E1&& e1, iir_params params) +{ + return expression_iir(std::forward(e1), iir_state{ std::move(params) }); +} + +/** + * @brief Returns template expressions that applies biquad filter to the input. + * @param e1 Input expression + * @param params Biquad coefficients + */ +template +KFR_FUNCTION expression_handle iir(E1&& e1, const iir_params& params) +{ + KFR_LOGIC_CHECK(next_poweroftwo(params.size()) <= maximum_biquad_count, "iir: too many biquad sections"); + return cswitch( + internal_generic::biquad_sizes, next_poweroftwo(params.size()), + [&](auto x) + { + constexpr size_t filters = x; + return to_handle(expression_iir( + std::forward(e1), iir_state{ iir_params(params.data(), params.size()) })); + }, + [&] { return to_handle(fixshape(zeros(), fixed_shape)); }); +} + +/** + * @brief Returns template expressions that applies biquad filter to the input. + * @param bq Biquad coefficients + * @param e1 Input expression + */ +template +KFR_FUNCTION expression_iir iir(E1&& e1, + std::reference_wrapper> state) +{ + return expression_iir(std::forward(e1), state); +} + +#define KFR_BIQUAD_DEPRECATED \ + [[deprecated("biquad(param, expr) prototype is deprecated. Use iir(expr, param) with swapped " \ + "arguments")]] + +/** + * @brief Returns template expressions that applies biquad filter to the input. + * @param bq Biquad coefficients + * @param e1 Input expression + */ +template +KFR_BIQUAD_DEPRECATED KFR_FUNCTION expression_iir<1, T, E1> biquad(const biquad_section& bq, E1&& e1) +{ + const biquad_section bqs[1] = { bq }; + return expression_iir<1, T, E1>(std::forward(e1), iir_state{ iir_params{ bqs } }); +} + +/** + * @brief Returns template expressions that applies cascade of biquad filters to the input. + * @param bq Array of biquad coefficients + * @param e1 Input expression + * @note This implementation introduces delay of N - 1 samples, where N is the filter count. + */ +template +KFR_BIQUAD_DEPRECATED KFR_FUNCTION expression_iir_l biquad_l( + const biquad_section (&bq)[filters], E1&& e1) +{ + return expression_iir_l(std::forward(e1), iir_state{ iir_params{ bq } }); +} + +/** + * @brief Returns template expressions that applies cascade of biquad filters to the input. + * @param bq Array of biquad coefficients + * @param e1 Input expression + * @note This implementation has zero latency + */ +template +KFR_BIQUAD_DEPRECATED KFR_FUNCTION expression_iir biquad( + const biquad_section (&bq)[filters], E1&& e1) +{ + return expression_iir(std::forward(e1), iir_state{ iir_params{ bq } }); +} + +/** + * @brief Returns template expressions that applies cascade of biquad filters to the input. + * @param bq Array of biquad coefficients + * @param e1 Input expression + * @note This implementation has zero latency + */ +template +KFR_BIQUAD_DEPRECATED KFR_FUNCTION expression_handle biquad(const biquad_section* bq, size_t count, + E1&& e1) +{ + KFR_LOGIC_CHECK(next_poweroftwo(count) <= maxfiltercount, + "biquad: too many biquad sections. Use higher maxfiltercount"); + return cswitch( + cfilter(internal_generic::biquad_sizes, internal_generic::biquad_sizes <= csize_t{}), + next_poweroftwo(count), + [&](auto x) + { + constexpr size_t filters = x; + return to_handle(expression_iir(std::forward(e1), + iir_state{ iir_params(bq, count) })); + }, + [&] { return to_handle(fixshape(zeros(), fixed_shape)); }); +} + +template +KFR_BIQUAD_DEPRECATED KFR_FUNCTION expression_handle biquad(const std::vector>& bq, + E1&& e1) +{ + return biquad(bq.data(), bq.size(), std::forward(e1)); +} + +template +using expression_biquads_l = expression_iir_l; + +template +using expression_biquads = expression_iir; + +} // namespace CMT_ARCH_NAME + +template +using biquad_params [[deprecated("biquad_params is deprecated. Use biquad_section")]] = biquad_section; + +template +using biquad_blocks [[deprecated("biquad_blocks is deprecated. Use iir_params")]] = iir_params; + +template +class iir_filter : public expression_filter +{ +public: + iir_filter(const iir_params& params); + + [[deprecated("iir_filter(bq, count) is deprecated. Use iir_filter(iir_params{bq, count})")]] iir_filter( + const biquad_section* bq, size_t count) + : iir_filter(iir_params(bq, count)) + { + } +}; + +template +using biquad_filter [[deprecated("biquad_filter is deprecated. Use iir_filter")]] = iir_filter; +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad_design.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad_design.hpp new file mode 100644 index 00000000..27f93626 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/biquad_design.hpp @@ -0,0 +1,249 @@ +/** @addtogroup biquad + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "biquad.hpp" +#include + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Calculates coefficients for the all-pass biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_allpass(identity frequency, identity Q) +{ + const T alpha = std::sin(frequency) / 2.0 * Q; + const T cs = std::cos(frequency); + + const T b0 = 1.0 / (1.0 + alpha); + const T b1 = -2.0 * cs * b0; + const T b2 = (1.0 - alpha) * b0; + const T a0 = (1.0 - alpha) * b0; + const T a1 = -2.0 * cs * b0; + const T a2 = (1.0 + alpha) * b0; + return { b0, b1, b2, a0, a1, a2 }; +} + +/** + * @brief Calculates coefficients for the low-pass biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_lowpass(identity frequency, identity Q) +{ + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T norm = 1 / (1 + K / Q + K2); + const T a0 = K2 * norm; + const T a1 = 2 * a0; + const T a2 = a0; + const T b1 = 2 * (K2 - 1) * norm; + const T b2 = (1 - K / Q + K2) * norm; + return { 1.0, b1, b2, a0, a1, a2 }; +} + +/** + * @brief Calculates coefficients for the high-pass biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_highpass(identity frequency, identity Q) +{ + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T norm = 1 / (1 + K / Q + K2); + const T a0 = 1 * norm; + const T a1 = -2 * a0; + const T a2 = a0; + const T b1 = 2 * (K2 - 1) * norm; + const T b2 = (1 - K / Q + K2) * norm; + return { 1.0, b1, b2, a0, a1, a2 }; +} + +/** + * @brief Calculates coefficients for the band-pass biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_bandpass(identity frequency, identity Q) +{ + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T norm = 1 / (1 + K / Q + K2); + const T a0 = K / Q * norm; + const T a1 = 0; + const T a2 = -a0; + const T b1 = 2 * (K2 - 1) * norm; + const T b2 = (1 - K / Q + K2) * norm; + return { 1.0, b1, b2, a0, a1, a2 }; +} + +/** + * @brief Calculates coefficients for the notch biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_notch(identity frequency, identity Q) +{ + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T norm = 1 / (1 + K / Q + K2); + const T a0 = (1 + K2) * norm; + const T a1 = 2 * (K2 - 1) * norm; + const T a2 = a0; + const T b1 = a1; + const T b2 = (1 - K / Q + K2) * norm; + return { 1.0, b1, b2, a0, a1, a2 }; +} + +/** + * @brief Calculates coefficients for the peak biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param Q Q factor + * @param gain Gain in dB + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_peak(identity frequency, identity Q, identity gain) +{ + biquad_section result; + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T V = std::exp(std::abs(gain) * (1.0 / 20.0) * c_log_10); + + if (gain >= 0) + { // boost + const T norm = 1 / (1 + 1 / Q * K + K2); + const T a0 = (1 + V / Q * K + K2) * norm; + const T a1 = 2 * (K2 - 1) * norm; + const T a2 = (1 - V / Q * K + K2) * norm; + const T b1 = a1; + const T b2 = (1 - 1 / Q * K + K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + else + { // cut + const T norm = 1 / (1 + V / Q * K + K2); + const T a0 = (1 + 1 / Q * K + K2) * norm; + const T a1 = 2 * (K2 - 1) * norm; + const T a2 = (1 - 1 / Q * K + K2) * norm; + const T b1 = a1; + const T b2 = (1 - V / Q * K + K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + return result; +} + +/** + * @brief Calculates coefficients for the low-shelf biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param gain Gain in dB + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_lowshelf(identity frequency, identity gain) +{ + biquad_section result; + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T V = std::exp(std::fabs(gain) * (1.0 / 20.0) * c_log_10); + + if (gain >= 0) + { // boost + const T norm = 1 / (1 + c_sqrt_2 * K + K2); + const T a0 = (1 + std::sqrt(2 * V) * K + V * K2) * norm; + const T a1 = 2 * (V * K2 - 1) * norm; + const T a2 = (1 - std::sqrt(2 * V) * K + V * K2) * norm; + const T b1 = 2 * (K2 - 1) * norm; + const T b2 = (1 - c_sqrt_2 * K + K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + else + { // cut + const T norm = 1 / (1 + std::sqrt(2 * V) * K + V * K2); + const T a0 = (1 + c_sqrt_2 * K + K2) * norm; + const T a1 = 2 * (K2 - 1) * norm; + const T a2 = (1 - c_sqrt_2 * K + K2) * norm; + const T b1 = 2 * (V * K2 - 1) * norm; + const T b2 = (1 - std::sqrt(2 * V) * K + V * K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + return result; +} + +/** + * @brief Calculates coefficients for the high-shelf biquad filter + * @param frequency Normalized frequency (frequency_Hz / samplerate_Hz) + * @param gain Gain in dB + * @return Biquad filter coefficients + */ +template +KFR_FUNCTION biquad_section biquad_highshelf(identity frequency, identity gain) +{ + biquad_section result; + const T K = std::tan(c_pi * frequency); + const T K2 = K * K; + const T V = std::exp(std::fabs(gain) * (1.0 / 20.0) * c_log_10); + + if (gain >= 0) + { // boost + const T norm = 1 / (1 + c_sqrt_2 * K + K2); + const T a0 = (V + std::sqrt(2 * V) * K + K2) * norm; + const T a1 = 2 * (K2 - V) * norm; + const T a2 = (V - std::sqrt(2 * V) * K + K2) * norm; + const T b1 = 2 * (K2 - 1) * norm; + const T b2 = (1 - c_sqrt_2 * K + K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + else + { // cut + const T norm = 1 / (V + std::sqrt(2 * V) * K + K2); + const T a0 = (1 + c_sqrt_2 * K + K2) * norm; + const T a1 = 2 * (K2 - 1) * norm; + const T a2 = (1 - c_sqrt_2 * K + K2) * norm; + const T b1 = 2 * (K2 - V) * norm; + const T b2 = (V - std::sqrt(2 * V) * K + K2) * norm; + result = { 1.0, b1, b2, a0, a1, a2 }; + } + return result; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/dcremove.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/dcremove.hpp new file mode 100644 index 00000000..259ae417 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/dcremove.hpp @@ -0,0 +1,41 @@ +/** @addtogroup biquad + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "biquad.hpp" +#include "biquad_design.hpp" + +namespace kfr +{ + +template >> +KFR_INTRINSIC expression_iir<1, T, E1> dcremove(E1&& e1, double cutoff = 0.00025) +{ + const biquad_section bqs[1] = { biquad_highpass(cutoff, 0.5) }; + return expression_iir<1, T, E1>(bqs, std::forward(e1)); +} + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/delay.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/delay.hpp new file mode 100644 index 00000000..830be9d3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/delay.hpp @@ -0,0 +1,220 @@ +/** @addtogroup fir + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/expression.hpp" +#include "../base/state_holder.hpp" +#include "../base/univector.hpp" +#include "fir.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +struct delay_state +{ + template + delay_state() : data({ 0 }), cursor(0) + { + } + + template + delay_state() : data(samples), cursor(0) + { + } + + univector data; + size_t cursor; +}; + +template +struct delay_state +{ + T data = T(0); +}; + +template +struct expression_delay : expression_with_arguments, public expression_traits_defaults +{ + using ArgTraits = expression_traits; + static_assert(ArgTraits::dims == 1, "expression_delay requires argument with dims == 1"); + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = 1; + constexpr static shape get_shape(const expression_delay& self) + { + return ArgTraits::get_shape(self.first()); + } + constexpr static shape get_shape() { return ArgTraits::get_shape(); } + constexpr static inline bool random_access = false; + + using T = value_type; + using expression_with_arguments::expression_with_arguments; + + expression_delay(E&& e, state_holder, stateless> state) + : expression_with_arguments(std::forward(e)), state(std::move(state)) + { + } + + template + friend KFR_INTRINSIC vec get_elements(const expression_delay& self, shape<1> index, + axis_params<0, N> sh) + { + vec out; + size_t c = self.state->cursor; + self.state->data.ringbuf_read(c, out); + const vec in = get_elements(self.first(), index, sh); + self.state->data.ringbuf_write(self.state->cursor, in); + return out; + } + friend vec get_elements(const expression_delay& self, shape<1> index, axis_params<0, 1> sh) + { + T out; + size_t c = self.state->cursor; + self.state->data.ringbuf_read(c, out); + const T in = get_elements(self.first(), index, sh).front(); + self.state->data.ringbuf_write(self.state->cursor, in); + return out; + } + template delay)> + friend vec get_elements(const expression_delay& self, shape<1> index, axis_params<0, N> sh) + { + vec out; + size_t c = self.state->cursor; + self.state->data.ringbuf_read(c, out); + const vec in = get_elements(self.first(), index, sh); + self.state->data.ringbuf_write(self.state->cursor, slice(in)); + return concat_and_slice<0, N>(out, in); + } + + mutable state_holder, stateless> state; +}; + +template +struct expression_delay<1, E, stateless, STag> : expression_with_arguments, expression_traits_defaults +{ + using ArgTraits = expression_traits; + static_assert(ArgTraits::dims == 1, "expression_delay requires argument with dims == 1"); + using value_type = typename ArgTraits::value_type; + constexpr static size_t dims = 1; + constexpr static shape get_shape(const expression_delay& self) + { + return ArgTraits::get_shape(self.first()); + } + constexpr static shape get_shape() { return ArgTraits::get_shape(); } + constexpr static inline bool random_access = false; + + using T = value_type; + using expression_with_arguments::expression_with_arguments; + + expression_delay(E&& e, const delay_state& state) + : expression_with_arguments(std::forward(e)), state(state) + { + } + + template + friend KFR_INTRINSIC vec get_elements(const expression_delay& self, shape<1> index, + axis_params<0, N> sh) + { + const vec in = get_elements(self.first(), index, sh); + const vec out = insertleft(self.state->data, in); + self.state->data = in[N - 1]; + return out; + } + mutable state_holder, stateless> state; +}; + +/** + * @brief Returns template expression that applies delay to the input (uses ring buffer internally) + * @param e1 an input expression + * @param samples delay in samples (must be a compile time value) + * @code + * univector v = counter(); + * auto d = delay(v, csize<4>); + * @endcode + */ +template > +KFR_INTRINSIC expression_delay delay(E1&& e1) +{ + static_assert(samples >= 1 && samples < 1024, ""); + return expression_delay(std::forward(e1), delay_state()); +} + +/** + * @brief Returns template expression that applies delay to the input (uses ring buffer in state) + * @param state delay filter state (taken by reference) + * @param e1 an input expression + * @code + * univector v = counter(); + * delay_state state; + * auto d = delay(state, v); + * @endcode + */ +template +KFR_INTRINSIC expression_delay delay( + E1&& e1, std::reference_wrapper> state) +{ + static_assert(STag == tag_dynamic_vector || (samples >= 1 && samples < 1024), ""); + return expression_delay(std::forward(e1), state); +} + +/** + * @brief Returns template expression that applies delay to the input (uses ring buffer in state) + * @param state delay filter state + * @param e1 an input expression + * @code + * univector v = counter(); + * delay_state state; + * auto d = delay(state, v); + * @endcode + */ +template +[[deprecated("delay(state, expr) is deprecated. Use delay(expr, std::ref(state))")]] KFR_INTRINSIC + expression_delay + delay(delay_state& state, E1&& e1) +{ + static_assert(STag == tag_dynamic_vector || (samples >= 1 && samples < 1024), ""); + return expression_delay(std::forward(e1), std::ref(state)); +} + +/** + * @brief Returns template expression that applies a fractional delay to the input + * @param e1 an input expression + * @param e1 a fractional delay in range 0..1 + */ +template +KFR_INTRINSIC expression_short_fir<2, T, expression_value_type, E1> fracdelay(E1&& e1, T delay) +{ + if (CMT_UNLIKELY(delay < 0)) + delay = 0; + univector taps({ 1 - delay, delay }); + return expression_short_fir<2, T, expression_value_type, E1>( + std::forward(e1), short_fir_state<2, T, expression_value_type>{ taps }); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/ebu.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/ebu.hpp new file mode 100644 index 00000000..b3cfbcdb --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/ebu.hpp @@ -0,0 +1,364 @@ +/** @addtogroup ebu + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include + +#include "../base.hpp" +#include "../testo/assert.hpp" +#include "biquad.hpp" +#include "biquad_design.hpp" +#include "speaker.hpp" +#include "units.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Winaccessible-base") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Winaccessible-base") +#endif + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC T energy_to_loudness(T energy) +{ + return T(10) * log10(energy) - T(0.691); +} + +template +KFR_INTRINSIC T loudness_to_energy(T loudness) +{ + return exp10((loudness + T(0.691)) * T(0.1)); +} + +template +struct integrated_vec : public univector +{ +private: + void compute() const + { + const T z_total = mean(static_cast&>(*this)); + T relative_gate = energy_to_loudness(z_total) - 10; + + T z = 0; + size_t num = 0; + for (T v : *this) + { + T lk = energy_to_loudness(v); + if (lk >= relative_gate) + { + z += v; + num++; + } + } + z /= num; + if (num >= 1) + { + m_integrated = energy_to_loudness(z); + } + else + { + m_integrated = -c_infinity; + } + + m_integrated_cached = true; + } + +public: + integrated_vec() : m_integrated(-c_infinity), m_integrated_cached(false) {} + void push(T mean_square) + { + T lk = energy_to_loudness(mean_square); + if (lk >= T(-70.)) + { + this->push_back(mean_square); + m_integrated_cached = false; + } + } + void reset() + { + m_integrated_cached = false; + this->clear(); + } + T get() const + { + if (!m_integrated_cached) + { + compute(); + } + return m_integrated; + } + +private: + mutable T m_integrated; + mutable bool m_integrated_cached; +}; + +template +struct lra_vec : public univector +{ +private: + void compute() const + { + m_range_high = -70; + m_range_low = -70; + static const T PRC_LOW = T(0.10); + static const T PRC_HIGH = T(0.95); + + const T z_total = mean(static_cast&>(*this)); + const T relative_gate = energy_to_loudness(z_total) - 20; + + if (this->size() < 2) + return; + + const size_t start_index = + std::upper_bound(this->begin(), this->end(), loudness_to_energy(relative_gate)) - this->begin(); + if (this->size() - start_index < 2) + return; + const size_t end_index = this->size() - 1; + + const size_t low_index = + static_cast(std::llround(start_index + (end_index - start_index) * PRC_LOW)); + const size_t high_index = + static_cast(std::llround(start_index + (end_index - start_index) * PRC_HIGH)); + m_range_low = energy_to_loudness((*this)[low_index]); + m_range_high = energy_to_loudness((*this)[high_index]); + + m_lra_cached = true; + } + +public: + lra_vec() : m_range_low(-70), m_range_high(-70), m_lra_cached(false) {} + void push(T mean_square) + { + const T lk = energy_to_loudness(mean_square); + if (lk >= -70) + { + auto it = std::upper_bound(this->begin(), this->end(), mean_square); + this->insert(it, mean_square); + m_lra_cached = false; + } + } + void reset() + { + m_lra_cached = false; + this->clear(); + } + void get(T& low, T& high) const + { + if (!m_lra_cached) + compute(); + low = m_range_low; + high = m_range_high; + } + +private: + mutable T m_range_low; + mutable T m_range_high; + mutable bool m_lra_cached; +}; + +template +KFR_INTRINSIC expression_handle make_kfilter(int samplerate) +{ + const biquad_section bq[] = { + biquad_highshelf(T(1681.81 / samplerate), T(+4.0)), + biquad_highpass(T(38.1106678246655 / samplerate), T(0.5)).normalized_all() + }; + return to_handle(iir(placeholder(), iir_params{ bq })); +} + +template +struct ebu_r128; + +template +struct ebu_channel +{ +public: + friend struct ebu_r128; + ebu_channel(int sample_rate, Speaker speaker, int packet_size_factor = 1, T input_gain = 1) + : m_sample_rate(sample_rate), m_speaker(speaker), m_input_gain(input_gain), + m_packet_size(sample_rate / 10 / packet_size_factor), m_kfilter(make_kfilter(sample_rate)), + m_short_sum_of_squares(3000 / 100 * packet_size_factor), + m_momentary_sum_of_squares(400 / 100 * packet_size_factor), m_output_energy_gain(1.0), + m_buffer_cursor(0), m_short_sum_of_squares_cursor(0), m_momentary_sum_of_squares_cursor(0) + { + switch (speaker) + { + case Speaker::Lfe: + case Speaker::Lfe2: + m_output_energy_gain = 0.0; + break; + case Speaker::LeftSurround: + case Speaker::RightSurround: + m_output_energy_gain = static_cast(dB_to_power(+1.5)); + break; + default: + break; + } + reset(); + } + + void reset() + { + std::fill(m_short_sum_of_squares.begin(), m_short_sum_of_squares.end(), T(0)); + std::fill(m_momentary_sum_of_squares.begin(), m_momentary_sum_of_squares.end(), T(0)); + } + + void process_packet(const T* src) + { + substitute(m_kfilter, to_handle(make_univector(src, m_packet_size) * m_input_gain)); + const T filtered_sum_of_squares = sumsqr(truncate(m_kfilter, m_packet_size)); + + m_short_sum_of_squares.ringbuf_write(m_short_sum_of_squares_cursor, filtered_sum_of_squares); + m_momentary_sum_of_squares.ringbuf_write(m_momentary_sum_of_squares_cursor, filtered_sum_of_squares); + } + Speaker get_speaker() const { return m_speaker; } + +private: + const int m_sample_rate; + const Speaker m_speaker; + const T m_input_gain; + const size_t m_packet_size; + expression_handle m_kfilter; + univector m_short_sum_of_squares; + univector m_momentary_sum_of_squares; + T m_output_energy_gain; + univector m_buffer; + size_t m_buffer_cursor; + size_t m_short_sum_of_squares_cursor; + size_t m_momentary_sum_of_squares_cursor; +}; + +template +struct ebu_r128 +{ +public: + // Correct values for packet_size_factor: 1 (10Hz refresh rate), 2 (20Hz), 3 (30Hz) + ebu_r128(int sample_rate, const std::vector& channels, int packet_size_factor = 1) + : m_sample_rate(sample_rate), m_running(true), m_need_reset(false), + m_packet_size(sample_rate / 10 / packet_size_factor) + { + KFR_LOGIC_CHECK(!channels.empty(), "channels must not be empty"); + KFR_LOGIC_CHECK(sample_rate > 0, "sample_rate must be greater than 0"); + KFR_LOGIC_CHECK(packet_size_factor >= 1 && packet_size_factor <= 6, + "packet_size_factor must be in range [1..6]"); + for (Speaker sp : channels) + { + m_channels.emplace_back(sample_rate, sp, packet_size_factor, T(1)); + } + } + + int sample_rate() const { return m_sample_rate; } + + size_t packet_size() const { return m_packet_size; } + + void get_values(T& loudness_momentary, T& loudness_short, T& loudness_intergrated, T& loudness_range_low, + T& loudness_range_high) + { + T sum_of_mean_square_momentary = 0; + T sum_of_mean_square_short = 0; + for (size_t ch = 0; ch < m_channels.size(); ch++) + { + sum_of_mean_square_momentary += mean(m_channels[ch].m_momentary_sum_of_squares) / m_packet_size * + m_channels[ch].m_output_energy_gain; + sum_of_mean_square_short += mean(m_channels[ch].m_short_sum_of_squares) / m_packet_size * + m_channels[ch].m_output_energy_gain; + } + loudness_momentary = energy_to_loudness(sum_of_mean_square_momentary); + loudness_short = energy_to_loudness(sum_of_mean_square_short); + loudness_intergrated = m_integrated_buffer.get(); + m_lra_buffer.get(loudness_range_low, loudness_range_high); + } + + const ebu_channel& operator[](size_t index) const { return m_channels[index]; } + size_t count() const { return m_channels.size(); } + + void process_packet(const std::initializer_list>& source) + { + process_packet(source); + } + void process_packet(const std::initializer_list>& source) + { + process_packet(source); + } + + template + void process_packet(const std::vector>& source) + { + T momentary = 0; + T shortterm = 0; + for (size_t ch = 0; ch < m_channels.size(); ch++) + { + TESTO_ASSERT(source[ch].size() == m_packet_size); + ebu_channel& chan = m_channels[ch]; + chan.process_packet(source[ch].data()); + if (m_running) + { + momentary += mean(m_channels[ch].m_momentary_sum_of_squares) / m_packet_size * + m_channels[ch].m_output_energy_gain; + shortterm += mean(m_channels[ch].m_short_sum_of_squares) / m_packet_size * + m_channels[ch].m_output_energy_gain; + } + } + + if (m_need_reset) + { + m_need_reset = false; + for (size_t ch = 0; ch < m_channels.size(); ch++) + { + m_channels[ch].reset(); + } + m_integrated_buffer.reset(); + m_lra_buffer.reset(); + } + if (m_running) + { + m_integrated_buffer.push(momentary); + m_lra_buffer.push(shortterm); + } + } + + void start() { m_running = true; } + void stop() { m_running = false; } + void reset() { m_need_reset = true; } + +private: + int m_sample_rate; + bool m_running; + bool m_need_reset; + size_t m_packet_size; + std::vector> m_channels; + integrated_vec m_integrated_buffer; + lra_vec m_lra_buffer; +}; + +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir.hpp new file mode 100644 index 00000000..d1a8918b --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir.hpp @@ -0,0 +1,429 @@ +/** @addtogroup fir + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/filter.hpp" +#include "../base/memory.hpp" +#include "../base/reduce.hpp" +#include "../base/simd_expressions.hpp" +#include "../base/state_holder.hpp" +#include "../base/univector.hpp" +#include "../simd/vec.hpp" + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4244)) + +namespace kfr +{ + +template +using fir_taps = univector; + +template +struct short_fir_state +{ + template + short_fir_state(const univector& taps) + : taps(widen(read(taps.data()), T(0))), delayline(0) + { + } + template + short_fir_state(const univector& taps) + : taps(widen(read(taps.data()), T(0))), delayline(0) + { + } + vec taps; + vec delayline; +}; + +template +struct fir_params +{ + univector taps; + + fir_params(const fir_params&) = default; + fir_params(fir_params&&) = default; + fir_params& operator=(const fir_params&) = default; + fir_params& operator=(fir_params&&) = default; + + fir_params(const T* data, size_t size) : taps(reverse(make_univector(data, size))) {} + + fir_params(univector&& taps) : taps(std::move(taps)) + { + std::reverse(this->taps.begin(), this->taps.end()); + } + + template + fir_params(Cont&& taps) : fir_params(std::data(taps), std::size(taps)) + { + } +}; + +template +fir_params(Cont&&) -> fir_params>>; + +template +struct fir_state +{ + fir_state(const fir_state&) = default; + fir_state(fir_state&&) = default; + fir_state& operator=(const fir_state&) = default; + fir_state& operator=(fir_state&&) = default; + + fir_state(fir_params params) + : params(std::move(params)), delayline(this->params.taps.size(), U(0)), delayline_cursor(0) + { + } + template + fir_state(Cont&& taps) : params(std::move(taps)), delayline(params.taps.size(), U(0)), delayline_cursor(0) + { + } + template + void push_delayline(Cont&& state) + { + delayline.ringbuf_write(delayline_cursor, std::data(state), std::size(state)); + } + fir_params params; + univector delayline; + size_t delayline_cursor; +}; + +template +fir_state(Cont&&) -> fir_state>; + +template +struct moving_sum_state +{ + moving_sum_state() : delayline({ 0 }), head_cursor(0), tail_cursor(1) {} + univector delayline; + size_t head_cursor, tail_cursor; +}; +template +struct moving_sum_state +{ + moving_sum_state(size_t sum_length) : delayline(sum_length, U(0)), head_cursor(0), tail_cursor(1) {} + univector delayline; + size_t head_cursor, tail_cursor; +}; + +inline namespace CMT_ARCH_NAME +{ + +template +struct expression_short_fir : expression_with_traits +{ + using value_type = U; // override value_type + + static_assert(expression_traits::dims == 1, "expression_short_fir requires input with dims == 1"); + constexpr static inline bool random_access = false; + + expression_short_fir(E1&& e1, state_holder, stateless> state) + : expression_with_traits(std::forward(e1)), state(std::move(state)) + { + } + + template + KFR_INTRINSIC friend vec get_elements(const expression_short_fir& self, shape<1> index, + axis_params<0, N> sh) + { + vec in = get_elements(self.first(), index, sh); + + vec out = in * self.state->taps.front(); + cforeach(csizeseq, + [&](auto I) { + out = out + concat_and_slice(self.state->delayline, in) * + self.state->taps[I]; + }); + self.state->delayline = concat_and_slice(self.state->delayline, in); + + return out; + } + mutable state_holder, stateless> state; +}; + +template +struct expression_fir : expression_with_traits +{ + using value_type = U; // override value_type + + static_assert(expression_traits::dims == 1, "expression_fir requires input with dims == 1"); + constexpr static inline bool random_access = false; + + expression_fir(E1&& e1, state_holder, stateless> state) + : expression_with_traits(std::forward(e1)), state(std::move(state)) + { + } + + template + KFR_INTRINSIC friend vec get_elements(const expression_fir& self, shape<1> index, + axis_params<0, N> sh) + { + const size_t tapcount = self.state->params.taps.size(); + const vec input = get_elements(self.first(), index, sh); + + vec output; + size_t cursor = self.state->delayline_cursor; + CMT_LOOP_NOUNROLL + for (size_t i = 0; i < N; i++) + { + self.state->delayline.ringbuf_write(cursor, input[i]); + U v = dotproduct(self.state->params.taps.slice(0, tapcount - cursor), + self.state->delayline.slice(cursor)); + if (cursor > 0) + v = v + dotproduct(self.state->params.taps.slice(tapcount - cursor), + self.state->delayline.slice(0, cursor)); + output[i] = v; + } + self.state->delayline_cursor = cursor; + return output; + } + mutable state_holder, stateless> state; +}; + +template +struct expression_moving_sum : expression_with_traits +{ + using value_type = U; // override value_type + + static_assert(expression_traits::dims == 1, "expression_moving_sum requires input with dims == 1"); + constexpr static inline bool random_access = false; + + expression_moving_sum(E1&& e1, state_holder, stateless> state) + : expression_with_traits(std::forward(e1)), state(std::move(state)) + { + } + + template + KFR_INTRINSIC friend vec get_elements(const expression_moving_sum& self, shape<1> index, + axis_params<0, N> sh) + { + const vec input = get_elements(self.first(), index, sh); + + vec output; + size_t wcursor = self.state->head_cursor; + size_t rcursor = self.state->tail_cursor; + + // initial summation + self.state->delayline.ringbuf_write(wcursor, input[0]); + auto s = sum(self.state->delayline); + output[0] = s; + + CMT_LOOP_NOUNROLL + for (size_t i = 1; i < N; i++) + { + U nextout; + self.state->delayline.ringbuf_read(rcursor, nextout); + const U nextin = input[i]; + self.state->delayline.ringbuf_write(wcursor, nextin); + s += nextin - nextout; + output[i] = s; + } + self.state->delayline.ringbuf_step(rcursor, 1); + self.state->head_cursor = wcursor; + self.state->tail_cursor = rcursor; + return output; + } + mutable state_holder, stateless> state; +}; + +/** + * @brief Returns template expression that applies FIR filter to the input + * @param e1 an input expression + * @param taps coefficients for the FIR filter (taken by value) + */ +template , typename Taps, + typename T = std::remove_cv_t>> +[[deprecated("fir(expr, taps) is deprecated. Use fir(expr, fir_params{taps})")]] KFR_INTRINSIC expression_fir< + T, U, E1, false> +fir(E1&& e1, Taps&& taps) +{ + return expression_fir(std::forward(e1), fir_state{ std::forward(taps) }); +} + +/** + * @brief Returns template expression that applies FIR filter to the input + * @param e1 an input expression + * @param state coefficients for the FIR filter (taken by value) + */ +template > +KFR_INTRINSIC expression_fir fir(E1&& e1, fir_params state) +{ + return expression_fir(std::forward(e1), fir_state{ std::move(state) }); +} + +/** + * @brief Returns template expression that applies FIR filter to the input + * @param e1 an input expression + * @param state coefficients and state of the filter (taken by reference, ensure proper lifetime) + */ +template +KFR_INTRINSIC expression_fir fir(E1&& e1, std::reference_wrapper> state) +{ + static_assert(std::is_same_v>, "fir: type mismatch"); + return expression_fir(std::forward(e1), state); +} + +/** + * @brief Returns template expression that applies FIR filter to the input + * @param state FIR filter state (state is referenced, ensure proper lifetime) + * @param e1 an input expression + */ +template +[[deprecated("fir(state, expr) is deprecated. Use fir(expr, std::ref(state))")]] KFR_INTRINSIC expression_fir< + T, U, E1, true> +fir(fir_state& state, E1&& e1) +{ + return fir(std::forward(e1), std::reference_wrapper>(state)); +} + +/** + * @brief Returns template expression that performs moving sum on the input + * @param e1 an input expression + */ +template +KFR_INTRINSIC expression_moving_sum, E1, tag_dynamic_vector> moving_sum( + E1&& e1, size_t sum_length) +{ + return expression_moving_sum, E1, tag_dynamic_vector>( + std::forward(e1), moving_sum_state, tag_dynamic_vector>{ sum_length }); +} + +/** + * @brief Returns template expression that performs moving sum on the input + * @param e1 an input expression + */ +template +[[deprecated("moving_sum is deprecated. Use moving_sum(expr, len) instead")]] KFR_INTRINSIC + expression_moving_sum, E1, tag_dynamic_vector> + moving_sum(E1&& e1) +{ + return expression_moving_sum, E1, tag_dynamic_vector>( + std::forward(e1), moving_sum_state, tag_dynamic_vector>{ sum_length }); +} + +/** + * @brief Returns template expression that performs moving sum on the input + * @param e1 an input expression + * @param state State (taken by reference) + */ +template +KFR_INTRINSIC expression_moving_sum moving_sum( + E1&& e1, std::reference_wrapper> state) +{ + return expression_moving_sum, E1, Tag, true>(std::forward(e1), state); +} + +/** + * @brief Returns template expression that performs moving sum on the input + * @param state moving sum state + * @param e1 an input expression + */ +template +[[deprecated("moving_sum(state, expr) is deprecated. Use moving_sum(expr, std::ref(state)) " + "instead")]] KFR_INTRINSIC expression_moving_sum +moving_sum(moving_sum_state& state, E1&& e1) +{ + return moving_sum(std::forward(e1), std::ref(state)); +} + +/** + * @brief Returns template expression that applies FIR filter to the input (count of coefficients must be in + * range 2..32) + * @param e1 an input expression + * @param taps coefficients for the FIR filter + */ +template > +KFR_INTRINSIC expression_short_fir short_fir( + E1&& e1, const univector& taps) +{ + static_assert(TapCount >= 2 && TapCount <= 33, "Use short_fir only for small FIR filters"); + return expression_short_fir( + std::forward(e1), short_fir_state{ taps }); +} +/** + * @brief Returns template expression that applies FIR filter to the input (count of coefficients must be in + * range 2..32) + * @param e1 an input expression + * @param state FIR filter state (state is referenced, ensure proper lifetime) + */ +template +KFR_INTRINSIC expression_short_fir short_fir( + E1&& e1, std::reference_wrapper> state) +{ + static_assert(std::is_same_v>, "short_fir: type mismatch"); + static_assert(TapCount >= 2 && TapCount <= 33, "Use short_fir only for small FIR filters"); + return expression_short_fir(std::forward(e1), state); +} + +/** + * @brief Returns template expression that applies FIR filter to the input (count of coefficients must be in + * range 2..32) + * @param state FIR filter state + * @param e1 an input expression + */ +template +[[deprecated("short_fir(state, expr) is deprecated, use short_fir(expr, std::ref(state))")]] KFR_INTRINSIC + expression_short_fir, E1, true> + short_fir(short_fir_state& state, E1&& e1) +{ + static_assert(InternalTapCount == next_poweroftwo(TapCount - 1) + 1, "short_fir: TapCount mismatch"); + return short_fir(std::forward(e1), std::ref(state)); +} + +} // namespace CMT_ARCH_NAME + +template +class fir_filter : public filter +{ +public: + fir_filter(fir_state state) : state(std::move(state)) {} + + void set_taps(fir_params params) { state = std::move(params); } + void set_params(fir_params params) { state = std::move(params); } + + /// Reset internal filter state + void reset() final + { + state.delayline = scalar(0); + state.delayline_cursor = 0; + } + +protected: + void process_buffer(U* dest, const U* src, size_t size) final; + void process_expression(U* dest, const expression_handle& src, size_t size) final; + + fir_state state; +}; + +template +using filter_fir = fir_filter; + +} // namespace kfr + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir_design.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir_design.hpp new file mode 100644 index 00000000..827457c8 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/fir_design.hpp @@ -0,0 +1,222 @@ +/** @addtogroup fir + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../math/sin_cos.hpp" +#include "fir.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ +template +void fir_lowpass(univector_ref taps, T cutoff, const expression_handle& window, bool normalize = true) +{ + const T scale = 2.0 * cutoff; + taps = bind_expression(fn::sinc(), symmlinspace((taps.size() - 1) * cutoff * c_pi, taps.size())) * + scale * window; + + if (is_odd(taps.size())) + taps[taps.size() / 2] = scale; + + if (normalize) + { + const T invsum = reciprocal(sum(taps)); + taps = taps * invsum; + } +} +template +void fir_highpass(univector_ref taps, T cutoff, const expression_handle& window, bool normalize = true) +{ + const T scale = 2.0 * -cutoff; + taps = bind_expression(fn::sinc(), symmlinspace((taps.size() - 1) * cutoff * c_pi, taps.size())) * + scale * window; + + if (is_odd(taps.size())) + taps[taps.size() / 2] = 1 - 2.0 * cutoff; + + if (normalize) + { + const T invsum = reciprocal(sum(taps) + 1); + taps = taps * invsum; + } +} + +template +void fir_bandpass(univector_ref taps, T frequency1, T frequency2, const expression_handle& window, + bool normalize = true) +{ + const T scale1 = 2.0 * frequency1; + const T scale2 = 2.0 * frequency2; + const T sc = c_pi * T(taps.size() - 1); + const T start1 = sc * frequency1; + const T start2 = sc * frequency2; + + taps = (bind_expression(fn::sinc(), symmlinspace(start2, taps.size())) * scale2 - + bind_expression(fn::sinc(), symmlinspace(start1, taps.size())) * scale1) * + window; + + if (is_odd(taps.size())) + taps[taps.size() / 2] = 2 * (frequency2 - frequency1); + + if (normalize) + { + const T invsum = reciprocal(sum(taps) + 1); + taps = taps * invsum; + } +} + +template +void fir_bandstop(univector_ref taps, T frequency1, T frequency2, const expression_handle& window, + bool normalize = true) +{ + const T scale1 = 2.0 * frequency1; + const T scale2 = 2.0 * frequency2; + const T sc = c_pi * T(taps.size() - 1); + const T start1 = sc * frequency1; + const T start2 = sc * frequency2; + + taps = (bind_expression(fn::sinc(), symmlinspace(start1, taps.size())) * scale1 - + bind_expression(fn::sinc(), symmlinspace(start2, taps.size())) * scale2) * + window; + + if (is_odd(taps.size())) + taps[taps.size() / 2] = 1 - 2 * (frequency2 - frequency1); + + if (normalize) + { + const T invsum = reciprocal(sum(taps)); + taps = taps * invsum; + } +} +} // namespace internal +KFR_I_FN_FULL(fir_lowpass, internal::fir_lowpass) +KFR_I_FN_FULL(fir_highpass, internal::fir_highpass) +KFR_I_FN_FULL(fir_bandpass, internal::fir_bandpass) +KFR_I_FN_FULL(fir_bandstop, internal::fir_bandstop) + +/** + * @brief Calculates coefficients for the low-pass FIR filter + * @param taps array where computed coefficients are stored + * @param cutoff Normalized frequency (frequency_Hz / samplerate_Hz) + * @param window pointer to a window function + * @param normalize true for normalized coefficients + */ +template +KFR_INTRINSIC void fir_lowpass(univector& taps, identity cutoff, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_lowpass(taps.slice(), cutoff, window, normalize); +} + +/** + * @brief Calculates coefficients for the high-pass FIR filter + * @param taps array where computed coefficients are stored + * @param cutoff Normalized frequency (frequency_Hz / samplerate_Hz) + * @param window pointer to a window function + * @param normalize true for normalized coefficients + */ +template +KFR_INTRINSIC void fir_highpass(univector& taps, identity cutoff, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_highpass(taps.slice(), cutoff, window, normalize); +} + +/** + * @brief Calculates coefficients for the band-pass FIR filter + * @param taps array where computed coefficients are stored + * @param frequency1 Normalized frequency (frequency_Hz / samplerate_Hz) + * @param frequency2 Normalized frequency (frequency_Hz / samplerate_Hz) + * @param window pointer to a window function + * @param normalize true for normalized coefficients + */ +template +KFR_INTRINSIC void fir_bandpass(univector& taps, identity frequency1, identity frequency2, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_bandpass(taps.slice(), frequency1, frequency2, window, normalize); +} + +/** + * @brief Calculates coefficients for the band-stop FIR filter + * @param taps array where computed coefficients are stored + * @param frequency1 Normalized frequency (frequency_Hz / samplerate_Hz) + * @param frequency2 Normalized frequency (frequency_Hz / samplerate_Hz) + * @param window pointer to a window function + * @param normalize true for normalized coefficients + */ +template +KFR_INTRINSIC void fir_bandstop(univector& taps, identity frequency1, identity frequency2, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_bandstop(taps.slice(), frequency1, frequency2, window, normalize); +} + +/** + * @copydoc kfr::fir_lowpass + */ +template +KFR_INTRINSIC void fir_lowpass(const univector_ref& taps, identity cutoff, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_lowpass(taps, cutoff, window, normalize); +} + +/** + * @copydoc kfr::fir_highpass + */ +template +KFR_INTRINSIC void fir_highpass(const univector_ref& taps, identity cutoff, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_highpass(taps, cutoff, window, normalize); +} + +/** + * @copydoc kfr::fir_bandpass + */ +template +KFR_INTRINSIC void fir_bandpass(const univector_ref& taps, identity frequency1, identity frequency2, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_bandpass(taps, frequency1, frequency2, window, normalize); +} + +/** + * @copydoc kfr::fir_bandstop + */ +template +KFR_INTRINSIC void fir_bandstop(const univector_ref& taps, identity frequency1, identity frequency2, + const expression_handle& window, bool normalize = true) +{ + return internal::fir_bandstop(taps, frequency1, frequency2, window, normalize); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/goertzel.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/goertzel.hpp new file mode 100644 index 00000000..f9b2b38e --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/goertzel.hpp @@ -0,0 +1,140 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../math/sin_cos.hpp" +#include "../simd/complex.hpp" +#include "../simd/vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +struct expression_goertzel : expression_traits_defaults +{ + constexpr static size_t dims = 1; + + using value_type = T; + + constexpr static shape<1> get_shape(const expression_goertzel&) { return shape<1>(infinite_size); } + constexpr static shape<1> get_shape() { return shape<1>(infinite_size); } + + expression_goertzel(complex& result, T omega) + : result(result), omega(omega), coeff(2 * cos(omega)), q0(0), q1(0), q2(0) + { + } + ~expression_goertzel() + { + result.real(q1 - q2 * cos(omega)); + result.imag(q2 * sin(omega)); + } + + template + friend KFR_INTRINSIC void set_elements(expression_goertzel& self, shape<1>, axis_params, + const identity>& x) + { + vec in = x; + CMT_LOOP_UNROLL + for (size_t i = 0; i < N; i++) + { + self.q0 = self.coeff * self.q1 - self.q2 + in[i]; + self.q2 = self.q1; + self.q1 = self.q0; + } + } + complex& result; + const T omega; + const T coeff; + T q0; + T q1; + T q2; +}; + +template +struct expression_parallel_goertzel : expression_traits_defaults +{ + constexpr static size_t dims = 1; + + using value_type = T; + + constexpr static shape<1> get_shape(const expression_parallel_goertzel&) + { + return shape<1>(infinite_size); + } + constexpr static shape<1> get_shape() { return shape<1>(infinite_size); } + + expression_parallel_goertzel(complex result[], vec omega) + : result(result), omega(omega), coeff(2 * cos(omega)), q0(T(0)), q1(T(0)), q2(T(0)) + { + } + ~expression_parallel_goertzel() + { + const vec re = q1 - q2 * cos(omega); + const vec im = q2 * sin(omega); + for (size_t i = 0; i < width; i++) + { + result[i].real(re[i]); + result[i].imag(im[i]); + } + } + template + friend KFR_INTRINSIC void set_elements(expression_parallel_goertzel& self, shape<1>, + axis_params, const identity>& x) + { + const vec in = x; + CMT_LOOP_UNROLL + for (size_t i = 0; i < N; i++) + { + self.q0 = self.coeff * self.q1 - self.q2 + in[i]; + self.q2 = self.q1; + self.q1 = self.q0; + } + } + complex* result; + const vec omega; + const vec coeff; + vec q0; + vec q1; + vec q2; +}; + +template +KFR_INTRINSIC expression_goertzel goertzel(complex& result, identity omega) +{ + return expression_goertzel(result, omega); +} + +template +KFR_INTRINSIC expression_parallel_goertzel goertzel(complex (&result)[width], + const T (&omega)[width]) +{ + return expression_parallel_goertzel(result, read(omega)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir.hpp new file mode 100644 index 00000000..2aa0eca3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir.hpp @@ -0,0 +1,28 @@ +/** @addtogroup biquad + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "biquad.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir_design.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir_design.hpp new file mode 100644 index 00000000..fe3e076c --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/iir_design.hpp @@ -0,0 +1,1262 @@ +/** @addtogroup iir + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/filter.hpp" +#include "../base/handle.hpp" +#include "../math/hyperbolic.hpp" +#include "../simd/complex.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/operators.hpp" +#include "../simd/vec.hpp" +#include "../testo/assert.hpp" +#include "biquad_design.hpp" + +namespace kfr +{ + +template +struct zpk +{ + univector> z; + univector> p; + T k; +}; + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_FUNCTION zpk chebyshev1(int N, identity rp) +{ + if (N <= 0) + { + return { {}, {}, 1 }; + } + + T eps = sqrt(exp10(T(0.1) * rp) - T(1.0)); + T mu = T(1.0) / N * std::asinh(1 / eps); + + univector m = linspace(-N + 1, N + 1, N, false, ctrue); + + univector theta = c_pi * m / (2 * N); + univector> p = -csinh(make_complex(mu, theta)); + T k = product(-p).real(); + if (N % 2 == 0) + k = k / sqrt(T(1.0) + eps * eps); + return { {}, std::move(p), k }; +} + +template +KFR_FUNCTION zpk chebyshev2(int N, identity rs) +{ + if (N <= 0) + { + return { {}, {}, 1 }; + } + + T de = T(1.0) / sqrt(exp10(T(0.1) * rs) - 1); + T mu = std::asinh(T(1.0) / de) / N; + + univector m; + + if (N % 2) + { + m = concatenate(linspace(-N + 1, -2, N / 2, true, ctrue), linspace(2, N - 1, N / 2, true, ctrue)); + } + else + { + m = linspace(-N + 1, N + 1, N, false, ctrue); + } + + univector> z = -cconj(complex(0, 1) / sin(m * c_pi / (T(2.0) * N))); + + univector> p = + -cexp(complex(0, 1) * c_pi * linspace(-N + 1, N + 1, N, false, ctrue) / (2 * N)); + p = make_complex(sinh(mu) * real(p), cosh(mu) * imag(p)); + p = T(1.0) / p; + + T k = (product(-p) / product(-z)).real(); + + return { std::move(z), std::move(p), k }; +} + +template +KFR_FUNCTION zpk butterworth(int N) +{ + switch (N) + { + case 1: + return { {}, { complex(-1., +0.) }, 1 }; + case 2: + return { {}, + { complex(-0.7071067811865476, -0.7071067811865476), + complex(-0.7071067811865476, +0.7071067811865476) }, + 1 }; + case 3: + return { {}, + { complex(-0.5000000000000001, -0.8660254037844386), complex(-1., +0.), + complex(-0.5000000000000001, +0.8660254037844386) }, + 1 }; + case 4: + return { {}, + { complex(-0.38268343236508984, -0.9238795325112867), + complex(-0.9238795325112867, -0.3826834323650898), + complex(-0.9238795325112867, +0.3826834323650898), + complex(-0.38268343236508984, +0.9238795325112867) }, + 1 }; + case 5: + return { {}, + { complex(-0.30901699437494745, -0.9510565162951535), + complex(-0.8090169943749475, -0.5877852522924731), complex(-1., +0.), + complex(-0.8090169943749475, +0.5877852522924731), + complex(-0.30901699437494745, +0.9510565162951535) }, + 1 }; + case 6: + return { {}, + { complex(-0.25881904510252096, -0.9659258262890682), + complex(-0.7071067811865476, -0.7071067811865476), + complex(-0.9659258262890683, -0.25881904510252074), + complex(-0.9659258262890683, +0.25881904510252074), + complex(-0.7071067811865476, +0.7071067811865476), + complex(-0.25881904510252096, +0.9659258262890682) }, + 1 }; + case 7: + return { {}, + { complex(-0.22252093395631445, -0.9749279121818236), + complex(-0.6234898018587336, -0.7818314824680298), + complex(-0.9009688679024191, -0.4338837391175581), complex(-1., +0.), + complex(-0.9009688679024191, +0.4338837391175581), + complex(-0.6234898018587336, +0.7818314824680298), + complex(-0.22252093395631445, +0.9749279121818236) }, + 1 }; + case 8: + return { {}, + { complex(-0.19509032201612833, -0.9807852804032304), + complex(-0.5555702330196023, -0.8314696123025452), + complex(-0.8314696123025452, -0.5555702330196022), + complex(-0.9807852804032304, -0.19509032201612825), + complex(-0.9807852804032304, +0.19509032201612825), + complex(-0.8314696123025452, +0.5555702330196022), + complex(-0.5555702330196023, +0.8314696123025452), + complex(-0.19509032201612833, +0.9807852804032304) }, + 1 }; + case 9: + return { {}, + { complex(-0.17364817766693041, -0.984807753012208), + complex(-0.5000000000000001, -0.8660254037844386), + complex(-0.766044443118978, -0.6427876096865393), + complex(-0.9396926207859084, -0.3420201433256687), complex(-1., +0.), + complex(-0.9396926207859084, +0.3420201433256687), + complex(-0.766044443118978, +0.6427876096865393), + complex(-0.5000000000000001, +0.8660254037844386), + complex(-0.17364817766693041, +0.984807753012208) }, + 1 }; + case 10: + return { {}, + { complex(-0.15643446504023092, -0.9876883405951378), + complex(-0.4539904997395468, -0.8910065241883678), + complex(-0.7071067811865476, -0.7071067811865476), + complex(-0.8910065241883679, -0.45399049973954675), + complex(-0.9876883405951378, -0.15643446504023087), + complex(-0.9876883405951378, +0.15643446504023087), + complex(-0.8910065241883679, +0.45399049973954675), + complex(-0.7071067811865476, +0.7071067811865476), + complex(-0.4539904997395468, +0.8910065241883678), + complex(-0.15643446504023092, +0.9876883405951378) }, + 1 }; + case 11: + return { {}, + { complex(-0.14231483827328512, -0.9898214418809327), + complex(-0.41541501300188644, -0.9096319953545183), + complex(-0.654860733945285, -0.7557495743542583), + complex(-0.8412535328311812, -0.5406408174555976), + complex(-0.9594929736144974, -0.28173255684142967), complex(-1., +0.), + complex(-0.9594929736144974, +0.28173255684142967), + complex(-0.8412535328311812, +0.5406408174555976), + complex(-0.654860733945285, +0.7557495743542583), + complex(-0.41541501300188644, +0.9096319953545183), + complex(-0.14231483827328512, +0.9898214418809327) }, + 1 }; + case 12: + return { {}, + { complex(-0.13052619222005193, -0.9914448613738104), + complex(-0.38268343236508984, -0.9238795325112867), + complex(-0.6087614290087207, -0.7933533402912352), + complex(-0.7933533402912353, -0.6087614290087205), + complex(-0.9238795325112867, -0.3826834323650898), + complex(-0.9914448613738104, -0.13052619222005157), + complex(-0.9914448613738104, +0.13052619222005157), + complex(-0.9238795325112867, +0.3826834323650898), + complex(-0.7933533402912353, +0.6087614290087205), + complex(-0.6087614290087207, +0.7933533402912352), + complex(-0.38268343236508984, +0.9238795325112867), + complex(-0.13052619222005193, +0.9914448613738104) }, + 1 }; + case 13: + return { {}, + { complex(-0.120536680255323, -0.992708874098054), + complex(-0.35460488704253557, -0.9350162426854148), + complex(-0.5680647467311558, -0.8229838658936565), + complex(-0.7485107481711011, -0.6631226582407952), + complex(-0.8854560256532099, -0.46472317204376856), + complex(-0.970941817426052, -0.23931566428755777), complex(-1., +0.), + complex(-0.970941817426052, +0.23931566428755777), + complex(-0.8854560256532099, +0.46472317204376856), + complex(-0.7485107481711011, +0.6631226582407952), + complex(-0.5680647467311558, +0.8229838658936565), + complex(-0.35460488704253557, +0.9350162426854148), + complex(-0.120536680255323, +0.992708874098054) }, + 1 }; + case 14: + return { {}, + { complex(-0.11196447610330791, -0.9937122098932426), + complex(-0.3302790619551673, -0.9438833303083675), + complex(-0.5320320765153366, -0.8467241992282841), + complex(-0.7071067811865476, -0.7071067811865476), + complex(-0.8467241992282842, -0.5320320765153366), + complex(-0.9438833303083676, -0.3302790619551671), + complex(-0.9937122098932426, -0.11196447610330786), + complex(-0.9937122098932426, +0.11196447610330786), + complex(-0.9438833303083676, +0.3302790619551671), + complex(-0.8467241992282842, +0.5320320765153366), + complex(-0.7071067811865476, +0.7071067811865476), + complex(-0.5320320765153366, +0.8467241992282841), + complex(-0.3302790619551673, +0.9438833303083675), + complex(-0.11196447610330791, +0.9937122098932426) }, + 1 }; + case 15: + return { {}, + { complex(-0.10452846326765346, -0.9945218953682733), + complex(-0.30901699437494745, -0.9510565162951535), + complex(-0.5000000000000001, -0.8660254037844386), + complex(-0.6691306063588582, -0.7431448254773941), + complex(-0.8090169943749475, -0.5877852522924731), + complex(-0.9135454576426009, -0.40673664307580015), + complex(-0.9781476007338057, -0.20791169081775931), complex(-1., +0.), + complex(-0.9781476007338057, +0.20791169081775931), + complex(-0.9135454576426009, +0.40673664307580015), + complex(-0.8090169943749475, +0.5877852522924731), + complex(-0.6691306063588582, +0.7431448254773941), + complex(-0.5000000000000001, +0.8660254037844386), + complex(-0.30901699437494745, +0.9510565162951535), + complex(-0.10452846326765346, +0.9945218953682733) }, + 1 }; + case 16: + return { {}, + { complex(-0.09801714032956077, -0.9951847266721968), + complex(-0.29028467725446233, -0.9569403357322089), + complex(-0.4713967368259978, -0.8819212643483549), + complex(-0.6343932841636455, -0.7730104533627369), + complex(-0.773010453362737, -0.6343932841636455), + complex(-0.881921264348355, -0.47139673682599764), + complex(-0.9569403357322088, -0.29028467725446233), + complex(-0.9951847266721969, -0.0980171403295606), + complex(-0.9951847266721969, +0.0980171403295606), + complex(-0.9569403357322088, +0.29028467725446233), + complex(-0.881921264348355, +0.47139673682599764), + complex(-0.773010453362737, +0.6343932841636455), + complex(-0.6343932841636455, +0.7730104533627369), + complex(-0.4713967368259978, +0.8819212643483549), + complex(-0.29028467725446233, +0.9569403357322089), + complex(-0.09801714032956077, +0.9951847266721968) }, + 1 }; + case 17: + return { {}, + { complex(-0.09226835946330202, -0.9957341762950345), + complex(-0.273662990072083, -0.961825643172819), + complex(-0.4457383557765383, -0.8951632913550623), + complex(-0.6026346363792565, -0.7980172272802395), + complex(-0.7390089172206591, -0.6736956436465572), + complex(-0.8502171357296142, -0.5264321628773557), + complex(-0.9324722294043558, -0.3612416661871529), + complex(-0.9829730996839018, -0.18374951781657034), complex(-1., +0.), + complex(-0.9829730996839018, +0.18374951781657034), + complex(-0.9324722294043558, +0.3612416661871529), + complex(-0.8502171357296142, +0.5264321628773557), + complex(-0.7390089172206591, +0.6736956436465572), + complex(-0.6026346363792565, +0.7980172272802395), + complex(-0.4457383557765383, +0.8951632913550623), + complex(-0.273662990072083, +0.961825643172819), + complex(-0.09226835946330202, +0.9957341762950345) }, + 1 }; + case 18: + return { {}, + { complex(-0.08715574274765814, -0.9961946980917455), + complex(-0.25881904510252096, -0.9659258262890682), + complex(-0.42261826174069944, -0.9063077870366499), + complex(-0.5735764363510463, -0.8191520442889917), + complex(-0.7071067811865476, -0.7071067811865476), + complex(-0.8191520442889918, -0.573576436351046), + complex(-0.9063077870366499, -0.4226182617406994), + complex(-0.9659258262890683, -0.25881904510252074), + complex(-0.9961946980917455, -0.08715574274765817), + complex(-0.9961946980917455, +0.08715574274765817), + complex(-0.9659258262890683, +0.25881904510252074), + complex(-0.9063077870366499, +0.4226182617406994), + complex(-0.8191520442889918, +0.573576436351046), + complex(-0.7071067811865476, +0.7071067811865476), + complex(-0.5735764363510463, +0.8191520442889917), + complex(-0.42261826174069944, +0.9063077870366499), + complex(-0.25881904510252096, +0.9659258262890682), + complex(-0.08715574274765814, +0.9961946980917455) }, + 1 }; + case 19: + return { {}, + { complex(-0.0825793454723324, -0.9965844930066698), + complex(-0.24548548714079924, -0.9694002659393304), + complex(-0.40169542465296953, -0.9157733266550574), + complex(-0.5469481581224269, -0.8371664782625285), + complex(-0.6772815716257411, -0.7357239106731316), + complex(-0.7891405093963936, -0.6142127126896678), + complex(-0.8794737512064891, -0.4759473930370735), + complex(-0.9458172417006346, -0.32469946920468346), + complex(-0.9863613034027223, -0.1645945902807339), complex(-1., +0.), + complex(-0.9863613034027223, +0.1645945902807339), + complex(-0.9458172417006346, +0.32469946920468346), + complex(-0.8794737512064891, +0.4759473930370735), + complex(-0.7891405093963936, +0.6142127126896678), + complex(-0.6772815716257411, +0.7357239106731316), + complex(-0.5469481581224269, +0.8371664782625285), + complex(-0.40169542465296953, +0.9157733266550574), + complex(-0.24548548714079924, +0.9694002659393304), + complex(-0.0825793454723324, +0.9965844930066698) }, + 1 }; + case 20: + return { {}, + { complex(-0.078459095727845, -0.996917333733128), + complex(-0.23344536385590525, -0.9723699203976767), + complex(-0.38268343236508984, -0.9238795325112867), + complex(-0.5224985647159487, -0.8526401643540923), + complex(-0.6494480483301837, -0.7604059656000309), + complex(-0.7604059656000309, -0.6494480483301837), + complex(-0.8526401643540923, -0.5224985647159488), + complex(-0.9238795325112867, -0.3826834323650898), + complex(-0.9723699203976766, -0.2334453638559054), + complex(-0.996917333733128, -0.07845909572784494), + complex(-0.996917333733128, +0.07845909572784494), + complex(-0.9723699203976766, +0.2334453638559054), + complex(-0.9238795325112867, +0.3826834323650898), + complex(-0.8526401643540923, +0.5224985647159488), + complex(-0.7604059656000309, +0.6494480483301837), + complex(-0.6494480483301837, +0.7604059656000309), + complex(-0.5224985647159487, +0.8526401643540923), + complex(-0.38268343236508984, +0.9238795325112867), + complex(-0.23344536385590525, +0.9723699203976767), + complex(-0.078459095727845, +0.996917333733128) }, + 1 }; + case 21: + return { {}, + { complex(-0.07473009358642439, -0.9972037971811801), + complex(-0.22252093395631445, -0.9749279121818236), + complex(-0.3653410243663952, -0.9308737486442041), + complex(-0.5000000000000001, -0.8660254037844386), + complex(-0.6234898018587336, -0.7818314824680298), + complex(-0.7330518718298263, -0.6801727377709194), + complex(-0.8262387743159949, -0.563320058063622), + complex(-0.9009688679024191, -0.4338837391175581), + complex(-0.9555728057861408, -0.29475517441090415), + complex(-0.9888308262251285, -0.14904226617617441), + complex(-1., +0.), + complex(-0.9888308262251285, +0.14904226617617441), + complex(-0.9555728057861408, +0.29475517441090415), + complex(-0.9009688679024191, +0.4338837391175581), + complex(-0.8262387743159949, +0.563320058063622), + complex(-0.7330518718298263, +0.6801727377709194), + complex(-0.6234898018587336, +0.7818314824680298), + complex(-0.5000000000000001, +0.8660254037844386), + complex(-0.3653410243663952, +0.9308737486442041), + complex(-0.22252093395631445, +0.9749279121818236), + complex(-0.07473009358642439, +0.9972037971811801) }, + 1 }; + case 22: + return { {}, + { complex(-0.07133918319923235, -0.9974521146102535), + complex(-0.21256528955297682, -0.9771468659711595), + complex(-0.3494641795990982, -0.9369497249997618), + complex(-0.479248986720057, -0.8776789895672555), + complex(-0.5992776665113468, -0.8005412409243605), + complex(-0.7071067811865477, -0.7071067811865475), + complex(-0.8005412409243604, -0.5992776665113468), + complex(-0.8776789895672557, -0.4792489867200568), + complex(-0.9369497249997617, -0.34946417959909837), + complex(-0.9771468659711595, -0.21256528955297668), + complex(-0.9974521146102535, -0.07133918319923234), + complex(-0.9974521146102535, +0.07133918319923234), + complex(-0.9771468659711595, +0.21256528955297668), + complex(-0.9369497249997617, +0.34946417959909837), + complex(-0.8776789895672557, +0.4792489867200568), + complex(-0.8005412409243604, +0.5992776665113468), + complex(-0.7071067811865477, +0.7071067811865475), + complex(-0.5992776665113468, +0.8005412409243605), + complex(-0.479248986720057, +0.8776789895672555), + complex(-0.3494641795990982, +0.9369497249997618), + complex(-0.21256528955297682, +0.9771468659711595), + complex(-0.07133918319923235, +0.9974521146102535) }, + 1 }; + case 23: + return { {}, + { complex(-0.06824241336467123, -0.9976687691905392), + complex(-0.20345601305263397, -0.9790840876823228), + complex(-0.3348796121709863, -0.9422609221188204), + complex(-0.4600650377311522, -0.8878852184023752), + complex(-0.5766803221148672, -0.816969893010442), + complex(-0.6825531432186541, -0.730835964278124), + complex(-0.7757112907044199, -0.6310879443260528), + complex(-0.8544194045464886, -0.5195839500354336), + complex(-0.917211301505453, -0.39840108984624145), + complex(-0.9629172873477994, -0.2697967711570243), + complex(-0.9906859460363308, -0.1361666490962466), + complex(-1., +0.), + complex(-0.9906859460363308, +0.1361666490962466), + complex(-0.9629172873477994, +0.2697967711570243), + complex(-0.917211301505453, +0.39840108984624145), + complex(-0.8544194045464886, +0.5195839500354336), + complex(-0.7757112907044199, +0.6310879443260528), + complex(-0.6825531432186541, +0.730835964278124), + complex(-0.5766803221148672, +0.816969893010442), + complex(-0.4600650377311522, +0.8878852184023752), + complex(-0.3348796121709863, +0.9422609221188204), + complex(-0.20345601305263397, +0.9790840876823228), + complex(-0.06824241336467123, +0.9976687691905392) }, + 1 }; + case 24: + return { {}, + { complex(-0.06540312923014327, -0.9978589232386035), + complex(-0.19509032201612833, -0.9807852804032304), + complex(-0.3214394653031617, -0.9469301294951056), + complex(-0.44228869021900125, -0.8968727415326884), + complex(-0.5555702330196024, -0.8314696123025451), + complex(-0.6593458151000688, -0.7518398074789774), + complex(-0.7518398074789775, -0.6593458151000687), + complex(-0.8314696123025452, -0.5555702330196022), + complex(-0.8968727415326884, -0.44228869021900125), + complex(-0.9469301294951057, -0.32143946530316153), + complex(-0.9807852804032304, -0.19509032201612825), + complex(-0.9978589232386035, -0.06540312923014306), + complex(-0.9978589232386035, +0.06540312923014306), + complex(-0.9807852804032304, +0.19509032201612825), + complex(-0.9469301294951057, +0.32143946530316153), + complex(-0.8968727415326884, +0.44228869021900125), + complex(-0.8314696123025452, +0.5555702330196022), + complex(-0.7518398074789775, +0.6593458151000687), + complex(-0.6593458151000688, +0.7518398074789774), + complex(-0.5555702330196024, +0.8314696123025451), + complex(-0.44228869021900125, +0.8968727415326884), + complex(-0.3214394653031617, +0.9469301294951056), + complex(-0.19509032201612833, +0.9807852804032304), + complex(-0.06540312923014327, +0.9978589232386035) }, + 1 }; + default: + return { {}, {}, 1.0 }; + } +} + +template +KFR_FUNCTION zpk bessel(int N) +{ + switch (N) + { + case 0: + return { {}, {}, 1.0 }; + case 1: + return { {}, { complex(-1., +0.) }, 1.0 }; + case 2: + return { {}, + { complex(-0.8660254037844385, -0.4999999999999999), + complex(-0.8660254037844385, +0.4999999999999999) }, + 1.0 }; + case 3: + return { {}, + { complex(-0.7456403858480766, -0.7113666249728353), complex(-0.9416000265332067, +0.), + complex(-0.7456403858480766, +0.7113666249728353) }, + 1.0 }; + case 4: + return { {}, + { complex(-0.6572111716718827, -0.830161435004873), + complex(-0.904758796788245, -0.27091873300387465), + complex(-0.904758796788245, +0.27091873300387465), + complex(-0.6572111716718827, +0.830161435004873) }, + 1.0 }; + case 5: + return { {}, + { complex(-0.5905759446119192, -0.9072067564574549), + complex(-0.8515536193688396, -0.44271746394433276), complex(-0.92644207738776, +0.), + complex(-0.8515536193688396, +0.44271746394433276), + complex(-0.5905759446119192, +0.9072067564574549) }, + 1.0 }; + case 6: + return { {}, + { complex(-0.5385526816693108, -0.9616876881954276), + complex(-0.7996541858328287, -0.5621717346937316), + complex(-0.9093906830472273, -0.1856964396793047), + complex(-0.9093906830472273, +0.1856964396793047), + complex(-0.7996541858328287, +0.5621717346937316), + complex(-0.5385526816693108, +0.9616876881954276) }, + 1.0 }; + case 7: + return { {}, + { complex(-0.4966917256672317, -1.0025085084544205), + complex(-0.7527355434093214, -0.6504696305522553), + complex(-0.8800029341523379, -0.32166527623077407), complex(-0.919487155649029, +0.), + complex(-0.8800029341523379, +0.32166527623077407), + complex(-0.7527355434093214, +0.6504696305522553), + complex(-0.4966917256672317, +1.0025085084544205) }, + 1.0 }; + case 8: + return { {}, + { complex(-0.46217404125321254, -1.0343886811269012), + complex(-0.7111381808485397, -0.71865173141084), + complex(-0.8473250802359334, -0.42590175382729345), + complex(-0.9096831546652911, -0.1412437976671423), + complex(-0.9096831546652911, +0.1412437976671423), + complex(-0.8473250802359334, +0.42590175382729345), + complex(-0.7111381808485397, +0.71865173141084), + complex(-0.46217404125321254, +1.0343886811269012) }, + 1.0 }; + case 9: + return { {}, + { complex(-0.43314155615536226, -1.0600736701359301), + complex(-0.6743622686854763, -0.7730546212691185), + complex(-0.8148021112269014, -0.50858156896315), + complex(-0.8911217017079759, -0.25265809345821644), + complex(-0.9154957797499037, +0.), + complex(-0.8911217017079759, +0.25265809345821644), + complex(-0.8148021112269014, +0.50858156896315), + complex(-0.6743622686854763, +0.7730546212691185), + complex(-0.43314155615536226, +1.0600736701359301) }, + 1.0 }; + case 10: + return { {}, + { complex(-0.4083220732868863, -1.0812748428191246), + complex(-0.6417513866988322, -0.8175836167191022), + complex(-0.7837694413101445, -0.5759147538499948), + complex(-0.8688459641284763, -0.34300082337663096), + complex(-0.9091347320900505, -0.11395831373355114), + complex(-0.9091347320900505, +0.11395831373355114), + complex(-0.8688459641284763, +0.34300082337663096), + complex(-0.7837694413101445, +0.5759147538499948), + complex(-0.6417513866988322, +0.8175836167191022), + complex(-0.4083220732868863, +1.0812748428191246) }, + 1.0 }; + case 11: + return { {}, + { complex(-0.3868149510055096, -1.0991174667631216), + complex(-0.6126871554915198, -0.8547813893314768), + complex(-0.7546938934722305, -0.6319150050721849), + complex(-0.8453044014712964, -0.4178696917801249), + complex(-0.8963656705721169, -0.20804803750710327), + complex(-0.9129067244518985, +0.), + complex(-0.8963656705721169, +0.20804803750710327), + complex(-0.8453044014712964, +0.4178696917801249), + complex(-0.7546938934722305, +0.6319150050721849), + complex(-0.6126871554915198, +0.8547813893314768), + complex(-0.3868149510055096, +1.0991174667631216) }, + 1.0 }; + case 12: + return { {}, + { complex(-0.3679640085526314, -1.1143735756415463), + complex(-0.5866369321861475, -0.8863772751320727), + complex(-0.7276681615395161, -0.6792961178764695), + complex(-0.8217296939939074, -0.48102121151006755), + complex(-0.880253434201683, -0.2871779503524227), + complex(-0.9084478234140686, -0.09550636521345042), + complex(-0.9084478234140686, +0.09550636521345042), + complex(-0.880253434201683, +0.2871779503524227), + complex(-0.8217296939939074, +0.48102121151006755), + complex(-0.7276681615395161, +0.6792961178764695), + complex(-0.5866369321861475, +0.8863772751320727), + complex(-0.3679640085526314, +1.1143735756415463) }, + 1.0 }; + case 13: + return { {}, + { complex(-0.35127923233898156, -1.1275915483177048), + complex(-0.5631559842430193, -0.9135900338325103), + complex(-0.7026234675721276, -0.7199611890171304), + complex(-0.7987460692470972, -0.5350752120696802), + complex(-0.8625094198260553, -0.35474137311729914), + complex(-0.8991314665475196, -0.17683429561610436), + complex(-0.9110914665984182, +0.), + complex(-0.8991314665475196, +0.17683429561610436), + complex(-0.8625094198260553, +0.35474137311729914), + complex(-0.7987460692470972, +0.5350752120696802), + complex(-0.7026234675721276, +0.7199611890171304), + complex(-0.5631559842430193, +0.9135900338325103), + complex(-0.35127923233898156, +1.1275915483177048) }, + 1.0 }; + case 14: + return { {}, + { complex(-0.3363868224902031, -1.1391722978398593), + complex(-0.5418766775112306, -0.9373043683516926), + complex(-0.6794256425119227, -0.7552857305042031), + complex(-0.7766591387063624, -0.581917067737761), + complex(-0.8441199160909851, -0.41316538251026935), + complex(-0.8869506674916446, -0.24700791787653334), + complex(-0.9077932138396491, -0.08219639941940154), + complex(-0.9077932138396491, +0.08219639941940154), + complex(-0.8869506674916446, +0.24700791787653334), + complex(-0.8441199160909851, +0.41316538251026935), + complex(-0.7766591387063624, +0.581917067737761), + complex(-0.6794256425119227, +0.7552857305042031), + complex(-0.5418766775112306, +0.9373043683516926), + complex(-0.3363868224902031, +1.1391722978398593) }, + 1.0 }; + case 15: + return { {}, + { complex(-0.3229963059766445, -1.14941615458363), + complex(-0.5224954069658334, -0.9581787261092526), + complex(-0.6579196593111002, -0.7862895503722519), + complex(-0.7556027168970723, -0.6229396358758262), + complex(-0.8256631452587148, -0.46423487527343266), + complex(-0.8731264620834984, -0.30823524705642674), + complex(-0.9006981694176978, -0.1537681197278439), complex(-0.9097482363849062, +0.), + complex(-0.9006981694176978, +0.1537681197278439), + complex(-0.8731264620834984, +0.30823524705642674), + complex(-0.8256631452587148, +0.46423487527343266), + complex(-0.7556027168970723, +0.6229396358758262), + complex(-0.6579196593111002, +0.7862895503722519), + complex(-0.5224954069658334, +0.9581787261092526), + complex(-0.3229963059766445, +1.14941615458363) }, + 1.0 }; + case 16: + return { {}, + { complex(-0.31087827556453856, -1.1585528411993304), + complex(-0.504760644442476, -0.9767137477799086), + complex(-0.6379502514039066, -0.8137453537108762), + complex(-0.7356166304713119, -0.6591950877860395), + complex(-0.8074790293236005, -0.5092933751171799), + complex(-0.8584264231521322, -0.3621697271802063), + complex(-0.8911723070323642, -0.2167089659900575), + complex(-0.9072099595087003, -0.07214211304111734), + complex(-0.9072099595087003, +0.07214211304111734), + complex(-0.8911723070323642, +0.2167089659900575), + complex(-0.8584264231521322, +0.3621697271802063), + complex(-0.8074790293236005, +0.5092933751171799), + complex(-0.7356166304713119, +0.6591950877860395), + complex(-0.6379502514039066, +0.8137453537108762), + complex(-0.504760644442476, +0.9767137477799086), + complex(-0.31087827556453856, +1.1585528411993304) }, + 1.0 }; + case 17: + return { {}, + { complex(-0.29984894599900724, -1.1667612729256673), + complex(-0.48846293376727057, -0.9932971956316782), + complex(-0.6193710717342136, -0.8382497252826987), + complex(-0.7166893842372348, -0.6914936286393606), + complex(-0.7897644147799701, -0.5493724405281085), + complex(-0.8433414495836128, -0.41007592829100215), + complex(-0.8801100704438625, -0.2725347156478803), + complex(-0.9016273850787279, -0.13602679951730237), + complex(-0.9087141161336388, +0.), + complex(-0.9016273850787279, +0.13602679951730237), + complex(-0.8801100704438625, +0.2725347156478803), + complex(-0.8433414495836128, +0.41007592829100215), + complex(-0.7897644147799701, +0.5493724405281085), + complex(-0.7166893842372348, +0.6914936286393606), + complex(-0.6193710717342136, +0.8382497252826987), + complex(-0.48846293376727057, +0.9932971956316782), + complex(-0.29984894599900724, +1.1667612729256673) }, + 1.0 }; + case 18: + return { {}, + { complex(-0.28975920298804847, -1.1741830106000584), + complex(-0.4734268069916154, -1.0082343003148009), + complex(-0.6020482668090646, -0.8602708961893666), + complex(-0.698782144500527, -0.7204696509726628), + complex(-0.7726285030739557, -0.5852778162086639), + complex(-0.8281885016242831, -0.45293856978159136), + complex(-0.8681095503628832, -0.32242049251632576), + complex(-0.8939764278132456, -0.19303746408947586), + complex(-0.9067004324162776, -0.06427924106393067), + complex(-0.9067004324162776, +0.06427924106393067), + complex(-0.8939764278132456, +0.19303746408947586), + complex(-0.8681095503628832, +0.32242049251632576), + complex(-0.8281885016242831, +0.45293856978159136), + complex(-0.7726285030739557, +0.5852778162086639), + complex(-0.698782144500527, +0.7204696509726628), + complex(-0.6020482668090646, +0.8602708961893666), + complex(-0.4734268069916154, +1.0082343003148009), + complex(-0.28975920298804847, +1.1741830106000584) }, + 1.0 }; + case 19: + return { {}, + { complex(-0.2804866851439361, -1.1809316284532905), + complex(-0.4595043449730983, -1.0217687769126707), + complex(-0.5858613321217832, -0.8801817131014564), + complex(-0.6818424412912442, -0.7466272357947761), + complex(-0.7561260971541627, -0.6176483917970176), + complex(-0.8131725551578203, -0.491536503556246), + complex(-0.8555768765618422, -0.3672925896399872), + complex(-0.8849290585034385, -0.24425907575498182), + complex(-0.9021937639390656, -0.12195683818720263), + complex(-0.9078934217899399, +0.), + complex(-0.9021937639390656, +0.12195683818720263), + complex(-0.8849290585034385, +0.24425907575498182), + complex(-0.8555768765618422, +0.3672925896399872), + complex(-0.8131725551578203, +0.491536503556246), + complex(-0.7561260971541627, +0.6176483917970176), + complex(-0.6818424412912442, +0.7466272357947761), + complex(-0.5858613321217832, +0.8801817131014564), + complex(-0.4595043449730983, +1.0217687769126707), + complex(-0.2804866851439361, +1.1809316284532905) }, + 1.0 }; + case 20: + return { {}, + { complex(-0.27192995802516506, -1.187099379810886), + complex(-0.44657006982051484, -1.0340977025608422), + complex(-0.5707026806915716, -0.8982829066468254), + complex(-0.6658120544829932, -0.7703721701100759), + complex(-0.7402780309646764, -0.6469975237605227), + complex(-0.7984251191290602, -0.526494238881713), + complex(-0.8427907479956664, -0.4078917326291931), + complex(-0.8749560316673335, -0.2905559296567909), + complex(-0.8959150941925766, -0.17403171759187044), + complex(-0.9062570115576768, -0.0579617802778495), + complex(-0.9062570115576768, +0.0579617802778495), + complex(-0.8959150941925766, +0.17403171759187044), + complex(-0.8749560316673335, +0.2905559296567909), + complex(-0.8427907479956664, +0.4078917326291931), + complex(-0.7984251191290602, +0.526494238881713), + complex(-0.7402780309646764, +0.6469975237605227), + complex(-0.6658120544829932, +0.7703721701100759), + complex(-0.5707026806915716, +0.8982829066468254), + complex(-0.44657006982051484, +1.0340977025608422), + complex(-0.27192995802516506, +1.187099379810886) }, + 1.0 }; + case 21: + return { {}, + { complex(-0.2640041595834027, -1.192762031948052), + complex(-0.4345168906815268, -1.045382255856986), + complex(-0.5564766488918566, -0.9148198405846728), + complex(-0.6506315378609466, -0.7920349342629495), + complex(-0.7250839687106612, -0.6737426063024383), + complex(-0.7840287980408347, -0.5583186348022857), + complex(-0.8299435470674444, -0.44481777394079575), + complex(-0.8643915813643203, -0.33262585125221866), + complex(-0.8883808106664449, -0.221306921508435), + complex(-0.9025428073192694, -0.11052525727898564), + complex(-0.9072262653142963, +0.), + complex(-0.9025428073192694, +0.11052525727898564), + complex(-0.8883808106664449, +0.221306921508435), + complex(-0.8643915813643203, +0.33262585125221866), + complex(-0.8299435470674444, +0.44481777394079575), + complex(-0.7840287980408347, +0.5583186348022857), + complex(-0.7250839687106612, +0.6737426063024383), + complex(-0.6506315378609466, +0.7920349342629495), + complex(-0.5564766488918566, +0.9148198405846728), + complex(-0.4345168906815268, +1.045382255856986), + complex(-0.2640041595834027, +1.192762031948052) }, + 1.0 }; + case 22: + return { {}, + { complex(-0.2566376987939318, -1.1979824335552132), + complex(-0.4232528745642629, -1.055755605227546), + complex(-0.5430983056306306, -0.9299947824439877), + complex(-0.6362427683267828, -0.811887504024635), + complex(-0.7105305456418792, -0.6982266265924527), + complex(-0.7700332930556816, -0.5874255426351151), + complex(-0.8171682088462721, -0.47856194922027806), + complex(-0.8534754036851689, -0.37103893194823206), + complex(-0.8799661455640174, -0.26443630392015344), + complex(-0.8972983138153532, -0.15843519122898653), + complex(-0.9058702269930871, -0.05277490828999903), + complex(-0.9058702269930871, +0.05277490828999903), + complex(-0.8972983138153532, +0.15843519122898653), + complex(-0.8799661455640174, +0.26443630392015344), + complex(-0.8534754036851689, +0.37103893194823206), + complex(-0.8171682088462721, +0.47856194922027806), + complex(-0.7700332930556816, +0.5874255426351151), + complex(-0.7105305456418792, +0.6982266265924527), + complex(-0.6362427683267828, +0.811887504024635), + complex(-0.5430983056306306, +0.9299947824439877), + complex(-0.4232528745642629, +1.055755605227546), + complex(-0.2566376987939318, +1.1979824335552132) }, + 1.0 }; + case 23: + return { {}, + { complex(-0.24976972022089572, -1.2028131878706978), + complex(-0.4126986617510148, -1.0653287944755134), + complex(-0.5304922463810198, -0.9439760364018306), + complex(-0.6225903228771341, -0.830155830281298), + complex(-0.6965966033912708, -0.720734137475305), + complex(-0.7564660146829886, -0.6141594859476034), + complex(-0.8045561642053178, -0.5095305912227259), + complex(-0.8423805948021129, -0.4062657948237603), + complex(-0.8709469395587415, -0.3039581993950041), + complex(-0.8909283242471254, -0.20230246993812237), + complex(-0.9027564979912508, -0.10105343353140452), + complex(-0.9066732476324991, +0.), + complex(-0.9027564979912508, +0.10105343353140452), + complex(-0.8909283242471254, +0.20230246993812237), + complex(-0.8709469395587415, +0.3039581993950041), + complex(-0.8423805948021129, +0.4062657948237603), + complex(-0.8045561642053178, +0.5095305912227259), + complex(-0.7564660146829886, +0.6141594859476034), + complex(-0.6965966033912708, +0.720734137475305), + complex(-0.6225903228771341, +0.830155830281298), + complex(-0.5304922463810198, +0.9439760364018306), + complex(-0.4126986617510148, +1.0653287944755134), + complex(-0.24976972022089572, +1.2028131878706978) }, + 1.0 }; + case 24: + return { {}, + { complex(-0.24334813375248746, -1.2072986837319728), + complex(-0.4027853855197519, -1.0741951965186751), + complex(-0.518591457482032, -0.9569048385259057), + complex(-0.6096221567378332, -0.8470292433077199), + complex(-0.6832565803536519, -0.7415032695091649), + complex(-0.7433392285088533, -0.6388084216222569), + complex(-0.7921695462343489, -0.5380628490968016), + complex(-0.8312326466813242, -0.4386985933597306), + complex(-0.8615278304016355, -0.34032021126186246), + complex(-0.8837358034555707, -0.24263352344013836), + complex(-0.8983105104397872, -0.14540561338736102), + complex(-0.9055312363372773, -0.0484400665404787), + complex(-0.9055312363372773, +0.0484400665404787), + complex(-0.8983105104397872, +0.14540561338736102), + complex(-0.8837358034555707, +0.24263352344013836), + complex(-0.8615278304016355, +0.34032021126186246), + complex(-0.8312326466813242, +0.4386985933597306), + complex(-0.7921695462343489, +0.5380628490968016), + complex(-0.7433392285088533, +0.6388084216222569), + complex(-0.6832565803536519, +0.7415032695091649), + complex(-0.6096221567378332, +0.8470292433077199), + complex(-0.518591457482032, +0.9569048385259057), + complex(-0.4027853855197519, +1.0741951965186751), + complex(-0.24334813375248746, +1.2072986837319728) }, + 1.0 }; + default: + return { {}, {}, 1.f }; + } +} + +// template +// KFR_FUNCTION zpk iirfilter(const zpk& filter) +// { +// } + +namespace internal +{ + +template +KFR_FUNCTION zpk bilinear(const zpk& filter, identity fs) +{ + const T fs2 = T(2.0) * fs; + zpk result; + result.z = (fs2 + filter.z) / (fs2 - filter.z); + result.p = (fs2 + filter.p) / (fs2 - filter.p); + result.z.resize(result.p.size(), complex(-1)); + result.k = filter.k * kfr::real(product(fs2 - filter.z) / product(fs2 - filter.p)); + return result; +} + +template +struct zero_pole_pairs +{ + complex p1, p2, z1, z2; +}; + +template +KFR_FUNCTION vec zpk2tf_poly(const complex& x, const complex& y) +{ + return { T(1), -(x.real() + y.real()), x.real() * y.real() - x.imag() * y.imag() }; +} + +template +KFR_FUNCTION biquad_section zpk2tf(const zero_pole_pairs& pairs, identity k) +{ + vec zz = k * zpk2tf_poly(pairs.z1, pairs.z2); + vec pp = zpk2tf_poly(pairs.p1, pairs.p2); + // return { zz[0], zz[1], zz[2], pp[0], pp[1], pp[2] }; + return { pp[0], pp[1], pp[2], zz[0], zz[1], zz[2] }; +} + +template +KFR_FUNCTION univector> cplxreal(const univector>& list) +{ + univector> x = list; + std::sort(x.begin(), x.end(), + [](const complex& a, const complex& b) { return a.real() < b.real(); }); + T tol = std::numeric_limits::epsilon() * 100; + univector> result = x; + for (size_t i = result.size(); i > 1; i--) + { + if (!isreal(result[i - 1]) && !isreal(result[i - 2])) + { + if (abs(result[i - 1].real() - result[i - 2].real()) < tol && + abs(result[i - 1].imag() + result[i - 2].imag()) < tol) + { + result.erase(result.begin() + i - 1); + result[i - 2].imag(abs(result[i - 2].imag())); + } + } + } + return result; +} + +template +KFR_FUNCTION size_t nearest_real_or_complex(const univector>& list, const complex& val, + bool mustbereal = true) +{ + univector> filtered; + for (complex v : list) + { + if (isreal(v) == mustbereal) + { + filtered.push_back(v); + } + } + TESTO_ASSERT(!filtered.empty()); + if (filtered.empty()) + return std::numeric_limits::max(); + + size_t minidx = 0; + T minval = cabs(val - filtered[0]); + for (size_t i = 1; i < filtered.size(); i++) + { + T newminval = cabs(val - filtered[i]); + if (newminval < minval) + { + minval = newminval; + minidx = i; + } + } + return minidx; +} + +template +KFR_FUNCTION int countreal(const univector>& list) +{ + int nreal = 0; + for (complex c : list) + { + if (c.imag() == 0) + nreal++; + } + return nreal; +} + +template +KFR_FUNCTION zpk lp2lp_zpk(const zpk& filter, identity wo) +{ + zpk result; + result.z = wo * filter.z; + result.p = wo * filter.p; + result.k = filter.k * pow(wo, filter.p.size() - filter.z.size()); + return result; +} + +template +KFR_FUNCTION zpk lp2hp_zpk(const zpk& filter, identity wo) +{ + zpk result; + result.z = wo / filter.z; + result.p = wo / filter.p; + result.z.resize(result.p.size(), T(0)); + result.k = filter.k * kfr::real(product(-filter.z) / product(-filter.p)); + return result; +} + +template +KFR_FUNCTION zpk lp2bp_zpk(const zpk& filter, identity wo, identity bw) +{ + zpk lowpass; + lowpass.z = bw * T(0.5) * filter.z; + lowpass.p = bw * T(0.5) * filter.p; + + zpk result; + result.z = concatenate(lowpass.z + csqrt(csqr(lowpass.z) - wo * wo), + lowpass.z - csqrt(csqr(lowpass.z) - wo * wo)); + result.p = concatenate(lowpass.p + csqrt(csqr(lowpass.p) - wo * wo), + lowpass.p - csqrt(csqr(lowpass.p) - wo * wo)); + + result.z.resize(result.z.size() + filter.p.size() - filter.z.size(), T(0)); + result.k = filter.k * pow(bw, filter.p.size() - filter.z.size()); + + return result; +} + +template +KFR_FUNCTION zpk lp2bs_zpk(const zpk& filter, identity wo, identity bw) +{ + zpk highpass; + highpass.z = (bw * T(0.5)) / filter.z; + highpass.p = (bw * T(0.5)) / filter.p; + + zpk result; + result.z = concatenate(highpass.z + csqrt(csqr(highpass.z) - wo * wo), + highpass.z - csqrt(csqr(highpass.z) - wo * wo)); + result.p = concatenate(highpass.p + csqrt(csqr(highpass.p) - wo * wo), + highpass.p - csqrt(csqr(highpass.p) - wo * wo)); + + result.z.resize(result.z.size() + filter.p.size() - filter.z.size(), complex(0, +wo)); + result.z.resize(result.z.size() + filter.p.size() - filter.z.size(), complex(0, -wo)); + result.k = filter.k * kfr::real(product(-filter.z) / product(-filter.p)); + + return result; +} + +template +KFR_FUNCTION T warp_freq(T frequency, T fs) +{ + frequency = 2 * frequency / fs; + fs = T(2.0); + T warped = 2 * fs * tan(c_pi * frequency / fs); + return warped; +} + +} // namespace internal + +/** + * @brief Calculates zero-pole-gain coefficients for the low-pass IIR filter + * @param filter Filter type: chebyshev1, chebyshev2, bessel, butterworth + * @param frequency Cutoff frequency (Hz) + * @param fs Sampling frequency (Hz) + * @return The resulting zpk filter + */ +template +KFR_FUNCTION zpk iir_lowpass(const zpk& filter, identity frequency, identity fs = T(2.0)) +{ + T warped = internal::warp_freq(frequency, fs); + + zpk result = filter; + result = internal::lp2lp_zpk(result, warped); + result = internal::bilinear(result, T(2.0)); // fs = 2.0 + return result; +} + + +/** + * @brief Calculates zero-pole-gain coefficients for the high-pass IIR filter + * @param filter Filter type: chebyshev1, chebyshev2, bessel, butterworth + * @param frequency Cutoff frequency (Hz) + * @param fs Sampling frequency (Hz) + * @return The resulting zpk filter + */ +template +KFR_FUNCTION zpk iir_highpass(const zpk& filter, identity frequency, identity fs = T(2.0)) +{ + T warped = internal::warp_freq(frequency, fs); + + zpk result = filter; + result = internal::lp2hp_zpk(result, warped); + result = internal::bilinear(result, T(2.0)); // fs = 2.0 + return result; +} + +/** + * @brief Calculates zero-pole-gain coefficients for the band-pass IIR filter + * @param filter Filter type: chebyshev1, chebyshev2, bessel, butterworth + * @param lowfreq Low cutoff frequency (Hz) + * @param lowfreq High cutoff frequency (Hz) + * @param fs Sampling frequency (Hz) + * @return The resulting zpk filter + */ +template +KFR_FUNCTION zpk iir_bandpass(const zpk& filter, identity lowfreq, identity highfreq, + identity fs = T(2.0)) +{ + T warpedlow = internal::warp_freq(lowfreq, fs); + T warpedhigh = internal::warp_freq(highfreq, fs); + + zpk result = filter; + result = internal::lp2bp_zpk(result, std::sqrt(warpedlow * warpedhigh), warpedhigh - warpedlow); + result = internal::bilinear(result, T(2.0)); // fs = 2.0 + return result; +} + +/** + * @brief Calculates zero-pole-gain coefficients for the band-stop IIR filter + * @param filter Filter type: chebyshev1, chebyshev2, bessel, butterworth + * @param lowfreq Low cutoff frequency (Hz) + * @param lowfreq High cutoff frequency (Hz) + * @param fs Sampling frequency (Hz) + * @return The resulting zpk filter + */ +template +KFR_FUNCTION zpk iir_bandstop(const zpk& filter, identity lowfreq, identity highfreq, + identity fs = T(2.0)) +{ + T warpedlow = internal::warp_freq(lowfreq, fs); + T warpedhigh = internal::warp_freq(highfreq, fs); + + zpk result = filter; + result = internal::lp2bs_zpk(result, std::sqrt(warpedlow * warpedhigh), warpedhigh - warpedlow); + result = internal::bilinear(result, T(2.0)); // fs = 2.0 + return result; +} + +template +KFR_FUNCTION iir_params to_sos(const zpk& filter) +{ + if (filter.p.empty() && filter.z.empty()) + return { biquad_section(filter.k, T(0.), T(0.), T(1.), T(0.), 0) }; + + zpk filt = filter; + size_t length = std::max(filter.p.size(), filter.z.size()); + filt.p.resize(length, complex(0)); + filt.z.resize(length, complex(0)); + + size_t n_sections = (length + 1) / 2; + if (length & 1) + { + filt.z.push_back(complex(0)); + filt.p.push_back(complex(0)); + } + + filt.z = internal::cplxreal(filt.z); + filt.p = internal::cplxreal(filt.p); + std::vector> pairs(n_sections); + + for (size_t si = 0; si < n_sections; si++) + { + size_t worstidx = 0; + T worstval = abs(1 - cabs(filt.p[0])); + for (size_t i = 1; i < filt.p.size(); i++) + { + T val = abs(1 - cabs(filt.p[i])); + if (val < worstval) + { + worstidx = i; + worstval = val; + } + } + complex p1 = filt.p[worstidx]; + filt.p.erase(filt.p.begin() + worstidx); + + complex z1, p2, z2; + if (isreal(p1) && internal::countreal(filt.p) == 0) + { + size_t z1_idx = internal::nearest_real_or_complex(filt.z, p1, true); + z1 = filt.z[z1_idx]; + filt.z.erase(filt.z.begin() + z1_idx); + p2 = z2 = 0; + } + else + { + size_t z1_idx; + if (!isreal(p1) && internal::countreal(filt.z) == 1) + { + z1_idx = internal::nearest_real_or_complex(filt.z, p1, false); + } + else + { + size_t minidx = 0; + T minval = cabs(p1 - filt.z[0]); + for (size_t i = 1; i < filt.z.size(); i++) + { + T newminval = cabs(p1 - filt.z[i]); + if (newminval < minval) + { + minidx = i; + minval = newminval; + } + } + z1_idx = minidx; + } + z1 = filt.z[z1_idx]; + filt.z.erase(filt.z.begin() + z1_idx); + if (!isreal(p1)) + { + if (!isreal(z1)) + { + p2 = cconj(p1); + z2 = cconj(z1); + } + else + { + p2 = cconj(p1); + size_t z2_idx = internal::nearest_real_or_complex(filt.z, p1, true); + z2 = filt.z[z2_idx]; + TESTO_ASSERT(isreal(z2)); + filt.z.erase(filt.z.begin() + z2_idx); + } + } + else + { + size_t p2_idx; + size_t z2_idx; + if (!isreal(z1)) + { + z2 = cconj(z1); + p2_idx = internal::nearest_real_or_complex(filt.z, p1, true); + p2 = filt.p[p2_idx]; + TESTO_ASSERT(isreal(p2)); + } + else + { + size_t worstidx = 0; + T worstval = abs(cabs(filt.p[0]) - 1); + for (size_t i = 1; i < filt.p.size(); i++) + { + T val = abs(cabs(filt.p[i]) - 1); + if (val < worstval) + { + worstidx = i; + worstval = val; + } + } + p2_idx = worstidx; + p2 = filt.p[p2_idx]; + + TESTO_ASSERT(isreal(p2)); + z2_idx = internal::nearest_real_or_complex(filt.z, p2, true); + z2 = filt.z[z2_idx]; + TESTO_ASSERT(isreal(z2)); + filt.z.erase(filt.z.begin() + z2_idx); + } + filt.p.erase(filt.p.begin() + p2_idx); + } + } + pairs[si].p1 = p1; + pairs[si].p2 = p2; + pairs[si].z1 = z1; + pairs[si].z2 = z2; + } + + iir_params result(n_sections); + for (size_t si = 0; si < n_sections; si++) + { + result[si] = internal::zpk2tf(pairs[n_sections - 1 - si], si == 0 ? filt.k : T(1)); + } + return result; +} + +/** + * @brief Returns template expressions that applies biquad filter to the input. + * @param e1 Input expression + * @param params IIR filter in ZPK form + * @remark This overload converts ZPK to biquad coefficients using to_sos function at every call + */ +template +KFR_FUNCTION expression_handle iir(E1&& e1, const zpk& params) +{ + return iir(std::forward(e1), to_sos(params)); +} + +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/mixdown.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/mixdown.hpp new file mode 100644 index 00000000..030c427f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/mixdown.hpp @@ -0,0 +1,81 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns template expression that returns the sum of all the inputs + */ +template +expression_function mixdown(E&&... e) +{ + return expression_function(fn::add(), std::forward(e)...); +} + +struct stereo_matrix +{ + template + KFR_MEM_INTRINSIC vec, N> operator()(const vec, N>& x) const + { + return process(x, csizeseq); + } + template + KFR_MEM_INTRINSIC vec, N> process(const vec, N>& x, csizes_t) const + { + return vec, N>(hadd(transpose(x[indices] * matrix))...); + } + const f64x2x2 matrix; +}; + +template +CMT_GNU_CONSTEXPR f64x2x2 matrix_sum_diff() +{ + return { f64x2{ 1, 1 }, f64x2{ 1, -1 } }; +} +template +CMT_GNU_CONSTEXPR f64x2x2 matrix_halfsum_halfdiff() +{ + return { f64x2{ 0.5, 0.5 }, f64x2{ 0.5, -0.5 } }; +} + +/** + * @brief Returns template expression that returns the vector of length 2 containing mix of the left and right + * channels + */ +template >> +Result mixdown_stereo(Left&& left, Right&& right, const f64x2x2& matrix) +{ + return Result(stereo_matrix{ matrix }, pack(std::forward(left), std::forward(right))); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/oscillators.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/oscillators.hpp new file mode 100644 index 00000000..1148527b --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/oscillators.hpp @@ -0,0 +1,284 @@ +/** @addtogroup oscillators + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/simd_expressions.hpp" +#include "../math/sin_cos.hpp" +#include "../simd/round.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +KFR_FUNCTION static auto phasor(identity frequency, identity sample_rate, identity phase = 0) +{ + return fract(counter(phase, frequency / sample_rate)); +} + +template +KFR_FUNCTION static auto phasor(identity frequency) +{ + return phasor(frequency, 1, 0); +} + +namespace intrinsics +{ +template +KFR_INTRINSIC T rawsine(const T& x) +{ + return intrinsics::fastsin(x * constants::pi_s(2)); +} +template +KFR_INTRINSIC T sinenorm(const T& x) +{ + return intrinsics::rawsine(fract(x)); +} +template +KFR_INTRINSIC T sine(const T& x) +{ + return intrinsics::sinenorm(constants::recip_pi_s(1, 2) * x); +} + +template +KFR_INTRINSIC T rawsquare(const T& x) +{ + return select(x < T(0.5), T(1), -T(1)); +} +template +KFR_INTRINSIC T squarenorm(const T& x) +{ + return intrinsics::rawsquare(fract(x)); +} +template +KFR_INTRINSIC T square(const T& x) +{ + return intrinsics::squarenorm(constants::recip_pi_s(1, 2) * x); +} + +template +KFR_INTRINSIC T rawsawtooth(const T& x) +{ + return T(1) - 2 * x; +} +template +KFR_INTRINSIC T sawtoothnorm(const T& x) +{ + return intrinsics::rawsawtooth(fract(x)); +} +template +KFR_INTRINSIC T sawtooth(const T& x) +{ + return intrinsics::sawtoothnorm(constants::recip_pi_s(1, 2) * x); +} + +template +KFR_INTRINSIC T isawtoothnorm(const T& x) +{ + return T(-1) + 2 * fract(x + 0.5); +} +template +KFR_INTRINSIC T isawtooth(const T& x) +{ + return intrinsics::isawtoothnorm(constants::recip_pi_s(1, 2) * x); +} + +template +KFR_INTRINSIC T rawtriangle(const T& x) +{ + return 1 - abs(4 * x - 2); +} +template +KFR_INTRINSIC T trianglenorm(const T& x) +{ + return intrinsics::rawtriangle(fract(x + 0.25)); +} +template +KFR_INTRINSIC T triangle(const T& x) +{ + return intrinsics::trianglenorm(constants::recip_pi_s(1, 2) * x); +} +} // namespace intrinsics +KFR_I_FN(rawsine) +KFR_I_FN(sine) +KFR_I_FN(sinenorm) +KFR_I_FN(rawsquare) +KFR_I_FN(square) +KFR_I_FN(squarenorm) +KFR_I_FN(rawtriangle) +KFR_I_FN(triangle) +KFR_I_FN(trianglenorm) +KFR_I_FN(rawsawtooth) +KFR_I_FN(sawtooth) +KFR_I_FN(sawtoothnorm) +KFR_I_FN(isawtooth) +KFR_I_FN(isawtoothnorm) + +template )> +KFR_FUNCTION T1 rawsine(const T1& x) +{ + return intrinsics::rawsine(x); +} +template +KFR_FUNCTION expression_function rawsine(E1&& x) +{ + return { std::forward(x) }; +} +template )> +KFR_FUNCTION T1 sine(const T1& x) +{ + return intrinsics::sine(x); +} +template +KFR_FUNCTION expression_function sine(E1&& x) +{ + return { std::forward(x) }; +} +template )> +KFR_FUNCTION T1 sinenorm(const T1& x) +{ + return intrinsics::sinenorm(x); +} +template +KFR_FUNCTION expression_function sinenorm(E1&& x) +{ + return { fn::sinenorm(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 rawsquare(const T1& x) +{ + return intrinsics::rawsquare(x); +} +template +KFR_FUNCTION expression_function rawsquare(E1&& x) +{ + return { fn::rawsquare(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 square(const T1& x) +{ + return intrinsics::square(x); +} +template +KFR_FUNCTION expression_function square(E1&& x) +{ + return { fn::square(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 squarenorm(const T1& x) +{ + return intrinsics::squarenorm(x); +} +template +KFR_FUNCTION expression_function squarenorm(E1&& x) +{ + return { fn::squarenorm(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 rawtriangle(const T1& x) +{ + return intrinsics::rawtriangle(x); +} +template +KFR_FUNCTION expression_function rawtriangle(E1&& x) +{ + return { fn::rawtriangle(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 triangle(const T1& x) +{ + return intrinsics::triangle(x); +} +template +KFR_FUNCTION expression_function triangle(E1&& x) +{ + return { fn::triangle(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 trianglenorm(const T1& x) +{ + return intrinsics::trianglenorm(x); +} +template +KFR_FUNCTION expression_function trianglenorm(E1&& x) +{ + return { fn::trianglenorm(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 rawsawtooth(const T1& x) +{ + return intrinsics::rawsawtooth(x); +} +template +KFR_FUNCTION expression_function rawsawtooth(E1&& x) +{ + return { fn::rawsawtooth(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 sawtooth(const T1& x) +{ + return intrinsics::sawtooth(x); +} +template +KFR_FUNCTION expression_function sawtooth(E1&& x) +{ + return { fn::sawtooth(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 sawtoothnorm(const T1& x) +{ + return intrinsics::sawtoothnorm(x); +} +template +KFR_FUNCTION expression_function sawtoothnorm(E1&& x) +{ + return { fn::sawtoothnorm(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 isawtooth(const T1& x) +{ + return intrinsics::isawtooth(x); +} +template +KFR_FUNCTION expression_function isawtooth(E1&& x) +{ + return { fn::isawtooth(), std::forward(x) }; +} +template )> +KFR_FUNCTION T1 isawtoothnorm(const T1& x) +{ + return intrinsics::isawtoothnorm(x); +} +template +KFR_FUNCTION expression_function isawtoothnorm(E1&& x) +{ + return { fn::isawtoothnorm(), std::forward(x) }; +} +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/sample_rate_conversion.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/sample_rate_conversion.hpp new file mode 100644 index 00000000..b3ac7933 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/sample_rate_conversion.hpp @@ -0,0 +1,342 @@ +/** @addtogroup dsp + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/memory.hpp" +#include "../base/reduce.hpp" +#include "../base/univector.hpp" +#include "../math/modzerobessel.hpp" +#include "../math/sqrt.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/vec.hpp" +#include "window.hpp" + +namespace kfr +{ + +enum class sample_rate_conversion_quality : int +{ + draft = 4, + low = 6, + normal = 8, + high = 10, + perfect = 12, +}; + +using resample_quality = sample_rate_conversion_quality; + +/// @brief Sample Rate converter +template +struct samplerate_converter +{ + using itype = i64; + using ftype = subtype; + +protected: + KFR_MEM_INTRINSIC ftype window(ftype n) const + { + return modzerobessel(kaiser_beta * sqrt(1 - sqr(2 * n - 1))) * reciprocal(modzerobessel(kaiser_beta)); + } + KFR_MEM_INTRINSIC ftype sidelobe_att() const { return static_cast(kaiser_beta / 0.1102 + 8.7); } + KFR_MEM_INTRINSIC ftype transition_width() const + { + return static_cast((sidelobe_att() - 8) / (depth - 1) / 2.285); + } + +public: + static KFR_MEM_INTRINSIC size_t filter_order(sample_rate_conversion_quality quality) + { + return size_t(1) << (static_cast(quality) + 1); + } + + /// @brief Returns sidelobe attenuation for the given quality (in dB) + static KFR_MEM_INTRINSIC ftype sidelobe_attenuation(sample_rate_conversion_quality quality) + { + return (static_cast(quality) - 3) * ftype(20); + } + + /// @brief Returns transition width for the given quality (in rad) + static KFR_MEM_INTRINSIC ftype transition_width(sample_rate_conversion_quality quality) + { + return (sidelobe_attenuation(quality) - 8) / (filter_order(quality) - 1) / ftype(2.285); + } + + static KFR_MEM_INTRINSIC ftype window_param(sample_rate_conversion_quality quality) + { + const ftype att = sidelobe_attenuation(quality); + if (att > 50) + return ftype(0.1102) * (att - ftype(8.7)); + if (att >= 21) + return ftype(0.5842) * pow(att - 21, ftype(0.4)) + ftype(0.07886) * (att - 21); + return 0; + } + + samplerate_converter(sample_rate_conversion_quality quality, itype interpolation_factor, + itype decimation_factor, ftype scale = ftype(1), ftype cutoff = 0.5f); + + KFR_MEM_INTRINSIC itype input_position_to_intermediate(itype in_pos) const + { + return in_pos * interpolation_factor; + } + KFR_MEM_INTRINSIC itype output_position_to_intermediate(itype out_pos) const + { + return out_pos * decimation_factor; + } + + KFR_MEM_INTRINSIC itype input_position_to_output(itype in_pos) const + { + return floor_div(input_position_to_intermediate(in_pos), decimation_factor).quot; + } + KFR_MEM_INTRINSIC itype output_position_to_input(itype out_pos) const + { + return floor_div(output_position_to_intermediate(out_pos), interpolation_factor).quot; + } + + KFR_MEM_INTRINSIC itype output_size_for_input(itype input_size) const + { + return input_position_to_output(input_position + input_size - 1) - + input_position_to_output(input_position - 1); + } + + KFR_MEM_INTRINSIC itype input_size_for_output(itype output_size) const + { + return output_position_to_input(output_position + output_size - 1) - + output_position_to_input(output_position - 1); + } + + size_t skip(size_t output_size, univector_ref input) + { + const itype required_input_size = input_size_for_output(output_size); + + if (required_input_size >= depth) + { + delay.slice(0, delay.size()) = padded(input.slice(size_t(required_input_size - depth))); + } + else + { + delay.truncate(size_t(depth - required_input_size)) = delay.slice(size_t(required_input_size)); + delay.slice(size_t(depth - required_input_size)) = padded(input); + } + + input_position += required_input_size; + output_position += output_size; + + return required_input_size; + } + + /// @brief Writes output.size() samples to output reading at most input.size(), then consuming zeros as + /// input. + /// @returns Number of processed input samples (may be less than input.size()). + template + size_t process(univector& output, univector_ref input) + { + return process_impl(output.slice(), input); + } + + KFR_MEM_INTRINSIC double get_fractional_delay() const { return (taps - 1) * 0.5 / decimation_factor; } + KFR_MEM_INTRINSIC size_t get_delay() const { return static_cast(get_fractional_delay()); } + + ftype kaiser_beta; + itype depth; + itype taps; + size_t order; + itype interpolation_factor; + itype decimation_factor; + univector filter; + univector delay; + +protected: + itype input_position; + itype output_position; + + size_t process_impl(univector_ref output, univector_ref input); +}; + +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ + +template +struct expression_upsample; + +template +struct expression_downsample; + +template +struct expression_upsample<2, E> : expression_with_arguments, expression_traits_defaults +{ + using expression_with_arguments::expression_with_arguments; + using value_type = expression_value_type; + using T = value_type; + + KFR_MEM_INTRINSIC size_t size() const CMT_NOEXCEPT { return expression_with_arguments::size() * 2; } + + template + KFR_INTRINSIC friend vec get_elements(const expression_upsample& self, index_t index, + axis_params<0, N>) + { + const vec x = get_elements(self.first(), index / 2, axis_params<0, N / 2>()); + return interleave(x, zerovector(x)); + } + KFR_INTRINSIC friend vec get_elements(const expression_upsample& self, index_t index, + axis_params<0, 1>) + { + if (index & 1) + return 0; + else + return get_elements(self.first(), index / 2, axis_params<0, 1>()); + } +}; + +template +struct expression_upsample<4, E> : expression_with_arguments +{ + using expression_with_arguments::expression_with_arguments; + using value_type = expression_value_type; + using T = value_type; + + KFR_MEM_INTRINSIC size_t size() const CMT_NOEXCEPT { return expression_with_arguments::size() * 4; } + + template + KFR_INTRINSIC friend vec get_elements(const expression_upsample& self, index_t index, + axis_params<0, N>) CMT_NOEXCEPT + { + const vec x = get_elements(self.first(), index / 4, axis_params<0, N / 4>()); + const vec xx = interleave(x, zerovector(x)); + return interleave(xx, zerovector(xx)); + } + KFR_INTRINSIC friend vec get_elements(const expression_upsample& self, index_t index, + axis_params<0, 2>) CMT_NOEXCEPT + { + switch (index & 3) + { + case 0: + return interleave(get_elements(self.first(), index / 4, axis_params<0, 1>()), zerovector()); + case 3: + return interleave(zerovector(), get_elements(self.first(), index / 4, axis_params<0, 1>())); + default: + return 0; + } + } + KFR_INTRINSIC friend vec get_elements(const expression_upsample& self, index_t index, + axis_params<0, 1>) CMT_NOEXCEPT + { + if (index & 3) + return 0; + else + return get_elements(self.first(), index / 4, axis_params<0, 1>()); + } +}; + +template +struct expression_downsample<2, offset, E> : expression_with_arguments +{ + using expression_with_arguments::expression_with_arguments; + using value_type = expression_value_type; + using T = value_type; + + KFR_MEM_INTRINSIC size_t size() const CMT_NOEXCEPT { return expression_with_arguments::size() / 2; } + + template + KFR_INTRINSIC friend vec get_elements(const expression_downsample& self, size_t index, + axis_params<0, N>) CMT_NOEXCEPT + { + const vec x = get_elements(self.first(), index * 2, axis_params<0, N * 2>()); + return x.shuffle(csizeseq); + } +}; + +template +struct expression_downsample<4, offset, E> : expression_with_arguments +{ + using expression_with_arguments::expression_with_arguments; + using value_type = expression_value_type; + using T = value_type; + + KFR_MEM_INTRINSIC size_t size() const CMT_NOEXCEPT { return expression_with_arguments::size() / 4; } + + template + KFR_INTRINSIC friend vec get_elements(const expression_downsample& self, index_t index, + axis_params<0, N>) CMT_NOEXCEPT + { + const vec x = get_elements(self.first(), index * 4, axis_params<0, N * 4>()); + return x.shuffle(csizeseq); + } +}; +} // namespace internal + +template +KFR_FUNCTION internal::expression_downsample<2, offset, E1> downsample2(E1&& e1, + csize_t = csize_t<0>()) +{ + return internal::expression_downsample<2, offset, E1>(std::forward(e1)); +} + +template +KFR_FUNCTION internal::expression_downsample<4, offset, E1> downsample4(E1&& e1, + csize_t = csize_t<0>()) +{ + return internal::expression_downsample<4, offset, E1>(std::forward(e1)); +} + +template +KFR_FUNCTION internal::expression_upsample<2, E1> upsample2(E1&& e1) +{ + return internal::expression_upsample<2, E1>(std::forward(e1)); +} + +template +KFR_FUNCTION internal::expression_upsample<4, E1> upsample4(E1&& e1) +{ + return internal::expression_upsample<4, E1>(std::forward(e1)); +} + +template +KFR_FUNCTION samplerate_converter sample_rate_converter(sample_rate_conversion_quality quality, + size_t interpolation_factor, + size_t decimation_factor, + subtype scale = subtype(1), + subtype cutoff = 0.5f) +{ + using itype = typename samplerate_converter::itype; + return samplerate_converter(quality, itype(interpolation_factor), itype(decimation_factor), scale, + cutoff); +} + +// Deprecated in 0.9.2 +template +KFR_FUNCTION samplerate_converter resampler(sample_rate_conversion_quality quality, + size_t interpolation_factor, size_t decimation_factor, + subtype scale = subtype(1), subtype cutoff = 0.5f) +{ + using itype = typename samplerate_converter::itype; + return samplerate_converter(quality, itype(interpolation_factor), itype(decimation_factor), scale, + cutoff); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/speaker.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/speaker.hpp new file mode 100644 index 00000000..55f650dd --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/speaker.hpp @@ -0,0 +1,97 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +namespace kfr +{ + +enum class Speaker : int +{ + None = -1, + Mono = 0, + M = static_cast(Mono), + Left = 1, + L = static_cast(Left), + Right = 2, + R = static_cast(Right), + Center = 3, + C = static_cast(Center), + Lfe = 4, + Ls = 5, + LeftSurround = static_cast(Ls), + Rs = 6, + RightSurround = static_cast(Rs), + Lc = 7, + Rc = 8, + S = 9, + Cs = static_cast(S), + Sl = 10, + Sr = 11, + Tm = 12, + Tfl = 13, + Tfc = 14, + Tfr = 15, + Trl = 16, + Trc = 17, + Trr = 18, + Lfe2 = 19 +}; + +enum class SpeakerArrangement : int +{ + None = -1, + Mono = 0, + Stereo = 1, + StereoSurround = 2, + StereoCenter = 3, + StereoSide = 4, + StereoCLfe = 5, + Cine30 = 6, + Music30 = 7, + Cine31 = 8, + Music31 = 9, + Cine40 = 10, + Music40 = 11, + Cine41 = 12, + Music41 = 13, + Arr50 = 14, + Arr51 = 15, + Cine60 = 16, + Music60 = 17, + Cine61 = 18, + Music61 = 19, + Cine70 = 20, + Music70 = 21, + Cine71 = 22, + Music71 = 23, + Cine80 = 24, + Music80 = 25, + Cine81 = 26, + Music81 = 27, + Arr102 = 28 +}; + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/special.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/special.hpp new file mode 100644 index 00000000..2ace2158 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/special.hpp @@ -0,0 +1,88 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../simd/operators.hpp" +#include "../simd/vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns expression template that generates a unit impulse + */ +template +auto unitimpulse() +{ + return lambda( + [](shape<1> index, auto x) + { + vec_shape sh{}; + if (CMT_UNLIKELY(index[0] == 0)) + return onoff(sh); + else + return zerovector(sh); + }); +} + +template +auto jaehne_arg(size_t size) +{ + return truncate(constants::pi_s(1, 2) * sqr(linspace(T(0), T(size), size, false)) / size, size); +} + +/** + * @brief Returns expression template that generates a jaehne vector + * Generates the sine with linearly increasing frequency from 0hz to nyquist frequency. + */ +template +auto jaehne(identity magn, size_t size) +{ + return magn * sin(jaehne_arg(size)); +} + +template +auto swept_arg(size_t size) +{ + return truncate(constants::pi_s(1, 4) * sqr(sqr(linspace(T(0), T(size), size, false)) / sqr(T(size))) * + T(size), + size); +} + +/** + * @brief Returns expression template that generates a jaehne vector + * Generates the sine with logarithmically increasing frequency from 0hz to nyquist frequency. + */ +template +auto swept(identity magn, size_t size) +{ + return magn * sin(swept_arg(size)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/units.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/units.hpp new file mode 100644 index 00000000..83c397c7 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/units.hpp @@ -0,0 +1,206 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../math/log_exp.hpp" +#include "../simd/abs.hpp" +#include "../simd/vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +using sample_rate_t = double; + +namespace intrinsics +{ +template +KFR_INTRINSIC std::common_type_t fix_nans(const T1& val, const T2& replacement) +{ + return select(val != val, replacement, val); +} + +template > +KFR_INTRINSIC TF amp_to_dB(const T& amp) +{ + return fix_nans(log(static_cast(abs(amp))) * subtype(8.6858896380650365530225783783322), + -c_infinity); + // return T( 20.0 ) * log10( level ); +} + +template > +KFR_INTRINSIC TF dB_to_amp(const T& dB) +{ + return exp(dB * subtype(0.11512925464970228420089957273422)); + // return exp10( dB / 20 ); +} + +template > +KFR_INTRINSIC TF amp_to_dB(const T& amp, const T& offset) +{ + return fix_nans( + log_fmadd(static_cast(abs(amp)), subtype(8.6858896380650365530225783783322), offset), + -c_infinity); + // return T( 20.0 ) * log10( level ); +} + +template > +KFR_INTRINSIC TF dB_to_amp(const T& dB, const T& offset) +{ + auto offs = -subtype(0.11512925464970228420089957273422) * offset; + return exp_fmadd(dB, subtype(0.11512925464970228420089957273422), offs); + // return exp10( dB / 20 ); +} + +template > +KFR_INTRINSIC Tout power_to_dB(const T& x) +{ + return log(static_cast(abs(x))) * (10 * c_recip_log_10); +} + +template > +KFR_INTRINSIC Tout dB_to_power(const T& x) +{ + if (CMT_UNLIKELY(x == -c_infinity)) + return 0.0; + else + return exp(x * (c_log_10 / 10.0)); +} + +template > +KFR_INTRINSIC TF note_to_hertz(const T& note) +{ + const subtype offset = 2.1011784386926213177653145771814; + + return intrinsics::exp_fmadd(note, subtype(0.05776226504666210911810267678818), offset); +} + +template > +KFR_INTRINSIC TF hertz_to_note(const T& hertz) +{ + const subtype offset = -36.376316562295915248836189714583; + + return intrinsics::log_fmadd(hertz, subtype(17.312340490667560888319096172023), offset); +} + +template >> +KFR_INTRINSIC Tc note_to_hertz(const T1& note, const T2& tunenote, const T3& tunehertz) +{ + const Tc offset = log(tunehertz) - tunenote * subtype(0.05776226504666210911810267678818); + + return intrinsics::exp_fmadd(note, subtype(0.05776226504666210911810267678818), offset); +} + +template >> +KFR_INTRINSIC Tc hertz_to_note(const T1& hertz, const T2& tunenote, const T3& tunehertz) +{ + const Tc offset = tunenote - log(tunehertz) * subtype(17.312340490667560888319096172023); + + return intrinsics::log_fmadd(hertz, subtype(17.312340490667560888319096172023), offset); +} +} // namespace intrinsics +KFR_I_FN(note_to_hertz) +KFR_I_FN(hertz_to_note) +KFR_I_FN(amp_to_dB) +KFR_I_FN(dB_to_amp) +KFR_I_FN(power_to_dB) +KFR_I_FN(dB_to_power) + +template )> +KFR_FUNCTION flt_type note_to_hertz(const T1& x) +{ + return intrinsics::note_to_hertz(x); +} + +template +KFR_FUNCTION expression_function note_to_hertz(E1&& x) +{ + return { fn::note_to_hertz(), std::forward(x) }; +} + +template )> +KFR_FUNCTION flt_type hertz_to_note(const T1& x) +{ + return intrinsics::hertz_to_note(x); +} + +template +KFR_FUNCTION expression_function hertz_to_note(E1&& x) +{ + return { fn::hertz_to_note(), std::forward(x) }; +} + +template )> +KFR_FUNCTION flt_type amp_to_dB(const T1& x) +{ + return intrinsics::amp_to_dB(x); +} + +template +KFR_FUNCTION expression_function amp_to_dB(E1&& x) +{ + return { fn::amp_to_dB(), std::forward(x) }; +} + +template )> +KFR_FUNCTION flt_type dB_to_amp(const T1& x) +{ + return intrinsics::dB_to_amp(x); +} + +template +KFR_FUNCTION expression_function dB_to_amp(E1&& x) +{ + return { fn::dB_to_amp(), std::forward(x) }; +} + +template )> +KFR_FUNCTION flt_type power_to_dB(const T1& x) +{ + return intrinsics::power_to_dB(x); +} + +template +KFR_FUNCTION expression_function power_to_dB(E1&& x) +{ + return { fn::power_to_dB(), std::forward(x) }; +} + +template )> +KFR_FUNCTION flt_type dB_to_power(const T1& x) +{ + return intrinsics::dB_to_power(x); +} + +template +KFR_FUNCTION expression_function dB_to_power(E1&& x) +{ + return { fn::dB_to_power(), std::forward(x) }; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/waveshaper.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/waveshaper.hpp new file mode 100644 index 00000000..ed8053d0 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/waveshaper.hpp @@ -0,0 +1,96 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/expression.hpp" +#include "../math/hyperbolic.hpp" +#include "../simd/clamp.hpp" +#include "../simd/operators.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +inline auto waveshaper_hardclip(E1&& input, double clip_level) +{ + return clamp(input, -clip_level, +clip_level); +} + +template +inline auto waveshaper_tanh(E1&& input, double saturation) +{ + return tanh(saturation * input) * (coth(saturation)); +} + +template )> +KFR_FUNCTION flt_type saturate_I(const T1& x) +{ + const flt_type xx = -1 / (abs(static_cast>(x)) + 1) + 1; + return mulsign(xx, static_cast>(x)); +} +KFR_FN(saturate_I) + +template )> +KFR_FUNCTION flt_type saturate_II(const T1& x) +{ + const flt_type xx = sqr(abs(static_cast>(x)) + 1); + return mulsign((xx - 1) / (xx + 1), static_cast>(x)); +} +KFR_FN(saturate_II) + +template +KFR_FUNCTION expression_function saturate_I(E1&& x) +{ + return { fn::saturate_I(), std::forward(x) }; +} + +template +KFR_FUNCTION expression_function saturate_II(E1&& x) +{ + return { fn::saturate_II(), std::forward(x) }; +} + +template +inline auto waveshaper_saturate_I(E1&& input, double saturation) +{ + return saturate_I(saturation * input) / (saturate_I(saturation)); +} + +template +inline auto waveshaper_saturate_II(E1&& input, double saturation) +{ + return saturate_II(saturation * input) / (saturate_II(saturation)); +} + +template +inline auto waveshaper_poly(E1&& input, fbase c1, fbase c3, Cs... cs) +{ + return horner_odd(input, c1, c3, static_cast(cs)...); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/weighting.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/weighting.hpp new file mode 100644 index 00000000..91b56943 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/weighting.hpp @@ -0,0 +1,136 @@ +/** @addtogroup dsp_extra + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/expression.hpp" +#include "../math/sqrt.hpp" +#include "../simd/operators.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC T weight_a_unnorm(T f) +{ + const T f2 = pow2(f); + const T nom = pow2(12200) * pow4(f); + const T den = (f2 + pow2(20.6)) * (sqrt((f2 + pow2(107.7)) * (f2 + pow2(737.9)))) * (f2 + pow2(12200)); + return nom / den; +} + +template +constexpr inline T weight_a_gain = T(1.25889662908332766733); + +template +KFR_INTRINSIC T aweighting(T f) +{ + return weight_a_unnorm(f) * weight_a_gain>; +} + +template +KFR_INTRINSIC T weight_b_unnorm(T f) +{ + const T f2 = pow2(f); + const T nom = pow2(12200) * pow3(f); + const T den = (f2 + pow2(20.6)) * (sqrt((f2 + pow2(158.5)))) * (f2 + pow2(12200)); + + return nom / den; +} + +template +constexpr inline T weight_b_gain = T(1.01971824783723263863); + +template +KFR_INTRINSIC T bweighting(T f) +{ + return weight_b_unnorm(f) * weight_b_gain>; +} + +template +KFR_INTRINSIC T weight_c_unnorm(T f) +{ + const T f2 = pow2(f); + const T nom = pow2(12200) * f2; + const T den = (f2 + pow2(20.6)) * (f2 + pow2(12200)); + + return nom / den; +} + +template +constexpr inline T weight_c_gain = T(1.00714583514109112805); + +template +KFR_INTRINSIC T cweighting(T f) +{ + return weight_c_unnorm(f) * weight_c_gain>; +} +} // namespace intrinsics +KFR_I_FN(aweighting) +KFR_I_FN(bweighting) +KFR_I_FN(cweighting) + +template )> +KFR_INTRINSIC T1 aweighting(const T1& x) +{ + return intrinsics::aweighting(x); +} + +template +KFR_INTRINSIC expression_function aweighting(E1&& x) +{ + return { fn::aweighting(), std::forward(x) }; +} + +template )> +KFR_INTRINSIC T1 bweighting(const T1& x) +{ + return intrinsics::bweighting(x); +} + +template +KFR_INTRINSIC expression_function bweighting(E1&& x) +{ + return { fn::bweighting(), std::forward(x) }; +} + +template )> +KFR_INTRINSIC T1 cweighting(const T1& x) +{ + return intrinsics::cweighting(x); +} + +template +KFR_INTRINSIC expression_function cweighting(E1&& x) +{ + return { fn::cweighting(), std::forward(x) }; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/dsp/window.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/window.hpp new file mode 100644 index 00000000..a4df4535 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/dsp/window.hpp @@ -0,0 +1,644 @@ +/** @addtogroup window + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/handle.hpp" +#include "../math/log_exp.hpp" +#include "../math/modzerobessel.hpp" +#include "../math/sin_cos.hpp" +#include "../math/sqrt.hpp" +#include "../simd/vec.hpp" + +namespace kfr +{ + +enum class window_type +{ + rectangular = 1, + triangular = 2, + bartlett = 3, + cosine = 4, + hann = 5, + bartlett_hann = 6, + hamming = 7, + bohman = 8, + blackman = 9, + blackman_harris = 10, + kaiser = 11, + flattop = 12, + gaussian = 13, + lanczos = 14, + cosine_np = 15, + planck_taper = 16, + tukey = 17, +}; + +template +using cwindow_type_t = cval_t; + +template +constexpr cwindow_type_t cwindow_type{}; + +enum class window_symmetry +{ + periodic, + symmetric +}; + +inline namespace CMT_ARCH_NAME +{ + +enum class window_metrics +{ + metrics_0_1, + metrics_m1_1, + metrics_mpi_pi, + metrics_m1_1_trunc, + metrics_m1_1_trunc2, +}; + +template +struct window_linspace : expression_linspace +{ + window_linspace(cval_t, size_t size, + window_symmetry symmetry) + : expression_linspace{ 0, 1, size, symmetry == window_symmetry::symmetric } + { + } + window_linspace(cval_t, size_t size, + window_symmetry symmetry) + : expression_linspace{ -1, 1, size, symmetry == window_symmetry::symmetric } + { + } + window_linspace(cval_t, size_t size, + window_symmetry symmetry) + : expression_linspace{ -c_pi, +c_pi, size, symmetry == window_symmetry::symmetric } + { + } + window_linspace(cval_t, size_t size, + window_symmetry symmetry) + : expression_linspace{ symmetric_linspace, calc_p(size, symmetry == window_symmetry::symmetric), + size, symmetry == window_symmetry::symmetric } + { + } + window_linspace(cval_t, size_t size, + window_symmetry symmetry) + : expression_linspace{ symmetric_linspace, calc_p2(size, symmetry == window_symmetry::symmetric), + size, symmetry == window_symmetry::symmetric } + { + } + static T calc_p(size_t size, bool sym) + { + if (!sym) + ++size; + return T(size - 1) / (size); + } + static T calc_p2(size_t size, bool sym) + { + if (!sym) + ++size; + return (size & 1) ? T(size - 1) / T(size + 1) : T(size - 1) / (size); + } +}; + +template +struct expression_window : expression_traits_defaults +{ + using value_type = T; + constexpr static size_t dims = 1; + constexpr static shape get_shape(const expression_window& self) + { + return shape(self.m_size); + } + constexpr static shape get_shape() { return shape<1>(undefined_size); } + + constexpr expression_window(size_t size) : m_size(size) {} + + size_t m_size; + size_t size() const { return m_size; } +}; + +template +struct expression_rectangular : expression_window +{ + expression_rectangular(size_t size, T = T(), window_symmetry symmetry = window_symmetry::symmetric) + : expression_window(size) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_rectangular& self, shape<1> index, + axis_params<0, N>) + { + using TI = utype; + const vec i = enumerate(vec_shape()) + static_cast(index.front()); + return select(i < static_cast(self.m_size), T(1), T(0)); + } +}; + +template +struct expression_window_with_metrics : expression_window +{ + expression_window_with_metrics(size_t size, T arg = T(), + window_symmetry symmetry = window_symmetry::symmetric) + : expression_window(size), linspace(cval, size, symmetry), arg(arg) + { + } + +protected: + window_linspace linspace; + T arg; +}; + +template +struct expression_triangular : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_triangular& self, shape<1> index, + axis_params<0, N> sh) + { + return 1 - abs(get_elements(self.linspace, index, sh)); + } +}; + +template +struct expression_bartlett : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + template + KFR_INTRINSIC friend vec get_elements(const expression_bartlett& self, shape<1> index, + axis_params<0, N> sh) + { + return 1 - abs(get_elements(self.linspace, index, sh)); + } +}; + +template +struct expression_cosine : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_cosine& self, shape<1> index, + axis_params<0, N> sh) + { + return sin(c_pi * (get_elements(self.linspace, index, sh))); + } +}; +template +struct expression_cosine_np : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_cosine_np& self, shape<1> index, + axis_params<0, N> sh) + { + return sin(c_pi * (1 + get_elements(self.linspace, index, sh))); + } +}; + +template +struct expression_hann : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_hann& self, shape<1> index, + axis_params<0, N> sh) + { + return T(0.5) * (T(1) - cos(c_pi * get_elements(self.linspace, index, sh))); + } +}; + +template +struct expression_bartlett_hann : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_bartlett_hann& self, shape<1> index, + axis_params<0, N> sh) + { + const vec xx = get_elements(self.linspace, index, sh); + return T(0.62) - T(0.48) * abs(xx - T(0.5)) + T(0.38) * cos(c_pi * (xx - T(0.5))); + } +}; + +template +struct expression_hamming : expression_window_with_metrics +{ + expression_hamming(size_t size, T alpha = 0.54, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, alpha, symmetry) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_hamming& self, shape<1> index, + axis_params<0, N> sh) + { + return self.arg - (T(1.0) - self.arg) * (cos(c_pi * get_elements(self.linspace, index, sh))); + } +}; + +template +struct expression_bohman : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_bohman& self, shape<1> index, + axis_params<0, N> sh) + { + const vec n = abs(get_elements(self.linspace, index, sh)); + return (T(1) - n) * cos(c_pi * n) + (T(1) / c_pi)*sin(c_pi * n); + } +}; + +template +struct expression_blackman : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + expression_blackman(size_t size, T alpha = 0.16, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, alpha, symmetry), + a0((1 - alpha) * 0.5), a1(0.5), a2(alpha * 0.5) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_blackman& self, shape<1> index, + axis_params<0, N> sh) + { + const vec n = get_elements(self.linspace, index, sh); + return self.a0 - self.a1 * cos(c_pi * n) + self.a2 * cos(c_pi * n); + } + +private: + T a0, a1, a2; +}; + +template +struct expression_blackman_harris : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_blackman_harris& self, shape<1> index, + axis_params<0, N> sh) + { + const vec n = get_elements(self.linspace, index, sh) * c_pi; + return T(0.35875) - T(0.48829) * cos(n) + T(0.14128) * cos(2 * n) - T(0.01168) * cos(3 * n); + } +}; + +template +struct expression_kaiser : expression_window_with_metrics +{ + expression_kaiser(size_t size, T beta = 0.5, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, beta, symmetry), + m(reciprocal(modzerobessel(make_vector(beta))[0])) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_kaiser& self, shape<1> index, + axis_params<0, N> sh) + { + return modzerobessel(self.arg * sqrt(1 - sqr(get_elements(self.linspace, index, sh)))) * self.m; + } + +private: + T m; +}; + +template +struct expression_flattop : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + + template + KFR_INTRINSIC friend vec get_elements(const expression_flattop& self, shape<1> index, + axis_params<0, N> sh) + { + const vec n = get_elements(self.linspace, index, sh) * c_pi; + constexpr T a0 = 0.21557895; + constexpr T a1 = 0.41663158; + constexpr T a2 = 0.277263158; + constexpr T a3 = 0.083578947; + constexpr T a4 = 0.006947368; + return a0 - a1 * cos(n) + a2 * cos(2 * n) - a3 * cos(3 * n) + a4 * cos(4 * n); + } +}; + +template +struct expression_gaussian : expression_window_with_metrics +{ + /// alpha = std / 2N + expression_gaussian(size_t size, T alpha = 2.5, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, alpha, symmetry) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_gaussian& self, shape<1> index, + axis_params<0, N> sh) + { + return exp(T(-0.5) * sqr(self.arg * get_elements(self.linspace, index, sh))); + } +}; + +template +struct expression_lanczos : expression_window_with_metrics +{ + using expression_window_with_metrics::expression_window_with_metrics; + template + KFR_INTRINSIC friend vec get_elements(const expression_lanczos& self, shape<1> index, + axis_params<0, N> sh) + { + return sinc(get_elements(self.linspace, index, sh)); + } +}; + +template +struct expression_planck_taper : expression_window_with_metrics +{ + expression_planck_taper(size_t size, T epsilon, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, epsilon, symmetry) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_planck_taper& self, shape<1> index, + axis_params<0, N> sh) + { + vec x = (T(1) - abs(get_elements(self.linspace, index, sh))) / (T(2) * self.arg); + vec val = T(1) / (T(1) + exp(T(1) / x - T(1) / (T(1) - x))); + return select(x <= T(0), T(0), select(x >= T(1), T(1), val)); + } +}; + +template +struct expression_tukey : expression_window_with_metrics +{ + expression_tukey(size_t size, T epsilon, window_symmetry symmetry = window_symmetry::symmetric) + : expression_window_with_metrics(size, epsilon, symmetry) + { + } + template + KFR_INTRINSIC friend vec get_elements(const expression_tukey& self, shape<1> index, + axis_params<0, N> sh) + { + vec x = (T(1) - abs(get_elements(self.linspace, index, sh))) / self.arg; + vec val = T(0.5) * (T(1) - cos(c_pi * x)); + return select(x <= T(0), T(0), select(x >= T(1), T(1), val)); + } +}; + +template +struct window_by_type; + +#define KFR_WINDOW_BY_TYPE(win) \ + template <> \ + struct window_by_type \ + { \ + template \ + using type = expression_##win; \ + }; +KFR_WINDOW_BY_TYPE(rectangular) +KFR_WINDOW_BY_TYPE(triangular) +KFR_WINDOW_BY_TYPE(bartlett) +KFR_WINDOW_BY_TYPE(cosine) +KFR_WINDOW_BY_TYPE(hann) +KFR_WINDOW_BY_TYPE(bartlett_hann) +KFR_WINDOW_BY_TYPE(hamming) +KFR_WINDOW_BY_TYPE(bohman) +KFR_WINDOW_BY_TYPE(blackman) +KFR_WINDOW_BY_TYPE(blackman_harris) +KFR_WINDOW_BY_TYPE(kaiser) +KFR_WINDOW_BY_TYPE(flattop) +KFR_WINDOW_BY_TYPE(gaussian) +KFR_WINDOW_BY_TYPE(lanczos) +KFR_WINDOW_BY_TYPE(cosine_np) +KFR_WINDOW_BY_TYPE(planck_taper) +KFR_WINDOW_BY_TYPE(tukey) +#undef KFR_WINDOW_BY_TYPE + +/** + * @brief Returns template expression that generates Rrectangular window of length @c size + */ +template +KFR_FUNCTION expression_rectangular window_rectangular(size_t size, ctype_t = ctype_t()) +{ + return expression_rectangular(size, T()); +} + +/** + * @brief Returns template expression that generates Triangular window of length @c size + */ +template +KFR_FUNCTION expression_triangular window_triangular(size_t size, ctype_t = ctype_t()) +{ + return expression_triangular(size); +} + +/** + * @brief Returns template expression that generates Bartlett window of length @c size + */ +template +KFR_FUNCTION expression_bartlett window_bartlett(size_t size, ctype_t = ctype_t()) +{ + return expression_bartlett(size); +} + +/** + * @brief Returns template expression that generates Cosine window of length @c size + */ +template +KFR_FUNCTION expression_cosine window_cosine(size_t size, ctype_t = ctype_t()) +{ + return expression_cosine(size); +} + +/** + * @brief Returns template expression that generates Cosine window (numpy compatible) of length @c size + */ +template +KFR_FUNCTION expression_cosine_np window_cosine_np(size_t size, ctype_t = ctype_t()) +{ + return expression_cosine_np(size); +} + +/** + * @brief Returns template expression that generates Hann window of length @c size + */ +template +KFR_FUNCTION expression_hann window_hann(size_t size, ctype_t = ctype_t()) +{ + return expression_hann(size); +} + +/** + * @brief Returns template expression that generates Bartlett-Hann window of length @c size + */ +template +KFR_FUNCTION expression_bartlett_hann window_bartlett_hann(size_t size, ctype_t = ctype_t()) +{ + return expression_bartlett_hann(size); +} + +/** + * @brief Returns template expression that generates Hamming window of length @c size where α = @c + * alpha + */ +template +KFR_FUNCTION expression_hamming window_hamming(size_t size, identity alpha = 0.54, + ctype_t = ctype_t()) +{ + return expression_hamming(size, alpha); +} + +/** + * @brief Returns template expression that generates Bohman window of length @c size + */ +template +KFR_FUNCTION expression_bohman window_bohman(size_t size, ctype_t = ctype_t()) +{ + return expression_bohman(size); +} + +/** + * @brief Returns template expression that generates Blackman window of length @c size where α = @c + * alpha + */ +template +KFR_FUNCTION expression_blackman window_blackman(size_t size, identity alpha = 0.16, + window_symmetry symmetry = window_symmetry::symmetric, + ctype_t = ctype_t()) +{ + return expression_blackman(size, alpha, symmetry); +} + +/** + * @brief Returns template expression that generates Blackman-Harris window of length @c size + */ +template +KFR_FUNCTION expression_blackman_harris window_blackman_harris( + size_t size, window_symmetry symmetry = window_symmetry::symmetric, ctype_t = ctype_t()) +{ + return expression_blackman_harris(size, T(), symmetry); +} + +/** + * @brief Returns template expression that generates Kaiser window of length @c size where β = @c + * beta + */ +template +KFR_FUNCTION expression_kaiser window_kaiser(size_t size, identity beta = T(0.5), + ctype_t = ctype_t()) +{ + return expression_kaiser(size, beta); +} + +/** + * @brief Returns template expression that generates Flat top window of length @c size + */ +template +KFR_FUNCTION expression_flattop window_flattop(size_t size, ctype_t = ctype_t()) +{ + return expression_flattop(size); +} + +/** + * @brief Returns template expression that generates Gaussian window of length @c size where α = @c + * alpha + */ +template +KFR_FUNCTION expression_gaussian window_gaussian(size_t size, identity alpha = 2.5, + ctype_t = ctype_t()) +{ + return expression_gaussian(size, alpha); +} + +/** + * @brief Returns template expression that generates Lanczos window of length @c size + */ +template +KFR_FUNCTION expression_lanczos window_lanczos(size_t size, ctype_t = ctype_t()) +{ + return expression_lanczos(size); +} + +/** + * @brief Returns template expression that generates Planck-taper window of length @c size + */ +template +KFR_FUNCTION expression_planck_taper window_planck_taper( + size_t size, identity epsilon, window_symmetry symmetry = window_symmetry::symmetric, + ctype_t = ctype_t()) +{ + return expression_planck_taper(size, epsilon, symmetry); +} + +/** + * @brief Returns template expression that generates Tukey window of length @c size (numpy compatible) + */ +template +KFR_FUNCTION expression_tukey window_tukey(size_t size, identity alpha, + window_symmetry symmetry = window_symmetry::symmetric, + ctype_t = ctype_t()) +{ + return expression_tukey(size, alpha, symmetry); +} + +template ::template type> +CMT_NOINLINE window_expr window(size_t size, cval_t, identity win_param = T(), + window_symmetry symmetry = window_symmetry::symmetric, + ctype_t = ctype_t()) +{ + return window_expr(size, win_param, symmetry); +} + +template +CMT_NOINLINE expression_handle window(size_t size, window_type type, identity win_param, + window_symmetry symmetry = window_symmetry::symmetric, + ctype_t = ctype_t()) +{ + return cswitch( + cvals_t(), + type, + [size, win_param, symmetry](auto win) + { + constexpr window_type window = val_of(decltype(win)()); + return to_handle(typename window_by_type::template type(size, win_param, symmetry)); + }, + fn_generic::returns>()); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/except.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/except.hpp new file mode 100644 index 00000000..eea537ac --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/except.hpp @@ -0,0 +1,97 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "cident.h" +#include "cometa/string.hpp" +#include + +namespace kfr +{ + +class exception : public std::exception +{ +public: + using std::exception::exception; + exception(std::string str) : m_what(std::move(str)) {} + + const char* what() const noexcept final { return m_what.c_str(); } + +private: + std::string m_what; +}; +class logic_error : public exception +{ +public: + using exception::exception; +}; +class runtime_error : public exception +{ +public: + using exception::exception; +}; + +#ifndef KFR_THROW_EXCEPTION +#define KFR_THROW_EXCEPTION(kind, ...) \ + do \ + { \ + throw ::kfr::CMT_CONCAT(kind, _error)(kfr::as_string(__VA_ARGS__)); \ + } while (0) +#endif + +#define KFR_PRINT_AND_ABORT(kind, ...) \ + do \ + { \ + kfr::errorln("KFR " CMT_STRINGIFY(kind) " error: ", __VA_ARGS__); \ + std::abort(); \ + } while (0) + +#if CMT_HAS_EXCEPTIONS +#define KFR_REPORT_ERROR KFR_THROW_EXCEPTION +#else +#define KFR_REPORT_ERROR KFR_PRINT_AND_ABORT +#endif + +#define KFR_CHECK_IMPL(cond, kind, ...) \ + do \ + { \ + if (CMT_UNLIKELY(!(cond))) \ + KFR_REPORT_ERROR(kind, __VA_ARGS__); \ + } while (0) + +#define KFR_REPORT_RUNTIME_ERROR(...) KFR_REPORT_ERROR(runtime, __VA_ARGS__) + +#define KFR_REPORT_LOGIC_ERROR(...) KFR_REPORT_ERROR(logic, __VA_ARGS__) + +#if !defined(KFR_DISABLE_CHECKS) + +#define KFR_RUNTIME_CHECK(cond, ...) KFR_CHECK_IMPL(cond, runtime, __VA_ARGS__) + +#define KFR_LOGIC_CHECK(cond, ...) KFR_CHECK_IMPL(cond, logic, __VA_ARGS__) + +#else +#define KFR_RUNTIME_CHECK(cond, ...) CMT_NOOP +#define KFR_LOGIC_CHECK(cond, ...) CMT_NOOP + +#endif + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/io.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/io.hpp new file mode 100644 index 00000000..ffe355fe --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/io.hpp @@ -0,0 +1,30 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "base.hpp" + +#include "io/audiofile.hpp" +#include "io/file.hpp" +#include "io/python_plot.hpp" +#include "io/tostring.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/io/audiofile.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/io/audiofile.hpp new file mode 100644 index 00000000..6071f117 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/io/audiofile.hpp @@ -0,0 +1,276 @@ +/** @addtogroup audio_io + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/conversion.hpp" +#include "../base/univector.hpp" +#include "../cometa/ctti.hpp" +#include "../simd/vec.hpp" +#include "file.hpp" + +namespace kfr +{ + +struct audio_format +{ + size_t channels = 2; + audio_sample_type type = audio_sample_type::i16; + fmax samplerate = 44100; + bool use_w64 = false; +}; + +struct audio_format_and_length : audio_format +{ + using audio_format::audio_format; + constexpr audio_format_and_length() CMT_NOEXCEPT {} + constexpr audio_format_and_length(const audio_format& fmt) : audio_format(fmt) {} + + imax length = 0; // in samples +}; + +template +struct audio_reader : public abstract_reader +{ + /// @brief Reads interleaved audio + using abstract_reader::read; + + univector2d read_channels() { return read_channels(format().length); } + + univector2d read_channels(size_t size) + { + univector interleaved = read(size * format().channels); + univector2d input_channels(format().channels, + univector(interleaved.size() / format().channels)); + deinterleave(input_channels, interleaved); + return input_channels; + } + + /// @brief Returns audio format description + virtual const audio_format_and_length& format() const = 0; +}; + +template +struct audio_writer : public abstract_writer +{ + /// @brief Writes interleaved audio + using abstract_writer::write; + + template + size_t write_channels(const univector2d& data) + { + const univector interleaved = interleave(data); + return write(interleaved) / format().channels; + } + + /// @brief Returns audio format description + virtual const audio_format_and_length& format() const = 0; + + /// @brief Finishes writing and closes underlying writer + virtual void close() = 0; +}; + +#ifndef KFR_DISABLE_WAV + +namespace internal_generic +{ +struct wav_file; +struct wav_file_deleter +{ + void operator()(wav_file*); +}; +} // namespace internal_generic + +/// @brief WAV format writer +template +struct audio_writer_wav : audio_writer +{ + /// @brief Constructs WAV writer using target writer and format + audio_writer_wav(std::shared_ptr>&& writer, const audio_format& fmt); + ~audio_writer_wav() override; + + using audio_writer::write; + + /// @brief Write data to underlying binary writer + /// data is PCM samples in interleaved format + /// size is the number of samples (PCM frames * channels) + size_t write(const T* data, size_t size) override; + + void close() override; + + const audio_format_and_length& format() const override { return fmt; } + + imax tell() const override { return fmt.length; } + + bool seek(imax, seek_origin) override { return false; } + +private: + std::shared_ptr> writer; + std::unique_ptr f; + audio_format_and_length fmt; +}; + +extern template struct audio_writer_wav; +extern template struct audio_writer_wav; +extern template struct audio_writer_wav; +extern template struct audio_writer_wav; +extern template struct audio_writer_wav; + +/// @brief WAV format reader +template +struct audio_reader_wav : audio_reader +{ + using audio_reader::read; + + /// @brief Constructs WAV reader + audio_reader_wav(std::shared_ptr>&& reader); + ~audio_reader_wav() override; + + /// @brief Reads and decodes audio data + size_t read(T* data, size_t size) override; + + /// @brief Seeks to specific sample + bool seek(imax offset, seek_origin origin) override; + + /// @brief Returns audio format description + const audio_format_and_length& format() const override { return fmt; } + + /// @brief Returns current position + imax tell() const override { return position; } + +private: + std::shared_ptr> reader; + std::unique_ptr f; + audio_format_and_length fmt; + imax position = 0; +}; + +extern template struct audio_reader_wav; +extern template struct audio_reader_wav; +extern template struct audio_reader_wav; +extern template struct audio_reader_wav; +extern template struct audio_reader_wav; +#endif + +#ifndef KFR_DISABLE_FLAC + +namespace internal_generic +{ +struct flac_file; +struct flac_file_deleter +{ + void operator()(flac_file*); +}; +} // namespace internal_generic + +/// @brief FLAC format reader +template +struct audio_reader_flac : audio_reader +{ + /// @brief Constructs FLAC reader + audio_reader_flac(std::shared_ptr>&& reader); + ~audio_reader_flac() override; + + /// @brief Reads and decodes audio data + size_t read(T* data, size_t size) override; + + /// @brief Seeks to specific sample + bool seek(imax offset, seek_origin origin) override; + + /// @brief Returns audio format description + const audio_format_and_length& format() const override { return fmt; } + + /// @brief Returns current position + imax tell() const override { return position; } + +private: + std::shared_ptr> reader; + std::unique_ptr f; + audio_format_and_length fmt; + imax position = 0; +}; + +extern template struct audio_reader_flac; +extern template struct audio_reader_flac; +extern template struct audio_reader_flac; +extern template struct audio_reader_flac; +extern template struct audio_reader_flac; +#endif + +#ifndef KFR_DISABLE_MP3 + +struct mp3_config +{ + uint32_t outputChannels; + uint32_t outputSampleRate; +}; + +namespace internal_generic +{ +struct mp3_file; +struct mp3_file_deleter +{ + void operator()(mp3_file*); +}; +} // namespace internal_generic + +/// @brief MP3 format reader +template +struct audio_reader_mp3 : audio_reader +{ + /// @brief Constructs MP3 reader + audio_reader_mp3(std::shared_ptr>&& reader); + ~audio_reader_mp3() override; + + /// @brief Reads and decodes audio data + size_t read(T* data, size_t size) override; + + /// @brief Seeks to specific sample + bool seek(imax offset, seek_origin origin) override; + + mp3_config config{ 0, 0 }; + + /// @brief Returns audio format description + const audio_format_and_length& format() const override { return fmt; } + + /// @brief Returns current position + imax tell() const override { return position; } + +private: + std::shared_ptr> reader; + std::unique_ptr f; + audio_format_and_length fmt; + imax position = 0; +}; + +extern template struct audio_reader_mp3; +extern template struct audio_reader_mp3; +extern template struct audio_reader_mp3; +extern template struct audio_reader_mp3; +extern template struct audio_reader_mp3; +#endif + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/io/file.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/io/file.hpp new file mode 100644 index 00000000..e14caadf --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/io/file.hpp @@ -0,0 +1,307 @@ +/** @addtogroup binary_io + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/univector.hpp" +#include "../simd/impl/function.hpp" +#include "../simd/vec.hpp" +#include +#include +#include + +namespace kfr +{ + +#ifdef CMT_OS_WIN +using filepath_char = wchar_t; +#define KFR_FILEPATH_PREFIX_CONCAT(x, y) x##y +#define KFR_FILEPATH(s) KFR_FILEPATH_PREFIX_CONCAT(L, s) +#else +using filepath_char = char; +#define KFR_FILEPATH(s) s +#endif + +using filepath = std::basic_string; + +#if defined _MSC_VER // MSVC +#define IO_SEEK_64 _fseeki64 +#define IO_TELL_64 _ftelli64 +#elif defined _WIN32 // MingW +#define IO_SEEK_64 fseeko64 +#define IO_TELL_64 ftello64 +#else // macOS, Linux +#define IO_SEEK_64 fseeko +#define IO_TELL_64 ftello +#endif + +/// @brief Opens file using portable path (char* on posix, wchar_t* on windows) +inline FILE* fopen_portable(const filepath_char* path, const filepath_char* mode) +{ +#ifdef CMT_OS_WIN + FILE* f = nullptr; + errno_t e = _wfopen_s(&f, path, mode); + (void)e; + return f; +#else + return fopen(path, mode); +#endif +} + +template +constexpr inline size_t element_size() +{ + return sizeof(T); +} +template <> +constexpr inline size_t element_size() +{ + return 1; +} + +/// @brief Seek origin +enum class seek_origin : int +{ + current = SEEK_CUR, ///< From the current position + begin = SEEK_SET, ///< From the beginning + end = SEEK_END, ///< From the end +}; + +/// @brief Base class for all typed readers and writer +template +struct abstract_stream +{ + virtual ~abstract_stream() {} + virtual imax tell() const = 0; + virtual bool seek(imax offset, seek_origin origin) = 0; + bool seek(imax offset, int origin) { return seek(offset, static_cast(origin)); } +}; + +namespace internal_generic +{ +struct empty +{ +}; + +} // namespace internal_generic + +/// @brief Base class for all typed readers +template +struct abstract_reader : abstract_stream +{ + virtual size_t read(T* data, size_t size) = 0; + + template + size_t read(univector& data) + { + return read(data.data(), data.size()); + } + size_t read(univector_ref&& data) { return read(data.data(), data.size()); } + + univector read(size_t size) + { + univector result(size); + this->read(result); + return result; + } + bool read(std::conditional_t, internal_generic::empty, T>& data) + { + return read(&data, 1) == 1; + } +}; + +/// @brief Base class for all typed writers +template +struct abstract_writer : abstract_stream +{ + virtual size_t write(const T* data, size_t size) = 0; + + template + size_t write(const univector& data) + { + return write(data.data(), data.size()); + } + size_t write(univector_ref&& data) { return write(data.data(), data.size()); } + bool write(const std::conditional_t, internal_generic::empty, T>& data) + { + return write(&data, 1) == 1; + } +}; + +template +struct reader_adapter : abstract_reader +{ + static_assert(element_size() % element_size() == 0 || + element_size() % element_size() == 0, + "From and To sizes must be compatible"); + reader_adapter(std::shared_ptr>&& reader) : reader(std::move(reader)) {} + virtual size_t read(To* data, size_t size) final + { + return reader->read(reinterpret_cast(data), size * element_size() / element_size()) * + element_size() / element_size(); + } + std::shared_ptr> reader; +}; + +template +struct writer_adapter : abstract_writer +{ + static_assert(element_size() % element_size() == 0 || + element_size() % element_size() == 0, + "From and To sizes must be compatible"); + writer_adapter(std::shared_ptr>&& writer) : writer(std::move(writer)) {} + virtual size_t write(const To* data, size_t size) final + { + return writer->write(reinterpret_cast(data), + size * element_size() / element_size()) * + element_size() / element_size(); + } + std::shared_ptr> writer; +}; + +/// @brief Binary reader +using binary_reader = abstract_reader<>; + +/// @brief Binary writer +using binary_writer = abstract_writer<>; + +/// @brief Byte reader +using byte_reader = abstract_reader; + +/// @brief Byte writer +using byte_writer = abstract_writer; + +/// @brief float reader +using f32_reader = abstract_reader; + +/// @brief float writer +using f32_writer = abstract_writer; + +struct file_handle +{ + file_handle(FILE* file) : file(file) {} + file_handle() = delete; + file_handle(const file_handle&) = delete; + file_handle(file_handle&& handle) : file(nullptr) { swap(handle); } + ~file_handle() + { + if (file) + { + fclose(file); + } + } + FILE* file; + void swap(file_handle& handle) { std::swap(file, handle.file); } +}; + +/// @brief Typed file reader +template +struct file_reader : abstract_reader +{ + file_reader(file_handle&& handle) : handle(std::move(handle)) {} + ~file_reader() override {} + size_t read(T* data, size_t size) final { return fread(data, element_size(), size, handle.file); } + + using abstract_reader::read; + + imax tell() const final { return IO_TELL_64(handle.file); } + bool seek(imax offset, seek_origin origin) final + { + return !IO_SEEK_64(handle.file, offset, static_cast(origin)); + } + file_handle handle; +}; + +/// @brief Typed file writer +template +struct file_writer : abstract_writer +{ + file_writer(file_handle&& handle) : handle(std::move(handle)) {} + ~file_writer() override {} + + using abstract_writer::write; + size_t write(const T* data, size_t size) final + { + return fwrite(data, element_size(), size, handle.file); + } + imax tell() const final { return IO_TELL_64(handle.file); } + bool seek(imax offset, seek_origin origin) final + { + return !IO_SEEK_64(handle.file, offset, static_cast(origin)); + } + file_handle handle; +}; + +/// @brief Opens typed file for reading +template +inline std::shared_ptr> open_file_for_reading(const filepath& path) +{ + std::FILE* f = fopen_portable(path.c_str(), KFR_FILEPATH("rb")); + return f ? std::make_shared>(f) : nullptr; +} + +/// @brief Opens typed file for writing +template +inline std::shared_ptr> open_file_for_writing(const filepath& path) +{ + std::FILE* f = fopen_portable(path.c_str(), KFR_FILEPATH("wb")); + return f ? std::make_shared>(f) : nullptr; +} + +/// @brief Opens typed file for appending +template +inline std::shared_ptr> open_file_for_appending(const filepath& path) +{ + std::FILE* f = fopen_portable(path.c_str(), KFR_FILEPATH("ab")); + return f ? std::make_shared>(f) : nullptr; +} + +#ifdef CMT_OS_WIN +/// @brief Opens typed file for reading +template +inline std::shared_ptr> open_file_for_reading(const std::string& path) +{ + std::FILE* f = fopen(path.c_str(), "rb"); + return f ? std::make_shared>(f) : nullptr; +} + +/// @brief Opens typed file for writing +template +inline std::shared_ptr> open_file_for_writing(const std::string& path) +{ + std::FILE* f = fopen(path.c_str(), "wb"); + return f ? std::make_shared>(f) : nullptr; +} + +/// @brief Opens typed file for appending +template +inline std::shared_ptr> open_file_for_appending(const std::string& path) +{ + std::FILE* f = fopen(path.c_str(), "ab"); + return f ? std::make_shared>(f) : nullptr; +} +#endif + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/io/python_plot.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/io/python_plot.hpp new file mode 100644 index 00000000..5d1335af --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/io/python_plot.hpp @@ -0,0 +1,184 @@ +/** @addtogroup plotting + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "../cometa/string.hpp" +#include "../simd/vec.hpp" +#include + +#ifdef CMT_OS_WIN +#include +#define cross_getcwd _getcwd +#else +#include +#define cross_getcwd getcwd +#endif + +namespace kfr +{ +namespace internal_generic +{ +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wdeprecated-declarations") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wunused-result") + +template +void python(const std::string& name, const std::string& code) +{ + std::string filename; + { + char curdir[1024]; + (void)cross_getcwd(curdir, (int)arraysize(curdir)); + filename = curdir; + } +#ifdef CMT_OS_WIN + const char* slash = "\\"; +#else + const char* slash = "/"; +#endif + filename = filename + slash + name + ".py"; + + FILE* f = fopen(filename.c_str(), "w"); + fwrite(code.c_str(), 1, code.size(), f); + fclose(f); +#ifndef CMT_OS_MOBILE + (void)std::system(("python \"" + filename + "\"").c_str()); +#endif +} +CMT_PRAGMA_GNU(GCC diagnostic pop) + +template )> +inline T flush_to_zero(T value) +{ + return std::isfinite(value) ? value : 0; +} +template )> +inline T flush_to_zero(T value) +{ + return static_cast(value); +} +} // namespace internal_generic + +inline std::string concat_args() { return {}; } + +template +std::string concat_args(const std::string& left, const Ts&... rest) +{ + const std::string right = concat_args(rest...); + return left.empty() ? right : right.empty() ? left : left + ", " + right; +} + +inline std::string python_prologue() +{ + return "#!/usr/bin/env python\n" + "import sys\n" + "import os\n" + "sys.path.append(os.path.abspath(__file__ + '/../../../../dspplot/dspplot'))\n" + "sys.path.append(os.path.abspath(__file__ + '/../../../dspplot/dspplot'))\n" + "import dspplotting as dspplot\n\n"; +} + +template +void plot_show(const std::string& name, const std::string& wavfile, const std::string& options = "") +{ + print(name, "..."); + std::string ss; + ss += python_prologue() + "dspplot.plot(" + concat_args("r'" + wavfile + "'", options) + ")\n"; + + internal_generic::python(name, ss); + print("done\n"); +} + +template +void plot_show(const std::string& name, const char* x, const std::string& options = "") +{ + plot_show(name, std::string(x), options); +} + +/// @brief Plot data using python +template +void plot_show(const std::string& name, const T& x, const std::string& options = "") +{ + print(name, "..."); + auto array = make_array_ref(x); + std::string ss; + ss += python_prologue() + "data = [\n"; + for (size_t i = 0; i < array.size(); i++) + ss += as_string(cometa::fmt<'g', 20, 17>(internal_generic::flush_to_zero(array[i])), ",\n"); + ss += "]\n"; + + ss += "dspplot.plot(" + concat_args("data", options) + ")\n"; + + internal_generic::python(name, ss); + print("done\n"); +} + +/// @brief Plot data using python and save to file +template +void plot_save(const std::string& name, const T& x, const std::string& options = "") +{ + plot_show(name, x, concat_args(options, "file='../svg/" + name + ".svg'")); +} + +template +void perfplot_show(const std::string& name, T1&& data, T2&& labels, const std::string& options = "") +{ + print(name, "..."); + auto array = make_array_ref(std::forward(data)); + auto labels_array = make_array_ref(std::forward(labels)); + std::string ss; + ss += python_prologue(); + ss += "data = [\n"; + for (size_t i = 0; i < array.size(); i++) + { + auto subarray = make_array_ref(array[i]); + ss += "[\n"; + for (size_t i = 0; i < subarray.size(); i++) + ss += as_string(" ", cometa::fmt<'g', 20, 17>(subarray[i]), ",\n"); + ss += "],"; + } + ss += "]\n"; + + ss += "labels = [\n"; + for (size_t i = 0; i < labels_array.size(); i++) + { + const std::string label = labels_array[i]; + ss += " '" + label + "',"; + } + ss += "]\n"; + + ss += "dspplot.perfplot(" + concat_args("data, labels", options) + ")\n"; + + internal_generic::python(name, ss); + print("done\n"); +} + +template +void perfplot_save(const std::string& name, T1&& data, T2&& labels, const std::string& options = "") +{ + perfplot_show(name, std::forward(data), std::forward(labels), + concat_args(options, "file='../perf/" + name + ".svg'")); +} +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/io/tostring.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/io/tostring.hpp new file mode 100644 index 00000000..0f3a879d --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/io/tostring.hpp @@ -0,0 +1,178 @@ +/** @addtogroup string_io + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/univector.hpp" +#include "../cometa/string.hpp" +#include "../simd/complex.hpp" +#include "../simd/vec.hpp" +#include +#include + +namespace cometa +{ + +template <> +struct representation +{ + using type = std::string; + static std::string get(const cometa::special_value& value) + { + using cometa::special_constant; + switch (value.c) + { + case special_constant::default_constructed: + return "default_constructed"; + case special_constant::infinity: + return "infinity"; + case special_constant::neg_infinity: + return "neg_infinity"; + case special_constant::min: + return "min"; + case special_constant::max: + return "max"; + case special_constant::neg_max: + return "neg_max"; + case special_constant::lowest: + return "lowest"; + case special_constant::integer: + return as_string(value.ll); + case special_constant::floating_point: + return as_string(value.d); + case special_constant::epsilon: + return "epsilon"; + case special_constant::random_bits: + return "random_bits"; + default: + return "unknown"; + } + } +}; + +namespace details +{ + +constexpr size_t number_width = 9; +constexpr size_t number_precision = 6; +constexpr size_t number_precision_short = 2; +constexpr size_t number_columns = 8; + +template +std::string fmtvalue(std::true_type, const T& x) +{ + std::string str = as_string(cometa::fmt<'g', number_width, number_precision>(x)); + if (str.size() > number_width) + str = as_string(cometa::fmt<'g', number_width, number_precision_short>(x)); + return str; +} + +template +std::string fmtvalue(std::true_type, const kfr::complex& x) +{ + std::string restr = as_string(cometa::fmt<'g', number_width, number_precision>(x.real())); + if (restr.size() > number_width) + restr = as_string(cometa::fmt<'g', number_width, number_precision_short>(x.real())); + + std::string imstr = as_string(cometa::fmt<'g', -1, number_precision>(std::abs(x.imag()))); + if (imstr.size() > number_width) + imstr = as_string(cometa::fmt<'g', -1, number_precision_short>(std::abs(x.imag()))); + + return restr + (x.imag() < T(0) ? "-" : "+") + padleft(number_width, imstr + "j"); +} + +template +std::string fmtvalue(std::false_type, const T& x) +{ + return as_string(fmtwidth(representation::get(x))); +} + +template +inline std::string array_to_string(const T* source, size_t N) +{ + std::string str; + for (size_t i = 0; i < N; i++) + { + if (i > 0) + { + if (i % details::number_columns == 0 || kfr::is_vec) + str += "\n"; + else + str += " "; + } + str += as_string(details::fmtvalue(std::is_floating_point(), source[i])); + } + return str; +} + +template +inline std::string array_to_string(const kfr::complex* source, size_t N) +{ + std::string str; + for (size_t i = 0; i < N; i++) + { + if (i > 0) + { + if (i % (details::number_columns / 2) == 0) + str += "\n"; + else + str += " "; + } + str += as_string(details::fmtvalue(std::true_type{}, source[i])); + } + return str; +} +} // namespace details + +template <> +struct representation +{ + using type = std::string; + static std::string get(kfr::cpu_t value) { return kfr::cpu_name(value); } +}; + +} // namespace cometa + +namespace kfr +{ + +/// @brief Converts dB value to string (uses oo for infinity symbol) +template +std::string dB_to_string(const T& value, double minimum = -140.0) +{ + if (value <= minimum) + return "-oo dB"; + return as_string(fmtwidth<0, 2>(value), " dB"); +} + +/// @brief Converts dB value to string (uses infinity symbol in utf-8 encoding) +template +std::string dB_to_utf8string(const T& value, double minimum = -140.0) +{ + if (value <= minimum) + return "-\xE2\x88\x9E dB"; // infinity symbol + return as_string(fmtwidth<0, 2>(value), " dB"); +} +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/kfr.h b/packages/react-native-audio-api/android/src/main/include/kfr/kfr.h new file mode 100644 index 00000000..9c3afa7f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/kfr.h @@ -0,0 +1,117 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +/** @addtogroup utility + * @{ + */ +#pragma once + +#include "config.h" + +#include +#include + +#include "cident.h" + +#define KFR_VERSION_MAJOR 6 +#define KFR_VERSION_MINOR 1 +#define KFR_VERSION_PATCH 0 +#define KFR_VERSION_LABEL "" + +#define KFR_VERSION_STRING \ + CMT_STRINGIFY(KFR_VERSION_MAJOR) \ + "." CMT_STRINGIFY(KFR_VERSION_MINOR) "." CMT_STRINGIFY(KFR_VERSION_PATCH) KFR_VERSION_LABEL +#define KFR_VERSION (KFR_VERSION_MAJOR * 10000 + KFR_VERSION_MINOR * 100 + KFR_VERSION_PATCH) + +#if defined DEBUG || defined KFR_DEBUG +#define KFR_DEBUG_STR " debug" +#elif defined NDEBUG || defined KFR_NDEBUG +#define KFR_DEBUG_STR " optimized" +#else +#define KFR_DEBUG_STR "" +#endif + +#define KFR_NATIVE_INTRINSICS 1 + +#if defined CMT_COMPILER_CLANG && !defined CMT_DISABLE_CLANG_EXT +#define CMT_CLANG_EXT +#endif + +#ifdef KFR_NATIVE_INTRINSICS +#define KFR_BUILD_DETAILS_1 " +in" +#else +#define KFR_BUILD_DETAILS_1 "" +#endif + +#ifdef CMT_CLANG_EXT +#define KFR_BUILD_DETAILS_2 " +ve" +#else +#define KFR_BUILD_DETAILS_2 "" +#endif + +#ifdef KFR_ENABLED_ARCHS +#define KFR_ENABLED_ARCHS_LIST "[" KFR_ENABLED_ARCHS "] " +#else +#define KFR_ENABLED_ARCHS_LIST "" +#endif + +#define KFR_VERSION_FULL \ + "KFR " KFR_VERSION_STRING KFR_DEBUG_STR \ + " " CMT_STRINGIFY(CMT_ARCH_NAME) " " KFR_ENABLED_ARCHS_LIST CMT_ARCH_BITNESS_NAME \ + " (" CMT_COMPILER_FULL_NAME "/" CMT_OS_NAME \ + ")" KFR_BUILD_DETAILS_1 KFR_BUILD_DETAILS_2 + +#ifdef __cplusplus +namespace kfr +{ +/// @brief KFR version string +constexpr inline const char version_string[] = KFR_VERSION_STRING; + +constexpr inline int version_major = KFR_VERSION_MAJOR; +constexpr inline int version_minor = KFR_VERSION_MINOR; +constexpr inline int version_patch = KFR_VERSION_PATCH; +constexpr inline int version = KFR_VERSION; + +/// @brief KFR version string including architecture and compiler name +constexpr inline const char version_full[] = KFR_VERSION_FULL; +} // namespace kfr +#endif + +#define KFR_INTRINSIC CMT_INTRINSIC +#define KFR_MEM_INTRINSIC CMT_MEM_INTRINSIC +#ifdef KFR_FUNCTION_IS_INTRINSIC +#define KFR_FUNCTION CMT_INTRINSIC +#else +#define KFR_FUNCTION +#endif +#ifdef CMT_NATIVE_F64 +#define KFR_NATIVE_F64 CMT_NATIVE_F64 +#endif + +#if defined CMT_ARCH_ARM && !defined CMT_ARCH_NEON && !defined CMT_FORCE_GENERIC_CPU +#error \ + "ARM builds require NEON support. Add -march=native for native build or skip the check with CMT_FORCE_GENERIC_CPU=1" +#endif + +#if defined CMT_ARCH_ARM && !defined CMT_COMPILER_CLANG && !defined CMT_FORCE_NON_CLANG +#error "ARM builds require Clang compiler. Disable checking with CMT_FORCE_NON_CLANG" +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math.hpp new file mode 100644 index 00000000..3763b267 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math.hpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "simd.hpp" + +#include "math/asin_acos.hpp" +#include "math/atan.hpp" +#include "math/compiletime.hpp" +#include "math/complex_math.hpp" +#include "math/gamma.hpp" +#include "math/hyperbolic.hpp" +#include "math/interpolation.hpp" +#include "math/log_exp.hpp" +#include "math/modzerobessel.hpp" +#include "math/sin_cos.hpp" +#include "math/sqrt.hpp" +#include "math/tan.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/asin_acos.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/asin_acos.hpp new file mode 100644 index 00000000..0cef3b8a --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/asin_acos.hpp @@ -0,0 +1,53 @@ +/** @addtogroup trigonometric + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/asin_acos.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the arc sine of x. The returned angle is in the range \f$-\pi/2\f$ through \f$\pi/2\f$. + */ +template )> +KFR_INTRINSIC flt_type asin(const T1& x) +{ + return intrinsics::asin(x); +} +/** + * @brief Returns the arc cosine of x. The returned angle is in the range 0 through \f$\pi\f$. + */ +template )> +KFR_INTRINSIC flt_type acos(const T1& x) +{ + return intrinsics::acos(x); +} +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/atan.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/atan.hpp new file mode 100644 index 00000000..b6a11051 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/atan.hpp @@ -0,0 +1,74 @@ +/** @addtogroup trigonometric + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/atan.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the arc tangent of x. The returned angle is in the range \f$-\pi/2\f$ through + * \f$\pi/2\f$. + */ +template )> +KFR_FUNCTION flt_type atan(const T1& x) +{ + return intrinsics::atan(x); +} + +/** + * @brief Returns the arc tangent of the x, expressed in degrees. The returned angle is in the range -90 + * through 90. + */ +template )> +KFR_FUNCTION flt_type atandeg(const T1& x) +{ + return intrinsics::atandeg(x); +} + +/** + * @brief Returns the arc tangent of y/x using the signs of arguments to determine the correct quadrant. + */ +template )> +KFR_FUNCTION std::common_type_t atan2(const T1& x, const T2& y) +{ + return intrinsics::atan2(x, y); +} + +/** + * @brief Returns the arc tangent of y/x (expressed in degrees) using the signs of arguments to determine the + * correct quadrant. + */ +template )> +KFR_FUNCTION std::common_type_t atan2deg(const T1& x, const T2& y) +{ + return intrinsics::atan2deg(x, y); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/compiletime.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/compiletime.hpp new file mode 100644 index 00000000..83280cd5 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/compiletime.hpp @@ -0,0 +1,84 @@ +/** @addtogroup math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "../simd/constants.hpp" +#include "../simd/operators.hpp" +#include "../simd/types.hpp" + +namespace kfr +{ + +namespace compiletime +{ + +template +constexpr inline T select(bool c, T x, T y) +{ + return c ? x : y; +} +template +constexpr inline T trunc(T x) +{ + return static_cast(static_cast(x)); +} +template +constexpr inline T abs(T x) +{ + return x < T() ? -x : x; +} +template +constexpr inline T mulsign(T x, T y) +{ + return y < T() ? -x : x; +} +template +constexpr inline T sin(T x) +{ + x = x - trunc(x / c_pi) * c_pi; + constexpr T c2 = -0.16665853559970855712890625; + constexpr T c4 = +8.31427983939647674560546875e-3; + constexpr T c6 = -1.85423981747590005397796630859375e-4; + + x -= c_pi; + T y = abs(x); + y = select(y > c_pi, c_pi - y, y); + y = mulsign(y, -x); + + const T y2 = y * y; + T formula = c6; + const T y3 = y2 * y; + formula = fmadd(formula, y2, c4); + formula = fmadd(formula, y2, c2); + formula = formula * y3 + y; + return formula; +} +template +constexpr inline T cos(T x) +{ + return sin(x + c_pi); +} +} // namespace compiletime +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/complex_math.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/complex_math.hpp new file mode 100644 index 00000000..d03acb4d --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/complex_math.hpp @@ -0,0 +1,339 @@ +/** @addtogroup complex + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/abs.hpp" +#include "../simd/complex.hpp" +#include "../simd/min_max.hpp" +#include "../simd/select.hpp" +#include "atan.hpp" +#include "hyperbolic.hpp" +#include "log_exp.hpp" +#include "sin_cos.hpp" +#include "sqrt.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ +template +KFR_INTRINSIC vec, N> csin(const vec, N>& x) +{ + return ccomp(sincos(cdecom(cdupreal(x))) * coshsinh(cdecom(cdupimag(x)))); +} +template +KFR_INTRINSIC vec, N> csinh(const vec, N>& x) +{ + return ccomp(sinhcosh(cdecom(cdupreal(x))) * cossin(cdecom(cdupimag(x)))); +} +template +KFR_INTRINSIC vec, N> ccos(const vec, N>& x) +{ + return ccomp(negodd(cossin(cdecom(cdupreal(x))) * coshsinh(cdecom(cdupimag(x))))); +} +template +KFR_INTRINSIC vec, N> ccosh(const vec, N>& x) +{ + return ccomp(coshsinh(cdecom(cdupreal(x))) * cossin(cdecom(cdupimag(x)))); +} + +template +KFR_INTRINSIC vec cabssqr(const vec, N>& x) +{ + const vec xx = sqr(cdecom(x)); + return even(xx) + odd(xx); +} +template +KFR_INTRINSIC vec cabs(const vec, N>& x) +{ + const vec xx = sqr(cdecom(x)); + return sqrt(even(xx) + odd(xx)); +} +template +KFR_INTRINSIC vec carg(const vec, N>& x) +{ + const vec xx = cdecom(x); + return atan2(odd(xx), even(xx)); +} + +template +KFR_INTRINSIC vec, N> clog(const vec, N>& x) +{ + return make_complex(log(cabs(x)), carg(x)); +} +template +KFR_INTRINSIC vec, N> clog2(const vec, N>& x) +{ + return clog(x) * c_recip_log_2; +} +template +KFR_INTRINSIC vec, N> clog10(const vec, N>& x) +{ + return clog(x) * c_recip_log_10; +} + +template +KFR_INTRINSIC vec, N> cexp(const vec, N>& x) +{ + return ccomp(exp(cdecom(cdupreal(x))) * cossin(cdecom(cdupimag(x)))); +} +template +KFR_INTRINSIC vec, N> cexp2(const vec, N>& x) +{ + return cexp(x * c_log_2); +} +template +KFR_INTRINSIC vec, N> cexp10(const vec, N>& x) +{ + return cexp(x * c_log_10); +} + +template +KFR_INTRINSIC vec, N> polar(const vec, N>& x) +{ + return make_complex(cabs(x), carg(x)); +} +template +KFR_INTRINSIC vec, N> cartesian(const vec, N>& x) +{ + return cdupreal(x) * ccomp(cossin(cdecom(cdupimag(x)))); +} + +template +KFR_INTRINSIC vec cabsdup(const vec& x) +{ + vec xx = sqr(x); + return sqrt(xx + swap<2>(xx)); +} + +template +KFR_INTRINSIC vec, N> csqrt(const vec, N>& x) +{ + const vec s = sqrt((abs(real(x)) + cabs(x)) * 0.5); + const vec d = abs(imag(x)) * 0.5 / s; + const mask posreal = real(x) >= T(0); + const vec imagsign = imag(x) & special_constants::highbitmask(); + return make_complex(select(posreal, s, d), select(posreal, d ^ imagsign, s ^ imagsign)); +} + +template +KFR_INTRINSIC vec, N> csqr(const vec, N>& x) +{ + return x * x; +} + +KFR_HANDLE_SCALAR(csin) +KFR_HANDLE_SCALAR(csinh) +KFR_HANDLE_SCALAR(ccos) +KFR_HANDLE_SCALAR(ccosh) +KFR_HANDLE_SCALAR(clog) +KFR_HANDLE_SCALAR(clog2) +KFR_HANDLE_SCALAR(clog10) +KFR_HANDLE_SCALAR(cexp) +KFR_HANDLE_SCALAR(cexp2) +KFR_HANDLE_SCALAR(cexp10) +KFR_HANDLE_SCALAR(polar) +KFR_HANDLE_SCALAR(cartesian) +KFR_HANDLE_SCALAR(csqrt) +KFR_HANDLE_SCALAR(csqr) + +template +KFR_INTRINSIC vec cabssqr(const vec& a) +{ + return to_scalar(intrinsics::cabssqr(static_cast, N>>(a))); +} +template +KFR_INTRINSIC vec cabs(const vec& a) +{ + return to_scalar(intrinsics::cabs(static_cast, N>>(a))); +} +template +KFR_INTRINSIC vec carg(const vec& a) +{ + return to_scalar(intrinsics::carg(static_cast, N>>(a))); +} +template +KFR_INTRINSIC realtype cabssqr(const T1& a) +{ + using vecout = vec1; + return to_scalar(intrinsics::cabssqr(vecout(a))); +} +template +KFR_INTRINSIC realtype cabs(const T1& a) +{ + using vecout = vec1; + return to_scalar(intrinsics::cabs(vecout(a))); +} +template +KFR_INTRINSIC realtype carg(const T1& a) +{ + using vecout = vec1; + return to_scalar(intrinsics::carg(vecout(a))); +} +} // namespace intrinsics + +KFR_I_FN(csin) +KFR_I_FN(csinh) +KFR_I_FN(ccos) +KFR_I_FN(ccosh) +KFR_I_FN(cabssqr) +KFR_I_FN(cabs) +KFR_I_FN(carg) +KFR_I_FN(clog) +KFR_I_FN(clog2) +KFR_I_FN(clog10) +KFR_I_FN(cexp) +KFR_I_FN(cexp2) +KFR_I_FN(cexp10) +KFR_I_FN(polar) +KFR_I_FN(cartesian) +KFR_I_FN(csqrt) +KFR_I_FN(csqr) + +/// @brief Returns the sine of the complex number x +template )> +KFR_FUNCTION T1 csin(const T1& x) +{ + return intrinsics::csin(x); +} + +/// @brief Returns the hyperbolic sine of the complex number x +template )> +KFR_FUNCTION T1 csinh(const T1& x) +{ + return intrinsics::csinh(x); +} + +/// @brief Returns the cosine of the complex number x +template )> +KFR_FUNCTION T1 ccos(const T1& x) +{ + return intrinsics::ccos(x); +} + +/// @brief Returns the hyperbolic cosine of the complex number x +template )> +KFR_FUNCTION T1 ccosh(const T1& x) +{ + return intrinsics::ccosh(x); +} + +/// @brief Returns the squared absolute value (magnitude squared) of the complex number x +template )> +KFR_FUNCTION realtype cabssqr(const T1& x) +{ + return intrinsics::cabssqr(x); +} + +/// @brief Returns the absolute value (magnitude) of the complex number x +template )> +KFR_FUNCTION realtype cabs(const T1& x) +{ + return intrinsics::cabs(x); +} + +/// @brief Returns the phase angle (argument) of the complex number x +template )> +KFR_FUNCTION realtype carg(const T1& x) +{ + return intrinsics::carg(x); +} + +/// @brief Returns the natural logarithm of the complex number x +template )> +KFR_FUNCTION T1 clog(const T1& x) +{ + return intrinsics::clog(x); +} + +/// @brief Returns the binary (base-2) logarithm of the complex number x +template )> +KFR_FUNCTION T1 clog2(const T1& x) +{ + return intrinsics::clog2(x); +} + +/// @brief Returns the common (base-10) logarithm of the complex number x +template )> +KFR_FUNCTION T1 clog10(const T1& x) +{ + return intrinsics::clog10(x); +} + +/// @brief Returns \f$e\f$ raised to the complex number x +template )> +KFR_FUNCTION T1 cexp(const T1& x) +{ + return intrinsics::cexp(x); +} + +/// @brief Returns 2 raised to the complex number x +template )> +KFR_FUNCTION T1 cexp2(const T1& x) +{ + return intrinsics::cexp2(x); +} + +/// @brief Returns 10 raised to the complex number x +template )> +KFR_FUNCTION T1 cexp10(const T1& x) +{ + return intrinsics::cexp10(x); +} + +/// @brief Converts complex number to polar +template )> +KFR_FUNCTION T1 polar(const T1& x) +{ + return intrinsics::polar(x); +} + +/// @brief Converts complex number to cartesian +template )> +KFR_FUNCTION T1 cartesian(const T1& x) +{ + return intrinsics::cartesian(x); +} + +/// @brief Returns square root of the complex number x +template )> +KFR_FUNCTION T1 csqrt(const T1& x) +{ + return intrinsics::csqrt(x); +} + +/// @brief Returns square of the complex number x +template )> +KFR_FUNCTION T1 csqr(const T1& x) +{ + return intrinsics::csqr(x); +} + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/gamma.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/gamma.hpp new file mode 100644 index 00000000..71b6669c --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/gamma.hpp @@ -0,0 +1,81 @@ +/** @addtogroup other_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/gamma.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Returns the approximate gamma function of an argument +template )> +KFR_FUNCTION flt_type gamma(const T1& x) +{ + return intrinsics::gamma(x); +} + +/// @brief Returns the approximate factorial of an argument +template )> +KFR_FUNCTION flt_type factorial_approx(const T1& x) +{ + return intrinsics::factorial_approx(x); +} + +constexpr inline uint64_t factorial_table[21] = { + 0, + 1, + 2, + 6, + 24, + 120, + 720, + 5040, + 40320, + 362880, + 3628800, + 39916800, + 479001600, + 6227020800, + 87178291200, + 1307674368000, + 20922789888000, + 355687428096000, + 6402373705728000, + 121645100408832000, + 2432902008176640000, +}; + +/// @brief Returns the factorial of an argument. Returns max(uint64_t) if does not fit to uint64_t +constexpr uint64_t factorial(int n) +{ + if (CMT_LIKELY(n < 0 || n > 20)) + return std::numeric_limits::max(); + return factorial_table[n]; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/hyperbolic.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/hyperbolic.hpp new file mode 100644 index 00000000..66b45165 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/hyperbolic.hpp @@ -0,0 +1,79 @@ +/** @addtogroup hyperbolic + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/hyperbolic.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Returns the hyperbolic sine of the x +template )> +KFR_FUNCTION flt_type sinh(const T1& x) +{ + return intrinsics::sinh(x); +} + +/// @brief Returns the hyperbolic cosine of the x +template )> +KFR_FUNCTION flt_type cosh(const T1& x) +{ + return intrinsics::cosh(x); +} + +/// @brief Returns the hyperbolic tangent of the x +template )> +KFR_FUNCTION flt_type tanh(const T1& x) +{ + return intrinsics::tanh(x); +} + +/// @brief Returns the hyperbolic cotangent of the x +template )> +KFR_FUNCTION flt_type coth(const T1& x) +{ + return intrinsics::coth(x); +} + +/// @brief Returns the hyperbolic sine of the even elements of the x and the hyperbolic cosine of the odd +/// elements of the x +template )> +KFR_FUNCTION flt_type sinhcosh(const T1& x) +{ + return intrinsics::sinhcosh(x); +} + +/// @brief Returns the hyperbolic cosine of the even elements of the x and the hyperbolic sine of the odd +/// elements of the x +template )> +KFR_FUNCTION flt_type coshsinh(const T1& x) +{ + return intrinsics::coshsinh(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/asin_acos.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/asin_acos.hpp new file mode 100644 index 00000000..bc9b2cc3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/asin_acos.hpp @@ -0,0 +1,58 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/impl/function.hpp" +#include "../../simd/select.hpp" +#include "../atan.hpp" +#include "../sqrt.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template > +KFR_INTRINSIC vec asin(const vec& x) +{ + const vec xx = x; + return atan2(xx, sqrt(Tout(1) - xx * xx)); +} + +template > +KFR_INTRINSIC vec acos(const vec& x) +{ + const vec xx = x; + return atan2(sqrt(Tout(1) - xx * xx), xx); +} +KFR_HANDLE_SCALAR(asin) +KFR_HANDLE_SCALAR(acos) +} // namespace intrinsics +KFR_I_FN(asin) +KFR_I_FN(acos) +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/atan.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/atan.hpp new file mode 100644 index 00000000..9a783b43 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/atan.hpp @@ -0,0 +1,227 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "../../simd/abs.hpp" +#include "../../simd/constants.hpp" +#include "../../simd/impl/function.hpp" +#include "../../simd/operators.hpp" +#include "../../simd/comparison.hpp" +#include "../../simd/select.hpp" +#include "../sin_cos.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ +template +KFR_INTRINSIC vec atan2k(const vec& yy, const vec& xx) +{ + vec x = xx, y = yy; + vec s, t, u; + vec q; + q = select(x < 0, -2, 0); + x = select(x < 0, -x, x); + mask m; + m = y > x; + t = x; + x = select(m, y, x); + y = select(m, -t, y); + q = select(m, q + 1, q); + s = y / x; + t = s * s; + u = fmadd(0.00282363896258175373077393f, t, -0.0159569028764963150024414f); + u = fmadd(u, t, 0.0425049886107444763183594f); + u = fmadd(u, t, -0.0748900920152664184570312f); + u = fmadd(u, t, 0.106347933411598205566406f); + u = fmadd(u, t, -0.142027363181114196777344f); + u = fmadd(u, t, 0.199926957488059997558594f); + u = fmadd(u, t, -0.333331018686294555664062f); + t = u * t * s + s; + t = broadcastto(q) * 1.5707963267948966192313216916398f + t; + return t; +} + +template +KFR_INTRINSIC vec atan2k(const vec& yy, const vec& xx) +{ + vec x = xx, y = yy; + vec s, t, u; + vec q; + q = select(x < 0, i64(-2), i64(0)); + x = select(x < 0, -x, x); + mask m; + m = y > x; + t = x; + x = select(m, y, x); + y = select(m, -t, y); + q = select(m, q + i64(1), q); + s = y / x; + t = s * s; + u = fmadd(-1.88796008463073496563746e-05, t, 0.000209850076645816976906797); + u = fmadd(u, t, -0.00110611831486672482563471); + u = fmadd(u, t, 0.00370026744188713119232403); + u = fmadd(u, t, -0.00889896195887655491740809); + u = fmadd(u, t, 0.016599329773529201970117); + u = fmadd(u, t, -0.0254517624932312641616861); + u = fmadd(u, t, 0.0337852580001353069993897); + u = fmadd(u, t, -0.0407629191276836500001934); + u = fmadd(u, t, 0.0466667150077840625632675); + u = fmadd(u, t, -0.0523674852303482457616113); + u = fmadd(u, t, 0.0587666392926673580854313); + u = fmadd(u, t, -0.0666573579361080525984562); + u = fmadd(u, t, 0.0769219538311769618355029); + u = fmadd(u, t, -0.090908995008245008229153); + u = fmadd(u, t, 0.111111105648261418443745); + u = fmadd(u, t, -0.14285714266771329383765); + u = fmadd(u, t, 0.199999999996591265594148); + u = fmadd(u, t, -0.333333333333311110369124); + t = u * t * s + s; + t = broadcastto(q) * 1.5707963267948966192313216916398 + t; + return t; +} + +template +KFR_INTRINSIC vec atan2(const vec& y, const vec& x) +{ + vec r = atan2k(abs(y), x); + constexpr f32 pi = 3.1415926535897932384626433832795f; + constexpr f32 pi_over_2 = 1.5707963267948966192313216916398f; + constexpr f32 pi_over_4 = 0.78539816339744830961566084581988f; + r = mulsign(r, x); + r = select(isinf(x) || x == 0.0f, pi_over_2 - select(x.asmask(), mulsign(pi_over_2, x), 0.0f), r); + r = select(isinf(y), pi_over_2 - select(x.asmask(), mulsign(pi_over_4, x), 0.0f), r); + r = select(y == 0.0f, select(x < 0.f, pi, 0.f), r); + r = (isnan(x) || isnan(y)).asvec() | mulsign(r, y); + return r; +} + +template +KFR_INTRINSIC vec atan2(const vec& y, const vec& x) +{ + vec r = atan2k(abs(y), x); + constexpr f64 pi = 3.1415926535897932384626433832795; + constexpr f64 pi_over_2 = 1.5707963267948966192313216916398; + constexpr f64 pi_over_4 = 0.78539816339744830961566084581988; + r = mulsign(r, x); + r = select(isinf(x) || x == 0.0, pi_over_2 - select(x.asmask(), mulsign(pi_over_2, x), 0.0), r); + r = select(isinf(y), pi_over_2 - select(x.asmask(), mulsign(pi_over_4, x), 0.0), r); + r = select(y == 0.0, select(x < 0., pi, 0.), r); + r = (isnan(x) || isnan(y)).asvec() | mulsign(r, y); + return r; +} + +template +KFR_INTRINSIC vec atan(const vec& x) +{ + vec t, u; + vec q; + q = select(x < 0.f, 2, 0); + vec s = select(x < 0.f, -x, x); + q = select(s > 1.f, q | 1, q); + s = select(s > 1.f, 1.0f / s, s); + t = s * s; + u = fmadd(0.00282363896258175373077393f, t, -0.0159569028764963150024414f); + u = fmadd(u, t, 0.0425049886107444763183594f); + u = fmadd(u, t, -0.0748900920152664184570312f); + u = fmadd(u, t, 0.106347933411598205566406f); + u = fmadd(u, t, -0.142027363181114196777344f); + u = fmadd(u, t, 0.199926957488059997558594f); + u = fmadd(u, t, -0.333331018686294555664062f); + t = s + s * (t * u); + t = select((q & 1) != 0, 1.570796326794896557998982f - t, t); + t = select((q & 2) != 0, -t, t); + return t; +} + +template +KFR_INTRINSIC vec atan(const vec& x) +{ + vec t, u; + vec q; + q = select(x < 0.0, i64(2), i64(0)); + vec s = select(x < 0.0, -x, x); + q = select(s > 1.0, q | 1, q); + s = select(s > 1.0, 1.0 / s, s); + t = s * s; + u = fmadd(-1.88796008463073496563746e-05, t, 0.000209850076645816976906797); + u = fmadd(u, t, -0.00110611831486672482563471); + u = fmadd(u, t, 0.00370026744188713119232403); + u = fmadd(u, t, -0.00889896195887655491740809); + u = fmadd(u, t, 0.016599329773529201970117); + u = fmadd(u, t, -0.0254517624932312641616861); + u = fmadd(u, t, 0.0337852580001353069993897); + u = fmadd(u, t, -0.0407629191276836500001934); + u = fmadd(u, t, 0.0466667150077840625632675); + u = fmadd(u, t, -0.0523674852303482457616113); + u = fmadd(u, t, 0.0587666392926673580854313); + u = fmadd(u, t, -0.0666573579361080525984562); + u = fmadd(u, t, 0.0769219538311769618355029); + u = fmadd(u, t, -0.090908995008245008229153); + u = fmadd(u, t, 0.111111105648261418443745); + u = fmadd(u, t, -0.14285714266771329383765); + u = fmadd(u, t, 0.199999999996591265594148); + u = fmadd(u, t, -0.333333333333311110369124); + t = s + s * (t * u); + t = select((q & 1) != 0, 1.570796326794896557998982 - t, t); + t = select((q & 2) != 0, -t, t); + return t; +} + +template +KFR_INTRINSIC vec atandeg(const vec& x) +{ + return atan(x) * c_radtodeg; +} + +template +KFR_INTRINSIC vec atandeg(const vec& x) +{ + return atan(x) * c_radtodeg; +} + +template +KFR_INTRINSIC vec atan2deg(const vec& y, const vec& x) +{ + return atan2(y, x) * c_radtodeg; +} + +template +KFR_INTRINSIC vec atan2deg(const vec& y, const vec& x) +{ + return atan2(y, x) * c_radtodeg; +} + +KFR_HANDLE_SCALAR(atan) +KFR_HANDLE_SCALAR(atan2) +KFR_HANDLE_SCALAR(atandeg) +KFR_HANDLE_SCALAR(atan2deg) +} // namespace intrinsics +KFR_I_FN(atan) +KFR_I_FN(atandeg) +KFR_I_FN(atan2) +KFR_I_FN(atan2deg) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/gamma.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/gamma.hpp new file mode 100644 index 00000000..53220a88 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/gamma.hpp @@ -0,0 +1,71 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "../../math/log_exp.hpp" +#include "../../simd/impl/function.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Wc99-extensions") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wc99-extensions") +#endif + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ +template +constexpr T gamma_precalc[] = { + T(0x2.81b263fec4e08p+0), T(0x3.07b4100e04448p+16), T(-0xa.a0da01d4d4e2p+16), T(0xf.05ccb27bb9dbp+16), + T(-0xa.fa79616b7c6ep+16), T(0x4.6dd6c10d4df5p+16), T(-0xf.a2304199eb4ap+12), T(0x1.c21dd4aade3dp+12), + T(-0x1.62f981f01cf84p+8), T(0x5.a937aa5c48d98p+0), T(-0x3.c640bf82e2104p-8), T(0xc.914c540f959cp-24), +}; + +template +KFR_INTRINSIC vec gamma(const vec& z) +{ + constexpr size_t Count = arraysize(gamma_precalc); + vec accm = gamma_precalc[0]; + CMT_LOOP_UNROLL + for (size_t k = 1; k < Count; k++) + accm += gamma_precalc[k] / (z + broadcastto>(k)); + accm *= exp(-(z + Count)) * pow(z + Count, z + 0.5); + return accm / z; +} + +template +KFR_INTRINSIC vec factorial_approx(const vec& x) +{ + return gamma(x + T(1)); +} +KFR_HANDLE_SCALAR(gamma) +KFR_HANDLE_SCALAR(factorial_approx) +} // namespace intrinsics +KFR_I_FN(gamma) +KFR_I_FN(factorial_approx) +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/hyperbolic.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/hyperbolic.hpp new file mode 100644 index 00000000..bd1841de --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/hyperbolic.hpp @@ -0,0 +1,99 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/abs.hpp" +#include "../../simd/constants.hpp" +#include "../../simd/impl/function.hpp" +#include "../../simd/min_max.hpp" +#include "../../simd/operators.hpp" +#include "../../simd/select.hpp" +#include "../log_exp.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template > +KFR_INTRINSIC vec sinh(const vec& x) +{ + const vec xx = static_cast>(x); + return (exp(xx) - exp(-xx)) * Tout(0.5); +} + +template > +KFR_INTRINSIC vec cosh(const vec& x) +{ + const vec xx = static_cast>(x); + return (exp(xx) + exp(-xx)) * Tout(0.5); +} + +template > +KFR_INTRINSIC vec tanh(const vec& x) +{ + const vec a = exp(2 * x); + return (a - 1) / (a + 1); +} + +template > +KFR_INTRINSIC vec coth(const vec& x) +{ + const vec a = exp(2 * x); + return (a + 1) / (a - 1); +} + +template > +KFR_INTRINSIC vec sinhcosh(const vec& x) +{ + const vec a = exp(x); + const vec b = exp(-x); + return subadd(a, b) * Tout(0.5); +} + +template > +KFR_INTRINSIC vec coshsinh(const vec& x) +{ + const vec a = exp(x); + const vec b = exp(-x); + return addsub(a, b) * Tout(0.5); +} + +KFR_HANDLE_SCALAR_1_T(sinh, flt_type) +KFR_HANDLE_SCALAR_1_T(cosh, flt_type) +KFR_HANDLE_SCALAR_1_T(tanh, flt_type) +KFR_HANDLE_SCALAR_1_T(coth, flt_type) +KFR_HANDLE_SCALAR_1_T(sinhcosh, flt_type) +KFR_HANDLE_SCALAR_1_T(coshsinh, flt_type) +} // namespace intrinsics +KFR_I_FN(sinh) +KFR_I_FN(cosh) +KFR_I_FN(tanh) +KFR_I_FN(coth) +KFR_I_FN(sinhcosh) +KFR_I_FN(coshsinh) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/log_exp.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/log_exp.hpp new file mode 100644 index 00000000..57109b86 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/log_exp.hpp @@ -0,0 +1,336 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/abs.hpp" +#include "../../simd/clamp.hpp" +#include "../../simd/constants.hpp" +#include "../../simd/impl/function.hpp" +#include "../../simd/min_max.hpp" +#include "../../simd/operators.hpp" +#include "../../simd/round.hpp" +#include "../../simd/select.hpp" +#include "../../simd/shuffle.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC vec vilogbp1(const vec& d) +{ + mask m = d < 5.421010862427522E-20f; + vec q = (ibitcast(select(m, 1.8446744073709552E19f * d, d)) >> 23) & 0xff; + q = select(m, q - (64 + 0x7e), q - 0x7e); + return q; +} + +template +KFR_INTRINSIC vec vilogbp1(const vec& d) +{ + mask m = d < 4.9090934652977266E-91; + vec q = (ibitcast(select(m, 2.037035976334486E90 * d, d)) >> 52) & 0x7ff; + q = select(m, q - (300 + 0x03fe), q - 0x03fe); + return q; +} + +template +KFR_INTRINSIC vec vldexpk(const vec& x, const vec& q) +{ + vec m = q >> 31; + m = (((m + q) >> 6) - m) << 4; + const vec qq = q - (m << 2); + m = clamp(m + 0x7f, vec(0xff)); + vec u = pow4(bitcast(broadcastto(m) << 23)); + return x * u * bitcast((broadcastto(qq + 0x7f)) << 23); +} + +template +KFR_INTRINSIC vec vldexpk(const vec& x, const vec& q) +{ + vec m = q >> 31; + m = (((m + q) >> 9) - m) << 7; + const vec qq = q - (m << 2); + m = clamp(m + 0x3ff, i64(0x7ff)); + vec u = pow4(bitcast(broadcastto(m) << 52)); + return x * u * bitcast((broadcastto(qq + 0x3ff)) << 52); +} + +template +KFR_INTRINSIC vec logb(const vec& x) +{ + return select(x == T(), -c_infinity, static_cast>(vilogbp1(x) - 1)); +} + +template +KFR_INTRINSIC vec log(const vec& d) +{ + vec e = vilogbp1(d * 0.7071); // 0678118654752440084436210485f ); + vec m = vldexpk(d, -e); + + vec x = (m - 1.0f) / (m + 1.0f); + vec x2 = x * x; + + vec sp = select(d < 0, constants::qnan, constants::neginfinity); + + vec t; + t = fmadd(0.2371599674224853515625f, x2, 0.285279005765914916992188f); + t = fmadd(t, x2, 0.400005519390106201171875f); + t = fmadd(t, x2, 0.666666567325592041015625f); + t = fmadd(t, x2, 2.0f); + + x = x * t + c_log_2 * broadcastto(e); + x = select(d > 0, x, sp); + + return x; +} + +template +KFR_INTRINSIC vec log(const vec& d) +{ + vec e = vilogbp1(d * 0.7071); // 0678118654752440084436210485 ); + vec m = vldexpk(d, -e); + + vec x = (m - 1.0) / (m + 1.0); + vec x2 = x * x; + + vec sp = select(d < 0, constants::qnan, constants::neginfinity); + + vec t; + t = fmadd(0.148197055177935105296783, x2, 0.153108178020442575739679); + t = fmadd(t, x2, 0.181837339521549679055568); + t = fmadd(t, x2, 0.22222194152736701733275); + t = fmadd(t, x2, 0.285714288030134544449368); + t = fmadd(t, x2, 0.399999999989941956712869); + t = fmadd(t, x2, 0.666666666666685503450651); + t = fmadd(t, x2, 2); + + x = x * t + constants::log_2 * broadcastto(e); + x = select(d > 0, x, sp); + + return x; +} + +template > +KFR_INTRINSIC vec log2(const vec& x) +{ + return log(broadcastto(x)) * constants::recip_log_2; +} +template > +KFR_INTRINSIC vec log10(const vec& x) +{ + return log(broadcastto(x)) * constants::recip_log_10; +} + +template +KFR_INTRINSIC vec exp(const vec& d) +{ + const f32 ln2_part1 = 0.6931457519f; + const f32 ln2_part2 = 1.4286067653e-6f; + + vec q = broadcastto(floor(d * constants::recip_log_2)); + vec s, u; + + s = fmadd(broadcastto(q), -ln2_part1, d); + s = fmadd(broadcastto(q), -ln2_part2, s); + + const f32 c2 = 0.4999999105930328369140625f; + const f32 c3 = 0.166668415069580078125f; + const f32 c4 = 4.16539050638675689697265625e-2f; + const f32 c5 = 8.378830738365650177001953125e-3f; + const f32 c6 = 1.304379315115511417388916015625e-3f; + const f32 c7 = 2.7555381529964506626129150390625e-4f; + + u = fmadd(c7, s, c6); + u = fmadd(u, s, c5); + u = fmadd(u, s, c4); + u = fmadd(u, s, c3); + u = fmadd(u, s, c2); + + u = s * s * u + s + 1.0f; + u = vldexpk(u, q); + + u = select(d == constants::neginfinity, 0.f, u); + + return u; +} + +template +KFR_INTRINSIC vec exp(const vec& d) +{ + const f64 ln2_part1 = 0.69314717501401901245; + const f64 ln2_part2 = 5.545926273775592108e-009; + + vec q = broadcastto(floor(d * constants::recip_log_2)); + vec s, u; + + s = fmadd(broadcastto(q), -ln2_part1, d); + s = fmadd(broadcastto(q), -ln2_part2, s); + + const f64 c2 = 0.499999999999994948485237955537741072475910186767578; + const f64 c3 = 0.166666666667024204739888659787538927048444747924805; + const f64 c4 = 4.16666666578945840693215529881854308769106864929199e-2; + const f64 c5 = 8.3333334397461874404333670440792047884315252304077e-3; + const f64 c6 = 1.3888881489747750223179290074426717183087021112442e-3; + const f64 c7 = 1.9841587032493949419205414574918222569976933300495e-4; + const f64 c8 = 2.47929324077393282239802768662784160369483288377523e-5; + const f64 c9 = 2.77076037925831049422552981864598109496000688523054e-6; + const f64 c10 = 2.59589616274586264243611237120812340606335055781528e-7; + const f64 c11 = 3.43801438838789632454461529017381016259946591162588e-8; + + u = fmadd(c11, s, c10); + u = fmadd(u, s, c9); + u = fmadd(u, s, c8); + u = fmadd(u, s, c7); + u = fmadd(u, s, c6); + u = fmadd(u, s, c5); + u = fmadd(u, s, c4); + u = fmadd(u, s, c3); + u = fmadd(u, s, c2); + + u = s * s * u + s + 1.0; + u = vldexpk(u, q); + + u = select(d == constants::neginfinity, 0.0, u); + + return u; +} +template > +KFR_INTRINSIC vec exp2(const vec& x) +{ + return exp(x * constants::log_2); +} +template > +KFR_INTRINSIC vec exp10(const vec& x) +{ + return exp(x * constants::log_10); +} + +template +KFR_INTRINSIC vec pow(const vec& a, const vec& b) +{ + const vec t = exp(b * log(abs(a))); + const mask isint = floor(b) == b; + const mask iseven = (broadcastto>(b) & 1) == 0; + return select( + a > T(), t, + select(a == T(), T(), select(isint, select(iseven, t, -t), broadcast(constants::qnan)))); +} + +template +KFR_INTRINSIC vec root(const vec& x, const vec& b) +{ + const vec t = exp(reciprocal(b) * log(abs(x))); + const mask isint = floor(b) == b; + const mask iseven = (broadcastto>(b) & 1) == 0; + return select(x > T(), t, + select(x == T(), T(), + select(isint, select(iseven, broadcast(constants::qnan), -t), + broadcast(constants::qnan)))); +} + +template +KFR_INTRINSIC vec cbrt(const vec& x) +{ + return root(x, T(3)); +} + +template ), typename Tout = flt_type> +KFR_INTRINSIC vec cbrt(const vec& x) +{ + return cbrt(broadcastto(x)); +} + +KFR_HANDLE_SCALAR_1_T(exp, flt_type) +KFR_HANDLE_SCALAR_1_T(exp2, flt_type) +KFR_HANDLE_SCALAR_1_T(exp10, flt_type) +KFR_HANDLE_SCALAR_1_T(log, flt_type) +KFR_HANDLE_SCALAR_1_T(log2, flt_type) +KFR_HANDLE_SCALAR_1_T(log10, flt_type) +KFR_HANDLE_SCALAR_1_T(logb, flt_type) +KFR_HANDLE_SCALAR_1_T(pow, flt_type) +KFR_HANDLE_SCALAR_1_T(root, flt_type) +KFR_HANDLE_SCALAR_1_T(cbrt, flt_type) + +KFR_HANDLE_ARGS_T(exp, flt_type) +KFR_HANDLE_ARGS_T(exp2, flt_type) +KFR_HANDLE_ARGS_T(exp10, flt_type) +KFR_HANDLE_ARGS_T(log, flt_type) +KFR_HANDLE_ARGS_T(log2, flt_type) +KFR_HANDLE_ARGS_T(log10, flt_type) +KFR_HANDLE_ARGS_T(logb, flt_type) +KFR_HANDLE_ARGS_T(pow, flt_type) +KFR_HANDLE_ARGS_T(root, flt_type) +KFR_HANDLE_ARGS_T(cbrt, flt_type) + +KFR_HANDLE_NOT_F_1(exp) +KFR_HANDLE_NOT_F_1(log) +KFR_HANDLE_NOT_F_1(logb) +KFR_HANDLE_NOT_F_1(pow) +KFR_HANDLE_NOT_F_1(root) +KFR_HANDLE_NOT_F_1(cbrt) + +template +KFR_INTRINSIC flt_type> logn(const T1& a, const T2& b) +{ + return log(a) / log(b); +} + +template +KFR_INTRINSIC flt_type> logm(const T1& a, const T2& b) +{ + return log(a) * b; +} + +template +KFR_INTRINSIC flt_type> exp_fmadd(const T1& x, const T2& m, const T3& a) +{ + return exp(fmadd(x, m, a)); +} + +template +KFR_INTRINSIC flt_type> log_fmadd(const T1& x, const T2& m, const T3& a) +{ + return fmadd(log(x), m, a); +} +} // namespace intrinsics +KFR_I_FN(exp) +KFR_I_FN(exp2) +KFR_I_FN(exp10) +KFR_I_FN(log) +KFR_I_FN(log2) +KFR_I_FN(log10) +KFR_I_FN(logb) +KFR_I_FN(logn) +KFR_I_FN(logm) +KFR_I_FN(exp_fmadd) +KFR_I_FN(log_fmadd) +KFR_I_FN(pow) +KFR_I_FN(root) +KFR_I_FN(cbrt) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/modzerobessel.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/modzerobessel.hpp new file mode 100644 index 00000000..ec462b68 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/modzerobessel.hpp @@ -0,0 +1,104 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../math/log_exp.hpp" +#include "../../simd/impl/function.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +#if CMT_HAS_WARNING("-Wc99-extensions") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wc99-extensions") +#endif + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC vec modzerobessel(const vec& x) +{ + constexpr static T bessel_coef[] = { T(0.25), + T(0.027777777777777776236), + T(0.0017361111111111110147), + T(6.9444444444444444384e-005), + T(1.9290123456790123911e-006), + T(3.9367598891408417495e-008), + T(6.1511873267825652335e-010), + T(7.5940584281266239246e-012), + T(7.5940584281266233693e-014), + T(6.2760813455591932909e-016), + T(4.3583898233049949985e-018), + T(2.5789288895295827557e-020), + T(1.3157800456783586208e-022), + T(5.8479113141260384983e-025), + T(2.2843403570804837884e-027), + T(7.904291893012054025e-030), + T(2.4395962632753252792e-032), + T(6.75788438580422547e-035), + T(1.689471096451056426e-037), + T(3.8310002187098784929e-040), + T(7.9152897080782616517e-043), + T(1.4962740468957016443e-045), + T(2.5976979980828152196e-048), + T(4.1563167969325041577e-051), + T(6.1483976285983795968e-054), + T(8.434015951438105991e-057), + T(1.0757673407446563809e-059), + T(1.2791526049282476926e-062), + T(1.4212806721424974034e-065), + T(1.4789601166935457918e-068), + T(1.4442969889585408123e-071), + T(1.3262598613026086927e-074), + T(1.1472836170437790782e-077), + T(9.3655805472961564331e-081), + T(7.2265282000741942594e-084), + T(5.2786911614858977913e-087), + T(3.6556032974279072401e-090), + T(2.4034209713529963119e-093), + T(1.5021381070956226783e-096) }; + + const vec x_2 = x * 0.5; + const vec x_2_sqr = x_2 * x_2; + vec num = x_2_sqr; + vec result; + result = 1 + x_2_sqr; + + CMT_LOOP_UNROLL + for (size_t i = 0; i < (sizeof(T) == 4 ? 20 : 39); i++) + { + result = fmadd((num *= x_2_sqr), bessel_coef[i], result); + } + return result; +} + +KFR_HANDLE_SCALAR(modzerobessel) +} // namespace intrinsics +KFR_I_FN(modzerobessel) +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sin_cos.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sin_cos.hpp new file mode 100644 index 00000000..7065169d --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sin_cos.hpp @@ -0,0 +1,310 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/abs.hpp" +#include "../../simd/constants.hpp" +#include "../../simd/impl/function.hpp" +#include "../../simd/min_max.hpp" +#include "../../simd/operators.hpp" +#include "../../simd/round.hpp" +#include "../../simd/select.hpp" +#include "../../simd/shuffle.hpp" + +#if CMT_HAS_WARNING("-Wc99-extensions") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wc99-extensions") +#endif + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC vec trig_horner(const vec&, const mask& msk, const T& a0, const T& b0) +{ + return select(msk, a0, b0); +} + +template +KFR_INTRINSIC vec trig_horner(const vec& x, const mask& msk, const T& a0, const T& b0, + const T& a1, const T& b1, const Ts&... values) +{ + return fmadd(trig_horner(x, msk, a1, b1, values...), x, select(msk, a0, b0)); +} + +template +KFR_INTRINSIC vec trig_fold(const vec& x, vec, N>& quadrant) +{ + const vec xabs = abs(x); + constexpr T div = constants::fold_constant_div; + vec y = floor(xabs / div); + quadrant = broadcastto>(broadcastto(y - floor(y * T(1.0 / 16.0)) * T(16.0))); + + const vec, N> odd = (quadrant & 1); + quadrant = (quadrant + odd) & itype(7); + y = y + cast(odd); + + constexpr T hi = constants::fold_constant_hi; + constexpr T rem1 = constants::fold_constant_rem1; + constexpr T rem2 = constants::fold_constant_rem2; + return (xabs - y * hi) - y * rem1 - y * rem2; +} + +template +KFR_INTRINSIC vec fold_range(const vec& x) +{ + vec, N> q; + return trig_fold(x, q); +} + +template +KFR_INTRINSIC vec trig_sincos(const vec& folded, const mask& cosmask) +{ + constexpr f32 sin_c2 = CMT_FP(-0x2.aaaaacp-4f, -1.6666667163e-01f); + constexpr f32 sin_c4 = CMT_FP(0x2.222334p-8f, 8.3333970979e-03f); + constexpr f32 sin_c6 = CMT_FP(-0xd.0566ep-16f, -1.9868623349e-04f); + constexpr f32 sin_c8 = CMT_FP(0x3.64cc1cp-20f, 3.2365221614e-06f); + constexpr f32 sin_c10 = CMT_FP(-0x5.6c4a4p-24f, -3.2323646337e-07f); + constexpr f32 cos_c2 = CMT_FP(-0x8.p-4f, -5.0000000000e-01f); + constexpr f32 cos_c4 = CMT_FP(0xa.aaaabp-8f, 4.1666667908e-02f); + constexpr f32 cos_c6 = CMT_FP(-0x5.b05d48p-12f, -1.3888973044e-03f); + constexpr f32 cos_c8 = CMT_FP(0x1.a065f8p-16f, 2.4819273676e-05f); + constexpr f32 cos_c10 = CMT_FP(-0x4.cd156p-24f, -2.8616830150e-07f); + + const vec x2 = folded * folded; + + vec formula = trig_horner(x2, cosmask, 1.0f, 1.0f, cos_c2, sin_c2, cos_c4, sin_c4, cos_c6, sin_c6, + cos_c8, sin_c8, cos_c10, sin_c10); + + formula = select(cosmask, formula, formula * folded); + return formula; +} + +template +KFR_INTRINSIC vec trig_sincos(const vec& folded, const mask& cosmask) +{ + constexpr f64 sin_c2 = CMT_FP(-0x2.aaaaaaaaaaaaap-4, -1.666666666666666574e-01); + constexpr f64 sin_c4 = CMT_FP(0x2.22222222220cep-8, 8.333333333333038315e-03); + constexpr f64 sin_c6 = CMT_FP(-0xd.00d00cffd6618p-16, -1.984126984092335463e-04); + constexpr f64 sin_c8 = CMT_FP(0x2.e3bc744fb879ep-20, 2.755731902164406591e-06); + constexpr f64 sin_c10 = CMT_FP(-0x6.b99034c1467a4p-28, -2.505204327429436704e-08); + constexpr f64 sin_c12 = CMT_FP(0xb.0711ea8fe8ee8p-36, 1.604729496525771112e-10); + constexpr f64 sin_c14 = CMT_FP(-0xb.7e010897e55dp-44, -6.532561241665605726e-13); + constexpr f64 sin_c16 = CMT_FP(-0xb.64eac07f1d6bp-48, -4.048035517573349688e-14); + constexpr f64 cos_c2 = CMT_FP(-0x8.p-4, -5.000000000000000000e-01); + constexpr f64 cos_c4 = CMT_FP(0xa.aaaaaaaaaaaa8p-8, 4.166666666666666435e-02); + constexpr f64 cos_c6 = CMT_FP(-0x5.b05b05b05ad28p-12, -1.388888888888844490e-03); + constexpr f64 cos_c8 = CMT_FP(0x1.a01a01a0022e6p-16, 2.480158730125666056e-05); + constexpr f64 cos_c10 = CMT_FP(-0x4.9f93ed845de2cp-24, -2.755731909937878141e-07); + constexpr f64 cos_c12 = CMT_FP(0x8.f76bc015abe48p-32, 2.087673146642573010e-09); + constexpr f64 cos_c14 = CMT_FP(-0xc.9bf2dbe00379p-40, -1.146797738558921387e-11); + constexpr f64 cos_c16 = CMT_FP(0xd.1232ac32f7258p-48, 4.643782497495272199e-14); + + vec x2 = folded * folded; + vec formula = + trig_horner(x2, cosmask, 1.0, 1.0, cos_c2, sin_c2, cos_c4, sin_c4, cos_c6, sin_c6, cos_c8, sin_c8, + cos_c10, sin_c10, cos_c12, sin_c12, cos_c14, sin_c14, cos_c16, sin_c16); + + formula = select(cosmask, formula, formula * folded); + return formula; +} + +template 1)> +KFR_INTRINSIC vec sincos_mask(const vec& x_full, const mask& cosmask) +{ + vec, N> quadrant; + vec folded = trig_fold(x_full, quadrant); + + mask flip_sign = + kfr::select(cosmask, ((quadrant == 2) || (quadrant == 4)).asvec(), (quadrant >= 4).asvec()).asmask(); + + mask usecos = (quadrant == 2) || (quadrant == 6); + usecos = usecos ^ cosmask; + + vec formula = trig_sincos(folded, usecos); + + mask negmask = x_full < T(0); + + flip_sign = flip_sign ^ (negmask & ~cosmask); + + formula = select(flip_sign, -formula, formula); + return formula; +} + +template )> +KFR_INTRINSIC vec sin(const vec& x) +{ + vec, N> quadrant; + mask xmask = mask(x); + vec folded = trig_fold(x, quadrant); + + mask flip_sign = (quadrant >= 4) ^ xmask; + mask usecos = (quadrant == 2) || (quadrant == 6); + + vec formula = trig_sincos(folded, usecos); + + formula = select(flip_sign, -formula, formula); + return formula; +} + +template )> +KFR_INTRINSIC vec cos(const vec& x) +{ + vec, N> quadrant; + vec folded = trig_fold(x, quadrant); + + mask eq4 = (quadrant == 4); + mask flip_sign = (quadrant == 2) || eq4; + mask usecos = (quadrant == 0) || eq4; + + vec formula = trig_sincos(folded, usecos); + + formula = select(flip_sign, -formula, formula); + return formula; +} + +template )> +KFR_INTRINSIC vec fastsin(const vec& x) +{ + const vec msk = broadcast(special_constants::highbitmask()); + + constexpr static T c2 = -0.16665853559970855712890625; + constexpr static T c4 = +8.31427983939647674560546875e-3; + constexpr static T c6 = -1.85423981747590005397796630859375e-4; + + const vec pi = c_pi; + + vec xx = x - pi; + vec y = abs(xx); + y = select(y > c_pi, pi - y, y); + y = y ^ (msk & ~xx); + + vec y2 = y * y; + vec formula = c6; + vec y3 = y2 * y; + formula = fmadd(formula, y2, c4); + formula = fmadd(formula, y2, c2); + formula = formula * y3 + y; + return formula; +} + +template )> +KFR_INTRINSIC vec fastcos(const vec& x) +{ + x += c_pi; + x = select(x >= c_pi, x - c_pi, x); + return fastsin(x); +} + +template 1 && is_f_class)> +KFR_INTRINSIC vec sincos(const vec& x) +{ + return sincos_mask(x, internal::oddmask()); +} + +template 1 && is_f_class)> +KFR_INTRINSIC vec cossin(const vec& x) +{ + return sincos_mask(x, internal::evenmask()); +} + +template )> +KFR_INTRINSIC vec sinc(const vec& x) +{ + return select(abs(x) <= constants::epsilon, T(1), sin(x) / x); +} + +KFR_HANDLE_SCALAR_1_T(sin, flt_type) +KFR_HANDLE_SCALAR_1_T(cos, flt_type) +KFR_HANDLE_SCALAR_1_T(fastsin, flt_type) +KFR_HANDLE_SCALAR_1_T(fastcos, flt_type) +KFR_HANDLE_SCALAR_1_T(sincos, flt_type) +KFR_HANDLE_SCALAR_1_T(cossin, flt_type) +KFR_HANDLE_SCALAR_1_T(sinc, flt_type) + +KFR_HANDLE_NOT_F_1(sin) +KFR_HANDLE_NOT_F_1(cos) +KFR_HANDLE_NOT_F_1(fastsin) +KFR_HANDLE_NOT_F_1(fastcos) +KFR_HANDLE_NOT_F_1(sincos) +KFR_HANDLE_NOT_F_1(cossin) +KFR_HANDLE_NOT_F_1(sinc) + +template > +KFR_INTRINSIC Tout sindeg(const T& x) +{ + return sin(x * constants::degtorad); +} + +template > +KFR_INTRINSIC Tout cosdeg(const T& x) +{ + return cos(x * constants::degtorad); +} + +template > +KFR_INTRINSIC Tout fastsindeg(const T& x) +{ + return fastsin(x * constants::degtorad); +} + +template > +KFR_INTRINSIC Tout fastcosdeg(const T& x) +{ + return fastcos(x * constants::degtorad); +} + +template > +KFR_INTRINSIC Tout sincosdeg(const T& x) +{ + return sincos(x * constants::degtorad); +} + +template > +KFR_INTRINSIC Tout cossindeg(const T& x) +{ + return cossin(x * constants::degtorad); +} +} // namespace intrinsics + +KFR_I_FN(sin) +KFR_I_FN(cos) +KFR_I_FN(fastsin) +KFR_I_FN(fastcos) +KFR_I_FN(sincos) +KFR_I_FN(cossin) + +KFR_I_FN(sindeg) +KFR_I_FN(cosdeg) +KFR_I_FN(fastsindeg) +KFR_I_FN(fastcosdeg) +KFR_I_FN(sincosdeg) +KFR_I_FN(cossindeg) + +KFR_I_FN(sinc) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sqrt.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sqrt.hpp new file mode 100644 index 00000000..3f4d50a7 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/sqrt.hpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/impl/function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#if defined CMT_ARCH_SSE2 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC f32x1 sqrt(const f32x1& x) { return slice<0, 1>(f32x4(_mm_sqrt_ss(extend<4>(x).v))); } +KFR_INTRINSIC f64x1 sqrt(const f64x1& x) +{ + return slice<0, 1>(f64x2(_mm_sqrt_sd(_mm_setzero_pd(), extend<2>(x).v))); +} +KFR_INTRINSIC f32sse sqrt(const f32sse& x) { return _mm_sqrt_ps(x.v); } +KFR_INTRINSIC f64sse sqrt(const f64sse& x) { return _mm_sqrt_pd(x.v); } + +#if defined CMT_ARCH_AVX +KFR_INTRINSIC f32avx sqrt(const f32avx& x) { return _mm256_sqrt_ps(x.v); } +KFR_INTRINSIC f64avx sqrt(const f64avx& x) { return _mm256_sqrt_pd(x.v); } +#endif + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC f32avx512 sqrt(const f32avx512& x) { return _mm512_sqrt_ps(x.v); } +KFR_INTRINSIC f64avx512 sqrt(const f64avx512& x) { return _mm512_sqrt_pd(x.v); } +#endif + +KFR_HANDLE_ALL_SIZES_1_IF(sqrt, is_f_class) + +#else + +// fallback +template )> +KFR_INTRINSIC vec sqrt(const vec& x) +{ + return apply([](T x) { return std::sqrt(x); }, x); +} +#endif +KFR_HANDLE_SCALAR_1_T(sqrt, flt_type) + +KFR_HANDLE_NOT_F_1(sqrt) +} // namespace intrinsics +KFR_I_FN(sqrt) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/tan.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/tan.hpp new file mode 100644 index 00000000..ab8b3a19 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/impl/tan.hpp @@ -0,0 +1,152 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../simd/abs.hpp" +#include "../../simd/constants.hpp" +#include "../../simd/impl/function.hpp" +#include "../../simd/operators.hpp" +#include "../../simd/select.hpp" +#include "../sin_cos.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template > +KFR_INTRINSIC vec trig_fold_simple(const vec& x_full, mask& inverse) +{ + constexpr T pi_14 = c_pi; + + vec y = abs(x_full); + vec scaled = y / pi_14; + + vec k_real = floor(scaled); + vec k = broadcastto(k_real); + + vec x = y - k_real * pi_14; + + mask need_offset = (k & 1) != 0; + x = select(need_offset, x - pi_14, x); + + vec k_mod4 = k & 3; + inverse = (k_mod4 == 1) || (k_mod4 == 2); + return x; +} + +template +KFR_INTRINSIC vec tan(const vec& x_full) +{ + mask inverse; + vec quad; + const vec x = trig_fold(x_full, quad); // trig_fold_simple(x_full, inverse); + inverse = quad == 2 || quad == 6; + + constexpr f32 tan_c2 = CMT_FP(0x5.555378p-4, 3.333315551280975342e-01); + constexpr f32 tan_c4 = CMT_FP(0x2.225bb8p-4, 1.333882510662078857e-01); + constexpr f32 tan_c6 = CMT_FP(0xd.ac3fep-8, 5.340956896543502808e-02); + constexpr f32 tan_c8 = CMT_FP(0x6.41644p-8, 2.443529665470123291e-02); + constexpr f32 tan_c10 = CMT_FP(0xc.bfe7ep-12, 3.112703096121549606e-03); + constexpr f32 tan_c12 = CMT_FP(0x2.6754dp-8, 9.389210492372512817e-03); + + constexpr f32 cot_c2 = CMT_FP(-0x5.555558p-4, -3.333333432674407959e-01); + constexpr f32 cot_c4 = CMT_FP(-0x5.b0581p-8, -2.222204580903053284e-02); + constexpr f32 cot_c6 = CMT_FP(-0x8.ac5ccp-12, -2.117502503097057343e-03); + constexpr f32 cot_c8 = CMT_FP(-0xd.aaa01p-16, -2.085343148792162538e-04); + constexpr f32 cot_c10 = CMT_FP(-0x1.a9a9b4p-16, -2.537148611736483872e-05); + constexpr f32 cot_c12 = CMT_FP(-0x6.f7d4dp-24, -4.153305894760705996e-07); + + const vec x2 = x * x; + const vec val = trig_horner(x2, inverse, 1.0f, 1.0f, cot_c2, tan_c2, cot_c4, tan_c4, cot_c6, + tan_c6, cot_c8, tan_c8, cot_c10, tan_c10, cot_c12, tan_c12); + + const vec z = select(inverse, val / -x, val * x); + return mulsign(z, x_full); +} + +template +KFR_INTRINSIC vec tan(const vec& x_full) +{ + mask inverse; + vec quad; + const vec x = trig_fold(x_full, quad); // trig_fold_simple(x_full, inverse); + inverse = quad == 2 || quad == 6; + + constexpr f64 tan_c2 = 0x1.5555555555a3cp-2; + constexpr f64 tan_c4 = 0x1.11111110c4068p-3; + constexpr f64 tan_c6 = 0x1.ba1ba1ef36a4dp-5; + constexpr f64 tan_c8 = 0x1.664f3f4af7ce2p-6; + constexpr f64 tan_c10 = 0x1.226f2682a2616p-7; + constexpr f64 tan_c12 = 0x1.d6b440e73f61dp-9; + constexpr f64 tan_c14 = 0x1.7f06cdd30bd39p-10; + constexpr f64 tan_c16 = 0x1.2a8fab895738ep-11; + constexpr f64 tan_c18 = 0x1.34ff88cfdc292p-12; + constexpr f64 tan_c20 = -0x1.b4165ea04339fp-18; + constexpr f64 tan_c22 = 0x1.5f93701d86962p-13; + constexpr f64 tan_c24 = -0x1.5a13a3cdfb8c1p-14; + constexpr f64 tan_c26 = 0x1.77c69cef3306cp-15; + + constexpr f64 cot_c2 = -0x1.5555555555555p-2; + constexpr f64 cot_c4 = -0x1.6c16c16c16dcdp-6; + constexpr f64 cot_c6 = -0x1.1566abbff68a7p-9; + constexpr f64 cot_c8 = -0x1.bbd7794ef9999p-13; + constexpr f64 cot_c10 = -0x1.66a8ea1991906p-16; + constexpr f64 cot_c12 = -0x1.228220068711cp-19; + constexpr f64 cot_c14 = -0x1.d65ed2c45e21dp-23; + constexpr f64 cot_c16 = -0x1.897ead4a2f71dp-26; + constexpr f64 cot_c18 = -0x1.b592dc8656ec9p-31; + constexpr f64 cot_c20 = -0x1.3dc07078c46d6p-29; + constexpr f64 cot_c22 = 0x1.06c9e5c370edcp-29; + constexpr f64 cot_c24 = -0x1.217f50c9dbca3p-30; + constexpr f64 cot_c26 = 0x1.163ed8171a0c8p-32; + + const vec x2 = x * x; + const vec val = + trig_horner(x2, inverse, 1.0, 1.0, cot_c2, tan_c2, cot_c4, tan_c4, cot_c6, tan_c6, cot_c8, tan_c8, + cot_c10, tan_c10, cot_c12, tan_c12, cot_c14, tan_c14, cot_c16, tan_c16, cot_c18, tan_c18, + cot_c20, tan_c20, cot_c22, tan_c22, cot_c24, tan_c24, cot_c26, tan_c26); + + const vec z = select(inverse, val / -x, val * x); + return mulsign(z, x_full); +} + +KFR_HANDLE_SCALAR_1_T(tan, flt_type) +KFR_HANDLE_NOT_F_1(tan) + +template +KFR_INTRINSIC flt_type tandeg(const T& x) +{ + return tan(x * c_degtorad>); +} +} // namespace intrinsics +namespace fn +{ +} +KFR_I_FN(tan) +KFR_I_FN(tandeg) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/interpolation.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/interpolation.hpp new file mode 100644 index 00000000..82b51904 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/interpolation.hpp @@ -0,0 +1,74 @@ +/** @addtogroup interpolation + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../simd/select.hpp" +#include "sin_cos.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +KFR_FUNCTION T nearest(M mu, T x1, T x2) +{ + return select(mu < M(0.5), x1, x2); +} + +template +KFR_FUNCTION T linear(M mu, T x1, T x2) +{ + return mix(mu, x1, x2); +} + +template +KFR_FUNCTION T cosine(M mu, T x1, T x2) +{ + return mix((M(1) - fastcos(mu * c_pi)) * M(0.5), x1, x2); +} + +template +KFR_FUNCTION T cubic(M mu, T x0, T x1, T x2, T x3) +{ + const T a0 = x3 - x2 - x0 + x1; + const T a1 = x0 - x1 - a0; + const T a2 = x2 - x0; + const T a3 = x1; + return horner(mu, a0, a1, a2, a3); +} + +template +KFR_FUNCTION T catmullrom(M mu, T x0, T x1, T x2, T x3) +{ + const T a0 = T(0.5) * (x3 - x0) - T(1.5) * (x2 - x1); + const T a1 = x0 - T(2.5) * x1 + T(2) * x2 - T(0.5) * x3; + const T a2 = T(0.5) * (x2 - x0); + const T a3 = x1; + return horner(mu, a0, a1, a2, a3); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/log_exp.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/log_exp.hpp new file mode 100644 index 00000000..e0017f61 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/log_exp.hpp @@ -0,0 +1,133 @@ +/** @addtogroup exponential + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/log_exp.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Returns e raised to the given power x. +template )> +KFR_FUNCTION flt_type exp(const T1& x) +{ + return intrinsics::exp(x); +} + +/// @brief Returns 2 raised to the given power x. +template )> +KFR_FUNCTION flt_type exp2(const T1& x) +{ + return intrinsics::exp2(x); +} + +/// @brief Returns 10 raised to the given power x. +template )> +KFR_FUNCTION flt_type exp10(const T1& x) +{ + return intrinsics::exp10(x); +} + +/// @brief Returns the natural logarithm of the x. +template )> +KFR_FUNCTION flt_type log(const T1& x) +{ + return intrinsics::log(x); +} + +/// @brief Returns the binary (base-2) logarithm of the x. +template )> +KFR_FUNCTION flt_type log2(const T1& x) +{ + return intrinsics::log2(x); +} + +/// @brief Returns the common (base-10) logarithm of the x. +template )> +KFR_FUNCTION flt_type log10(const T1& x) +{ + return intrinsics::log10(x); +} + +/// @brief Returns the rounded binary (base-2) logarithm of the x. +template )> +KFR_FUNCTION flt_type logb(const T1& x) +{ + return intrinsics::logb(x); +} + +/// @brief Returns the logarithm of the x with base y. +template )> +KFR_FUNCTION flt_type> logn(const T1& x, const T2& y) +{ + return intrinsics::logn(x, y); +} + +/// @brief Returns log(x) * y. +template )> +KFR_FUNCTION flt_type> logm(const T1& x, const T2& y) +{ + return intrinsics::logm(x, y); +} + +/// @brief Returns exp(x * m + a). +template )> +KFR_FUNCTION flt_type> exp_fmadd(const T1& x, const T2& y, const T3& z) +{ + return intrinsics::exp_fmadd(x, y, z); +} + +/// @brief Returns log(x) * m + a. +template )> +KFR_FUNCTION flt_type> log_fmadd(const T1& x, const T2& y, const T3& z) +{ + return intrinsics::log_fmadd(x, y, z); +} + +/// @brief Returns the x raised to the given power y. +template )> +KFR_FUNCTION flt_type> pow(const T1& x, const T2& y) +{ + return intrinsics::pow(x, y); +} + +/// @brief Returns the real nth root of the x. +template )> +KFR_FUNCTION flt_type> root(const T1& x, const T2& y) +{ + return intrinsics::root(x, y); +} + +/// @brief Returns the cube root of the x. +template )> +KFR_FUNCTION flt_type cbrt(const T1& x) +{ + return intrinsics::cbrt(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/modzerobessel.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/modzerobessel.hpp new file mode 100644 index 00000000..38b5e2d9 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/modzerobessel.hpp @@ -0,0 +1,41 @@ +/** @addtogroup other_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/modzerobessel.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template )> +KFR_FUNCTION T1 modzerobessel(const T1& x) +{ + return intrinsics::modzerobessel(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/sin_cos.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/sin_cos.hpp new file mode 100644 index 00000000..50134f43 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/sin_cos.hpp @@ -0,0 +1,195 @@ +/** @addtogroup trigonometric + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/sin_cos.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the trigonometric sine of x. + */ +template )> +KFR_FUNCTION flt_type sin(const T1& x) +{ + return intrinsics::sin(x); +} + +/** + * @brief Returns the trigonometric cosine of x. + */ +template )> +KFR_FUNCTION flt_type cos(const T1& x) +{ + return intrinsics::cos(x); +} + +/** + * @brief Returns an approximation of the trigonometric sine of x. + */ +template )> +KFR_FUNCTION flt_type fastsin(const T1& x) +{ + return intrinsics::fastsin(x); +} + +/** + * @brief Returns an approximation of the trigonometric cosine of x. + */ +template )> +KFR_FUNCTION flt_type fastcos(const T1& x) +{ + return intrinsics::fastcos(x); +} + +/** + * @brief Returns the trigonometric sine of the even elements of the x and cosine of the odd elements. x must + * be a vector. + */ +template )> +KFR_FUNCTION flt_type sincos(const T1& x) +{ + return intrinsics::sincos(x); +} + +/** + * @brief Returns the trigonometric cosine of the even elements of the x and sine of the odd elements. x must + * be a vector. + */ +template )> +KFR_FUNCTION flt_type cossin(const T1& x) +{ + return intrinsics::cossin(x); +} + +/** + * @brief Returns the trigonometric sine of the x (expressed in degrees). + */ +template )> +KFR_FUNCTION flt_type sindeg(const T1& x) +{ + return intrinsics::sindeg(x); +} + +/** + * @brief Returns the trigonometric cosine of the x (expressed in degrees). + */ +template )> +KFR_FUNCTION flt_type cosdeg(const T1& x) +{ + return intrinsics::cosdeg(x); +} + +/** + * @brief Returns an approximation of the trigonometric sine of the x (expressed in degrees). + */ +template )> +KFR_FUNCTION flt_type fastsindeg(const T1& x) +{ + return intrinsics::fastsindeg(x); +} + +/** + * @brief Returns an approximation of the trigonometric cosine of the x (expressed in degrees). + */ +template )> +KFR_FUNCTION flt_type fastcosdeg(const T1& x) +{ + return intrinsics::fastcosdeg(x); +} + +/** + * @brief Returns the trigonometric sine of the even elements of the x and cosine of the odd elements. x must + * be a vector and expressed in degrees. + */ +template )> +KFR_FUNCTION flt_type sincosdeg(const T1& x) +{ + return intrinsics::sincosdeg(x); +} + +/** + * @brief Returns the trigonometric cosine of the even elements of the x and sine of the odd elements. x must + * be a vector and expressed in degrees. + */ +template )> +KFR_FUNCTION flt_type cossindeg(const T1& x) +{ + return intrinsics::cossindeg(x); +} + +/** + * @brief Returns the sinc function of x. + * \f[ + * sinc(x) = \frac{sin(x)}{x} + * \f] + */ +template )> +KFR_FUNCTION flt_type sinc(const T1& x) +{ + return intrinsics::sinc(x); +} + +/** + * @brief Returns the trigonometric sine of the angle 2x using sin(x) and cos(x). + */ +template +KFR_INTRINSIC T sin2x(const T& sinx, const T& cosx) +{ + return 2 * sinx * cosx; +} + +/** + * @brief Returns the trigonometric sine of the angle 3x using already computed sin(x) and cos(x). + */ +template +KFR_INTRINSIC T sin3x(const T& sinx, const T& cosx) +{ + return sinx * (-1 + 4 * sqr(cosx)); +} + +/** + * @brief Returns the trigonometric cosine of the angle 2x using already computed sin(x) and cos(x). + */ +template +KFR_INTRINSIC T cos2x(const T& sinx, const T& cosx) +{ + return sqr(cosx) - sqr(sinx); +} + +/** + * @brief Returns the trigonometric cosine of the angle 3x using already computed sin(x) and cos(x). + */ +template +KFR_INTRINSIC T cos3x(const T& sinx, const T& cosx) +{ + return cosx * (1 - 4 * sqr(sinx)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/sqrt.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/sqrt.hpp new file mode 100644 index 00000000..534cd808 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/sqrt.hpp @@ -0,0 +1,44 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/sqrt.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the positive square root of the x. \f$\sqrt{x}\f$ + */ +template )> +KFR_INTRINSIC flt_type sqrt(const T1& x) +{ + return intrinsics::sqrt(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/math/tan.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/math/tan.hpp new file mode 100644 index 00000000..07d58cae --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/math/tan.hpp @@ -0,0 +1,47 @@ +/** @addtogroup trigonometric + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/tan.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template )> +KFR_FUNCTION flt_type tan(const T1& x) +{ + return intrinsics::tan(x); +} + +template )> +KFR_FUNCTION flt_type tandeg(const T1& x) +{ + return intrinsics::tandeg(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/multiarch.h b/packages/react-native-audio-api/android/src/main/include/kfr/multiarch.h new file mode 100644 index 00000000..7ce1b9ce --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/multiarch.h @@ -0,0 +1,196 @@ +#include "cident.h" + +#ifdef CMT_ARCH_X86 + +// x86 + +#ifdef CMT_MULTI_ENABLED_AVX512 +#define CMT_IF_ENABLED_AVX512(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_AVX512(...) +#endif + +#ifdef CMT_MULTI_ENABLED_AVX2 +#define CMT_IF_ENABLED_AVX2(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_AVX2(...) +#endif + +#ifdef CMT_MULTI_ENABLED_AVX +#define CMT_IF_ENABLED_AVX(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_AVX(...) +#endif + +#ifdef CMT_MULTI_ENABLED_SSE42 +#define CMT_IF_ENABLED_SSE42(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_SSE42(...) +#endif + +#ifdef CMT_MULTI_ENABLED_SSE41 +#define CMT_IF_ENABLED_SSE41(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_SSE41(...) +#endif + +#ifdef CMT_MULTI_ENABLED_SSSE3 +#define CMT_IF_ENABLED_SSSE3(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_SSSE3(...) +#endif + +#ifdef CMT_MULTI_ENABLED_SSE3 +#define CMT_IF_ENABLED_SSE3(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_SSE3(...) +#endif + +#ifdef CMT_MULTI_ENABLED_SSE2 +#define CMT_IF_ENABLED_SSE2(...) __VA_ARGS__ +#else +#define CMT_IF_ENABLED_SSE2(...) +#endif + +#ifdef CMT_MULTI + +#define CMT_MULTI_PROTO_GATE(...) \ + if (cpu == cpu_t::runtime) \ + cpu = get_cpu(); \ + switch (cpu) \ + { \ + case cpu_t::avx512: \ + CMT_IF_ENABLED_AVX512(return avx512::__VA_ARGS__;) \ + case cpu_t::avx2: \ + CMT_IF_ENABLED_AVX2(return avx2::__VA_ARGS__;) \ + case cpu_t::avx: \ + CMT_IF_ENABLED_AVX(return avx::__VA_ARGS__;) \ + case cpu_t::sse42: \ + CMT_IF_ENABLED_SSE42(return sse42::__VA_ARGS__;) \ + case cpu_t::sse41: \ + CMT_IF_ENABLED_SSE41(return sse41::__VA_ARGS__;) \ + case cpu_t::ssse3: \ + CMT_IF_ENABLED_SSSE3(return ssse3::__VA_ARGS__;) \ + case cpu_t::sse3: \ + CMT_IF_ENABLED_SSE3(return sse3::__VA_ARGS__;) \ + case cpu_t::sse2: \ + CMT_IF_ENABLED_SSE2(return sse2::__VA_ARGS__;) \ + default: \ + CMT_UNREACHABLE; \ + } + +#define CMT_MULTI_GATE(...) \ + switch (get_cpu()) \ + { \ + case cpu_t::avx512: \ + CMT_IF_ENABLED_AVX512({ \ + namespace ns = kfr::avx512; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::avx2: \ + CMT_IF_ENABLED_AVX2({ \ + namespace ns = kfr::avx2; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::avx: \ + CMT_IF_ENABLED_AVX({ \ + namespace ns = kfr::avx; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::sse42: \ + CMT_IF_ENABLED_SSE42({ \ + namespace ns = kfr::sse42; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::sse41: \ + CMT_IF_ENABLED_SSE41({ \ + namespace ns = kfr::sse41; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::ssse3: \ + CMT_IF_ENABLED_SSSE3({ \ + namespace ns = kfr::ssse3; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::sse3: \ + CMT_IF_ENABLED_SSE3({ \ + namespace ns = kfr::sse3; \ + __VA_ARGS__; \ + break; \ + }) \ + case cpu_t::sse2: \ + CMT_IF_ENABLED_SSE2({ \ + namespace ns = kfr::sse2; \ + __VA_ARGS__; \ + break; \ + }) \ + default: \ + CMT_UNREACHABLE; \ + } + +#define CMT_MULTI_PROTO(...) \ + CMT_IF_ENABLED_SSE2(CMT_IF_IS_SSE2(inline) namespace sse2{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_SSE3(CMT_IF_IS_SSE3(inline) namespace sse3{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_SSSE3(CMT_IF_IS_SSSE3(inline) namespace ssse3{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_SSE42(CMT_IF_IS_SSE42(inline) namespace sse42{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_SSE41(CMT_IF_IS_SSE41(inline) namespace sse41{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_AVX(CMT_IF_IS_AVX(inline) namespace avx{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_AVX2(CMT_IF_IS_AVX2(inline) namespace avx2{ __VA_ARGS__ }) \ + CMT_IF_ENABLED_AVX512(CMT_IF_IS_AVX512(inline) namespace avx512{ __VA_ARGS__ }) +#else +#define CMT_MULTI_GATE(...) \ + do \ + { \ + namespace ns = kfr::CMT_ARCH_NAME; \ + __VA_ARGS__; \ + break; \ + } while (0) + +#define CMT_MULTI_PROTO(...) \ + inline namespace CMT_ARCH_NAME \ + { \ + __VA_ARGS__ \ + } +#endif + +#if defined(CMT_BASE_ARCH) || !defined(CMT_MULTI) +#define CMT_MULTI_NEEDS_GATE +#else +#endif + +#else + +// ARM + +#define CMT_MULTI_PROTO_GATE(...) \ + do \ + { \ + return CMT_ARCH_NAME::__VA_ARGS__; \ + } while (0) + +#define CMT_MULTI_GATE(...) \ + do \ + { \ + namespace ns = kfr::CMT_ARCH_NAME; \ + __VA_ARGS__; \ + break; \ + } while (0) + +#define CMT_MULTI_PROTO(...) \ + inline namespace CMT_ARCH_NAME \ + { \ + __VA_ARGS__ \ + } + +#if defined(CMT_BASE_ARCH) || !defined(CMT_MULTI) +#define CMT_MULTI_NEEDS_GATE +#else +#endif + +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/runtime.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/runtime.hpp new file mode 100644 index 00000000..d10b049d --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/runtime.hpp @@ -0,0 +1,26 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "runtime/cpuid.hpp" +#include "runtime/cpuid_auto.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid.hpp new file mode 100644 index 00000000..63185050 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid.hpp @@ -0,0 +1,313 @@ +/** @addtogroup cpuid + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#ifdef _MSC_VER +#include +#endif + +#include "../simd/platform.hpp" +#include "../simd/types.hpp" +#include + +namespace kfr +{ +#if defined(CMT_ARCH_X86) && !defined(__wasm) +struct cpu_features +{ + u32 max; + u32 exmax; + u32 isIntel : 1; + u32 isAMD : 1; + u32 has3DNOW : 1; + u32 has3DNOWEXT : 1; + u32 hasABM : 1; + u32 hasADX : 1; + u32 hasAES : 1; + u32 hasAVX : 1; + u32 hasAVX2 : 1; + u32 hasAVXOSSUPPORT : 1; + u32 hasAVX512OSSUPPORT : 1; + u32 hasAVX512CD : 1; + u32 hasAVX512ER : 1; + u32 hasAVX512F : 1; + u32 hasAVX512DQ : 1; + u32 hasAVX512PF : 1; + u32 hasAVX512BW : 1; + u32 hasAVX512VL : 1; + u32 hasBMI1 : 1; + u32 hasBMI2 : 1; + u32 hasCLFSH : 1; + u32 hasCMOV : 1; + u32 hasCMPXCHG16B : 1; + u32 hasCX8 : 1; + u32 hasERMS : 1; + u32 hasF16C : 1; + u32 hasFMA : 1; + u32 hasFSGSBASE : 1; + u32 hasFXSR : 1; + u32 hasHLE : 1; + u32 hasINVPCID : 1; + u32 hasLAHF : 1; + u32 hasLZCNT : 1; + u32 hasMMX : 1; + u32 hasMMXEXT : 1; + u32 hasMONITOR : 1; + u32 hasMOVBE : 1; + u32 hasMSR : 1; + u32 hasOSXSAVE : 1; + u32 hasPCLMULQDQ : 1; + u32 hasPOPCNT : 1; + u32 hasPREFETCHWT1 : 1; + u32 hasRDRAND : 1; + u32 hasRDSEED : 1; + u32 hasRDTSCP : 1; + u32 hasRTM : 1; + u32 hasSEP : 1; + u32 hasSHA : 1; + u32 hasSSE : 1; + u32 hasSSE2 : 1; + u32 hasSSE3 : 1; + u32 hasSSE41 : 1; + u32 hasSSE42 : 1; + u32 hasSSE4a : 1; + u32 hasSSSE3 : 1; + u32 hasSYSCALL : 1; + u32 hasTBM : 1; + u32 hasXOP : 1; + u32 hasXSAVE : 1; + u32 padding1 : 6; + alignas(int32_t) char vendor[17]; + alignas(int32_t) char model[49]; + alignas(int32_t) char padding2[2]; +}; + +namespace internal_generic +{ + +struct cpu_data +{ + u32 data[4]; +}; + +#if defined CMT_COMPILER_GNU || defined CMT_COMPILER_CLANG +#if defined __i386__ +KFR_INTRINSIC u32 get_cpuid(u32 func, u32 subfunc, u32* eax, u32* ebx, u32* ecx, u32* edx) +{ + __asm__("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "0"(func), "2"(subfunc)); + return 1; +} +#else +KFR_INTRINSIC u32 get_cpuid(u32 func, u32 subfunc, u32* eax, u32* ebx, u32* ecx, u32* edx) +{ + __asm("xchgq %%rbx,%q1\n" + "cpuid\n" + "xchgq %%rbx,%q1" + : "=a"(*eax), "=r"(*ebx), "=c"(*ecx), "=d"(*edx) + : "0"(func), "2"(subfunc)); + return 1; +} +#endif +KFR_INTRINSIC void cpuid(u32* ptr, u32 func, u32 subfunc = 0) +{ + get_cpuid(func, subfunc, &ptr[0], &ptr[1], &ptr[2], &ptr[3]); +} +KFR_INTRINSIC u32 get_xcr0() +{ + u32 xcr0; + __asm__ __volatile__("xgetbv" : "=a"(xcr0) : "c"(0) : "%edx"); + return xcr0; +} +#elif defined CMT_COMPILER_MSVC + +KFR_INTRINSIC void cpuid(u32* ptr, u32 func, u32 subfunc = 0) +{ + __cpuidex((int*)ptr, (int)func, (int)subfunc); +} +KFR_INTRINSIC u32 get_xcr0() +{ +#ifdef _XCR_XFEATURE_ENABLED_MASK + unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); + return (u32)Result; +#else + return 0; +#endif +} +#endif + +template +cpu_t detect_cpu() +{ + cpu_features c; + memset(&c, 0, sizeof(c)); + cpu_data data0; + cpu_data exdata0; + + u32 f_1_ECX(0); + u32 f_1_EDX(0); + u32 f_7_EBX(0); + u32 f_7_ECX(0); + u32 f_81_ECX(0); + u32 f_81_EDX(0); + + cpuid(data0.data, 0); + c.max = static_cast(data0.data[0]); + cpuid(exdata0.data, 0x80000000); + c.exmax = static_cast(exdata0.data[0]); + + *ptr_cast(c.vendor) = static_cast(data0.data[1]); + *ptr_cast(c.vendor + 4) = static_cast(data0.data[3]); + *ptr_cast(c.vendor + 8) = static_cast(data0.data[2]); + + c.isIntel = strncmp(c.vendor, "GenuineIntel", sizeof(c.vendor)) == 0 ? 1 : 0; + c.isAMD = strncmp(c.vendor, "AuthenticAMD", sizeof(c.vendor)) == 0 ? 1 : 0; + + if (c.max >= 1) + { + cpu_data data1; + cpuid(data1.data, 1); + f_1_ECX = static_cast(data1.data[2]); + f_1_EDX = static_cast(data1.data[3]); + } + + if (c.max >= 7) + { + cpu_data data7; + cpuid(data7.data, 7); + f_7_EBX = static_cast(data7.data[1]); + f_7_ECX = static_cast(data7.data[2]); + } + + if (c.exmax >= 0x80000001) + { + cpu_data data81; + cpuid(data81.data, 0x80000001); + f_81_ECX = static_cast(data81.data[2]); + f_81_EDX = static_cast(data81.data[3]); + } + + if (c.exmax >= 0x80000004) + { + cpu_data data82; + cpu_data data83; + cpu_data data84; + cpuid(data82.data, 0x80000002); + cpuid(data83.data, 0x80000003); + cpuid(data84.data, 0x80000004); + memcpy(c.model, data82.data, sizeof(cpu_data)); + memcpy(c.model + 16, data83.data, sizeof(cpu_data)); + memcpy(c.model + 32, data84.data, sizeof(cpu_data)); + } + + c.hasSSE3 = f_1_ECX >> 0 & 1; + c.hasPCLMULQDQ = f_1_ECX >> 1 & 1; + c.hasMONITOR = f_1_ECX >> 3 & 1; + c.hasSSSE3 = f_1_ECX >> 9 & 1; + c.hasFMA = f_1_ECX >> 12 & 1; + c.hasCMPXCHG16B = f_1_ECX >> 13 & 1; + c.hasSSE41 = f_1_ECX >> 19 & 1; + c.hasSSE42 = f_1_ECX >> 20 & 1; + c.hasMOVBE = f_1_ECX >> 22 & 1; + c.hasPOPCNT = f_1_ECX >> 23 & 1; + c.hasAES = f_1_ECX >> 25 & 1; + c.hasXSAVE = f_1_ECX >> 26 & 1; + c.hasOSXSAVE = f_1_ECX >> 27 & 1; + c.hasAVX = f_1_ECX >> 28 & 1; + c.hasF16C = f_1_ECX >> 29 & 1; + c.hasRDRAND = f_1_ECX >> 30 & 1; + c.hasMSR = f_1_EDX >> 5 & 1; + c.hasCX8 = f_1_EDX >> 8 & 1; + c.hasSEP = f_1_EDX >> 11 & 1; + c.hasCMOV = f_1_EDX >> 15 & 1; + c.hasCLFSH = f_1_EDX >> 19 & 1; + c.hasMMX = f_1_EDX >> 23 & 1; + c.hasFXSR = f_1_EDX >> 24 & 1; + c.hasSSE = f_1_EDX >> 25 & 1; + c.hasSSE2 = f_1_EDX >> 26 & 1; + c.hasFSGSBASE = f_7_EBX >> 0 & 1; + c.hasBMI1 = f_7_EBX >> 3 & 1; + c.hasHLE = c.isIntel && f_7_EBX >> 4 & 1; + c.hasAVX2 = f_7_EBX >> 5 & 1; + c.hasBMI2 = f_7_EBX >> 8 & 1; + c.hasERMS = f_7_EBX >> 9 & 1; + c.hasINVPCID = f_7_EBX >> 10 & 1; + c.hasRTM = c.isIntel && f_7_EBX >> 11 & 1; + c.hasAVX512F = f_7_EBX >> 16 & 1; + c.hasAVX512DQ = f_7_EBX >> 17 & 1; + c.hasRDSEED = f_7_EBX >> 18 & 1; + c.hasADX = f_7_EBX >> 19 & 1; + c.hasAVX512PF = f_7_EBX >> 26 & 1; + c.hasAVX512ER = f_7_EBX >> 27 & 1; + c.hasAVX512CD = f_7_EBX >> 28 & 1; + c.hasSHA = f_7_EBX >> 29 & 1; + c.hasAVX512BW = f_7_EBX >> 30 & 1; + c.hasAVX512VL = f_7_EBX >> 31 & 1; + c.hasPREFETCHWT1 = f_7_ECX >> 0 & 1; + c.hasLAHF = f_81_ECX >> 0 & 1; + c.hasLZCNT = c.isIntel && f_81_ECX >> 5 & 1; + c.hasABM = c.isAMD && f_81_ECX >> 5 & 1; + c.hasSSE4a = c.isAMD && f_81_ECX >> 6 & 1; + c.hasXOP = c.isAMD && f_81_ECX >> 11 & 1; + c.hasTBM = c.isAMD && f_81_ECX >> 21 & 1; + c.hasSYSCALL = c.isIntel && f_81_EDX >> 11 & 1; + c.hasMMXEXT = c.isAMD && f_81_EDX >> 22 & 1; + c.hasRDTSCP = c.isIntel && f_81_EDX >> 27 & 1; + c.has3DNOWEXT = c.isAMD && f_81_EDX >> 30 & 1; + c.has3DNOW = c.isAMD && f_81_EDX >> 31 & 1; + + c.hasAVXOSSUPPORT = c.hasAVX && c.hasOSXSAVE && (get_xcr0() & 0x06) == 0x06; + c.hasAVX512OSSUPPORT = c.hasAVXOSSUPPORT && c.hasAVX512F && c.hasOSXSAVE && (get_xcr0() & 0xE0) == 0xE0; + + if (c.hasAVX512F && c.hasAVX512CD && c.hasAVX512VL && c.hasAVX512BW && c.hasAVX512DQ && + c.hasAVX512OSSUPPORT) + return cpu_t::avx512; + if (c.hasAVX2 && c.hasAVXOSSUPPORT) + return cpu_t::avx2; + if (c.hasAVX && c.hasAVXOSSUPPORT) + return cpu_t::avx1; + if (c.hasSSE42) + return cpu_t::sse42; + if (c.hasSSE41) + return cpu_t::sse41; + if (c.hasSSSE3) + return cpu_t::ssse3; + if (c.hasSSE3) + return cpu_t::sse3; + if (c.hasSSE2) + return cpu_t::sse2; + return cpu_t::lowest; +} +} // namespace internal_generic +#else + +template +cpu_t detect_cpu() +{ + return cpu_t::native; +} + +#endif +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid_auto.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid_auto.hpp new file mode 100644 index 00000000..b359c877 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/runtime/cpuid_auto.hpp @@ -0,0 +1,69 @@ +/** @addtogroup cpuid + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "cpuid.hpp" + +namespace kfr +{ + +namespace internal_generic +{ + +KFR_INTRINSIC cpu_t& cpu_v() +{ + static cpu_t v1 = cpu_t::native; + return v1; +} + +KFR_INTRINSIC char init_cpu_v() +{ + cpu_v() = detect_cpu<0>(); + return 0; +} + +KFR_INTRINSIC char init_dummyvar() +{ + static char dummy = init_cpu_v(); + return dummy; +} + +static char dummyvar = init_dummyvar(); +} // namespace internal_generic + +/** + * @brief Returns cpu instruction set detected at runtime. + */ +inline cpu_t get_cpu() { return internal_generic::cpu_v(); } + +inline cpu_t override_cpu(cpu_t cpu) +{ + cpu_t previous = internal_generic::cpu_v(); + internal_generic::cpu_v() = cpu; + return previous; +} + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd.hpp new file mode 100644 index 00000000..7a66882f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd.hpp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "simd/abs.hpp" +#include "simd/clamp.hpp" +#include "simd/comparison.hpp" +#include "simd/complex.hpp" +#include "simd/complex_type.hpp" +#include "simd/constants.hpp" +#include "simd/digitreverse.hpp" +#include "simd/horizontal.hpp" +#include "simd/logical.hpp" +#include "simd/mask.hpp" +#include "simd/min_max.hpp" +#include "simd/operators.hpp" +#include "simd/platform.hpp" +#include "simd/read_write.hpp" +#include "simd/round.hpp" +#include "simd/saturation.hpp" +#include "simd/select.hpp" +#include "simd/shuffle.hpp" +#include "simd/sort.hpp" +#include "simd/types.hpp" +#include "simd/vec.hpp" diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/abs.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/abs.hpp new file mode 100644 index 00000000..f668e691 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/abs.hpp @@ -0,0 +1,45 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/abs.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the absolute value of x. + */ +template )> +KFR_INTRINSIC T1 abs(const T1& x) +{ + return intrinsics::abs(x); +} +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/clamp.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/clamp.hpp new file mode 100644 index 00000000..da80be15 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/clamp.hpp @@ -0,0 +1,51 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/clamp.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Returns the first argument clamped to a range [lo, hi] +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout clamp(const T1& x, const T2& lo, const T3& hi) +{ + return intrinsics::clamp(static_cast(x), static_cast(lo), static_cast(hi)); +} + +/// @brief Returns the first argument clamped to a range [0, hi] +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout clamp(const T1& x, const T2& hi) +{ + return intrinsics::clamp(static_cast(x), static_cast(hi)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/comparison.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/comparison.hpp new file mode 100644 index 00000000..573090c8 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/comparison.hpp @@ -0,0 +1,116 @@ +/** @addtogroup logical + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "constants.hpp" +#include "impl/function.hpp" +#include "vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +inline maskfor> equal(const T1& x, const T2& y) +{ + return x == y; +} +template +inline maskfor> notequal(const T1& x, const T2& y) +{ + return x != y; +} +template +inline maskfor> less(const T1& x, const T2& y) +{ + return x < y; +} +template +inline maskfor> greater(const T1& x, const T2& y) +{ + return x > y; +} +template +inline maskfor> lessorequal(const T1& x, const T2& y) +{ + return x <= y; +} +template +inline maskfor> greaterorequal(const T1& x, const T2& y) +{ + return x >= y; +} +KFR_FN(equal) +KFR_FN(notequal) +KFR_FN(less) +KFR_FN(greater) +KFR_FN(lessorequal) +KFR_FN(greaterorequal) + +template +KFR_INTRINSIC mask isnan(const vec& x) +{ + return x != x; +} + +template +KFR_INTRINSIC mask isinf(const vec& x) +{ + return x == constants::infinity || x == -constants::infinity; +} + +template +KFR_INTRINSIC mask isfinite(const vec& x) +{ + return !isnan(x) && !isinf(x); +} + +template +KFR_INTRINSIC mask isnegative(const vec& x) +{ + return (x & special_constants::highbitmask()) != 0; +} + +template +KFR_INTRINSIC mask ispositive(const vec& x) +{ + return !isnegative(x); +} + +template +KFR_INTRINSIC mask iszero(const vec& x) +{ + return x == T(); +} + +template +KFR_INTRINSIC maskfor> inrange(const T1& x, const T2& min, const T3& max) +{ + return x >= min && x <= max; +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex.hpp new file mode 100644 index 00000000..db0ebfff --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex.hpp @@ -0,0 +1,348 @@ +/** @addtogroup complex + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "constants.hpp" +#include "impl/function.hpp" +#include "operators.hpp" +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4814)) + +namespace kfr +{ + +} // namespace kfr +namespace cometa +{ +template +struct compound_type_traits> +{ + constexpr static size_t width = 2; + constexpr static size_t deep_width = width * compound_type_traits::width; + using subtype = T; + using deep_subtype = cometa::deep_subtype; + constexpr static bool is_scalar = false; + constexpr static size_t depth = cometa::compound_type_traits::depth + 1; + template + using rebind = std::complex; + template + using deep_rebind = std::complex::template deep_rebind>; + + static constexpr subtype at(const std::complex& value, size_t index) + { + return index == 0 ? value.real() : value.imag(); + } +}; +} // namespace cometa +namespace kfr +{ + +/// @brief Alias for complex +using c32 = complex; + +/// @brief Alias for complex +using c64 = complex; + +/// @brief Alias for complex +using cbase = complex; + +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ +template +constexpr inline complex vcomplex(const vec& v) +{ + return complex(v.front(), v.back()); +} +template +constexpr inline vec vcomplex(const complex& v) +{ + return vec(v.real(), v.imag()); +} +template +constexpr inline simd vvcomplex(const complex& v) +{ + return intrinsics::simd_make(cometa::ctype, v.real(), v.imag()); +} +} // namespace intrinsics + +template +KFR_INTRINSIC vec, sizeof...(indices)> shufflevector(const vec, N>& x, + csizes_t) CMT_NOEXCEPT +{ + return intrinsics::simd_shuffle(intrinsics::simd_t, N>{}, x.v, scale<2, indices...>(), + overload_auto); +} +template +KFR_INTRINSIC vec, sizeof...(indices)> shufflevectors(const vec, N>& x, + const vec& y, + csizes_t) CMT_NOEXCEPT +{ + return intrinsics::simd_shuffle(intrinsics::simd2_t, N, N>{}, x.v, y.v, + scale<2, indices...>(), overload_auto); +} +namespace internal +{ +template +struct compoundcast> +{ + static vec to_flat(const complex& x) { return { x.real(), x.imag() }; } + static complex from_flat(const vec& x) { return { x.front(), x.back() }; } +}; + +template +struct compoundcast, N>> +{ + static vec to_flat(const vec, N>& x) { return x.flatten(); } + static vec, N / 2> from_flat(const vec& x) + { + return vec, N / 2>::from_flatten(x); + } +}; +} // namespace internal + +template +constexpr KFR_INTRINSIC vec, N / 2> ccomp(const vec& x) +{ + return vec, N / 2>::from_flatten(x); +} + +template +constexpr KFR_INTRINSIC vec cdecom(const vec, N>& x) +{ + return x.flatten(); +} + +/// @brief Returns vector of complex values with real part duplicated +template +KFR_INTRINSIC vec, N> cdupreal(const vec, N>& x) +{ + return ccomp(dupeven(cdecom(x))); +} +KFR_FN(cdupreal) + +/// @brief Returns vector of complex values with imaginary part duplicated +template +KFR_INTRINSIC vec, N> cdupimag(const vec, N>& x) +{ + return ccomp(dupodd(cdecom(x))); +} +KFR_FN(cdupimag) + +/// @brief Returns vector of complex values with real and imaginary parts swapped +template +KFR_INTRINSIC vec, N> cswapreim(const vec, N>& x) +{ + return ccomp(swap<2>(cdecom(x))); +} +KFR_FN(cswapreim) + +/// @brief Returns vector of complex values with real part negated +template +KFR_INTRINSIC vec, N> cnegreal(const vec, N>& x) +{ + return x ^ complex(-T(), T()); +} +KFR_FN(cnegreal) + +/// @brief Returns vector of complex values with imaginary part negated +template +KFR_INTRINSIC vec, N> cnegimag(const vec, N>& x) +{ + return x ^ complex(T(), -T()); +} +KFR_FN(cnegimag) + +/// @brief Returns mask with true for real elements +template +KFR_INTRINSIC bool isreal(const complex& x) +{ + return x.imag() == 0; +} +KFR_FN(isreal) + +namespace internal +{ +template +struct is_complex_impl : std::false_type +{ +}; +template +struct is_complex_impl> : std::true_type +{ +}; + +// vector to vector +template +struct conversion<1, 1, vec, N>, vec, N>, conv> +{ + static_assert(!is_compound_type, ""); + static_assert(!is_compound_type, ""); + static vec, N> cast(const vec, N>& value) + { + return vec(value.flatten()).v; + } +}; + +// vector to vector +template +struct conversion<1, 1, vec, N>, vec, conv> +{ + static_assert(!is_compound_type, ""); + static_assert(!is_compound_type, ""); + static vec, N> cast(const vec& value) + { + const vec casted = static_cast>(value); + return interleave(casted, zerovector(casted)).v; + } +}; + +} // namespace internal + +/// @brief Returns the real part of the complex value +template )> +constexpr KFR_INTRINSIC T real(const T& value) +{ + return value; +} + +/// @brief Returns the real part of the complex value +template +constexpr KFR_INTRINSIC T real(const complex& value) +{ + return value.real(); +} + +/// @brief Returns the real part of the complex value +template +constexpr KFR_INTRINSIC vec real(const vec, N>& value) +{ + return even(cdecom(value)); +} + +template +using realtype = decltype(kfr::real(std::declval())); +template +using realftype = ftype()))>; + +KFR_FN(real) + +/// @brief Returns the imaginary part of the complex value +template +constexpr KFR_INTRINSIC T imag(const complex& value) +{ + return value.imag(); +} + +/// @brief Returns the imaginary part of the complex value +template +constexpr KFR_INTRINSIC vec imag(const vec, N>& value) +{ + return odd(cdecom(value)); +} +KFR_FN(imag) + +/// @brief Constructs complex value from real and imaginary parts +template > +constexpr KFR_INTRINSIC vec, N> make_complex(const vec& real, + const vec& imag = T2(0)) +{ + return ccomp(interleave(promoteto(real), promoteto(imag))); +} + +/// @brief Constructs complex value from real and imaginary parts +template , + KFR_ENABLE_IF(is_numeric_args)> +constexpr KFR_INTRINSIC complex make_complex(T1 real, T2 imag = T2(0)) +{ + return complex(promoteto(real), promoteto(imag)); +} +KFR_FN(make_complex) + +namespace intrinsics +{ +template +KFR_INTRINSIC vec, N> cconj(const vec, N>& x) +{ + return cnegimag(x); +} + +KFR_HANDLE_SCALAR(cconj) +} // namespace intrinsics +KFR_I_FN(cconj) + +/// @brief Returns the complex conjugate of the complex number x +template )> +KFR_INTRINSIC T1 cconj(const T1& x) +{ + return intrinsics::cconj(x); +} + +template +struct vec_of_complex +{ + template + using type = vec, N>; +}; +} // namespace CMT_ARCH_NAME + +template +constexpr bool is_complex = internal::is_complex_impl::value; + +} // namespace kfr + +namespace std +{ + +template +struct common_type, kfr::complex> + : kfr::construct_common_type, kfr::complex> +{ +}; +template +struct common_type, T2> : kfr::construct_common_type, kfr::complex> +{ +}; +template +struct common_type> : kfr::construct_common_type, kfr::complex> +{ +}; +template +struct common_type, kfr::vec> + : kfr::construct_common_type, kfr::vec_of_complex::template type> +{ +}; +template +struct common_type, kfr::complex> + : kfr::construct_common_type, kfr::vec_of_complex::template type> +{ +}; +} // namespace std + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex_type.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex_type.hpp new file mode 100644 index 00000000..5566dafd --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/complex_type.hpp @@ -0,0 +1,64 @@ +/** @addtogroup complex + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../cometa/string.hpp" +#include "constants.hpp" + +#include + +namespace kfr +{ +#ifndef KFR_CUSTOM_COMPLEX +template +using complex = std::complex; +#endif + +} // namespace kfr + +namespace cometa +{ +template +struct representation> +{ + using type = std::string; + static std::string get(const kfr::complex& value) + { + return as_string(value.real()) + " + " + as_string(value.imag()) + "j"; + } +}; + +template +struct representation, t, width, prec>> +{ + using type = std::string; + static std::string get(const fmt_t, t, width, prec>& value) + { + return as_string(cometa::fmt(value.value.real())) + " + " + + as_string(cometa::fmt(value.value.imag())) + "j"; + } +}; +} // namespace cometa diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/constants.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/constants.hpp new file mode 100644 index 00000000..ff4fc619 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/constants.hpp @@ -0,0 +1,163 @@ +/** @addtogroup constants + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "types.hpp" +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4309)) +CMT_PRAGMA_MSVC(warning(disable : 4146)) + +namespace kfr +{ + +#if CMT_COMPILER_GNU +constexpr double infinity = __builtin_inf(); +constexpr double qnan = __builtin_nan(""); +#else +constexpr double infinity = HUGE_VAL; +constexpr double qnan = NAN; +#endif +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Woverflow") + +template +struct scalar_constants +{ + constexpr static T pi_s(int m, int d = 1) { return pi * m / d; } + constexpr static T recip_pi_s(int m, int d = 1) { return recip_pi * m / d; } + + constexpr static T pi = static_cast(3.1415926535897932384626433832795); + constexpr static T sqr_pi = static_cast(9.8696044010893586188344909998762); + constexpr static T recip_pi = static_cast(0.31830988618379067153776752674503); + constexpr static T degtorad = static_cast(pi / 180); + constexpr static T radtodeg = static_cast(pi * 180); + constexpr static T e = static_cast(2.718281828459045235360287471352662); + constexpr static T recip_log_2 = static_cast(1.442695040888963407359924681001892137426645954); + constexpr static T recip_log_10 = static_cast(0.43429448190325182765112891891661); + constexpr static T log_2 = static_cast(0.69314718055994530941723212145818); + constexpr static T log_10 = static_cast(2.3025850929940456840179914546844); + constexpr static T sqrt_2 = static_cast(1.4142135623730950488016887242097); + + constexpr static T fold_constant_div = choose_const( + CMT_FP(0x1.921fb6p-1f, 7.8539818525e-01f), CMT_FP(0x1.921fb54442d18p-1, 7.853981633974482790e-01)); + + constexpr static T fold_constant_hi = choose_const( + CMT_FP(0x1.922000p-1f, 7.8540039062e-01f), CMT_FP(0x1.921fb40000000p-1, 7.853981256484985352e-01)); + constexpr static T fold_constant_rem1 = + choose_const(CMT_FP(-0x1.2ae000p-19f, -2.2267922759e-06f), + CMT_FP(0x1.4442d00000000p-25, 3.774894707930798177e-08)); + constexpr static T fold_constant_rem2 = + choose_const(CMT_FP(-0x1.de973ep-32f, -4.3527578764e-10f), + CMT_FP(0x1.8469898cc5170p-49, 2.695151429079059484e-15)); + + constexpr static T epsilon = std::numeric_limits::epsilon(); + constexpr static T infinity = std::numeric_limits::infinity(); + constexpr static T neginfinity = -std::numeric_limits::infinity(); + constexpr static T qnan = std::numeric_limits::quiet_NaN(); +}; + +template +struct constants : public scalar_constants> +{ +public: + using Tsub = subtype; +}; + +template +constexpr inline size_t force_compiletime_size_t = Value; + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +/// π (pi) +/// c_pi = 4pi +/// c_pi = 3/4pi +template +constexpr inline subtype c_pi = subtype(3.1415926535897932384626433832795 * m / d); + +/// π² (pi²) +/// c_sqr_pi = 4pi² +/// c_sqr_pi = 3/4pi² +template +constexpr inline subtype c_sqr_pi = subtype(9.8696044010893586188344909998762 * m / d); + +/// 1/π (1/pi) +/// c_recip_pi 1/pi +/// c_recip_pi 4/pi +template +constexpr inline subtype c_recip_pi = subtype(0.31830988618379067153776752674503 * m / d); + +/// degree to radian conversion factor +template +constexpr inline subtype c_degtorad = c_pi; + +/// radian to degree conversion factor +template +constexpr inline subtype c_radtodeg = c_recip_pi; + +/// e, Euler's number +template +constexpr inline subtype c_e = subtype(2.718281828459045235360287471352662 * m / d); + +template +constexpr inline unsigned c_mantissa_bits = sizeof(subtype) == 32 ? 23 : 52; + +template +constexpr inline subtype c_mantissa_mask = (subtype(1) << c_mantissa_bits)-1; + +template +constexpr inline subtype c_epsilon = (std::numeric_limits>::epsilon()); + +/// infinity +template +constexpr inline subtype c_infinity = std::numeric_limits>::infinity(); + +/// -infinity +template +constexpr inline subtype c_neginfinity = -std::numeric_limits>::infinity(); + +/// Quiet NaN +template +constexpr inline subtype c_qnan = std::numeric_limits>::quiet_NaN(); + +template +constexpr inline subtype c_recip_log_2 = subtype(1.442695040888963407359924681001892137426645954); + +template +constexpr inline subtype c_recip_log_10 = subtype(0.43429448190325182765112891891661); + +template +constexpr inline subtype c_log_2 = subtype(0.69314718055994530941723212145818); + +template +constexpr inline subtype c_log_10 = subtype(2.3025850929940456840179914546844); + +template +constexpr inline subtype c_sqrt_2 = subtype(1.4142135623730950488016887242097 * m / d); +} // namespace kfr + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/digitreverse.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/digitreverse.hpp new file mode 100644 index 00000000..31d099a3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/digitreverse.hpp @@ -0,0 +1,118 @@ +/** @addtogroup shuffle + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "shuffle.hpp" +#include "types.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace internal +{ + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshift-count-overflow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshift-count-negative") + +constexpr KFR_INTRINSIC u32 bit_permute_step_impl(u32 x, cvals_t) { return x; } + +template +constexpr KFR_INTRINSIC u32 bit_permute_step_impl(u32 x, cvals_t) +{ + return bit_permute_step_impl(((x & m) << shift) | ((x >> shift) & m), cvals_t()); +} + +template +constexpr KFR_INTRINSIC u32 digitreverse_impl(u32 x, csize_t<2>) +{ + constexpr cvals_t + steps{}; + if constexpr (bits > 16) + return bit_permute_step_impl(x, steps) >> (32 - bits); + else if constexpr (bits > 8) + return bit_permute_step_impl(x, steps[csizeseq<8>]) >> (16 - bits); + else + return bit_permute_step_impl(x, steps[csizeseq<6>]) >> (8 - bits); +} + +template +constexpr KFR_INTRINSIC u32 digitreverse_impl(u32 x, csize_t<4>) +{ + constexpr cvals_t steps{}; + if constexpr (bits > 16) + return bit_permute_step_impl(x, steps) >> (32 - bits); + else if constexpr (bits > 8) + return bit_permute_step_impl(x, steps[csizeseq<6>]) >> (16 - bits); + else + return bit_permute_step_impl(x, steps[csizeseq<4>]) >> (8 - bits); +} + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +template +struct shuffle_index_digitreverse +{ + constexpr KFR_INTRINSIC size_t operator()(size_t index) const CMT_NOEXCEPT + { + return digitreverse_impl(static_cast(index), csize_t()); + } +}; +} // namespace internal + +template +KFR_INTRINSIC vec digitreverse(const vec& x) +{ + return x.shuffle(scale( + csizeseq.map(internal::shuffle_index_digitreverse()))); +} + +template +KFR_INTRINSIC vec bitreverse(const vec& x) +{ + return digitreverse<2, groupsize>(x); +} + +template +KFR_INTRINSIC vec digitreverse4(const vec& x) +{ + return digitreverse<4, groupsize>(x); +} + +template +constexpr KFR_INTRINSIC u32 bitreverse(u32 x) +{ + return internal::digitreverse_impl(x, csize_t<2>()); +} + +template +constexpr KFR_INTRINSIC u32 digitreverse4(u32 x) +{ + return internal::digitreverse_impl(x, csize_t<4>()); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/horizontal.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/horizontal.hpp new file mode 100644 index 00000000..719ba3a0 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/horizontal.hpp @@ -0,0 +1,155 @@ +/** @addtogroup horizontal + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "operators.hpp" +#include "min_max.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC T horizontal_impl(const vec& value, ReduceFn&&) +{ + return T(value.front()); +} + +template 1 && is_poweroftwo(N))> +KFR_INTRINSIC T horizontal_impl(const vec& value, ReduceFn&& reduce) +{ + return horizontal_impl(reduce(low(value), high(value)), std::forward(reduce)); +} +template 1 && !is_poweroftwo(N))> +KFR_INTRINSIC T horizontal_impl(const vec& value, ReduceFn&& reduce) +{ + const T initial = reduce(initialvalue()); + return horizontal_impl(widen(value, initial), std::forward(reduce)); +} +} // namespace intrinsics + +template +KFR_INTRINSIC T horizontal(const vec& value, ReduceFn&& reduce) +{ + return intrinsics::horizontal_impl(value, std::forward(reduce)); +} + +/// @brief Sum all elements of the vector +template +KFR_INTRINSIC T hadd(const vec& value) +{ + return horizontal(value, fn::add()); +} +KFR_FN(hadd) + +/// @brief Sum all elements of the vector +template +KFR_INTRINSIC T hsum(const vec& value) +{ + return horizontal(value, fn::add()); +} +KFR_FN(hsum) + +/// @brief Multiply all elements of the vector +template +KFR_INTRINSIC T hmul(const vec& value) +{ + return horizontal(value, fn::mul()); +} +KFR_FN(hmul) + +/// @brief Multiply all elements of the vector +template +KFR_INTRINSIC T hproduct(const vec& value) +{ + return horizontal(value, fn::mul()); +} +KFR_FN(hproduct) + +template +KFR_INTRINSIC T hbitwiseand(const vec& value) +{ + return horizontal(value, fn::bitwiseand()); +} +KFR_FN(hbitwiseand) +template +KFR_INTRINSIC T hbitwiseor(const vec& value) +{ + return horizontal(value, fn::bitwiseor()); +} +KFR_FN(hbitwiseor) +template +KFR_INTRINSIC T hbitwisexor(const vec& value) +{ + return horizontal(value, fn::bitwisexor()); +} +KFR_FN(hbitwisexor) + +/// @brief Calculate the Dot-Product of two vectors +template +KFR_INTRINSIC T hdot(const vec& x, const vec& y) +{ + return hadd(x * y); +} +KFR_FN(hdot) + +/// @brief Calculate the Arithmetic mean of all elements in the vector +template +KFR_INTRINSIC T havg(const vec& value) +{ + return hadd(value) / N; +} +KFR_FN(havg) + +/// @brief Calculate the RMS of all elements in the vector +template +KFR_INTRINSIC T hrms(const vec& value) +{ + return builtin_sqrt(hadd(value * value) / N); +} +KFR_FN(hrms) + +/// @brief Calculate the minimum of all elements in the vector +template +KFR_INTRINSIC T hmin(const vec& value) +{ + return horizontal(value, fn::min()); +} +KFR_FN(hmin) + +/// @brief Calculate the maximum of all elements in the vector +template +KFR_INTRINSIC T hmax(const vec& value) +{ + return horizontal(value, fn::max()); +} +KFR_FN(hmax) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/abs.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/abs.hpp new file mode 100644 index 00000000..cd48524f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/abs.hpp @@ -0,0 +1,138 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../operators.hpp" +#include "../select.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#if defined CMT_ARCH_SSSE3 && defined KFR_NATIVE_INTRINSICS + +// floating point +template )> +KFR_INTRINSIC vec abs(const vec& x) CMT_NOEXCEPT +{ + return x & special_constants::invhighbitmask(); +} + +KFR_INTRINSIC i64sse abs(const i64sse& x) CMT_NOEXCEPT +{ + const __m128i sh = _mm_srai_epi32(x.v, 31); + const __m128i msk = _mm_shuffle_epi32(sh, _MM_SHUFFLE(3, 3, 1, 1)); + return _mm_sub_epi64(_mm_xor_si128(x.v, msk), msk); +} +KFR_INTRINSIC i32sse abs(const i32sse& x) CMT_NOEXCEPT { return _mm_abs_epi32(x.v); } +KFR_INTRINSIC i16sse abs(const i16sse& x) CMT_NOEXCEPT { return _mm_abs_epi16(x.v); } +KFR_INTRINSIC i8sse abs(const i8sse& x) CMT_NOEXCEPT { return _mm_abs_epi8(x.v); } +KFR_INTRINSIC u64sse abs(const u64sse& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u32sse abs(const u32sse& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u16sse abs(const u16sse& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u8sse abs(const u8sse& x) CMT_NOEXCEPT { return x; } + +#if defined CMT_ARCH_AVX2 +KFR_INTRINSIC i64avx abs(const i64avx& x) CMT_NOEXCEPT +{ + const __m256i sh = _mm256_srai_epi32(x.v, 31); + const __m256i msk = _mm256_shuffle_epi32(sh, _MM_SHUFFLE(3, 3, 1, 1)); + return _mm256_sub_epi64(_mm256_xor_si256(x.v, msk), msk); +} +KFR_INTRINSIC i32avx abs(const i32avx& x) CMT_NOEXCEPT { return _mm256_abs_epi32(x.v); } +KFR_INTRINSIC i16avx abs(const i16avx& x) CMT_NOEXCEPT { return _mm256_abs_epi16(x.v); } +KFR_INTRINSIC i8avx abs(const i8avx& x) CMT_NOEXCEPT { return _mm256_abs_epi8(x.v); } +KFR_INTRINSIC u64avx abs(const u64avx& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u32avx abs(const u32avx& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u16avx abs(const u16avx& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u8avx abs(const u8avx& x) CMT_NOEXCEPT { return x; } +#endif + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC i64avx512 abs(const i64avx512& x) CMT_NOEXCEPT { return _mm512_abs_epi64(x.v); } +KFR_INTRINSIC i32avx512 abs(const i32avx512& x) CMT_NOEXCEPT { return _mm512_abs_epi32(x.v); } +KFR_INTRINSIC i16avx512 abs(const i16avx512& x) CMT_NOEXCEPT { return _mm512_abs_epi16(x.v); } +KFR_INTRINSIC i8avx512 abs(const i8avx512& x) CMT_NOEXCEPT { return _mm512_abs_epi8(x.v); } +KFR_INTRINSIC u64avx512 abs(const u64avx512& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u32avx512 abs(const u32avx512& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u16avx512 abs(const u16avx512& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u8avx512 abs(const u8avx512& x) CMT_NOEXCEPT { return x; } +#endif + +KFR_HANDLE_ALL_SIZES_1_IF(abs, !is_f_class) + +#elif defined CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC i8neon abs(const i8neon& x) CMT_NOEXCEPT { return vabsq_s8(x.v); } +KFR_INTRINSIC i16neon abs(const i16neon& x) CMT_NOEXCEPT { return vabsq_s16(x.v); } +KFR_INTRINSIC i32neon abs(const i32neon& x) CMT_NOEXCEPT { return vabsq_s32(x.v); } +#if defined CMT_ARCH_NEON64 +KFR_INTRINSIC i64neon abs(const i64neon& x) CMT_NOEXCEPT { return vabsq_s64(x.v); } +#else +KFR_INTRINSIC i64neon abs(const i64neon& x) CMT_NOEXCEPT { return select(x >= 0, x, -x); } +#endif + +KFR_INTRINSIC u8neon abs(const u8neon& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u16neon abs(const u16neon& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u32neon abs(const u32neon& x) CMT_NOEXCEPT { return x; } +KFR_INTRINSIC u64neon abs(const u64neon& x) CMT_NOEXCEPT { return x; } + +KFR_INTRINSIC f32neon abs(const f32neon& x) CMT_NOEXCEPT { return vabsq_f32(x.v); } +#if defined CMT_ARCH_NEON64 +KFR_INTRINSIC f64neon abs(const f64neon& x) CMT_NOEXCEPT { return vabsq_f64(x.v); } +#else +KFR_INTRINSIC f64neon abs(const f64neon& x) CMT_NOEXCEPT +{ + return x & special_constants::invhighbitmask(); +} +#endif + +KFR_HANDLE_ALL_SIZES_1(abs) + +#else + +// floating point +template )> +KFR_INTRINSIC vec abs(const vec& x) CMT_NOEXCEPT +{ + return x & special_constants::invhighbitmask(); +} + +// fallback +template )> +KFR_INTRINSIC vec abs(const vec& x) CMT_NOEXCEPT +{ + return select(x >= T(0), x, -x); +} +#endif +KFR_HANDLE_SCALAR(abs) +} // namespace intrinsics + +KFR_I_FN(abs) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend.hpp new file mode 100644 index 00000000..d3a612ea --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend.hpp @@ -0,0 +1,79 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "simd.hpp" +#ifdef CMT_CLANG_EXT +#include "backend_clang.hpp" +#else +#include "backend_generic.hpp" +#endif + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#ifdef KFR_AUTOTESTS +template +struct check_sizes +{ + static_assert(sizeof(simd) == sizeof(T), ""); + static_assert(sizeof(simd) == sizeof(T) * 2, ""); + static_assert(sizeof(simd) == sizeof(T) * 4, ""); + static_assert(sizeof(simd) == sizeof(T) * 4, ""); + static_assert(sizeof(simd) == sizeof(T) * 8, ""); + static_assert(sizeof(simd) == sizeof(T) * 8, ""); + static_assert(sizeof(simd) == sizeof(T) * 8, ""); + static_assert(sizeof(simd) == sizeof(T) * 8, ""); + static_assert(sizeof(simd) == sizeof(T) * 16, ""); + static_assert(sizeof(simd) == sizeof(T) * 32, ""); + static_assert(sizeof(simd) == sizeof(T) * 64, ""); + static_assert(sizeof(simd) == sizeof(T) * 128, ""); + static_assert(sizeof(simd) == sizeof(T) * 256, ""); + static_assert(sizeof(simd) == sizeof(T) * 512, ""); + static_assert(sizeof(simd) == sizeof(T) * 1024, ""); + static_assert(sizeof(simd) == sizeof(T) * 1024, ""); + static_assert(sizeof(simd) == sizeof(T) * 1024, ""); +}; + +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; +template struct check_sizes; + +#endif +} // namespace intrinsics +} // namespace CMT_ARCH_NAME + +using CMT_ARCH_NAME::intrinsics::simd; +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_clang.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_clang.hpp new file mode 100644 index 00000000..41285463 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_clang.hpp @@ -0,0 +1,195 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "simd.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wc99-extensions") + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +using simd = unwrap_bit __attribute__((ext_vector_type(NN))); + +template +KFR_INTRINSIC simd simd_concat(const simd& x); + +template )> +KFR_INTRINSIC simd simd_concat(const simd& x, const simd& y, + const simd&... z); + +template +KFR_INTRINSIC void simd_make(ctype_t) = delete; + +template +KFR_INTRINSIC simd simd_make(ctype_t, const Arg& arg) +{ + return (simd){ unwrap_bit_value(arg) }; +} + +template 1)> +KFR_INTRINSIC simd simd_make(ctype_t, const Args&... args) +{ + return (simd){ unwrap_bit_value(args)... }; +} + +// @brief Returns vector with undefined value +template +KFR_INTRINSIC simd simd_undefined() +{ + simd x; + return x; +} + +// @brief Returns vector with all zeros +template +KFR_INTRINSIC simd simd_zeros() +{ + return Tout(); +} + +// @brief Returns vector with all ones +template +KFR_INTRINSIC simd simd_allones() +{ + return unwrap_bit_value(special_constants::allones()); +} + +// @brief Converts input vector to vector with subtype Tout +template +KFR_INTRINSIC simd simd_bitcast(simd_cvt_t, const simd& x) +{ + return (simd)x; +} + +template +KFR_INTRINSIC simd simd_bitcast(simd_cvt_t, const simd& x) +{ + return x; +} + +template +KFR_INTRINSIC T simd_get_element(const simd& value, csize_t) +{ + return wrap_bit_value(value[index]); +} + +template +KFR_INTRINSIC simd simd_set_element(simd value, csize_t, T x) +{ + value[index] = unwrap_bit_value(x); + return value; +} + +template +KFR_INTRINSIC simd simd_broadcast(simd_t, identity value) +{ + return unwrap_bit_value(value); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, csizes_t, + overload_generic) +{ + return __builtin_shufflevector(x, x, (indices > N ? -1 : static_cast(indices))...); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, const simd& y, + csizes_t, overload_generic) +{ + static_assert(N == N2, ""); + return __builtin_shufflevector(x, y, (indices > 2 * N ? -1 : static_cast(indices))...); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, const simd& y, + csizes_t, overload_generic) +{ + constexpr size_t Nmax = (N1 > N2 ? N1 : N2); + return simd_shuffle(simd2_t{}, + simd_shuffle(simd_t{}, x, csizeseq, overload_auto), + simd_shuffle(simd_t{}, y, csizeseq, overload_auto), + csizes<(indices < N1 ? indices + : indices < N1 + N2 ? indices + (Nmax - N1) + : index_undefined)...>, + overload_auto); +} + +template +KFR_INTRINSIC simd simd_concat(const simd& x) +{ + return x; +} + +template )*/> +KFR_INTRINSIC simd simd_concat(const simd& x, const simd& y, + const simd&... z) +{ + return simd_shuffle(simd2_t{}, x, simd_concat(y, z...), + csizeseq, overload_auto); +} + +// @brief Converts input vector to vector with subtype Tout +template +KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) +{ + return __builtin_convertvector(x, simd); +} + +// @brief Converts input vector to vector with subtype Tout +template +KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) +{ + return x; +} + +template +using simd_storage = struct_with_alignment, A>; + +template +KFR_INTRINSIC T simd_get_element(const simd& value, size_t index) +{ + return wrap_bit_value(value[index]); +} + +template +KFR_INTRINSIC simd simd_set_element(simd value, size_t index, T x) +{ + value[index] = unwrap_bit_value(x); + return value; +} +} // namespace intrinsics +} // namespace CMT_ARCH_NAME + +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_generic.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_generic.hpp new file mode 100644 index 00000000..1a21f551 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/backend_generic.hpp @@ -0,0 +1,1944 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#ifndef CMT_CLANG_EXT + +#include "simd.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wuninitialized") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpragmas") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wunknown-warning-option") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wmaybe-uninitialized") + +namespace kfr +{ +template +struct shuffle_mask; + +template +struct shuffle_mask<8, i0, i1, i2, i3, i4, i5, i6, i7> +{ + constexpr static inline size_t Nmax = 1; + constexpr static inline size_t value = (const_min(i7, Nmax) << 7) | (const_min(i6, Nmax) << 6) | + (const_min(i5, Nmax) << 5) | (const_min(i4, Nmax) << 4) | + (const_min(i3, Nmax) << 3) | (const_min(i2, Nmax) << 2) | + (const_min(i1, Nmax) << 1) | const_min(i0, Nmax); +}; + +template +struct shuffle_mask<8, i0, i1, i2, i3> +{ + constexpr static inline size_t Nmax = 3; + constexpr static inline size_t value = (const_min(i3, Nmax) << 6) | (const_min(i2, Nmax) << 4) | + (const_min(i1, Nmax) << 2) | const_min(i0, Nmax); +}; + +template +struct shuffle_mask<4, i0, i1, i2, i3> +{ + constexpr static inline size_t Nmax = 1; + constexpr static inline size_t value = (const_min(i3, Nmax) << 3) | (const_min(i2, Nmax) << 2) | + (const_min(i1, Nmax) << 1) | const_min(i0, Nmax); +}; + +template +struct shuffle_mask<2, i0, i1> +{ + constexpr static inline size_t Nmax = 1; + constexpr static inline size_t value = (const_min(i1, Nmax) << 1) | const_min(i0, Nmax); +}; + +#if KFR_SHOW_NOT_OPTIMIZED +CMT_PUBLIC_C CMT_DLL_EXPORT void not_optimized(const char* fn) CMT_NOEXCEPT; +#else +#define not_optimized(...) CMT_NOOP +#endif + +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +using simd = typename simd_type, next_poweroftwo(static_cast(N))>::type; + +template +struct simd_small_array +{ + static_assert(is_poweroftwo(N), ""); + static_assert(sizeof(T) * N == sizeof(U), ""); + U whole; + + using value_type = T; + constexpr static size_t size = N; + using packed_type = U; + +#ifdef CMT_COMPILER_IS_MSVC + KFR_INTRINSIC constexpr simd_small_array() CMT_NOEXCEPT = default; +#else + KFR_INTRINSIC simd_small_array() CMT_NOEXCEPT {} +#endif + + KFR_INTRINSIC constexpr simd_small_array(U whole) CMT_NOEXCEPT : whole(whole) {} + + template + KFR_INTRINSIC constexpr simd_small_array(T a, T b, Args... args) CMT_NOEXCEPT + : whole(pack_elements(a, b, args...)) + { + } + + KFR_INTRINSIC static constexpr simd_small_array from(U whole) CMT_NOEXCEPT { return { whole }; } +}; + +template <> +struct simd_small_array +{ + f64 whole; + + using value_type = f32; + constexpr static size_t size = 2; + using packed_type = f64; + +#ifdef CMT_COMPILER_IS_MSVC + KFR_MEM_INTRINSIC constexpr simd_small_array() CMT_NOEXCEPT = default; +#else + KFR_MEM_INTRINSIC simd_small_array() CMT_NOEXCEPT {} +#endif + +#ifdef CMT_COMPILER_IS_MSVC + // MSVC Internal Compiler Error workaround + KFR_MEM_INTRINSIC constexpr simd_small_array(const simd_small_array& v) CMT_NOEXCEPT : whole(v.whole) {} + KFR_MEM_INTRINSIC constexpr simd_small_array(simd_small_array&& v) CMT_NOEXCEPT : whole(v.whole) {} + KFR_MEM_INTRINSIC constexpr simd_small_array& operator=(const simd_small_array& v) CMT_NOEXCEPT + { + whole = v.whole; + return *this; + } + KFR_MEM_INTRINSIC constexpr simd_small_array& operator=(simd_small_array&& v) CMT_NOEXCEPT + { + whole = v.whole; + return *this; + } +#endif + + KFR_MEM_INTRINSIC constexpr simd_small_array(f64 whole) CMT_NOEXCEPT : whole(whole) {} + + KFR_MEM_INTRINSIC simd_small_array(f32 x, f32 y) CMT_NOEXCEPT + { +#ifdef CMT_COMPILER_IS_MSVC +#ifdef CMT_ARCH_SSE2 + // whole = _mm_cvtsd_f64(_mm_castps_pd(_mm_setr_ps(x, y, x, y))); + whole = _mm_cvtsd_f64(_mm_castps_pd(_mm_unpacklo_ps(_mm_set_ss(x), _mm_set_ss(y)))); +#else + union + { + struct + { + f32 x; + f32 y; + }; + f64 r; + } u; + u.x = x; + u.y = y; + whole = u.r; +#endif +#else + union + { + struct + { + f32 x; + f32 y; + }; + f64 r; + } u{ { x, y } }; + whole = u.r; +#endif + } + + KFR_MEM_INTRINSIC static constexpr simd_small_array from(f64 whole) CMT_NOEXCEPT { return { whole }; } +}; + +template +constexpr inline bool is_simd_small_array = false; + +template +constexpr inline bool is_simd_small_array> = true; + +#define KFR_SIMD_TYPE(T, N, ...) \ + template <> \ + struct simd_type \ + { \ + using type = __VA_ARGS__; \ + }; + +#define KFR_SIMD_SMALL_TYPE(T, N, U) \ + template <> \ + struct simd_type \ + { \ + using type = simd_small_array; \ + }; + +template +struct simd_type +{ + using type = T; +}; + +template +struct simd_type +{ + using type = simd_halves; +}; + +KFR_SIMD_SMALL_TYPE(u8, 2, u16) +KFR_SIMD_SMALL_TYPE(i8, 2, u16) + +KFR_SIMD_SMALL_TYPE(u8, 4, u32) +KFR_SIMD_SMALL_TYPE(u16, 2, u32) +KFR_SIMD_SMALL_TYPE(i8, 4, u32) +KFR_SIMD_SMALL_TYPE(i16, 2, u32) + +KFR_SIMD_SMALL_TYPE(u8, 8, u64) +KFR_SIMD_SMALL_TYPE(u16, 4, u64) +KFR_SIMD_SMALL_TYPE(u32, 2, u64) +KFR_SIMD_SMALL_TYPE(i8, 8, u64) +KFR_SIMD_SMALL_TYPE(i16, 4, u64) +KFR_SIMD_SMALL_TYPE(i32, 2, u64) + +#ifdef CMT_ARCH_SSE +#ifndef KFR_f32x2_array +KFR_SIMD_SMALL_TYPE(f32, 2, f64) +#endif + +KFR_SIMD_TYPE(f32, 4, __m128) +KFR_SIMD_TYPE(f64, 2, __m128d) +#endif // CMT_ARCH_SSE + +#ifdef CMT_ARCH_SSE2 +KFR_SIMD_TYPE(u8, 16, __m128i) +KFR_SIMD_TYPE(u16, 8, __m128i) +KFR_SIMD_TYPE(u32, 4, __m128i) +KFR_SIMD_TYPE(u64, 2, __m128i) +KFR_SIMD_TYPE(i8, 16, __m128i) +KFR_SIMD_TYPE(i16, 8, __m128i) +KFR_SIMD_TYPE(i32, 4, __m128i) +KFR_SIMD_TYPE(i64, 2, __m128i) +#endif // CMT_ARCH_SSE2 + +#ifdef CMT_ARCH_AVX +KFR_SIMD_TYPE(float, 8, __m256) +KFR_SIMD_TYPE(double, 4, __m256d) +KFR_SIMD_TYPE(u8, 32, __m256i) +KFR_SIMD_TYPE(u16, 16, __m256i) +KFR_SIMD_TYPE(u32, 8, __m256i) +KFR_SIMD_TYPE(u64, 4, __m256i) +KFR_SIMD_TYPE(i8, 32, __m256i) +KFR_SIMD_TYPE(i16, 16, __m256i) +KFR_SIMD_TYPE(i32, 8, __m256i) +KFR_SIMD_TYPE(i64, 4, __m256i) +#endif // CMT_ARCH_AVX + +#ifdef CMT_ARCH_AVX512 +KFR_SIMD_TYPE(float, 16, __m512) +KFR_SIMD_TYPE(double, 8, __m512d) +KFR_SIMD_TYPE(u8, 64, __m512i) +KFR_SIMD_TYPE(u16, 32, __m512i) +KFR_SIMD_TYPE(u32, 16, __m512i) +KFR_SIMD_TYPE(u64, 8, __m512i) +KFR_SIMD_TYPE(i8, 64, __m512i) +KFR_SIMD_TYPE(i16, 32, __m512i) +KFR_SIMD_TYPE(i32, 16, __m512i) +KFR_SIMD_TYPE(i64, 8, __m512i) +#endif // CMT_ARCH_AVX512 + +#ifdef CMT_ARCH_NEON +KFR_SIMD_TYPE(u8, 16, uint8x16_t); +KFR_SIMD_TYPE(u16, 8, uint16x8_t); +KFR_SIMD_TYPE(u32, 4, uint32x4_t); +KFR_SIMD_TYPE(u64, 2, uint64x2_t); +KFR_SIMD_TYPE(i8, 16, int8x16_t); +KFR_SIMD_TYPE(i16, 8, int16x8_t); +KFR_SIMD_TYPE(i32, 4, int32x4_t); +KFR_SIMD_TYPE(i64, 2, int64x2_t); +KFR_SIMD_TYPE(f32, 4, float32x4_t); +#ifdef CMT_ARCH_NEON64 +KFR_SIMD_TYPE(f64, 2, float64x2_t); +#endif // CMT_ARCH_NEON64 +#endif // CMT_ARCH_NEON + +#if defined CMT_COMPILER_IS_MSVC +#define KFR_i8sse_INDEX(x, i) x.m128i_i8[i] +#define KFR_i16sse_INDEX(x, i) x.m128i_i16[i] +#define KFR_i32sse_INDEX(x, i) x.m128i_i32[i] +#define KFR_i64sse_INDEX(x, i) x.m128i_i64[i] +#define KFR_u8sse_INDEX(x, i) x.m128i_u8[i] +#define KFR_u16sse_INDEX(x, i) x.m128i_u16[i] +#define KFR_u32sse_INDEX(x, i) x.m128i_u32[i] +#define KFR_u64sse_INDEX(x, i) x.m128i_u64[i] +#define KFR_f32sse_INDEX(x, i) x.m128_f32[i] +#define KFR_f64sse_INDEX(x, i) x.m128d_f64[i] +#else +#define KFR_i8sse_INDEX(x, i) bitcast_anything>(x).val[i] +#define KFR_i16sse_INDEX(x, i) bitcast_anything>(x).val[i] +#define KFR_i32sse_INDEX(x, i) _mm_cvtsi128_si32(_mm_shuffle_epi32(x, _MM_SHUFFLE(3, 2, 1, i))) +#define KFR_i64sse_INDEX(x, i) _mm_cvtsi128_si64(_mm_shuffle_epi32(x, _MM_SHUFFLE(3, 2, (i) * 2 + 1, i * 2))) +#define KFR_u8sse_INDEX(x, i) bitcast_anything>(x).val[i] +#define KFR_u16sse_INDEX(x, i) bitcast_anything>(x).val[i] +#define KFR_u32sse_INDEX(x, i) _mm_cvtsi128_si32(_mm_shuffle_epi32(x, _MM_SHUFFLE(3, 2, 1, i))) +#define KFR_u64sse_INDEX(x, i) _mm_cvtsi128_si64(_mm_shuffle_epi32(x, _MM_SHUFFLE(3, 2, (i) * 2 + 1, i * 2))) +#define KFR_f32sse_INDEX(x, i) _mm_cvtss_f32(_mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 2, 1, i))) +#define KFR_f64sse_INDEX(x, i) _mm_cvtsd_f64(_mm_shuffle_pd(x, x, _MM_SHUFFLE2(1, i))) +#endif + +// specializations + +template +KFR_INTRINSIC simd universal_shuffle(simd_t, const simd& x, csizes_t); + +#ifdef KFR_NATIVE_INTRINSICS + +#define KFR_GEN_ty(n, ty) ty(n) +#define KFR_GEN_arg_def(n, ty) ty arg##n +#define KFR_GEN_arg(n, ty) arg##n + +#define KFR_INTRIN_MAKE(n, ty, intrin) \ + KFR_INTRINSIC simd simd_make(ctype_t, CMT_GEN_LIST(n, KFR_GEN_arg_def, ty)) CMT_NOEXCEPT \ + { \ + return intrin(CMT_GEN_LIST(n, KFR_GEN_arg, ty)); \ + } + +#ifdef CMT_ARCH_SSE2 + +KFR_INTRINSIC double take_hi_sd(__m128d x) { return _mm_cvtsd_f64(_mm_unpackhi_pd(x, x)); } + +KFR_INTRINSIC __m128i KFR_mm_setr_epi64x(int64_t q0, int64_t q1) CMT_NOEXCEPT +{ + return _mm_set_epi64x(q1, q0); +} +KFR_INTRINSIC __m128i KFR_mm_setr_epi32(int32_t q0, int32_t q1, int32_t q2, int32_t q3) CMT_NOEXCEPT +{ + return _mm_set_epi32(q3, q2, q1, q0); +} +KFR_INTRIN_MAKE(2, i64, KFR_mm_setr_epi64x) +KFR_INTRIN_MAKE(2, u64, KFR_mm_setr_epi64x) +KFR_INTRIN_MAKE(2, f64, _mm_setr_pd) +KFR_INTRIN_MAKE(4, i32, KFR_mm_setr_epi32) +KFR_INTRIN_MAKE(4, u32, KFR_mm_setr_epi32) +KFR_INTRIN_MAKE(4, f32, _mm_setr_ps) +KFR_INTRIN_MAKE(8, i16, _mm_setr_epi16) +KFR_INTRIN_MAKE(8, u16, _mm_setr_epi16) +KFR_INTRIN_MAKE(16, i8, _mm_setr_epi8) +KFR_INTRIN_MAKE(16, u8, _mm_setr_epi8) + +#define KFR_INTRIN_BITCAST(Tout, Tin, N, ...) \ + KFR_INTRINSIC simd simd_bitcast(simd_cvt_t, const simd& x) CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } +KFR_INTRIN_BITCAST(f32, i32, 4, _mm_castsi128_ps(x)) +KFR_INTRIN_BITCAST(i32, f32, 4, _mm_castps_si128(x)) +KFR_INTRIN_BITCAST(f64, i64, 2, _mm_castsi128_pd(x)) +KFR_INTRIN_BITCAST(i64, f64, 2, _mm_castpd_si128(x)) + +#define KFR_INTRIN_BROADCAST(T, N, ...) \ + KFR_INTRINSIC simd simd_broadcast(simd_t, T value) CMT_NOEXCEPT { return __VA_ARGS__; } + +KFR_INTRIN_BROADCAST(i8, 16, _mm_set1_epi8(value)) +KFR_INTRIN_BROADCAST(i16, 8, _mm_set1_epi16(value)) +KFR_INTRIN_BROADCAST(i32, 4, _mm_set1_epi32(value)) +KFR_INTRIN_BROADCAST(i64, 2, _mm_set1_epi64x(value)) +KFR_INTRIN_BROADCAST(u8, 16, _mm_set1_epi8(value)) +KFR_INTRIN_BROADCAST(u16, 8, _mm_set1_epi16(value)) +KFR_INTRIN_BROADCAST(u32, 4, _mm_set1_epi32(value)) +KFR_INTRIN_BROADCAST(u64, 2, _mm_set1_epi64x(value)) +KFR_INTRIN_BROADCAST(f32, 4, _mm_set1_ps(value)) +KFR_INTRIN_BROADCAST(f64, 2, _mm_set1_pd(value)) + +KFR_INTRIN_BROADCAST(i32, 2, simd(value, value)) +KFR_INTRIN_BROADCAST(u32, 2, simd(value, value)) +KFR_INTRIN_BROADCAST(f32, 2, simd{ value, value }) + +template +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, + csizes_t ind, overload_priority<2>) CMT_NOEXCEPT +{ + return universal_shuffle(simd_t{}, x, ind); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, + csizes_t ind, overload_priority<2>) CMT_NOEXCEPT +{ + return universal_shuffle(simd_t{}, x, ind); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, + const simd& y, csizes_t ind, + overload_priority<2>) CMT_NOEXCEPT +{ + return universal_shuffle(simd_t{}, simd_from_halves(simd_t{}, x, y), ind); +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, + const simd& y, csizes_t ind, + overload_priority<2>) CMT_NOEXCEPT +{ + return universal_shuffle(simd_t{}, simd_from_halves(simd_t{}, x, y), ind); +} + +#define KFR_INTRIN_SHUFFLE_DUPHALVES(T, N, ...) \ + KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, \ + decltype(csizeseq % csize), overload_priority<9>) \ + CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } + +#define KFR_INTRIN_SHUFFLE_SWAP(T, N, ...) \ + KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, \ + decltype(csizeseq ^ csize<1>), overload_priority<9>) \ + CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } + +#define KFR_INTRIN_SHUFFLE_LINEAR(T, Nout, Nin, ...) \ + KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, csizeseq_t, \ + overload_priority<9>) CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } +#define KFR_INTRIN_SHUFFLE_LINEAR_START(T, Nout, Nin, Nstart, ...) \ + KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, \ + csizeseq_t, overload_priority<9>) CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } + +#define KFR_INTRIN_SHUFFLE_CONCAT(T, Nin, ...) \ + KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, \ + const simd& y, csizeseq_t, \ + overload_priority<9>) CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } + +KFR_INTRINSIC __m128 KFR_swap_ps(__m128 x) { return _mm_shuffle_ps(x, x, _MM_SHUFFLE(2, 3, 0, 1)); } + +#ifndef KFR_f32x2_array +// KFR_INTRIN_SHUFFLE_CONCAT(f32, 2, _mm_castpd_ps(_mm_setr_pd(x.whole, y.whole))) +KFR_INTRIN_SHUFFLE_SWAP(f32, 2, + _mm_cvtsd_f64(_mm_castps_pd(KFR_swap_ps(_mm_castpd_ps(_mm_set1_pd(x.whole)))))) +#else +KFR_INTRIN_SHUFFLE_CONCAT(f32, 2, _mm_setr_ps(x.low, x.high, y.low, y.high)) +KFR_INTRIN_SHUFFLE_SWAP(f32, 2, simd{ x.high, x.low }) +#endif + +#if defined CMT_COMPILER_IS_MSVC && defined CMT_ARCH_X32 +KFR_INTRINSIC __m128i _mm_cvtsi64_si128(int64_t u) +{ + __m128i r = _mm_setzero_si128(); + r.m128i_i64[0] = u; + return r; +} +KFR_INTRINSIC int64_t _mm_cvtsi128_si64(const __m128i& i) { return i.m128i_i64[0]; } +KFR_INTRINSIC int64_t _mm_cvttsd_si64(const __m128d& d) { return static_cast(d.m128d_f64[0]); } +KFR_INTRINSIC __m128d _mm_cvtsi64_sd(const __m128d& a, int64_t b) +{ + __m128d r = a; + r.m128d_f64[0] = static_cast(b); + return r; +} +#endif + +KFR_INTRIN_BITCAST(f32, i32, 1, _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(x)))) +KFR_INTRIN_BITCAST(i32, f32, 1, _mm_cvtsi128_si32(_mm_castps_si128(_mm_set_ss(x)))) +KFR_INTRIN_BITCAST(f64, i64, 1, _mm_cvtsd_f64(_mm_castsi128_pd(_mm_cvtsi64_si128(x)))) +KFR_INTRIN_BITCAST(i64, f64, 1, _mm_cvtsi128_si64(_mm_castpd_si128(_mm_set_sd(x)))) + +#ifndef CMT_ARCH_AVX +KFR_INTRIN_SHUFFLE_DUPHALVES(i8, 16, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(u8, 16, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(i16, 8, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(u16, 8, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(i32, 4, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(u32, 4, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(i64, 2, simd{ x, x }) +KFR_INTRIN_SHUFFLE_DUPHALVES(u64, 2, simd{ x, x }) +#endif + +// extend +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16, 1, _mm_cvtsi32_si128(u8(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8, 1, _mm_cvtsi32_si128(u16(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4, 1, _mm_cvtsi32_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2, 1, _mm_cvtsi64_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16, 1, _mm_cvtsi32_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8, 1, _mm_cvtsi32_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4, 1, _mm_cvtsi32_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u64, 2, 1, _mm_cvtsi64_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4, 1, _mm_set_ss(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2, 1, _mm_set_sd(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16, 2, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16, 2, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16, 4, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16, 4, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16, 8, _mm_cvtsi64_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16, 8, _mm_cvtsi64_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8, 2, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8, 2, _mm_cvtsi32_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8, 4, _mm_cvtsi64_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8, 4, _mm_cvtsi64_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4, 2, _mm_cvtsi64_si128(x.whole)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4, 2, _mm_cvtsi64_si128(x.whole)) + +// slice +KFR_INTRIN_SHUFFLE_LINEAR(i32, 1, 4, _mm_cvtsi128_si32(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 1, 4, _mm_cvtsi128_si32(x)) +#if defined CMT_COMPILER_IS_MSVC && _MSC_VER > 1936 +KFR_INTRIN_SHUFFLE_LINEAR(i64, 1, 2, i64(x.m128i_i64[0])) +#else +KFR_INTRIN_SHUFFLE_LINEAR(i64, 1, 2, _mm_cvtsi128_si64(x)) +#endif +KFR_INTRIN_SHUFFLE_LINEAR(u64, 1, 2, _mm_cvtsi128_si64(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f32, 1, 4, _mm_cvtss_f32(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f32, 2, 4, bitcast_anything>(_mm_cvtsd_f64(_mm_castps_pd(x)))) +#ifndef KFR_f32x2_array +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4, 2, _mm_castpd_ps(_mm_set_sd(x.whole))) +#else +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4, 2, _mm_unpacklo_ps(_mm_set_ss(x.low), _mm_set_ss(x.high))) +#endif +KFR_INTRIN_SHUFFLE_LINEAR(f64, 1, 2, _mm_cvtsd_f64(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(i8, 2, 16, simd::from(u16(_mm_cvtsi128_si32(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 4, 16, simd::from(_mm_cvtsi128_si32(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 8, 16, simd::from(_mm_cvtsi128_si64(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 2, 16, simd::from(u16(_mm_cvtsi128_si32(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 4, 16, simd::from(_mm_cvtsi128_si32(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 8, 16, simd::from(_mm_cvtsi128_si64(x))) + +KFR_INTRIN_SHUFFLE_LINEAR(i16, 2, 8, simd::from(_mm_cvtsi128_si32(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 4, 8, simd::from(_mm_cvtsi128_si64(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 2, 8, simd::from(_mm_cvtsi128_si32(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 4, 8, simd::from(_mm_cvtsi128_si64(x))) + +KFR_INTRIN_SHUFFLE_LINEAR(i32, 2, 4, simd::from(_mm_cvtsi128_si64(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 2, 4, simd::from(_mm_cvtsi128_si64(x))) + +// high +KFR_INTRIN_SHUFFLE_LINEAR_START(u8, 8, 16, 8, simd::from(KFR_u64sse_INDEX(x, 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i8, 8, 16, 8, simd::from(KFR_u64sse_INDEX(x, 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u16, 4, 8, 4, simd::from(KFR_u64sse_INDEX(x, 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i16, 4, 8, 4, simd::from(KFR_u64sse_INDEX(x, 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u32, 2, 4, 2, simd::from(KFR_u64sse_INDEX(x, 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i32, 2, 4, 2, simd::from(KFR_u64sse_INDEX(x, 1))) + +#ifndef KFR_f32x2_array +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 2, 4, 2, simd::from(take_hi_sd(_mm_castps_pd(x)))) +#else +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 2, 4, 2, + simd_halves{ KFR_f32sse_INDEX(x, 2), KFR_f32sse_INDEX(x, 3) }) +#endif + +#define KFR_INTRIN_CONVERT(Tout, Tin, N, ...) \ + KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) CMT_NOEXCEPT \ + { \ + return __VA_ARGS__; \ + } + +#define KFR_INTRIN_CONVERT_NOOP_REF(Tout, Tin, N) \ + KFR_INTRINSIC const simd& simd_convert(simd_cvt_t, const simd& x) \ + CMT_NOEXCEPT \ + { \ + return x; \ + } +#define KFR_INTRIN_CONVERT_NOOP(Tout, Tin, N) \ + KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) CMT_NOEXCEPT \ + { \ + return x; \ + } + +KFR_INTRIN_CONVERT(f32, i32, 4, _mm_cvtepi32_ps(x)) +KFR_INTRIN_CONVERT(i32, f32, 4, _mm_cvttps_epi32(x)) +KFR_INTRIN_CONVERT(i32, f64, 2, simd::from(_mm_cvtsi128_si64(_mm_cvttpd_epi32(x)))) +#ifdef CMT_COMPILER_IS_MSVC +KFR_INTRIN_CONVERT(f64, i32, 2, + _mm_cvtepi32_pd(_mm_setr_epi32(bitcast_anything>(x).val[0], + bitcast_anything>(x).val[1], 0, 0))) +#else +KFR_INTRIN_CONVERT(f64, i32, 2, _mm_cvtepi32_pd(KFR_mm_setr_epi64x(x.whole, 0))) +#endif +KFR_INTRIN_CONVERT(i64, f64, 2, + KFR_mm_setr_epi64x(_mm_cvttsd_si64(x), _mm_cvttsd_si64(_mm_unpackhi_pd(x, x)))) +KFR_INTRIN_CONVERT(f64, i64, 2, + _mm_unpacklo_pd(_mm_cvtsi64_sd(_mm_setzero_pd(), _mm_cvtsi128_si64(x)), + _mm_cvtsi64_sd(_mm_setzero_pd(), KFR_i64sse_INDEX(x, 1)))) +#ifdef CMT_ARCH_AVX +KFR_INTRIN_CONVERT(f64, f32, 4, _mm256_cvtps_pd(x)) +#else +KFR_INTRIN_CONVERT(f64, f32, 4, + simd{ _mm_cvtps_pd(x), + _mm_cvtps_pd(_mm_shuffle_ps(x, x, _MM_SHUFFLE(1, 0, 3, 2))) }) +#endif +#ifdef CMT_ARCH_AVX +KFR_INTRIN_CONVERT(f32, f64, 4, _mm256_cvtpd_ps(x)) +#else +KFR_INTRIN_CONVERT(f32, f64, 4, + simd{ _mm_castpd_ps(_mm_unpacklo_pd(_mm_castps_pd(_mm_cvtpd_ps(x.low)), + _mm_castps_pd(_mm_cvtpd_ps(x.high)))) }) +#endif + +KFR_INTRIN_CONVERT_NOOP(u8, i8, 1) +KFR_INTRIN_CONVERT_NOOP(i8, u8, 1) +KFR_INTRIN_CONVERT_NOOP(u16, i16, 1) +KFR_INTRIN_CONVERT_NOOP(i16, u16, 1) +KFR_INTRIN_CONVERT_NOOP(u32, i32, 1) +KFR_INTRIN_CONVERT_NOOP(i32, u32, 1) +KFR_INTRIN_CONVERT_NOOP(u64, i64, 1) +KFR_INTRIN_CONVERT_NOOP(i64, u64, 1) + +KFR_INTRIN_CONVERT_NOOP_REF(u8, i8, 16) +KFR_INTRIN_CONVERT_NOOP_REF(i8, u8, 16) +KFR_INTRIN_CONVERT_NOOP_REF(u16, i16, 8) +KFR_INTRIN_CONVERT_NOOP_REF(i16, u16, 8) +KFR_INTRIN_CONVERT_NOOP_REF(u32, i32, 4) +KFR_INTRIN_CONVERT_NOOP_REF(i32, u32, 4) +KFR_INTRIN_CONVERT_NOOP_REF(u64, i64, 2) +KFR_INTRIN_CONVERT_NOOP_REF(i64, u64, 2) + +#endif // CMT_ARCH_SSE2 + +#ifdef CMT_ARCH_SSE41 + +KFR_INTRIN_CONVERT(i16, i8, 8, _mm_cvtepi8_epi16(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(u16, u8, 8, _mm_cvtepu8_epi16(_mm_cvtsi64_si128(x.whole))) + +KFR_INTRIN_CONVERT(i32, i16, 4, _mm_cvtepi16_epi32(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(u32, u16, 4, _mm_cvtepu16_epi32(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(i32, i8, 4, _mm_cvtepi8_epi32(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_CONVERT(u32, u8, 4, _mm_cvtepu8_epi32(_mm_cvtsi32_si128(x.whole))) + +KFR_INTRIN_CONVERT(i64, i32, 2, _mm_cvtepi32_epi64(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(u64, u32, 2, _mm_cvtepu32_epi64(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(i64, i16, 2, _mm_cvtepi16_epi64(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_CONVERT(u64, u16, 2, _mm_cvtepu16_epi64(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_CONVERT(i64, i8, 2, _mm_cvtepi8_epi64(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_CONVERT(u64, u8, 2, _mm_cvtepu8_epi64(_mm_cvtsi32_si128(x.whole))) + +KFR_INTRIN_CONVERT(f32, i8, 4, _mm_cvtepi32_ps(_mm_cvtepi8_epi32(_mm_cvtsi32_si128(x.whole)))) +KFR_INTRIN_CONVERT(f32, i16, 4, _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_cvtsi64_si128(x.whole)))) +KFR_INTRIN_CONVERT(f32, u8, 4, _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_cvtsi32_si128(x.whole)))) +KFR_INTRIN_CONVERT(f32, u16, 4, _mm_cvtepi32_ps(_mm_cvtepu16_epi32(_mm_cvtsi64_si128(x.whole)))) + +#ifndef CMT_ARCH_AVX +KFR_INTRIN_CONVERT(i64, i32, 4, + simd{ _mm_cvtepi32_epi64(x), + _mm_cvtepi32_epi64(_mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))) }) +#endif +#endif + +#ifdef CMT_ARCH_AVX +KFR_INTRIN_MAKE(4, f64, _mm256_setr_pd) +KFR_INTRIN_MAKE(8, f32, _mm256_setr_ps) + +KFR_INTRIN_BITCAST(f32, i32, 8, _mm256_castsi256_ps(x)) + +KFR_INTRIN_BITCAST(i32, f32, 8, _mm256_castps_si256(x)) +KFR_INTRIN_BITCAST(f64, i64, 4, _mm256_castsi256_pd(x)) +KFR_INTRIN_BITCAST(i64, f64, 4, _mm256_castpd_si256(x)) + +#ifndef CMT_ARCH_AVX512 +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, + csizes_t<2, 3, 6, 7, 10, 11, 14, 15>, overload_priority<9>) +{ + const __m256 t1 = _mm256_permute2f128_ps(x.low, x.high, (0 << 0) | (2 << 4)); + const __m256 t2 = _mm256_permute2f128_ps(x.low, x.high, (1 << 0) | (3 << 4)); + return _mm256_shuffle_ps(t1, t2, (shuffle_mask<8, 2, 3, 2, 3>::value)); +} + +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, + csizes_t<0, 1, 4, 5, 8, 9, 12, 13>, overload_priority<9>) +{ + const __m256 t1 = _mm256_permute2f128_ps(x.low, x.high, (0 << 0) | (2 << 4)); + const __m256 t2 = _mm256_permute2f128_ps(x.low, x.high, (1 << 0) | (3 << 4)); + return _mm256_shuffle_ps(t1, t2, (shuffle_mask<8, 0, 1, 0, 1>::value)); +} +#endif + +#ifndef CMT_ARCH_AVX2 +KFR_INTRIN_SHUFFLE_DUPHALVES(i8, 16, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u8, 16, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i16, 8, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u16, 8, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i32, 4, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u32, 4, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i64, 2, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u64, 2, _mm256_insertf128_si256(_mm256_castsi128_si256(x), x, 1)) +#endif + +KFR_INTRINSIC __m256 KFR_mm256_setr_m128(__m128 x, __m128 y) +{ + return _mm256_insertf128_ps(_mm256_castps128_ps256(x), y, 1); +} + +KFR_INTRINSIC __m256d KFR_mm256_setr_m128d(__m128d x, __m128d y) +{ + return _mm256_insertf128_pd(_mm256_castpd128_pd256(x), y, 1); +} +KFR_INTRINSIC __m256i KFR_mm256_setr_m128i(__m128i x, __m128i y) +{ +#ifdef CMT_ARCH_AVX2 + return _mm256_inserti128_si256(_mm256_castsi128_si256(x), y, 1); +#else + return _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); +#endif +} + +KFR_INTRIN_SHUFFLE_CONCAT(f32, 4, KFR_mm256_setr_m128(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(f64, 2, KFR_mm256_setr_m128d(x, y)) + +// concat +KFR_INTRIN_SHUFFLE_CONCAT(i8, 16, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i16, 8, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i32, 4, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i64, 2, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u8, 16, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u16, 8, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u32, 4, KFR_mm256_setr_m128i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u64, 2, KFR_mm256_setr_m128i(x, y)) + +#ifndef CMT_COMPILER_GCC +// GCC bug workaround +KFR_INTRIN_SHUFFLE_CONCAT(i8, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u8, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i16, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u16, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i32, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u32, 1, simd(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(f32, 1, simd{ x, y }) +#endif + +KFR_INTRIN_SHUFFLE_CONCAT(f64, 1, _mm_setr_pd(x, y)) + +KFR_INTRIN_SHUFFLE_DUPHALVES(f32, 4, KFR_mm256_setr_m128(x, x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(f64, 2, KFR_mm256_setr_m128d(x, x)) + +// low +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4, 8, _mm256_castps256_ps128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2, 4, _mm256_castpd256_pd128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16, 32, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8, 16, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4, 8, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2, 4, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16, 32, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8, 16, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4, 8, _mm256_castsi256_si128(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u64, 2, 4, _mm256_castsi256_si128(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(f32, 2, 8, _mm_cvtsd_f64(_mm_castps_pd(_mm256_castps256_ps128(x)))) +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 2, 8, 2, take_hi_sd(_mm_castps_pd(_mm256_castps256_ps128(x)))) +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 2, 8, 4, _mm_cvtsd_f64(_mm_castps_pd(_mm256_extractf128_ps(x, 1)))) +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 2, 8, 6, take_hi_sd(_mm_castps_pd(_mm256_extractf128_ps(x, 1)))) + +// extend +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4 * 2, 4, _mm256_castps128_ps256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2 * 2, 2, _mm256_castpd128_pd256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4 * 2, 2, _mm256_castps128_ps256(_mm_castpd_ps(_mm_set_sd(x.whole)))) + +// high +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 4, 8, 4, _mm256_extractf128_ps(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(f64, 2, 4, 2, _mm256_extractf128_pd(x, 1)) + +#ifndef CMT_ARCH_AVX2 +// high +KFR_INTRIN_SHUFFLE_LINEAR_START(i8, 16, 32, 16, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i16, 8, 16, 8, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i32, 4, 8, 4, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(i64, 2, 4, 2, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u8, 16, 32, 16, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u16, 8, 16, 8, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u32, 4, 8, 4, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +KFR_INTRIN_SHUFFLE_LINEAR_START(u64, 2, 4, 2, + _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(x), 1))) +#endif + +KFR_INTRIN_BROADCAST(f32, 8, _mm256_set1_ps(value)) +KFR_INTRIN_BROADCAST(f64, 4, _mm256_set1_pd(value)) + +KFR_INTRIN_SHUFFLE_LINEAR(f32, 8, 1, _mm256_castps128_ps256(_mm_set_ss(x))) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 4, 1, _mm256_castpd128_pd256(_mm_set_sd(x))) +#endif // CMT_ARCH_AVX + +#ifdef CMT_ARCH_AVX2 +KFR_INTRIN_MAKE(4, i64, _mm256_setr_epi64x) +KFR_INTRIN_MAKE(4, u64, _mm256_setr_epi64x) +KFR_INTRIN_MAKE(8, i32, _mm256_setr_epi32) +KFR_INTRIN_MAKE(8, u32, _mm256_setr_epi32) +KFR_INTRIN_MAKE(16, i16, _mm256_setr_epi16) +KFR_INTRIN_MAKE(16, u16, _mm256_setr_epi16) +KFR_INTRIN_MAKE(32, i8, _mm256_setr_epi8) +KFR_INTRIN_MAKE(32, u8, _mm256_setr_epi8) + +KFR_INTRIN_CONVERT(i16, i8, 16, _mm256_cvtepi8_epi16(x)) +KFR_INTRIN_CONVERT(u16, u8, 16, _mm256_cvtepu8_epi16(x)) + +KFR_INTRIN_CONVERT(i32, i16, 8, _mm256_cvtepi16_epi32(x)) +KFR_INTRIN_CONVERT(u32, u16, 8, _mm256_cvtepu16_epi32(x)) +KFR_INTRIN_CONVERT(i32, i8, 8, _mm256_cvtepi8_epi32(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(u32, u8, 8, _mm256_cvtepu8_epi32(_mm_cvtsi64_si128(x.whole))) + +KFR_INTRIN_CONVERT(i64, i32, 4, _mm256_cvtepi32_epi64(x)) +KFR_INTRIN_CONVERT(u64, u32, 4, _mm256_cvtepu32_epi64(x)) +KFR_INTRIN_CONVERT(i64, i16, 4, _mm256_cvtepi16_epi64(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(u64, u16, 4, _mm256_cvtepu16_epi64(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_CONVERT(i64, i8, 4, _mm256_cvtepi8_epi64(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_CONVERT(u64, u8, 4, _mm256_cvtepu8_epi64(_mm_cvtsi32_si128(x.whole))) + +KFR_INTRIN_CONVERT(f32, i8, 8, _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(_mm_cvtsi64_si128(x.whole)))) +KFR_INTRIN_CONVERT(f32, i16, 8, _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(x))) +KFR_INTRIN_CONVERT(f32, u8, 8, _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_cvtsi64_si128(x.whole)))) +KFR_INTRIN_CONVERT(f32, u16, 8, _mm256_cvtepi32_ps(_mm256_cvtepu16_epi32(x))) + +KFR_INTRIN_SHUFFLE_LINEAR_START(i8, 16, 32, 16, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(i16, 8, 16, 8, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(i32, 4, 8, 4, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(i64, 2, 4, 2, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(u8, 16, 32, 16, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(u16, 8, 16, 8, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(u32, 4, 8, 4, _mm256_extracti128_si256(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(u64, 2, 4, 2, _mm256_extracti128_si256(x, 1)) + +KFR_INTRIN_BROADCAST(i8, 32, _mm256_set1_epi8(value)) +KFR_INTRIN_BROADCAST(i16, 16, _mm256_set1_epi16(value)) +KFR_INTRIN_BROADCAST(i32, 8, _mm256_set1_epi32(value)) +KFR_INTRIN_BROADCAST(i64, 4, _mm256_set1_epi64x(value)) +KFR_INTRIN_BROADCAST(u8, 32, _mm256_set1_epi8(value)) +KFR_INTRIN_BROADCAST(u16, 16, _mm256_set1_epi16(value)) +KFR_INTRIN_BROADCAST(u32, 8, _mm256_set1_epi32(value)) +KFR_INTRIN_BROADCAST(u64, 4, _mm256_set1_epi64x(value)) + +KFR_INTRINSIC __m256i KFR_mm_broadcastsi128_si256(const __m128i& x) +{ + return _mm256_inserti128_si256(_mm256_castsi128_si256(x), x, 1); +} + +KFR_INTRIN_SHUFFLE_DUPHALVES(i8, 16, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u8, 16, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i16, 8, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u16, 8, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i32, 4, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u32, 4, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(i64, 2, KFR_mm_broadcastsi128_si256(x)) +KFR_INTRIN_SHUFFLE_DUPHALVES(u64, 2, KFR_mm_broadcastsi128_si256(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 16, _mm256_castsi128_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 2, 8, _mm256_castsi128_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 2, 4, _mm256_castsi128_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 2, 2, _mm256_castsi128_si256(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(u8(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(u16(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi64_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u64, 2 * 2, 1, _mm256_castsi128_si256(_mm_cvtsi64_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 2, 4, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 4, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 2, 8, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 8, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 2, 4, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 2, 4, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 2, 2, _mm256_castsi128_si256(_mm_cvtsi64_si128(x.whole))) + +KFR_INTRIN_CONVERT(i32, f32, 8, _mm256_cvttps_epi32(x)) +KFR_INTRIN_CONVERT(f32, i32, 8, _mm256_cvtepi32_ps(x)) +KFR_INTRIN_CONVERT(f64, i32, 4, _mm256_cvtepi32_pd(x)) +KFR_INTRIN_CONVERT(i32, f64, 4, _mm256_cvttpd_epi32(x)) +#endif // CMT_ARCH_AVX2 + +#ifdef CMT_ARCH_AVX512 + +static inline __m512d KFR_mm512_setr_pd(f64 x0, f64 x1, f64 x2, f64 x3, f64 x4, f64 x5, f64 x6, f64 x7) +{ + return _mm512_set_pd(x7, x6, x5, x4, x3, x2, x1, x0); +} +static inline __m512 KFR_mm512_setr_ps(f32 x0, f32 x1, f32 x2, f32 x3, f32 x4, f32 x5, f32 x6, f32 x7, f32 x8, + f32 x9, f32 x10, f32 x11, f32 x12, f32 x13, f32 x14, f32 x15) +{ + return _mm512_set_ps(x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0); +} +static inline __m512i KFR_mm512_setr_epi64(i64 x0, i64 x1, i64 x2, i64 x3, i64 x4, i64 x5, i64 x6, i64 x7) +{ + return _mm512_set_epi64(x7, x6, x5, x4, x3, x2, x1, x0); +} +static inline __m512i KFR_mm512_setr_epi32(i32 x0, i32 x1, i32 x2, i32 x3, i32 x4, i32 x5, i32 x6, i32 x7, + i32 x8, i32 x9, i32 x10, i32 x11, i32 x12, i32 x13, i32 x14, + i32 x15) +{ + return _mm512_set_epi32(x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0); +} +static inline __m512i KFR_mm512_setr_epi16(i16 x0, i16 x1, i16 x2, i16 x3, i16 x4, i16 x5, i16 x6, i16 x7, + i16 x8, i16 x9, i16 x10, i16 x11, i16 x12, i16 x13, i16 x14, + i16 x15, i16 x16, i16 x17, i16 x18, i16 x19, i16 x20, i16 x21, + i16 x22, i16 x23, i16 x24, i16 x25, i16 x26, i16 x27, i16 x28, + i16 x29, i16 x30, i16 x31) +{ +#ifdef CMT_COMPILER_GCC + typedef short v32hi __attribute__((__vector_size__(64))); + return __extension__(__m512i)(v32hi){ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, + x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, + x22, x23, x24, x25, x26, x27, x28, x29, x30, x31 }; +#else + return _mm512_set_epi16(x31, x30, x29, x28, x27, x26, x25, x24, x23, x22, x21, x20, x19, x18, x17, x16, + x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0); +#endif +} +static inline __m512i KFR_mm512_setr_epi8(i8 x0, i8 x1, i8 x2, i8 x3, i8 x4, i8 x5, i8 x6, i8 x7, i8 x8, + i8 x9, i8 x10, i8 x11, i8 x12, i8 x13, i8 x14, i8 x15, i8 x16, + i8 x17, i8 x18, i8 x19, i8 x20, i8 x21, i8 x22, i8 x23, i8 x24, + i8 x25, i8 x26, i8 x27, i8 x28, i8 x29, i8 x30, i8 x31, i8 x32, + i8 x33, i8 x34, i8 x35, i8 x36, i8 x37, i8 x38, i8 x39, i8 x40, + i8 x41, i8 x42, i8 x43, i8 x44, i8 x45, i8 x46, i8 x47, i8 x48, + i8 x49, i8 x50, i8 x51, i8 x52, i8 x53, i8 x54, i8 x55, i8 x56, + i8 x57, i8 x58, i8 x59, i8 x60, i8 x61, i8 x62, i8 x63) +{ +#ifdef CMT_COMPILER_GCC + typedef char v64qi __attribute__((__vector_size__(64))); + return __extension__(__m512i)(v64qi){ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, + x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, + x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, + x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, + x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63 }; +#else + return _mm512_set_epi8(x63, x62, x61, x60, x59, x58, x57, x56, x55, x54, x53, x52, x51, x50, x49, x48, + x47, x46, x45, x44, x43, x42, x41, x40, x39, x38, x37, x36, x35, x34, x33, x32, + x31, x30, x29, x28, x27, x26, x25, x24, x23, x22, x21, x20, x19, x18, x17, x16, + x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0); +#endif +} + +KFR_INTRINSIC __m512 KFR_mm512_setr_m256(__m256 x, __m256 y) +{ + return _mm512_insertf32x8(_mm512_castps256_ps512(x), y, 1); +} + +KFR_INTRINSIC __m512d KFR_mm512_setr_m256d(__m256d x, __m256d y) +{ + return _mm512_insertf64x4(_mm512_castpd256_pd512(x), y, 1); +} +KFR_INTRINSIC __m512i KFR_mm512_setr_m256i(__m256i x, __m256i y) +{ + return _mm512_inserti32x8(_mm512_castsi256_si512(x), y, 1); +} + +KFR_INTRIN_MAKE(8, f64, KFR_mm512_setr_pd) +KFR_INTRIN_MAKE(16, f32, KFR_mm512_setr_ps) + +KFR_INTRIN_MAKE(8, i64, KFR_mm512_setr_epi64) +KFR_INTRIN_MAKE(8, u64, KFR_mm512_setr_epi64) +KFR_INTRIN_MAKE(16, i32, KFR_mm512_setr_epi32) +KFR_INTRIN_MAKE(16, u32, KFR_mm512_setr_epi32) +KFR_INTRIN_MAKE(32, i16, KFR_mm512_setr_epi16) +KFR_INTRIN_MAKE(32, u16, KFR_mm512_setr_epi16) +KFR_INTRIN_MAKE(64, i8, KFR_mm512_setr_epi8) +KFR_INTRIN_MAKE(64, u8, KFR_mm512_setr_epi8) + +KFR_INTRIN_BROADCAST(f32, 16, _mm512_set1_ps(value)) +KFR_INTRIN_BROADCAST(f64, 8, _mm512_set1_pd(value)) + +KFR_INTRIN_BROADCAST(i8, 64, _mm512_set1_epi8(value)) +KFR_INTRIN_BROADCAST(i16, 32, _mm512_set1_epi16(value)) +KFR_INTRIN_BROADCAST(i32, 16, _mm512_set1_epi32(value)) +KFR_INTRIN_BROADCAST(i64, 8, _mm512_set1_epi64(value)) +KFR_INTRIN_BROADCAST(u8, 64, _mm512_set1_epi8(value)) +KFR_INTRIN_BROADCAST(u16, 32, _mm512_set1_epi16(value)) +KFR_INTRIN_BROADCAST(u32, 16, _mm512_set1_epi32(value)) +KFR_INTRIN_BROADCAST(u64, 8, _mm512_set1_epi64(value)) + +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(u8(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(u16(x)))) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi64_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi32_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u64, 2 * 4, 1, _mm512_castsi128_si512(_mm_cvtsi64_si128(x))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 4, 4, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 4, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 4, 8, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 8, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi32_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 4, 4, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 4, 4, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 4, 2, _mm512_castsi128_si512(_mm_cvtsi64_si128(x.whole))) + +KFR_INTRIN_CONVERT(i32, f32, 16, _mm512_cvttps_epi32(x)) +KFR_INTRIN_CONVERT(f32, i32, 16, _mm512_cvtepi32_ps(x)) +KFR_INTRIN_CONVERT(f64, i32, 8, _mm512_cvtepi32_pd(x)) +KFR_INTRIN_CONVERT(i32, f64, 8, _mm512_cvttpd_epi32(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4 * 4, 4, _mm512_castps128_ps512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2 * 4, 2, _mm512_castpd128_pd512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 16, _mm512_castsi128_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 4, 8, _mm512_castsi128_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 4, 4, _mm512_castsi128_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 4, 2, _mm512_castsi128_si512(x)) + +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4 * 4, 2 * 4, _mm512_castps256_ps512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2 * 4, 2 * 2, _mm512_castpd256_pd512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 4, 2 * 16, _mm512_castsi256_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 4, 2 * 8, _mm512_castsi256_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 4, 2 * 4, _mm512_castsi256_si512(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 4, 2 * 2, _mm512_castsi256_si512(x)) + +// low +KFR_INTRIN_SHUFFLE_LINEAR(f32, 4 * 2, 8 * 2, _mm512_castps512_ps256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(f64, 2 * 2, 4 * 2, _mm512_castpd512_pd256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i8, 16 * 2, 32 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i16, 8 * 2, 16 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i32, 4 * 2, 8 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(i64, 2 * 2, 4 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u8, 16 * 2, 32 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u16, 8 * 2, 16 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u32, 4 * 2, 8 * 2, _mm512_castsi512_si256(x)) +KFR_INTRIN_SHUFFLE_LINEAR(u64, 2 * 2, 4 * 2, _mm512_castsi512_si256(x)) + +// high +KFR_INTRIN_SHUFFLE_LINEAR_START(f32, 4 * 2, 8 * 2, 4 * 2, _mm512_extractf32x8_ps(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(f64, 2 * 2, 4 * 2, 2 * 2, _mm512_extractf64x4_pd(x, 1)) + +KFR_INTRIN_SHUFFLE_LINEAR_START(i32, 4 * 2, 8 * 2, 4 * 2, _mm512_extracti32x8_epi32(x, 1)) +KFR_INTRIN_SHUFFLE_LINEAR_START(i64, 2 * 2, 4 * 2, 2 * 2, _mm512_extracti64x4_epi64(x, 1)) + +// concat +KFR_INTRIN_SHUFFLE_CONCAT(f32, 4 * 2, KFR_mm512_setr_m256(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(f64, 2 * 2, KFR_mm512_setr_m256d(x, y)) + +KFR_INTRIN_SHUFFLE_CONCAT(i8, 16 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i16, 8 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i32, 4 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(i64, 2 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u8, 16 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u16, 8 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u32, 4 * 2, KFR_mm512_setr_m256i(x, y)) +KFR_INTRIN_SHUFFLE_CONCAT(u64, 2 * 2, KFR_mm512_setr_m256i(x, y)) +#endif + +#endif + +// generic functions + +template +KFR_INTRINSIC const simd& simd_concat(const simd& x) CMT_NOEXCEPT; + +template )> +KFR_INTRINSIC simd simd_concat(const simd& x, const simd& y, + const simd&... z) CMT_NOEXCEPT; + +template +KFR_INTRINSIC simd_array to_simd_array(const simd& x) CMT_NOEXCEPT +{ + return bitcast_anything>(x); +} + +#if defined CMT_COMPILER_IS_MSVC + +template >)> +KFR_INTRINSIC simd from_simd_array(const simd_array& x) CMT_NOEXCEPT +{ + return bitcast_anything>(x); +} + +template +KFR_INTRINSIC simd from_simd_array_impl(const simd_array& x, csizes_t) CMT_NOEXCEPT +{ + return { unwrap_bit_value(x.val[indices])... }; +} + +template >)> +KFR_INTRINSIC simd from_simd_array(const simd_array& x) CMT_NOEXCEPT +{ + return from_simd_array_impl(x, csizeseq); +} +#else +template +KFR_INTRINSIC simd from_simd_array(const simd_array& x) CMT_NOEXCEPT +{ + return bitcast_anything>(x); +} + +#endif + +template +KFR_INTRINSIC void simd_make(ctype_t) CMT_NOEXCEPT = delete; + +template +KFR_INTRINSIC simd simd_make(ctype_t, const Arg& arg) CMT_NOEXCEPT +{ + return simd{ unwrap_bit_value(static_cast(arg)) }; +} + +template +KFR_INTRINSIC simd simd_make_helper(csizes_t, const Args&... args) CMT_NOEXCEPT; + +template 1)> +KFR_INTRINSIC simd simd_make(ctype_t, const Args&... args) CMT_NOEXCEPT +{ + constexpr size_t Nlow = prev_poweroftwo(N - 1); + return simd_concat(simd_make_helper(csizeseq, args...), + simd_make_helper(csizeseq, args...)); +} + +template +KFR_INTRINSIC simd simd_make_helper(csizes_t, const Args&... args) CMT_NOEXCEPT +{ + const T temp[] = { static_cast(args)... }; + return simd_make(cometa::ctype, temp[indices]...); +} + +/// @brief Returns vector with undefined value +template +KFR_INTRINSIC simd simd_undefined() CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + simd x; + return x; +} + +/// @brief Returns vector with all zeros +template +KFR_INTRINSIC simd simd_zeros() CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + return from_simd_array({ Tout() }); +} + +/// @brief Returns vector with all ones +template +KFR_INTRINSIC simd simd_allones() CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + simd_array x{}; + KFR_COMPONENTWISE(x.val[i] = special_constants::allones()); + return from_simd_array(x); +} + +/// @brief Converts input vector to vector with subtype Tout +template ) +#else + , + KFR_ENABLE_IF(Nout == 1 || N == 1) +#endif + > +KFR_INTRINSIC simd simd_bitcast(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + return bitcast_anything>(x); +} + +/// @brief Converts input vector to vector with subtype Tout +template 1 && N > 1 && !std::is_same_v) +#else + , + KFR_ENABLE_IF(Nout > 1 && N > 1) +#endif + > +KFR_INTRINSIC simd simd_bitcast(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + constexpr size_t Nlow = prev_poweroftwo(N - 1); + return simd_concat( + simd_bitcast(simd_cvt_t{}, + unwrap_bit_value(simd_shuffle(simd_t{}, x, csizeseq, overload_auto))), + simd_bitcast( + simd_cvt_t{}, + unwrap_bit_value(simd_shuffle(simd_t{}, x, csizeseq, overload_auto)))); +} + +template +KFR_INTRINSIC const simd& simd_bitcast(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + return x; +} + +template +KFR_INTRINSIC T simd_get_element(const simd& value, csize_t) CMT_NOEXCEPT +{ + return wrap_bit_value(simd_shuffle(simd_t{}, value, csizes, overload_auto)); +} + +template +KFR_INTRINSIC simd simd_set_element(simd value, csize_t, unwrap_bit x) CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + simd_array arr = to_simd_array(value); + arr.val[index] = x; + return from_simd_array(arr); +} + +template +KFR_INTRINSIC const simd& simd_shuffle(simd_t, const simd& x, csizeseq_t, + overload_priority<10>) CMT_NOEXCEPT +{ + return x; +} + +template +KFR_INTRINSIC const simd& simd_shuffle(simd2_t, const simd& x, const simd&, + csizeseq_t, overload_priority<9>) CMT_NOEXCEPT +{ + return x; +} + +template +KFR_INTRINSIC const simd& simd_shuffle(simd2_t, const simd&, const simd& y, + csizeseq_t, overload_priority<9>) CMT_NOEXCEPT +{ + return y; +} + +// concat() +template , simd_halves, N + N>>)> +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, const simd& y, + csizeseq_t, overload_priority<8>) CMT_NOEXCEPT +{ + return simd{ x, y }; +} + +template +KFR_INTRINSIC simd simd_broadcast(simd_t, identity value) CMT_NOEXCEPT +{ + return { unwrap_bit_value(value) }; +} + +template = 2), size_t Nlow = prev_poweroftwo(N - 1)> +KFR_INTRINSIC simd simd_broadcast(simd_t, identity value) CMT_NOEXCEPT +{ + return simd_concat(simd_broadcast(simd_t{}, value), + simd_broadcast(simd_t{}, value)); +} + +template , simd_halves, N>>)> +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, csizeseq_t, + overload_priority<7>) CMT_NOEXCEPT +{ + return x.low; +} + +template , simd_halves, N>>)> +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, csizeseq_t, + overload_priority<7>) CMT_NOEXCEPT +{ + return x.high; +} + +template +KFR_INTRINSIC T simd_shuffle(simd_t, const simd& x, csizes_t, + overload_priority<6>) CMT_NOEXCEPT +{ + return to_simd_array(x).val[index]; +} + +template +simd_array simd_shuffle_generic(const simd_array& x, const unsigned (&indices)[Nout]) +{ + simd_array result; + for (size_t i = 0; i < Nout; ++i) + { + const size_t index = indices[i]; + result.val[i] = index >= N ? T() : static_cast(x.val[index]); + } + return result; +} + +template +simd_array simd_shuffle2_generic(const simd_array& x, const simd_array& y, + const unsigned (&indices)[Nout]) +{ + simd_array result; + for (size_t i = 0; i < Nout; ++i) + { + const size_t index = indices[i]; + result.val[i] = index >= N1 + N2 ? T() + : index >= N1 ? static_cast(y.val[index - N1]) + : static_cast(x.val[index]); + } + return result; +} + +template +KFR_INTRINSIC simd simd_shuffle(simd_t, const simd& x, csizes_t, + overload_generic) CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); +#ifdef CMT_COMPILER_IS_MSVC + const simd_array xx = to_simd_array(x); + constexpr static unsigned indices_array[] = { static_cast(indices)... }; + return from_simd_array(simd_shuffle_generic(xx, indices_array)); +#else + return from_simd_array({ (indices >= N ? T() : to_simd_array(x).val[indices])... }); +#endif +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, const simd& y, + csizes_t, overload_generic) CMT_NOEXCEPT +{ + static_assert(N == N2, ""); + not_optimized(CMT_FUNC_SIGNATURE); +#ifdef CMT_COMPILER_IS_MSVC + const simd_array xx = to_simd_array(x); + const simd_array yy = to_simd_array(y); + constexpr static unsigned indices_array[] = { static_cast(indices)... }; + return from_simd_array(simd_shuffle2_generic(xx, yy, indices_array)); +#else + return from_simd_array({ (indices >= N * 2 ? T() + : indices >= N ? to_simd_array(y).val[indices - N] + : to_simd_array(x).val[indices])... }); +#endif +} + +template +KFR_INTRINSIC simd simd_shuffle(simd2_t, const simd& x, const simd& y, + csizes_t, overload_generic) CMT_NOEXCEPT +{ + not_optimized(CMT_FUNC_SIGNATURE); + +#ifdef CMT_COMPILER_IS_MSVC + const simd_array xx = to_simd_array(x); + const simd_array yy = to_simd_array(y); + constexpr static unsigned indices_array[] = { static_cast(indices)... }; + return from_simd_array(simd_shuffle2_generic(xx, yy, indices_array)); +#else + + return from_simd_array({ (indices > N1 + N2 ? T() + : indices >= N1 ? to_simd_array(y).val[indices - N1] + : to_simd_array(x).val[indices])... }); +#endif +} + +template +KFR_INTRINSIC const simd& simd_concat(const simd& x) CMT_NOEXCEPT +{ + return x; +} + +template +KFR_INTRINSIC simd simd_concat4(const simd& x, const simd& y, + const simd& z, const simd& w) CMT_NOEXCEPT +{ + return simd_shuffle(simd2_t{}, + simd_shuffle(simd2_t{}, x, y, csizeseq, overload_auto), + simd_shuffle(simd2_t{}, z, w, csizeseq, overload_auto), + csizeseq, overload_auto); +} + +template )*/> +KFR_INTRINSIC simd simd_concat(const simd& x, const simd& y, + const simd&... z) CMT_NOEXCEPT +{ + if constexpr (sizeof...(Ns) == 2) + { + return simd_concat4(x, y, z...); + } + else + { + return simd_shuffle(simd2_t{}, x, simd_concat(y, z...), + csizeseq, overload_auto); + } +} + +template +KFR_INTRINSIC simd simd_convert__(const simd& x, csizes_t) CMT_NOEXCEPT +{ + const simd_array xx = to_simd_array(x); + return simd_make(cometa::ctype, static_cast(xx.val[indices])...); +} + +/// @brief Converts input vector to vector with subtype Tout +template ::value)> +KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + return simd_make(cometa::ctype, static_cast(x)); +} + +/// @brief Converts input vector to vector with subtype Tout +template +KFR_INTRINSIC simd simd_convert(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + constexpr size_t Nlow = prev_poweroftwo(N - 1); + return simd_concat( + simd_convert(simd_cvt_t{}, + simd_shuffle(simd_t{}, x, csizeseq, overload_auto)), + simd_convert(simd_cvt_t{}, + simd_shuffle(simd_t{}, x, csizeseq, overload_auto))); +} + +/// @brief Converts input vector to vector with subtype Tout +template +KFR_INTRINSIC const simd& simd_convert(simd_cvt_t, const simd& x) CMT_NOEXCEPT +{ + return x; +} + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wignored-attributes") + +template +using simd_storage = struct_with_alignment, A>; + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +template +KFR_INTRINSIC T simd_get_element(const simd& value, size_t index) CMT_NOEXCEPT +{ + return to_simd_array(value).val[index]; +} + +template +KFR_INTRINSIC simd simd_set_element(const simd& value, size_t index, unwrap_bit x) CMT_NOEXCEPT +{ + simd_array arr = to_simd_array(value); + arr.val[index] = x; + return from_simd_array(arr); +} + +#define SIMD_TYPE_INTRIN(T, N, TO_SCALAR, FROM_SCALAR, FROM_BROADCAST, FROM_ZERO) \ + KFR_INTRINSIC T simd_to_scalar(simd_t, const simd& x) { return TO_SCALAR; } \ + KFR_INTRINSIC simd simd_from_scalar(simd_t, unwrap_bit x) { return FROM_SCALAR; } \ + KFR_INTRINSIC simd simd_from_broadcast(simd_t, unwrap_bit x) { return FROM_BROADCAST; } \ + KFR_INTRINSIC simd simd_from_zero(simd_t) { return FROM_ZERO; } + +#define SIMD_TYPE_INTRIN_EX(T, N, TO_SCALAR, FROM_SCALAR, FROM_BROADCAST, FROM_ZERO, GET_LOW, GET_HIGH, \ + FROM_HALVES) \ + SIMD_TYPE_INTRIN(T, N, TO_SCALAR, FROM_SCALAR, FROM_BROADCAST, FROM_ZERO) \ + KFR_INTRINSIC simd simd_get_low(simd_t, const simd& x) { return GET_LOW; } \ + KFR_INTRINSIC simd simd_get_high(simd_t, const simd& x) { return GET_HIGH; } \ + KFR_INTRINSIC simd simd_from_halves(simd_t, const simd& x, \ + const simd& y) \ + { \ + return FROM_HALVES; \ + } + +template +KFR_INTRINSIC simd simd_from_partial(simd2_t, const simd& x) +{ +#ifdef CMT_COMPILER_IS_MSVC + union + { + simd in; + simd out; + } u; + u.in = x; + return u.out; +#else + union + { + simd in; + simd out; + } u{ x }; + return u.out; +#endif +} +template +KFR_INTRINSIC simd simd_get_low(simd_t, const simd& x) +{ + return x.low; +} +template +KFR_INTRINSIC simd simd_get_high(simd_t, const simd& x) +{ + return x.high; +} +template +KFR_INTRINSIC simd simd_from_halves(simd_t, const simd& x, const simd& y) +{ + return { x, y }; +} + +KFR_INTRINSIC simd simd_from_halves(simd_t, const simd& x, + const simd& y) +{ +#ifndef KFR_f32x2_array + return _mm_castpd_ps(_mm_setr_pd(x.whole, y.whole)); +#else + return _mm_setr_ps(x.low, x.high, y.low, y.high); +#endif +} + +KFR_INTRINSIC simd simd_from_halves(simd_t, const simd& x, + const simd& y) +{ + return _mm_setr_pd(x, y); +} + +SIMD_TYPE_INTRIN(f32, 4, _mm_cvtss_f32(x), _mm_set_ss(x), _mm_set1_ps(x), _mm_setzero_ps()) +SIMD_TYPE_INTRIN(f64, 2, _mm_cvtsd_f64(x), _mm_set_sd(x), _mm_set1_pd(x), _mm_setzero_pd()) + +#ifdef CMT_ARCH_AVX +SIMD_TYPE_INTRIN_EX(f32, 8, _mm256_cvtss_f32(x), _mm256_castps128_ps256(_mm_set_ss(x)), _mm256_set1_ps(x), + _mm256_setzero_ps(), _mm256_castps256_ps128(x), _mm256_extractf128_ps(x, 1), + KFR_mm256_setr_m128(x, y)) +SIMD_TYPE_INTRIN_EX(f64, 4, _mm256_cvtsd_f64(x), _mm256_castpd128_pd256(_mm_set_sd(x)), _mm256_set1_pd(x), + _mm256_setzero_pd(), _mm256_castpd256_pd128(x), _mm256_extractf128_pd(x, 1), + KFR_mm256_setr_m128d(x, y)) +#endif + +#ifdef CMT_ARCH_AVX512 +SIMD_TYPE_INTRIN_EX(f32, 16, _mm512_cvtss_f32(x), _mm512_castps128_ps512(_mm_set_ss(x)), _mm512_set1_ps(x), + _mm512_setzero_ps(), _mm512_castps512_ps256(x), _mm512_extractf32x8_ps(x, 1), + KFR_mm512_setr_m256(x, y)) +SIMD_TYPE_INTRIN_EX(f64, 8, _mm512_cvtsd_f64(x), _mm512_castpd128_pd512(_mm_set_sd(x)), _mm512_set1_pd(x), + _mm512_setzero_pd(), _mm512_castpd512_pd256(x), _mm512_extractf64x4_pd(x, 1), + KFR_mm512_setr_m256d(x, y)) +#endif + +#ifdef CMT_ARCH_SSE2 + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // SSE -> SSE + return _mm_shuffle_ps(x, x, (shuffle_mask<8, I0, I1, I2, I3>::value)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, csizes_t) +{ + // SSE -> SSE + return _mm_shuffle_pd(x, x, (shuffle_mask<2, I0, I1>::value)); +} +#endif + +template +KFR_INTRINSIC constexpr uint8_t vec_idx(size_t value) +{ + return value >= static_cast(max) ? 0 : static_cast(value); +} + +#ifdef CMT_ARCH_AVX512 + +template +KFR_INTRINSIC simd simd_vec_shuffle( + simd_t, const simd& x, + csizes_t) +{ + // AVX512 -> AVX512 + return _mm512_permutexvar_ps( + _mm512_setr_epi32(vec_idx<16>(I0), vec_idx<16>(I1), vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I4), + vec_idx<16>(I5), vec_idx<16>(I6), vec_idx<16>(I7), vec_idx<16>(I8), vec_idx<16>(I9), + vec_idx<16>(I10), vec_idx<16>(I11), vec_idx<16>(I12), vec_idx<16>(I13), + vec_idx<16>(I14), vec_idx<16>(I15)), + x); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX512 -> AVX512 + return _mm512_permutexvar_pd(_mm512_setr_epi64(vec_idx<8>(I0), vec_idx<8>(I1), vec_idx<8>(I2), + vec_idx<8>(I3), vec_idx<8>(I4), vec_idx<8>(I5), + vec_idx<8>(I6), vec_idx<8>(I7)), + x); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX512 -> AVX + return _mm512_castps512_ps256(_mm512_permutexvar_ps( + _mm512_setr_epi32(vec_idx<16>(I0), vec_idx<16>(I1), vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I4), + vec_idx<16>(I5), vec_idx<16>(I6), vec_idx<16>(I7), vec_idx<16>(I0), vec_idx<16>(I1), + vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I4), vec_idx<16>(I5), vec_idx<16>(I6), + vec_idx<16>(I7)), + x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX512 -> SSE + return _mm512_castps512_ps128(_mm512_permutexvar_ps( + _mm512_setr_epi32(vec_idx<16>(I0), vec_idx<16>(I1), vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I0), + vec_idx<16>(I1), vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I0), vec_idx<16>(I1), + vec_idx<16>(I2), vec_idx<16>(I3), vec_idx<16>(I0), vec_idx<16>(I1), vec_idx<16>(I2), + vec_idx<16>(I3)), + x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX512 -> AVX + return _mm512_castpd512_pd256(_mm512_permutexvar_pd( + _mm512_setr_epi64(vec_idx<8>(I0), vec_idx<8>(I1), vec_idx<8>(I2), vec_idx<8>(I3), vec_idx<8>(I0), + vec_idx<8>(I1), vec_idx<8>(I2), vec_idx<8>(I3)), + x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, csizes_t) +{ + // AVX512 -> SSE + return _mm512_castpd512_pd128(_mm512_permutexvar_pd( + _mm512_setr_epi64(vec_idx<8>(I0), vec_idx<8>(I1), vec_idx<8>(I0), vec_idx<8>(I1), vec_idx<8>(I0), + vec_idx<8>(I1), vec_idx<8>(I0), vec_idx<8>(I1)), + x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle( + simd_t, const simd& x, + csizes_t) +{ + // AVX -> AVX512 + return _mm512_permutexvar_ps( + _mm512_setr_epi32(vec_idx<8>(I0), vec_idx<8>(I1), vec_idx<8>(I2), vec_idx<8>(I3), vec_idx<8>(I4), + vec_idx<8>(I5), vec_idx<8>(I6), vec_idx<8>(I7), vec_idx<8>(I8), vec_idx<8>(I9), + vec_idx<8>(I10), vec_idx<8>(I11), vec_idx<8>(I12), vec_idx<8>(I13), vec_idx<8>(I14), + vec_idx<8>(I15)), + _mm512_castps256_ps512(x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle( + simd_t, const simd& x, + csizes_t) +{ + // SSE -> AVX512 + return _mm512_permutexvar_ps( + _mm512_setr_epi32(vec_idx<4>(I0), vec_idx<4>(I1), vec_idx<4>(I2), vec_idx<4>(I3), vec_idx<4>(I4), + vec_idx<4>(I5), vec_idx<4>(I6), vec_idx<4>(I7), vec_idx<4>(I8), vec_idx<4>(I9), + vec_idx<4>(I10), vec_idx<4>(I11), vec_idx<4>(I12), vec_idx<4>(I13), vec_idx<4>(I14), + vec_idx<4>(I15)), + _mm512_castps128_ps512(x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX -> AVX512 + return _mm512_permutexvar_pd(_mm512_setr_epi64(vec_idx<4>(I0), vec_idx<4>(I1), vec_idx<4>(I2), + vec_idx<4>(I3), vec_idx<4>(I4), vec_idx<4>(I5), + vec_idx<4>(I6), vec_idx<4>(I7)), + _mm512_castpd256_pd512(x)); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // SSE -> AVX512 + return _mm512_permutexvar_pd(_mm512_setr_epi64(vec_idx<2>(I0), vec_idx<2>(I1), vec_idx<2>(I2), + vec_idx<2>(I3), vec_idx<2>(I4), vec_idx<2>(I5), + vec_idx<2>(I6), vec_idx<2>(I7)), + _mm512_castpd128_pd512(x)); +} + +#endif + +#ifdef CMT_ARCH_AVX + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX -> AVX + if constexpr (cmaxof(csizes) < 4 && csizes.equal(csizes)) + { + const simd tmp = universal_shuffle(simd_t{}, simd_get_low(simd_t{}, x), + csizes); + return simd_from_halves(simd_t{}, tmp, tmp); + } + else if constexpr (cmaxof(csizes) < 4 && cminof(csizes) >= 4) + { + if constexpr (csizes.equal( + csizes)) + { + return _mm256_shuffle_ps(x, x, (shuffle_mask<8, I0, I1, I2, I3>::value)); + } + else + { + return simd_from_halves(simd_t{}, + universal_shuffle(simd_t{}, simd_get_low(simd_t{}, x), + csizes), + universal_shuffle(simd_t{}, + simd_get_high(simd_t{}, x), + csizes)); + } + } + else + { + const __m256 sw = _mm256_permute2f128_ps(x, x, 1); // swap lanes + const __m256 t1 = _mm256_permutevar_ps( + x, _mm256_setr_epi32(I0 % 4, I1 % 4, I2 % 4, I3 % 4, I4 % 4, I5 % 4, I6 % 4, I7 % 4)); + const __m256 t2 = _mm256_permutevar_ps( + sw, _mm256_setr_epi32(I0 % 4, I1 % 4, I2 % 4, I3 % 4, I4 % 4, I5 % 4, I6 % 4, I7 % 4)); + return _mm256_blend_ps(t1, t2, + (shuffle_mask<8, I0 / 4, I1 / 4, I2 / 4, I3 / 4, 1 - I4 / 4, 1 - I5 / 4, + 1 - I6 / 4, 1 - I7 / 4>::value)); + } +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX -> AVX + if constexpr (cmaxof(csizes) < 2 && csizes.equal(csizes)) + { + const simd tmp = + universal_shuffle(simd_t{}, simd_get_low(simd_t{}, x), csizes); + return simd_from_halves(simd_t{}, tmp, tmp); + } + else if constexpr (cmaxof(csizes) < 4 && cminof(csizes) >= 4) + { + if constexpr (csizes.equal(csizes)) + { + return _mm256_shuffle_pd(x, x, (shuffle_mask<2, I0, I1>::value)); + } + else + { + return simd_from_halves( + simd_t{}, + universal_shuffle(simd_t{}, simd_get_low(simd_t{}, x), csizes), + universal_shuffle(simd_t{}, simd_get_high(simd_t{}, x), + csizes)); + } + } + else + { + const __m256d sw = _mm256_permute2f128_pd(x, x, 1); // swap lanes + const __m256d t1 = _mm256_permutevar_pd( + x, _mm256_setr_epi64x((I0 % 2) << 1, (I1 % 2) << 1, (I2 % 2) << 1, (I3 % 2) << 1)); + const __m256d t2 = _mm256_permutevar_pd( + sw, _mm256_setr_epi64x((I0 % 2) << 1, (I1 % 2) << 1, (I2 % 2) << 1, (I3 % 2) << 1)); + return _mm256_blend_pd(t1, t2, (shuffle_mask<4, I0 / 2, I1 / 2, 1 - I2 / 2, 1 - I3 / 2>::value)); + } +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // AVX -> SSE + if constexpr (I0 % 4 == 0 && I1 % 4 == 1 && I2 % 4 == 2 && I3 % 4 == 3) + { + __m128 t1 = simd_get_low(simd_t{}, x); + __m128 t2 = simd_get_high(simd_t{}, x); + return _mm_blend_ps(t1, t2, (shuffle_mask<4, I0 / 4, I1 / 4, I2 / 4, I3 / 4>::value)); + } + else + { + __m128 t1 = simd_get_low(simd_t{}, x); + __m128 t2 = simd_get_high(simd_t{}, x); + t1 = _mm_permute_ps(t1, (shuffle_mask<8, I0 % 4, I1 % 4, I2 % 4, I3 % 4>::value)); + t2 = _mm_permute_ps(t2, (shuffle_mask<8, I0 % 4, I1 % 4, I2 % 4, I3 % 4>::value)); + return _mm_blend_ps(t1, t2, (shuffle_mask<4, I0 / 4, I1 / 4, I2 / 4, I3 / 4>::value)); + } +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, csizes_t) +{ + // AVX -> SSE + if constexpr (I0 % 2 == 0 && I1 % 2 == 1) + { + __m128d t1 = simd_get_low(simd_t{}, x); + __m128d t2 = simd_get_high(simd_t{}, x); + return _mm_blend_pd(t1, t2, (shuffle_mask<2, I0 / 2, I1 / 2>::value)); + } + else + { + __m128d t1 = simd_get_low(simd_t{}, x); + __m128d t2 = simd_get_high(simd_t{}, x); + t1 = _mm_permute_pd(t1, (shuffle_mask<2, I0 % 2, I1 % 2>::value)); + t2 = _mm_permute_pd(t2, (shuffle_mask<2, I0 % 2, I1 % 2>::value)); + return _mm_blend_pd(t1, t2, (shuffle_mask<2, I0 / 2, I1 / 2>::value)); + } +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // SSE -> AVX + return KFR_mm256_setr_m128(_mm_shuffle_ps(x, x, (shuffle_mask<8, I0, I1, I2, I3>::value)), + _mm_shuffle_ps(x, x, (shuffle_mask<8, I4, I5, I6, I7>::value))); +} + +template +KFR_INTRINSIC simd simd_vec_shuffle(simd_t, const simd& x, + csizes_t) +{ + // SSE -> AVX + return KFR_mm256_setr_m128d(_mm_shuffle_pd(x, x, (shuffle_mask<2, I0, I1>::value)), + _mm_shuffle_pd(x, x, (shuffle_mask<2, I2, I3>::value))); +} + +#endif + +template +KFR_INTRINSIC simd universal_shuffle(simd_t, const simd& x, csizes_t) +{ + using Indices = csizes_t; + + constexpr size_t minwidth = minimum_vector_width; + constexpr size_t maxwidth = vector_width; + constexpr size_t minindex = cminof(Indices{}); + constexpr size_t maxindex = cmaxof(csizes<(indices >= Nin ? 0 : indices)...>); + + if constexpr (Nin == 1 && Nout == 1) + { + return x; + } + else if constexpr (next_poweroftwo(Nin) == next_poweroftwo(Nout) && Indices{}.equal(csizeseq)) + { + return x; + } + else if constexpr (!is_poweroftwo(Nin) || !is_poweroftwo(Nout)) + { + // Fix if not power of two + return universal_shuffle( + simd_t{}, x, + cconcat(Indices{}, csizeseq)); + } + else if constexpr (Nout < minwidth) + { + // Expand indices if less than vector + const simd tmp = universal_shuffle( + simd_t{}, x, cconcat(Indices{}, csizeseq)); + + if constexpr (Nout == 1) + { + return simd_to_scalar(simd_t{}, tmp); + } + else + { + union + { + simd tmp; + simd r; + } u{ tmp }; + return u.r; + } + } + else if constexpr (Nout > maxwidth) + { + auto lowi = Indices{}[csizeseq]; + auto highi = Indices{}[csizeseq]; + if constexpr (lowi.equal(highi)) + { + auto tmp = universal_shuffle(simd_t{}, x, lowi); + return { tmp, tmp }; + } + else + { + return { universal_shuffle(simd_t{}, x, lowi), + universal_shuffle(simd_t{}, x, highi) }; + } + } + else if constexpr (minindex >= Nin) + { + return simd_from_zero(simd_t{}); + } + else if constexpr (Nin == 1) + { + return simd_from_broadcast(simd_t{}, x); + } + else if constexpr (Nin < minwidth) + { + return universal_shuffle(simd_t{}, simd_from_partial(simd2_t{}, x), + Indices{}); + } + else if constexpr (Nin > Nout && maxindex < Nin / 2) + { + return universal_shuffle(simd_t{}, simd_get_low(simd_t{}, x), Indices{}); + } + else if constexpr (Nin > Nout && minindex >= Nin / 2) + { + return universal_shuffle(simd_t{}, simd_get_high(simd_t{}, x), + csizes<(indices < Nin ? indices - csize : indices)...>); + } + else if constexpr (Nin >= minwidth && Nin <= maxwidth && Nout >= minwidth && Nout <= maxwidth) + { + return simd_vec_shuffle(simd_t{}, x, Indices{}); + } + else + { + not_optimized(CMT_FUNC_SIGNATURE); + const simd_array xx = to_simd_array(x); + constexpr static unsigned indices_array[] = { static_cast(indices)... }; + return from_simd_array(simd_shuffle_generic(xx, indices_array)); + } +} + +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_GNU(GCC diagnostic pop) +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_clang.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_clang.hpp new file mode 100644 index 00000000..f01d5aee --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_clang.hpp @@ -0,0 +1,184 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../mask.hpp" +#include "function.hpp" +#include +#include + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template )> +KFR_INTRINSIC vec neg(const vec& x) +{ + return -x.v; +} + +template )> +KFR_INTRINSIC vec bnot(const vec& x) +{ + return simd_bitcast(simd_cvt_t, N>{}, ~simd_bitcast(simd_cvt_t, T, N>{}, x.v)); +} + +#define KFR_OP_SCALAR2(fn, op, resultprefix, operprefix, soperprefix) \ + template )> \ + KFR_INTRINSIC vec fn(const vec& x, const T& y) \ + { \ + return resultprefix(operprefix(x.v) op soperprefix(y)); \ + } \ + template )> \ + KFR_INTRINSIC vec fn(const T& x, const vec& y) \ + { \ + return resultprefix(soperprefix(x) op operprefix(y.v)); \ + } + +template )> +KFR_INTRINSIC vec add(const vec& x, const vec& y) +{ + return x.v + y.v; +} +KFR_OP_SCALAR2(add, +, , , ) + +template )> +KFR_INTRINSIC vec sub(const vec& x, const vec& y) +{ + return x.v - y.v; +} +KFR_OP_SCALAR2(sub, -, , , ) + +template )> +KFR_INTRINSIC vec mul(const vec& x, const vec& y) +{ + return x.v * y.v; +} +KFR_OP_SCALAR2(mul, *, , , ) + +template )> +KFR_INTRINSIC vec div(const vec& x, const vec& y) +{ + return x.v / y.v; +} +KFR_OP_SCALAR2(div, /, , , ) +template )> +KFR_INTRINSIC vec mod(const vec& x, const vec& y) +{ + return x.v % y.v; +} +KFR_OP_SCALAR2(mod, %, , , ) + +template )> +KFR_INTRINSIC vec band(const vec& x, const vec& y) +{ + return (simd)((simd, N>)(x.v) & (simd, N>)(y.v)); +} +KFR_OP_SCALAR2(band, &, (simd), (simd, N>), ubitcast) + +template )> +KFR_INTRINSIC vec bor(const vec& x, const vec& y) +{ + return (simd)((simd, N>)(x.v) | (simd, N>)(y.v)); +} +KFR_OP_SCALAR2(bor, |, (simd), (simd, N>), ubitcast) + +template )> +KFR_INTRINSIC vec bxor(const vec& x, const vec& y) +{ + return (simd)((simd, N>)(x.v) ^ (simd, N>)(y.v)); +} +KFR_OP_SCALAR2(bxor, ^, (simd), (simd, N>), ubitcast) + +template )> +KFR_INTRINSIC vec shl(const vec& x, const vec, N>& y) +{ + return (simd)((simd>, N * sizeof(deep_subtype) / sizeof(T)>)(x.v) << y.v); +} + +template )> +KFR_INTRINSIC vec shr(const vec& x, const vec, N>& y) +{ + return (simd)((simd>, N * sizeof(deep_subtype) / sizeof(T)>)(x.v) >> y.v); +} + +template )> +KFR_INTRINSIC vec shl(const vec& x, unsigned y) +{ + return (simd)((simd>, N * sizeof(deep_subtype) / sizeof(T)>)(x.v) << y); +} + +template )> +KFR_INTRINSIC vec shr(const vec& x, unsigned y) +{ + return (simd)((simd>, N * sizeof(deep_subtype) / sizeof(T)>)(x.v) >> y); +} + +template )> +KFR_INTRINSIC vec eq(const vec& x, const vec& y) +{ + return (simd)(x.v == y.v); +} +KFR_OP_SCALAR2(eq, ==, (simd), , ) + +template )> +KFR_INTRINSIC vec ne(const vec& x, const vec& y) +{ + return (simd)(x.v != y.v); +} +KFR_OP_SCALAR2(ne, !=, (simd), , ) + +template )> +KFR_INTRINSIC vec le(const vec& x, const vec& y) +{ + return (simd)(x.v <= y.v); +} +KFR_OP_SCALAR2(le, <=, (simd), , ) + +template )> +KFR_INTRINSIC vec ge(const vec& x, const vec& y) +{ + return (simd)(x.v >= y.v); +} +KFR_OP_SCALAR2(ge, >=, (simd), , ) + +template )> +KFR_INTRINSIC vec lt(const vec& x, const vec& y) +{ + return (simd)(x.v < y.v); +} +KFR_OP_SCALAR2(lt, <, (simd), , ) + +template )> +KFR_INTRINSIC vec gt(const vec& x, const vec& y) +{ + return (simd)(x.v > y.v); +} +KFR_OP_SCALAR2(gt, >, (simd), , ) +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_complex.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_complex.hpp new file mode 100644 index 00000000..4cc09fd2 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_complex.hpp @@ -0,0 +1,113 @@ +/** @addtogroup complex + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../complex_type.hpp" +#include "../operators.hpp" +#include "../vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ +namespace intrinsics +{ + +template +KFR_INTRINSIC vec, N> neg(const vec, N>& x) +{ + return neg(x.flatten()).v; +} + +template +KFR_INTRINSIC vec, N> add(const vec, N>& x, const vec, N>& y) +{ + return add(x.flatten(), y.flatten()).v; +} + +template +KFR_INTRINSIC vec, N> sub(const vec, N>& x, const vec, N>& y) +{ + return sub(x.flatten(), y.flatten()).v; +} + +template +KFR_INTRINSIC vec, N> mul(const vec, N>& x, const vec, N>& y) +{ + const vec xx = x.v; + const vec yy = y.v; + return subadd(mul(xx, dupeven(yy)), mul(swap<2>(xx), dupodd(yy))).v; +} + +template +KFR_INTRINSIC vec, N> div(const vec, N>& x, const vec, N>& y) +{ + const vec xx = x.v; + const vec yy = y.v; + const vec m = (add(sqr(dupeven(yy)), sqr(dupodd(yy)))); + return swap<2>(subadd(mul(swap<2>(xx), dupeven(yy)), mul(xx, dupodd(yy))) / m).v; +} + +template +KFR_INTRINSIC vec, N> bor(const vec, N>& x, const vec, N>& y) +{ + return bor(x.flatten(), y.flatten()).v; +} +template +KFR_INTRINSIC vec, N> bxor(const vec, N>& x, const vec, N>& y) +{ + return bxor(x.flatten(), y.flatten()).v; +} +template +KFR_INTRINSIC vec, N> band(const vec, N>& x, const vec, N>& y) +{ + return band(x.flatten(), y.flatten()).v; +} + +#define KFR_COMPLEX_OP_CVT(fn) \ + template \ + KFR_INTRINSIC vec, N> fn(const vec, N>& x, const complex& y) \ + { \ + return fn(x, vec, N>(y)); \ + } \ + template \ + KFR_INTRINSIC vec, N> fn(const complex& x, const vec, N>& y) \ + { \ + return fn(vec, N>(x), y); \ + } + +KFR_COMPLEX_OP_CVT(add) +KFR_COMPLEX_OP_CVT(sub) +KFR_COMPLEX_OP_CVT(mul) +KFR_COMPLEX_OP_CVT(div) +KFR_COMPLEX_OP_CVT(band) +KFR_COMPLEX_OP_CVT(bxor) +KFR_COMPLEX_OP_CVT(bor) + +} // namespace intrinsics +} // namespace CMT_ARCH_NAME + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_generic.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_generic.hpp new file mode 100644 index 00000000..5da28293 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/basicoperators_generic.hpp @@ -0,0 +1,1642 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../mask.hpp" +#include "function.hpp" +#include +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4700)) +CMT_PRAGMA_MSVC(warning(disable : 4309)) + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#define KFR_DIV_MOD_FN(ty) \ + KFR_INTRINSIC ty div(const ty& x, const ty& y) \ + { \ + KFR_COMPONENTWISE_RET_I(ty, result[i] = y[i] ? x[i] / y[i] : 0); \ + } \ + KFR_INTRINSIC ty mod(const ty& x, const ty& y) \ + { \ + KFR_COMPONENTWISE_RET_I(ty, result[i] = y[i] ? x[i] % y[i] : 0); \ + } + +#if defined CMT_ARCH_SSE2 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC __m128 _mm_allones_ps() +{ + return _mm_castsi128_ps(_mm_cmpeq_epi8(_mm_setzero_si128(), _mm_setzero_si128())); +} + +KFR_INTRINSIC __m128d _mm_allones_pd() +{ + return _mm_castsi128_pd(_mm_cmpeq_epi8(_mm_setzero_si128(), _mm_setzero_si128())); +} + +KFR_INTRINSIC __m128i _mm_allones_si128() { return _mm_cmpeq_epi8(_mm_setzero_si128(), _mm_setzero_si128()); } + +KFR_INTRINSIC __m128 _mm_not_ps(const __m128& x) { return _mm_xor_ps(x, _mm_allones_ps()); } + +KFR_INTRINSIC __m128d _mm_not_pd(const __m128d& x) { return _mm_xor_pd(x, _mm_allones_pd()); } + +KFR_INTRINSIC __m128i _mm_not_si128(const __m128i& x) { return _mm_xor_si128(x, _mm_allones_si128()); } + +KFR_INTRINSIC __m128i _mm_highbit_epi8() { return _mm_set1_epi8(static_cast(0x80)); } +KFR_INTRINSIC __m128i _mm_highbit_epi16() { return _mm_set1_epi16(static_cast(0x8000)); } +KFR_INTRINSIC __m128i _mm_highbit_epi32() { return _mm_set1_epi32(static_cast(0x80000000)); } +KFR_INTRINSIC __m128i _mm_highbit_epi64() { return _mm_set1_epi64x(0x8000000000000000ll); } + +KFR_INTRINSIC f32sse add(const f32sse& x, const f32sse& y) { return f32sse(_mm_add_ps(x.v, y.v)); } +KFR_INTRINSIC f32sse sub(const f32sse& x, const f32sse& y) { return f32sse(_mm_sub_ps(x.v, y.v)); } +KFR_INTRINSIC f32sse mul(const f32sse& x, const f32sse& y) { return f32sse(_mm_mul_ps(x.v, y.v)); } +KFR_INTRINSIC f32sse div(const f32sse& x, const f32sse& y) { return f32sse(_mm_div_ps(x.v, y.v)); } + +KFR_INTRINSIC f64sse add(const f64sse& x, const f64sse& y) { return f64sse(_mm_add_pd(x.v, y.v)); } +KFR_INTRINSIC f64sse sub(const f64sse& x, const f64sse& y) { return f64sse(_mm_sub_pd(x.v, y.v)); } +KFR_INTRINSIC f64sse mul(const f64sse& x, const f64sse& y) { return f64sse(_mm_mul_pd(x.v, y.v)); } +KFR_INTRINSIC f64sse div(const f64sse& x, const f64sse& y) { return f64sse(_mm_div_pd(x.v, y.v)); } + +KFR_INTRINSIC u8sse add(const u8sse& x, const u8sse& y) { return _mm_add_epi8(x.v, y.v); } +KFR_INTRINSIC u8sse sub(const u8sse& x, const u8sse& y) { return _mm_sub_epi8(x.v, y.v); } +KFR_DIV_MOD_FN(u8sse) + +KFR_INTRINSIC i8sse add(const i8sse& x, const i8sse& y) { return _mm_add_epi8(x.v, y.v); } +KFR_INTRINSIC i8sse sub(const i8sse& x, const i8sse& y) { return _mm_sub_epi8(x.v, y.v); } +KFR_DIV_MOD_FN(i8sse) + +KFR_INTRINSIC __m128i mul_epi8(const __m128i& x, const __m128i& y) +{ + const __m128i even = _mm_mullo_epi16(x, y); + const __m128i odd = _mm_mullo_epi16(_mm_srli_epi16(x, 8), _mm_srli_epi16(y, 8)); + return _mm_or_si128(_mm_slli_epi16(odd, 8), _mm_srli_epi16(_mm_slli_epi16(even, 8), 8)); +} + +KFR_INTRINSIC u8sse mul(const u8sse& x, const u8sse& y) { return mul_epi8(x.v, y.v); } + +KFR_INTRINSIC i8sse mul(const i8sse& x, const i8sse& y) { return mul_epi8(x.v, y.v); } + +KFR_INTRINSIC u16sse add(const u16sse& x, const u16sse& y) { return _mm_add_epi16(x.v, y.v); } +KFR_INTRINSIC u16sse sub(const u16sse& x, const u16sse& y) { return _mm_sub_epi16(x.v, y.v); } +KFR_INTRINSIC u16sse mul(const u16sse& x, const u16sse& y) { return _mm_mullo_epi16(x.v, y.v); } +KFR_DIV_MOD_FN(u16sse) + +KFR_INTRINSIC i16sse add(const i16sse& x, const i16sse& y) { return _mm_add_epi16(x.v, y.v); } +KFR_INTRINSIC i16sse sub(const i16sse& x, const i16sse& y) { return _mm_sub_epi16(x.v, y.v); } +KFR_INTRINSIC i16sse mul(const i16sse& x, const i16sse& y) { return _mm_mullo_epi16(x.v, y.v); } +KFR_DIV_MOD_FN(i16sse) + +KFR_INTRINSIC u32sse add(const u32sse& x, const u32sse& y) { return _mm_add_epi32(x.v, y.v); } +KFR_INTRINSIC u32sse sub(const u32sse& x, const u32sse& y) { return _mm_sub_epi32(x.v, y.v); } + +KFR_INTRINSIC i32sse add(const i32sse& x, const i32sse& y) { return _mm_add_epi32(x.v, y.v); } +KFR_INTRINSIC i32sse sub(const i32sse& x, const i32sse& y) { return _mm_sub_epi32(x.v, y.v); } + +#if defined CMT_ARCH_SSE41 +KFR_INTRINSIC u32sse mul(const u32sse& x, const u32sse& y) { return _mm_mullo_epi32(x.v, y.v); } +KFR_INTRINSIC i32sse mul(const i32sse& x, const i32sse& y) { return _mm_mullo_epi32(x.v, y.v); } +#else +KFR_INTRINSIC u32sse mul(const u32sse& x, const u32sse& y) +{ + __m128i tmp1 = _mm_mul_epu32(x.v, y.v); + __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(x.v, 4), _mm_srli_si128(y.v, 4)); + return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), + _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); +} +KFR_INTRINSIC i32sse mul(const i32sse& x, const i32sse& y) +{ + __m128i tmp1 = _mm_mul_epu32(x.v, y.v); + __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(x.v, 4), _mm_srli_si128(y.v, 4)); + return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), + _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); +} +#endif +KFR_DIV_MOD_FN(u32sse) +KFR_DIV_MOD_FN(i32sse) + +KFR_INTRINSIC u64sse add(const u64sse& x, const u64sse& y) { return _mm_add_epi64(x.v, y.v); } +KFR_INTRINSIC u64sse sub(const u64sse& x, const u64sse& y) { return _mm_sub_epi64(x.v, y.v); } +KFR_INTRINSIC u64sse mul(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = x[i] * y[i]); +} + +KFR_INTRINSIC i64sse add(const i64sse& x, const i64sse& y) { return _mm_add_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse sub(const i64sse& x, const i64sse& y) { return _mm_sub_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse mul(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = x[i] * y[i]); +} +KFR_DIV_MOD_FN(u64sse) +KFR_DIV_MOD_FN(i64sse) + +KFR_INTRINSIC f32sse shl(const f32sse& x, unsigned y) +{ + return _mm_castsi128_ps(_mm_slli_epi32(_mm_castps_si128(x.v), y)); +} +KFR_INTRINSIC f64sse shl(const f64sse& x, unsigned y) +{ + return _mm_castsi128_pd(_mm_slli_epi64(_mm_castpd_si128(x.v), y)); +} +KFR_INTRINSIC f32sse shr(const f32sse& x, unsigned y) +{ + return _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(x.v), y)); +} +KFR_INTRINSIC f64sse shr(const f64sse& x, unsigned y) +{ + return _mm_castsi128_pd(_mm_srli_epi64(_mm_castpd_si128(x.v), y)); +} + +KFR_INTRINSIC u16sse shl(const u16sse& x, unsigned y) { return _mm_slli_epi16(x.v, y); } +KFR_INTRINSIC u32sse shl(const u32sse& x, unsigned y) { return _mm_slli_epi32(x.v, y); } +KFR_INTRINSIC u64sse shl(const u64sse& x, unsigned y) { return _mm_slli_epi64(x.v, y); } +KFR_INTRINSIC i16sse shl(const i16sse& x, unsigned y) { return _mm_slli_epi16(x.v, y); } +KFR_INTRINSIC i32sse shl(const i32sse& x, unsigned y) { return _mm_slli_epi32(x.v, y); } +KFR_INTRINSIC i64sse shl(const i64sse& x, unsigned y) { return _mm_slli_epi64(x.v, y); } + +KFR_INTRINSIC u16sse shr(const u16sse& x, unsigned y) { return _mm_srli_epi16(x.v, y); } +KFR_INTRINSIC u32sse shr(const u32sse& x, unsigned y) { return _mm_srli_epi32(x.v, y); } +KFR_INTRINSIC u64sse shr(const u64sse& x, unsigned y) { return _mm_srli_epi64(x.v, y); } +KFR_INTRINSIC i16sse shr(const i16sse& x, unsigned y) { return _mm_srai_epi16(x.v, y); } +KFR_INTRINSIC i32sse shr(const i32sse& x, unsigned y) { return _mm_srai_epi32(x.v, y); } + +KFR_INTRINSIC u8sse shl(const u8sse& x, unsigned y) +{ + __m128i l = _mm_unpacklo_epi8(_mm_setzero_si128(), x.v); + __m128i h = _mm_unpackhi_epi8(_mm_setzero_si128(), x.v); + + __m128i ll = _mm_slli_epi16(l, y); + __m128i hh = _mm_slli_epi16(h, y); + + return _mm_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8sse shl(const i8sse& x, unsigned y) +{ + __m128i l = _mm_unpacklo_epi8(_mm_setzero_si128(), x.v); + __m128i h = _mm_unpackhi_epi8(_mm_setzero_si128(), x.v); + + __m128i ll = _mm_slli_epi16(l, y); + __m128i hh = _mm_slli_epi16(h, y); + + return _mm_packs_epi16(ll, hh); +} +KFR_INTRINSIC u8sse shr(const u8sse& x, unsigned y) +{ + __m128i l = _mm_unpacklo_epi8(_mm_setzero_si128(), x.v); + __m128i h = _mm_unpackhi_epi8(_mm_setzero_si128(), x.v); + + __m128i ll = _mm_srli_epi16(l, y); + __m128i hh = _mm_srli_epi16(h, y); + + return _mm_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8sse shr(const i8sse& x, unsigned y) +{ + __m128i l = _mm_unpacklo_epi8(_mm_setzero_si128(), x.v); + __m128i h = _mm_unpackhi_epi8(_mm_setzero_si128(), x.v); + + __m128i ll = _mm_srai_epi16(l, y); + __m128i hh = _mm_srai_epi16(h, y); + + return _mm_packs_epi16(ll, hh); +} + +KFR_INTRINSIC i64sse shr(const i64sse& x, unsigned y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = x[i] >> y); +} + +template (N))> +KFR_INTRINSIC vec shl(const vec& x, const vec, N>& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) << y[i]))); +} +template (N))> +KFR_INTRINSIC vec shr(const vec& x, const vec, N>& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) >> y[i]))); +} + +KFR_INTRINSIC f32sse band(const f32sse& x, const f32sse& y) { return _mm_and_ps(x.v, y.v); } +KFR_INTRINSIC f64sse band(const f64sse& x, const f64sse& y) { return _mm_and_pd(x.v, y.v); } + +KFR_INTRINSIC u8sse band(const u8sse& x, const u8sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC u16sse band(const u16sse& x, const u16sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC u32sse band(const u32sse& x, const u32sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC u64sse band(const u64sse& x, const u64sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC i8sse band(const i8sse& x, const i8sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC i16sse band(const i16sse& x, const i16sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC i32sse band(const i32sse& x, const i32sse& y) { return _mm_and_si128(x.v, y.v); } +KFR_INTRINSIC i64sse band(const i64sse& x, const i64sse& y) { return _mm_and_si128(x.v, y.v); } + +KFR_INTRINSIC f32sse bor(const f32sse& x, const f32sse& y) { return _mm_or_ps(x.v, y.v); } +KFR_INTRINSIC f64sse bor(const f64sse& x, const f64sse& y) { return _mm_or_pd(x.v, y.v); } + +KFR_INTRINSIC u8sse bor(const u8sse& x, const u8sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC u16sse bor(const u16sse& x, const u16sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC u32sse bor(const u32sse& x, const u32sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC u64sse bor(const u64sse& x, const u64sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC i8sse bor(const i8sse& x, const i8sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC i16sse bor(const i16sse& x, const i16sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC i32sse bor(const i32sse& x, const i32sse& y) { return _mm_or_si128(x.v, y.v); } +KFR_INTRINSIC i64sse bor(const i64sse& x, const i64sse& y) { return _mm_or_si128(x.v, y.v); } + +KFR_INTRINSIC f32sse bxor(const f32sse& x, const f32sse& y) { return _mm_xor_ps(x.v, y.v); } +KFR_INTRINSIC f64sse bxor(const f64sse& x, const f64sse& y) { return _mm_xor_pd(x.v, y.v); } + +KFR_INTRINSIC u8sse bxor(const u8sse& x, const u8sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC u16sse bxor(const u16sse& x, const u16sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC u32sse bxor(const u32sse& x, const u32sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC u64sse bxor(const u64sse& x, const u64sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC i8sse bxor(const i8sse& x, const i8sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC i16sse bxor(const i16sse& x, const i16sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC i32sse bxor(const i32sse& x, const i32sse& y) { return _mm_xor_si128(x.v, y.v); } +KFR_INTRINSIC i64sse bxor(const i64sse& x, const i64sse& y) { return _mm_xor_si128(x.v, y.v); } + +KFR_INTRINSIC f32sse eq(const f32sse& x, const f32sse& y) { return _mm_cmpeq_ps(x.v, y.v); } +KFR_INTRINSIC f64sse eq(const f64sse& x, const f64sse& y) { return _mm_cmpeq_pd(x.v, y.v); } +KFR_INTRINSIC u8sse eq(const u8sse& x, const u8sse& y) { return _mm_cmpeq_epi8(x.v, y.v); } +KFR_INTRINSIC u16sse eq(const u16sse& x, const u16sse& y) { return _mm_cmpeq_epi16(x.v, y.v); } +KFR_INTRINSIC u32sse eq(const u32sse& x, const u32sse& y) { return _mm_cmpeq_epi32(x.v, y.v); } +KFR_INTRINSIC i8sse eq(const i8sse& x, const i8sse& y) { return _mm_cmpeq_epi8(x.v, y.v); } +KFR_INTRINSIC i16sse eq(const i16sse& x, const i16sse& y) { return _mm_cmpeq_epi16(x.v, y.v); } +KFR_INTRINSIC i32sse eq(const i32sse& x, const i32sse& y) { return _mm_cmpeq_epi32(x.v, y.v); } + +KFR_INTRINSIC f32sse ne(const f32sse& x, const f32sse& y) { return _mm_not_ps(_mm_cmpeq_ps(x.v, y.v)); } +KFR_INTRINSIC f64sse ne(const f64sse& x, const f64sse& y) { return _mm_not_pd(_mm_cmpeq_pd(x.v, y.v)); } +KFR_INTRINSIC u8sse ne(const u8sse& x, const u8sse& y) { return _mm_not_si128(_mm_cmpeq_epi8(x.v, y.v)); } +KFR_INTRINSIC u16sse ne(const u16sse& x, const u16sse& y) { return _mm_not_si128(_mm_cmpeq_epi16(x.v, y.v)); } +KFR_INTRINSIC u32sse ne(const u32sse& x, const u32sse& y) { return _mm_not_si128(_mm_cmpeq_epi32(x.v, y.v)); } +KFR_INTRINSIC i8sse ne(const i8sse& x, const i8sse& y) { return _mm_not_si128(_mm_cmpeq_epi8(x.v, y.v)); } +KFR_INTRINSIC i16sse ne(const i16sse& x, const i16sse& y) { return _mm_not_si128(_mm_cmpeq_epi16(x.v, y.v)); } +KFR_INTRINSIC i32sse ne(const i32sse& x, const i32sse& y) { return _mm_not_si128(_mm_cmpeq_epi32(x.v, y.v)); } + +KFR_INTRINSIC f32sse lt(const f32sse& x, const f32sse& y) { return _mm_cmplt_ps(x.v, y.v); } +KFR_INTRINSIC f64sse lt(const f64sse& x, const f64sse& y) { return _mm_cmplt_pd(x.v, y.v); } +KFR_INTRINSIC i8sse lt(const i8sse& x, const i8sse& y) { return _mm_cmplt_epi8(x.v, y.v); } +KFR_INTRINSIC i16sse lt(const i16sse& x, const i16sse& y) { return _mm_cmplt_epi16(x.v, y.v); } +KFR_INTRINSIC i32sse lt(const i32sse& x, const i32sse& y) { return _mm_cmplt_epi32(x.v, y.v); } + +KFR_INTRINSIC u8sse lt(const u8sse& x, const u8sse& y) +{ + const __m128i hb = _mm_highbit_epi8(); + return _mm_cmplt_epi8(_mm_add_epi8(x.v, hb), _mm_add_epi8(y.v, hb)); +} + +KFR_INTRINSIC u16sse lt(const u16sse& x, const u16sse& y) +{ + const __m128i hb = _mm_highbit_epi16(); + return _mm_cmplt_epi16(_mm_add_epi16(x.v, hb), _mm_add_epi16(y.v, hb)); +} +KFR_INTRINSIC u32sse lt(const u32sse& x, const u32sse& y) +{ + const __m128i hb = _mm_highbit_epi32(); + return _mm_cmplt_epi32(_mm_add_epi32(x.v, hb), _mm_add_epi32(y.v, hb)); +} + +KFR_INTRINSIC f32sse gt(const f32sse& x, const f32sse& y) { return _mm_cmpgt_ps(x.v, y.v); } +KFR_INTRINSIC f64sse gt(const f64sse& x, const f64sse& y) { return _mm_cmpgt_pd(x.v, y.v); } +KFR_INTRINSIC i8sse gt(const i8sse& x, const i8sse& y) { return _mm_cmpgt_epi8(x.v, y.v); } +KFR_INTRINSIC i16sse gt(const i16sse& x, const i16sse& y) { return _mm_cmpgt_epi16(x.v, y.v); } +KFR_INTRINSIC i32sse gt(const i32sse& x, const i32sse& y) { return _mm_cmpgt_epi32(x.v, y.v); } + +KFR_INTRINSIC u8sse gt(const u8sse& x, const u8sse& y) +{ + const __m128i hb = _mm_highbit_epi8(); + return _mm_cmpgt_epi8(_mm_add_epi8(x.v, hb), _mm_add_epi8(y.v, hb)); +} + +KFR_INTRINSIC u16sse gt(const u16sse& x, const u16sse& y) +{ + const __m128i hb = _mm_highbit_epi16(); + return _mm_cmpgt_epi16(_mm_add_epi16(x.v, hb), _mm_add_epi16(y.v, hb)); +} +KFR_INTRINSIC u32sse gt(const u32sse& x, const u32sse& y) +{ + const __m128i hb = _mm_highbit_epi32(); + return _mm_cmpgt_epi32(_mm_add_epi32(x.v, hb), _mm_add_epi32(y.v, hb)); +} + +KFR_INTRINSIC f32sse le(const f32sse& x, const f32sse& y) { return _mm_cmple_ps(x.v, y.v); } +KFR_INTRINSIC f64sse le(const f64sse& x, const f64sse& y) { return _mm_cmple_pd(x.v, y.v); } +KFR_INTRINSIC i8sse le(const i8sse& x, const i8sse& y) { return _mm_not_si128(_mm_cmpgt_epi8(x.v, y.v)); } +KFR_INTRINSIC i16sse le(const i16sse& x, const i16sse& y) { return _mm_not_si128(_mm_cmpgt_epi16(x.v, y.v)); } +KFR_INTRINSIC i32sse le(const i32sse& x, const i32sse& y) { return _mm_not_si128(_mm_cmpgt_epi32(x.v, y.v)); } + +KFR_INTRINSIC u8sse le(const u8sse& x, const u8sse& y) +{ + const __m128i hb = _mm_highbit_epi8(); + return _mm_not_si128(_mm_cmpgt_epi8(_mm_add_epi8(x.v, hb), _mm_add_epi8(y.v, hb))); +} + +KFR_INTRINSIC u16sse le(const u16sse& x, const u16sse& y) +{ + const __m128i hb = _mm_highbit_epi16(); + return _mm_not_si128(_mm_cmpgt_epi16(_mm_add_epi16(x.v, hb), _mm_add_epi16(y.v, hb))); +} +KFR_INTRINSIC u32sse le(const u32sse& x, const u32sse& y) +{ + const __m128i hb = _mm_highbit_epi32(); + return _mm_not_si128(_mm_cmpgt_epi32(_mm_add_epi32(x.v, hb), _mm_add_epi32(y.v, hb))); +} + +KFR_INTRINSIC f32sse ge(const f32sse& x, const f32sse& y) { return _mm_cmpge_ps(x.v, y.v); } +KFR_INTRINSIC f64sse ge(const f64sse& x, const f64sse& y) { return _mm_cmpge_pd(x.v, y.v); } +KFR_INTRINSIC i8sse ge(const i8sse& x, const i8sse& y) { return _mm_not_si128(_mm_cmplt_epi8(x.v, y.v)); } +KFR_INTRINSIC i16sse ge(const i16sse& x, const i16sse& y) { return _mm_not_si128(_mm_cmplt_epi16(x.v, y.v)); } +KFR_INTRINSIC i32sse ge(const i32sse& x, const i32sse& y) { return _mm_not_si128(_mm_cmplt_epi32(x.v, y.v)); } + +KFR_INTRINSIC u8sse ge(const u8sse& x, const u8sse& y) +{ + const __m128i hb = _mm_highbit_epi8(); + return _mm_not_si128(_mm_cmplt_epi8(_mm_add_epi8(x.v, hb), _mm_add_epi8(y.v, hb))); +} + +KFR_INTRINSIC u16sse ge(const u16sse& x, const u16sse& y) +{ + const __m128i hb = _mm_highbit_epi16(); + return _mm_not_si128(_mm_cmplt_epi16(_mm_add_epi16(x.v, hb), _mm_add_epi16(y.v, hb))); +} +KFR_INTRINSIC u32sse ge(const u32sse& x, const u32sse& y) +{ + const __m128i hb = _mm_highbit_epi32(); + return _mm_not_si128(_mm_cmplt_epi32(_mm_add_epi32(x.v, hb), _mm_add_epi32(y.v, hb))); +} + +#if defined CMT_ARCH_SSE41 && defined KFR_NATIVE_INTRINSICS +KFR_INTRINSIC u64sse eq(const u64sse& x, const u64sse& y) { return _mm_cmpeq_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse eq(const i64sse& x, const i64sse& y) { return _mm_cmpeq_epi64(x.v, y.v); } +KFR_INTRINSIC u64sse ne(const u64sse& x, const u64sse& y) { return _mm_not_si128(_mm_cmpeq_epi64(x.v, y.v)); } +KFR_INTRINSIC i64sse ne(const i64sse& x, const i64sse& y) { return _mm_not_si128(_mm_cmpeq_epi64(x.v, y.v)); } +#else +KFR_INTRINSIC u64sse eq(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] == y[i])); +} +KFR_INTRINSIC i64sse eq(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] == y[i])); +} +KFR_INTRINSIC u64sse ne(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] != y[i])); +} +KFR_INTRINSIC i64sse ne(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] != y[i])); +} +#endif + +#if defined CMT_ARCH_SSE42 +KFR_INTRINSIC i64sse gt(const i64sse& x, const i64sse& y) { return _mm_cmpgt_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse lt(const i64sse& x, const i64sse& y) { return _mm_cmpgt_epi64(y.v, x.v); } +KFR_INTRINSIC i64sse ge(const i64sse& x, const i64sse& y) { return _mm_not_si128(_mm_cmpgt_epi64(y.v, x.v)); } +KFR_INTRINSIC i64sse le(const i64sse& x, const i64sse& y) { return _mm_not_si128(_mm_cmpgt_epi64(x.v, y.v)); } + +KFR_INTRINSIC u64sse gt(const u64sse& x, const u64sse& y) +{ + const __m128i hb = _mm_highbit_epi64(); + return _mm_cmpgt_epi64(_mm_add_epi64(x.v, hb), _mm_add_epi64(y.v, hb)); +} +KFR_INTRINSIC u64sse lt(const u64sse& x, const u64sse& y) +{ + const __m128i hb = _mm_highbit_epi64(); + return _mm_cmpgt_epi64(_mm_add_epi64(y.v, hb), _mm_add_epi64(x.v, hb)); +} +KFR_INTRINSIC u64sse ge(const u64sse& x, const u64sse& y) +{ + const __m128i hb = _mm_highbit_epi64(); + return _mm_not_si128(_mm_cmpgt_epi64(_mm_add_epi64(y.v, hb), _mm_add_epi64(x.v, hb))); +} +KFR_INTRINSIC u64sse le(const u64sse& x, const u64sse& y) +{ + const __m128i hb = _mm_highbit_epi64(); + return _mm_not_si128(_mm_cmpgt_epi64(_mm_add_epi64(x.v, hb), _mm_add_epi64(y.v, hb))); +} + +#else +KFR_INTRINSIC u64sse gt(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] > y[i])); +} +KFR_INTRINSIC i64sse gt(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] > y[i])); +} +KFR_INTRINSIC u64sse lt(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] < y[i])); +} +KFR_INTRINSIC i64sse lt(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] < y[i])); +} +KFR_INTRINSIC u64sse ge(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] >= y[i])); +} +KFR_INTRINSIC i64sse ge(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] >= y[i])); +} +KFR_INTRINSIC u64sse le(const u64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(u64sse, result[i] = maskbits(x[i] <= y[i])); +} +KFR_INTRINSIC i64sse le(const i64sse& x, const i64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = maskbits(x[i] <= y[i])); +} +#endif + +#if defined CMT_ARCH_AVX + +KFR_INTRINSIC f32avx add(const f32avx& x, const f32avx& y) { return f32avx(_mm256_add_ps(x.v, y.v)); } +KFR_INTRINSIC f64avx add(const f64avx& x, const f64avx& y) { return f64avx(_mm256_add_pd(x.v, y.v)); } +KFR_INTRINSIC f32avx sub(const f32avx& x, const f32avx& y) { return f32avx(_mm256_sub_ps(x.v, y.v)); } +KFR_INTRINSIC f64avx sub(const f64avx& x, const f64avx& y) { return f64avx(_mm256_sub_pd(x.v, y.v)); } +KFR_INTRINSIC f32avx mul(const f32avx& x, const f32avx& y) { return f32avx(_mm256_mul_ps(x.v, y.v)); } +KFR_INTRINSIC f64avx mul(const f64avx& x, const f64avx& y) { return f64avx(_mm256_mul_pd(x.v, y.v)); } +KFR_INTRINSIC f32avx div(const f32avx& x, const f32avx& y) { return f32avx(_mm256_div_ps(x.v, y.v)); } +KFR_INTRINSIC f64avx div(const f64avx& x, const f64avx& y) { return f64avx(_mm256_div_pd(x.v, y.v)); } + +KFR_INTRINSIC __m256 _mm256_allones_ps() +{ + return _mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_UQ); +} + +KFR_INTRINSIC __m256d _mm256_allones_pd() +{ + return _mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_UQ); +} + +#if defined CMT_ARCH_AVX2 +KFR_INTRINSIC __m256i _mm256_allones_si256() +{ + return _mm256_cmpeq_epi8(_mm256_setzero_si256(), _mm256_setzero_si256()); +} +KFR_INTRINSIC __m256i _mm256_not_si256(const __m256i& x) +{ + return _mm256_xor_si256(x, _mm256_allones_si256()); +} +#else +KFR_INTRINSIC __m256i _mm256_allones_si256() +{ + return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_UQ)); +} +KFR_INTRINSIC __m256i _mm256_not_si256(const __m256i& x) +{ + return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(x), _mm256_allones_ps())); +} +#endif + +KFR_INTRINSIC __m256 _mm256_not_ps(const __m256& x) { return _mm256_xor_ps(x, _mm256_allones_ps()); } +KFR_INTRINSIC __m256d _mm256_not_pd(const __m256d& x) { return _mm256_xor_pd(x, _mm256_allones_pd()); } + +KFR_INTRINSIC __m256i _mm256_highbit_epi8() { return _mm256_set1_epi8(static_cast(0x80)); } +KFR_INTRINSIC __m256i _mm256_highbit_epi16() { return _mm256_set1_epi16(static_cast(0x8000)); } +KFR_INTRINSIC __m256i _mm256_highbit_epi32() { return _mm256_set1_epi32(static_cast(0x80000000)); } +KFR_INTRINSIC __m256i _mm256_highbit_epi64() { return _mm256_set1_epi64x(0x8000000000000000ll); } + +KFR_INTRINSIC f32avx eq(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_EQ_OQ); } +KFR_INTRINSIC f64avx eq(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_EQ_OQ); } +KFR_INTRINSIC f32avx ne(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_NEQ_OQ); } +KFR_INTRINSIC f64avx ne(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_NEQ_OQ); } +KFR_INTRINSIC f32avx lt(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_LT_OQ); } +KFR_INTRINSIC f64avx lt(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_LT_OQ); } +KFR_INTRINSIC f32avx gt(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_GT_OQ); } +KFR_INTRINSIC f64avx gt(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_GT_OQ); } +KFR_INTRINSIC f32avx le(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_LE_OQ); } +KFR_INTRINSIC f64avx le(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_LE_OQ); } +KFR_INTRINSIC f32avx ge(const f32avx& x, const f32avx& y) { return _mm256_cmp_ps(x.v, y.v, _CMP_GE_OQ); } +KFR_INTRINSIC f64avx ge(const f64avx& x, const f64avx& y) { return _mm256_cmp_pd(x.v, y.v, _CMP_GE_OQ); } + +KFR_INTRINSIC f32avx band(const f32avx& x, const f32avx& y) { return _mm256_and_ps(x.v, y.v); } +KFR_INTRINSIC f64avx band(const f64avx& x, const f64avx& y) { return _mm256_and_pd(x.v, y.v); } +KFR_INTRINSIC f32avx bor(const f32avx& x, const f32avx& y) { return _mm256_or_ps(x.v, y.v); } +KFR_INTRINSIC f64avx bor(const f64avx& x, const f64avx& y) { return _mm256_or_pd(x.v, y.v); } +KFR_INTRINSIC f32avx bxor(const f32avx& x, const f32avx& y) { return _mm256_xor_ps(x.v, y.v); } +KFR_INTRINSIC f64avx bxor(const f64avx& x, const f64avx& y) { return _mm256_xor_pd(x.v, y.v); } + +KFR_INTRINSIC f32avx shl(const f32avx& x, unsigned y) +{ +#if defined CMT_ARCH_AVX2 + return _mm256_castsi256_ps(_mm256_slli_epi32(_mm256_castps_si256(x.v), y)); +#else + return KFR_mm256_setr_m128( + _mm_castsi128_ps(_mm_slli_epi32(_mm_castps_si128(_mm256_castps256_ps128(x.v)), y)), + _mm_castsi128_ps(_mm_slli_epi32(_mm_castps_si128(_mm256_extractf128_ps(x.v, 1)), y))); +#endif +} +KFR_INTRINSIC f64avx shl(const f64avx& x, unsigned y) +{ +#if defined CMT_ARCH_AVX2 + return _mm256_castsi256_pd(_mm256_slli_epi64(_mm256_castpd_si256(x.v), y)); +#else + return KFR_mm256_setr_m128d( + _mm_castsi128_pd(_mm_slli_epi64(_mm_castpd_si128(_mm256_castpd256_pd128(x.v)), y)), + _mm_castsi128_pd(_mm_slli_epi64(_mm_castpd_si128(_mm256_extractf128_pd(x.v, 1)), y))); +#endif +} +KFR_INTRINSIC f32avx shr(const f32avx& x, unsigned y) +{ +#if defined CMT_ARCH_AVX2 + return _mm256_castsi256_ps(_mm256_srli_epi32(_mm256_castps_si256(x.v), y)); +#else + return KFR_mm256_setr_m128( + _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(_mm256_castps256_ps128(x.v)), y)), + _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(_mm256_extractf128_ps(x.v, 1)), y))); +#endif +} +KFR_INTRINSIC f64avx shr(const f64avx& x, unsigned y) +{ +#if defined CMT_ARCH_AVX2 + return _mm256_castsi256_pd(_mm256_srli_epi64(_mm256_castpd_si256(x.v), y)); +#else + return KFR_mm256_setr_m128d( + _mm_castsi128_pd(_mm_srli_epi64(_mm_castpd_si128(_mm256_castpd256_pd128(x.v)), y)), + _mm_castsi128_pd(_mm_srli_epi64(_mm_castpd_si128(_mm256_extractf128_pd(x.v, 1)), y))); +#endif +} + +#if defined CMT_ARCH_AVX2 + +KFR_INTRINSIC u8avx add(const u8avx& x, const u8avx& y) { return _mm256_add_epi8(x.v, y.v); } +KFR_INTRINSIC u8avx sub(const u8avx& x, const u8avx& y) { return _mm256_sub_epi8(x.v, y.v); } +KFR_DIV_MOD_FN(u8avx) + +KFR_INTRINSIC i8avx add(const i8avx& x, const i8avx& y) { return _mm256_add_epi8(x.v, y.v); } +KFR_INTRINSIC i8avx sub(const i8avx& x, const i8avx& y) { return _mm256_sub_epi8(x.v, y.v); } +KFR_DIV_MOD_FN(i8avx) + +KFR_INTRINSIC u16avx add(const u16avx& x, const u16avx& y) { return _mm256_add_epi16(x.v, y.v); } +KFR_INTRINSIC u16avx sub(const u16avx& x, const u16avx& y) { return _mm256_sub_epi16(x.v, y.v); } +KFR_INTRINSIC u16avx mul(const u16avx& x, const u16avx& y) { return _mm256_mullo_epi16(x.v, y.v); } +KFR_DIV_MOD_FN(u16avx) + +KFR_INTRINSIC i16avx add(const i16avx& x, const i16avx& y) { return _mm256_add_epi16(x.v, y.v); } +KFR_INTRINSIC i16avx sub(const i16avx& x, const i16avx& y) { return _mm256_sub_epi16(x.v, y.v); } +KFR_INTRINSIC i16avx mul(const i16avx& x, const i16avx& y) { return _mm256_mullo_epi16(x.v, y.v); } +KFR_DIV_MOD_FN(i16avx) + +KFR_INTRINSIC u32avx add(const u32avx& x, const u32avx& y) { return _mm256_add_epi32(x.v, y.v); } +KFR_INTRINSIC u32avx sub(const u32avx& x, const u32avx& y) { return _mm256_sub_epi32(x.v, y.v); } + +KFR_INTRINSIC i32avx add(const i32avx& x, const i32avx& y) { return _mm256_add_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx sub(const i32avx& x, const i32avx& y) { return _mm256_sub_epi32(x.v, y.v); } + +KFR_INTRINSIC u32avx mul(const u32avx& x, const u32avx& y) { return _mm256_mullo_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx mul(const i32avx& x, const i32avx& y) { return _mm256_mullo_epi32(x.v, y.v); } +KFR_DIV_MOD_FN(u32avx) +KFR_DIV_MOD_FN(i32avx) + +KFR_INTRINSIC u64avx add(const u64avx& x, const u64avx& y) { return _mm256_add_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx sub(const u64avx& x, const u64avx& y) { return _mm256_sub_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx mul(const u64avx& x, const u64avx& y) +{ + KFR_COMPONENTWISE_RET_I(u64avx, result[i] = x[i] * y[i]); +} + +KFR_INTRINSIC i64avx add(const i64avx& x, const i64avx& y) { return _mm256_add_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx sub(const i64avx& x, const i64avx& y) { return _mm256_sub_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx mul(const i64avx& x, const i64avx& y) +{ + KFR_COMPONENTWISE_RET_I(i64avx, result[i] = x[i] * y[i]); +} +KFR_DIV_MOD_FN(u64avx) +KFR_DIV_MOD_FN(i64avx) + +KFR_INTRINSIC __m256i mul_epi8(const __m256i& x, const __m256i& y) +{ + const __m256i even = _mm256_mullo_epi16(x, y); + const __m256i odd = _mm256_mullo_epi16(_mm256_srli_epi16(x, 8), _mm256_srli_epi16(y, 8)); + return _mm256_or_si256(_mm256_slli_epi16(odd, 8), _mm256_srli_epi16(_mm256_slli_epi16(even, 8), 8)); +} + +KFR_INTRINSIC u8avx mul(const u8avx& x, const u8avx& y) { return mul_epi8(x.v, y.v); } +KFR_INTRINSIC i8avx mul(const i8avx& x, const i8avx& y) { return mul_epi8(x.v, y.v); } + +KFR_INTRINSIC u8avx band(const u8avx& x, const u8avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC u16avx band(const u16avx& x, const u16avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC u32avx band(const u32avx& x, const u32avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC u64avx band(const u64avx& x, const u64avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC i8avx band(const i8avx& x, const i8avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC i16avx band(const i16avx& x, const i16avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC i32avx band(const i32avx& x, const i32avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC i64avx band(const i64avx& x, const i64avx& y) { return _mm256_and_si256(x.v, y.v); } +KFR_INTRINSIC u8avx bor(const u8avx& x, const u8avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC u16avx bor(const u16avx& x, const u16avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC u32avx bor(const u32avx& x, const u32avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC u64avx bor(const u64avx& x, const u64avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC i8avx bor(const i8avx& x, const i8avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC i16avx bor(const i16avx& x, const i16avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC i32avx bor(const i32avx& x, const i32avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC i64avx bor(const i64avx& x, const i64avx& y) { return _mm256_or_si256(x.v, y.v); } +KFR_INTRINSIC u8avx bxor(const u8avx& x, const u8avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC u16avx bxor(const u16avx& x, const u16avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC u32avx bxor(const u32avx& x, const u32avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC u64avx bxor(const u64avx& x, const u64avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC i8avx bxor(const i8avx& x, const i8avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC i16avx bxor(const i16avx& x, const i16avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC i32avx bxor(const i32avx& x, const i32avx& y) { return _mm256_xor_si256(x.v, y.v); } +KFR_INTRINSIC i64avx bxor(const i64avx& x, const i64avx& y) { return _mm256_xor_si256(x.v, y.v); } + +KFR_INTRINSIC u16avx shl(const u16avx& x, unsigned y) { return _mm256_slli_epi16(x.v, y); } +KFR_INTRINSIC u32avx shl(const u32avx& x, unsigned y) { return _mm256_slli_epi32(x.v, y); } +KFR_INTRINSIC i16avx shl(const i16avx& x, unsigned y) { return _mm256_slli_epi16(x.v, y); } +KFR_INTRINSIC i32avx shl(const i32avx& x, unsigned y) { return _mm256_slli_epi32(x.v, y); } +KFR_INTRINSIC u16avx shr(const u16avx& x, unsigned y) { return _mm256_srli_epi16(x.v, y); } +KFR_INTRINSIC u32avx shr(const u32avx& x, unsigned y) { return _mm256_srli_epi32(x.v, y); } +KFR_INTRINSIC i16avx shr(const i16avx& x, unsigned y) { return _mm256_srai_epi16(x.v, y); } +KFR_INTRINSIC i32avx shr(const i32avx& x, unsigned y) { return _mm256_srai_epi32(x.v, y); } + +KFR_INTRINSIC u64avx shl(const u64avx& x, unsigned y) { return _mm256_slli_epi64(x.v, y); } +KFR_INTRINSIC u64avx shr(const u64avx& x, unsigned y) { return _mm256_srli_epi64(x.v, y); } +KFR_INTRINSIC i64avx shl(const i64avx& x, unsigned y) { return _mm256_slli_epi64(x.v, y); } +KFR_INTRINSIC i64avx shr(const i64avx& x, unsigned y) +{ + KFR_COMPONENTWISE_RET_I(u64avx, result[i] = x[i] >> y); +} + +KFR_INTRINSIC u8avx shl(const u8avx& x, unsigned y) +{ + __m256i l = _mm256_unpacklo_epi8(_mm256_setzero_si256(), x.v); + __m256i h = _mm256_unpackhi_epi8(_mm256_setzero_si256(), x.v); + __m256i ll = _mm256_slli_epi16(l, y); + __m256i hh = _mm256_slli_epi16(h, y); + + return _mm256_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8avx shl(const i8avx& x, unsigned y) +{ + __m256i l = _mm256_unpacklo_epi8(_mm256_setzero_si256(), x.v); + __m256i h = _mm256_unpackhi_epi8(_mm256_setzero_si256(), x.v); + __m256i ll = _mm256_slli_epi16(l, y); + __m256i hh = _mm256_slli_epi16(h, y); + + return _mm256_packs_epi16(ll, hh); +} +KFR_INTRINSIC u8avx shr(const u8avx& x, unsigned y) +{ + __m256i l = _mm256_unpacklo_epi8(_mm256_setzero_si256(), x.v); + __m256i h = _mm256_unpackhi_epi8(_mm256_setzero_si256(), x.v); + __m256i ll = _mm256_srli_epi16(l, y); + __m256i hh = _mm256_srli_epi16(h, y); + + return _mm256_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8avx shr(const i8avx& x, unsigned y) +{ + __m256i l = _mm256_unpacklo_epi8(_mm256_setzero_si256(), x.v); + __m256i h = _mm256_unpackhi_epi8(_mm256_setzero_si256(), x.v); + __m256i ll = _mm256_srai_epi16(l, y); + __m256i hh = _mm256_srai_epi16(h, y); + + return _mm256_packs_epi16(ll, hh); +} + +KFR_INTRINSIC u32sse shl(const u32sse& x, const u32sse& y) { return _mm_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC i32sse shl(const i32sse& x, const u32sse& y) { return _mm_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC u64sse shl(const u64sse& x, const u64sse& y) { return _mm_sllv_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse shl(const i64sse& x, const u64sse& y) { return _mm_sllv_epi64(x.v, y.v); } + +KFR_INTRINSIC u32avx shl(const u32avx& x, const u32avx& y) { return _mm256_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx shl(const i32avx& x, const u32avx& y) { return _mm256_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx shl(const u64avx& x, const u64avx& y) { return _mm256_sllv_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx shl(const i64avx& x, const u64avx& y) { return _mm256_sllv_epi64(x.v, y.v); } + +KFR_INTRINSIC u32sse shr(const u32sse& x, const u32sse& y) { return _mm_srlv_epi32(x.v, y.v); } +KFR_INTRINSIC i32sse shr(const i32sse& x, const u32sse& y) { return _mm_srav_epi32(x.v, y.v); } +KFR_INTRINSIC u64sse shr(const u64sse& x, const u64sse& y) { return _mm_srlv_epi64(x.v, y.v); } +KFR_INTRINSIC i64sse shr(const i64sse& x, const u64sse& y) +{ + KFR_COMPONENTWISE_RET_I(i64sse, result[i] = x[i] >> y[i]); +} + +KFR_INTRINSIC u32avx shr(const u32avx& x, const u32avx& y) { return _mm256_srlv_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx shr(const i32avx& x, const u32avx& y) { return _mm256_srav_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx shr(const u64avx& x, const u64avx& y) { return _mm256_srlv_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx shr(const i64avx& x, const u64avx& y) +{ + KFR_COMPONENTWISE_RET_I(i64avx, result[i] = x[i] >> y[i]); +} + +KFR_INTRINSIC f32sse shl(const f32sse& x, const u32sse& y) +{ + return _mm_castsi128_ps(_mm_sllv_epi32(_mm_castps_si128(x.v), y.v)); +} +KFR_INTRINSIC f64sse shl(const f64sse& x, const u64sse& y) +{ + return _mm_castsi128_pd(_mm_sllv_epi64(_mm_castpd_si128(x.v), y.v)); +} +KFR_INTRINSIC f32sse shr(const f32sse& x, const u32sse& y) +{ + return _mm_castsi128_ps(_mm_srlv_epi32(_mm_castps_si128(x.v), y.v)); +} +KFR_INTRINSIC f64sse shr(const f64sse& x, const u64sse& y) +{ + return _mm_castsi128_pd(_mm_srlv_epi64(_mm_castpd_si128(x.v), y.v)); +} + +KFR_INTRINSIC f32avx shl(const f32avx& x, const u32avx& y) +{ + return _mm256_castsi256_ps(_mm256_sllv_epi32(_mm256_castps_si256(x.v), y.v)); +} +KFR_INTRINSIC f64avx shl(const f64avx& x, const u64avx& y) +{ + return _mm256_castsi256_pd(_mm256_sllv_epi64(_mm256_castpd_si256(x.v), y.v)); +} +KFR_INTRINSIC f32avx shr(const f32avx& x, const u32avx& y) +{ + return _mm256_castsi256_ps(_mm256_srlv_epi32(_mm256_castps_si256(x.v), y.v)); +} +KFR_INTRINSIC f64avx shr(const f64avx& x, const u64avx& y) +{ + return _mm256_castsi256_pd(_mm256_srlv_epi64(_mm256_castpd_si256(x.v), y.v)); +} + +KFR_INTRINSIC i8avx eq(const i8avx& x, const i8avx& y) { return _mm256_cmpeq_epi8(x.v, y.v); } +KFR_INTRINSIC i16avx eq(const i16avx& x, const i16avx& y) { return _mm256_cmpeq_epi16(x.v, y.v); } +KFR_INTRINSIC i32avx eq(const i32avx& x, const i32avx& y) { return _mm256_cmpeq_epi32(x.v, y.v); } +KFR_INTRINSIC i64avx eq(const i64avx& x, const i64avx& y) { return _mm256_cmpeq_epi64(x.v, y.v); } +KFR_INTRINSIC u8avx eq(const u8avx& x, const u8avx& y) { return _mm256_cmpeq_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx eq(const u16avx& x, const u16avx& y) { return _mm256_cmpeq_epi16(x.v, y.v); } +KFR_INTRINSIC u32avx eq(const u32avx& x, const u32avx& y) { return _mm256_cmpeq_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx eq(const u64avx& x, const u64avx& y) { return _mm256_cmpeq_epi64(x.v, y.v); } + +KFR_INTRINSIC i8avx ne(const i8avx& x, const i8avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi8(x.v, y.v)); +} +KFR_INTRINSIC i16avx ne(const i16avx& x, const i16avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi16(x.v, y.v)); +} +KFR_INTRINSIC i32avx ne(const i32avx& x, const i32avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi32(x.v, y.v)); +} +KFR_INTRINSIC i64avx ne(const i64avx& x, const i64avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi64(x.v, y.v)); +} +KFR_INTRINSIC u8avx ne(const u8avx& x, const u8avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi8(x.v, y.v)); +} +KFR_INTRINSIC u16avx ne(const u16avx& x, const u16avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi16(x.v, y.v)); +} +KFR_INTRINSIC u32avx ne(const u32avx& x, const u32avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi32(x.v, y.v)); +} +KFR_INTRINSIC u64avx ne(const u64avx& x, const u64avx& y) +{ + return _mm256_not_si256(_mm256_cmpeq_epi64(x.v, y.v)); +} + +KFR_INTRINSIC i8avx lt(const i8avx& x, const i8avx& y) { return _mm256_cmpgt_epi8(y.v, x.v); } +KFR_INTRINSIC i16avx lt(const i16avx& x, const i16avx& y) { return _mm256_cmpgt_epi16(y.v, x.v); } +KFR_INTRINSIC i32avx lt(const i32avx& x, const i32avx& y) { return _mm256_cmpgt_epi32(y.v, x.v); } +KFR_INTRINSIC i64avx lt(const i64avx& x, const i64avx& y) { return _mm256_cmpgt_epi64(y.v, x.v); } + +KFR_INTRINSIC i8avx gt(const i8avx& x, const i8avx& y) { return _mm256_cmpgt_epi8(x.v, y.v); } +KFR_INTRINSIC i16avx gt(const i16avx& x, const i16avx& y) { return _mm256_cmpgt_epi16(x.v, y.v); } +KFR_INTRINSIC i32avx gt(const i32avx& x, const i32avx& y) { return _mm256_cmpgt_epi32(x.v, y.v); } +KFR_INTRINSIC i64avx gt(const i64avx& x, const i64avx& y) { return _mm256_cmpgt_epi64(x.v, y.v); } + +KFR_INTRINSIC i8avx le(const i8avx& x, const i8avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi8(x.v, y.v)); +} +KFR_INTRINSIC i16avx le(const i16avx& x, const i16avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi16(x.v, y.v)); +} +KFR_INTRINSIC i32avx le(const i32avx& x, const i32avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi32(x.v, y.v)); +} +KFR_INTRINSIC i64avx le(const i64avx& x, const i64avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi64(x.v, y.v)); +} + +KFR_INTRINSIC i8avx ge(const i8avx& x, const i8avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi8(y.v, x.v)); +} +KFR_INTRINSIC i16avx ge(const i16avx& x, const i16avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi16(y.v, x.v)); +} +KFR_INTRINSIC i32avx ge(const i32avx& x, const i32avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi32(y.v, x.v)); +} +KFR_INTRINSIC i64avx ge(const i64avx& x, const i64avx& y) +{ + return _mm256_not_si256(_mm256_cmpgt_epi64(y.v, x.v)); +} + +KFR_INTRINSIC u8avx lt(const u8avx& x, const u8avx& y) +{ + const __m256i hb = _mm256_highbit_epi8(); + return _mm256_cmpgt_epi8(_mm256_add_epi8(y.v, hb), _mm256_add_epi8(x.v, hb)); +} +KFR_INTRINSIC u16avx lt(const u16avx& x, const u16avx& y) +{ + const __m256i hb = _mm256_highbit_epi16(); + return _mm256_cmpgt_epi16(_mm256_add_epi16(y.v, hb), _mm256_add_epi16(x.v, hb)); +} +KFR_INTRINSIC u32avx lt(const u32avx& x, const u32avx& y) +{ + const __m256i hb = _mm256_highbit_epi32(); + return _mm256_cmpgt_epi32(_mm256_add_epi32(y.v, hb), _mm256_add_epi32(x.v, hb)); +} +KFR_INTRINSIC u64avx lt(const u64avx& x, const u64avx& y) +{ + const __m256i hb = _mm256_highbit_epi64(); + return _mm256_cmpgt_epi64(_mm256_add_epi64(y.v, hb), _mm256_add_epi64(x.v, hb)); +} +KFR_INTRINSIC u8avx gt(const u8avx& x, const u8avx& y) +{ + const __m256i hb = _mm256_highbit_epi8(); + return _mm256_cmpgt_epi8(_mm256_add_epi8(x.v, hb), _mm256_add_epi8(y.v, hb)); +} +KFR_INTRINSIC u16avx gt(const u16avx& x, const u16avx& y) +{ + const __m256i hb = _mm256_highbit_epi16(); + return _mm256_cmpgt_epi16(_mm256_add_epi16(x.v, hb), _mm256_add_epi16(y.v, hb)); +} +KFR_INTRINSIC u32avx gt(const u32avx& x, const u32avx& y) +{ + const __m256i hb = _mm256_highbit_epi32(); + return _mm256_cmpgt_epi32(_mm256_add_epi32(x.v, hb), _mm256_add_epi32(y.v, hb)); +} +KFR_INTRINSIC u64avx gt(const u64avx& x, const u64avx& y) +{ + const __m256i hb = _mm256_highbit_epi64(); + return _mm256_cmpgt_epi64(_mm256_add_epi64(x.v, hb), _mm256_add_epi64(y.v, hb)); +} +KFR_INTRINSIC u8avx le(const u8avx& x, const u8avx& y) +{ + const __m256i hb = _mm256_highbit_epi8(); + return _mm256_not_si256(_mm256_cmpgt_epi8(_mm256_add_epi8(x.v, hb), _mm256_add_epi8(y.v, hb))); +} +KFR_INTRINSIC u16avx le(const u16avx& x, const u16avx& y) +{ + const __m256i hb = _mm256_highbit_epi16(); + return _mm256_not_si256(_mm256_cmpgt_epi16(_mm256_add_epi16(x.v, hb), _mm256_add_epi16(y.v, hb))); +} +KFR_INTRINSIC u32avx le(const u32avx& x, const u32avx& y) +{ + const __m256i hb = _mm256_highbit_epi32(); + return _mm256_not_si256(_mm256_cmpgt_epi32(_mm256_add_epi32(x.v, hb), _mm256_add_epi32(y.v, hb))); +} +KFR_INTRINSIC u64avx le(const u64avx& x, const u64avx& y) +{ + const __m256i hb = _mm256_highbit_epi64(); + return _mm256_not_si256(_mm256_cmpgt_epi64(_mm256_add_epi64(x.v, hb), _mm256_add_epi64(y.v, hb))); +} +KFR_INTRINSIC u8avx ge(const u8avx& x, const u8avx& y) +{ + const __m256i hb = _mm256_highbit_epi8(); + return _mm256_not_si256(_mm256_cmpgt_epi8(_mm256_add_epi8(y.v, hb), _mm256_add_epi8(x.v, hb))); +} +KFR_INTRINSIC u16avx ge(const u16avx& x, const u16avx& y) +{ + const __m256i hb = _mm256_highbit_epi16(); + return _mm256_not_si256(_mm256_cmpgt_epi16(_mm256_add_epi16(y.v, hb), _mm256_add_epi16(x.v, hb))); +} +KFR_INTRINSIC u32avx ge(const u32avx& x, const u32avx& y) +{ + const __m256i hb = _mm256_highbit_epi32(); + return _mm256_not_si256(_mm256_cmpgt_epi32(_mm256_add_epi32(y.v, hb), _mm256_add_epi32(x.v, hb))); +} +KFR_INTRINSIC u64avx ge(const u64avx& x, const u64avx& y) +{ + const __m256i hb = _mm256_highbit_epi64(); + return _mm256_not_si256(_mm256_cmpgt_epi64(_mm256_add_epi64(y.v, hb), _mm256_add_epi64(x.v, hb))); +} + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC f32avx512 add(const f32avx512& x, const f32avx512& y) { return _mm512_add_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 add(const f64avx512& x, const f64avx512& y) { return _mm512_add_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 sub(const f32avx512& x, const f32avx512& y) { return _mm512_sub_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 sub(const f64avx512& x, const f64avx512& y) { return _mm512_sub_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 mul(const f32avx512& x, const f32avx512& y) { return _mm512_mul_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 mul(const f64avx512& x, const f64avx512& y) { return _mm512_mul_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 div(const f32avx512& x, const f32avx512& y) { return _mm512_div_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 div(const f64avx512& x, const f64avx512& y) { return _mm512_div_pd(x.v, y.v); } + +KFR_INTRINSIC __m512 _mm512_allones_ps() +{ + return _mm512_castsi512_ps(_mm512_ternarylogic_epi32(_mm512_setzero_si512(), _mm512_setzero_si512(), + _mm512_setzero_si512(), 0xFF)); +} + +KFR_INTRINSIC __m512d _mm512_allones_pd() +{ + return _mm512_castsi512_pd(_mm512_ternarylogic_epi32(_mm512_setzero_si512(), _mm512_setzero_si512(), + _mm512_setzero_si512(), 0xFF)); +} + +KFR_INTRINSIC __m512i _mm512_allones_si512() +{ + return _mm512_ternarylogic_epi32(_mm512_setzero_si512(), _mm512_setzero_si512(), _mm512_setzero_si512(), + 0xFF); +} + +KFR_INTRINSIC __m512 _mm512_not_ps(const __m512& x) { return _mm512_xor_ps(x, _mm512_allones_ps()); } +KFR_INTRINSIC __m512d _mm512_not_pd(const __m512d& x) { return _mm512_xor_pd(x, _mm512_allones_pd()); } +KFR_INTRINSIC __m512i _mm512_not_si512(const __m512i& x) +{ + return _mm512_xor_si512(x, _mm512_allones_si512()); +} + +KFR_INTRINSIC __m512i _mm512_highbit_epi8() { return _mm512_set1_epi8(static_cast(0x80)); } +KFR_INTRINSIC __m512i _mm512_highbit_epi16() { return _mm512_set1_epi16(static_cast(0x8000)); } +KFR_INTRINSIC __m512i _mm512_highbit_epi32() { return _mm512_set1_epi32(static_cast(0x80000000)); } +KFR_INTRINSIC __m512i _mm512_highbit_epi64() { return _mm512_set1_epi64(0x8000000000000000ll); } + +KFR_INTRINSIC f32avx512 eq(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_EQ_OQ))); +} +KFR_INTRINSIC f64avx512 eq(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_EQ_OQ))); +} +KFR_INTRINSIC f32avx512 ne(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_NEQ_OQ))); +} +KFR_INTRINSIC f64avx512 ne(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_NEQ_OQ))); +} +KFR_INTRINSIC f32avx512 lt(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_LT_OQ))); +} +KFR_INTRINSIC f64avx512 lt(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_LT_OQ))); +} +KFR_INTRINSIC f32avx512 gt(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_GT_OQ))); +} +KFR_INTRINSIC f64avx512 gt(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_GT_OQ))); +} +KFR_INTRINSIC f32avx512 le(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_LE_OQ))); +} +KFR_INTRINSIC f64avx512 le(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_LE_OQ))); +} +KFR_INTRINSIC f32avx512 ge(const f32avx512& x, const f32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_movm_epi32(_mm512_cmp_ps_mask(x.v, y.v, _CMP_GE_OQ))); +} +KFR_INTRINSIC f64avx512 ge(const f64avx512& x, const f64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(x.v, y.v, _CMP_GE_OQ))); +} + +KFR_INTRINSIC f32avx512 band(const f32avx512& x, const f32avx512& y) { return _mm512_and_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 band(const f64avx512& x, const f64avx512& y) { return _mm512_and_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 bor(const f32avx512& x, const f32avx512& y) { return _mm512_or_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 bor(const f64avx512& x, const f64avx512& y) { return _mm512_or_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 bxor(const f32avx512& x, const f32avx512& y) { return _mm512_xor_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 bxor(const f64avx512& x, const f64avx512& y) { return _mm512_xor_pd(x.v, y.v); } + +#if 1 +#define KFR_knot_mask8(x) ((__mmask8)(~((u8)(x)))) +#define KFR_knot_mask16(x) ((__mmask16)(~((u16)(x)))) +#define KFR_knot_mask32(x) ((__mmask32)(~((u32)(x)))) +#define KFR_knot_mask64(x) ((__mmask64)(~((u64)(x)))) +#else +#define KFR_knot_mask8(x) _knot_mask8(x) +#define KFR_knot_mask16(x) _knot_mask16(x) +#define KFR_knot_mask32(x) _knot_mask32(x) +#define KFR_knot_mask64(x) _knot_mask64(x) +#endif + +KFR_INTRINSIC i8avx512 eq(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmpeq_epi8_mask(x.v, y.v)); +} +KFR_INTRINSIC i16avx512 eq(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmpeq_epi16_mask(x.v, y.v)); +} +KFR_INTRINSIC i32avx512 eq(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmpeq_epi32_mask(x.v, y.v)); +} +KFR_INTRINSIC i64avx512 eq(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmpeq_epi64_mask(x.v, y.v)); +} +KFR_INTRINSIC i8avx512 ne(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmpeq_epi8_mask(x.v, y.v))); +} +KFR_INTRINSIC i16avx512 ne(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmpeq_epi16_mask(x.v, y.v))); +} +KFR_INTRINSIC i32avx512 ne(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmpeq_epi32_mask(x.v, y.v))); +} +KFR_INTRINSIC i64avx512 ne(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmpeq_epi64_mask(x.v, y.v))); +} +KFR_INTRINSIC i8avx512 ge(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmplt_epi8_mask(x.v, y.v))); +} +KFR_INTRINSIC i16avx512 ge(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmplt_epi16_mask(x.v, y.v))); +} +KFR_INTRINSIC i32avx512 ge(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmplt_epi32_mask(x.v, y.v))); +} +KFR_INTRINSIC i64avx512 ge(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmplt_epi64_mask(x.v, y.v))); +} +KFR_INTRINSIC i8avx512 lt(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmplt_epi8_mask(x.v, y.v)); +} +KFR_INTRINSIC i16avx512 lt(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmplt_epi16_mask(x.v, y.v)); +} +KFR_INTRINSIC i32avx512 lt(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmplt_epi32_mask(x.v, y.v)); +} +KFR_INTRINSIC i64avx512 lt(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmplt_epi64_mask(x.v, y.v)); +} +KFR_INTRINSIC i8avx512 le(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmplt_epi8_mask(y.v, x.v))); +} +KFR_INTRINSIC i16avx512 le(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmplt_epi16_mask(y.v, x.v))); +} +KFR_INTRINSIC i32avx512 le(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmplt_epi32_mask(y.v, x.v))); +} +KFR_INTRINSIC i64avx512 le(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmplt_epi64_mask(y.v, x.v))); +} +KFR_INTRINSIC i8avx512 gt(const i8avx512& x, const i8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmplt_epi8_mask(y.v, x.v)); +} +KFR_INTRINSIC i16avx512 gt(const i16avx512& x, const i16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmplt_epi16_mask(y.v, x.v)); +} +KFR_INTRINSIC i32avx512 gt(const i32avx512& x, const i32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmplt_epi32_mask(y.v, x.v)); +} +KFR_INTRINSIC i64avx512 gt(const i64avx512& x, const i64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmplt_epi64_mask(y.v, x.v)); +} + +KFR_INTRINSIC u8avx512 eq(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmpeq_epu8_mask(x.v, y.v)); +} +KFR_INTRINSIC u16avx512 eq(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmpeq_epu16_mask(x.v, y.v)); +} +KFR_INTRINSIC u32avx512 eq(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmpeq_epu32_mask(x.v, y.v)); +} +KFR_INTRINSIC u64avx512 eq(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmpeq_epu64_mask(x.v, y.v)); +} +KFR_INTRINSIC u8avx512 ne(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmpeq_epu8_mask(x.v, y.v))); +} +KFR_INTRINSIC u16avx512 ne(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmpeq_epu16_mask(x.v, y.v))); +} +KFR_INTRINSIC u32avx512 ne(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmpeq_epu32_mask(x.v, y.v))); +} +KFR_INTRINSIC u64avx512 ne(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmpeq_epu64_mask(x.v, y.v))); +} +KFR_INTRINSIC u8avx512 ge(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmplt_epu8_mask(x.v, y.v))); +} +KFR_INTRINSIC u16avx512 ge(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmplt_epu16_mask(x.v, y.v))); +} +KFR_INTRINSIC u32avx512 ge(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmplt_epu32_mask(x.v, y.v))); +} +KFR_INTRINSIC u64avx512 ge(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmplt_epu64_mask(x.v, y.v))); +} +KFR_INTRINSIC u8avx512 lt(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmplt_epu8_mask(x.v, y.v)); +} +KFR_INTRINSIC u16avx512 lt(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmplt_epu16_mask(x.v, y.v)); +} +KFR_INTRINSIC u32avx512 lt(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmplt_epu32_mask(x.v, y.v)); +} +KFR_INTRINSIC u64avx512 lt(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmplt_epu64_mask(x.v, y.v)); +} +KFR_INTRINSIC u8avx512 le(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(KFR_knot_mask64(_mm512_cmplt_epu8_mask(y.v, x.v))); +} +KFR_INTRINSIC u16avx512 le(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(KFR_knot_mask32(_mm512_cmplt_epu16_mask(y.v, x.v))); +} +KFR_INTRINSIC u32avx512 le(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(KFR_knot_mask16(_mm512_cmplt_epu32_mask(y.v, x.v))); +} +KFR_INTRINSIC u64avx512 le(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(KFR_knot_mask8(_mm512_cmplt_epu64_mask(y.v, x.v))); +} +KFR_INTRINSIC u8avx512 gt(const u8avx512& x, const u8avx512& y) +{ + return _mm512_movm_epi8(_mm512_cmplt_epu8_mask(y.v, x.v)); +} +KFR_INTRINSIC u16avx512 gt(const u16avx512& x, const u16avx512& y) +{ + return _mm512_movm_epi16(_mm512_cmplt_epu16_mask(y.v, x.v)); +} +KFR_INTRINSIC u32avx512 gt(const u32avx512& x, const u32avx512& y) +{ + return _mm512_movm_epi32(_mm512_cmplt_epu32_mask(y.v, x.v)); +} +KFR_INTRINSIC u64avx512 gt(const u64avx512& x, const u64avx512& y) +{ + return _mm512_movm_epi64(_mm512_cmplt_epu64_mask(y.v, x.v)); +} + +KFR_INTRINSIC i8avx512 add(const i8avx512& x, const i8avx512& y) { return _mm512_add_epi8(x.v, y.v); } +KFR_INTRINSIC i16avx512 add(const i16avx512& x, const i16avx512& y) { return _mm512_add_epi16(x.v, y.v); } +KFR_INTRINSIC i32avx512 add(const i32avx512& x, const i32avx512& y) { return _mm512_add_epi32(x.v, y.v); } +KFR_INTRINSIC i64avx512 add(const i64avx512& x, const i64avx512& y) { return _mm512_add_epi64(x.v, y.v); } +KFR_INTRINSIC u8avx512 add(const u8avx512& x, const u8avx512& y) { return _mm512_add_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 add(const u16avx512& x, const u16avx512& y) { return _mm512_add_epi16(x.v, y.v); } +KFR_INTRINSIC u32avx512 add(const u32avx512& x, const u32avx512& y) { return _mm512_add_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx512 add(const u64avx512& x, const u64avx512& y) { return _mm512_add_epi64(x.v, y.v); } + +KFR_INTRINSIC i8avx512 sub(const i8avx512& x, const i8avx512& y) { return _mm512_sub_epi8(x.v, y.v); } +KFR_INTRINSIC i16avx512 sub(const i16avx512& x, const i16avx512& y) { return _mm512_sub_epi16(x.v, y.v); } +KFR_INTRINSIC i32avx512 sub(const i32avx512& x, const i32avx512& y) { return _mm512_sub_epi32(x.v, y.v); } +KFR_INTRINSIC i64avx512 sub(const i64avx512& x, const i64avx512& y) { return _mm512_sub_epi64(x.v, y.v); } +KFR_INTRINSIC u8avx512 sub(const u8avx512& x, const u8avx512& y) { return _mm512_sub_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 sub(const u16avx512& x, const u16avx512& y) { return _mm512_sub_epi16(x.v, y.v); } +KFR_INTRINSIC u32avx512 sub(const u32avx512& x, const u32avx512& y) { return _mm512_sub_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx512 sub(const u64avx512& x, const u64avx512& y) { return _mm512_sub_epi64(x.v, y.v); } + +KFR_INTRINSIC __m512i mul_epi8(const __m512i& x, const __m512i& y) +{ + const __m512i even = _mm512_mullo_epi16(x, y); + const __m512i odd = _mm512_mullo_epi16(_mm512_srli_epi16(x, 8), _mm512_srli_epi16(y, 8)); + return _mm512_or_si512(_mm512_slli_epi16(odd, 8), _mm512_srli_epi16(_mm512_slli_epi16(even, 8), 8)); +} + +KFR_INTRINSIC i8avx512 mul(const i8avx512& x, const i8avx512& y) { return mul_epi8(x.v, y.v); } +KFR_INTRINSIC i16avx512 mul(const i16avx512& x, const i16avx512& y) { return _mm512_mullo_epi16(x.v, y.v); } +KFR_INTRINSIC i32avx512 mul(const i32avx512& x, const i32avx512& y) { return _mm512_mullo_epi32(x.v, y.v); } +KFR_INTRINSIC i64avx512 mul(const i64avx512& x, const i64avx512& y) { return _mm512_mullo_epi64(x.v, y.v); } +KFR_INTRINSIC u8avx512 mul(const u8avx512& x, const u8avx512& y) { return mul_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 mul(const u16avx512& x, const u16avx512& y) { return _mm512_mullo_epi16(x.v, y.v); } +KFR_INTRINSIC u32avx512 mul(const u32avx512& x, const u32avx512& y) { return _mm512_mullo_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx512 mul(const u64avx512& x, const u64avx512& y) { return _mm512_mullo_epi64(x.v, y.v); } + +KFR_DIV_MOD_FN(i8avx512) +KFR_DIV_MOD_FN(i16avx512) +KFR_DIV_MOD_FN(i32avx512) +KFR_DIV_MOD_FN(i64avx512) +KFR_DIV_MOD_FN(u8avx512) +KFR_DIV_MOD_FN(u16avx512) +KFR_DIV_MOD_FN(u32avx512) +KFR_DIV_MOD_FN(u64avx512) + +KFR_INTRINSIC i8avx512 band(const i8avx512& x, const i8avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC i16avx512 band(const i16avx512& x, const i16avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC i32avx512 band(const i32avx512& x, const i32avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC i64avx512 band(const i64avx512& x, const i64avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC u8avx512 band(const u8avx512& x, const u8avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC u16avx512 band(const u16avx512& x, const u16avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC u32avx512 band(const u32avx512& x, const u32avx512& y) { return _mm512_and_si512(x.v, y.v); } +KFR_INTRINSIC u64avx512 band(const u64avx512& x, const u64avx512& y) { return _mm512_and_si512(x.v, y.v); } + +KFR_INTRINSIC i8avx512 bor(const i8avx512& x, const i8avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC i16avx512 bor(const i16avx512& x, const i16avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC i32avx512 bor(const i32avx512& x, const i32avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC i64avx512 bor(const i64avx512& x, const i64avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC u8avx512 bor(const u8avx512& x, const u8avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC u16avx512 bor(const u16avx512& x, const u16avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC u32avx512 bor(const u32avx512& x, const u32avx512& y) { return _mm512_or_si512(x.v, y.v); } +KFR_INTRINSIC u64avx512 bor(const u64avx512& x, const u64avx512& y) { return _mm512_or_si512(x.v, y.v); } + +KFR_INTRINSIC i8avx512 bxor(const i8avx512& x, const i8avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC i16avx512 bxor(const i16avx512& x, const i16avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC i32avx512 bxor(const i32avx512& x, const i32avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC i64avx512 bxor(const i64avx512& x, const i64avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC u8avx512 bxor(const u8avx512& x, const u8avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC u16avx512 bxor(const u16avx512& x, const u16avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC u32avx512 bxor(const u32avx512& x, const u32avx512& y) { return _mm512_xor_si512(x.v, y.v); } +KFR_INTRINSIC u64avx512 bxor(const u64avx512& x, const u64avx512& y) { return _mm512_xor_si512(x.v, y.v); } + +KFR_INTRINSIC f32avx512 shl(const f32avx512& x, unsigned y) +{ + return _mm512_castsi512_ps(_mm512_slli_epi32(_mm512_castps_si512(x.v), y)); +} +KFR_INTRINSIC f64avx512 shl(const f64avx512& x, unsigned y) +{ + return _mm512_castsi512_pd(_mm512_slli_epi64(_mm512_castpd_si512(x.v), y)); +} +KFR_INTRINSIC f32avx512 shr(const f32avx512& x, unsigned y) +{ + return _mm512_castsi512_ps(_mm512_srli_epi32(_mm512_castps_si512(x.v), y)); +} +KFR_INTRINSIC f64avx512 shr(const f64avx512& x, unsigned y) +{ + return _mm512_castsi512_pd(_mm512_srli_epi64(_mm512_castpd_si512(x.v), y)); +} + +KFR_INTRINSIC u16avx512 shl(const u16avx512& x, unsigned y) { return _mm512_slli_epi16(x.v, y); } +KFR_INTRINSIC u32avx512 shl(const u32avx512& x, unsigned y) { return _mm512_slli_epi32(x.v, y); } +KFR_INTRINSIC i16avx512 shl(const i16avx512& x, unsigned y) { return _mm512_slli_epi16(x.v, y); } +KFR_INTRINSIC i32avx512 shl(const i32avx512& x, unsigned y) { return _mm512_slli_epi32(x.v, y); } +KFR_INTRINSIC u16avx512 shr(const u16avx512& x, unsigned y) { return _mm512_srli_epi16(x.v, y); } +KFR_INTRINSIC u32avx512 shr(const u32avx512& x, unsigned y) { return _mm512_srli_epi32(x.v, y); } +KFR_INTRINSIC i16avx512 shr(const i16avx512& x, unsigned y) { return _mm512_srai_epi16(x.v, y); } +KFR_INTRINSIC i32avx512 shr(const i32avx512& x, unsigned y) { return _mm512_srai_epi32(x.v, y); } + +KFR_INTRINSIC u64avx512 shl(const u64avx512& x, unsigned y) { return _mm512_slli_epi64(x.v, y); } +KFR_INTRINSIC u64avx512 shr(const u64avx512& x, unsigned y) { return _mm512_srli_epi64(x.v, y); } +KFR_INTRINSIC i64avx512 shl(const i64avx512& x, unsigned y) { return _mm512_slli_epi64(x.v, y); } +KFR_INTRINSIC i64avx512 shr(const i64avx512& x, unsigned y) +{ + KFR_COMPONENTWISE_RET_I(u64avx512, result[i] = x[i] >> y); +} + +KFR_INTRINSIC u8avx512 shl(const u8avx512& x, unsigned y) +{ + __m512i l = _mm512_unpacklo_epi8(_mm512_setzero_si512(), x.v); + __m512i h = _mm512_unpackhi_epi8(_mm512_setzero_si512(), x.v); + __m512i ll = _mm512_slli_epi16(l, y); + __m512i hh = _mm512_slli_epi16(h, y); + + return _mm512_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8avx512 shl(const i8avx512& x, unsigned y) +{ + __m512i l = _mm512_unpacklo_epi8(_mm512_setzero_si512(), x.v); + __m512i h = _mm512_unpackhi_epi8(_mm512_setzero_si512(), x.v); + __m512i ll = _mm512_slli_epi16(l, y); + __m512i hh = _mm512_slli_epi16(h, y); + + return _mm512_packs_epi16(ll, hh); +} +KFR_INTRINSIC u8avx512 shr(const u8avx512& x, unsigned y) +{ + __m512i l = _mm512_unpacklo_epi8(_mm512_setzero_si512(), x.v); + __m512i h = _mm512_unpackhi_epi8(_mm512_setzero_si512(), x.v); + __m512i ll = _mm512_srli_epi16(l, y); + __m512i hh = _mm512_srli_epi16(h, y); + + return _mm512_packs_epi16(ll, hh); +} +KFR_INTRINSIC i8avx512 shr(const i8avx512& x, unsigned y) +{ + __m512i l = _mm512_unpacklo_epi8(_mm512_setzero_si512(), x.v); + __m512i h = _mm512_unpackhi_epi8(_mm512_setzero_si512(), x.v); + __m512i ll = _mm512_srai_epi16(l, y); + __m512i hh = _mm512_srai_epi16(h, y); + + return _mm512_packs_epi16(ll, hh); +} + +KFR_INTRINSIC u32avx512 shl(const u32avx512& x, const u32avx512& y) { return _mm512_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx512 shl(const i32avx512& x, const u32avx512& y) { return _mm512_sllv_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx512 shl(const u64avx512& x, const u64avx512& y) { return _mm512_sllv_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx512 shl(const i64avx512& x, const u64avx512& y) { return _mm512_sllv_epi64(x.v, y.v); } + +KFR_INTRINSIC u32avx512 shr(const u32avx512& x, const u32avx512& y) { return _mm512_srlv_epi32(x.v, y.v); } +KFR_INTRINSIC i32avx512 shr(const i32avx512& x, const u32avx512& y) { return _mm512_srav_epi32(x.v, y.v); } +KFR_INTRINSIC u64avx512 shr(const u64avx512& x, const u64avx512& y) { return _mm512_srlv_epi64(x.v, y.v); } +KFR_INTRINSIC i64avx512 shr(const i64avx512& x, const u64avx512& y) { return _mm512_srav_epi64(x.v, y.v); } + +KFR_INTRINSIC f32avx512 shl(const f32avx512& x, const u32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_sllv_epi32(_mm512_castps_si512(x.v), y.v)); +} +KFR_INTRINSIC f64avx512 shl(const f64avx512& x, const u64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_sllv_epi64(_mm512_castpd_si512(x.v), y.v)); +} +KFR_INTRINSIC f32avx512 shr(const f32avx512& x, const u32avx512& y) +{ + return _mm512_castsi512_ps(_mm512_srlv_epi32(_mm512_castps_si512(x.v), y.v)); +} +KFR_INTRINSIC f64avx512 shr(const f64avx512& x, const u64avx512& y) +{ + return _mm512_castsi512_pd(_mm512_srlv_epi64(_mm512_castpd_si512(x.v), y.v)); +} + +#endif + +#endif + +#endif + +#define KFR_HANDLE_ALL_SIZES_SHIFT_2(fn) \ + template && !is_simd_size(N) && is_simd_type)> \ + KFR_INTRINSIC vec fn(const vec& a, const unsigned b) \ + { \ + return slice<0, N>(fn(expand_simd(a), b)); \ + } \ + template vector_width && is_simd_type), typename = void> \ + KFR_INTRINSIC vec fn(const vec& a, const unsigned b) \ + { \ + return concat(fn(low(a), b), fn(high(a), b)); \ + } +#define KFR_HANDLE_ALL_SIZES_SHIFT_VAR_2(fn) \ + template && !is_simd_size(N) && is_simd_type)> \ + KFR_INTRINSIC vec fn(const vec& a, const vec, N>& b) \ + { \ + return slice<0, N>(fn(expand_simd(a), expand_simd(b))); \ + } \ + template vector_width && is_simd_type), typename = void> \ + KFR_INTRINSIC vec fn(const vec& a, const vec, N>& b) \ + { \ + return concat(fn(low(a), low(b)), fn(high(a), high(b))); \ + } + +KFR_HANDLE_ALL_SIZES_2(add) +KFR_HANDLE_ALL_SIZES_2(sub) +KFR_HANDLE_ALL_SIZES_2(mul) +KFR_HANDLE_ALL_SIZES_2(div) +KFR_HANDLE_ALL_SIZES_2(mod) + +KFR_HANDLE_ALL_SIZES_2(eq) +KFR_HANDLE_ALL_SIZES_2(ne) +KFR_HANDLE_ALL_SIZES_2(lt) +KFR_HANDLE_ALL_SIZES_2(gt) +KFR_HANDLE_ALL_SIZES_2(le) +KFR_HANDLE_ALL_SIZES_2(ge) + +KFR_HANDLE_ALL_SIZES_2(band) +KFR_HANDLE_ALL_SIZES_2(bor) +KFR_HANDLE_ALL_SIZES_2(bxor) + +KFR_HANDLE_ALL_SIZES_SHIFT_2(shl) +KFR_HANDLE_ALL_SIZES_SHIFT_2(shr) +KFR_HANDLE_ALL_SIZES_SHIFT_VAR_2(shl) +KFR_HANDLE_ALL_SIZES_SHIFT_VAR_2(shr) + +#else + +template )> +KFR_INTRINSIC vec shl(const vec& x, const vec, N>& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) << y[i]))); +} +template )> +KFR_INTRINSIC vec shl(const vec& x, unsigned y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) << y))); +} +template )> +KFR_INTRINSIC vec shr(const vec& x, const vec, N>& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) >> y[i]))); +} +template )> +KFR_INTRINSIC vec shr(const vec& x, unsigned y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(uibitcast(x[i]) >> y))); +} + +template )> +KFR_INTRINSIC vec eq(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] == y[i])); +} +template )> +KFR_INTRINSIC vec ne(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] != y[i])); +} +template )> +KFR_INTRINSIC vec ge(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] >= y[i])); +} +template )> +KFR_INTRINSIC vec le(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] <= y[i])); +} +template )> +KFR_INTRINSIC vec gt(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] > y[i])); +} +template )> +KFR_INTRINSIC vec lt(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = maskbits(x[i] < y[i])); +} + +template )> +KFR_INTRINSIC vec bor(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>((ubitcast(x[i]) | ubitcast(y[i]))))); +} +template )> +KFR_INTRINSIC vec bxor(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(ubitcast(x[i]) ^ ubitcast(y[i])))); +} +template )> +KFR_INTRINSIC vec band(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = bitcast(static_cast>(ubitcast(x[i]) & ubitcast(y[i])))); +} + +template )> +KFR_INTRINSIC vec add(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = x[i] + y[i]); +} +template )> +KFR_INTRINSIC vec sub(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = x[i] - y[i]); +} +template )> +KFR_INTRINSIC vec mul(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = x[i] * y[i]); +} +template )> +KFR_INTRINSIC vec div(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = x[i] / y[i]); +} +template )> +KFR_INTRINSIC vec mod(const vec& x, const vec& y) +{ + KFR_COMPONENTWISE_RET(result[i] = x[i] % y[i]); +} + +#define KFR_HANDLE_VEC_SCA(fn) \ + template )> \ + KFR_INTRINSIC vec fn(const vec& x, const T& y) \ + { \ + return fn(x, vec(y)); \ + } \ + template )> \ + KFR_INTRINSIC vec fn(const T& x, const vec& y) \ + { \ + return fn(vec(x), y); \ + } + +KFR_HANDLE_VEC_SCA(add) +KFR_HANDLE_VEC_SCA(sub) +KFR_HANDLE_VEC_SCA(mul) +KFR_HANDLE_VEC_SCA(div) +KFR_HANDLE_VEC_SCA(mod) +KFR_HANDLE_VEC_SCA(band) +KFR_HANDLE_VEC_SCA(bor) +KFR_HANDLE_VEC_SCA(bxor) +KFR_HANDLE_VEC_SCA(eq) +KFR_HANDLE_VEC_SCA(ne) +KFR_HANDLE_VEC_SCA(lt) +KFR_HANDLE_VEC_SCA(gt) +KFR_HANDLE_VEC_SCA(le) +KFR_HANDLE_VEC_SCA(ge) + +#endif + +template +KFR_INTRINSIC vec bnot(const vec& x) +{ + return bxor(special_constants::allones(), x); +} + +template )> +KFR_INTRINSIC vec neg(const vec& x) +{ + return sub(T(0), x); +} +template )> +KFR_INTRINSIC vec neg(const vec& x) +{ + return bxor(special_constants::highbitmask(), x); +} + +template +KFR_INTRINSIC vec, N> bxor(const vec, N>& x, const vec, N>& y) +{ + return bxor(vec(x.v), vec(y.v)).v; +} +template +KFR_INTRINSIC vec, N> bor(const vec, N>& x, const vec, N>& y) +{ + return bor(vec(x.v), vec(y.v)).v; +} +template +KFR_INTRINSIC vec, N> band(const vec, N>& x, const vec, N>& y) +{ + return band(vec(x.v), vec(y.v)).v; +} +template +KFR_INTRINSIC vec, N> bnot(const vec, N>& x) +{ + return bnot(vec(x.v)).v; +} + +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/clamp.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/clamp.hpp new file mode 100644 index 00000000..06954cf6 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/clamp.hpp @@ -0,0 +1,55 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../min_max.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +KFR_INTRINSIC T clamp(const T& x, const T& lo, const T& hi) +{ + return max(min(x, hi), lo); +} + +template +KFR_INTRINSIC vec clamp(const vec& x, const vec& lo, const vec& hi) +{ + return max(min(x, hi), lo); +} + +template +KFR_INTRINSIC vec clamp(const vec& x, const vec& hi) +{ + return max(min(x, hi), zerovector()); +} +} // namespace intrinsics +KFR_I_FN(clamp) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/function.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/function.hpp new file mode 100644 index 00000000..7789deb3 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/function.hpp @@ -0,0 +1,335 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../shuffle.hpp" +#include "../types.hpp" +#include "../vec.hpp" + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +#define KFR_HANDLE_NOT_F_1(fn) \ + template )> \ + KFR_INTRINSIC vec, N> fn(const vec& a) CMT_NOEXCEPT \ + { \ + return intrinsics::fn(promoteto>(a)); \ + } + +#define KFR_HANDLE_SCALAR(fn) \ + template , \ + KFR_ENABLE_IF(!(is_vec || (is_vec || ...)))> \ + KFR_INTRINSIC Tout fn(const T1& a, const Args&... b) CMT_NOEXCEPT \ + { \ + using vecout = vec1; \ + return to_scalar(::kfr::intrinsics::fn(vecout(a), vecout(b)...)); \ + } + +#define KFR_HANDLE_SCALAR_1_T(fn, Tout) \ + template , \ + KFR_ENABLE_IF(!(is_vec || (is_vec || ...)))> \ + KFR_INTRINSIC Tout fn(const T1& a, const Args&... b) CMT_NOEXCEPT \ + { \ + using vecout = vec1; \ + return to_scalar(::kfr::intrinsics::fn(vecout(a), vecout(b)...)); \ + } + +#define KFR_HANDLE_ARGS_T(fn, Tout) \ + template , \ + KFR_ENABLE_IF((is_vec || (is_vec || ...)))> \ + KFR_INTRINSIC Tout fn(const T1& a, const Args&... b) CMT_NOEXCEPT \ + { \ + using vecout = vec1; \ + return to_scalar(::kfr::intrinsics::fn(vecout(a), vecout(b)...)); \ + } + +namespace intrinsics +{ +#ifdef CMT_ARCH_X86 +using f32sse = vec; +using f64sse = vec; +using i8sse = vec; +using i16sse = vec; +using i32sse = vec; +using i64sse = vec; +using u8sse = vec; +using u16sse = vec; +using u32sse = vec; +using u64sse = vec; + +using f32avx = vec; +using f64avx = vec; +using i8avx = vec; +using i16avx = vec; +using i32avx = vec; +using i64avx = vec; +using u8avx = vec; +using u16avx = vec; +using u32avx = vec; +using u64avx = vec; + +using f32avx512 = vec; +using f64avx512 = vec; +using i8avx512 = vec; +using i16avx512 = vec; +using i32avx512 = vec; +using i64avx512 = vec; +using u8avx512 = vec; +using u16avx512 = vec; +using u32avx512 = vec; +using u64avx512 = vec; + +using mf32sse = mask; +using mf64sse = mask; +using mi8sse = mask; +using mi16sse = mask; +using mi32sse = mask; +using mi64sse = mask; +using mu8sse = mask; +using mu16sse = mask; +using mu32sse = mask; +using mu64sse = mask; + +using mf32avx = mask; +using mf64avx = mask; +using mi8avx = mask; +using mi16avx = mask; +using mi32avx = mask; +using mi64avx = mask; +using mu8avx = mask; +using mu16avx = mask; +using mu32avx = mask; +using mu64avx = mask; + +using mf32avx512 = mask; +using mf64avx512 = mask; +using mi8avx512 = mask; +using mi16avx512 = mask; +using mi32avx512 = mask; +using mi64avx512 = mask; +using mu8avx512 = mask; +using mu16avx512 = mask; +using mu32avx512 = mask; +using mu64avx512 = mask; + +#else +using f32neon = vec; +using f64neon = vec; +using i8neon = vec; +using i16neon = vec; +using i32neon = vec; +using i64neon = vec; +using u8neon = vec; +using u16neon = vec; +using u32neon = vec; +using u64neon = vec; + +using mf32neon = mask; +using mf64neon = mask; +using mi8neon = mask; +using mi16neon = mask; +using mi32neon = mask; +using mi64neon = mask; +using mu8neon = mask; +using mu16neon = mask; +using mu32neon = mask; +using mu64neon = mask; +#endif + +template +constexpr inline size_t next_simd_width(size_t n) CMT_NOEXCEPT +{ + return n < minimum_vector_width ? minimum_vector_width : next_poweroftwo(n); +} + +template (N)> +KFR_INTRINSIC vec expand_simd(const vec& x) CMT_NOEXCEPT +{ + return broadcast(x); +} + +template (N)> +KFR_INTRINSIC vec expand_simd(const vec& x) CMT_NOEXCEPT +{ + return extend(x); +} + +template (N)> +KFR_INTRINSIC vec expand_simd(const vec& x, identity value) CMT_NOEXCEPT +{ + return widen(x, value); +} + +template , typename Fn, KFR_ENABLE_IF(N <= Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const vec& b, const vec& c, + Fn&& fn) +{ + result = fn(a, b, c); +} + +template , typename Fn, KFR_ENABLE_IF(N > Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const vec& b, const vec& c, + Fn&& fn) +{ + intrin(result.h.low, a.h.low, b.h.low, c.h.low, fn); + intrin(result.h.high, a.h.high, b.h.high, c.h.high, fn); +} + +template , typename Fn, KFR_ENABLE_IF(N <= Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, Fn&& fn) +{ + result = fn(a); +} + +template , size_t N, typename Fn, KFR_ENABLE_IF(N > Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, Fn&& fn) +{ + intrin(result.h.low, a.h.low, fn); + intrin(result.h.high, a.h.high, fn); +} + +template , typename Fn, KFR_ENABLE_IF(N <= Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const vec& b, Fn&& fn) +{ + result = fn(a, b); +} + +template , typename Fn, KFR_ENABLE_IF(N > Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const vec& b, Fn&& fn) +{ + intrin(result.h.low, a.h.low, b.h.low, fn); + intrin(result.h.high, a.h.high, b.h.high, fn); +} + +template , typename Fn, KFR_ENABLE_IF(N <= Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const T& b, Fn&& fn) +{ + result = fn(a, b); +} + +template , typename Fn, KFR_ENABLE_IF(N > Nvec)> +KFR_INTRINSIC void intrin(vec& result, const vec& a, const T& b, Fn&& fn) +{ + intrin(result.h.low, a.h.low, b, fn); + intrin(result.h.high, a.h.high, b, fn); +} + +template , typename Fn, KFR_ENABLE_IF(N <= Nvec)> +KFR_INTRINSIC void intrin(vec& result, const T& a, const vec& b, Fn&& fn) +{ + result = fn(a, b); +} + +template , typename Fn, KFR_ENABLE_IF(N > Nvec)> +KFR_INTRINSIC void intrin(vec& result, const T& a, const vec& b, Fn&& fn) +{ + intrin(result.h.low, a, b.h.low, fn); + intrin(result.h.high, a, b.h.high, fn); +} + +#define KFR_HANDLE_ALL_SIZES_1_IF(fn, cond) \ + template && !is_simd_size(N) && is_simd_type && cond)> \ + KFR_INTRINSIC vec fn(const vec& a) CMT_NOEXCEPT \ + { \ + constexpr size_t Nout = intrinsics::next_simd_width(N); \ + return intrinsics::fn(a.shuffle(csizeseq)).shuffle(csizeseq); \ + } \ + template vector_width && is_simd_type && cond), \ + typename = void> \ + KFR_INTRINSIC vec fn(const vec& a) CMT_NOEXCEPT \ + { \ + vec r; \ + intrin(r, a, [](const auto& x) { return intrinsics::fn(x); }); \ + return r; \ + } + +#define KFR_HANDLE_ALL_SIZES_1(fn) KFR_HANDLE_ALL_SIZES_1_IF(fn, true) + +#define KFR_HANDLE_ALL_SIZES_2(fn) \ + template && !is_simd_size(N) && is_simd_type)> \ + KFR_INTRINSIC vec fn(const vec& a, const vec& b) CMT_NOEXCEPT \ + { \ + constexpr size_t Nout = intrinsics::next_simd_width(N); \ + return intrinsics::fn(a.shuffle(csizeseq_t()), b.shuffle(csizeseq_t())) \ + .shuffle(csizeseq); \ + } \ + template vector_width && is_simd_type), typename = void> \ + KFR_INTRINSIC vec fn(const vec& a, const vec& b) CMT_NOEXCEPT \ + { \ + vec r; \ + intrin(r, a, b, [](const auto& aa, const auto& bb) { return intrinsics::fn(aa, bb); }); \ + return r; \ + } \ + template && !is_simd_size(N) && is_simd_type)> \ + KFR_INTRINSIC vec fn(const vec& a, const T& b) CMT_NOEXCEPT \ + { \ + constexpr size_t Nout = intrinsics::next_simd_width(N); \ + return intrinsics::fn(a.shuffle(csizeseq_t()), vec(b)).shuffle(csizeseq); \ + } \ + template vector_width && is_simd_type), typename = void> \ + KFR_INTRINSIC vec fn(const vec& a, const T& b) CMT_NOEXCEPT \ + { \ + vec r; \ + intrin(r, a, b, [](const auto& aa, const auto& bb) { return intrinsics::fn(aa, bb); }); \ + return r; \ + } \ + template && !is_simd_size(N) && is_simd_type)> \ + KFR_INTRINSIC vec fn(const T& a, const vec& b) CMT_NOEXCEPT \ + { \ + constexpr size_t Nout = intrinsics::next_simd_width(N); \ + return intrinsics::fn(vec(a), b.shuffle(csizeseq_t())).shuffle(csizeseq); \ + } \ + template vector_width && is_simd_type), typename = void> \ + KFR_INTRINSIC vec fn(const T& a, const vec& b) CMT_NOEXCEPT \ + { \ + vec r; \ + intrin(r, a, b, [](const auto& aa, const auto& bb) { return intrinsics::fn(aa, bb); }); \ + return r; \ + } + +template +using vec1 = std::conditional_t, T, vec>; + +template +inline const T& to_scalar(const T& value) CMT_NOEXCEPT +{ + return value; +} +template +inline T to_scalar(const vec& value) CMT_NOEXCEPT +{ + return value[0]; +} +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/intrinsics.h b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/intrinsics.h new file mode 100644 index 00000000..cda2e8ae --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/intrinsics.h @@ -0,0 +1,55 @@ +#pragma once + +#include "../../cident.h" +#include +#include +#include + +#ifdef CMT_ARCH_SSE2 +#include +#ifdef CMT_OS_WIN +#include +#endif +#endif + +#ifdef CMT_ARCH_NEON +#include +#endif + +#if defined CMT_COMPILER_GCC && defined CMT_ARCH_X86 +#include +#endif + +#ifdef CMT_COMPILER_CLANG +#define builtin_addressof(x) __builtin_addressof(x) +#else +template +inline T* builtin_addressof(T& arg) +{ + return reinterpret_cast(&const_cast(reinterpret_cast(arg))); +} +#endif + +#ifdef CMT_COMPILER_GNU +CMT_INLINE float builtin_sqrt(float x) { return __builtin_sqrtf(x); } +CMT_INLINE double builtin_sqrt(double x) { return __builtin_sqrt(x); } +CMT_INLINE long double builtin_sqrt(long double x) { return __builtin_sqrtl(x); } +CMT_INLINE void builtin_memcpy(void* dest, const void* src, size_t size) +{ + __builtin_memcpy(dest, src, size); +} +CMT_INLINE void builtin_memmove(void* dest, const void* src, size_t size) +{ + __builtin_memmove(dest, src, size); +} +CMT_INLINE void builtin_memset(void* dest, int val, size_t size) { __builtin_memset(dest, val, size); } +#else +CMT_INLINE float builtin_sqrt(float x) { return ::sqrtf(x); } +CMT_INLINE double builtin_sqrt(double x) { return ::sqrt(x); } +CMT_INLINE long double builtin_sqrt(long double x) { return ::sqrtl(x); } +CMT_INLINE void builtin_memcpy(void* dest, const void* src, size_t size) { ::memcpy(dest, src, size); } +CMT_INLINE void builtin_memmove(void* dest, const void* src, size_t size) { ::memmove(dest, src, size); } +CMT_INLINE void builtin_memset(void* dest, int val, size_t size) { ::memset(dest, val, size); } +#endif + +#define KFR_ENABLE_IF CMT_ENABLE_IF diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/logical.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/logical.hpp new file mode 100644 index 00000000..a511088f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/logical.hpp @@ -0,0 +1,286 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../abs.hpp" +#include "../operators.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#if defined CMT_ARCH_SSE2 && defined KFR_NATIVE_INTRINSICS + +#if defined CMT_ARCH_SSE41 + +// horizontal OR +KFR_INTRINSIC bool bittestany(const mu8sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu16sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu32sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu64sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi8sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi16sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi32sse& x) { return !_mm_testz_si128(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi64sse& x) { return !_mm_testz_si128(x.v, x.v); } + +// horizontal AND +KFR_INTRINSIC bool bittestall(const mu8sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu16sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu32sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu64sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi8sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi16sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi32sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi64sse& x) { return _mm_testc_si128(x.v, allonesvector(x).v); } +#endif + +#if defined CMT_ARCH_AVX +// horizontal OR +KFR_INTRINSIC bool bittestany(const mf32sse& x) { return !_mm_testz_ps(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mf64sse& x) { return !_mm_testz_pd(x.v, x.v); } + +KFR_INTRINSIC bool bittestany(const mf32avx& x) { return !_mm256_testz_ps(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mf64avx& x) { return !_mm256_testz_pd(x.v, x.v); } + +KFR_INTRINSIC bool bittestany(const mu8avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu16avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu32avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mu64avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi8avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi16avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi32avx& x) { return !_mm256_testz_si256(x.v, x.v); } +KFR_INTRINSIC bool bittestany(const mi64avx& x) { return !_mm256_testz_si256(x.v, x.v); } + +// horizontal AND +KFR_INTRINSIC bool bittestall(const mf32sse& x) { return _mm_testc_ps(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mf64sse& x) { return _mm_testc_pd(x.v, allonesvector(x).v); } + +KFR_INTRINSIC bool bittestall(const mf32avx& x) { return _mm256_testc_ps(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mf64avx& x) { return _mm256_testc_pd(x.v, allonesvector(x).v); } + +KFR_INTRINSIC bool bittestall(const mu8avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu16avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu32avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mu64avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi8avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi16avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi32avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } +KFR_INTRINSIC bool bittestall(const mi64avx& x) { return _mm256_testc_si256(x.v, allonesvector(x).v); } + +#if defined CMT_ARCH_AVX512 +// horizontal OR +KFR_INTRINSIC bool bittestany(const mf32avx512& x) { return _mm512_movepi32_mask(_mm512_castps_si512(x.v)); } +KFR_INTRINSIC bool bittestany(const mf64avx512& x) { return _mm512_movepi64_mask(_mm512_castpd_si512(x.v)); } +KFR_INTRINSIC bool bittestany(const mu8avx512& x) { return _mm512_movepi8_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mu16avx512& x) { return _mm512_movepi16_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mu32avx512& x) { return _mm512_movepi32_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mu64avx512& x) { return _mm512_movepi64_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mi8avx512& x) { return _mm512_movepi8_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mi16avx512& x) { return _mm512_movepi16_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mi32avx512& x) { return _mm512_movepi32_mask(x.v); } +KFR_INTRINSIC bool bittestany(const mi64avx512& x) { return _mm512_movepi64_mask(x.v); } + +// horizontal AND +KFR_INTRINSIC bool bittestall(const mf32avx512& x) +{ + return !~_mm512_movepi32_mask(_mm512_castps_si512(x.v)); +} +KFR_INTRINSIC bool bittestall(const mf64avx512& x) +{ + return !~_mm512_movepi64_mask(_mm512_castpd_si512(x.v)); +} +KFR_INTRINSIC bool bittestall(const mu8avx512& x) { return !~_mm512_movepi8_mask(x.v); } +KFR_INTRINSIC bool bittestall(const mu16avx512& x) { return !~_mm512_movepi16_mask(x.v); } +KFR_INTRINSIC bool bittestall(const mu32avx512& x) { return !uint16_t(~_mm512_movepi32_mask(x.v)); } +KFR_INTRINSIC bool bittestall(const mu64avx512& x) { return !uint8_t(~_mm512_movepi64_mask(x.v)); } +KFR_INTRINSIC bool bittestall(const mi8avx512& x) { return !~_mm512_movepi8_mask(x.v); } +KFR_INTRINSIC bool bittestall(const mi16avx512& x) { return !~_mm512_movepi16_mask(x.v); } +KFR_INTRINSIC bool bittestall(const mi32avx512& x) { return !uint16_t(~_mm512_movepi32_mask(x.v)); } +KFR_INTRINSIC bool bittestall(const mi64avx512& x) { return !uint8_t(~_mm512_movepi64_mask(x.v)); } + +#endif + +#elif defined CMT_ARCH_SSE41 +KFR_INTRINSIC bool bittestany(const mf32sse& x) +{ + return !_mm_testz_si128(bitcast>(x).v, bitcast>(x).v); +} +KFR_INTRINSIC bool bittestany(const mf64sse& x) +{ + return !_mm_testz_si128(bitcast>(x).v, bitcast>(x).v); +} +KFR_INTRINSIC bool bittestall(const mf32sse& x) +{ + return _mm_testc_si128(bitcast>(x).v, allonesvector(bitcast>(x)).v); +} +KFR_INTRINSIC bool bittestall(const mf64sse& x) +{ + return _mm_testc_si128(bitcast>(x).v, allonesvector(bitcast>(x)).v); +} +#endif + +#if !defined CMT_ARCH_SSE41 + +KFR_INTRINSIC bool bittestany(const mf32sse& x) { return _mm_movemask_ps(x.v); } +KFR_INTRINSIC bool bittestany(const mf64sse& x) { return _mm_movemask_pd(x.v); } +KFR_INTRINSIC bool bittestany(const mu8sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mu16sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mu32sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mu64sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mi8sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mi16sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mi32sse& x) { return _mm_movemask_epi8(x.v); } +KFR_INTRINSIC bool bittestany(const mi64sse& x) { return _mm_movemask_epi8(x.v); } + +KFR_INTRINSIC bool bittestall(const mf32sse& x) { return !_mm_movemask_ps((~x).v); } +KFR_INTRINSIC bool bittestall(const mf64sse& x) { return !_mm_movemask_pd((~x).v); } +KFR_INTRINSIC bool bittestall(const mu8sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mu16sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mu32sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mu64sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mi8sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mi16sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mi32sse& x) { return !_mm_movemask_epi8((~x).v); } +KFR_INTRINSIC bool bittestall(const mi64sse& x) { return !_mm_movemask_epi8((~x).v); } +#endif + +template )> +KFR_INTRINSIC bool bittestall(const mask& a) +{ + return bittestall(expand_simd(a, bit(true))); +} +template = vector_width), typename = void> +KFR_INTRINSIC bool bittestall(const mask& a) +{ + return bittestall(low(a)) && bittestall(high(a)); +} + +template )> +KFR_INTRINSIC bool bittestany(const mask& a) +{ + return bittestany(expand_simd(a, bit(false))); +} +template = vector_width), typename = void> +KFR_INTRINSIC bool bittestany(const mask& a) +{ + return bittestany(low(a)) || bittestany(high(a)); +} + +#elif CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC bool bittestall(const mu32neon& a) +{ + const uint32x2_t tmp = vand_u32(vget_low_u32(a.v), vget_high_u32(a.v)); + return vget_lane_u32(vpmin_u32(tmp, tmp), 0) == 0xFFFFFFFFu; +} + +KFR_INTRINSIC bool bittestany(const mu32neon& a) +{ + const uint32x2_t tmp = vorr_u32(vget_low_u32(a.v), vget_high_u32(a.v)); + return vget_lane_u32(vpmax_u32(tmp, tmp), 0) != 0; +} +KFR_INTRINSIC bool bittestany(const mu8neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mu16neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mu64neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mi8neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mi16neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mi32neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mi64neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mf32neon& a) { return bittestany(bitcast>(a)); } +KFR_INTRINSIC bool bittestany(const mf64neon& a) { return bittestany(bitcast>(a)); } + +KFR_INTRINSIC bool bittestall(const mu8neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mu16neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mu64neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mi8neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mi16neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mi32neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mi64neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mf32neon& a) { return bittestall(bitcast>(a)); } +KFR_INTRINSIC bool bittestall(const mf64neon& a) { return bittestall(bitcast>(a)); } + +template )> +KFR_INTRINSIC bool bittestall(const mask& a) +{ + return bittestall(expand_simd(a, bit(true))); +} +template = vector_width), typename = void> +KFR_INTRINSIC bool bittestall(const mask& a) +{ + return bittestall(low(a)) && bittestall(high(a)); +} + +template )> +KFR_INTRINSIC bool bittestany(const mask& a) +{ + return bittestany(expand_simd(a, bit(false))); +} +template = vector_width), typename = void> +KFR_INTRINSIC bool bittestany(const mask& a) +{ + return bittestany(low(a)) || bittestany(high(a)); +} + +#else + +template +KFR_INTRINSIC bitmask getmask(const mask& x) +{ + typename bitmask::type val = 0; + for (size_t i = 0; i < N; i++) + { + val |= static_cast(x[i]) << i; + } + return val; +} + +template +KFR_INTRINSIC bool bittestany(const mask& x) +{ + return getmask(x).value; +} +template +KFR_INTRINSIC bool bittestany(const mask& x, const mask& y) +{ + return bittestany(x & y); +} + +template +KFR_INTRINSIC bool bittestall(const mask& x) +{ + return !getmask(~x).value; +} +template +KFR_INTRINSIC bool bittestall(const mask& x, const mask& y) +{ + return !bittestany(~x & y); +} +#endif +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/min_max.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/min_max.hpp new file mode 100644 index 00000000..be9ff616 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/min_max.hpp @@ -0,0 +1,236 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../abs.hpp" +#include "../operators.hpp" +#include "../select.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#if defined CMT_ARCH_SSE2 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC f32sse min(const f32sse& x, const f32sse& y) { return _mm_min_ps(x.v, y.v); } +KFR_INTRINSIC f64sse min(const f64sse& x, const f64sse& y) { return _mm_min_pd(x.v, y.v); } +KFR_INTRINSIC u8sse min(const u8sse& x, const u8sse& y) { return _mm_min_epu8(x.v, y.v); } +KFR_INTRINSIC i16sse min(const i16sse& x, const i16sse& y) { return _mm_min_epi16(x.v, y.v); } + +KFR_INTRINSIC f32sse max(const f32sse& x, const f32sse& y) { return _mm_max_ps(x.v, y.v); } +KFR_INTRINSIC f64sse max(const f64sse& x, const f64sse& y) { return _mm_max_pd(x.v, y.v); } +KFR_INTRINSIC u8sse max(const u8sse& x, const u8sse& y) { return _mm_max_epu8(x.v, y.v); } +KFR_INTRINSIC i16sse max(const i16sse& x, const i16sse& y) { return _mm_max_epi16(x.v, y.v); } + +#if defined CMT_ARCH_AVX2 +KFR_INTRINSIC u8avx min(const u8avx& x, const u8avx& y) { return _mm256_min_epu8(x.v, y.v); } +KFR_INTRINSIC i16avx min(const i16avx& x, const i16avx& y) { return _mm256_min_epi16(x.v, y.v); } +KFR_INTRINSIC i8avx min(const i8avx& x, const i8avx& y) { return _mm256_min_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx min(const u16avx& x, const u16avx& y) { return _mm256_min_epu16(x.v, y.v); } +KFR_INTRINSIC i32avx min(const i32avx& x, const i32avx& y) { return _mm256_min_epi32(x.v, y.v); } +KFR_INTRINSIC u32avx min(const u32avx& x, const u32avx& y) { return _mm256_min_epu32(x.v, y.v); } + +KFR_INTRINSIC u8avx max(const u8avx& x, const u8avx& y) { return _mm256_max_epu8(x.v, y.v); } +KFR_INTRINSIC i16avx max(const i16avx& x, const i16avx& y) { return _mm256_max_epi16(x.v, y.v); } +KFR_INTRINSIC i8avx max(const i8avx& x, const i8avx& y) { return _mm256_max_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx max(const u16avx& x, const u16avx& y) { return _mm256_max_epu16(x.v, y.v); } +KFR_INTRINSIC i32avx max(const i32avx& x, const i32avx& y) { return _mm256_max_epi32(x.v, y.v); } +KFR_INTRINSIC u32avx max(const u32avx& x, const u32avx& y) { return _mm256_max_epu32(x.v, y.v); } + +#endif + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC f32avx512 min(const f32avx512& x, const f32avx512& y) { return _mm512_min_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 min(const f64avx512& x, const f64avx512& y) { return _mm512_min_pd(x.v, y.v); } +KFR_INTRINSIC f32avx512 max(const f32avx512& x, const f32avx512& y) { return _mm512_max_ps(x.v, y.v); } +KFR_INTRINSIC f64avx512 max(const f64avx512& x, const f64avx512& y) { return _mm512_max_pd(x.v, y.v); } + +KFR_INTRINSIC u8avx512 min(const u8avx512& x, const u8avx512& y) { return _mm512_min_epu8(x.v, y.v); } +KFR_INTRINSIC i16avx512 min(const i16avx512& x, const i16avx512& y) { return _mm512_min_epi16(x.v, y.v); } +KFR_INTRINSIC i8avx512 min(const i8avx512& x, const i8avx512& y) { return _mm512_min_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 min(const u16avx512& x, const u16avx512& y) { return _mm512_min_epu16(x.v, y.v); } +KFR_INTRINSIC i32avx512 min(const i32avx512& x, const i32avx512& y) { return _mm512_min_epi32(x.v, y.v); } +KFR_INTRINSIC u32avx512 min(const u32avx512& x, const u32avx512& y) { return _mm512_min_epu32(x.v, y.v); } +KFR_INTRINSIC u8avx512 max(const u8avx512& x, const u8avx512& y) { return _mm512_max_epu8(x.v, y.v); } +KFR_INTRINSIC i16avx512 max(const i16avx512& x, const i16avx512& y) { return _mm512_max_epi16(x.v, y.v); } +KFR_INTRINSIC i8avx512 max(const i8avx512& x, const i8avx512& y) { return _mm512_max_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 max(const u16avx512& x, const u16avx512& y) { return _mm512_max_epu16(x.v, y.v); } +KFR_INTRINSIC i32avx512 max(const i32avx512& x, const i32avx512& y) { return _mm512_max_epi32(x.v, y.v); } +KFR_INTRINSIC u32avx512 max(const u32avx512& x, const u32avx512& y) { return _mm512_max_epu32(x.v, y.v); } +KFR_INTRINSIC i64avx512 min(const i64avx512& x, const i64avx512& y) { return _mm512_min_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx512 min(const u64avx512& x, const u64avx512& y) { return _mm512_min_epu64(x.v, y.v); } +KFR_INTRINSIC i64avx512 max(const i64avx512& x, const i64avx512& y) { return _mm512_max_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx512 max(const u64avx512& x, const u64avx512& y) { return _mm512_max_epu64(x.v, y.v); } + +KFR_INTRINSIC i64avx min(const i64avx& x, const i64avx& y) { return _mm256_min_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx min(const u64avx& x, const u64avx& y) { return _mm256_min_epu64(x.v, y.v); } +KFR_INTRINSIC i64avx max(const i64avx& x, const i64avx& y) { return _mm256_max_epi64(x.v, y.v); } +KFR_INTRINSIC u64avx max(const u64avx& x, const u64avx& y) { return _mm256_max_epu64(x.v, y.v); } + +KFR_INTRINSIC i64sse min(const i64sse& x, const i64sse& y) { return _mm_min_epi64(x.v, y.v); } +KFR_INTRINSIC u64sse min(const u64sse& x, const u64sse& y) { return _mm_min_epu64(x.v, y.v); } +KFR_INTRINSIC i64sse max(const i64sse& x, const i64sse& y) { return _mm_max_epi64(x.v, y.v); } +KFR_INTRINSIC u64sse max(const u64sse& x, const u64sse& y) { return _mm_max_epu64(x.v, y.v); } +#else +KFR_INTRINSIC i64sse min(const i64sse& x, const i64sse& y) { return select(x < y, x, y); } +KFR_INTRINSIC u64sse min(const u64sse& x, const u64sse& y) { return select(x < y, x, y); } +KFR_INTRINSIC i64sse max(const i64sse& x, const i64sse& y) { return select(x > y, x, y); } +KFR_INTRINSIC u64sse max(const u64sse& x, const u64sse& y) { return select(x > y, x, y); } +KFR_INTRINSIC i64avx min(const i64avx& x, const i64avx& y) { return select(x < y, x, y); } +KFR_INTRINSIC u64avx min(const u64avx& x, const u64avx& y) { return select(x < y, x, y); } +KFR_INTRINSIC i64avx max(const i64avx& x, const i64avx& y) { return select(x > y, x, y); } +KFR_INTRINSIC u64avx max(const u64avx& x, const u64avx& y) { return select(x > y, x, y); } +#endif + +#if defined CMT_ARCH_AVX +KFR_INTRINSIC f32avx min(const f32avx& x, const f32avx& y) { return _mm256_min_ps(x.v, y.v); } +KFR_INTRINSIC f64avx min(const f64avx& x, const f64avx& y) { return _mm256_min_pd(x.v, y.v); } +KFR_INTRINSIC f32avx max(const f32avx& x, const f32avx& y) { return _mm256_max_ps(x.v, y.v); } +KFR_INTRINSIC f64avx max(const f64avx& x, const f64avx& y) { return _mm256_max_pd(x.v, y.v); } +#endif + +#if defined CMT_ARCH_SSE41 +KFR_INTRINSIC i8sse min(const i8sse& x, const i8sse& y) { return _mm_min_epi8(x.v, y.v); } +KFR_INTRINSIC u16sse min(const u16sse& x, const u16sse& y) { return _mm_min_epu16(x.v, y.v); } +KFR_INTRINSIC i32sse min(const i32sse& x, const i32sse& y) { return _mm_min_epi32(x.v, y.v); } +KFR_INTRINSIC u32sse min(const u32sse& x, const u32sse& y) { return _mm_min_epu32(x.v, y.v); } + +KFR_INTRINSIC i8sse max(const i8sse& x, const i8sse& y) { return _mm_max_epi8(x.v, y.v); } +KFR_INTRINSIC u16sse max(const u16sse& x, const u16sse& y) { return _mm_max_epu16(x.v, y.v); } +KFR_INTRINSIC i32sse max(const i32sse& x, const i32sse& y) { return _mm_max_epi32(x.v, y.v); } +KFR_INTRINSIC u32sse max(const u32sse& x, const u32sse& y) { return _mm_max_epu32(x.v, y.v); } +#else +KFR_INTRINSIC i8sse min(const i8sse& x, const i8sse& y) { return select(x < y, x, y); } +KFR_INTRINSIC u16sse min(const u16sse& x, const u16sse& y) { return select(x < y, x, y); } +KFR_INTRINSIC i32sse min(const i32sse& x, const i32sse& y) { return select(x < y, x, y); } +KFR_INTRINSIC u32sse min(const u32sse& x, const u32sse& y) { return select(x < y, x, y); } + +KFR_INTRINSIC i8sse max(const i8sse& x, const i8sse& y) { return select(x > y, x, y); } +KFR_INTRINSIC u16sse max(const u16sse& x, const u16sse& y) { return select(x > y, x, y); } +KFR_INTRINSIC i32sse max(const i32sse& x, const i32sse& y) { return select(x > y, x, y); } +KFR_INTRINSIC u32sse max(const u32sse& x, const u32sse& y) { return select(x > y, x, y); } + +#endif + +KFR_HANDLE_ALL_SIZES_2(min) +KFR_HANDLE_ALL_SIZES_2(max) + +#elif defined CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC i8neon min(const i8neon& x, const i8neon& y) { return vminq_s8(x.v, y.v); } +KFR_INTRINSIC u8neon min(const u8neon& x, const u8neon& y) { return vminq_u8(x.v, y.v); } +KFR_INTRINSIC i16neon min(const i16neon& x, const i16neon& y) { return vminq_s16(x.v, y.v); } +KFR_INTRINSIC u16neon min(const u16neon& x, const u16neon& y) { return vminq_u16(x.v, y.v); } +KFR_INTRINSIC i32neon min(const i32neon& x, const i32neon& y) { return vminq_s32(x.v, y.v); } +KFR_INTRINSIC u32neon min(const u32neon& x, const u32neon& y) { return vminq_u32(x.v, y.v); } +KFR_INTRINSIC i64neon min(const i64neon& x, const i64neon& y) { return select(x < y, x, y); } +KFR_INTRINSIC u64neon min(const u64neon& x, const u64neon& y) { return select(x < y, x, y); } + +KFR_INTRINSIC i8neon max(const i8neon& x, const i8neon& y) { return vmaxq_s8(x.v, y.v); } +KFR_INTRINSIC u8neon max(const u8neon& x, const u8neon& y) { return vmaxq_u8(x.v, y.v); } +KFR_INTRINSIC i16neon max(const i16neon& x, const i16neon& y) { return vmaxq_s16(x.v, y.v); } +KFR_INTRINSIC u16neon max(const u16neon& x, const u16neon& y) { return vmaxq_u16(x.v, y.v); } +KFR_INTRINSIC i32neon max(const i32neon& x, const i32neon& y) { return vmaxq_s32(x.v, y.v); } +KFR_INTRINSIC u32neon max(const u32neon& x, const u32neon& y) { return vmaxq_u32(x.v, y.v); } +KFR_INTRINSIC i64neon max(const i64neon& x, const i64neon& y) { return select(x > y, x, y); } +KFR_INTRINSIC u64neon max(const u64neon& x, const u64neon& y) { return select(x > y, x, y); } + +KFR_INTRINSIC f32neon min(const f32neon& x, const f32neon& y) { return vminq_f32(x.v, y.v); } +KFR_INTRINSIC f32neon max(const f32neon& x, const f32neon& y) { return vmaxq_f32(x.v, y.v); } +#if defined CMT_ARCH_NEON64 +KFR_INTRINSIC f64neon min(const f64neon& x, const f64neon& y) { return vminq_f64(x.v, y.v); } +KFR_INTRINSIC f64neon max(const f64neon& x, const f64neon& y) { return vmaxq_f64(x.v, y.v); } +#else +KFR_INTRINSIC f64neon min(const f64neon& x, const f64neon& y) { return select(x < y, x, y); } +KFR_INTRINSIC f64neon max(const f64neon& x, const f64neon& y) { return select(x > y, x, y); } +#endif + +KFR_HANDLE_ALL_SIZES_2(min) +KFR_HANDLE_ALL_SIZES_2(max) + +#else + +// fallback +template +KFR_INTRINSIC vec min(const vec& x, const vec& y) +{ + return select(x < y, x, y); +} +template +KFR_INTRINSIC vec max(const vec& x, const vec& y) +{ + return select(x > y, x, y); +} +#endif + +template +KFR_INTRINSIC T min(initialvalue) +{ + return std::numeric_limits::has_infinity ? std::numeric_limits::infinity() + : std::numeric_limits::max(); +} +template +KFR_INTRINSIC T max(initialvalue) +{ + return std::numeric_limits::has_infinity ? -std::numeric_limits::infinity() + : std::numeric_limits::min(); +} +template +KFR_INTRINSIC T absmin(initialvalue) +{ + return std::numeric_limits::has_infinity ? std::numeric_limits::infinity() + : std::numeric_limits::max(); +} +template +KFR_INTRINSIC T absmax(initialvalue) +{ + return 0; +} + +template +KFR_INTRINSIC vec absmin(const vec& x, const vec& y) +{ + return min(abs(x), abs(y)); +} +template +KFR_INTRINSIC vec absmax(const vec& x, const vec& y) +{ + return max(abs(x), abs(y)); +} + +KFR_HANDLE_SCALAR(min) +KFR_HANDLE_SCALAR(max) +KFR_HANDLE_SCALAR(absmin) +KFR_HANDLE_SCALAR(absmax) +} // namespace intrinsics +KFR_I_FN(min) +KFR_I_FN(max) +KFR_I_FN(absmin) +KFR_I_FN(absmax) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/operators.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/operators.hpp new file mode 100644 index 00000000..eb0403b2 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/operators.hpp @@ -0,0 +1,97 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "function.hpp" + +#ifdef CMT_CLANG_EXT +#include "basicoperators_clang.hpp" +#else +#include "basicoperators_generic.hpp" +#endif + +#include "basicoperators_complex.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ +namespace intrinsics +{ + +#define KFR_VECVEC_OP1(fn) \ + template \ + KFR_INTRINSIC vec, N2> fn(const vec, N2>& x) \ + { \ + return fn(x.flatten()).v; \ + } + +#define KFR_VECVEC_OP2(fn) \ + template , \ + KFR_ENABLE_IF(is_simd_type)> \ + KFR_INTRINSIC vec, N2> fn(const vec, N2>& x, const vec, N2>& y) \ + { \ + return fn(broadcastto(x.flatten()), broadcastto(y.flatten())).v; \ + } \ + template , \ + KFR_ENABLE_IF(is_simd_type)> \ + KFR_INTRINSIC vec, N2> fn(const vec, N2>& x, const T2& y) \ + { \ + return fn(broadcastto(x.flatten()), broadcastto(y)).v; \ + } \ + template , \ + KFR_ENABLE_IF(is_simd_type)> \ + KFR_INTRINSIC vec, N2> fn(const vec, N2>& x, const vec& y) \ + { \ + return fn(broadcastto(x.flatten()), repeat(broadcastto(y.flatten()))).v; \ + } \ + template , \ + KFR_ENABLE_IF(is_simd_type)> \ + KFR_INTRINSIC vec, N2> fn(const T1& x, const vec, N2>& y) \ + { \ + return fn(broadcastto(x), broadcastto(y.flatten())).v; \ + } \ + template , \ + KFR_ENABLE_IF(is_simd_type)> \ + KFR_INTRINSIC vec, N2> fn(const vec& x, const vec, N2>& y) \ + { \ + return fn(repeat(broadcastto(x.flatten())), broadcastto(y.flatten())).v; \ + } + +KFR_VECVEC_OP1(neg) +KFR_VECVEC_OP1(bnot) +KFR_VECVEC_OP2(add) +KFR_VECVEC_OP2(sub) +KFR_VECVEC_OP2(mul) +KFR_VECVEC_OP2(div) +KFR_VECVEC_OP2(mod) +KFR_VECVEC_OP2(band) +KFR_VECVEC_OP2(bor) +KFR_VECVEC_OP2(bxor) + +} // namespace intrinsics +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/read_write.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/read_write.hpp new file mode 100644 index 00000000..e5cb538e --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/read_write.hpp @@ -0,0 +1,402 @@ +/** @addtogroup read_write + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../shuffle.hpp" +#include "../types.hpp" +#include "../vec.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ +namespace intrinsics +{ + +#ifndef CMT_CLANG_EXT + +#ifdef CMT_ARCH_SSE2 + +template +KFR_INTRINSIC vec read(cunaligned_t, csize_t<1>, const T* ptr) +{ + return *ptr; +} + +KFR_INTRINSIC f32x2 read(cunaligned_t, csize_t<2>, const f32* ptr) +{ + return f32x2::simd_type{ ptr[0], ptr[1] }; +} + +#if !defined(CMT_COMPILER_GCC) + +KFR_INTRINSIC u8x2 read(cunaligned_t, csize_t<2>, const u8* ptr) +{ + return u8x2::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i8x2 read(cunaligned_t, csize_t<2>, const i8* ptr) +{ + return i8x2::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC u8x4 read(cunaligned_t, csize_t<4>, const u8* ptr) +{ + return u8x4::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i8x4 read(cunaligned_t, csize_t<4>, const i8* ptr) +{ + return i8x4::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC u16x2 read(cunaligned_t, csize_t<2>, const u16* ptr) +{ + return u16x2::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i16x2 read(cunaligned_t, csize_t<2>, const i16* ptr) +{ + return i16x2::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC u8x8 read(cunaligned_t, csize_t<8>, const u8* ptr) +{ + return u8x8::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i8x8 read(cunaligned_t, csize_t<8>, const i8* ptr) +{ + return i8x8::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC u16x4 read(cunaligned_t, csize_t<4>, const u16* ptr) +{ + return u16x4::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i16x4 read(cunaligned_t, csize_t<4>, const i16* ptr) +{ + return i16x4::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC u32x2 read(cunaligned_t, csize_t<2>, const u32* ptr) +{ + return u32x2::simd_type::from(*reinterpret_cast(ptr)); +} +KFR_INTRINSIC i32x2 read(cunaligned_t, csize_t<2>, const i32* ptr) +{ + return i32x2::simd_type::from(*reinterpret_cast(ptr)); +} + +#endif + +KFR_INTRINSIC f32sse read(cunaligned_t, csize_t<4>, const f32* ptr) { return _mm_loadu_ps(ptr); } +KFR_INTRINSIC f64sse read(cunaligned_t, csize_t<2>, const f64* ptr) { return _mm_loadu_pd(ptr); } +KFR_INTRINSIC u8sse read(cunaligned_t, csize_t<16>, const u8* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i8sse read(cunaligned_t, csize_t<16>, const i8* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u16sse read(cunaligned_t, csize_t<8>, const u16* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i16sse read(cunaligned_t, csize_t<8>, const i16* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u32sse read(cunaligned_t, csize_t<4>, const u32* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i32sse read(cunaligned_t, csize_t<4>, const i32* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u64sse read(cunaligned_t, csize_t<2>, const u64* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i64sse read(cunaligned_t, csize_t<2>, const i64* ptr) +{ + return _mm_loadu_si128(reinterpret_cast(ptr)); +} + +template +KFR_INTRINSIC void write(cunaligned_t, T* ptr, const vec& x) +{ + *ptr = x.front(); +} +KFR_INTRINSIC void write(cunaligned_t, f32* ptr, const f32x2& x) +{ +#ifndef KFR_f32x2_array + *reinterpret_cast(ptr) = x.v.whole; +#else + ptr[0] = x.v.low; + ptr[1] = x.v.high; +#endif +} + +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8x2& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8x2& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8x4& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8x4& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, u16* ptr, const u16x2& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i16* ptr, const i16x2& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8x8& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8x8& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, u16* ptr, const u16x4& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i16* ptr, const i16x4& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, u32* ptr, const u32x2& x) { *reinterpret_cast(ptr) = x.v.whole; } +KFR_INTRINSIC void write(cunaligned_t, i32* ptr, const i32x2& x) { *reinterpret_cast(ptr) = x.v.whole; } + +KFR_INTRINSIC void write(cunaligned_t, f32* ptr, const f32sse& x) { _mm_storeu_ps(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, f64* ptr, const f64sse& x) { _mm_storeu_pd(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u16* ptr, const u16sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i16* ptr, const i16sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u32* ptr, const u32sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i32* ptr, const i32sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u64* ptr, const u64sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i64* ptr, const i64sse& x) +{ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), x.v); +} + +#if defined CMT_ARCH_AVX + +KFR_INTRINSIC f32avx read(cunaligned_t, csize_t<8>, const f32* ptr) { return _mm256_loadu_ps(ptr); } +KFR_INTRINSIC f64avx read(cunaligned_t, csize_t<4>, const f64* ptr) { return _mm256_loadu_pd(ptr); } + +KFR_INTRINSIC void write(cunaligned_t, f32* ptr, const f32avx& x) { _mm256_storeu_ps(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, f64* ptr, const f64avx& x) { _mm256_storeu_pd(ptr, x.v); } + +#if defined CMT_ARCH_AVX2 + +KFR_INTRINSIC u8avx read(cunaligned_t, csize_t<32>, const u8* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i8avx read(cunaligned_t, csize_t<32>, const i8* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u16avx read(cunaligned_t, csize_t<16>, const u16* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i16avx read(cunaligned_t, csize_t<16>, const i16* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u32avx read(cunaligned_t, csize_t<8>, const u32* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i32avx read(cunaligned_t, csize_t<8>, const i32* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC u64avx read(cunaligned_t, csize_t<4>, const u64* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} +KFR_INTRINSIC i64avx read(cunaligned_t, csize_t<4>, const i64* ptr) +{ + return _mm256_loadu_si256(reinterpret_cast(ptr)); +} + +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u16* ptr, const u16avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i16* ptr, const i16avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u32* ptr, const u32avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i32* ptr, const i32avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, u64* ptr, const u64avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} +KFR_INTRINSIC void write(cunaligned_t, i64* ptr, const i64avx& x) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), x.v); +} + +#if defined CMT_ARCH_AVX512 + +KFR_INTRINSIC f32avx512 read(cunaligned_t, csize_t<16>, const f32* ptr) { return _mm512_loadu_ps(ptr); } +KFR_INTRINSIC f64avx512 read(cunaligned_t, csize_t<8>, const f64* ptr) { return _mm512_loadu_pd(ptr); } + +KFR_INTRINSIC u8avx512 read(cunaligned_t, csize_t<64>, const u8* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC i8avx512 read(cunaligned_t, csize_t<64>, const i8* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC u16avx512 read(cunaligned_t, csize_t<32>, const u16* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC i16avx512 read(cunaligned_t, csize_t<32>, const i16* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC u32avx512 read(cunaligned_t, csize_t<16>, const u32* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC i32avx512 read(cunaligned_t, csize_t<16>, const i32* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC u64avx512 read(cunaligned_t, csize_t<8>, const u64* ptr) { return _mm512_loadu_si512(ptr); } +KFR_INTRINSIC i64avx512 read(cunaligned_t, csize_t<8>, const i64* ptr) { return _mm512_loadu_si512(ptr); } + +KFR_INTRINSIC void write(cunaligned_t, f32* ptr, const f32avx512& x) { _mm512_storeu_ps(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, f64* ptr, const f64avx512& x) { _mm512_storeu_pd(ptr, x.v); } + +KFR_INTRINSIC void write(cunaligned_t, u8* ptr, const u8avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, i8* ptr, const i8avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, u16* ptr, const u16avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, i16* ptr, const i16avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, u32* ptr, const u32avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, i32* ptr, const i32avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, u64* ptr, const u64avx512& x) { _mm512_storeu_si512(ptr, x.v); } +KFR_INTRINSIC void write(cunaligned_t, i64* ptr, const i64avx512& x) { _mm512_storeu_si512(ptr, x.v); } + +#endif +#endif +#endif +#else + +// fallback + +template (N))> +KFR_INTRINSIC vec read(cunaligned_t, csize_t, const T* ptr) CMT_NOEXCEPT +{ + vec result{}; + for (size_t i = 0; i < N; i++) + result[i] = ptr[i]; + return result; +} + +template (N))> +KFR_INTRINSIC void write(cunaligned_t, T* ptr, const vec& x) CMT_NOEXCEPT +{ + for (size_t i = 0; i < N; i++) + ptr[i] = x[i]; +} + +#endif + +template (N)), + size_t Nlow = prev_poweroftwo(N - 1)> +KFR_INTRINSIC vec read(cunaligned_t, csize_t, const T* ptr) CMT_NOEXCEPT +{ + return concat(read(cunaligned, csize, ptr), read(cunaligned, csize, ptr + Nlow)); +} + +template (N)), + size_t Nlow = prev_poweroftwo(N - 1)> +KFR_INTRINSIC void write(cunaligned_t, T* ptr, const vec& x) CMT_NOEXCEPT +{ + write(cunaligned, ptr, x.shuffle(csizeseq)); + write(cunaligned, ptr + Nlow, x.shuffle(csizeseq)); +} + +#else + +template +KFR_INTRINSIC simd simd_read(const T* src) CMT_NOEXCEPT +{ + return reinterpret_cast::const_pointer>(src)->value; +} + +template +KFR_INTRINSIC vec read(cunaligned_t, csize_t, const T* src) CMT_NOEXCEPT +{ + // Clang requires a separate function returning vector (simd). + // Direct returning vec causes aligned read instruction + return simd_read(src); +} + +template +KFR_INTRINSIC vec read(cunaligned_t, csize_t, const T* src) CMT_NOEXCEPT +{ + constexpr size_t first = prev_poweroftwo(N); + return concat(read(cunaligned, csize, src), read(cunaligned, csize, src + first)); +} + +template +KFR_INTRINSIC void write(cunaligned_t, T* dest, const vec& x) CMT_NOEXCEPT +{ + reinterpret_cast::pointer>(dest)->value = x.v; +} + +template +KFR_INTRINSIC void write(cunaligned_t, T* dest, const vec& x) CMT_NOEXCEPT +{ + write(cunaligned, dest, x.shuffle(csizeseq)); + write(cunaligned, dest + Nlow, x.shuffle(csizeseq)); +} + +#endif + +template +KFR_INTRINSIC vec read(caligned_t, csize_t, const T* __restrict ptr) CMT_NOEXCEPT +{ + return *reinterpret_cast::simd_type*>(ptr); +} + +template +KFR_INTRINSIC void write(caligned_t, T* __restrict ptr, const vec& __restrict x) CMT_NOEXCEPT +{ + *reinterpret_cast::simd_type*>(ptr) = x.v; +} + +} // namespace intrinsics + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/round.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/round.hpp new file mode 100644 index 00000000..d20ad45a --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/round.hpp @@ -0,0 +1,282 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../operators.hpp" +#include "abs.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#define KFR_mm_trunc_ps(V) _mm_round_ps((V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm_roundnearest_ps(V) _mm_round_ps((V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) +#define KFR_mm_trunc_pd(V) _mm_round_pd((V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm_roundnearest_pd(V) _mm_round_pd((V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) + +#define KFR_mm_trunc_ss(V) _mm_round_ss(_mm_setzero_ps(), (V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm_roundnearest_ss(V) \ + _mm_round_ss(_mm_setzero_ps(), (V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) +#define KFR_mm_trunc_sd(V) _mm_round_sd(_mm_setzero_pd(), (V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm_roundnearest_sd(V) \ + _mm_round_sd(_mm_setzero_pd(), (V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) + +#define KFR_mm_floor_ss(V) _mm_floor_ss(_mm_setzero_ps(), (V)) +#define KFR_mm_floor_sd(V) _mm_floor_sd(_mm_setzero_pd(), (V)) +#define KFR_mm_ceil_ss(V) _mm_ceil_ss(_mm_setzero_ps(), (V)) +#define KFR_mm_ceil_sd(V) _mm_ceil_sd(_mm_setzero_pd(), (V)) + +#define KFR_mm256_trunc_ps(V) _mm256_round_ps((V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm256_roundnearest_ps(V) _mm256_round_ps((V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) +#define KFR_mm256_trunc_pd(V) _mm256_round_pd((V), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC) +#define KFR_mm256_roundnearest_pd(V) _mm256_round_pd((V), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) + +#if defined CMT_ARCH_SSE41 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC f32sse floor(const f32sse& value) { return _mm_floor_ps(value.v); } +KFR_INTRINSIC f32sse ceil(const f32sse& value) { return _mm_ceil_ps(value.v); } +KFR_INTRINSIC f32sse trunc(const f32sse& value) { return KFR_mm_trunc_ps(value.v); } +KFR_INTRINSIC f32sse round(const f32sse& value) { return KFR_mm_roundnearest_ps(value.v); } +KFR_INTRINSIC f64sse floor(const f64sse& value) { return _mm_floor_pd(value.v); } +KFR_INTRINSIC f64sse ceil(const f64sse& value) { return _mm_ceil_pd(value.v); } +KFR_INTRINSIC f64sse trunc(const f64sse& value) { return KFR_mm_trunc_pd(value.v); } +KFR_INTRINSIC f64sse round(const f64sse& value) { return KFR_mm_roundnearest_pd(value.v); } +KFR_INTRINSIC f32sse fract(const f32sse& x) { return x - floor(x); } +KFR_INTRINSIC f64sse fract(const f64sse& x) { return x - floor(x); } + +#if defined CMT_ARCH_AVX + +KFR_INTRINSIC f32avx floor(const f32avx& value) { return _mm256_floor_ps(value.v); } +KFR_INTRINSIC f32avx ceil(const f32avx& value) { return _mm256_ceil_ps(value.v); } +KFR_INTRINSIC f32avx trunc(const f32avx& value) { return KFR_mm256_trunc_ps(value.v); } +KFR_INTRINSIC f32avx round(const f32avx& value) { return KFR_mm256_roundnearest_ps(value.v); } +KFR_INTRINSIC f64avx floor(const f64avx& value) { return _mm256_floor_pd(value.v); } +KFR_INTRINSIC f64avx ceil(const f64avx& value) { return _mm256_ceil_pd(value.v); } +KFR_INTRINSIC f64avx trunc(const f64avx& value) { return KFR_mm256_trunc_pd(value.v); } +KFR_INTRINSIC f64avx round(const f64avx& value) { return KFR_mm256_roundnearest_pd(value.v); } +KFR_INTRINSIC f32avx fract(const f32avx& x) { return x - floor(x); } +KFR_INTRINSIC f64avx fract(const f64avx& x) { return x - floor(x); } + +#endif + +#if defined CMT_ARCH_AVX512 + +KFR_INTRINSIC f32avx512 floor(const f32avx512& value) +{ + return _mm512_roundscale_ps(value.v, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f32avx512 ceil(const f32avx512& value) +{ + return _mm512_roundscale_ps(value.v, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f32avx512 trunc(const f32avx512& value) +{ + return _mm512_roundscale_ps(value.v, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f32avx512 round(const f32avx512& value) +{ + return _mm512_roundscale_ps(value.v, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f64avx512 floor(const f64avx512& value) +{ + return _mm512_roundscale_pd(value.v, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f64avx512 ceil(const f64avx512& value) +{ + return _mm512_roundscale_pd(value.v, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f64avx512 trunc(const f64avx512& value) +{ + return _mm512_roundscale_pd(value.v, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f64avx512 round(const f64avx512& value) +{ + return _mm512_roundscale_pd(value.v, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); +} +KFR_INTRINSIC f32avx512 fract(const f32avx512& x) { return x - floor(x); } +KFR_INTRINSIC f64avx512 fract(const f64avx512& x) { return x - floor(x); } +#endif + +KFR_HANDLE_ALL_SIZES_1_IF(floor, is_f_class) +KFR_HANDLE_ALL_SIZES_1_IF(ceil, is_f_class) +KFR_HANDLE_ALL_SIZES_1_IF(round, is_f_class) +KFR_HANDLE_ALL_SIZES_1_IF(trunc, is_f_class) +KFR_HANDLE_ALL_SIZES_1_IF(fract, is_f_class) + +#else + +// fallback + +template +constexpr inline T fp_precision_limit = 4503599627370496.0; +template <> +constexpr inline f32 fp_precision_limit = 16777216.0f; + +template +KFR_INTRINSIC vec floor(const vec& x) +{ + vec t = broadcastto(broadcastto(x)); + return select(abs(x) >= fp_precision_limit, x, t - select(x < t, 1.f, 0.f)); +} +template +KFR_INTRINSIC vec floor(const vec& x) +{ + vec t = broadcastto(broadcastto(x)); + return select(abs(x) >= fp_precision_limit, x, t - select(x < t, 1., 0.)); +} +template +KFR_INTRINSIC vec ceil(const vec& x) +{ + vec t = broadcastto(broadcastto(x)); + return select(abs(x) >= fp_precision_limit, x, t + select(x > t, 1.f, 0.f)); +} +template +KFR_INTRINSIC vec ceil(const vec& x) +{ + vec t = broadcastto(broadcastto(x)); + return select(abs(x) >= fp_precision_limit, x, t + select(x > t, 1., 0.)); +} +template +KFR_INTRINSIC vec round(const vec& x) +{ + return select(abs(x) >= fp_precision_limit, x, + broadcastto(broadcastto(x + mulsign(broadcast(0.5f), x)))); +} +template +KFR_INTRINSIC vec round(const vec& x) +{ + return select(abs(x) >= fp_precision_limit, x, + broadcastto(broadcastto(x + mulsign(broadcast(0.5), x)))); +} +template +KFR_INTRINSIC vec trunc(const vec& x) +{ + return select(abs(x) >= fp_precision_limit, x, broadcastto(broadcastto(x))); +} +template +KFR_INTRINSIC vec trunc(const vec& x) +{ + return select(abs(x) >= fp_precision_limit, x, broadcastto(broadcastto(x))); +} +template +KFR_INTRINSIC vec fract(const vec& x) +{ + return x - floor(x); +} +template +KFR_INTRINSIC vec fract(const vec& x) +{ + return x - floor(x); +} +#endif + +template )> +KFR_INTRINSIC vec floor(const vec& value) +{ + return value; +} +template )> +KFR_INTRINSIC vec ceil(const vec& value) +{ + return value; +} +template )> +KFR_INTRINSIC vec trunc(const vec& value) +{ + return value; +} +template )> +KFR_INTRINSIC vec round(const vec& value) +{ + return value; +} +template )> +KFR_INTRINSIC vec fract(const vec&) +{ + return T(0); +} + +template > +KFR_INTRINSIC vec ifloor(const vec& value) +{ + return broadcastto(floor(value)); +} +template > +KFR_INTRINSIC vec iceil(const vec& value) +{ + return broadcastto(ceil(value)); +} +template > +KFR_INTRINSIC vec itrunc(const vec& value) +{ + return broadcastto(trunc(value)); +} +template > +KFR_INTRINSIC vec iround(const vec& value) +{ + return broadcastto(round(value)); +} + +KFR_HANDLE_SCALAR(floor) +KFR_HANDLE_SCALAR(ceil) +KFR_HANDLE_SCALAR(round) +KFR_HANDLE_SCALAR(trunc) +KFR_HANDLE_SCALAR(fract) +KFR_HANDLE_SCALAR(ifloor) +KFR_HANDLE_SCALAR(iceil) +KFR_HANDLE_SCALAR(iround) +KFR_HANDLE_SCALAR(itrunc) +} // namespace intrinsics +KFR_I_FN(floor) +KFR_I_FN(ceil) +KFR_I_FN(round) +KFR_I_FN(trunc) +KFR_I_FN(fract) +KFR_I_FN(ifloor) +KFR_I_FN(iceil) +KFR_I_FN(iround) +KFR_I_FN(itrunc) +} // namespace CMT_ARCH_NAME +} // namespace kfr + +#undef KFR_mm_trunc_ps +#undef KFR_mm_roundnearest_ps +#undef KFR_mm_trunc_pd +#undef KFR_mm_roundnearest_pd +#undef KFR_mm_trunc_ss +#undef KFR_mm_roundnearest_ss +#undef KFR_mm_trunc_sd +#undef KFR_mm_roundnearest_sd +#undef KFR_mm_floor_ss +#undef KFR_mm_floor_sd +#undef KFR_mm_ceil_ss +#undef KFR_mm_ceil_sd +#undef KFR_mm256_trunc_ps +#undef KFR_mm256_roundnearest_ps +#undef KFR_mm256_trunc_pd +#undef KFR_mm256_roundnearest_pd diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/saturation.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/saturation.hpp new file mode 100644 index 00000000..57da206f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/saturation.hpp @@ -0,0 +1,205 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../operators.hpp" +#include "../select.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +// Generic functions +template +KFR_INTRINSIC vec saturated_signed_add(const vec& a, const vec& b) +{ + using UT = utype; + constexpr size_t shift = typebits::bits - 1; + vec aa = bitcast(a); + vec bb = bitcast(b); + const vec sum = aa + bb; + aa = (aa >> shift) + static_cast(std::numeric_limits::max()); + + return select(bitcast((aa ^ bb) | ~(bb ^ sum)) >= T(), a, bitcast(sum)); +} +template +KFR_INTRINSIC vec saturated_signed_sub(const vec& a, const vec& b) +{ + using UT = utype; + constexpr size_t shift = typebits::bits - 1; + vec aa = bitcast(a); + vec bb = bitcast(b); + const vec diff = aa - bb; + aa = (aa >> shift) + static_cast(std::numeric_limits::max()); + + return select(bitcast((aa ^ bb) & (aa ^ diff)) < T(), a, bitcast(diff)); +} +template +KFR_INTRINSIC vec saturated_unsigned_add(const vec& a, const vec& b) +{ + const vec t = allonesvector(a); + return select(a > t - b, t, a + b); +} +template +KFR_INTRINSIC vec saturated_unsigned_sub(const vec& a, const vec& b) +{ + return select(a < b, zerovector(a), a - b); +} + +#if defined CMT_ARCH_SSE2 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC u8sse satadd(const u8sse& x, const u8sse& y) { return _mm_adds_epu8(x.v, y.v); } +KFR_INTRINSIC i8sse satadd(const i8sse& x, const i8sse& y) { return _mm_adds_epi8(x.v, y.v); } +KFR_INTRINSIC u16sse satadd(const u16sse& x, const u16sse& y) { return _mm_adds_epu16(x.v, y.v); } +KFR_INTRINSIC i16sse satadd(const i16sse& x, const i16sse& y) { return _mm_adds_epi16(x.v, y.v); } + +KFR_INTRINSIC u8sse satsub(const u8sse& x, const u8sse& y) { return _mm_subs_epu8(x.v, y.v); } +KFR_INTRINSIC i8sse satsub(const i8sse& x, const i8sse& y) { return _mm_subs_epi8(x.v, y.v); } +KFR_INTRINSIC u16sse satsub(const u16sse& x, const u16sse& y) { return _mm_subs_epu16(x.v, y.v); } +KFR_INTRINSIC i16sse satsub(const i16sse& x, const i16sse& y) { return _mm_subs_epi16(x.v, y.v); } + +KFR_INTRINSIC i32sse satadd(const i32sse& a, const i32sse& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC i64sse satadd(const i64sse& a, const i64sse& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC u32sse satadd(const u32sse& a, const u32sse& b) { return saturated_unsigned_add(a, b); } +KFR_INTRINSIC u64sse satadd(const u64sse& a, const u64sse& b) { return saturated_unsigned_add(a, b); } + +KFR_INTRINSIC i32sse satsub(const i32sse& a, const i32sse& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC i64sse satsub(const i64sse& a, const i64sse& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC u32sse satsub(const u32sse& a, const u32sse& b) { return saturated_unsigned_sub(a, b); } +KFR_INTRINSIC u64sse satsub(const u64sse& a, const u64sse& b) { return saturated_unsigned_sub(a, b); } + +#if defined CMT_ARCH_AVX2 +KFR_INTRINSIC u8avx satadd(const u8avx& x, const u8avx& y) { return _mm256_adds_epu8(x.v, y.v); } +KFR_INTRINSIC i8avx satadd(const i8avx& x, const i8avx& y) { return _mm256_adds_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx satadd(const u16avx& x, const u16avx& y) { return _mm256_adds_epu16(x.v, y.v); } +KFR_INTRINSIC i16avx satadd(const i16avx& x, const i16avx& y) { return _mm256_adds_epi16(x.v, y.v); } + +KFR_INTRINSIC u8avx satsub(const u8avx& x, const u8avx& y) { return _mm256_subs_epu8(x.v, y.v); } +KFR_INTRINSIC i8avx satsub(const i8avx& x, const i8avx& y) { return _mm256_subs_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx satsub(const u16avx& x, const u16avx& y) { return _mm256_subs_epu16(x.v, y.v); } +KFR_INTRINSIC i16avx satsub(const i16avx& x, const i16avx& y) { return _mm256_subs_epi16(x.v, y.v); } + +KFR_INTRINSIC i32avx satadd(const i32avx& a, const i32avx& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC i64avx satadd(const i64avx& a, const i64avx& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC u32avx satadd(const u32avx& a, const u32avx& b) { return saturated_unsigned_add(a, b); } +KFR_INTRINSIC u64avx satadd(const u64avx& a, const u64avx& b) { return saturated_unsigned_add(a, b); } + +KFR_INTRINSIC i32avx satsub(const i32avx& a, const i32avx& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC i64avx satsub(const i64avx& a, const i64avx& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC u32avx satsub(const u32avx& a, const u32avx& b) { return saturated_unsigned_sub(a, b); } +KFR_INTRINSIC u64avx satsub(const u64avx& a, const u64avx& b) { return saturated_unsigned_sub(a, b); } +#endif + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC u8avx512 satadd(const u8avx512& x, const u8avx512& y) { return _mm512_adds_epu8(x.v, y.v); } +KFR_INTRINSIC i8avx512 satadd(const i8avx512& x, const i8avx512& y) { return _mm512_adds_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 satadd(const u16avx512& x, const u16avx512& y) { return _mm512_adds_epu16(x.v, y.v); } +KFR_INTRINSIC i16avx512 satadd(const i16avx512& x, const i16avx512& y) { return _mm512_adds_epi16(x.v, y.v); } +KFR_INTRINSIC u8avx512 satsub(const u8avx512& x, const u8avx512& y) { return _mm512_subs_epu8(x.v, y.v); } +KFR_INTRINSIC i8avx512 satsub(const i8avx512& x, const i8avx512& y) { return _mm512_subs_epi8(x.v, y.v); } +KFR_INTRINSIC u16avx512 satsub(const u16avx512& x, const u16avx512& y) { return _mm512_subs_epu16(x.v, y.v); } +KFR_INTRINSIC i16avx512 satsub(const i16avx512& x, const i16avx512& y) { return _mm512_subs_epi16(x.v, y.v); } + +KFR_INTRINSIC i32avx512 satadd(const i32avx512& a, const i32avx512& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC i64avx512 satadd(const i64avx512& a, const i64avx512& b) { return saturated_signed_add(a, b); } +KFR_INTRINSIC u32avx512 satadd(const u32avx512& a, const u32avx512& b) +{ + return saturated_unsigned_add(a, b); +} +KFR_INTRINSIC u64avx512 satadd(const u64avx512& a, const u64avx512& b) +{ + return saturated_unsigned_add(a, b); +} +KFR_INTRINSIC i32avx512 satsub(const i32avx512& a, const i32avx512& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC i64avx512 satsub(const i64avx512& a, const i64avx512& b) { return saturated_signed_sub(a, b); } +KFR_INTRINSIC u32avx512 satsub(const u32avx512& a, const u32avx512& b) +{ + return saturated_unsigned_sub(a, b); +} +KFR_INTRINSIC u64avx512 satsub(const u64avx512& a, const u64avx512& b) +{ + return saturated_unsigned_sub(a, b); +} +#endif + +KFR_HANDLE_ALL_SIZES_2(satadd) +KFR_HANDLE_ALL_SIZES_2(satsub) + +#elif defined CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC u8neon satadd(const u8neon& x, const u8neon& y) { return vqaddq_u8(x.v, y.v); } +KFR_INTRINSIC i8neon satadd(const i8neon& x, const i8neon& y) { return vqaddq_s8(x.v, y.v); } +KFR_INTRINSIC u16neon satadd(const u16neon& x, const u16neon& y) { return vqaddq_u16(x.v, y.v); } +KFR_INTRINSIC i16neon satadd(const i16neon& x, const i16neon& y) { return vqaddq_s16(x.v, y.v); } +KFR_INTRINSIC u32neon satadd(const u32neon& a, const u32neon& b) { return vqaddq_u32(a.v, b.v); } +KFR_INTRINSIC i32neon satadd(const i32neon& a, const i32neon& b) { return vqaddq_s32(a.v, b.v); } +KFR_INTRINSIC u64neon satadd(const u64neon& a, const u64neon& b) { return vqaddq_u64(a.v, b.v); } +KFR_INTRINSIC i64neon satadd(const i64neon& a, const i64neon& b) { return vqaddq_s64(a.v, b.v); } + +KFR_INTRINSIC u8neon satsub(const u8neon& x, const u8neon& y) { return vqsubq_u8(x.v, y.v); } +KFR_INTRINSIC i8neon satsub(const i8neon& x, const i8neon& y) { return vqsubq_s8(x.v, y.v); } +KFR_INTRINSIC u16neon satsub(const u16neon& x, const u16neon& y) { return vqsubq_u16(x.v, y.v); } +KFR_INTRINSIC i16neon satsub(const i16neon& x, const i16neon& y) { return vqsubq_s16(x.v, y.v); } +KFR_INTRINSIC u32neon satsub(const u32neon& a, const u32neon& b) { return vqsubq_u32(a.v, b.v); } +KFR_INTRINSIC i32neon satsub(const i32neon& a, const i32neon& b) { return vqsubq_s32(a.v, b.v); } +KFR_INTRINSIC u64neon satsub(const u64neon& a, const u64neon& b) { return vqsubq_u64(a.v, b.v); } +KFR_INTRINSIC i64neon satsub(const i64neon& a, const i64neon& b) { return vqsubq_s64(a.v, b.v); } + +KFR_HANDLE_ALL_SIZES_2(satadd) +KFR_HANDLE_ALL_SIZES_2(satsub) + +#else +// fallback +template )> +KFR_INTRINSIC vec satadd(const vec& a, const vec& b) +{ + return saturated_signed_add(a, b); +} +template )> +KFR_INTRINSIC vec satadd(const vec& a, const vec& b) +{ + return saturated_unsigned_add(a, b); +} +template )> +KFR_INTRINSIC vec satsub(const vec& a, const vec& b) +{ + return saturated_signed_sub(a, b); +} +template )> +KFR_INTRINSIC vec satsub(const vec& a, const vec& b) +{ + return saturated_unsigned_sub(a, b); +} +#endif +KFR_HANDLE_SCALAR(satadd) +KFR_HANDLE_SCALAR(satsub) +} // namespace intrinsics +KFR_I_FN(satadd) +KFR_I_FN(satsub) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/select.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/select.hpp new file mode 100644 index 00000000..6e8253dc --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/select.hpp @@ -0,0 +1,331 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../operators.hpp" +#include "function.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +#if defined CMT_ARCH_SSE41 && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC u8sse select(const mu8sse& m, const u8sse& x, const u8sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u16sse select(const mu16sse& m, const u16sse& x, const u16sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u32sse select(const mu32sse& m, const u32sse& x, const u32sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u64sse select(const mu64sse& m, const u64sse& x, const u64sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i8sse select(const mi8sse& m, const i8sse& x, const i8sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i16sse select(const mi16sse& m, const i16sse& x, const i16sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i32sse select(const mi32sse& m, const i32sse& x, const i32sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i64sse select(const mi64sse& m, const i64sse& x, const i64sse& y) +{ + return _mm_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC f32sse select(const mf32sse& m, const f32sse& x, const f32sse& y) +{ + return _mm_blendv_ps(y.v, x.v, m.v); +} +KFR_INTRINSIC f64sse select(const mf64sse& m, const f64sse& x, const f64sse& y) +{ + return _mm_blendv_pd(y.v, x.v, m.v); +} + +#if defined CMT_ARCH_AVX +KFR_INTRINSIC f64avx select(const mf64avx& m, const f64avx& x, const f64avx& y) +{ + return _mm256_blendv_pd(y.v, x.v, m.v); +} +KFR_INTRINSIC f32avx select(const mf32avx& m, const f32avx& x, const f32avx& y) +{ + return _mm256_blendv_ps(y.v, x.v, m.v); +} +#endif + +#if defined CMT_ARCH_AVX2 +KFR_INTRINSIC u8avx select(const mu8avx& m, const u8avx& x, const u8avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u16avx select(const mu16avx& m, const u16avx& x, const u16avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u32avx select(const mu32avx& m, const u32avx& x, const u32avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC u64avx select(const mu64avx& m, const u64avx& x, const u64avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i8avx select(const mi8avx& m, const i8avx& x, const i8avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i16avx select(const mi16avx& m, const i16avx& x, const i16avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i32avx select(const mi32avx& m, const i32avx& x, const i32avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +KFR_INTRINSIC i64avx select(const mi64avx& m, const i64avx& x, const i64avx& y) +{ + return _mm256_blendv_epi8(y.v, x.v, m.v); +} +#endif + +#if defined CMT_ARCH_AVX512 +KFR_INTRINSIC f64avx512 select(const mf64avx512& m, const f64avx512& x, const f64avx512& y) +{ + return _mm512_mask_blend_pd(_mm512_movepi64_mask(_mm512_castpd_si512(m.v)), y.v, x.v); +} +KFR_INTRINSIC f32avx512 select(const mf32avx512& m, const f32avx512& x, const f32avx512& y) +{ + return _mm512_mask_blend_ps(_mm512_movepi32_mask(_mm512_castps_si512(m.v)), y.v, x.v); +} +KFR_INTRINSIC u8avx512 select(const mu8avx512& m, const u8avx512& x, const u8avx512& y) +{ + return _mm512_mask_blend_epi8(_mm512_movepi8_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC u16avx512 select(const mu16avx512& m, const u16avx512& x, const u16avx512& y) +{ + return _mm512_mask_blend_epi16(_mm512_movepi16_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC u32avx512 select(const mu32avx512& m, const u32avx512& x, const u32avx512& y) +{ + return _mm512_mask_blend_epi32(_mm512_movepi32_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC u64avx512 select(const mu64avx512& m, const u64avx512& x, const u64avx512& y) +{ + return _mm512_mask_blend_epi64(_mm512_movepi64_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC i8avx512 select(const mi8avx512& m, const i8avx512& x, const i8avx512& y) +{ + return _mm512_mask_blend_epi8(_mm512_movepi8_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC i16avx512 select(const mi16avx512& m, const i16avx512& x, const i16avx512& y) +{ + return _mm512_mask_blend_epi16(_mm512_movepi16_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC i32avx512 select(const mi32avx512& m, const i32avx512& x, const i32avx512& y) +{ + return _mm512_mask_blend_epi32(_mm512_movepi32_mask(m.v), y.v, x.v); +} +KFR_INTRINSIC i64avx512 select(const mi64avx512& m, const i64avx512& x, const i64avx512& y) +{ + return _mm512_mask_blend_epi64(_mm512_movepi64_mask(m.v), y.v, x.v); +} +#endif + +template && !is_simd_size(N))> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const vec& c) +{ + constexpr size_t Nout = next_simd_width(N); + return select(a.shuffle(csizeseq), b.shuffle(csizeseq), c.shuffle(csizeseq)) + .shuffle(csizeseq); +} +template vector_width), typename = void> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const vec& c) +{ + return concat(select(low(a), low(b), low(c)), select(high(a), high(b), high(c))); + // return concat2(select(a.h.low, b.h.low, c.h.low), select(a.h.high, b.h.high, c.h.high)); +} + +template && !is_simd_size(N))> +KFR_INTRINSIC vec select(const vec, N>& a, const T& b, const T& c) +{ + constexpr size_t Nout = next_simd_width(N); + return select(a.shuffle(csizeseq), vec(b), vec(c)).shuffle(csizeseq); +} +template vector_width), typename = void> +KFR_INTRINSIC vec select(const vec, N>& a, const T& b, const T& c) +{ + return concat2(select(a.h.low, b, c), select(a.h.high, b, c)); +} + +template && !is_simd_size(N))> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const T& c) +{ + constexpr size_t Nout = next_simd_width(N); + return select(a.shuffle(csizeseq), b.shuffle(csizeseq), vec(c)).shuffle(csizeseq); +} +template vector_width), typename = void> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const T& c) +{ + return concat2(select(a.h.low, b.h.low, c), select(a.h.high, b.h.high, c)); +} + +template && !is_simd_size(N))> +KFR_INTRINSIC vec select(const vec, N>& a, const T& b, const vec& c) +{ + constexpr size_t Nout = next_simd_width(N); + return select(shufflevector(a, csizeseq), vec(b), c.shuffle(csizeseq)) + .shuffle(csizeseq); +} +template vector_width), typename = void> +KFR_INTRINSIC vec select(const vec, N>& a, const T& b, const vec& c) +{ + return concat2(select(a.h.low, b, c.h.low), select(a.h.high, b, c.h.high)); +} + +#elif defined CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS + +KFR_INTRINSIC f32neon select(const mf32neon& m, const f32neon& x, const f32neon& y) +{ + return vbslq_f32(m.v, x.v, y.v); +} +KFR_INTRINSIC i8neon select(const mi8neon& m, const i8neon& x, const i8neon& y) +{ + return vbslq_s8(m.v, x.v, y.v); +} +KFR_INTRINSIC u8neon select(const mu8neon& m, const u8neon& x, const u8neon& y) +{ + return vbslq_u8(m.v, x.v, y.v); +} +KFR_INTRINSIC i16neon select(const mi16neon& m, const i16neon& x, const i16neon& y) +{ + return vbslq_s16(m.v, x.v, y.v); +} +KFR_INTRINSIC u16neon select(const mu16neon& m, const u16neon& x, const u16neon& y) +{ + return vbslq_u16(m.v, x.v, y.v); +} +KFR_INTRINSIC i32neon select(const mi32neon& m, const i32neon& x, const i32neon& y) +{ + return vbslq_s32(m.v, x.v, y.v); +} +KFR_INTRINSIC u32neon select(const mu32neon& m, const u32neon& x, const u32neon& y) +{ + return vbslq_u32(m.v, x.v, y.v); +} +KFR_INTRINSIC i64neon select(const mi64neon& m, const i64neon& x, const i64neon& y) +{ + return vbslq_s64(m.v, x.v, y.v); +} +KFR_INTRINSIC u64neon select(const mu64neon& m, const u64neon& x, const u64neon& y) +{ + return vbslq_u64(m.v, x.v, y.v); +} + +#ifdef CMT_ARCH_NEON64 +KFR_INTRINSIC f64neon select(const mf64neon& m, const f64neon& x, const f64neon& y) +{ + return vbslq_f64(m.v, x.v, y.v); +} +#else +KFR_INTRINSIC f64neon select(const mf64neon& m, const f64neon& x, const f64neon& y) +{ + return y ^ ((x ^ y) & m.asvec()); +} +#endif + +template && !is_simd_size(N))> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const vec& c) +{ + constexpr size_t Nout = next_simd_width(N); + return select(a.shuffle(csizeseq), b.shuffle(csizeseq), c.shuffle(csizeseq)) + .shuffle(csizeseq); +} +template vector_width), typename = void> +KFR_INTRINSIC vec select(const vec, N>& a, const vec& b, const vec& c) +{ + return concat2(select(a.h.low, b.h.low, c.h.low), select(a.h.high, b.h.high, c.h.high)); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const T& x, const T& y) +{ + return select(m, vec(x), vec(y)); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const vec& x, const T& y) +{ + return select(m, x, vec(y)); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const T& x, const vec& y) +{ + return select(m, vec(x), y); +} + +#else + +// fallback +template +KFR_INTRINSIC vec select(const vec, N>& m, const vec& x, const vec& y) +{ + return y ^ ((x ^ y) & m.asvec()); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const T& x, const T& y) +{ + return select(m, vec(x), vec(y)); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const vec& x, const T& y) +{ + return select(m, x, vec(y)); +} +template +KFR_INTRINSIC vec select(const vec, N>& m, const T& x, const vec& y) +{ + return select(m, vec(x), y); +} +#endif +template +KFR_INTRINSIC std::common_type_t select(bool m, const T1& x, const T2& y) +{ + return m ? x : y; +} + +} // namespace intrinsics +KFR_I_FN(select) +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/simd.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/simd.hpp new file mode 100644 index 00000000..f4b6a03b --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/simd.hpp @@ -0,0 +1,132 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../constants.hpp" +#include "../platform.hpp" + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +namespace intrinsics +{ + +template +struct simd_t +{ + using value_type = T; + + constexpr static size_t size() { return N; } +}; + +template +struct simd2_t +{ + using value_type = T; + + constexpr static size_t size1() { return N1; } + + constexpr static size_t size2() { return N2; } +}; + +template +struct simd_cvt_t +{ + using value_type_out = Tout; + using value_type_in = Tin; + + constexpr static size_t size() { return N; } +}; + +template +constexpr size_t alignment() +{ + return const_min(size_t(platform<>::native_vector_alignment), next_poweroftwo(sizeof(T) * N)); +} + +template +struct alignas(force_compiletime_size_t()>) simd_array +{ + T val[next_poweroftwo(N)]; +}; + +template +struct simd_type; + +template +struct simd_type +{ + // SFINAE +}; + +template +struct simd_halves +{ + using subtype = typename simd_type::type; + + subtype low; + subtype high; +#if defined KFR_DEFINE_CTORS_FOR_HALVES && KFR_DEFINE_CTORS_FOR_HALVES + simd_halves() CMT_NOEXCEPT {} + simd_halves(const subtype& l, const subtype& h) CMT_NOEXCEPT : low(l), high(h) {} + simd_halves(const simd_halves& v) CMT_NOEXCEPT : low(v.low), high(v.high) {} + simd_halves(simd_halves&& v) CMT_NOEXCEPT : low(v.low), high(v.high) {} + + simd_halves& operator=(const simd_halves& v) CMT_NOEXCEPT + { + low = v.low; + high = v.high; + return *this; + } + simd_halves& operator=(simd_halves&& v) CMT_NOEXCEPT + { + low = v.low; + high = v.high; + return *this; + } +#endif +}; + +} // namespace intrinsics +} // namespace CMT_ARCH_NAME + +#define KFR_COMPONENTWISE_RET(code) \ + vec result; \ + for (size_t i = 0; i < N; i++) \ + code; \ + return result; + +#define KFR_COMPONENTWISE_RET_I(Tvec, code) \ + Tvec result; \ + for (size_t i = 0; i < result.size(); i++) \ + code; \ + return result; + +#define KFR_COMPONENTWISE(code) \ + for (size_t i = 0; i < N; i++) \ + code; + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specialconstants.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specialconstants.hpp new file mode 100644 index 00000000..544cb3a1 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specialconstants.hpp @@ -0,0 +1,101 @@ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../../cometa/numeric.hpp" +#include "intrinsics.h" + +namespace kfr +{ +using namespace cometa; + +#if defined CMT_COMPILER_GNU +constexpr f32 allones_f32() CMT_NOEXCEPT { return -__builtin_nanf("0xFFFFFFFF"); } +constexpr f64 allones_f64() CMT_NOEXCEPT { return -__builtin_nan("0xFFFFFFFFFFFFFFFF"); } +constexpr f32 invhighbit_f32() CMT_NOEXCEPT { return __builtin_nanf("0x7FFFFFFF"); } +constexpr f64 invhighbit_f64() CMT_NOEXCEPT { return __builtin_nan("0x7FFFFFFFFFFFFFFF"); } +#elif defined CMT_COMPILER_MSVC +constexpr f32 allones_f32() CMT_NOEXCEPT { return -__builtin_nanf("-1"); } +constexpr f64 allones_f64() CMT_NOEXCEPT { return -__builtin_nan("-1"); } +constexpr f32 invhighbit_f32() CMT_NOEXCEPT { return __builtin_nanf("-1"); } +constexpr f64 invhighbit_f64() CMT_NOEXCEPT { return __builtin_nan("-1"); } +#else +inline f32 allones_f32() CMT_NOEXCEPT +{ + return _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(0xFFFFFFFFu))); +} +inline f64 allones_f64() CMT_NOEXCEPT +{ + return _mm_cvtsd_f64(_mm_castsi128_pd(_mm_cvtsi64x_si128(0xFFFFFFFFFFFFFFFFull))); +} +inline f32 invhighbit_f32() CMT_NOEXCEPT +{ + return _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(0x7FFFFFFFu))); +} +inline f64 invhighbit_f64() CMT_NOEXCEPT +{ + return _mm_cvtsd_f64(_mm_castsi128_pd(_mm_cvtsi64x_si128(0x7FFFFFFFFFFFFFFFull))); +} +#endif + +template +struct special_scalar_constants +{ + constexpr static T highbitmask() { return static_cast(1ull << (sizeof(T) * 8 - 1)); } + constexpr static T allones() { return static_cast(-1ll); } + constexpr static T allzeros() { return T(0); } + constexpr static T invhighbitmask() { return static_cast((1ull << (sizeof(T) * 8 - 1)) - 1); } +}; + +#ifndef CMT_COMPILER_INTEL +#define KFR_CONSTEXPR_NON_INTEL constexpr +#else +#define KFR_CONSTEXPR_NON_INTEL +#endif + +template <> +struct special_scalar_constants +{ + constexpr static float highbitmask() { return -0.f; } + KFR_CONSTEXPR_NON_INTEL static float allones() noexcept { return allones_f32(); } + constexpr static float allzeros() { return 0.f; } + KFR_CONSTEXPR_NON_INTEL static float invhighbitmask() { return invhighbit_f32(); } +}; + +template <> +struct special_scalar_constants +{ + constexpr static double highbitmask() { return -0.; } + KFR_CONSTEXPR_NON_INTEL static double allones() noexcept { return allones_f64(); } + constexpr static double allzeros() { return 0.; } + KFR_CONSTEXPR_NON_INTEL static double invhighbitmask() { return invhighbit_f64(); } +}; + +template +struct special_constants : public special_scalar_constants> +{ +public: + using Tsub = subtype; +}; + +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specializations.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specializations.hpp new file mode 100644 index 00000000..d45c4685 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/impl/specializations.hpp @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + * This file is part of KFR + * + * KFR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * KFR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KFR. + */ +#pragma once + +#include "../vec.hpp" +#ifndef KFR_SHUFFLE_SPECIALIZATIONS +#include "../shuffle.hpp" +#endif + +#ifdef CMT_COMPILER_GNU + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 1, 8, 9, 16, 17, 24, 25, 2, 3, 10, 11, 18, 19, 26, 27, 4, 5, 12, 13, 20, 21, 28, 29, 6, 7, 14, + 15, 22, 23, 30, 31>) const CMT_NOEXCEPT +{ + f32x32 w = *this; + + w = concat(permute<0, 1, 8, 9, 4, 5, 12, 13, 2, 3, 10, 11, 6, 7, 14, 15>(low(w)), + permute<0, 1, 8, 9, 4, 5, 12, 13, 2, 3, 10, 11, 6, 7, 14, 15>(high(w))); + + w = permutegroups<(4), 0, 4, 2, 6, 1, 5, 3, 7>(w); // avx: vperm2f128 & vinsertf128, sse: no-op + return w; +} + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, 2, 3, 18, 19, 10, 11, 26, 27, 6, 7, 22, + 23, 14, 15, 30, 31>) const CMT_NOEXCEPT +{ + f32x32 w = *this; + + w = concat(permute<0, 1, 8, 9, 4, 5, 12, 13, /**/ 2, 3, 10, 11, 6, 7, 14, 15>(even<8>(w)), + permute<0, 1, 8, 9, 4, 5, 12, 13, /**/ 2, 3, 10, 11, 6, 7, 14, 15>(odd<8>(w))); + + w = permutegroups<(4), 0, 4, 1, 5, 2, 6, 3, 7>(w); // avx: vperm2f128 & vinsertf128, sse: no-op + return w; +} + +inline vec bitreverse_2(const vec& x) +{ + return x.shuffle(csizes<0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, 2, 3, 18, 19, 10, 11, + 26, 27, 6, 7, 22, 23, 14, 15, 30, 31>); +} + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 1, 32, 33, 16, 17, 48, 49, 8, 9, 40, 41, 24, 25, 56, 57, 4, 5, 36, 37, 20, 21, 52, 53, 12, 13, + 44, 45, 28, 29, 60, 61, 2, 3, 34, 35, 18, 19, 50, 51, 10, 11, 42, 43, 26, 27, 58, 59, 6, 7, 38, + 39, 22, 23, 54, 55, 14, 15, 46, 47, 30, 31, 62, 63>) const CMT_NOEXCEPT +{ + return permutegroups<(8), 0, 4, 1, 5, 2, 6, 3, 7>( + concat(bitreverse_2(even<8>(*this)), bitreverse_2(odd<8>(*this)))); +} + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15>) const CMT_NOEXCEPT +{ + const vec xx = permutegroups<(4), 0, 2, 1, 3>(*this); + + return concat(low(xx).shuffle(high(xx), csizes<0, 2, 8 + 0, 8 + 2, 4, 6, 8 + 4, 8 + 6>), + low(xx).shuffle(high(xx), csizes<1, 3, 8 + 1, 8 + 3, 5, 7, 8 + 5, 8 + 7>)); +} + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15>) const CMT_NOEXCEPT +{ + const vec xx = + concat(low(*this).shuffle(high(*this), csizes<0, 8 + 0, 1, 8 + 1, 4, 8 + 4, 5, 8 + 5>), + low(*this).shuffle(high(*this), csizes<2, 8 + 2, 3, 8 + 3, 6, 8 + 6, 7, 8 + 7>)); + + return permutegroups<(4), 0, 2, 1, 3>(xx); +} + +template <> +template <> +inline vec vec::shuffle( + csizes_t<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23, 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, + 29, 14, 30, 15, 31>) const CMT_NOEXCEPT +{ + const vec xx = permutegroups<(8), 0, 2, 1, 3>(*this); + + return concat(interleavehalves(low(xx)), interleavehalves(high(xx))); +} + +} // namespace CMT_ARCH_NAME +} // namespace kfr +#endif diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/logical.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/logical.hpp new file mode 100644 index 00000000..9ce10500 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/logical.hpp @@ -0,0 +1,54 @@ +/** @addtogroup logical + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/logical.hpp" + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns x[0] && x[1] && ... && x[N-1] + */ +template +KFR_INTRINSIC bool all(const mask& x) +{ + return intrinsics::bittestall(x); +} + +/** + * @brief Returns x[0] || x[1] || ... || x[N-1] + */ +template +KFR_INTRINSIC bool any(const mask& x) +{ + return intrinsics::bittestany(x); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/mask.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/mask.hpp new file mode 100644 index 00000000..213b457f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/mask.hpp @@ -0,0 +1,62 @@ +/** @addtogroup logical + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "vec.hpp" + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +template +using maskfor = typename T::mask_t; + +namespace internal +{ + +template +constexpr vec partial_mask_helper(csizes_t) +{ + return make_vector(maskbits(indices < N1)...); +} + +template +constexpr vec partial_mask() +{ + return internal::partial_mask_helper(csizeseq_t()); +} +} // namespace internal + +template +constexpr KFR_INTRINSIC vec, Nout> make_mask(bool arg, Args... args) +{ + return vec, Nout>(arg, static_cast(args)...); +} + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/min_max.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/min_max.hpp new file mode 100644 index 00000000..d247ccc9 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/min_max.hpp @@ -0,0 +1,75 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/min_max.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns the smaller of two values. + */ +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout min(const T1& x, const T2& y) +{ + return intrinsics::min(x, y); +} + +/** + * @brief Returns the greater of two values. + */ +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout max(const T1& x, const T2& y) +{ + return intrinsics::max(x, y); +} + +/** + * @brief Returns the smaller in magnitude of two values. + */ +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout absmin(const T1& x, const T2& y) +{ + return intrinsics::absmin(x, y); +} + +/** + * @brief Returns the greater in magnitude of two values. + */ +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout absmax(const T1& x, const T2& y) +{ + return intrinsics::absmax(x, y); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/operators.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/operators.hpp new file mode 100644 index 00000000..2b0c9bbc --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/operators.hpp @@ -0,0 +1,651 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/operators.hpp" +#include "mask.hpp" +#include +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 4244)) + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +#define KFR_VEC_OPERATOR1(op, fn) \ + template ) */> \ + constexpr KFR_INTRINSIC vec operator op(const vec& x) \ + { \ + return intrinsics::fn(x); \ + } + +#define KFR_VEC_OPERATOR2(op, asgnop, fn) \ + template == vec_rank)> \ + constexpr KFR_INTRINSIC vec& operator asgnop(vec& x, const vec& y) \ + { \ + x = intrinsics::fn(x, promoteto(y)); \ + return x; \ + } \ + template > vec_rank)> \ + constexpr KFR_INTRINSIC vec& operator asgnop(vec& x, const T2 & y) \ + { \ + x = intrinsics::fn(x, T1(y)); \ + return x; \ + } \ + template , \ + KFR_ENABLE_IF(1 + vec_rank > vec_rank)> \ + constexpr KFR_INTRINSIC vec operator op(const vec& x, const T2 & y) \ + { \ + return intrinsics::fn(promoteto(x), C(y)); \ + } \ + template , \ + KFR_ENABLE_IF(vec_rank < 1 + vec_rank)> \ + constexpr KFR_INTRINSIC vec operator op(const T1 & x, const vec& y) \ + { \ + return intrinsics::fn(C(x), promoteto(y)); \ + } \ + template , \ + KFR_ENABLE_IF(vec_rank == vec_rank)> \ + constexpr KFR_INTRINSIC vec operator op(const vec& x, const vec& y) \ + { \ + return intrinsics::fn(promoteto(x), promoteto(y)); \ + } + +#define KFR_VEC_SHIFT_OPERATOR(op, asgnop, fn) \ + template \ + constexpr KFR_INTRINSIC vec& operator asgnop(vec& x, unsigned y) \ + { \ + x = intrinsics::fn(x, y); \ + return x; \ + } \ + template == vec_rank)> \ + constexpr KFR_INTRINSIC vec& operator asgnop(vec& x, const vec& y) \ + { \ + x = intrinsics::fn(x, promoteto>(y)); \ + return x; \ + } \ + template \ + constexpr KFR_INTRINSIC vec operator op(const vec& x, unsigned y) \ + { \ + return intrinsics::fn(x, y); \ + } \ + template < 1 + vec_rank)> \ + constexpr KFR_INTRINSIC vec operator op(const T1 & x, const vec& y) \ + { \ + return intrinsics::fn(broadcastto(x), promoteto>(y)); \ + } \ + template == vec_rank)> \ + constexpr KFR_INTRINSIC vec operator op(const vec& x, const vec& y) \ + { \ + return intrinsics::fn(x, promoteto>(y)); \ + } + +#define KFR_VEC_CMP_OPERATOR(op, fn) \ + template , \ + KFR_ENABLE_IF(1 + vec_rank > vec_rank)> \ + constexpr KFR_INTRINSIC mask operator op(const vec& x, const T2 & y) \ + { \ + return intrinsics::fn(promoteto(x), vec(y)).asmask(); \ + } \ + template , \ + KFR_ENABLE_IF(vec_rank < 1 + vec_rank)> \ + constexpr KFR_INTRINSIC mask operator op(const T1 & x, const vec& y) \ + { \ + return intrinsics::fn(vec(x), promoteto(y)).asmask(); \ + } \ + template , \ + KFR_ENABLE_IF(vec_rank == vec_rank)> \ + constexpr KFR_INTRINSIC mask operator op(const vec& x, const vec& y) \ + { \ + return intrinsics::fn(promoteto(x), promoteto(y)).asmask(); \ + } + +KFR_VEC_OPERATOR1(-, neg) +KFR_VEC_OPERATOR1(~, bnot) + +KFR_VEC_OPERATOR2(+, +=, add) +KFR_VEC_OPERATOR2(-, -=, sub) +KFR_VEC_OPERATOR2(*, *=, mul) +KFR_VEC_OPERATOR2(/, /=, div) +KFR_VEC_OPERATOR2(%, %=, mod) + +KFR_VEC_OPERATOR2(&, &=, band) +KFR_VEC_OPERATOR2(|, |=, bor) +KFR_VEC_OPERATOR2(^, ^=, bxor) +KFR_VEC_SHIFT_OPERATOR(<<, <<=, shl) +KFR_VEC_SHIFT_OPERATOR(>>, >>=, shr) + +KFR_VEC_CMP_OPERATOR(==, eq) +KFR_VEC_CMP_OPERATOR(!=, ne) +KFR_VEC_CMP_OPERATOR(>=, ge) +KFR_VEC_CMP_OPERATOR(<=, le) +KFR_VEC_CMP_OPERATOR(>, gt) +KFR_VEC_CMP_OPERATOR(<, lt) + +template , + KFR_ENABLE_IF(sizeof(T1) == sizeof(T2))> +KFR_INTRINSIC mask operator&(const mask& x, const mask& y) CMT_NOEXCEPT +{ + return mask((bitcast(vec(x.v)) & bitcast(vec(y.v))).v); +} +template , + KFR_ENABLE_IF(sizeof(T1) == sizeof(T2))> +KFR_INTRINSIC mask operator|(const mask& x, const mask& y) CMT_NOEXCEPT +{ + return mask((bitcast(vec(x.v)) | bitcast(vec(y.v))).v); +} +template , + KFR_ENABLE_IF(sizeof(T1) == sizeof(T2))> +KFR_INTRINSIC mask operator&&(const mask& x, const mask& y) CMT_NOEXCEPT +{ + return mask((bitcast(vec(x.v)) & bitcast(vec(y.v))).v); +} +template , + KFR_ENABLE_IF(sizeof(T1) == sizeof(T2))> +KFR_INTRINSIC mask operator||(const mask& x, const mask& y) CMT_NOEXCEPT +{ + return mask((bitcast(vec(x.v)) | bitcast(vec(y.v))).v); +} +template , + KFR_ENABLE_IF(sizeof(T1) == sizeof(T2))> +KFR_INTRINSIC mask operator^(const mask& x, const mask& y) CMT_NOEXCEPT +{ + return mask((bitcast(vec(x.v)) ^ bitcast(vec(y.v))).v); +} + +template +KFR_INTRINSIC mask operator~(const mask& x) CMT_NOEXCEPT +{ + return mask(~x.asvec()); +} +template +KFR_INTRINSIC mask operator!(const mask& x) CMT_NOEXCEPT +{ + return mask(~x.asvec()); +} + +KFR_INTRINSIC float bitwisenot(float x) { return fbitcast(~ubitcast(x)); } +KFR_INTRINSIC float bitwiseor(float x, float y) { return fbitcast(ubitcast(x) | ubitcast(y)); } +KFR_INTRINSIC float bitwiseand(float x, float y) { return fbitcast(ubitcast(x) & ubitcast(y)); } +KFR_INTRINSIC float bitwiseandnot(float x, float y) { return fbitcast(ubitcast(x) & ~ubitcast(y)); } +KFR_INTRINSIC float bitwisexor(float x, float y) { return fbitcast(ubitcast(x) ^ ubitcast(y)); } +KFR_INTRINSIC double bitwisenot(double x) { return fbitcast(~ubitcast(x)); } +KFR_INTRINSIC double bitwiseor(double x, double y) { return fbitcast(ubitcast(x) | ubitcast(y)); } +KFR_INTRINSIC double bitwiseand(double x, double y) { return fbitcast(ubitcast(x) & ubitcast(y)); } +KFR_INTRINSIC double bitwiseandnot(double x, double y) { return fbitcast(ubitcast(x) & ~ubitcast(y)); } +KFR_INTRINSIC double bitwisexor(double x, double y) { return fbitcast(ubitcast(x) ^ ubitcast(y)); } + +/// @brief Bitwise Not +template +KFR_INTRINSIC T1 bitwisenot(const T1& x) +{ + return ~x; +} +KFR_FN(bitwisenot) + +/// @brief Bitwise And +template +KFR_INTRINSIC std::common_type_t bitwiseand(const T1& x, const T2& y) +{ + return x & y; +} +template +constexpr KFR_INTRINSIC T bitwiseand(initialvalue) +{ + return special_constants::allones(); +} +KFR_FN(bitwiseand) + +/// @brief Bitwise And-Not +template +KFR_INTRINSIC std::common_type_t bitwiseandnot(const T1& x, const T2& y) +{ + return x & ~y; +} +template +constexpr inline T bitwiseandnot(initialvalue) +{ + return special_constants::allones(); +} +KFR_FN(bitwiseandnot) + +/// @brief Bitwise Or +template +KFR_INTRINSIC std::common_type_t bitwiseor(const T1& x, const T2& y) +{ + return x | y; +} +template +constexpr KFR_INTRINSIC T bitwiseor(initialvalue) +{ + return subtype(0); +} +KFR_FN(bitwiseor) + +/// @brief Bitwise Xor (Exclusive Or) +template +KFR_INTRINSIC std::common_type_t bitwisexor(const T1& x, const T2& y) +{ + return x ^ y; +} +template +constexpr KFR_INTRINSIC T bitwisexor(initialvalue) +{ + return subtype(); +} +KFR_FN(bitwisexor) + +/// @brief Bitwise Left shift +template +KFR_INTRINSIC T1 shl(const T1& left, const T2& right) +{ + return left << right; +} +KFR_FN(shl) + +/// @brief Bitwise Right shift +template +KFR_INTRINSIC T1 shr(const T1& left, const T2& right) +{ + return left >> right; +} +KFR_FN(shr) + +/// @brief Bitwise Left Rotate +template +KFR_INTRINSIC T1 rol(const T1& left, const T2& right) +{ + return shl(left, right) | shr(left, (static_cast>(typebits::bits) - right)); +} +KFR_FN(rol) + +/// @brief Bitwise Right Rotate +template +KFR_INTRINSIC T1 ror(const T1& left, const T2& right) +{ + return shr(left, right) | shl(left, (static_cast>(typebits::bits) - right)); +} +KFR_FN(ror) + +template +constexpr KFR_INTRINSIC T add(const T& x) +{ + return x; +} + +/** + * @brief Returns sum of all the arguments passed to a function. + */ +template )> +constexpr KFR_INTRINSIC std::common_type_t add(const T1& x, const T2& y, const Ts&... rest) +{ + return x + add(y, rest...); +} +template +constexpr KFR_INTRINSIC T add(initialvalue) +{ + return T(0); +} +KFR_FN(add) + +template +constexpr KFR_INTRINSIC std::common_type_t sub(const T1& x, const T2& y) +{ + return x - y; +} +template +constexpr KFR_INTRINSIC T sub(initialvalue) +{ + return T(0); +} +KFR_FN(sub) + +template +constexpr KFR_INTRINSIC T1 mul(const T1& x) +{ + return x; +} + +/** + * @brief Returns product of all the arguments passed to a function. + */ +template +constexpr KFR_INTRINSIC std::common_type_t mul(const T1& x, const T2& y, const Ts&... rest) +{ + return x * mul(y, rest...); +} + +template +constexpr KFR_INTRINSIC T mul(initialvalue) +{ + return T(1); +} +KFR_FN(mul) + +/** + * @brief Returns square of x. + */ +template )> +constexpr inline T1 sqr(const T1& x) +{ + return x * x; +} +KFR_FN(sqr) + +/** + * @brief Returns cube of x. + */ +template )> +constexpr inline T1 cub(const T1& x) +{ + return sqr(x) * x; +} +KFR_FN(cub) + +template )> +constexpr KFR_INTRINSIC T pow2(const T& x) +{ + return sqr(x); +} + +template )> +constexpr KFR_INTRINSIC T pow3(const T& x) +{ + return cub(x); +} + +template )> +constexpr KFR_INTRINSIC T pow4(const T& x) +{ + return sqr(sqr(x)); +} + +template )> +constexpr KFR_INTRINSIC T pow5(const T& x) +{ + return pow4(x) * x; +} +KFR_FN(pow2) +KFR_FN(pow3) +KFR_FN(pow4) +KFR_FN(pow5) + +/// Raise x to the power base \f$ x^{base} \f$ +/// @code +/// CHECK( ipow( 10, 3 ) == 1000 ); +/// CHECK( ipow( 0.5, 2 ) == 0.25 ); +/// @endcode +template +constexpr inline T ipow(const T& x, int base) +{ + T xx = x; + T result = T(1); + while (base) + { + if (base & 1) + result *= xx; + base >>= 1; + xx *= xx; + } + return result; +} +KFR_FN(ipow) + +/// Return square of the sum of all arguments +/// @code +/// CHECK(sqrsum(1,2,3) == 36); +/// @endcode +template +constexpr inline std::common_type_t sqrsum(const T1& x, const Ts&... rest) +{ + return sqr(add(x, rest...)); +} + +template +constexpr inline std::common_type_t sqrdiff(const T1& x, const T2& y) +{ + return sqr(x - y); +} +KFR_FN(sqrsum) +KFR_FN(sqrdiff) + +/// Division +template > +KFR_INTRINSIC Tout div(const T1& x, const T2& y) +{ + return static_cast(x) / static_cast(y); +} +KFR_FN(div) + +/// Modulo +template > +KFR_INTRINSIC Tout mod(const T1& x, const T2& y) +{ + return static_cast(x) % static_cast(y); +} +KFR_FN(mod) +/// Remainder +template > +KFR_INTRINSIC Tout rem(const T1& x, const T2& y) +{ + return static_cast(x) % static_cast(y); +} +KFR_FN(rem) + +/// Negation +template +inline T1 neg(const T1& x) +{ + return -x; +} +KFR_FN(neg) + +/// @brief Fused Multiply-Add +template +KFR_INTRINSIC constexpr std::common_type_t fmadd(const T1& x, const T2& y, const T3& z) +{ + return x * y + z; +} +/// @brief Fused Multiply-Sub +template +KFR_INTRINSIC constexpr std::common_type_t fmsub(const T1& x, const T2& y, const T3& z) +{ + return x * y - z; +} +KFR_FN(fmadd) +KFR_FN(fmsub) + +/// @brief Linear blend of `x` and `y` (`c` must be in the range 0...+1) +/// Returns `x + ( y - x ) * c` +template )> +KFR_INTRINSIC constexpr std::common_type_t mix(const T1& c, const T2& x, const T3& y) +{ + return fmadd(c, y - x, x); +} + +/// @brief Linear blend of `x` and `y` (`c` must be in the range -1...+1) +template )> +KFR_INTRINSIC constexpr std::common_type_t mixs(const T1& c, const T2& x, const T3& y) +{ + return mix(fmadd(c, 0.5, 0.5), x, y); +} +KFR_FN(mix) +KFR_FN(mixs) + +namespace intrinsics +{ + +template +constexpr KFR_INTRINSIC std::common_type_t horner(const T1&, const T2& c0) +{ + return c0; +} + +template +constexpr KFR_INTRINSIC std::common_type_t horner(const T1& x, const T2& c0, const T3& c1, + const Ts&... values) +{ + return fmadd(horner(x, c1, values...), x, c0); +} + +template +constexpr KFR_INTRINSIC std::common_type_t horner_even(const T1&, const T2& c0) +{ + return c0; +} + +template +constexpr KFR_INTRINSIC std::common_type_t horner_even(const T1& x, const T2& c0, + const T3& c2, const Ts&... values) +{ + const T1 x2 = x * x; + return fmadd(horner(x2, c2, values...), x2, c0); +} + +template +constexpr KFR_INTRINSIC std::common_type_t horner_odd(const T1& x, const T2& c1) +{ + return c1 * x; +} + +template +constexpr KFR_INTRINSIC std::common_type_t horner_odd(const T1& x, const T2& c1, + const T3& c3, const Ts&... values) +{ + const T1 x2 = x * x; + return fmadd(horner(x2, c3, values...), x2, c1) * x; +} +} // namespace intrinsics + +/// @brief Calculate polynomial using Horner's method +/// +/// ``horner(x, 1, 2, 3)`` is equivalent to \(3x^2 + 2x + 1\) +template )> +constexpr KFR_INTRINSIC std::common_type_t horner(const T1& x, const Ts&... c) +{ + return intrinsics::horner(x, c...); +} +KFR_FN(horner) + +/// @brief Calculate polynomial using Horner's method (even powers) +/// +/// ``horner_even(x, 1, 2, 3)`` is equivalent to \(3x^4 + 2x^2 + 1\) +template )> +constexpr KFR_INTRINSIC std::common_type_t horner_even(const T1& x, const Ts&... c) +{ + return intrinsics::horner_even(x, c...); +} +KFR_FN(horner_even) + +/// @brief Calculate polynomial using Horner's method (odd powers) +/// +/// ``horner_odd(x, 1, 2, 3)`` is equivalent to \(3x^5 + 2x^3 + 1x\) +template )> +constexpr KFR_INTRINSIC std::common_type_t horner_odd(const T1& x, const Ts&... c) +{ + return intrinsics::horner_odd(x, c...); +} +KFR_FN(horner_odd) + +/// @brief Calculate Multiplicative Inverse of `x` +/// Returns `1/x` +template +constexpr KFR_INTRINSIC T reciprocal(const T& x) +{ + static_assert(std::is_floating_point_v>, "T must be floating point type"); + return subtype(1) / x; +} +KFR_FN(reciprocal) + +template +KFR_INTRINSIC std::common_type_t mulsign(const T1& x, const T2& y) +{ + return bitwisexor(x, bitwiseand(y, special_constants::highbitmask())); +} +KFR_FN(mulsign) + +template +constexpr KFR_INTRINSIC vec copysign(const vec& x, const vec& y) +{ + return (x & special_constants::highbitmask()) | (y & special_constants::highbitmask()); +} + +/// @brief Swap byte order +template +KFR_INTRINSIC T swapbyteorder(const T& x) +{ + return bitcast_anything(swap)>(bitcast_anything>(x))); +} +KFR_FN(swapbyteorder) + +template = 2)> +KFR_INTRINSIC vec subadd(const vec& a, const vec& b) +{ + return blend<1, 0>(a + b, a - b); +} +template = 2)> +KFR_INTRINSIC vec addsub(const vec& a, const vec& b) +{ + return blend<0, 1>(a + b, a - b); +} +KFR_FN(subadd) +KFR_FN(addsub) + +template +KFR_INTRINSIC vec negeven(const vec& x) +{ + return x ^ broadcast(-T(), T()); +} +template +KFR_INTRINSIC vec negodd(const vec& x) +{ + return x ^ broadcast(T(), -T()); +} + +template +vec, N1> packtranspose(const vec& x, const vec&... rest) +{ + const vec t = transpose(concat(x, rest...)); + return t.v; +} + +KFR_FN(packtranspose) + +#if 0 +template +KFR_I_CE vec, N>::vec(const base& v) CMT_NOEXCEPT +{ + this->v = base::frombits((vec, N>::frombits(v) < itype(0)).asvec()).v; +} +#endif + +} // namespace CMT_ARCH_NAME +} // namespace kfr + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/platform.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/platform.hpp new file mode 100644 index 00000000..cc5da156 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/platform.hpp @@ -0,0 +1,297 @@ +/** @addtogroup types + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "types.hpp" + +namespace kfr +{ + +/// @brief An enumeration representing cpu instruction set +enum class cpu_t : int +{ + generic = 0, +#ifdef CMT_ARCH_X86 + sse2 = 1, + sse3 = 2, + ssse3 = 3, + sse41 = 4, + sse42 = 5, + avx1 = 6, + avx2 = 7, + avx512 = 8, // F, CD, VL, DQ and BW + avx = static_cast(avx1), + lowest = static_cast(sse2), + highest = static_cast(avx512), +#endif +#ifdef CMT_ARCH_ARM + neon = 1, + neon64 = 2, + lowest = static_cast(neon), + highest = static_cast(neon64), +#endif + native = static_cast(CMT_ARCH_NAME), + +#ifdef CMT_ARCH_AVX +#define KFR_HAS_SECONDARY_PLATFORM + secondary = static_cast(sse42), +#else + secondary = static_cast(native), +#endif + + common = generic, // For compatibility + runtime = -1, +}; + +template +using ccpu_t = cval_t; + +template +constexpr ccpu_t ccpu{}; + +namespace internal_generic +{ +constexpr cpu_t older(cpu_t x) { return static_cast(static_cast(x) - 1); } +constexpr cpu_t newer(cpu_t x) { return static_cast(static_cast(x) + 1); } + +#ifdef CMT_ARCH_X86 +constexpr auto cpu_list = cvals_t(); +#else +constexpr auto cpu_list = cvals; +#endif +} // namespace internal_generic + +template +using cpuval_t = cval_t; +template +constexpr auto cpuval = cpuval_t{}; + +constexpr auto cpu_all = + cfilter(internal_generic::cpu_list, internal_generic::cpu_list >= cpuval_t()); + +/// @brief Returns name of the cpu instruction set +CMT_UNUSED static const char* cpu_name(cpu_t set) +{ +#ifdef CMT_ARCH_X86 + static const char* names[] = { "generic", "sse2", "sse3", "ssse3", "sse41", + "sse42", "avx", "avx2", "avx512" }; +#endif +#ifdef CMT_ARCH_ARM + static const char* names[] = { "generic", "neon", "neon64" }; +#endif + if (CMT_LIKELY(set >= cpu_t::lowest && set <= cpu_t::highest)) + return names[static_cast(set)]; + return "-"; +} + +#ifdef CMT_ARCH_X64 +template +constexpr inline const char* bitness_const(const char*, const char* x64) +{ + return x64; +} +template +constexpr inline const T& bitness_const(const T&, const T& x64) +{ + return x64; +} +#else +template +constexpr inline const char* bitness_const(const char* x32, const char*) +{ + return x32; +} +template +constexpr inline const T& bitness_const(const T& x32, const T&) +{ + return x32; +} +#endif + +template +struct platform; + +#ifdef CMT_ARCH_X86 +template <> +struct platform +{ + constexpr static size_t native_cache_alignment = 64; + constexpr static size_t native_cache_alignment_mask = native_cache_alignment - 1; + constexpr static size_t maximum_vector_alignment = 64; + constexpr static size_t maximum_vector_alignment_mask = maximum_vector_alignment - 1; + + constexpr static size_t simd_register_count = 1; + + constexpr static size_t common_float_vector_size = 16; + constexpr static size_t common_int_vector_size = 16; + + constexpr static size_t minimum_float_vector_size = 16; + constexpr static size_t minimum_int_vector_size = 16; + + constexpr static size_t native_float_vector_size = 16; + constexpr static size_t native_int_vector_size = 16; + + constexpr static size_t native_vector_alignment = 16; + constexpr static size_t native_vector_alignment_mask = native_vector_alignment - 1; + + constexpr static bool fast_unaligned = false; + + constexpr static bool mask_registers = false; +}; +template <> +struct platform : platform +{ + constexpr static size_t simd_register_count = bitness_const(8, 16); +}; +template <> +struct platform : platform +{ +}; +template <> +struct platform : platform +{ +}; +template <> +struct platform : platform +{ +}; +template <> +struct platform : platform +{ +}; +template <> +struct platform : platform +{ + constexpr static size_t native_float_vector_size = 32; + + constexpr static size_t native_vector_alignment = 32; + constexpr static size_t native_vector_alignment_mask = native_vector_alignment - 1; + + constexpr static bool fast_unaligned = true; +}; +template <> +struct platform : platform +{ + constexpr static size_t native_int_vector_size = 32; +}; +template <> +struct platform : platform +{ + constexpr static size_t native_float_vector_size = 64; + constexpr static size_t native_int_vector_size = 64; + + constexpr static size_t native_vector_alignment = 64; + constexpr static size_t native_vector_alignment_mask = native_vector_alignment - 1; + + constexpr static size_t simd_register_count = bitness_const(8, 32); + + constexpr static bool mask_registers = true; +}; +#endif +#ifdef CMT_ARCH_ARM +template <> +struct platform +{ + constexpr static size_t native_cache_alignment = 64; + constexpr static size_t native_cache_alignment_mask = native_cache_alignment - 1; + constexpr static size_t maximum_vector_alignment = 16; + constexpr static size_t maximum_vector_alignment_mask = maximum_vector_alignment - 1; + + constexpr static size_t simd_register_count = 1; + + constexpr static size_t common_float_vector_size = 16; + constexpr static size_t common_int_vector_size = 16; + + constexpr static size_t minimum_float_vector_size = 16; + constexpr static size_t minimum_int_vector_size = 16; + + constexpr static size_t native_float_vector_size = 16; + constexpr static size_t native_int_vector_size = 16; + + constexpr static size_t native_vector_alignment = 16; + constexpr static size_t native_vector_alignment_mask = native_vector_alignment - 1; + + constexpr static bool fast_unaligned = false; + + constexpr static bool mask_registers = false; +}; +template <> +struct platform : platform +{ + constexpr static size_t simd_register_count = 32; +}; +template <> +struct platform : platform +{ +}; +#endif + +inline namespace CMT_ARCH_NAME +{ + +/// @brief SIMD vector width for the given cpu instruction set +template +constexpr static size_t vector_width = + (const_max(size_t(1), typeclass == datatype::f ? platform<>::native_float_vector_size / sizeof(T) + : platform<>::native_int_vector_size / sizeof(T))); + +template +constexpr static size_t vector_width_for = + (const_max(size_t(1), typeclass == datatype::f ? platform::native_float_vector_size / sizeof(T) + : platform::native_int_vector_size / sizeof(T))); + +template +constexpr static size_t minimum_vector_width = + (const_max(size_t(1), typeclass == datatype::f ? platform<>::minimum_float_vector_size / sizeof(T) + : platform<>::minimum_int_vector_size / sizeof(T))); + +template +constexpr static size_t vector_capacity = platform<>::simd_register_count * vector_width; + +#ifdef CMT_COMPILER_IS_MSVC +template +constexpr static size_t maximum_vector_size = const_min(static_cast(32), vector_width * 2); +#else +template +constexpr static size_t maximum_vector_size = const_min( + static_cast(32), const_max(size_t(1), platform<>::simd_register_count / 4) * vector_width); +#endif + +template +constexpr static bool is_simd_size(size_t size) +{ + return is_poweroftwo(size) && size >= minimum_vector_width && size <= vector_width; +} + +template > +struct vec; + +template > +using mask = vec, N>; + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/read_write.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/read_write.hpp new file mode 100644 index 00000000..1337e176 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/read_write.hpp @@ -0,0 +1,321 @@ +/** @addtogroup read_write + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/read_write.hpp" +#include + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec read(const T* src) +{ + return vec::from_flatten(intrinsics::read(cbool, csize::deep_width>, + ptr_cast>(src))); +} + +template +KFR_INTRINSIC void write(T* dest, const vec& value) +{ + intrinsics::write(cbool, ptr_cast>(dest), value.flatten()); +} + +namespace internal +{ +template +KFR_INTRINSIC vec read_group_impl(const T* src, size_t stride, csizes_t) +{ + return concat(intrinsics::read(cbool, csize, src + group * stride * indices)...); +} +template +KFR_INTRINSIC void write_group_impl(T* dest, size_t stride, const vec& value, + csizes_t) +{ + swallow{ (write(dest + group * stride * indices, slice(value)), + 0)... }; +} +} // namespace internal + +template +KFR_INTRINSIC vec read_group(const T* src, size_t stride) +{ + return internal::read_group_impl(ptr_cast(src), stride, csizeseq_t()); +} + +template +KFR_INTRINSIC void write_group(T* dest, size_t stride, const vec& value) +{ + return internal::write_group_impl(dest, stride, value, csizeseq_t()); +} + +template +KFR_INTRINSIC vec gather(const T* base, size_t index, Indices... indices) +{ + return make_vector(base[index], base[indices]...); +} + +template +KFR_INTRINSIC vec gather(const T* base) +{ + return make_vector(base[Index], base[Indices]...); +} + +template +KFR_INTRINSIC void scatter(const T* base, const vec& value) +{ + base[Index] = value[InIndex]; + scatter(base, value); +} + +namespace internal +{ +template +KFR_INTRINSIC vec gather(const T* base, const vec& indices, csizes_t) +{ + return make_vector(base[indices[Indices]]...); +} +template +KFR_INTRINSIC vec gather_stride(const T* base, csizes_t) +{ + return make_vector(base[Indices * Stride]...); +} +template +KFR_INTRINSIC vec gather_stride_s(const T* base, size_t stride, csizes_t) +{ + return concat(read(base + Indices * groupsize * stride)...); +} +} // namespace internal + +template +KFR_INTRINSIC vec gather(const T* base, const vec& indices) +{ + return internal::gather(base, indices, csizeseq); +} + +template +KFR_INTRINSIC vec gather_stride(const T* base, size_t stride) +{ + if constexpr (Nout > 2) + { + constexpr size_t Nlow = prev_poweroftwo(Nout - 1); + return concat(internal::gather_stride_s(base, stride, csizeseq), + internal::gather_stride_s(base + Nlow * stride, stride, + csizeseq)); + } + else + return internal::gather_stride_s(base, stride, csizeseq); +} + +template +KFR_INTRINSIC vec gather_stride(const T* base) +{ + return internal::gather_stride(base, csizeseq); +} + +namespace internal +{ +template +KFR_INTRINSIC vec gather_helper(const T* base, const vec& offset, + csizes_t) +{ + return concat(read(base + groupsize * offset[Indices])...); +} +} // namespace internal +template +KFR_INTRINSIC vec gather(const T* base, const vec& offset) +{ + return internal::gather_helper(base, offset, csizeseq); +} + +namespace internal +{ +template +KFR_INTRINSIC void scatter_helper(T* base, const vec& offset, const vec& value, + csizes_t) +{ + swallow{ (write(base + groupsize * offset[Indices], slice(value)), + 0)... }; +} +template +KFR_INTRINSIC void scatter_helper_s(T* base, size_t stride, const vec& value, csizes_t) +{ + swallow{ (write(base + groupsize * Indices * stride, slice(value)), + 0)... }; +} +} // namespace internal + +template +KFR_INTRINSIC void scatter(T* base, const vec& offset, const vec& value) +{ + return internal::scatter_helper(base, offset, value, csizeseq); +} + +template +KFR_INTRINSIC void scatter_stride(T* base, const vec& value, size_t stride) +{ + constexpr size_t Nout = N / groupsize; + if constexpr (Nout > 2) + { + constexpr size_t Nlow = prev_poweroftwo(Nout - 1); + internal::scatter_helper_s(base, stride, slice<0, Nlow>(value), csizeseq); + internal::scatter_helper_s(base + Nlow * stride, stride, slice(value), + csizeseq<(Nout - Nlow)>); + } + else + return internal::scatter_helper_s(base, stride, value, csizeseq); +} + +template +struct stride_pointer : public stride_pointer +{ + template + void write(const vec& val, csize_t = csize_t()) + { + kfr::scatter_stride(this->ptr, val); + } +}; + +template +struct stride_pointer +{ + const T* ptr; + const size_t stride; + + template + vec read(csize_t = csize_t()) + { + return kfr::gather_stride(ptr, stride); + } +}; + +template +KFR_INTRINSIC vec to_vec(const std::array& a) +{ + return read(a.data()); +} + +template +constexpr T partial_masks[] = { special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + special_constants::allones(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T(), + T() }; + +template +KFR_INTRINSIC vec partial_mask(size_t index) +{ + static_assert(N <= arraysize(partial_masks) / 2, + "N must not be greater than half of partial_masks array"); + return read(&partial_masks[0] + arraysize(partial_masks) / 2 - index); +} +template +KFR_INTRINSIC vec partial_mask(size_t index, vec_shape) +{ + return partial_mask(index); +} + +// read/write +template +template +KFR_MEM_INTRINSIC constexpr vec::vec(const value_type* src, cbool_t) CMT_NOEXCEPT + : vec(vec::from_flatten(intrinsics::read(cbool, + csize::deep_width>, + ptr_cast>(src)))) +{ +} + +template +template +KFR_MEM_INTRINSIC const vec& vec::write(value_type* dest, cbool_t) const CMT_NOEXCEPT +{ + intrinsics::write(cbool, ptr_cast>(dest), flatten()); + return *this; +} + +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/round.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/round.hpp new file mode 100644 index 00000000..5a8fb3e5 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/round.hpp @@ -0,0 +1,108 @@ +/** @addtogroup round + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/round.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Returns the largest integer value not greater than x +template )> +KFR_INTRINSIC T1 floor(const T1& x) +{ + return intrinsics::floor(x); +} + +template )> +KFR_INTRINSIC T1 ceil(const T1& x) +{ + return intrinsics::ceil(x); +} + +template )> +KFR_INTRINSIC T1 round(const T1& x) +{ + return intrinsics::round(x); +} + +template )> +KFR_INTRINSIC T1 trunc(const T1& x) +{ + return intrinsics::trunc(x); +} + +template )> +KFR_INTRINSIC T1 fract(const T1& x) +{ + return intrinsics::fract(x); +} + +template )> +KFR_INTRINSIC itype ifloor(const T1& x) +{ + return intrinsics::ifloor(x); +} + +template )> +KFR_INTRINSIC itype iceil(const T1& x) +{ + return intrinsics::iceil(x); +} + +template )> +KFR_INTRINSIC itype iround(const T1& x) +{ + return intrinsics::iround(x); +} + +template )> +KFR_INTRINSIC itype itrunc(const T1& x) +{ + return intrinsics::itrunc(x); +} + +template )> +KFR_INTRINSIC T fmod(const T& x, const T& y) +{ + return x - trunc(x / y) * y; +} +KFR_FN(fmod) + +template )> +constexpr KFR_INTRINSIC vec rem(const vec& x, const vec& y) +{ + return x % y; +} +template )> +KFR_INTRINSIC vec rem(const vec& x, const vec& y) +{ + return fmod(x, y); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/saturation.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/saturation.hpp new file mode 100644 index 00000000..3bb9da2f --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/saturation.hpp @@ -0,0 +1,51 @@ +/** @addtogroup saturation + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/saturation.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/// @brief Adds two arguments using saturation +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout satadd(const T1& x, const T2& y) +{ + return intrinsics::satadd(x, y); +} + +/// @brief Subtracts two arguments using saturation +template ), + typename Tout = std::common_type_t> +KFR_INTRINSIC Tout satsub(const T1& x, const T2& y) +{ + return intrinsics::satsub(x, y); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/select.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/select.hpp new file mode 100644 index 00000000..0071e845 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/select.hpp @@ -0,0 +1,49 @@ +/** @addtogroup basic_math + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "impl/select.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Returns x if m is true, otherwise return y. Order of the arguments is same as in ternary operator. + * @code + * return m ? x : y + * @endcode + */ +template ), + typename Tout = subtype>> +KFR_INTRINSIC vec select(const mask& m, const T2& x, const T3& y) +{ + return intrinsics::select(bitcast(cast>(bitcast>(m.asvec()))).asmask(), + broadcastto(x), broadcastto(y)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/shuffle.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/shuffle.hpp new file mode 100644 index 00000000..a83f9f86 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/shuffle.hpp @@ -0,0 +1,660 @@ +/** @addtogroup shuffle + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once +#include "constants.hpp" +#include "mask.hpp" +#include "types.hpp" +#include "vec.hpp" + +#include +#include + +CMT_PRAGMA_MSVC(warning(push)) +CMT_PRAGMA_MSVC(warning(disable : 5051)) +CMT_PRAGMA_MSVC(warning(disable : 4244)) + +namespace kfr +{ + +inline namespace CMT_ARCH_NAME +{ + +template +KFR_INTRINSIC vec low(const vec& x) +{ + return x.shuffle(csizeseq); +} + +template +KFR_INTRINSIC vec_shape low(vec_shape) +{ + return {}; +} + +template +KFR_INTRINSIC vec lowhalf(const vec& x) +{ + return x.shuffle(csizeseq); +} + +template +KFR_INTRINSIC vec_shape lowhalf(vec_shape) +{ + return {}; +} + +template +KFR_INTRINSIC vec high(const vec& x) +{ + return x.shuffle(csizeseq); +} + +template +KFR_INTRINSIC vec_shape high(vec_shape) +{ + return {}; +} + +template +KFR_INTRINSIC vec highhalf(const vec& x) +{ + return x.shuffle(csizeseq); +} + +template +KFR_INTRINSIC vec_shape highhalf(vec_shape) +{ + return {}; +} + +template +KFR_INTRINSIC vec()> concat(const vec&... vs) CMT_NOEXCEPT +{ + return vec()>( + intrinsics::simd_concat::scalar_type, vec::scalar_size()...>(vs.v...)); +} + +template +KFR_INTRINSIC vec concat2(const vec& x, const vec& y) CMT_NOEXCEPT +{ + return vec()>( + intrinsics::simd_concat::scalar_type, vec::scalar_size(), + vec::scalar_size()>(x.v, y.v)); +} + +template +KFR_INTRINSIC vec concat4(const vec& a, const vec& b, const vec& c, + const vec& d) CMT_NOEXCEPT +{ + return intrinsics::simd_concat::scalar_type, vec::scalar_size(), + vec::scalar_size()>( + intrinsics::simd_concat::scalar_type, vec::scalar_size(), + vec::scalar_size()>(a.v, b.v), + intrinsics::simd_concat::scalar_type, vec::scalar_size(), + vec::scalar_size()>(c.v, d.v)); +} + +template +KFR_INTRINSIC vec repeat(const vec& x) +{ + return x.shuffle(csizeseq % csize); +} + +template +KFR_INTRINSIC vec resize(const vec& x) +{ + return x.shuffle(csizeseq % csize); +} +template +constexpr KFR_INTRINSIC const vec& resize(const vec& x) +{ + return x; +} + +namespace intrinsics +{ + +template +KFR_INTRINSIC vec broadcast_helper(csizes_t, const Ts&... values) +{ + const std::tuple tup(values...); + return vec(std::get(tup)...); +} +} // namespace intrinsics + +template ::type> +KFR_INTRINSIC vec broadcast(const Ts&... values) +{ + return intrinsics::broadcast_helper(csizeseq, values...); +} +KFR_FN(broadcast) + +template +KFR_INTRINSIC vec padhigh(const vec& x) +{ + return x.shuffle(csizeseq); +} +template +KFR_INTRINSIC vec padhigh(const vec& x, identity newvalue) +{ + if constexpr (Ncount == 0) + return x; + else + return concat(x, broadcast(newvalue)); +} +KFR_FN(padhigh) + +template +KFR_INTRINSIC vec padlow(const vec& x) +{ + return x.shuffle(csizeseq); +} +template +KFR_INTRINSIC vec padlow(const vec& x, identity newvalue) +{ + if constexpr (Ncount == 0) + return x; + else + return concat(broadcast(newvalue), x); +} +KFR_FN(padlow) + +template +KFR_INTRINSIC vec extend(const vec& x) +{ + return vec(x.front()); +} +template 1)> +KFR_INTRINSIC vec extend(const vec& x) +{ + return x.shuffle(csizeseq); +} +template 1)> +constexpr KFR_INTRINSIC const vec& extend(const vec& x) +{ + return x; +} +KFR_FN(extend) + +template +KFR_INTRINSIC vec slice(const vec& x) +{ + return x.shuffle(csizeseq); +} +template +KFR_INTRINSIC vec slice(const vec& x, const vec& y) +{ + return x.shuffle(y, csizeseq); +} +KFR_FN(slice) + +template +KFR_INTRINSIC vec replace(const vec& x, const vec& y) +{ + return x.shuffle(y, csizeseq + (csizeseq >= csize && csizeseq < csize)*N); +} +KFR_FN(replace) + +template +KFR_INTRINSIC void split(const vec&) +{ +} +template +KFR_INTRINSIC void split(const vec& x, vec& out, Args&&... args) +{ + out = x.shuffle(csizeseq); + split(x, std::forward(args)...); +} +template +KFR_INTRINSIC void split(const vec& x, vec& low, vec& high) +{ + low = x.shuffle(csizeseq); + high = x.shuffle(csizeseq); +} +template +KFR_INTRINSIC void split(const vec& x, vec& w0, vec& w1, vec& w2, + vec& w3) +{ + w0 = x.shuffle(csizeseq); + w1 = x.shuffle(csizeseq); + w2 = x.shuffle(csizeseq); + w3 = x.shuffle(csizeseq); +} +KFR_FN(split) + +template +KFR_INTRINSIC vec part(const vec& x) +{ + static_assert(N % total == 0, "N % total == 0"); + return x.shuffle(csizeseq); +} +KFR_FN(part) + +template +KFR_INTRINSIC vec concat_and_slice(const vec& x, const vec& y) +{ + return x.shuffle(y, csizeseq); +} + +template N2)> +KFR_INTRINSIC vec concat_and_slice(const vec& x, const vec& y) +{ + return x.shuffle(y.shuffle(csizeseq), csizeseq).shuffle(csizeseq); +} + +template +KFR_INTRINSIC vec concat_and_slice(const vec& x, const vec& y) +{ + return x.shuffle(csizeseq) + .shuffle(y, csizeseq) + .shuffle(csizeseq); +} + +KFR_FN(concat_and_slice) + +template N)> +KFR_INTRINSIC vec widen(const vec& x, identity newvalue = T()) +{ + static_assert(Nout > N, "Nout > N"); + return concat(x, broadcast(newvalue)); +} +template +constexpr KFR_INTRINSIC const vec& widen(const vec& x, TS) +{ + return x; +} +KFR_FN(widen) + +template +KFR_INTRINSIC vec narrow(const vec& x) +{ + static_assert(Nout <= N, "Nout <= N"); + return slice<0, Nout>(x); +} +KFR_FN(narrow) + +template = 2 && (N & 1) == 0)> +KFR_INTRINSIC vec even(const vec& x) +{ + return x.shuffle(scale(csizeseq)); +} +KFR_FN(even) + +template = 2 && (N & 1) == 0)> +KFR_INTRINSIC vec odd(const vec& x) +{ + return x.shuffle(scale(csizeseq)); +} +KFR_FN(odd) + +template +KFR_INTRINSIC vec dupeven(const vec& x) +{ + static_assert(N % 2 == 0, "N must be even"); + return x.shuffle(csizeseq & ~csize<1>); +} +KFR_FN(dupeven) + +template +KFR_INTRINSIC vec dupodd(const vec& x) +{ + static_assert(N % 2 == 0, "N must be even"); + return x.shuffle(csizeseq | csize<1>); +} +KFR_FN(dupodd) + +template +KFR_INTRINSIC vec duphalves(const vec& x) +{ + return x.shuffle(csizeseq % csize); +} +KFR_FN(duphalves) + +template +KFR_INTRINSIC vec shuffle(const vec& x, const vec& y, + elements_t i = elements_t()) +{ + return x.shuffle(y, i[csizeseq_t() % csize_t()] + + csizeseq_t() / csize_t() * csize_t()); +} +KFR_FN(shuffle) + +template +KFR_INTRINSIC vec shufflegroups(const vec& x, const vec& y, + elements_t i = elements_t()) +{ + return x.shuffle(y, scale(i[csizeseq_t() % csize_t()] + + csizeseq_t() / csize_t() * csize_t())); +} +KFR_FN(shufflegroups) + +template +KFR_INTRINSIC vec permute(const vec& x, elements_t i = elements_t()) +{ + return x.shuffle(i[csizeseq_t() % csize_t()] + + csizeseq_t() / csize_t() * csize_t()); +} +KFR_FN(permute) + +template +KFR_INTRINSIC vec permutegroups(const vec& x, elements_t i = elements_t()) +{ + return x.shuffle(scale(i[csizeseq_t() % csize_t()] + + csizeseq_t() / csize_t() * csize_t())); +} +KFR_FN(permutegroups) + +namespace internal +{ + +template +constexpr KFR_INTRINSIC vec generate_vector(csizes_t) +{ + return make_vector(static_cast(Fn()(Indices))...); +} +} // namespace internal + +template +constexpr KFR_INTRINSIC vec generate_vector() +{ + return internal::generate_vector(cvalseq_t()); +} +KFR_FN(generate_vector) + +namespace internal +{ +template +KFR_INTRINSIC mask evenmask() +{ + return mask(broadcast(maskbits(true), maskbits(false))); +} +template +KFR_INTRINSIC mask oddmask() +{ + return mask(broadcast(maskbits(false), maskbits(true))); +} +} // namespace internal + +template +KFR_INTRINSIC vec dup(const vec& x) +{ + return x.shuffle(csizeseq_t() / csize_t<2>()); +} +KFR_FN(dup) + +template +KFR_INTRINSIC vec duplow(const vec& x) +{ + return x.shuffle(csizeseq_t() % csize_t()); +} +KFR_FN(duplow) + +template +KFR_INTRINSIC vec duphigh(const vec& x) +{ + return x.shuffle(csizeseq_t() % csize_t() + csize_t()); +} +KFR_FN(duphigh) + +template +KFR_INTRINSIC vec blend(const vec& x, const vec& y, + elements_t i = elements_t()) +{ + return x.shuffle(y, i[csizeseq_t() % csize_t()] * csize_t() + csizeseq_t()); +} +KFR_FN(blend) + +template +KFR_INTRINSIC vec swap(const vec& x) +{ + return x.shuffle(csizeseq_t() ^ csize_t()); +} +CMT_FN_TPL((size_t elements), (elements), swap) + +template +KFR_INTRINSIC vec rotatetwo(const vec& lo, const vec& hi) +{ + return shift == 0 ? lo : (shift == N ? hi : hi.shuffle(lo, csizeseq_t())); +} + +template +KFR_INTRINSIC vec rotateright(const vec& x, csize_t = csize_t()) +{ + static_assert(amount >= 0 && amount < N, "amount >= 0 && amount < N"); + return x.shuffle(csizeseq_t() % csize_t()); +} +KFR_FN(rotateright) + +template +KFR_INTRINSIC vec rotateleft(const vec& x, csize_t = csize_t()) +{ + static_assert(amount >= 0 && amount < N, "amount >= 0 && amount < N"); + return x.shuffle(csizeseq_t() % csize_t()); +} +KFR_FN(rotateleft) + +template +KFR_INTRINSIC vec insertright(T x, const vec& y) +{ + return concat_and_slice<1, N>(y, vec(x)); +} +KFR_FN(insertright) + +template +KFR_INTRINSIC vec insertleft(T x, const vec& y) +{ + return concat_and_slice<0, N>(vec(x), y); +} +KFR_FN(insertleft) + +template 3)> +KFR_INTRINSIC vec transpose(const vec& x) +{ + return x.shuffle(scale(csizeseq_t() % csize_t() * csize_t() + + csizeseq_t() / csize_t())); +} +template +KFR_INTRINSIC vec transpose(const vec& x) +{ + return x; +} +template +KFR_INTRINSIC vec, N> transpose(const vec, N>& x) +{ + return vec, N>::from_flatten(transpose(x.flatten())); +} +KFR_FN(transpose) + +template 3)> +KFR_INTRINSIC vec transposeinverse(const vec& x) +{ + return x.shuffle(scale(csizeseq_t() % csize_t() * csize_t() + + csizeseq_t() / csize_t())); +} +template +KFR_INTRINSIC vec transposeinverse(const vec& x) +{ + return x; +} +KFR_FN(transposeinverse) + +template +KFR_INTRINSIC vec ctranspose(const vec& x) +{ + return transpose(x); +} +KFR_FN(ctranspose) + +template +KFR_INTRINSIC vec ctransposeinverse(const vec& x) +{ + return transposeinverse(x); +} +KFR_FN(ctransposeinverse) + +template +KFR_INTRINSIC vec interleave(const vec& x, const vec& y) +{ + return x.shuffle(y, scale(csizeseq_t() % csize_t() * csize_t() + + csizeseq_t() / csize_t())); +} +KFR_FN(interleave) + +template (), + size_t side2 = 1 + sizeof...(Ns), size_t side1 = size / side2> +KFR_INTRINSIC vec, side1> zip(const vec& x, const vec&... y) +{ + static_assert(is_poweroftwo(1 + sizeof...(Ns)), "number of vectors must be power of two"); + return vec, side1>::from_flatten(concat(x, y...).shuffle(scale<1>( + csizeseq_t() % csize_t() * csize_t() + csizeseq_t() / csize_t()))); +} +KFR_FN(zip) + +template +KFR_INTRINSIC vec column(const vec, N2>& x) +{ + static_assert(index < N1, "column index must be less than inner vector length"); + return x.flatten().shuffle(csizeseq_t() * csize_t() + csize_t()); +} + +template +KFR_INTRINSIC vec interleavehalves(const vec& x) +{ + return x.shuffle(scale(csizeseq_t() % csize_t() * csize_t() + + csizeseq_t() / csize_t())); +} +KFR_FN(interleavehalves) + +template +KFR_INTRINSIC vec splitpairs(const vec& x) +{ + return x.shuffle(scale(csizeseq_t() % csize_t() * csize_t() + + csizeseq_t() / csize_t())); +} +KFR_FN(splitpairs) + +template )> +KFR_INTRINSIC vec reverse(const vec& x) +{ + constexpr size_t size = N / group; + return x.shuffle(scale(csizeseq_t())); +} +template +KFR_INTRINSIC vec, N2> reverse(const vec, N2>& x) +{ + return swap(x.flatten()).v; +} +KFR_FN(reverse) + +template +KFR_INTRINSIC vec combine(const vec& x, const vec& y) +{ + static_assert(N2 <= N1, "N2 <= N1"); + return x.shuffle(extend(y), (csizeseq_t() < csize_t()) * csize_t() + csizeseq_t()); +} +KFR_FN(combine) + +namespace internal +{ +template +struct generate_index +{ + KFR_INTRINSIC constexpr size_t operator()(size_t index) const { return start + index * stride; } +}; +template +struct generate_onoff +{ + KFR_INTRINSIC constexpr size_t operator()(size_t index) const + { + return index >= start && index < start + size ? on : off; + } +}; +} // namespace internal + +template +constexpr KFR_INTRINSIC vec enumerate() +{ + return generate_vector>(); +} +template +constexpr KFR_INTRINSIC vec enumerate(vec_shape) +{ + return generate_vector>(); +} +template +KFR_INTRINSIC vec enumerate(vec_shape sh, identity step) +{ + if constexpr (N == 1) + { + return czeros; + } + else if constexpr (!is_poweroftwo(N)) + { + return slice<0, N>(enumerate(vec_shape{}, step)); + } + else + { + vec vv = step; + vec zz(czeros); + + vec acc = blend(zz, vv, csizeseq % csize<2>); + cfor(csize<0>, csize, + [&](auto idx) CMT_INLINE_LAMBDA + { + vv = vv + vv; + acc += blend(zz, vv, csizeseq / (csize<2 << (idx)>) % csize<2>); + }); + return acc; + } +} + +KFR_FN(enumerate) + +template +constexpr KFR_INTRINSIC vec onoff(cint_t = cint_t(), cint_t = cint_t()) +{ + return generate_vector>(); +} +template +constexpr KFR_INTRINSIC vec onoff(vec_shape, cint_t = cint_t(), + cint_t = cint_t()) +{ + return generate_vector>(); +} +KFR_FN(onoff) + +} // namespace CMT_ARCH_NAME +} // namespace kfr +#define KFR_SHUFFLE_SPECIALIZATIONS 1 +#include "impl/specializations.hpp" + +CMT_PRAGMA_MSVC(warning(pop)) diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/sort.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/sort.hpp new file mode 100644 index 00000000..479de37a --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/sort.hpp @@ -0,0 +1,103 @@ +/** @addtogroup sort + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "min_max.hpp" +#include "shuffle.hpp" +#include "vec.hpp" + +namespace kfr +{ +inline namespace CMT_ARCH_NAME +{ + +/** + * @brief Sort the elements in the vector in ascending order + * @param x input vector + * @return sorted vector + * @code + * CHECK(sort(make_vector(1000, 1, 2, -10)) == make_vector(-10, 1, 2, 1000)); + * @endcode + */ +template +KFR_INTRINSIC vec sort(const vec& x) +{ + constexpr size_t Nhalf = N / 2; + vec e = low(x); + vec o = high(x); + constexpr auto blend0 = cconcat(csizes<1>, csizeseq); + for (size_t i = 0; i < Nhalf; i++) + { + vec t; + t = min(e, o); + o = max(e, o); + o = rotateright<1>(o); + e = t; + t = max(e, o); + o = min(e, o); + e = t; + t = blend(e, o, blend0); + o = blend(o, e, blend0); + o = rotateleft<1>(o); + e = t; + } + return interleavehalves(concat(e, o)); +} + +/** + * @brief Sort the elements in the vector in descending order + * @param x input vector + * @return sorted vector + * @code + * CHECK(sort(make_vector(1000, 1, 2, -10)) == make_vector(1000, 2, 1, -10)); + * @endcode + */ +template +KFR_INTRINSIC vec sortdesc(const vec& x) +{ + constexpr size_t Nhalf = N / 2; + vec e = low(x); + vec o = high(x); + constexpr auto blend0 = cconcat(csizes<1>, csizeseq); + for (size_t i = 0; i < Nhalf; i++) + { + vec t; + t = max(e, o); + o = min(e, o); + o = rotateright<1>(o); + e = t; + t = min(e, o); + o = max(e, o); + e = t; + t = blend(e, o, blend0); + o = blend(o, e, blend0); + o = rotateleft<1>(o); + e = t; + } + return interleavehalves(concat(e, o)); +} +} // namespace CMT_ARCH_NAME +} // namespace kfr diff --git a/packages/react-native-audio-api/android/src/main/include/kfr/simd/types.hpp b/packages/react-native-audio-api/android/src/main/include/kfr/simd/types.hpp new file mode 100644 index 00000000..1c08fea9 --- /dev/null +++ b/packages/react-native-audio-api/android/src/main/include/kfr/simd/types.hpp @@ -0,0 +1,418 @@ +/** @addtogroup types + * @{ + */ +/* + Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com) + This file is part of KFR + + KFR is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + KFR is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KFR. + + If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + Buying a commercial license is mandatory as soon as you develop commercial activities without + disclosing the source code of your own applications. + See https://www.kfrlib.com for details. + */ +#pragma once + +#include "../kfr.h" + +#include "impl/intrinsics.h" +#include "impl/specialconstants.hpp" + +#include + +#include +#include +#include + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wignored-qualifiers") + +#ifdef KFR_TESTING +#include "../cometa/function.hpp" +#include "../testo/testo.hpp" +#endif + +#include "../cometa.hpp" +#include "../cometa/numeric.hpp" + +namespace kfr +{ + +// Include all from CoMeta library +using namespace cometa; + +using cometa::identity; + +using cometa::fbase; +using cometa::fmax; + +template +using decay_common = std::decay_t>; + +template typename Tpl, typename = void> +struct construct_common_type +{ +}; +template typename Tpl> +struct construct_common_type> +{ + using type = Tpl; +}; + +constexpr ctypes_t signed_types{}; +constexpr ctypes_t unsigned_types{}; +constexpr ctypes_t integer_types{}; +constexpr ctypes_t + float_types{}; +constexpr ctypes_t + numeric_types{}; + +constexpr csizes_t<1, 2, 3, 4, 8, 16, 32, 64> test_vector_sizes{}; + +#ifdef CMT_ARCH_AVX512 +constexpr size_t max_test_size = 128; +#elif defined CMT_ARCH_AVX +constexpr size_t max_test_size = 64; +#else +constexpr size_t max_test_size = 32; +#endif + +template