Skip to content

Commit

Permalink
performance testing and lfo improvements (#178)
Browse files Browse the repository at this point in the history
* performance testing and lfo improvements

* Fix a header

* more missing headers in perftest
  • Loading branch information
baconpaul authored Feb 17, 2025
1 parent fe9ccff commit 89a78d0
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 21 deletions.
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ if (${SST_BASIC_BLOCKS_BUILD_TESTS})
tests/modulator_tests.cpp
tests/mod_matrix_tests.cpp
)


add_executable(sst-basic-blocks-perf-test
tests/perf/perf_test.cpp
tests/perf/lfo.cpp
)

if (NOT TARGET simde)
message(STATUS "Importing SIMDE with CPM")
CPMAddPackage(NAME simde
Expand All @@ -47,11 +54,17 @@ if (${SST_BASIC_BLOCKS_BUILD_TESTS})
target_include_directories(sst-basic-blocks-test PRIVATE
${simde_SOURCE_DIR}
tests)
target_include_directories(sst-basic-blocks-perf-test PRIVATE
${simde_SOURCE_DIR}
tests/perf)
else ()
target_link_libraries(sst-basic-blocks-test PRIVATE simde)
target_link_libraries(sst-basic-blocks-perf-test PRIVATE simde)
endif ()

target_link_libraries(sst-basic-blocks-test PRIVATE fmt ${PROJECT_NAME})
target_link_libraries(sst-basic-blocks-perf-test PRIVATE fmt ${PROJECT_NAME})

target_include_directories(sst-basic-blocks-test PRIVATE libs/catch2)

if ((DEFINED ${CMAKE_OSX_DEPLOYMENT_TARGET}) AND ("${CMAKE_OSX_DEPLOYMENT_TARGET}" VERSION_LESS "10.12"))
Expand Down
28 changes: 10 additions & 18 deletions cmake/CPM.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
set(CPM_DOWNLOAD_VERSION 0.36.0)
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors

set(CPM_DOWNLOAD_VERSION 0.40.5)
set(CPM_HASH_SUM "c46b876ae3b9f994b4f05a4c15553e0485636862064f1fcc9d8b4f832086bc5d")

if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
Expand All @@ -11,22 +16,9 @@ endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)

function(download_cpm)
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endfunction()

if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
download_cpm()
else()
# resume download if it previously failed
file(READ ${CPM_DOWNLOAD_LOCATION} check)
if("${check}" STREQUAL "")
download_cpm()
endif()
endif()
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)

