From 026a5aceee83aa5ee960bb977b60acd82c11205e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 1 Apr 2020 18:42:41 +0200 Subject: [PATCH 01/16] SIMD-accelerated strings effect --- benchmarks/CMakeLists.txt | 4 +- cmake/SfizzConfig.cmake | 17 +- cmake/SfizzSIMDSourceFiles.cmake | 25 ++- src/CMakeLists.txt | 9 +- src/sfizz/Buffer.h | 2 +- src/sfizz/SIMDConfig.h | 27 +++ src/sfizz/effects/Strings.cpp | 84 ++++----- src/sfizz/effects/Strings.h | 6 +- src/sfizz/effects/StringsPrivate.h | 174 ------------------- src/sfizz/effects/dsp/resonant_string.dsp | 8 + src/sfizz/effects/impl/ResonantArray.cpp | 70 ++++++++ src/sfizz/effects/impl/ResonantArray.h | 57 ++++++ src/sfizz/effects/impl/ResonantArrayAVX.cpp | 104 +++++++++++ src/sfizz/effects/impl/ResonantArrayAVX.h | 42 +++++ src/sfizz/effects/impl/ResonantArraySSE.cpp | 107 ++++++++++++ src/sfizz/effects/impl/ResonantArraySSE.h | 42 +++++ src/sfizz/effects/impl/ResonantString.cpp | 103 +++++++++++ src/sfizz/effects/impl/ResonantString.h | 48 +++++ src/sfizz/effects/impl/ResonantStringAVX.cpp | 125 +++++++++++++ src/sfizz/effects/impl/ResonantStringAVX.h | 53 ++++++ src/sfizz/effects/impl/ResonantStringSSE.cpp | 125 +++++++++++++ src/sfizz/effects/impl/ResonantStringSSE.h | 53 ++++++ 22 files changed, 1045 insertions(+), 240 deletions(-) delete mode 100644 src/sfizz/effects/StringsPrivate.h create mode 100644 src/sfizz/effects/dsp/resonant_string.dsp create mode 100644 src/sfizz/effects/impl/ResonantArray.cpp create mode 100644 src/sfizz/effects/impl/ResonantArray.h create mode 100644 src/sfizz/effects/impl/ResonantArrayAVX.cpp create mode 100644 src/sfizz/effects/impl/ResonantArrayAVX.h create mode 100644 src/sfizz/effects/impl/ResonantArraySSE.cpp create mode 100644 src/sfizz/effects/impl/ResonantArraySSE.h create mode 100644 src/sfizz/effects/impl/ResonantString.cpp create mode 100644 src/sfizz/effects/impl/ResonantString.h create mode 100644 src/sfizz/effects/impl/ResonantStringAVX.cpp create mode 100644 src/sfizz/effects/impl/ResonantStringAVX.h create mode 100644 src/sfizz/effects/impl/ResonantStringSSE.cpp create mode 100644 src/sfizz/effects/impl/ResonantStringSSE.h diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 2a217244..3da1d309 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -2,8 +2,8 @@ project(sfizz) # Check SIMD include (SfizzSIMDSourceFiles) -set(BENCHMARK_SIMD_SOURCES ${SFIZZ_SIMD_SOURCES}) -list(TRANSFORM BENCHMARK_SIMD_SOURCES PREPEND "../src/") +set(BENCHMARK_SIMD_SOURCES) +sfizz_add_simd_sources(BENCHMARK_SIMD_SOURCES "../src") find_package(benchmark CONFIG REQUIRED) # Check libsamplerate diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 68c02078..76aea885 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -15,22 +15,29 @@ if (WIN32) add_compile_definitions(_WIN32_WINNT=0x601) endif() +# The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... +# see https://gitlab.kitware.com/cmake/cmake/issues/15170 + +if(MSVC) + set(SFIZZ_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") +else() + set(SFIZZ_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") +endif() + # Add required flags for the builds if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_compile_options(-Wall) add_compile_options(-Wextra) add_compile_options(-ffast-math) add_compile_options(-fno-omit-frame-pointer) # For debugging purposes + if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^i.86$") + add_compile_options(-msse2) + endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CMAKE_CXX_STANDARD 17) add_compile_options(/Zc:__cplusplus) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() -if (CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - add_compile_options(-msse2) - endif() -endif() add_library(sfizz-sndfile INTERFACE) diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index e518dadd..ef0e1d1b 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -1,6 +1,21 @@ -set (SFIZZ_SIMD_SOURCES - sfizz/SIMDSSE.cpp - sfizz/SIMDNEON.cpp - sfizz/SIMDDummy.cpp) +macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) + # It needs a macro, otherwise the source properties cannot take effect. -list (APPEND SFIZZ_SOURCES ${SFIZZ_SIMD_SOURCES}) + list (APPEND ${SOURCES_VAR} + ${PREFIX}/sfizz/SIMDSSE.cpp + ${PREFIX}/sfizz/SIMDNEON.cpp + ${PREFIX}/sfizz/SIMDDummy.cpp) + + # For CPU-dispatched X86 sources + # Always build them for all X86 targets. + if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64|i.86|x86|X86)$") + # on GCC, it requires to set ISA support flags on individual files + # to be able to use the intrinsics + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set_source_files_properties( + ${PREFIX}/sfizz/effects/impl/ResonantStringAVX.cpp + ${PREFIX}/sfizz/effects/impl/ResonantArrayAVX.cpp + PROPERTIES COMPILE_FLAGS "-mavx") + endif() + endif() +endmacro() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d24083a9..1655147b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,8 +29,15 @@ set (SFIZZ_SOURCES sfizz/effects/Rectify.cpp sfizz/effects/Gain.cpp sfizz/effects/Width.cpp -) + sfizz/effects/impl/ResonantString.cpp + sfizz/effects/impl/ResonantStringSSE.cpp + sfizz/effects/impl/ResonantStringAVX.cpp + sfizz/effects/impl/ResonantArray.cpp + sfizz/effects/impl/ResonantArraySSE.cpp + sfizz/effects/impl/ResonantArrayAVX.cpp) + include (SfizzSIMDSourceFiles) +sfizz_add_simd_sources (SFIZZ_SOURCES ".") # Parser core library add_library (sfizz_parser STATIC) diff --git a/src/sfizz/Buffer.h b/src/sfizz/Buffer.h index b7b0ce8d..35779eab 100644 --- a/src/sfizz/Buffer.h +++ b/src/sfizz/Buffer.h @@ -282,7 +282,7 @@ private: static constexpr int TypeAlignment { Alignment / sizeof(value_type) }; static constexpr int TypeAlignmentMask { TypeAlignment - 1 }; static_assert(std::is_arithmetic::value, "Type should be arithmetic"); - static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16, "Bad alignment value"); + static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16 || Alignment == 32, "Bad alignment value"); static_assert(TypeAlignment * sizeof(value_type) == Alignment, "The alignment does not appear to be divided by the size of the Type"); void* align(std::size_t alignment, std::size_t size, void *&ptr, std::size_t &space ) { diff --git a/src/sfizz/SIMDConfig.h b/src/sfizz/SIMDConfig.h index 8b7f427f..c4f77d48 100644 --- a/src/sfizz/SIMDConfig.h +++ b/src/sfizz/SIMDConfig.h @@ -67,3 +67,30 @@ # define SFIZZ_HAVE_NEON 0 # endif #endif + +/** + Detect one of the following the processor families. + + - SFIZZ_CPU_FAMILY_X86_64 + - SFIZZ_CPU_FAMILY_I386 + - SFIZZ_CPU_FAMILY_AARCH64 + - SFIZZ_CPU_FAMILY_ARM + */ + +#if defined(_MSC_VER) && defined(_M_AMD64) +# define SFIZZ_CPU_FAMILY_X86_64 1 +#elif defined(_MSC_VER) && defined(_M_IX86) +# define SFIZZ_CPU_FAMILY_I386 1 +#elif defined(_MSC_VER) && defined(_M_ARM64) +# define SFIZZ_CPU_FAMILY_AARCH64 1 +#elif defined(_MSC_VER) && defined(_M_ARM) +# define SFIZZ_CPU_FAMILY_ARM 1 +#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) +# define SFIZZ_CPU_FAMILY_X86_64 1 +#elif defined(__i386__) || defined(__i386) +# define SFIZZ_CPU_FAMILY_I386 1 +#elif defined(__aarch64__) +# define SFIZZ_CPU_FAMILY_AARCH64 1 +#elif defined(__arm__) || defined(__arm) +# define SFIZZ_CPU_FAMILY_ARM 1 +#endif diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 6073e753..d739c593 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -16,7 +16,9 @@ Extensions */ #include "Strings.h" -#include "StringsPrivate.h" +#include "impl/ResonantArray.h" +#include "impl/ResonantArraySSE.h" +#include "impl/ResonantArrayAVX.h" #include "Opcode.h" #include "MathHelpers.h" #include "SIMDHelpers.h" @@ -26,13 +28,8 @@ Extensions namespace sfz { namespace fx { - struct Strings::ResonantString { - Bw2BPF bpf; - WgResonator res; - }; - Strings::Strings() - : _strings(new ResonantString[MaximumNumStrings]) + : _stringsArray(new ResonantArrayScalar) { } @@ -42,42 +39,48 @@ namespace fx { void Strings::setSampleRate(double sampleRate) { - for (unsigned i = 0, n = _numStrings; i < n; ++i) { - ResonantString& rs = _strings[i]; - rs.bpf.init(sampleRate); - rs.res.init(sampleRate); + const unsigned numStrings = _numStrings; + AudioBuffer parameterBuffers { 4, numStrings }; + + auto pitches = parameterBuffers.getSpan(0); + auto bandwidths = parameterBuffers.getSpan(1); + auto feedbacks = parameterBuffers.getSpan(2); + auto gains = parameterBuffers.getSpan(3); + + for (unsigned i = 0; i < numStrings; ++i) { int midiNote = i + 24; - double midiFrequency = 440.0 * std::exp2((midiNote - 69) * (1.0 / 12.0)); - - // 1 Hz works decently as compromise of selectivity/speed - double bpfBandwidth = 1.0; - rs.bpf.setCutoff( - midiFrequency - 0.5 * bpfBandwidth, - midiFrequency + 0.5 * bpfBandwidth); - - rs.res.setFrequency(midiFrequency); - - // TODO(jpc) find how to adjust the string feedbacks - // for now set a fixed release time for all strings - double releaseTime = 50e-3; - double releaseFeedback = std::exp(-6.91 / (releaseTime * sampleRate)); - rs.res.setFeedback(releaseFeedback); + pitches[i] = 440.0 * std::exp2((midiNote - 69) * (1.0 / 12.0)); } + + // 1 Hz works decently as compromise of selectivity/speed + sfz::fill(bandwidths, 1.0f); + + // TODO(jpc) find how to adjust the string feedbacks + // for now set a fixed release time for all strings + const double releaseTime = 50e-3; + const double releaseFeedback = std::exp(-6.91 / (releaseTime * sampleRate)); + sfz::fill(feedbacks, releaseFeedback); + + // TODO(jpc) damping of the high frequencies + // fixed gains for now + sfz::fill(gains, 1e-3f); + + _stringsArray->setup( + sampleRate, numStrings, + pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); } void Strings::setSamplesPerBlock(int samplesPerBlock) { _tempBuffer.resize(samplesPerBlock); + + _stringsArray->setSamplesPerBlock(samplesPerBlock); } void Strings::clear() { - for (unsigned i = 0, n = _numStrings; i < n; ++i) { - ResonantString& rs = _strings[i]; - rs.bpf.clear(); - rs.res.clear(); - } + _stringsArray->clear(); } void Strings::process(const float* const inputs[], float* const outputs[], unsigned nframes) @@ -92,30 +95,15 @@ namespace fx { // generate the strings summed into a common buffer absl::Span resOutput = _tempBuffer.getSpan(1).first(nframes); - sfz::fill(resOutput, 0.0f); - for (unsigned is = 0, ns = _numStrings; is < ns; ++is) { - ResonantString& rs = _strings[is]; - for (unsigned i = 0; i < nframes; ++i) { - float sample = resInput[i]; - sample = rs.bpf.process(sample); - sample = rs.res.process(sample); - resOutput[i] += sample; - } - } - - // TODO(jpc) damping of the high frequencies - // it's easiest apply individual gains to resonating strings - // or pass resonator output through LPF + _stringsArray->process(resInput.data(), resOutput.data(), nframes); // mix the resonator into the output auto outputL = absl::MakeSpan(outputs[0], nframes); auto outputR = absl::MakeSpan(outputs[1], nframes); - constexpr float resAttenuate = 1e-3; // need significant attenuation, here -60dB - absl::Span wet = _tempBuffer.getSpan(2).first(nframes); - sfz::fill(wet, 0.01f * resAttenuate *_wet); // TOD strings_wet_oncc modulation... + sfz::fill(wet, 0.01f *_wet); // TOD strings_wet_oncc modulation... sfz::copy(inputL, outputL); sfz::copy(inputR, outputR); diff --git a/src/sfizz/effects/Strings.h b/src/sfizz/effects/Strings.h index a628960a..2f46254b 100644 --- a/src/sfizz/effects/Strings.h +++ b/src/sfizz/effects/Strings.h @@ -12,8 +12,7 @@ namespace sfz { namespace fx { - class Bw2BPF; - class WgResonator; + class ResonantArray; /** * @brief String resonance effect @@ -55,8 +54,7 @@ namespace fx { unsigned _numStrings = MaximumNumStrings; float _wet = 0; - struct ResonantString; - std::unique_ptr _strings; + std::unique_ptr _stringsArray; AudioBuffer _tempBuffer { 3, config::defaultSamplesPerBlock }; }; diff --git a/src/sfizz/effects/StringsPrivate.h b/src/sfizz/effects/StringsPrivate.h deleted file mode 100644 index e17a8b59..00000000 --- a/src/sfizz/effects/StringsPrivate.h +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#pragma once -#include "MathHelpers.h" -#include - -namespace sfz { -namespace fx { - - // Butterworth 2nd order bandpass (faust -double -os) - /* - import("stdfaust.lib"); - process = fi.bandpass(1, loF, hiF) with { - loF = hslider("[1] Lo frequency [unit:Hz]", 1, 0, 1000, 1); - hiF = hslider("[2] Hi frequency [unit:Hz]", 1, 0, 1000, 1); - }; - */ - class Bw2BPF { - private: - typedef float FAUSTFLOAT; - - public: - /** - * @brief Initialize. - */ - void init(double sampleRate) - { - fConst0 = sampleRate; - fConst1 = (2.0 / fConst0); - fConst2 = (2.0 * fConst0); - fConst3 = (3.1415926535897931 / fConst0); - fConst4 = (0.5 / fConst0); - fConst5 = (4.0 * power2(fConst0)); - fConst6 = power2((1.0 / fConst0)); - fConst7 = (2.0 * fConst6); - clear(); - } - - /** - * @brief Clear the memory of the filter. - */ - void clear() - { - for (int l0 = 0; (l0 < 3); l0 = (l0 + 1)) { - fRec0[l0] = 0.0; - } - } - - /** - * @brief Set the BPF low and high frequencies for -3dB response. - * - * The center frequency is (loF+hiF)/2. - */ - void setCutoff(double loF, double hiF) - { - fControl[0] = std::tan((fConst3 * double(hiF))); - fControl[1] = power2(std::sqrt((fConst5 * (fControl[0] * std::tan((fConst3 * double(loF))))))); - fControl[2] = ((fConst2 * fControl[0]) - (fConst4 * (fControl[1] / fControl[0]))); - fControl[3] = (fConst6 * fControl[1]); - fControl[4] = (fConst1 * fControl[2]); - fControl[5] = ((fControl[3] + fControl[4]) + 4.0); - fControl[6] = (fConst1 * (fControl[2] / fControl[5])); - fControl[7] = (1.0 / fControl[5]); - fControl[8] = ((fConst7 * fControl[1]) + -8.0); - fControl[9] = (fControl[3] + (4.0 - fControl[4])); - fControl[10] = (0.0 - fControl[6]); - } - - /** - * @brief Process the next filtered sample. - */ - FAUSTFLOAT process(FAUSTFLOAT input) - { - fRec0[0] = (double(input) - (fControl[7] * ((fControl[8] * fRec0[1]) + (fControl[9] * fRec0[2])))); - FAUSTFLOAT output = FAUSTFLOAT(((fControl[6] * fRec0[0]) + (fControl[10] * fRec0[2]))); - fRec0[2] = fRec0[1]; - fRec0[1] = fRec0[0]; - return output; - } - - private: - double fRec0[3] {}; - double fControl[11] {}; - double fConst0 {}; - double fConst1 {}; - double fConst2 {}; - double fConst3 {}; - double fConst4 {}; - double fConst5 {}; - double fConst6 {}; - double fConst7 {}; - }; - - //-------------------------------------------------------------------------- - - // Waveguide resonator (faust -os) - /* - import("stdfaust.lib"); - process = fi.nlf2(f, r) : (_,!) with { - f = hslider("[1] Resonance frequency [unit:Hz]", 1, 0, 1000, 1); - r = hslider("[2] Resonance feedback", 0, 0, 1, 1e-3); - }; - */ - class WgResonator { - private: - typedef float FAUSTFLOAT; - - public: - /** - * @brief Initialize. - */ - void init(float sampleRate) - { - fConst0 = (6.28318548f / sampleRate); - clear(); - } - - /** - * @brief Clear the memory of the resonator. - */ - void clear() - { - for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { - fRec0[l0] = 0.0f; - } - for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { - fRec1[l1] = 0.0f; - } - } - - /** - * @brief Set the resonance frequency. - */ - void setFrequency(float frequency) - { - fControl[1] = (fConst0 * float(frequency)); - fControl[2] = std::sin(fControl[1]); - fControl[3] = std::cos(fControl[1]); - } - - /** - * @brief Set the resonance feedback. - */ - void setFeedback(float feedback) - { - fControl[0] = float(feedback); - } - - /** - * @brief Process the next resonance sample. - */ - FAUSTFLOAT process(FAUSTFLOAT input) - { - fRec0[0] = (fControl[0] * ((fControl[2] * fRec1[1]) + (fControl[3] * fRec0[1]))); - fRec1[0] = ((float(input) + (fControl[3] * fRec1[1])) - (fControl[2] * fRec0[1])); - FAUSTFLOAT output = FAUSTFLOAT(fRec0[0]); - fRec0[1] = fRec0[0]; - fRec1[1] = fRec1[0]; - return output; - } - - private: - float fRec0[2] {}; - float fRec1[2] {}; - float fControl[4]; - float fConst0 {}; - }; - -} // namespace sfz -} // namespace fx diff --git a/src/sfizz/effects/dsp/resonant_string.dsp b/src/sfizz/effects/dsp/resonant_string.dsp new file mode 100644 index 00000000..8a6d896c --- /dev/null +++ b/src/sfizz/effects/dsp/resonant_string.dsp @@ -0,0 +1,8 @@ +import("stdfaust.lib"); + +f = hslider("[1] Resonance frequency [unit:Hz]", 1, 0, 22000, 1); +r = hslider("[2] Resonance feedback", 0, 0, 1, 0.001); +b = hslider("[3] Bandwidth [unit:Hz]", 1, 0, 10, 0.01); +g = hslider("[4] Gain", 0, 0, 1, 0.01); + +process = fi.bandpass(1, f-0.5*b, f+0.5*b) : fi.nlf2(f, r) : (_,!) : *(g); diff --git a/src/sfizz/effects/impl/ResonantArray.cpp b/src/sfizz/effects/impl/ResonantArray.cpp new file mode 100644 index 00000000..59204916 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArray.cpp @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ResonantArray.h" +#include "ResonantString.h" +#include "SIMDHelpers.h" + +namespace sfz { +namespace fx { + +ResonantArrayScalar::ResonantArrayScalar() +{ +} + +ResonantArrayScalar::~ResonantArrayScalar() +{ +} + +void ResonantArrayScalar::setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) +{ + ResonantString* strings = new ResonantString[numStrings]; + + _strings.reset(strings); + _numStrings = numStrings; + + for (unsigned i = 0; i < numStrings; ++i) { + ResonantString& rs = strings[i]; + rs.init(sampleRate); + rs.setResonanceFrequency(pitches[i], bandwidths[i]); + rs.setResonanceFeedback(feedbacks[i]); + rs.setGain(gains[i]); + } +} + +void ResonantArrayScalar::clear() +{ + ResonantString* strings = _strings.get(); + const unsigned numStrings = _numStrings; + + for (unsigned i = 0; i < numStrings; ++i) { + ResonantString& rs = strings[i]; + rs.clear(); + } +} + +void ResonantArrayScalar::process(const float *inPtr, float *outPtr, unsigned numFrames) +{ + ResonantString* strings = _strings.get(); + const unsigned numStrings = _numStrings; + + auto input = absl::MakeSpan(inPtr, numFrames); + auto output = absl::MakeSpan(outPtr, numFrames); + + sfz::fill(output, 0.0f); + + for (unsigned is = 0; is < numStrings; ++is) { + ResonantString& rs = strings[is]; + for (unsigned i = 0; i < numFrames; ++i) + output[i] += rs.process(input[i]); + } +} + +} // namespace sfz +} // namespace fx diff --git a/src/sfizz/effects/impl/ResonantArray.h b/src/sfizz/effects/impl/ResonantArray.h new file mode 100644 index 00000000..e0c6f662 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArray.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +namespace sfz { +namespace fx { + +class ResonantString; + +//------------------------------------------------------------------------------ + +class ResonantArray { +public: + virtual ~ResonantArray() {} + + virtual void setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) = 0; + + virtual void setSamplesPerBlock(unsigned samplesPerBlock) = 0; + + virtual void clear() = 0; + + virtual void process(const float *input, float *output, unsigned numFrames) = 0; +}; + +//------------------------------------------------------------------------------ + +class ResonantArrayScalar final : public ResonantArray { +public: + ResonantArrayScalar(); + ~ResonantArrayScalar(); + + void setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) override; + + void setSamplesPerBlock(unsigned) override {} + + void clear() override; + + void process(const float *inPtr, float *outPtr, unsigned numFrames) override; + +private: + std::unique_ptr _strings; + unsigned _numStrings = 0; +}; + +} // namespace sfz +} // namespace fx diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.cpp b/src/sfizz/effects/impl/ResonantArrayAVX.cpp new file mode 100644 index 00000000..73cbe86c --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArrayAVX.cpp @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ResonantArrayAVX.h" +#include "ResonantStringAVX.h" +#include "Config.h" +#include + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +namespace sfz { +namespace fx { + +static constexpr unsigned avxVectorSize = sizeof(__m256) / sizeof(float); + +ResonantArrayAVX::ResonantArrayAVX() +{ + setSamplesPerBlock(config::defaultSamplesPerBlock); +} + +ResonantArrayAVX::~ResonantArrayAVX() +{ +} + +void ResonantArrayAVX::setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) +{ + const unsigned numStringPacks = (numStrings + avxVectorSize - 1) / avxVectorSize; + ResonantStringAVX* stringPacks = new ResonantStringAVX[numStringPacks]; + + _stringPacks.reset(stringPacks); + _numStrings = numStrings; + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringAVX& rs = stringPacks[p]; + rs.init(sampleRate); + + __m256 pitchAVX = _mm256_set1_ps(0.0f); + __m256 bandwidthAVX = _mm256_set1_ps(0.0f); + __m256 feedbackAVX = _mm256_set1_ps(0.0f); + __m256 gainAVX = _mm256_set1_ps(0.0f); + + // copy 8 string parameters, or less if not enough remaining in buffer + unsigned numCopy = std::min(avxVectorSize, numStrings - (p * avxVectorSize)); + + std::memcpy(&pitchAVX, &pitches[p * avxVectorSize], numCopy * sizeof(float)); + std::memcpy(&bandwidthAVX, &bandwidths[p * avxVectorSize], numCopy * sizeof(float)); + std::memcpy(&feedbackAVX, &feedbacks[p * avxVectorSize], numCopy * sizeof(float)); + std::memcpy(&gainAVX, &gains[p * avxVectorSize], numCopy * sizeof(float)); + + rs.setResonanceFrequency(pitchAVX, bandwidthAVX); + rs.setResonanceFeedback(feedbackAVX); + rs.setGain(gainAVX); + } +} + +void ResonantArrayAVX::setSamplesPerBlock(unsigned samplesPerBlock) +{ + _workBuffer.resize(avxVectorSize * samplesPerBlock); +} + +void ResonantArrayAVX::clear() +{ + ResonantStringAVX* stringPacks = _stringPacks.get(); + const unsigned numStringPacks = (_numStrings + avxVectorSize - 1) / avxVectorSize; + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringAVX& rs = stringPacks[p]; + rs.clear(); + } +} + +void ResonantArrayAVX::process(const float *inPtr, float *outPtr, unsigned numFrames) +{ + ResonantStringAVX* stringPacks = _stringPacks.get(); + const unsigned numStringPacks = (_numStrings + avxVectorSize - 1) / avxVectorSize; + + // receive 4 resonator outputs per pack + __m256* outputs8 = reinterpret_cast<__m256*>(_workBuffer.data()); + std::memset(outputs8, 0, numFrames * sizeof(__m256)); + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringAVX& rs = stringPacks[p]; + for (unsigned i = 0; i < numFrames; ++i) + outputs8[i] += rs.process(_mm256_broadcast_ss(&inPtr[i])); + } + + // sum resonator outputs 8 to 1 + for (unsigned i = 0; i < numFrames; ++i) { + __m256 x = outputs8[i]; + const __m128 x128 = _mm_add_ps(_mm256_extractf128_ps(x, 1), _mm256_castps256_ps128(x)); + const __m128 x64 = _mm_add_ps(x128, _mm_movehl_ps(x128, x128)); + const __m128 x32 = _mm_add_ss(x64, _mm_shuffle_ps(x64, x64, 0x55)); + outPtr[i] = _mm_cvtss_f32(x32); + } +} + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.h b/src/sfizz/effects/impl/ResonantArrayAVX.h new file mode 100644 index 00000000..93dca2e2 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArrayAVX.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "ResonantArray.h" +#include "Buffer.h" +#include "SIMDConfig.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +namespace sfz { +namespace fx { + +class ResonantStringAVX; + +class ResonantArrayAVX final : public ResonantArray { +public: + ResonantArrayAVX(); + ~ResonantArrayAVX(); + + void setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) override; + + void setSamplesPerBlock(unsigned samplesPerBlock) override; + + void clear() override; + + void process(const float *inPtr, float *outPtr, unsigned numFrames) override; + +private: + std::unique_ptr _stringPacks; + unsigned _numStrings = 0; + Buffer _workBuffer; +}; + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantArraySSE.cpp b/src/sfizz/effects/impl/ResonantArraySSE.cpp new file mode 100644 index 00000000..75051664 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArraySSE.cpp @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ResonantArraySSE.h" +#include "ResonantStringSSE.h" +#include "Config.h" +#include + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +namespace sfz { +namespace fx { + +static constexpr unsigned sseVectorSize = sizeof(__m128) / sizeof(float); + +ResonantArraySSE::ResonantArraySSE() +{ + setSamplesPerBlock(config::defaultSamplesPerBlock); +} + +ResonantArraySSE::~ResonantArraySSE() +{ +} + +void ResonantArraySSE::setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) +{ + const unsigned numStringPacks = (numStrings + sseVectorSize - 1) / sseVectorSize; + ResonantStringSSE* stringPacks = new ResonantStringSSE[numStringPacks]; + + _stringPacks.reset(stringPacks); + _numStrings = numStrings; + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringSSE& rs = stringPacks[p]; + rs.init(sampleRate); + + __m128 pitchSSE = _mm_set1_ps(0.0f); + __m128 bandwidthSSE = _mm_set1_ps(0.0f); + __m128 feedbackSSE = _mm_set1_ps(0.0f); + __m128 gainSSE = _mm_set1_ps(0.0f); + + // copy 4 string parameters, or less if not enough remaining in buffer + unsigned numCopy = std::min(sseVectorSize, numStrings - (p * sseVectorSize)); + + std::memcpy(&pitchSSE, &pitches[p * sseVectorSize], numCopy * sizeof(float)); + std::memcpy(&bandwidthSSE, &bandwidths[p * sseVectorSize], numCopy * sizeof(float)); + std::memcpy(&feedbackSSE, &feedbacks[p * sseVectorSize], numCopy * sizeof(float)); + std::memcpy(&gainSSE, &gains[p * sseVectorSize], numCopy * sizeof(float)); + + rs.setResonanceFrequency(pitchSSE, bandwidthSSE); + rs.setResonanceFeedback(feedbackSSE); + rs.setGain(gainSSE); + } +} + +void ResonantArraySSE::setSamplesPerBlock(unsigned samplesPerBlock) +{ + _workBuffer.resize(sseVectorSize * samplesPerBlock); +} + +void ResonantArraySSE::clear() +{ + ResonantStringSSE* stringPacks = _stringPacks.get(); + const unsigned numStringPacks = (_numStrings + sseVectorSize - 1) / sseVectorSize; + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringSSE& rs = stringPacks[p]; + rs.clear(); + } +} + +void ResonantArraySSE::process(const float *inPtr, float *outPtr, unsigned numFrames) +{ + ResonantStringSSE* stringPacks = _stringPacks.get(); + const unsigned numStringPacks = (_numStrings + sseVectorSize - 1) / sseVectorSize; + + // receive 4 resonator outputs per pack + __m128* outputs4 = reinterpret_cast<__m128*>(_workBuffer.data()); + std::memset(outputs4, 0, numFrames * sizeof(__m128)); + + for (unsigned p = 0; p < numStringPacks; ++p) { + ResonantStringSSE& rs = stringPacks[p]; + for (unsigned i = 0; i < numFrames; ++i) + outputs4[i] += rs.process(_mm_load1_ps(&inPtr[i])); + } + + // sum resonator outputs 4 to 1 + for (unsigned i = 0; i < numFrames; ++i) { + __m128 xmm0 = outputs4[i]; + __m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5); + __m128 xmm2 = _mm_movehl_ps(xmm0, xmm0); + xmm1 = _mm_add_ss(xmm1, xmm0); + xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0xe7); + xmm2 = _mm_add_ss(xmm2, xmm1); + xmm0 = _mm_add_ss(xmm0, xmm2); + outPtr[i] = _mm_cvtss_f32(xmm0); + } +} + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantArraySSE.h b/src/sfizz/effects/impl/ResonantArraySSE.h new file mode 100644 index 00000000..36a67579 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantArraySSE.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "ResonantArray.h" +#include "Buffer.h" +#include "SIMDConfig.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +namespace sfz { +namespace fx { + +class ResonantStringSSE; + +class ResonantArraySSE final : public ResonantArray { +public: + ResonantArraySSE(); + ~ResonantArraySSE(); + + void setup( + float sampleRate, unsigned numStrings, + const float pitches[], const float bandwidths[], + const float feedbacks[], const float gains[]) override; + + void setSamplesPerBlock(unsigned samplesPerBlock) override; + + void clear() override; + + void process(const float *inPtr, float *outPtr, unsigned numFrames) override; + +private: + std::unique_ptr _stringPacks; + unsigned _numStrings = 0; + Buffer _workBuffer; +}; + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantString.cpp b/src/sfizz/effects/impl/ResonantString.cpp new file mode 100644 index 00000000..7e7aaf40 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantString.cpp @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#include "ResonantString.h" +#include +#include +#include + +namespace sfz { +namespace fx { + +static float faustpower2_f(float value) +{ + return (value * value); +} + +void ResonantString::init(float sample_rate) +{ + fConst0 = sample_rate; + fConst1 = (6.28318548f / fConst0); + fConst2 = (2.0f / fConst0); + fConst3 = (2.0f * fConst0); + fConst4 = (3.14159274f / fConst0); + fConst5 = (0.5f / fConst0); + fConst6 = (4.0f * faustpower2_f(fConst0)); + fConst7 = faustpower2_f((1.0f / fConst0)); + fConst8 = (2.0f * fConst7); + + clear(); +} + +void ResonantString::clear() +{ + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + fRec0[l0] = 0.0f; + } + for (int l1 = 0; (l1 < 3); l1 = (l1 + 1)) { + fRec2[l1] = 0.0f; + } + for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { + fRec1[l2] = 0.0f; + } +} + +void ResonantString::setGain(float gain) +{ + fControl[0] = gain; +} + +void ResonantString::setResonanceFeedback(float feedback) +{ + fControl[1] = feedback; +} + +void ResonantString::setResonanceFrequency(float frequency, float bandwidth) +{ + fControl[2] = frequency; + fControl[3] = (fConst1 * fControl[2]); + fControl[4] = std::sin(fControl[3]); + fControl[5] = std::cos(fControl[3]); + fControl[6] = (0.5f * bandwidth); + fControl[7] = std::tan((fConst4 * (fControl[6] + fControl[2]))); + fControl[8] = faustpower2_f(std::sqrt((fConst6 * (fControl[7] * std::tan((fConst4 * (fControl[2] - fControl[6]))))))); + fControl[9] = ((fConst3 * fControl[7]) - (fConst5 * (fControl[8] / fControl[7]))); + fControl[10] = (fConst7 * fControl[8]); + fControl[11] = (fConst2 * fControl[9]); + fControl[12] = ((fControl[10] + fControl[11]) + 4.0f); + fControl[13] = (fConst2 * (fControl[9] / fControl[12])); + fControl[14] = (0.0f - fControl[13]); + fControl[15] = (1.0f / fControl[12]); + fControl[16] = ((fConst8 * fControl[8]) + -8.0f); + fControl[17] = (fControl[10] + (4.0f - fControl[11])); +} + +float ResonantString::process(float input) +{ + fRec0[0] = (fControl[1] * ((fControl[4] * fRec1[1]) + (fControl[5] * fRec0[1]))); + float fTemp0 = input; + fRec2[0] = (fTemp0 - (fControl[15] * ((fControl[16] * fRec2[1]) + (fControl[17] * fRec2[2])))); + fRec1[0] = (((fControl[14] * fRec2[2]) + ((fControl[5] * fRec1[1]) + (fControl[13] * fRec2[0]))) - (fControl[4] * fRec0[1])); + float output = float((fControl[0] * fRec0[0])); + fRec0[1] = fRec0[0]; + fRec2[2] = fRec2[1]; + fRec2[1] = fRec2[0]; + fRec1[1] = fRec1[0]; + return output; +} + +} // namespace sfz +} // namespace fx diff --git a/src/sfizz/effects/impl/ResonantString.h b/src/sfizz/effects/impl/ResonantString.h new file mode 100644 index 00000000..df45a8ac --- /dev/null +++ b/src/sfizz/effects/impl/ResonantString.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#pragma once + +namespace sfz { +namespace fx { + +class ResonantString { +public: + void init(float sample_rate); + void clear(); + void setGain(float gain); + void setResonanceFeedback(float feedback); + void setResonanceFrequency(float frequency, float bandwidth); + float process(float input); + +private: + float fConst0 {}; + float fConst1 {}; + float fRec0[2] {}; + float fConst2 {}; + float fConst3 {}; + float fConst4 {}; + float fConst5 {}; + float fConst6 {}; + float fConst7 {}; + float fConst8 {}; + float fRec2[3] {}; + float fRec1[2] {}; + float fControl[18] {}; +}; + +} // namespace sfz +} // namespace fx diff --git a/src/sfizz/effects/impl/ResonantStringAVX.cpp b/src/sfizz/effects/impl/ResonantStringAVX.cpp new file mode 100644 index 00000000..e1819b52 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantStringAVX.cpp @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#include "ResonantStringAVX.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +#include +#include +#include + +namespace sfz { +namespace fx { + +static float faustpower2_f(float value) +{ + return (value * value); +} + +static __m256 faustpower2_v(__m256 value) +{ + return _mm256_mul_ps(value, value); +} + +static float load_nth_v(const __m256 &x, unsigned i) +{ + return reinterpret_cast(&x)[i]; +} + +static void store_nth_v(__m256 &x, unsigned i, float v) +{ + reinterpret_cast(&x)[i] = v; +} + +void ResonantStringAVX::init(float sample_rate) +{ + fConst0 = _mm256_set1_ps(sample_rate); + fConst1 = _mm256_div_ps(_mm256_set1_ps(6.28318548f), fConst0); + fConst2 = _mm256_div_ps(_mm256_set1_ps(2.0f), fConst0); + fConst3 = _mm256_mul_ps(_mm256_set1_ps(2.0f), fConst0); + fConst4 = _mm256_div_ps(_mm256_set1_ps(3.14159274f), fConst0); + fConst5 = _mm256_div_ps(_mm256_set1_ps(0.5f), fConst0); + fConst6 = _mm256_mul_ps(_mm256_set1_ps(4.0f), faustpower2_v(fConst0)); + fConst7 = faustpower2_v(_mm256_div_ps(_mm256_set1_ps(1.0f), fConst0)); + fConst8 = _mm256_mul_ps(_mm256_set1_ps(2.0f), fConst7); + + clear(); +} + +void ResonantStringAVX::clear() +{ + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + fRec0[l0] = _mm256_set1_ps(0.0f); + } + for (int l1 = 0; (l1 < 3); l1 = (l1 + 1)) { + fRec2[l1] = _mm256_set1_ps(0.0f); + } + for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { + fRec1[l2] = _mm256_set1_ps(0.0f); + } +} + +void ResonantStringAVX::setGain(__m256 gain) +{ + fControl[0] = gain; +} + +void ResonantStringAVX::setResonanceFeedback(__m256 feedback) +{ + fControl[1] = feedback; +} + +void ResonantStringAVX::setResonanceFrequency(__m256 frequency, __m256 bandwidth) +{ + fControl[2] = frequency; + fControl[3] = _mm256_mul_ps(fConst1, fControl[2]); + for (int i = 0; i < int(sizeof(__m256) / sizeof(float)); ++i) { + store_nth_v(fControl[4], i, std::sin(load_nth_v(fControl[3], i))); + store_nth_v(fControl[5], i, std::cos(load_nth_v(fControl[3], i))); + } + fControl[6] = _mm256_mul_ps(_mm256_set1_ps(0.5f), bandwidth); + for (int i = 0; i < int(sizeof(__m256) / sizeof(float)); ++i) { + store_nth_v(fControl[7], i, std::tan((load_nth_v(fConst4, i) * (load_nth_v(fControl[6], i) + load_nth_v(fControl[2], i))))); + store_nth_v(fControl[8], i, faustpower2_f(std::sqrt((load_nth_v(fConst6, i) * (load_nth_v(fControl[7], i) * std::tan((load_nth_v(fConst4, i) * (load_nth_v(fControl[2], i) - load_nth_v(fControl[6], i))))))))); + } + fControl[9] = _mm256_sub_ps(_mm256_mul_ps(fConst3, fControl[7]), _mm256_mul_ps(fConst5, _mm256_div_ps(fControl[8], fControl[7]))); + fControl[10] = _mm256_mul_ps(fConst7, fControl[8]); + fControl[11] = _mm256_mul_ps(fConst2, fControl[9]); + fControl[12] = _mm256_add_ps(_mm256_add_ps(fControl[10], fControl[11]), _mm256_set1_ps(4.0f)); + fControl[13] = _mm256_mul_ps(fConst2, _mm256_div_ps(fControl[9], fControl[12])); + fControl[14] = _mm256_sub_ps(_mm256_set1_ps(0.0f), fControl[13]); + fControl[15] = _mm256_div_ps(_mm256_set1_ps(1.0f), fControl[12]); + fControl[16] = _mm256_add_ps(_mm256_mul_ps(fConst8, fControl[8]), _mm256_set1_ps(-8.0f)); + fControl[17] = _mm256_add_ps(fControl[10], _mm256_sub_ps(_mm256_set1_ps(4.0f), fControl[11])); +} + +__m256 ResonantStringAVX::process(__m256 input) +{ + fRec0[0] = _mm256_mul_ps(fControl[1], _mm256_add_ps(_mm256_mul_ps(fControl[4], fRec1[1]), _mm256_mul_ps(fControl[5], fRec0[1]))); + __m256 fTemp0 = input; + fRec2[0] = _mm256_sub_ps(fTemp0, _mm256_mul_ps(fControl[15], _mm256_add_ps(_mm256_mul_ps(fControl[16], fRec2[1]), _mm256_mul_ps(fControl[17], fRec2[2])))); + fRec1[0] = _mm256_sub_ps(_mm256_add_ps(_mm256_mul_ps(fControl[14], fRec2[2]), _mm256_add_ps(_mm256_mul_ps(fControl[5], fRec1[1]), _mm256_mul_ps(fControl[13], fRec2[0]))),_mm256_mul_ps(fControl[4], fRec0[1])); + __m256 output = _mm256_mul_ps(fControl[0], fRec0[0]); + fRec0[1] = fRec0[0]; + fRec2[2] = fRec2[1]; + fRec2[1] = fRec2[0]; + fRec1[1] = fRec1[0]; + return output; +} + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantStringAVX.h b/src/sfizz/effects/impl/ResonantStringAVX.h new file mode 100644 index 00000000..4bcc1ec7 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantStringAVX.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#pragma once +#include "SIMDConfig.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +#include "immintrin.h" + +namespace sfz { +namespace fx { + +class alignas(32) ResonantStringAVX { +public: + void init(float sample_rate); + void clear(); + void setGain(__m256 gain); + void setResonanceFeedback(__m256 feedback); + void setResonanceFrequency(__m256 frequency, __m256 bandwidth); + __m256 process(__m256 input); + +private: + __m256 fConst0 {}; + __m256 fConst1 {}; + __m256 fRec0[2] {}; + __m256 fConst2 {}; + __m256 fConst3 {}; + __m256 fConst4 {}; + __m256 fConst5 {}; + __m256 fConst6 {}; + __m256 fConst7 {}; + __m256 fConst8 {}; + __m256 fRec2[3] {}; + __m256 fRec1[2] {}; + __m256 fControl[18] {}; +}; + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantStringSSE.cpp b/src/sfizz/effects/impl/ResonantStringSSE.cpp new file mode 100644 index 00000000..df802d48 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantStringSSE.cpp @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#include "ResonantStringSSE.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +#include +#include +#include + +namespace sfz { +namespace fx { + +static float faustpower2_f(float value) +{ + return (value * value); +} + +static __m128 faustpower2_v(__m128 value) +{ + return _mm_mul_ps(value, value); +} + +static float load_nth_v(const __m128 &x, unsigned i) +{ + return reinterpret_cast(&x)[i]; +} + +static void store_nth_v(__m128 &x, unsigned i, float v) +{ + reinterpret_cast(&x)[i] = v; +} + +void ResonantStringSSE::init(float sample_rate) +{ + fConst0 = _mm_set1_ps(sample_rate); + fConst1 = _mm_div_ps(_mm_set1_ps(6.28318548f), fConst0); + fConst2 = _mm_div_ps(_mm_set1_ps(2.0f), fConst0); + fConst3 = _mm_mul_ps(_mm_set1_ps(2.0f), fConst0); + fConst4 = _mm_div_ps(_mm_set1_ps(3.14159274f), fConst0); + fConst5 = _mm_div_ps(_mm_set1_ps(0.5f), fConst0); + fConst6 = _mm_mul_ps(_mm_set1_ps(4.0f), faustpower2_v(fConst0)); + fConst7 = faustpower2_v(_mm_div_ps(_mm_set1_ps(1.0f), fConst0)); + fConst8 = _mm_mul_ps(_mm_set1_ps(2.0f), fConst7); + + clear(); +} + +void ResonantStringSSE::clear() +{ + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + fRec0[l0] = _mm_set1_ps(0.0f); + } + for (int l1 = 0; (l1 < 3); l1 = (l1 + 1)) { + fRec2[l1] = _mm_set1_ps(0.0f); + } + for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { + fRec1[l2] = _mm_set1_ps(0.0f); + } +} + +void ResonantStringSSE::setGain(__m128 gain) +{ + fControl[0] = gain; +} + +void ResonantStringSSE::setResonanceFeedback(__m128 feedback) +{ + fControl[1] = feedback; +} + +void ResonantStringSSE::setResonanceFrequency(__m128 frequency, __m128 bandwidth) +{ + fControl[2] = frequency; + fControl[3] = _mm_mul_ps(fConst1, fControl[2]); + for (int i = 0; i < int(sizeof(__m128) / sizeof(float)); ++i) { + store_nth_v(fControl[4], i, std::sin(load_nth_v(fControl[3], i))); + store_nth_v(fControl[5], i, std::cos(load_nth_v(fControl[3], i))); + } + fControl[6] = _mm_mul_ps(_mm_set1_ps(0.5f), bandwidth); + for (int i = 0; i < int(sizeof(__m128) / sizeof(float)); ++i) { + store_nth_v(fControl[7], i, std::tan((load_nth_v(fConst4, i) * (load_nth_v(fControl[6], i) + load_nth_v(fControl[2], i))))); + store_nth_v(fControl[8], i, faustpower2_f(std::sqrt((load_nth_v(fConst6, i) * (load_nth_v(fControl[7], i) * std::tan((load_nth_v(fConst4, i) * (load_nth_v(fControl[2], i) - load_nth_v(fControl[6], i))))))))); + } + fControl[9] = _mm_sub_ps(_mm_mul_ps(fConst3, fControl[7]), _mm_mul_ps(fConst5, _mm_div_ps(fControl[8], fControl[7]))); + fControl[10] = _mm_mul_ps(fConst7, fControl[8]); + fControl[11] = _mm_mul_ps(fConst2, fControl[9]); + fControl[12] = _mm_add_ps(_mm_add_ps(fControl[10], fControl[11]), _mm_set1_ps(4.0f)); + fControl[13] = _mm_mul_ps(fConst2, _mm_div_ps(fControl[9], fControl[12])); + fControl[14] = _mm_sub_ps(_mm_set1_ps(0.0f), fControl[13]); + fControl[15] = _mm_div_ps(_mm_set1_ps(1.0f), fControl[12]); + fControl[16] = _mm_add_ps(_mm_mul_ps(fConst8, fControl[8]), _mm_set1_ps(-8.0f)); + fControl[17] = _mm_add_ps(fControl[10], _mm_sub_ps(_mm_set1_ps(4.0f), fControl[11])); +} + +__m128 ResonantStringSSE::process(__m128 input) +{ + fRec0[0] = _mm_mul_ps(fControl[1], _mm_add_ps(_mm_mul_ps(fControl[4], fRec1[1]), _mm_mul_ps(fControl[5], fRec0[1]))); + __m128 fTemp0 = input; + fRec2[0] = _mm_sub_ps(fTemp0, _mm_mul_ps(fControl[15], _mm_add_ps(_mm_mul_ps(fControl[16], fRec2[1]), _mm_mul_ps(fControl[17], fRec2[2])))); + fRec1[0] = _mm_sub_ps(_mm_add_ps(_mm_mul_ps(fControl[14], fRec2[2]), _mm_add_ps(_mm_mul_ps(fControl[5], fRec1[1]), _mm_mul_ps(fControl[13], fRec2[0]))),_mm_mul_ps(fControl[4], fRec0[1])); + __m128 output = _mm_mul_ps(fControl[0], fRec0[0]); + fRec0[1] = fRec0[0]; + fRec2[2] = fRec2[1]; + fRec2[1] = fRec2[0]; + fRec1[1] = fRec1[0]; + return output; +} + +} // namespace sfz +} // namespace fx +#endif diff --git a/src/sfizz/effects/impl/ResonantStringSSE.h b/src/sfizz/effects/impl/ResonantStringSSE.h new file mode 100644 index 00000000..ca32b5e2 --- /dev/null +++ b/src/sfizz/effects/impl/ResonantStringSSE.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + Note(jpc): generated with faust and edited + */ + +/* ------------------------------------------------------------ +name: "resonant_string" +Code generated with Faust 2.20.2 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -os -scal -ftz 0 +------------------------------------------------------------ */ + +#pragma once +#include "SIMDConfig.h" + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +#include "xmmintrin.h" + +namespace sfz { +namespace fx { + +class alignas(16) ResonantStringSSE { +public: + void init(float sample_rate); + void clear(); + void setGain(__m128 gain); + void setResonanceFeedback(__m128 feedback); + void setResonanceFrequency(__m128 frequency, __m128 bandwidth); + __m128 process(__m128 input); + +private: + __m128 fConst0 {}; + __m128 fConst1 {}; + __m128 fRec0[2] {}; + __m128 fConst2 {}; + __m128 fConst3 {}; + __m128 fConst4 {}; + __m128 fConst5 {}; + __m128 fConst6 {}; + __m128 fConst7 {}; + __m128 fConst8 {}; + __m128 fRec2[3] {}; + __m128 fRec1[2] {}; + __m128 fControl[18] {}; +}; + +} // namespace sfz +} // namespace fx +#endif From 10fa64b2c8e71687f40da0ea61321cea1a2b369d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 01:28:43 +0200 Subject: [PATCH 02/16] Add the cpuid library --- src/external/cpuid/CMakeLists.txt | 6 + src/external/cpuid/LICENSE.rst | 31 ++++ src/external/cpuid/platform/LICENSE.rst | 31 ++++ .../cpuid/platform/src/platform/config.hpp | 159 ++++++++++++++++++ src/external/cpuid/src/cpuid/cpuinfo.cpp | 103 ++++++++++++ src/external/cpuid/src/cpuid/cpuinfo.hpp | 72 ++++++++ .../cpuid/src/cpuid/detail/cpuinfo_impl.hpp | 39 +++++ .../src/cpuid/detail/extract_x86_flags.hpp | 39 +++++ .../cpuid/src/cpuid/detail/init_gcc_x86.hpp | 73 ++++++++ .../src/cpuid/detail/init_ios_clang_arm.hpp | 30 ++++ .../src/cpuid/detail/init_linux_gcc_arm.hpp | 64 +++++++ .../cpuid/src/cpuid/detail/init_msvc_arm.hpp | 26 +++ .../cpuid/src/cpuid/detail/init_msvc_x86.hpp | 52 ++++++ .../cpuid/src/cpuid/detail/init_unknown.hpp | 20 +++ src/external/cpuid/src/cpuid/version.cpp | 18 ++ src/external/cpuid/src/cpuid/version.hpp | 21 +++ 16 files changed, 784 insertions(+) create mode 100644 src/external/cpuid/CMakeLists.txt create mode 100644 src/external/cpuid/LICENSE.rst create mode 100644 src/external/cpuid/platform/LICENSE.rst create mode 100644 src/external/cpuid/platform/src/platform/config.hpp create mode 100644 src/external/cpuid/src/cpuid/cpuinfo.cpp create mode 100644 src/external/cpuid/src/cpuid/cpuinfo.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/cpuinfo_impl.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/extract_x86_flags.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_gcc_x86.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_ios_clang_arm.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_linux_gcc_arm.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_msvc_arm.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_msvc_x86.hpp create mode 100644 src/external/cpuid/src/cpuid/detail/init_unknown.hpp create mode 100644 src/external/cpuid/src/cpuid/version.cpp create mode 100644 src/external/cpuid/src/cpuid/version.hpp diff --git a/src/external/cpuid/CMakeLists.txt b/src/external/cpuid/CMakeLists.txt new file mode 100644 index 00000000..d4e779be --- /dev/null +++ b/src/external/cpuid/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required (VERSION 3.5) +project(sfizz-cpuid) + +add_library(sfizz-cpuid STATIC src/cpuid/cpuinfo.cpp src/cpuid/version.cpp) +set_property(TARGET sfizz-cpuid PROPERTY CXX_STANDARD 11) +target_include_directories(sfizz-cpuid PUBLIC src PRIVATE platform/src) diff --git a/src/external/cpuid/LICENSE.rst b/src/external/cpuid/LICENSE.rst new file mode 100644 index 00000000..9bfdb29a --- /dev/null +++ b/src/external/cpuid/LICENSE.rst @@ -0,0 +1,31 @@ +cpuid license +------------- +cpuid is provided under the "BSD (3-clause) License":: + + Copyright (c) 2014, Steinwurf ApS + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Steinwurf ApS nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS 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. diff --git a/src/external/cpuid/platform/LICENSE.rst b/src/external/cpuid/platform/LICENSE.rst new file mode 100644 index 00000000..6f26a40f --- /dev/null +++ b/src/external/cpuid/platform/LICENSE.rst @@ -0,0 +1,31 @@ +platform license +---------------- +platform is provided under the "BSD (3-clause) License":: + + Copyright (c) 2014, Steinwurf ApS + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Steinwurf ApS nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS 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. diff --git a/src/external/cpuid/platform/src/platform/config.hpp b/src/external/cpuid/platform/src/platform/config.hpp new file mode 100644 index 00000000..570fda76 --- /dev/null +++ b/src/external/cpuid/platform/src/platform/config.hpp @@ -0,0 +1,159 @@ +// Copyright (c) 2014 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +// Here we create a number of defines to make it easy to choose between +// different compilers, operatings systems and CPU architectures. +// Some information about the defines used can be found here: +// http://sourceforge.net/p/predef/wiki/Architectures/ + +// Detect operating systems +#if defined(__linux__) + #define PLATFORM_LINUX 1 + #if defined(__ANDROID__) + #define PLATFORM_ANDROID 1 + #endif +#elif defined(_WIN32) + #define PLATFORM_WINDOWS 1 + #if defined(WINAPI_FAMILY) + #include + #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) + #define PLATFORM_WINDOWS_PHONE 1 + #endif + #endif +#elif defined(__APPLE__) + // Detect iOS before MacOSX (__MACH__ is also defined for iOS) + #if defined(IPHONE) + #define PLATFORM_IOS 1 + #elif defined(__MACH__) + #define PLATFORM_MAC 1 + #endif +#elif defined(__EMSCRIPTEN__) + #define PLATFORM_EMSCRIPTEN 1 +#else + #error "Unable to determine operating system" +#endif + +// Detect compilers and CPU architectures +// Note: clang also defines __GNUC__ since it aims to be compatible with GCC. +// Therefore we need to check for __clang__ or __llvm__ first. +#if defined(__clang__) || defined(__llvm__) + #define PLATFORM_CLANG 1 + #define PLATFORM_GCC_COMPATIBLE 1 + #if defined(__i386__) || defined(__x86_64__) + #define PLATFORM_X86 1 + #define PLATFORM_CLANG_X86 1 + #define PLATFORM_GCC_COMPATIBLE_X86 1 + #elif defined(__arm__) || defined (__arm64__) || defined (__aarch64__) + #define PLATFORM_ARM 1 + #define PLATFORM_CLANG_ARM 1 + #define PLATFORM_GCC_COMPATIBLE_ARM 1 + #elif defined(__mips__) + #define PLATFORM_MIPS 1 + #define PLATFORM_CLANG_MIPS 1 + #define PLATFORM_GCC_COMPATIBLE_MIPS 1 + #elif defined(__asmjs__) + #define PLATFORM_ASMJS 1 + #define PLATFORM_CLANG_ASMJS 1 + #define PLATFORM_GCC_COMPATIBLE_ASMJS 1 + #endif +#elif defined(__GNUC__) + #define PLATFORM_GCC 1 + #define PLATFORM_GCC_COMPATIBLE 1 + #if defined(__i386__) || defined(__x86_64__) + #define PLATFORM_X86 1 + #define PLATFORM_GCC_X86 1 + #define PLATFORM_GCC_COMPATIBLE_X86 1 + #elif defined(__arm__) || defined (__arm64__) || defined (__aarch64__) + #define PLATFORM_ARM 1 + #define PLATFORM_GCC_ARM 1 + #define PLATFORM_GCC_COMPATIBLE_ARM 1 + #elif defined(__mips__) + #define PLATFORM_MIPS 1 + #define PLATFORM_GCC_MIPS 1 + #define PLATFORM_GCC_COMPATIBLE_MIPS 1 + #endif +#elif defined(_MSC_VER) + #define PLATFORM_MSVC 1 + #if defined(_M_IX86) || defined(_M_X64) + #define PLATFORM_X86 1 + #define PLATFORM_MSVC_X86 1 + #elif defined(_M_ARM) || defined(_M_ARMT) + #define PLATFORM_ARM 1 + #define PLATFORM_MSVC_ARM 1 + #endif +#else + #error "Unable to determine compiler" +#endif + +// Define macros for supported CPU instruction sets +#if defined(PLATFORM_GCC_COMPATIBLE) + #if defined(__MMX__) + #define PLATFORM_MMX 1 + #endif + #if defined(__SSE__) + #define PLATFORM_SSE 1 + #endif + #if defined(__SSE2__) + #define PLATFORM_SSE2 1 + #endif + #if defined(__SSE3__) + #define PLATFORM_SSE3 1 + #endif + #if defined(__SSSE3__) + #define PLATFORM_SSSE3 1 + #endif + #if defined(__SSE4_1__) + #define PLATFORM_SSE41 1 + #endif + #if defined(__SSE4_2__) + #define PLATFORM_SSE42 1 + #endif + #if defined(__PCLMUL__) + #define PLATFORM_PCLMUL 1 + #endif + #if defined(__AVX__) + #define PLATFORM_AVX 1 + #endif + #if defined(__AVX2__) + #define PLATFORM_AVX2 1 + #endif + #if defined(__ARM_NEON__) || defined (__ARM_NEON) + #define PLATFORM_NEON 1 + #endif + // First, check the PLATFORM_WINDOWS_PHONE define, because + // the X86 instructions sets are not supported on the Windows Phone emulator +#elif defined(PLATFORM_WINDOWS_PHONE) + #if defined(PLATFORM_MSVC_ARM) + // NEON introduced in VS2012 + #if (_MSC_VER >= 1700) + #define PLATFORM_NEON 1 + #endif + #endif +#elif defined(PLATFORM_MSVC_X86) + // MMX, SSE and SSE2 introduced in VS2003 + #if (_MSC_VER >= 1310) + #define PLATFORM_MMX 1 + #define PLATFORM_SSE 1 + #define PLATFORM_SSE2 1 + #endif + // SSE3 introduced in VS2005 + #if (_MSC_VER >= 1400) + #define PLATFORM_SSE3 1 + #endif + // SSSE3, SSE4.1, SSE4.2, PCLMUL introduced in VS2008 + #if (_MSC_VER >= 1500) + #define PLATFORM_SSSE3 1 + #define PLATFORM_SSE41 1 + #define PLATFORM_SSE42 1 + #define PLATFORM_PCLMUL 1 + #endif + // AVX and AVX2 introduced in VS2012 + #if (_MSC_VER >= 1700) + #define PLATFORM_AVX 1 + #define PLATFORM_AVX2 1 + #endif +#endif diff --git a/src/external/cpuid/src/cpuid/cpuinfo.cpp b/src/external/cpuid/src/cpuid/cpuinfo.cpp new file mode 100644 index 00000000..93569229 --- /dev/null +++ b/src/external/cpuid/src/cpuid/cpuinfo.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#include + +#include "cpuinfo.hpp" +#include "detail/cpuinfo_impl.hpp" + +#if defined(PLATFORM_GCC_COMPATIBLE_X86) + #include "detail/init_gcc_x86.hpp" +#elif defined(PLATFORM_MSVC_X86) && !defined(PLATFORM_WINDOWS_PHONE) + #include "detail/init_msvc_x86.hpp" +#elif defined(PLATFORM_MSVC_ARM) + #include "detail/init_msvc_arm.hpp" +#elif defined(PLATFORM_CLANG_ARM) && defined(PLATFORM_IOS) + #include "detail/init_ios_clang_arm.hpp" +#elif defined(PLATFORM_GCC_COMPATIBLE_ARM) && defined(PLATFORM_LINUX) + #include "detail/init_linux_gcc_arm.hpp" +#else + #include "detail/init_unknown.hpp" +#endif + +namespace cpuid +{ + +inline namespace STEINWURF_CPUID_VERSION +{ + +cpuinfo::cpuinfo() : + m_impl(new impl) +{ + init_cpuinfo(*m_impl); +} + +cpuinfo::~cpuinfo() +{ +} + +// x86 member functions +bool cpuinfo::has_fpu() const +{ + return m_impl->m_has_fpu; +} + +bool cpuinfo::has_mmx() const +{ + return m_impl->m_has_mmx; +} + +bool cpuinfo::has_sse() const +{ + return m_impl->m_has_sse; +} + +bool cpuinfo::has_sse2() const +{ + return m_impl->m_has_sse2; +} + +bool cpuinfo::has_sse3() const +{ + return m_impl->m_has_sse3; +} + +bool cpuinfo::has_ssse3() const +{ + return m_impl->m_has_ssse3; +} + +bool cpuinfo::has_sse4_1() const +{ + return m_impl->m_has_sse4_1; +} + +bool cpuinfo::has_sse4_2() const +{ + return m_impl->m_has_sse4_2; +} + +bool cpuinfo::has_pclmulqdq() const +{ + return m_impl->m_has_pclmulqdq; +} + +bool cpuinfo::has_avx() const +{ + return m_impl->m_has_avx; +} + +bool cpuinfo::has_avx2() const +{ + return m_impl->m_has_avx2; +} + +// ARM functions +bool cpuinfo::has_neon() const +{ + return m_impl->m_has_neon; +} +} +} diff --git a/src/external/cpuid/src/cpuid/cpuinfo.hpp b/src/external/cpuid/src/cpuid/cpuinfo.hpp new file mode 100644 index 00000000..60979c1e --- /dev/null +++ b/src/external/cpuid/src/cpuid/cpuinfo.hpp @@ -0,0 +1,72 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include + +#include "version.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +/// The cpuinfo object extract information about which, if any, additional +/// instructiions are supported by the CPU. +class cpuinfo +{ +public: + /// Constructor for feature detection with default values + cpuinfo(); + + /// Destructor + ~cpuinfo(); + + /// Has X87 FPU + bool has_fpu() const; + + /// Return true if the CPU supports MMX + bool has_mmx() const; + + /// Return true if the CPU supports SSE + bool has_sse() const; + + /// Return true if the CPU supports SSE2 + bool has_sse2() const; + + /// Return true if the CPU supports SSE3 + bool has_sse3() const; + + /// Return true if the CPU supports SSSE3 + bool has_ssse3() const; + + /// Return true if the CPU supports SSE 4.1 + bool has_sse4_1() const; + + /// Return true if the CPU supports SSE 4.2 + bool has_sse4_2() const; + + /// Return true if the CPU supports pclmulqdq + bool has_pclmulqdq() const; + + /// Return true if the CPU supports AVX + bool has_avx() const; + + /// Return true if the CPU supports AVX2 + bool has_avx2() const; + + /// ARM member functions + bool has_neon() const; + +public: + /// Private implementation + struct impl; + +private: + /// Pimpl pointer + std::unique_ptr m_impl; +}; +} +} diff --git a/src/external/cpuid/src/cpuid/detail/cpuinfo_impl.hpp b/src/external/cpuid/src/cpuid/detail/cpuinfo_impl.hpp new file mode 100644 index 00000000..9eee303a --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/cpuinfo_impl.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include "../cpuinfo.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ + +struct cpuinfo::impl +{ + impl() : + m_has_fpu(false), m_has_mmx(false), m_has_sse(false), m_has_sse2(false), + m_has_sse3(false), m_has_ssse3(false), m_has_sse4_1(false), + m_has_sse4_2(false), m_has_pclmulqdq(false), m_has_avx(false), + m_has_avx2(false), m_has_neon(false) + { + } + + bool m_has_fpu; + bool m_has_mmx; + bool m_has_sse; + bool m_has_sse2; + bool m_has_sse3; + bool m_has_ssse3; + bool m_has_sse4_1; + bool m_has_sse4_2; + bool m_has_pclmulqdq; + bool m_has_avx; + bool m_has_avx2; + bool m_has_neon; +}; +} +} diff --git a/src/external/cpuid/src/cpuid/detail/extract_x86_flags.hpp b/src/external/cpuid/src/cpuid/detail/extract_x86_flags.hpp new file mode 100644 index 00000000..eee98190 --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/extract_x86_flags.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include + +#include "cpuinfo_impl.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +void extract_x86_flags(cpuinfo::impl& info, uint32_t ecx, uint32_t edx) +{ + // Instruction set flags + + info.m_has_fpu = (edx & (1 << 0)) != 0; + info.m_has_mmx = (edx & (1 << 23)) != 0; + info.m_has_sse = (edx & (1 << 25)) != 0; + info.m_has_sse2 = (edx & (1 << 26)) != 0; + info.m_has_sse3 = (ecx & (1 << 0)) != 0; + info.m_has_ssse3 = (ecx & (1 << 9)) != 0; + info.m_has_sse4_1 = (ecx & (1 << 19)) != 0; + info.m_has_sse4_2 = (ecx & (1 << 20)) != 0; + info.m_has_pclmulqdq = (ecx & (1 << 1)) != 0; + info.m_has_avx = (ecx & (1 << 28)) != 0; +} + +void extract_x86_extended_flags(cpuinfo::impl& info, uint32_t ebx) +{ + // Extended instruction set flags + + info.m_has_avx2 = (ebx & (1 << 5)) != 0; +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_gcc_x86.hpp b/src/external/cpuid/src/cpuid/detail/init_gcc_x86.hpp new file mode 100644 index 00000000..916175b5 --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_gcc_x86.hpp @@ -0,0 +1,73 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include + +#include "cpuinfo_impl.hpp" +#include "extract_x86_flags.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +// Reference for this code is Intel's recommendation for detecting AVX2 +// on Haswell located here: http://goo.gl/c6IkGX +void run_cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd) +{ + uint32_t ebx = 0, edx = 0; + +#if defined(__i386__) && defined(__PIC__) + // If PIC used under 32-bit, EBX cannot be clobbered + // EBX is saved to EDI and later restored + __asm__("movl %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=D"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx)); +#else + __asm__("cpuid;" : "+b"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx)); +#endif + + abcd[0] = eax; + abcd[1] = ebx; + abcd[2] = ecx; + abcd[3] = edx; +} + +/// @todo Document +void init_cpuinfo(cpuinfo::impl& info) +{ + // Note: We need to capture these 4 registers, otherwise we get + // a segmentation fault on 32-bit Linux + uint32_t output[4]; + + // The register information per input can be extracted from here: + // http://en.wikipedia.org/wiki/CPUID + + // CPUID should be called with EAX=0 first, as this will return the + // maximum supported EAX input value for future calls + run_cpuid(0, 0, output); + uint32_t maximum_index = output[0]; + + // Set registers for basic flag extraction + // All CPUs should support index=1 + if (maximum_index >= 1U) + { + run_cpuid(1, 0, output); + extract_x86_flags(info, output[2], output[3]); + } + + // Set registers for extended flags extraction using index=7 + // This operation is not supported on older CPUs, so it should be skipped + // to avoid incorrect results + if (maximum_index >= 7U) + { + run_cpuid(7, 0, output); + extract_x86_extended_flags(info, output[1]); + } +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_ios_clang_arm.hpp b/src/external/cpuid/src/cpuid/detail/init_ios_clang_arm.hpp new file mode 100644 index 00000000..5eae039f --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_ios_clang_arm.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include "cpuinfo_impl.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +/// @todo docs +void init_cpuinfo(cpuinfo::impl& info) +{ + // The __ARM_NEON__ macro will be defined by the Apple Clang compiler + // when targeting ARMv7 processors that have NEON. + // The compiler guarantees this capability, so there is no benefit + // in doing a runtime check. More info in this SO answer: + // http://stackoverflow.com/a/1601234 + +#if defined __ARM_NEON__ + info.m_has_neon = true; +#else + info.m_has_neon = false; +#endif +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_linux_gcc_arm.hpp b/src/external/cpuid/src/cpuid/detail/init_linux_gcc_arm.hpp new file mode 100644 index 00000000..2895ac4b --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_linux_gcc_arm.hpp @@ -0,0 +1,64 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include "cpuinfo_impl.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +/// @todo docs +void init_cpuinfo(cpuinfo::impl& info) +{ +#if defined(__aarch64__) + // The Advanced SIMD (NEON) instruction set is required on AArch64 + // (64-bit ARM). Note that /proc/cpuinfo will display "asimd" instead of + // "neon" in the Features list on a 64-bit ARM CPU. + info.m_has_neon = true; +#else + // Runtime detection of NEON is necessary on 32-bit ARM CPUs + // + // Follow recommendation from Cortex-A Series Programmer's guide + // in Section 20.1.7 Detecting NEON. The guide is available at + // Steinwurf's Google drive: steinwurf/technical/experimental/cpuid + + auto cpufile = open("/proc/self/auxv", O_RDONLY); + assert(cpufile); + + Elf32_auxv_t auxv; + + if (cpufile >= 0) + { + const auto size_auxv_t = sizeof(Elf32_auxv_t); + while (read(cpufile, &auxv, size_auxv_t) == size_auxv_t) + { + if (auxv.a_type == AT_HWCAP) + { + info.m_has_neon = (auxv.a_un.a_val & 4096) != 0; + break; + } + } + + close(cpufile); + } + else + { + info.m_has_neon = false; + } +#endif +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_msvc_arm.hpp b/src/external/cpuid/src/cpuid/detail/init_msvc_arm.hpp new file mode 100644 index 00000000..60cbf3f7 --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_msvc_arm.hpp @@ -0,0 +1,26 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include "cpuinfo_impl.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +void init_cpuinfo(cpuinfo::impl& info) +{ + // Visual Studio 2012 (and above) guarantees the NEON capability when + // compiling for Windows Phone 8 (and above) + +#if defined(PLATFORM_WINDOWS_PHONE) + info.m_has_neon = true; +#else + info.m_has_neon = false; +#endif +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_msvc_x86.hpp b/src/external/cpuid/src/cpuid/detail/init_msvc_x86.hpp new file mode 100644 index 00000000..7ce670a9 --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_msvc_x86.hpp @@ -0,0 +1,52 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include + +#include "cpuinfo_impl.hpp" +#include "extract_x86_flags.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +/// @todo docs +void init_cpuinfo(cpuinfo::impl& info) +{ + int registers[4]; + + /// According to the msvc docs eax, ebx, ecx and edx are + /// stored (in that order) in the array passed to the __cpuid + /// function. + + // The register information per input can be extracted from here: + // http://en.wikipedia.org/wiki/CPUID + + // CPUID should be called with EAX=0 first, as this will return the + // maximum supported EAX input value for future calls + __cpuid(registers, 0); + uint32_t maximum_eax = registers[0]; + + // Set registers for basic flag extraction, eax=1 + // All CPUs should support index=1 + if (maximum_eax >= 1U) + { + __cpuid(registers, 1); + extract_x86_flags(info, registers[2], registers[3]); + } + + // Set registers for extended flags extraction, eax=7 and ecx=0 + // This operation is not supported on older CPUs, so it should be skipped + // to avoid incorrect results + if (maximum_eax >= 7U) + { + __cpuidex(registers, 7, 0); + extract_x86_extended_flags(info, registers[1]); + } +} +} +} diff --git a/src/external/cpuid/src/cpuid/detail/init_unknown.hpp b/src/external/cpuid/src/cpuid/detail/init_unknown.hpp new file mode 100644 index 00000000..ff876f9f --- /dev/null +++ b/src/external/cpuid/src/cpuid/detail/init_unknown.hpp @@ -0,0 +1,20 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include "cpuinfo_impl.hpp" + +namespace cpuid +{ +inline namespace STEINWURF_CPUID_VERSION +{ +/// @todo docs +void init_cpuinfo(cpuinfo::impl& info) +{ + (void)info; +} +} +} diff --git a/src/external/cpuid/src/cpuid/version.cpp b/src/external/cpuid/src/cpuid/version.cpp new file mode 100644 index 00000000..8b35150a --- /dev/null +++ b/src/external/cpuid/src/cpuid/version.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#include "version.hpp" + +namespace cpuid +{ + +inline namespace STEINWURF_CPUID_VERSION +{ +std::string version() +{ + return "6.3.1"; +} +} +} diff --git a/src/external/cpuid/src/cpuid/version.hpp b/src/external/cpuid/src/cpuid/version.hpp new file mode 100644 index 00000000..9bb4fb87 --- /dev/null +++ b/src/external/cpuid/src/cpuid/version.hpp @@ -0,0 +1,21 @@ +// Copyright (c) 2013 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#pragma once + +#include + +namespace cpuid +{ +/// Here we define the STEINWURF_CPUID_VERSION this should be updated on each +/// release +#define STEINWURF_CPUID_VERSION v6_3_1 + +inline namespace STEINWURF_CPUID_VERSION +{ +/// @return The version of the library as string +std::string version(); +} +} From 843d603f37f7c52fd77c8ec9f90e69edd275926b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 01:29:11 +0200 Subject: [PATCH 03/16] Add CPU dispatch for the strings effect --- src/CMakeLists.txt | 5 +++-- src/sfizz/effects/Strings.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1655147b..b3d472df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ include (GNUInstallDirs) add_subdirectory(external/kiss_fft) +add_subdirectory(external/cpuid) set (SFIZZ_SOURCES sfizz/Synth.cpp @@ -54,7 +55,7 @@ target_sources(sfizz_static PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp sfi target_include_directories (sfizz_static PUBLIC .) target_include_directories (sfizz_static PUBLIC external) target_link_libraries (sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-kissfft) +target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-kissfft sfizz-cpuid) set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") if (WIN32) target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES) @@ -89,7 +90,7 @@ if (SFIZZ_SHARED) target_sources(sfizz_shared PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories (sfizz_shared PRIVATE .) target_include_directories (sfizz_shared PRIVATE external) - target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-kissfft) + target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-kissfft sfizz-cpuid) if (WIN32) target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES) endif() diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index d739c593..e3f8bcc9 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -22,6 +22,7 @@ Extensions #include "Opcode.h" #include "MathHelpers.h" #include "SIMDHelpers.h" +#include "cpuid/cpuinfo.hpp" #include "absl/memory/memory.h" #include @@ -31,6 +32,19 @@ namespace fx { Strings::Strings() : _stringsArray(new ResonantArrayScalar) { + ResonantArray* array = nullptr; + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + cpuid::cpuinfo cpuInfo; + if (cpuInfo.has_avx()) + array = new ResonantArrayAVX; + else if (cpuInfo.has_sse()) + array = new ResonantArraySSE; +#endif + if (!array) + array = new ResonantArrayScalar; + + _stringsArray.reset(array); } Strings::~Strings() From 3e3ed3c3ac9ca9f266944bc79ba559b964f3010c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 01:56:17 +0200 Subject: [PATCH 04/16] Fix for MSVC --- src/sfizz/effects/impl/ResonantArrayAVX.cpp | 3 ++- src/sfizz/effects/impl/ResonantArraySSE.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.cpp b/src/sfizz/effects/impl/ResonantArrayAVX.cpp index 73cbe86c..b06c41f2 100644 --- a/src/sfizz/effects/impl/ResonantArrayAVX.cpp +++ b/src/sfizz/effects/impl/ResonantArrayAVX.cpp @@ -86,7 +86,8 @@ void ResonantArrayAVX::process(const float *inPtr, float *outPtr, unsigned numFr for (unsigned p = 0; p < numStringPacks; ++p) { ResonantStringAVX& rs = stringPacks[p]; for (unsigned i = 0; i < numFrames; ++i) - outputs8[i] += rs.process(_mm256_broadcast_ss(&inPtr[i])); + outputs8[i] = _mm256_add_ps( + outputs8[i], rs.process(_mm256_broadcast_ss(&inPtr[i]))); } // sum resonator outputs 8 to 1 diff --git a/src/sfizz/effects/impl/ResonantArraySSE.cpp b/src/sfizz/effects/impl/ResonantArraySSE.cpp index 75051664..7480a877 100644 --- a/src/sfizz/effects/impl/ResonantArraySSE.cpp +++ b/src/sfizz/effects/impl/ResonantArraySSE.cpp @@ -86,7 +86,8 @@ void ResonantArraySSE::process(const float *inPtr, float *outPtr, unsigned numFr for (unsigned p = 0; p < numStringPacks; ++p) { ResonantStringSSE& rs = stringPacks[p]; for (unsigned i = 0; i < numFrames; ++i) - outputs4[i] += rs.process(_mm_load1_ps(&inPtr[i])); + outputs4[i] = _mm_add_ps( + outputs4[i], rs.process(_mm_load1_ps(&inPtr[i]))); } // sum resonator outputs 4 to 1 From 319554321b2ef1515ccdab752883fe605fc3b1c4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 02:06:27 +0200 Subject: [PATCH 05/16] Fix mistake in comment [ci skip] --- src/sfizz/effects/impl/ResonantArrayAVX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.cpp b/src/sfizz/effects/impl/ResonantArrayAVX.cpp index b06c41f2..a427375c 100644 --- a/src/sfizz/effects/impl/ResonantArrayAVX.cpp +++ b/src/sfizz/effects/impl/ResonantArrayAVX.cpp @@ -79,7 +79,7 @@ void ResonantArrayAVX::process(const float *inPtr, float *outPtr, unsigned numFr ResonantStringAVX* stringPacks = _stringPacks.get(); const unsigned numStringPacks = (_numStrings + avxVectorSize - 1) / avxVectorSize; - // receive 4 resonator outputs per pack + // receive 8 resonator outputs per pack __m256* outputs8 = reinterpret_cast<__m256*>(_workBuffer.data()); std::memset(outputs8, 0, numFrames * sizeof(__m256)); From 86e3c2232ff6abdab8f2b361fdb44cba0f779e5b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 09:15:54 +0200 Subject: [PATCH 06/16] Add the benchmark for string resonator --- benchmarks/BM_stringResonator.cpp | 103 ++++++++++++++++++++++++++++++ benchmarks/CMakeLists.txt | 10 +++ 2 files changed, 113 insertions(+) create mode 100644 benchmarks/BM_stringResonator.cpp diff --git a/benchmarks/BM_stringResonator.cpp b/benchmarks/BM_stringResonator.cpp new file mode 100644 index 00000000..2ddbaa6b --- /dev/null +++ b/benchmarks/BM_stringResonator.cpp @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Macros.h" +#include "ScopedFTZ.h" +#include "MathHelpers.h" +#include "SIMDConfig.h" +#include "effects/impl/ResonantArray.h" +#include "effects/impl/ResonantArraySSE.h" +#include "effects/impl/ResonantArrayAVX.h" +#include +#include +#include + +class AddArray : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State& state) { + std::random_device rd { }; + std::mt19937 gen { rd() }; + + numStrings = state.range(0); + pitches.resize(numStrings); + bandwidths.resize(numStrings); + feedbacks.resize(numStrings); + gains.resize(numStrings); + + std::generate(pitches.begin(), pitches.end(), [&]() { + std::uniform_int_distribution<> dist {0, 127}; + return midiNoteFrequency(dist(gen)); + }); + + std::fill(bandwidths.begin(), bandwidths.end(), 1.0f); + std::fill(feedbacks.begin(), feedbacks.end(), std::exp(-6.91 / (50e-3 * sampleRate))); + std::fill(gains.begin(), gains.end(), 1e-3f); + + input.resize(numFrames); + output.resize(numFrames); + + std::generate(input.begin(), input.end(), [&]() { + std::uniform_real_distribution<> dist {-1, 1}; + return dist(gen); + }); + } + + void TearDown(const ::benchmark::State& state) { + UNUSED(state); + } + + static constexpr float sampleRate = 44100; + static constexpr unsigned numFrames = sampleRate * 5.0; + std::vector input; + std::vector output; + unsigned numStrings = 0; + std::vector pitches; + std::vector bandwidths; + std::vector feedbacks; + std::vector gains; +}; + +BENCHMARK_DEFINE_F(AddArray, StringResonator_Scalar)(benchmark::State& state) { + ScopedFTZ ftz; + sfz::fx::ResonantArrayScalar resonator; + resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); + resonator.setSamplesPerBlock(numFrames); + for (auto _ : state) + { + resonator.process(input.data(), output.data(), numFrames); + } +} + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +BENCHMARK_DEFINE_F(AddArray, StringResonator_SSE)(benchmark::State& state) { + ScopedFTZ ftz; + sfz::fx::ResonantArraySSE resonator; + resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); + resonator.setSamplesPerBlock(numFrames); + for (auto _ : state) + { + resonator.process(input.data(), output.data(), numFrames); + } +} + +BENCHMARK_DEFINE_F(AddArray, StringResonator_AVX)(benchmark::State& state) { + ScopedFTZ ftz; + sfz::fx::ResonantArrayAVX resonator; + resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); + resonator.setSamplesPerBlock(numFrames); + for (auto _ : state) + { + resonator.process(input.data(), output.data(), numFrames); + } +} +#endif + +BENCHMARK_REGISTER_F(AddArray, StringResonator_Scalar)->RangeMultiplier(4)->Range(1, 128); +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +BENCHMARK_REGISTER_F(AddArray, StringResonator_SSE)->RangeMultiplier(4)->Range(1, 128); +BENCHMARK_REGISTER_F(AddArray, StringResonator_AVX)->RangeMultiplier(4)->Range(1, 128); +#endif +BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 3da1d309..493f450e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -93,6 +93,15 @@ target_link_libraries(bm_filterModulation PRIVATE sfizz-sndfile) sfizz_add_benchmark(bm_filterStereoMono BM_filterStereoMono.cpp ../src/sfizz/SfzFilter.cpp) target_link_libraries(bm_filterStereoMono PRIVATE sfizz-sndfile) +sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp + ../src/sfizz/effects/impl/ResonantArray.cpp + ../src/sfizz/effects/impl/ResonantArraySSE.cpp + ../src/sfizz/effects/impl/ResonantArrayAVX.cpp + ../src/sfizz/effects/impl/ResonantString.cpp + ../src/sfizz/effects/impl/ResonantStringSSE.cpp + ../src/sfizz/effects/impl/ResonantStringAVX.cpp) +target_link_libraries(bm_stringResonator PRIVATE sfizz-sndfile) + add_custom_target(sfizz_benchmarks) add_dependencies(sfizz_benchmarks bm_opf_high_vs_low @@ -126,6 +135,7 @@ add_dependencies(sfizz_benchmarks bm_flacfile bm_filterModulation bm_filterStereoMono + bm_stringResonator ) if (TARGET bm_resample) From 03289c7b8045a7e3e22c61ae7a3d4a0a45d4e381 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:05:32 +0200 Subject: [PATCH 07/16] Remove the initializers to make the classes trivial --- src/sfizz/effects/impl/ResonantString.h | 26 +++++++++++----------- src/sfizz/effects/impl/ResonantStringAVX.h | 26 +++++++++++----------- src/sfizz/effects/impl/ResonantStringSSE.h | 26 +++++++++++----------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/sfizz/effects/impl/ResonantString.h b/src/sfizz/effects/impl/ResonantString.h index df45a8ac..0442598f 100644 --- a/src/sfizz/effects/impl/ResonantString.h +++ b/src/sfizz/effects/impl/ResonantString.h @@ -29,19 +29,19 @@ public: float process(float input); private: - float fConst0 {}; - float fConst1 {}; - float fRec0[2] {}; - float fConst2 {}; - float fConst3 {}; - float fConst4 {}; - float fConst5 {}; - float fConst6 {}; - float fConst7 {}; - float fConst8 {}; - float fRec2[3] {}; - float fRec1[2] {}; - float fControl[18] {}; + float fConst0; + float fConst1; + float fRec0[2]; + float fConst2; + float fConst3; + float fConst4; + float fConst5; + float fConst6; + float fConst7; + float fConst8; + float fRec2[3]; + float fRec1[2]; + float fControl[18]; }; } // namespace sfz diff --git a/src/sfizz/effects/impl/ResonantStringAVX.h b/src/sfizz/effects/impl/ResonantStringAVX.h index 4bcc1ec7..91c8ebde 100644 --- a/src/sfizz/effects/impl/ResonantStringAVX.h +++ b/src/sfizz/effects/impl/ResonantStringAVX.h @@ -33,19 +33,19 @@ public: __m256 process(__m256 input); private: - __m256 fConst0 {}; - __m256 fConst1 {}; - __m256 fRec0[2] {}; - __m256 fConst2 {}; - __m256 fConst3 {}; - __m256 fConst4 {}; - __m256 fConst5 {}; - __m256 fConst6 {}; - __m256 fConst7 {}; - __m256 fConst8 {}; - __m256 fRec2[3] {}; - __m256 fRec1[2] {}; - __m256 fControl[18] {}; + __m256 fConst0; + __m256 fConst1; + __m256 fRec0[2]; + __m256 fConst2; + __m256 fConst3; + __m256 fConst4; + __m256 fConst5; + __m256 fConst6; + __m256 fConst7; + __m256 fConst8; + __m256 fRec2[3]; + __m256 fRec1[2]; + __m256 fControl[18]; }; } // namespace sfz diff --git a/src/sfizz/effects/impl/ResonantStringSSE.h b/src/sfizz/effects/impl/ResonantStringSSE.h index ca32b5e2..269b14c9 100644 --- a/src/sfizz/effects/impl/ResonantStringSSE.h +++ b/src/sfizz/effects/impl/ResonantStringSSE.h @@ -33,19 +33,19 @@ public: __m128 process(__m128 input); private: - __m128 fConst0 {}; - __m128 fConst1 {}; - __m128 fRec0[2] {}; - __m128 fConst2 {}; - __m128 fConst3 {}; - __m128 fConst4 {}; - __m128 fConst5 {}; - __m128 fConst6 {}; - __m128 fConst7 {}; - __m128 fConst8 {}; - __m128 fRec2[3] {}; - __m128 fRec1[2] {}; - __m128 fControl[18] {}; + __m128 fConst0; + __m128 fConst1; + __m128 fRec0[2]; + __m128 fConst2; + __m128 fConst3; + __m128 fConst4; + __m128 fConst5; + __m128 fConst6; + __m128 fConst7; + __m128 fConst8; + __m128 fRec2[3]; + __m128 fRec1[2]; + __m128 fControl[18]; }; } // namespace sfz From bb826e8347572a583e7eaeb94fe26e5f21a8de0d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:21:10 +0200 Subject: [PATCH 08/16] Raise an error if misalignment is detected --- src/sfizz/effects/impl/ResonantStringAVX.cpp | 6 +++++- src/sfizz/effects/impl/ResonantStringSSE.cpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sfizz/effects/impl/ResonantStringAVX.cpp b/src/sfizz/effects/impl/ResonantStringAVX.cpp index e1819b52..e3f0275c 100644 --- a/src/sfizz/effects/impl/ResonantStringAVX.cpp +++ b/src/sfizz/effects/impl/ResonantStringAVX.cpp @@ -19,7 +19,8 @@ Compilation options: -lang cpp -inpl -os -scal -ftz 0 #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 #include #include -#include +#include +#include namespace sfz { namespace fx { @@ -46,6 +47,9 @@ static void store_nth_v(__m256 &x, unsigned i, float v) void ResonantStringAVX::init(float sample_rate) { + if (reinterpret_cast(this) & 31) + throw std::runtime_error("The resonant string is misaligned for AVX"); + fConst0 = _mm256_set1_ps(sample_rate); fConst1 = _mm256_div_ps(_mm256_set1_ps(6.28318548f), fConst0); fConst2 = _mm256_div_ps(_mm256_set1_ps(2.0f), fConst0); diff --git a/src/sfizz/effects/impl/ResonantStringSSE.cpp b/src/sfizz/effects/impl/ResonantStringSSE.cpp index df802d48..95109cc2 100644 --- a/src/sfizz/effects/impl/ResonantStringSSE.cpp +++ b/src/sfizz/effects/impl/ResonantStringSSE.cpp @@ -19,7 +19,8 @@ Compilation options: -lang cpp -inpl -os -scal -ftz 0 #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 #include #include -#include +#include +#include namespace sfz { namespace fx { @@ -46,6 +47,9 @@ static void store_nth_v(__m128 &x, unsigned i, float v) void ResonantStringSSE::init(float sample_rate) { + if (reinterpret_cast(this) & 31) + throw std::runtime_error("The resonant string is misaligned for SSE"); + fConst0 = _mm_set1_ps(sample_rate); fConst1 = _mm_div_ps(_mm_set1_ps(6.28318548f), fConst0); fConst2 = _mm_div_ps(_mm_set1_ps(2.0f), fConst0); From 62012f25a906d080467e87a0c9557ebffeb3a521 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:32:53 +0200 Subject: [PATCH 09/16] Relaxed the restrictions on the Buffer class --- src/sfizz/Buffer.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Buffer.h b/src/sfizz/Buffer.h index 35779eab..c48372bc 100644 --- a/src/sfizz/Buffer.h +++ b/src/sfizz/Buffer.h @@ -281,9 +281,10 @@ private: static constexpr int AlignmentMask { Alignment - 1 }; static constexpr int TypeAlignment { Alignment / sizeof(value_type) }; static constexpr int TypeAlignmentMask { TypeAlignment - 1 }; - static_assert(std::is_arithmetic::value, "Type should be arithmetic"); + static_assert(std::is_trivial::value, "Type should be trivial"); static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16 || Alignment == 32, "Bad alignment value"); - static_assert(TypeAlignment * sizeof(value_type) == Alignment, "The alignment does not appear to be divided by the size of the Type"); + static_assert(TypeAlignment * sizeof(value_type) == Alignment || !std::is_arithmetic::value, + "The alignment does not appear to be divided by the size of the arithmetic Type"); void* align(std::size_t alignment, std::size_t size, void *&ptr, std::size_t &space ) { std::uintptr_t pn = reinterpret_cast< std::uintptr_t>( ptr ); From f32f14dfa258618753ee83990b3523426e245e7e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:34:21 +0200 Subject: [PATCH 10/16] Little oopsie --- src/sfizz/effects/impl/ResonantStringSSE.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/effects/impl/ResonantStringSSE.cpp b/src/sfizz/effects/impl/ResonantStringSSE.cpp index 95109cc2..6e02d730 100644 --- a/src/sfizz/effects/impl/ResonantStringSSE.cpp +++ b/src/sfizz/effects/impl/ResonantStringSSE.cpp @@ -47,7 +47,7 @@ static void store_nth_v(__m128 &x, unsigned i, float v) void ResonantStringSSE::init(float sample_rate) { - if (reinterpret_cast(this) & 31) + if (reinterpret_cast(this) & 15) throw std::runtime_error("The resonant string is misaligned for SSE"); fConst0 = _mm_set1_ps(sample_rate); From bcb0c91599e99b10f8eb3b8955e23cb694d1e612 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:35:21 +0200 Subject: [PATCH 11/16] Fix the alignment problem --- src/sfizz/effects/impl/ResonantArrayAVX.cpp | 13 ++++++------- src/sfizz/effects/impl/ResonantArrayAVX.h | 5 ++--- src/sfizz/effects/impl/ResonantArraySSE.cpp | 9 ++++----- src/sfizz/effects/impl/ResonantArraySSE.h | 5 ++--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.cpp b/src/sfizz/effects/impl/ResonantArrayAVX.cpp index a427375c..40ac0df3 100644 --- a/src/sfizz/effects/impl/ResonantArrayAVX.cpp +++ b/src/sfizz/effects/impl/ResonantArrayAVX.cpp @@ -5,7 +5,6 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "ResonantArrayAVX.h" -#include "ResonantStringAVX.h" #include "Config.h" #include @@ -30,9 +29,9 @@ void ResonantArrayAVX::setup( const float feedbacks[], const float gains[]) { const unsigned numStringPacks = (numStrings + avxVectorSize - 1) / avxVectorSize; - ResonantStringAVX* stringPacks = new ResonantStringAVX[numStringPacks]; + _stringPacks.resize(numStringPacks); + ResonantStringAVX* stringPacks = _stringPacks.data(); - _stringPacks.reset(stringPacks); _numStrings = numStrings; for (unsigned p = 0; p < numStringPacks; ++p) { @@ -65,18 +64,18 @@ void ResonantArrayAVX::setSamplesPerBlock(unsigned samplesPerBlock) void ResonantArrayAVX::clear() { - ResonantStringAVX* stringPacks = _stringPacks.get(); + ResonantStringAVX* stringPacks = _stringPacks.data(); const unsigned numStringPacks = (_numStrings + avxVectorSize - 1) / avxVectorSize; for (unsigned p = 0; p < numStringPacks; ++p) { - ResonantStringAVX& rs = stringPacks[p]; + ResonantStringAVX& rs = reinterpret_cast(stringPacks[p]); rs.clear(); } } void ResonantArrayAVX::process(const float *inPtr, float *outPtr, unsigned numFrames) { - ResonantStringAVX* stringPacks = _stringPacks.get(); + ResonantStringAVX* stringPacks = _stringPacks.data(); const unsigned numStringPacks = (_numStrings + avxVectorSize - 1) / avxVectorSize; // receive 8 resonator outputs per pack @@ -84,7 +83,7 @@ void ResonantArrayAVX::process(const float *inPtr, float *outPtr, unsigned numFr std::memset(outputs8, 0, numFrames * sizeof(__m256)); for (unsigned p = 0; p < numStringPacks; ++p) { - ResonantStringAVX& rs = stringPacks[p]; + ResonantStringAVX& rs = reinterpret_cast(stringPacks[p]); for (unsigned i = 0; i < numFrames; ++i) outputs8[i] = _mm256_add_ps( outputs8[i], rs.process(_mm256_broadcast_ss(&inPtr[i]))); diff --git a/src/sfizz/effects/impl/ResonantArrayAVX.h b/src/sfizz/effects/impl/ResonantArrayAVX.h index 93dca2e2..a35b3346 100644 --- a/src/sfizz/effects/impl/ResonantArrayAVX.h +++ b/src/sfizz/effects/impl/ResonantArrayAVX.h @@ -6,6 +6,7 @@ #pragma once #include "ResonantArray.h" +#include "ResonantStringAVX.h" #include "Buffer.h" #include "SIMDConfig.h" @@ -13,8 +14,6 @@ namespace sfz { namespace fx { -class ResonantStringAVX; - class ResonantArrayAVX final : public ResonantArray { public: ResonantArrayAVX(); @@ -32,7 +31,7 @@ public: void process(const float *inPtr, float *outPtr, unsigned numFrames) override; private: - std::unique_ptr _stringPacks; + Buffer _stringPacks; unsigned _numStrings = 0; Buffer _workBuffer; }; diff --git a/src/sfizz/effects/impl/ResonantArraySSE.cpp b/src/sfizz/effects/impl/ResonantArraySSE.cpp index 7480a877..b72f989c 100644 --- a/src/sfizz/effects/impl/ResonantArraySSE.cpp +++ b/src/sfizz/effects/impl/ResonantArraySSE.cpp @@ -5,7 +5,6 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "ResonantArraySSE.h" -#include "ResonantStringSSE.h" #include "Config.h" #include @@ -30,9 +29,9 @@ void ResonantArraySSE::setup( const float feedbacks[], const float gains[]) { const unsigned numStringPacks = (numStrings + sseVectorSize - 1) / sseVectorSize; - ResonantStringSSE* stringPacks = new ResonantStringSSE[numStringPacks]; + _stringPacks.resize(numStringPacks); + ResonantStringSSE* stringPacks = _stringPacks.data(); - _stringPacks.reset(stringPacks); _numStrings = numStrings; for (unsigned p = 0; p < numStringPacks; ++p) { @@ -65,7 +64,7 @@ void ResonantArraySSE::setSamplesPerBlock(unsigned samplesPerBlock) void ResonantArraySSE::clear() { - ResonantStringSSE* stringPacks = _stringPacks.get(); + ResonantStringSSE* stringPacks = _stringPacks.data(); const unsigned numStringPacks = (_numStrings + sseVectorSize - 1) / sseVectorSize; for (unsigned p = 0; p < numStringPacks; ++p) { @@ -76,7 +75,7 @@ void ResonantArraySSE::clear() void ResonantArraySSE::process(const float *inPtr, float *outPtr, unsigned numFrames) { - ResonantStringSSE* stringPacks = _stringPacks.get(); + ResonantStringSSE* stringPacks = _stringPacks.data(); const unsigned numStringPacks = (_numStrings + sseVectorSize - 1) / sseVectorSize; // receive 4 resonator outputs per pack diff --git a/src/sfizz/effects/impl/ResonantArraySSE.h b/src/sfizz/effects/impl/ResonantArraySSE.h index 36a67579..f5082f4b 100644 --- a/src/sfizz/effects/impl/ResonantArraySSE.h +++ b/src/sfizz/effects/impl/ResonantArraySSE.h @@ -6,6 +6,7 @@ #pragma once #include "ResonantArray.h" +#include "ResonantStringSSE.h" #include "Buffer.h" #include "SIMDConfig.h" @@ -13,8 +14,6 @@ namespace sfz { namespace fx { -class ResonantStringSSE; - class ResonantArraySSE final : public ResonantArray { public: ResonantArraySSE(); @@ -32,7 +31,7 @@ public: void process(const float *inPtr, float *outPtr, unsigned numFrames) override; private: - std::unique_ptr _stringPacks; + Buffer _stringPacks; unsigned _numStrings = 0; Buffer _workBuffer; }; From 5ad260e4c48cba81d23c4469fb64e63f954b8dfc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:36:38 +0200 Subject: [PATCH 12/16] Make the string benchmark compute less --- benchmarks/BM_stringResonator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/BM_stringResonator.cpp b/benchmarks/BM_stringResonator.cpp index 2ddbaa6b..713c61bf 100644 --- a/benchmarks/BM_stringResonator.cpp +++ b/benchmarks/BM_stringResonator.cpp @@ -50,7 +50,7 @@ public: } static constexpr float sampleRate = 44100; - static constexpr unsigned numFrames = sampleRate * 5.0; + static constexpr unsigned numFrames = sampleRate * 1.0; std::vector input; std::vector output; unsigned numStrings = 0; From 773e1542a0760f12cf8c36a4c2f28f1a5bfcc64e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:37:55 +0200 Subject: [PATCH 13/16] Eliminate the unnecessary allocation --- src/sfizz/effects/Strings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index e3f8bcc9..db48ca77 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -30,7 +30,6 @@ namespace sfz { namespace fx { Strings::Strings() - : _stringsArray(new ResonantArrayScalar) { ResonantArray* array = nullptr; From 9d9fec27ffae2e0623bd322e899c01db1e3615bb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 15:53:46 +0200 Subject: [PATCH 14/16] Forgot to rename the strings benchmark --- benchmarks/BM_stringResonator.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/benchmarks/BM_stringResonator.cpp b/benchmarks/BM_stringResonator.cpp index 713c61bf..1d779321 100644 --- a/benchmarks/BM_stringResonator.cpp +++ b/benchmarks/BM_stringResonator.cpp @@ -15,7 +15,7 @@ #include #include -class AddArray : public benchmark::Fixture { +class StringResonator : public benchmark::Fixture { public: void SetUp(const ::benchmark::State& state) { std::random_device rd { }; @@ -60,7 +60,7 @@ public: std::vector gains; }; -BENCHMARK_DEFINE_F(AddArray, StringResonator_Scalar)(benchmark::State& state) { +BENCHMARK_DEFINE_F(StringResonator, StringResonator_Scalar)(benchmark::State& state) { ScopedFTZ ftz; sfz::fx::ResonantArrayScalar resonator; resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); @@ -72,7 +72,7 @@ BENCHMARK_DEFINE_F(AddArray, StringResonator_Scalar)(benchmark::State& state) { } #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 -BENCHMARK_DEFINE_F(AddArray, StringResonator_SSE)(benchmark::State& state) { +BENCHMARK_DEFINE_F(StringResonator, StringResonator_SSE)(benchmark::State& state) { ScopedFTZ ftz; sfz::fx::ResonantArraySSE resonator; resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); @@ -83,7 +83,7 @@ BENCHMARK_DEFINE_F(AddArray, StringResonator_SSE)(benchmark::State& state) { } } -BENCHMARK_DEFINE_F(AddArray, StringResonator_AVX)(benchmark::State& state) { +BENCHMARK_DEFINE_F(StringResonator, StringResonator_AVX)(benchmark::State& state) { ScopedFTZ ftz; sfz::fx::ResonantArrayAVX resonator; resonator.setup(sampleRate, numStrings, pitches.data(), bandwidths.data(), feedbacks.data(), gains.data()); @@ -95,9 +95,9 @@ BENCHMARK_DEFINE_F(AddArray, StringResonator_AVX)(benchmark::State& state) { } #endif -BENCHMARK_REGISTER_F(AddArray, StringResonator_Scalar)->RangeMultiplier(4)->Range(1, 128); +BENCHMARK_REGISTER_F(StringResonator, StringResonator_Scalar)->RangeMultiplier(4)->Range(1, 128); #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 -BENCHMARK_REGISTER_F(AddArray, StringResonator_SSE)->RangeMultiplier(4)->Range(1, 128); -BENCHMARK_REGISTER_F(AddArray, StringResonator_AVX)->RangeMultiplier(4)->Range(1, 128); +BENCHMARK_REGISTER_F(StringResonator, StringResonator_SSE)->RangeMultiplier(4)->Range(1, 128); +BENCHMARK_REGISTER_F(StringResonator, StringResonator_AVX)->RangeMultiplier(4)->Range(1, 128); #endif BENCHMARK_MAIN(); From 3ed8c4f7719899217dddf9e2ce70d4943a66e499 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 16:30:37 +0200 Subject: [PATCH 15/16] Print the system processor in summary --- cmake/SfizzConfig.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 76aea885..ccd52103 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -86,6 +86,7 @@ function (show_build_info_if_needed) message (STATUS " Project name: ${PROJECT_NAME} Build type: ${CMAKE_BUILD_TYPE} +Build processor: ${SFIZZ_SYSTEM_PROCESSOR} Build using LTO: ${ENABLE_LTO} Build as shared library: ${SFIZZ_SHARED} Build JACK stand-alone client: ${SFIZZ_JACK} From 8ce71cafad5353b21dcc8c309a15b205d6989f48 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 2 Apr 2020 16:53:55 +0200 Subject: [PATCH 16/16] Attempt to fix MOD devices --- .travis/script_moddevices.sh | 4 +++- cmake/SfizzConfig.cmake | 10 ++++++---- cmake/VSTConfig.cmake | 9 ++------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.travis/script_moddevices.sh b/.travis/script_moddevices.sh index 7b074e15..d36b982c 100755 --- a/.travis/script_moddevices.sh +++ b/.travis/script_moddevices.sh @@ -5,5 +5,7 @@ set -ex mkdir -p build/${INSTALL_DIR} && cd build -buildenv mod-plugin-builder /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF .. +buildenv mod-plugin-builder /usr/local/bin/cmake \ + -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF .. buildenv mod-plugin-builder make -j diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index ccd52103..bbf9f43e 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -18,10 +18,12 @@ endif() # The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... # see https://gitlab.kitware.com/cmake/cmake/issues/15170 -if(MSVC) - set(SFIZZ_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") -else() - set(SFIZZ_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") +if (NOT SFIZZ_SYSTEM_PROCESSOR) + if(MSVC) + set(SFIZZ_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") + else() + set(SFIZZ_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") + endif() endif() # Add required flags for the builds diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index afa29779..02ec9137 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -11,13 +11,8 @@ else() "Install destination for VST bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/vst3}]") endif() -# The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... -# see https://gitlab.kitware.com/cmake/cmake/issues/15170 - -if(MSVC) - set(VST3_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") -else() - set(VST3_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") +if (NOT VST3_SYSTEM_PROCESSOR) + set(VST3_SYSTEM_PROCESSOR "${SFIZZ_SYSTEM_PROCESSOR}") endif() message(STATUS "The system architecture is: ${VST3_SYSTEM_PROCESSOR}")