Skip to content

A C++ library for defining and evaluating piecewise functions, inspired by the Web Audio API AudioParam interface.

License

Notifications You must be signed in to change notification settings

nativeformat/NFParam

Repository files navigation

NFParam

CircleCI License Spotify FOSS Slack Readme Score

A C++ library for defining and evaluating piecewise functions, inspired by the Web Audio API AudioParam interface.

Platform support

NFParam should compile and run on any platform with a C++11 compiler, but the following are tested in CI.

  • 📱 iOS 9.0+
  • 💻 OS X 10.11+
  • 🐧 Ubuntu Trusty 14.04+ (clang 3.9 or gcc 4.9)

Developed at Spotify 2019-2022, Discontinued and handed over to new maintainers January 2023

Raison D'être 💭

When designing a cross platform player that could be used for complex mixing and effects, we required a library that worked in the same way that the Web Audio API AudioParam worked but on none web based platforms. This led to the creation of this library, which is not only able to emulate the AudioParam library but can also handle seeks into the centre of a function being evaluated due to its architecture not being a state machine. In addition to supporting everything AudioParam supports, we have also added in some extra goodies such as smoothedValueForTimeRange and cumulativeValueForTimeRange.

Architecture 📐

NFParam is designed as a C++11 interface to define a control curve and interact with it in real time. The API allows you to create a parameter and then begin to add control curves to execute at specific times. The library is thread safe and can be written or read from any thread. The system works by having a list of events, doing a binary search on that list to find the correct function to execute, then executing that function on the current time being requested.

Installation

CMake 3.5 or later is required to generate the build.

brew install cmake

or

sudo apt-get install cmake

NFParam is a CMake project, so to use it within a larger CMake project, simply add the following line to your CMakeLists.txt file:

add_subdirectory(NFParam)

Alternatively, you can compile NFParam as a standalone library. The ci build scripts can be used to install all necessary dependencies, build the library, and run unit tests.

For Linux

sh ci/linux.sh build

For iOS/OSX

sh ci/osx.sh build

Examples

Create the "Audio Param Example" curve pictured below

Create the Param

Specify the default value, min, max, and a name. Until events are added, its value will be the default value for all times.

auto p = nativeformat::param::createParam(0, 1, -1, "testParam");

Add some events

The setValueAtTime command behaves as a step function. The value specified will be maintained until the next event anchor.

p->setValueAtTime(0.2f, 0.0);
p->setValueAtTime(0.3f, 0.1);
p->setValueAtTime(0.4f, 0.2);

The linearRampToValueAtTime event computes the slope necessary to reach the target value from the previous anchor point by the specified time.

p->linearRampToValueAtTime(1.0f, 0.3);
p->linearRampToValueAtTime(0.8f, 0.325);

The setTargetAtTime command will expoenentially approach the target value from the previous anchor with a rate specified by the time constant. It does not have a fixed end time.

p->setTargetAtTime(0.5f, 0.325, time_constant);
p->setValueAtTime(0.552f, 0.5);

The exponentialRampToValueAtTime event computes the constant necessary to reach the target value from the previous anchor point by the specified time.

p->exponentialRampToValueAtTime(0.75f, 0.6);
p->exponentialRampToValueAtTime(0.05f, 0.7);

The setValueCurveAtTime event linearly interpolates between the points provided on the user-defined curve. It cannot overlap with any other command anchors.

size_t curve_len = 44100;
std::vector<float> curve(curve_len);
for (int i = 0; i < curve_len; ++i) {
  curve[i] = std::sin((3.14159265 * i) / curve_len);
}
p->setValueCurveAtTime(curve, 0.7, 0.3);

Retrieve some values from the Param

Finally, let's sample some values from the param we have defined!

size_t points = 1001;
std::vector<float> x(points), y(points);
p->valuesForTimeRange(y.data(), points, 0.0, 1.0);

double ts = 1.0 / (points - 1);
double t = 0;
for (int i = 0; i < x.size(); ++i) {
  x[i] = t;
  t += ts;
}

Tests

NFParamTests.cpp contains a number of test cases, two of which generate TSV output files that should match the AudioParam automation example from the WAA spec. In the resources directory, there is a script that will plot the unit test output data if you have gnuplot installed. The path where paramAutomation.txt is generated when the tests are run by the ci scripts varies by platform.

Generating a plot

sh plot.sh ../build/source/test/Debug/paramAutomation.txt out.png

Contributing 📬

Contributions are welcomed, have a look at the CONTRIBUTING.md document for more information.

License 📝

The project is available under the Apache 2.0 license.

Acknowledgements

  • Icon in readme banner is “Settings” by Bharat from the Noun Project.

Contributors

About

A C++ library for defining and evaluating piecewise functions, inspired by the Web Audio API AudioParam interface.

Resources

License

Stars

Watchers

Forks

Packages

No packages published