Skip to content

Commit

Permalink
Concepts Usage, Exploration One (#101)
Browse files Browse the repository at this point in the history
Add some code concepts for types and strategies we've used
throughout the codebase for common APIs like sample rate, ote
to pitch, db to linear.

rather than using this commit to consilidate all the names of
all the clients, use this to enumerate all of them into a concept
and start using that concept. Once we've propagated that, we can
quickly and easily see where we need to consolidate names with
the compiler.
  • Loading branch information
baconpaul authored May 28, 2024
1 parent e717204 commit e7504e4
Show file tree
Hide file tree
Showing 5 changed files with 388 additions and 6 deletions.
9 changes: 9 additions & 0 deletions include/sst/basic-blocks/concepts/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,26 @@
#ifndef INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_CONCEPTS_H
#define INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_CONCEPTS_H

#include <concepts>
#include <type_traits>

// Why this form? gcc10 works but provides -std=c++2a in some cases
static_assert(__cplusplus > 201703L, "sst-basic-blocks requires C++20; please update your build");

#include "sample_rate.h"
#include "envelope_modulator_rate.h"
#include "unit_conversions.h"

namespace sst::basic_blocks::concepts
{
template <class T> constexpr bool is_positive_power_of_two(T x) noexcept
{
return (x > 0) && ((x & (x - 1)) == 0) && std::is_integral_v<T>;
}
template <class T> constexpr bool is_power_of_two_ge(T x, T above) noexcept
{
return (x > 0) && ((x & (x - 1)) == 0) && std::is_integral_v<T>;
}
} // namespace sst::basic_blocks::concepts

#endif // SURGE_CONCEPTS_H
58 changes: 58 additions & 0 deletions include/sst/basic-blocks/concepts/envelope_modulator_rate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_ENVELOPE_MODULATOR_RATE_H
#define INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_ENVELOPE_MODULATOR_RATE_H

#include <concepts>
#include <type_traits>

namespace sst::basic_blocks::concepts
{

/*
* Envelope Rate Linear No-Wrap is defined as
* block size * 2^f / sample rate
*/
template <typename T>
concept has_envelope_rate_linear_nowrap = requires(T *t, float f) {
{
t->envelope_rate_linear_nowrap(f)
} -> std::convertible_to<float>;
};

template <typename T>
concept providesModulatorDPhase = has_envelope_rate_linear_nowrap<T>;

template <typename T>
requires(providesModulatorDPhase<T>)
inline double getModulatorDPhase(T *t, float f)
{
return t->envelope_rate_linear_nowrap(f);
}
} // namespace sst::basic_blocks::concepts

#endif // SHORTCIRCUITXT_ENVELOPE_MODULATOR_RATE_H
155 changes: 155 additions & 0 deletions include/sst/basic-blocks/concepts/sample_rate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* 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 INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_SAMPLE_RATE_H
#define INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_SAMPLE_RATE_H

#include <concepts>
#include <type_traits>

namespace sst::basic_blocks::concepts
{
template <typename T>
concept has_samplerate_member = requires(T *t) {
{
t->samplerate
} -> std::convertible_to<float>;
};

template <typename T>
concept has_sampleRate_member = requires(T *t) {
{
t->sampleRate
} -> std::convertible_to<float>;
};

template <typename T>
concept has_getSampleRate_method = requires(T *t) {
{
t->getSampleRate()
} -> std::convertible_to<float>;
};

template <typename T>
concept has_staticGetSampleRate_method = requires(T *t) {
{
T::getSampleRate(t)
} -> std::convertible_to<float>;
};

template <typename T>
concept has_dsamplerate_member = requires(T *t) {
{
t->dsamplerate
} -> std::same_as<double>;
};

template <typename T>
concept has_samplerate_inv_member = requires(T *t) {
{
t->samplerate_inv
} -> std::convertible_to<float>;
};

template <typename T>
concept has_sampleRateInv_member = requires(T *t) {
{
t->sampleRateInv
} -> std::convertible_to<float>;
};

template <typename T>
concept has_getSampleRateInv_method = requires(T *t) {
{
t->getSampleRateInv()
} -> std::convertible_to<float>;
};

template <typename T>
concept has_dsamplerate_inv_member = requires(T *t) {
{
t->dsamplerate_inv
} -> std::same_as<double>;
};

template <typename T>
concept has_staticGetSampleRateInv_method = requires(T *s) {
{
T::getSampleRateInv(s)
} -> std::floating_point;
};

template <typename T>
concept has_staticSampleRateInv_method = requires(T *s) {
{
T::sampleRateInv(s)
} -> std::floating_point;
};
template <typename T>
concept supportsSampleRate = has_samplerate_member<T> || has_sampleRate_member<T> ||
has_getSampleRate_method<T> || has_staticGetSampleRate_method<T>;

template <typename T>
concept supportsSampleRateInv =
has_samplerate_inv_member<T> || has_sampleRateInv_member<T> || has_getSampleRateInv_method<T> ||
has_staticGetSampleRateInv_method<T> || has_staticSampleRateInv_method<T>;

template <typename T>
concept supportsDoubleSampleRate = has_dsamplerate_member<T> && has_dsamplerate_inv_member<T>;

template <typename T>
inline float getSampleRate(T *t)
requires(supportsSampleRate<T>)
{
if constexpr (has_samplerate_member<T>)
return t->samplerate;
else if constexpr (has_sampleRate_member<T>)
return t->sampleRate;
else if constexpr (has_getSampleRate_method<T>)
return t->getSampleRate();
else if constexpr (has_staticGetSampleRate_method<T>)
return T::getSampleRate(t);
}

template <typename T>
inline float getSampleRateInv(T *t)
requires(supportsSampleRateInv<T>)
{
if constexpr (has_samplerate_inv_member<T>)
return t->samplerate_inv;
else if constexpr (has_sampleRateInv_member<T>)
return t->sampleRateInv;
else if constexpr (has_getSampleRateInv_method<T>)
return t->getSampleRateInv();
else if constexpr (has_staticGetSampleRateInv_method<T>)
return T::getSampleRateInv(t);
else if constexpr (has_staticSampleRateInv_method<T>)
return T::sampleRateInv(t);
}

} // namespace sst::basic_blocks::concepts

#endif // SHORTCIRCUITXT_SAMPLE_RATE_H
157 changes: 157 additions & 0 deletions include/sst/basic-blocks/concepts/unit_conversions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* 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 INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_UNIT_CONVERSIONS_H
#define INCLUDE_SST_BASIC_BLOCKS_CONCEPTS_UNIT_CONVERSIONS_H

#include <concepts>
#include <type_traits>
#include <cassert>

/*
* All the names and flavorts we evern given these are here.
* We obviously need to trim these down once we have everything
* going. That's tedious but doable because we can just
* remove the constraint from the concept and the if once we
* are there.
*/
namespace sst::basic_blocks::concepts
{
template <typename T>
concept has_note_to_pitch_ignoring_tuning = requires(T *s, float f) {
{
s->note_to_pitch_ignoring_tuning(f)
} -> std::floating_point;
};

template <typename T>
concept has_noteToPitchIgnoringTuning = requires(T *s, float f) {
{
s->noteToPitchIgnoringTuning(f)
} -> std::floating_point;
};

template <typename T>
concept has_noteToPitch = requires(T *s, float f) {
{
s->noteToPitch(f)
} -> std::floating_point;
};

template <typename T>
concept has_staticNoteToPitchIgnoringTuning = requires(T *s, float f) {
{
T::noteToPitchIgnoringTuning(s, f)
} -> std::floating_point;
};

template <typename T>
concept has_staticEqualNoteToPitch = requires(T *s, float f) {
{
T::equalNoteToPitch(s, f)
} -> std::floating_point;
};

template <typename T>
concept providesNoteToPitch =
has_noteToPitchIgnoringTuning<T> || has_note_to_pitch_ignoring_tuning<T> ||
has_noteToPitch<T> || has_staticNoteToPitchIgnoringTuning<T> || has_staticEqualNoteToPitch<T>;

template <typename T>
requires(providesNoteToPitch<T>)
inline float convertNoteToPitch(T *t, float n)
{
if constexpr (has_note_to_pitch_ignoring_tuning<T>)
{
return t->note_to_pitch_ignoring_tuning(n);
}
else if constexpr (has_noteToPitchIgnoringTuning<T>)
{
return t->noteToPitchIgnoringTuning(n);
}
else if constexpr (has_noteToPitch<T>)
{
return t->noteToPitch(n);
}
else if constexpr (has_staticNoteToPitchIgnoringTuning<T>)
{
return T::noteToPitchIgnoringTuning(t, n);
}
else if constexpr (has_staticEqualNoteToPitch<T>)
{
return T::equalNoteToPitch(t, n);
}

assert(false);
return 0;
}

template <typename T>
concept has_db_to_linear = requires(T *s, float f) {
{
s->db_to_linear(f)
} -> std::floating_point;
};

template <typename T>
concept has_dbToLinear = requires(T *s, float f) {
{
s->dbToLinear(f)
} -> std::floating_point;
};

template <typename T>
concept has_staticDbToLinear = requires(T *s, float f) {
{
T::dbToLinear(s, f)
} -> std::floating_point;
};

template <typename T>
concept providesDbToLinear = has_dbToLinear<T> || has_db_to_linear<T> || has_staticDbToLinear<T>;

template <typename T>
requires(providesDbToLinear<T>)
inline float convertDbToLinear(T *t, float n)
{
if constexpr (has_db_to_linear<T>)
{
return t->db_to_linear(n);
}
else if constexpr (has_dbToLinear<T>)
{
return t->dbToLinear(n);
}
else if constexpr (has_staticDbToLinear<T>)
{
return T::dbToLinear(t, n);
}
assert(false);
return 0;
}

} // namespace sst::basic_blocks::concepts
#endif // SHORTCIRCUITXT_UNIT_CONVERSIONS_H
Loading

0 comments on commit e7504e4

Please sign in to comment.