SIMD-accelerated strings effect

This commit is contained in:
Jean Pierre Cimalando 2020-04-01 18:42:41 +02:00
parent 3aaf44b636
commit 026a5aceee
22 changed files with 1045 additions and 240 deletions

View file

@ -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

View file

@ -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$<$<CONFIG:Debug>: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)

View file

@ -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()

View file

@ -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)

View file

@ -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>::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 )
{

View file

@ -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

View file

@ -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<float, 4> 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<float>(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<float> 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<float> 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);

View file

@ -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<ResonantString[]> _strings;
std::unique_ptr<ResonantArray> _stringsArray;
AudioBuffer<float, 3> _tempBuffer { 3, config::defaultSamplesPerBlock };
};

View file

@ -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 <cmath>
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

View file

@ -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);

View file

@ -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

View file

@ -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 <memory>
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<ResonantString[]> _strings;
unsigned _numStrings = 0;
};
} // namespace sfz
} // namespace fx

View file

@ -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 <cstring>
#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

View file

@ -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<ResonantStringAVX[]> _stringPacks;
unsigned _numStrings = 0;
Buffer<float, 32> _workBuffer;
};
} // namespace sfz
} // namespace fx
#endif

View file

@ -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 <cstring>
#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

View file

@ -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<ResonantStringSSE[]> _stringPacks;
unsigned _numStrings = 0;
Buffer<float, 16> _workBuffer;
};
} // namespace sfz
} // namespace fx
#endif

View file

@ -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 <algorithm>
#include <cmath>
#include <math.h>
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

View file

@ -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

View file

@ -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 <algorithm>
#include <cmath>
#include <math.h>
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<const float *>(&x)[i];
}
static void store_nth_v(__m256 &x, unsigned i, float v)
{
reinterpret_cast<float *>(&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

View file

@ -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

View file

@ -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 <algorithm>
#include <cmath>
#include <math.h>
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<const float *>(&x)[i];
}
static void store_nth_v(__m128 &x, unsigned i, float v)
{
reinterpret_cast<float *>(&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

View file

@ -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