include(${CPM_DOWNLOAD_LOCATION})
14 changes: 11 additions & 3 deletions include/sst/basic-blocks/modulators/SimpleLFO.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace sst::basic_blocks::modulators
{

// For context on SRProvider see the ADSRDAHD Envelope
template <typename SRProvider, int BLOCK_SIZE> struct SimpleLFO
template <typename SRProvider, int BLOCK_SIZE, bool clampDeform = false> struct SimpleLFO
{
SRProvider *srProvider{nullptr};

Expand Down Expand Up @@ -127,8 +127,10 @@ template <typename SRProvider, int BLOCK_SIZE> struct SimpleLFO
{
if (d == 0)
return x;
if constexpr (clampDeform)
d = std::clamp(d, -3.f, 3.f);
auto a = 0.5 * d;

auto a = 0.5 * std::clamp(d, -3.f, 3.f);
x = x - a * x * x + a;
x = x - a * x * x + a;
return x;
Expand Down Expand Up @@ -193,12 +195,18 @@ template <typename SRProvider, int BLOCK_SIZE> struct SimpleLFO
}
}

float lastRate{-123485924.0}, lastFRate{0};
inline void process_block(const float r, const float d, const int lshape, bool reverse = false,
float tsScale = 1.f)
{
float target{0.f};

auto frate = tsScale * srProvider->envelope_rate_linear_nowrap(-r);
auto frate = lastFRate;
if (r != lastRate)
{
frate = tsScale * srProvider->envelope_rate_linear_nowrap(-r);
lastRate = r;
}
phase += frate * (reverse ? -1 : 1);
int phaseMidpoint{0};
bool phaseTurned{false};
Expand Down
96 changes: 96 additions & 0 deletions tests/perf/lfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* sst-basic-blocks - an open source library of core audio utilities
* built by Surge Synth Team.
*
* Provides a collection of tools useful on the audio thread for blocks,
* modulation, etc... or useful for adapting code to multiple environments.
*
* Copyright 2023, various authors, as described in the GitHub
* transaction log. Parts of this code are derived from similar
* functions original in Surge or ShortCircuit.
*
* sst-basic-blocks is released under the GNU General Public Licence v3
* or later (GPL-3.0-or-later). The license is found in the "LICENSE"
* file in the root of this repository, or at
* https://www.gnu.org/licenses/gpl-3.0.en.html.
*
* A very small number of explicitly chosen header files can also be
* used in an MIT/BSD context. Please see the README.md file in this
* repo or the comments in the individual files. Only headers with an
* explicit mention that they are dual licensed may be copied and reused
* outside the GPL3 terms.
*
* All source in sst-basic-blocks available at
* https://github.com/surge-synthesizer/sst-basic-blocks
*/

#include <iostream>
#include <array>

#include "sst/basic-blocks/modulators/SimpleLFO.h"
#include "sst/basic-blocks/tables/TwoToTheXProvider.h"
#include "sst/basic-blocks/dsp/RNG.h"
#include "perfutils.h"

template <int blockSize> struct SRProvider
{
const sst::basic_blocks::tables::TwoToTheXProvider &ttx;
SRProvider(const sst::basic_blocks::tables::TwoToTheXProvider &t) : ttx(t) {}
float envelope_rate_linear_nowrap(float f) const
{
return (blockSize * sampleRateInv) * ttx.twoToThe(-f);
}

void setSampleRate(double sr)
{
samplerate = sr;
sampleRate = sr;
sampleRateInv = 1.0 / sr;
}
double samplerate{1};
double sampleRate{1};
double sampleRateInv{1};
};

template <int blockSize>
void basicTest(sst::basic_blocks::tables::TwoToTheXProvider &ttx, sst::basic_blocks::dsp::RNG &rng)
{
using srp_t = SRProvider<blockSize>;
using lfo_t = sst::basic_blocks::modulators::SimpleLFO<SRProvider<blockSize>, blockSize>;

auto srp = srp_t(ttx);
srp.setSampleRate(48000 * 2.5);

std::array<lfo_t, 8> lfos{
lfo_t(&srp, rng), lfo_t(&srp, rng), lfo_t(&srp, rng), lfo_t(&srp, rng),
lfo_t(&srp, rng), lfo_t(&srp, rng), lfo_t(&srp, rng), lfo_t(&srp, rng),
};

for (auto sh = lfo_t::SINE; sh <= lfo_t::SH_NOISE; sh = (typename lfo_t::Shape)((int)sh + 1))
for (auto def : {-0.1f, 0.f, 0.2f})
{
{
auto blocks = (int)(200 * srp.sampleRate / blockSize);
perf::TimeGuard tg("LFO - shape=" + std::to_string(sh) +
" def=" + std::to_string(def),
__FILE__, __LINE__, 248688);
for (int lf = 0; lf < lfos.size(); ++lf)
lfos[lf].attack(sh);

for (int i = 0; i < blocks; ++i)
{
for (int lf = 0; lf < lfos.size(); ++lf)
lfos[lf].process_block(2.4, def, sh, false, 1.0);
}
}
}
}

void lfoPerformance()
{
sst::basic_blocks::tables::TwoToTheXProvider ttxlfo;
sst::basic_blocks::dsp::RNG rng(782567);
ttxlfo.init();
std::cout << __FILE__ << ":" << __LINE__ << " LFO Perf starting" << std::endl;
basicTest<8>(ttxlfo, rng);
}
31 changes: 31 additions & 0 deletions tests/perf/perf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* sst-basic-blocks - an open source library of core audio utilities
* built by Surge Synth Team.
*
* Provides a collection of tools useful on the audio thread for blocks,
* modulation, etc... or useful for adapting code to multiple environments.
*
* Copyright 2023, various authors, as described in the GitHub
* transaction log. Parts of this code are derived from similar
* functions original in Surge or ShortCircuit.
*
* sst-basic-blocks is released under the GNU General Public Licence v3
* or later (GPL-3.0-or-later). The license is found in the "LICENSE"
* file in the root of this repository, or at
* https://www.gnu.org/licenses/gpl-3.0.en.html.
*
* A very small number of explicitly chosen header files can also be
* used in an MIT/BSD context. Please see the README.md file in this
* repo or the comments in the individual files. Only headers with an
* explicit mention that they are dual licensed may be copied and reused
* outside the GPL3 terms.
*
* All source in sst-basic-blocks available at
* https://github.com/surge-synthesizer/sst-basic-blocks
*/

#include <iostream>

extern void lfoPerformance();

int main(int argc, char **argv) { lfoPerformance(); }
55 changes: 55 additions & 0 deletions tests/perf/perfutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* sst-basic-blocks - an open source library of core audio utilities
* built by Surge Synth Team.
*
* Provides a collection of tools useful on the audio thread for blocks,
* modulation, etc... or useful for adapting code to multiple environments.
*
* Copyright 2023, various authors, as described in the GitHub
* transaction log. Parts of this code are derived from similar
* functions original in Surge or ShortCircuit.
*
* sst-basic-blocks is released under the GNU General Public Licence v3
* or later (GPL-3.0-or-later). The license is found in the "LICENSE"
* file in the root of this repository, or at
* https://www.gnu.org/licenses/gpl-3.0.en.html.
*
* A very small number of explicitly chosen header files can also be
* used in an MIT/BSD context. Please see the README.md file in this
* repo or the comments in the individual files. Only headers with an
* explicit mention that they are dual licensed may be copied and reused
* outside the GPL3 terms.
*
* All source in sst-basic-blocks available at
* https://github.com/surge-synthesizer/sst-basic-blocks
*/

#ifndef SST_BASIC_BLOCK_TESTS_PERF_PERFUTILS_H
#define SST_BASIC_BLOCK_TESTS_PERF_PERFUTILS_H

#include <iostream>
#include <chrono>
#include <string>

namespace perf
{
struct TimeGuard
{
std::string m;
int d;
std::chrono::high_resolution_clock::time_point t;
TimeGuard(const std::string &msg, const std::string &f, int l, int divisor = 1) : d(divisor)
{
m = f + ":" + std::to_string(l) + " " + msg;
t = std::chrono::high_resolution_clock::now();
}
~TimeGuard()
{
auto e = std::chrono::high_resolution_clock::now();
auto us = std::chrono::duration_cast<std::chrono::microseconds>(e - t).count();
std::cout << m << " " << us << " us; pct=" << 100.0 * us / d << "%" << std::endl;
}
};
}; // namespace perf

#endif

0 comments on commit 89a78d0

Please sign in to comment.