Home

Awesome

Melatonin Parameters

A very basic C++ JUCE module that contains

  1. A logarithmic NormalizableRange "factory" that accepts an exponent value to toy with the amount of skew.
  2. stringFromTimeValue and timeValueFromString helpers for parameters that behave in a user-friendly way.
  3. Tests for the above written in Catch2.

These are the parameter behaviors I want by default. Having something like this in JUCE proper probably makes sense.

How to use

If you are a solo coder using Projucer, you could git clone and then manually add this module your project via the UI.

I'm not a fan of copying and pasting dependencies (IMO that's one of reasons we can't have nice things in C++). Assuming you use git and want/have modules in a modules folder in your project, this will set you up with a git submodule tracking the main branch:

git submodule add -b main https://github.com/sudara/melatonin_parameters modules/melatonin_parameters
git commit -m "Added melatonin_parameters submodule."

When you want to update melatonin_parameters, you can now run

git submodule update --remote --merge modules/melatonin_parameters

If you use CMake, you can inform JUCE about the module in your CMakeLists.txt:

juce_add_module("modules/melatonin_parameters")

zzzzzz.... Wake me up when C++ has widely supported package management plzthxbai.

Running tests

Catch2 tests are in melatonin_parameters.cpp surrounded by if RUN_MELATONIN_TESTS

Assuming you use CMake:

  1. Have Catch2 setup in your project. See pamplejuce.

  2. Add the module as above

  3. Add the preprocessor flag to the test binary with:

target_compile_definitions(Tests PRIVATE RUN_MELATONIN_TESTS=1)

where Tests is the name of your test binary.

Logarithmic Range

It has a default exponent setting of 6:

juce::AudioParameterFloat ("release", "Release", logarithmicRange (0, 15.0f), 0.1f),

A custom exponent of 10 might be a sensible value for frequency:

juce::AudioParameterFloat ("frequency", "Frequency", logarithmicRange (20.0f, 20000.0f, 10.0f), 0.1f),

Reversed Logarithmic Range

When you want the slider to be reversed in direction. The arguments are still in the same order, lowest possibility first.

juce::AudioParameterFloat ("release", "Release", reversedLogarithmicRange (0, 15.0f), 0.1f),

Why

Auditory perception of time and frequency is logarithmic, so it's a good default for many knobs in audio.

Imagine a release knob. The first little bit of the knob, you'd probably want some fine control over 0-100ms to craft short release times. Maybe by the time you get to the middle of the knob it's at 1s. And then the rest of the knob can handle 1-10s, where granularity is much less important.

Implementation

Screenshot 2021-04-08 Linear to logarithmic range conversion - Safari

The math can be viewed at this desmos link.

<details>

Github can't render latex, but here's the latex formulas in case the desmos link goes away.

From a normalized 0-1 to an unnormalized y0 to y1:

y_{0}\ +\frac{2^{kx}-1}{2^{k}-1}\left(y_{1}-y_{0}\right)

To a normalized 0-1 from an unnormalized y0 to y1

\frac{\log_{2}\left(\frac{x-y_{0}}{y_{1}-y_{0}}\left(2^{k}-1\right)+1\right)}{k}
</details>

Understanding the math is a bit of a pain, but the core idea is to be able to translate to and from any logarithmic range to JUCE's normalized 0-1 range.

See the references for more detail. Other solutions I ran into had oddities such as not allowing the logarithmic minimum to be 0 (as it would result in division by 0).

I went back to the math to cook up something that I could understand, where the range could start at 0, and where the exponential-ness (skew) and starting positions could be adjusted.

stringFromTimeValue and timeValueFromString

How to use

juce::AudioParameterFloat> ("delay", "Delay", logarithmicRange(0.0f, 1.0f), 0.0f, juce::String(), juce::AudioProcessorParameter::genericParameter, stringFromTimeValue, timeValueFromString)

Why?

In JUCE, parameters don't "know" what units they are nor how to display them. Even though most plugins will have similar values such as frequency and time and "note value", the formatting display of those values is up to the user; there are no out of the box defaults.

stringFromTimeValue Implementation

This is is optimized for normal person usability, not for accuracy.

  1. Under 0.5s, values are displayed as ms with NO decimal places. It will look like 1ms, 5ms, etc.
  2. Excess 0s are removed. 1.00 is displayed as 1s
  3. A max of two digits after the decimal place. 1.111 will display as 1.11.

timeValueFromString Implementation

  1. Values can be with or without decimal

  2. ms and s are accepted as units: 0ms, 11.1ms, 100ms, 1.0s, 15.98s are all valid.

  3. Without a unit, single digits or a decimal place will trigger seconds conversion: 1 or 1. or 1.0

  4. Without a unit, double and triple digits convert to ms.

See the tests for more detail.

References

TODO