Math
The Math
class is a collection of math functions that can be used in the scripting engine. It is a feature-complete clone of the "official" Javascript Math object
.
Unless specified otherwise, the value type of the function is double
. Most of the functions are pretty self-explanatory if you managed to get through high school, but there are a few special function that deserve a more detailed explanation.
If you're going to start out with SNEX or use the expression nodes in scriptnode, you might be happy to know that this class is also available there.
In the editor the Math
keyword will also give you access to a few Math constants (PI, E).
Class methods
abs
Returns the absolute (unsigned) value.
Math.abs(var value)
Useful for inverting negative values.
acos
Calculates the acosine value (radian based).
Math.acos(var value)
Wikipedia: Inverse Trigonmetric functions
acosh
Calculates the acosh value (radian based).
Math.acosh(var value)
The hyperbolic version of acos.
asin
Calculates the asine value (radian based).
Math.asin(var value)
asinh
Calculates the asinh value (radian based).
Math.asinh(var value)
atan
Calculates the atan value (radian based).
Math.atan(var value)
atanh
Calculates the atanh value (radian based).
Math.atanh(var value)
ceil
Rounds up the value.
Math.ceil(var value)
Pushes the value up to the next full number.
cos
Calculates the cosine value (radian based).
Math.cos(var value)
Basic Trigonometric Function
. Returns 1 at 0 and -1 at PI.
cosh
Calculates the cosh value (radian based).
Math.cosh(var value)
exp
Calculates the exp value.
Math.exp(var value)
Wikipedia: Exponential function
floor
Rounds down the value.
Math.floor(var value)
Opposite of Math.ceil()
fmod
Returns the remainder when dividing value with limit.
Math.fmod(var value, var limit)
This is usually useful for two use cases:
- Get the fractional part:
Math.fmod(19.52, 1.0) == 0.52)
- Loop around a range limit:
Math.fmod(13.2, 12.0) == 1.2
Note that if you're using it for the latter use case, the function Math.wrap()
might be a better candidate as it correctly wraps around negative values too.
from0To1
Converts a normalised value (between 0 and 1) to a range defined by the JSON data in rangeObj.
Math.from0To1(var value, var rangeObj)
Converting between value ranges is a pretty common task when writing scripts. This function will scale a normalized input value from (0...1) to a given output range which allows you to switch between different domains without excessive math formula usage. The inverse process can be achieved with Math.to0to1
.
The second parameter will define a range and you can either use a JSON object or a fix object created by a FixObjectFactory . The latter will significantly improve the performance of this function because it doesn't have to look up the dynamic properties but uses a internal LUT to create the C++ range object.
A range object has up to 5 properties:
- a minimum value
- a maximum value
- a factor that skews the curve (think gamma curve)
- an interval for making discrete steps
- a inversion
Note that the interval and the skew factor property are mutually exclusive: you either want to skew the output or you want discrete steps .
Unfortunately there are multiple types of range definitions used across HISE so there is not a single property set, but it tries to cope with them all and automatically detects which range property set to use:
Domain | Property Names | Additional information |
scriptnode | MinValue
, MaxValue
, SkewFactor
, StepSize
, Inverted
|
the range object from scriptnode parameters |
UI components | min
, max
, middlePosition
, stepSize
, Inverted
|
the range object from a UI component's JSON. Note that it uses the middle position to calculate the skew factor (this introduces a small overhead so make sure to use another mode if performance is critical) |
MIDI Automation | Start
, End
, Skew
, Interval
, Inverted
|
the range object from a MIDI automation connection MIDI automation connection |
You can use Math.skew() in order to convert a mid position value to a skew factor.
Take a look at the example how to use it with a fix object factory:
// define a prototype using the scriptnode syntax
reg prototype = {
"MinValue": 20.0,
"MaxValue": 20000.0,
"SkewFactor": 0.6
};
// pass that into the factory to create a fix object
const var f1 = Engine.createFixObjectFactory(prototype);
// create a fix object (think JSON but faster)
const var range = f1.create();
// 9.5% slower than just calling Math.pow() (which is the baseline for this function)
const var x = Math.from0To1(0.5, range);
// 34% slower than just calling Math.pow
const var y = Math.from0To1(0.5, prototype);
// There's a small rounding error because of single precision vs. double precision
// but that shouldn't have a real world impact
Console.assertTrue(Math.abs(x - y) < 0.001);
isinf
Checks for infinity. Edit on GitHub
Math.isinf(var value)
isnan
Checks for NaN (invalid floating point value). Edit on GitHub
Math.isnan(var value)
log
Calculates the log value (with base E).
Math.log(var value)
inverse
of Math.exp()
.
log10
Calculates the log value (with base 10).
Math.log10(var value)
max
Returns the bigger number.
Math.max(var first, var second)
Math.max(x,0);
min
Returns the smaller number.
Math.min(var first, var second)
Math.min(x,0);
pow
Calculates the power of base and exponent.
Math.pow(var base, var exp)
Math.pow(x,3);
Be aware that this is a rather costly operation, so if you just want to square the value, the plain ol' x*x
will get you there faster.
randInt
Returns a random integer between the low and the high values. Edit on GitHub
Math.randInt(var low, var high)
random
Returns a random number between 0.0 and 1.0. Edit on GitHub
Math.random()
range
Limits the value to the given range.
Math.range(var value, var lowerLimit, var upperLimit)
Math.range(x, -1, 1)
round
Rounds the value to the next integer.
Math.round(var value)
Rounds the value up or down at .5
sanitize
Sets infinity & NaN floating point numbers to zero. Edit on GitHub
Math.sanitize(var value)
sign
Returns the sign of the value.
Math.sign(var value)
sin
Calculates the sine value (radian based).
Math.sin(var value)
Oh, holy. As in Sinewave Generator .
sinh
Calculates the sinh value (radian based).
Math.sinh(var value)
skew
Returns the skew factor for the given mid point.
Math.skew(var start, var end, var midPoint)
The raw usage of this function allows you to simulate the range behaviour from the Math.from0to1()
method:
const var skewFactor = Math.skew(0.0, 20000.0, 1000.0);
const var midPoint = Math.pow(0.5, 1.0 / skewFactor) * 20000.0; // => 1000
However the most interesting use case for this would be if you want to convert a range object from a mid point to a skew factor based range definition for increased performance:
// This is a range how it would come from a UI component
// it defines the curve with a middle position
const var p1 = {
min: 20.0,
max: 20000.0,
middlePosition: 1000.0
}
// Using a skew-based range avoids an additional log calculation
// in the conversion functions
const var p2 = {
MinValue: p1.min,
MaxValue: p1.max,
SkewFactor: Math.skew(p1.min, p1.max, p1.middlePosition)
};
// We're caring about performance here so we use fix objects:
const var f1 = Engine.createFixObjectFactory(p1);
const var f2 = Engine.createFixObjectFactory(p2);
const var o1 = f1.create();
const var o2 = f2.create();
{
.profile(" - mid point with JSON");
for(i = 0; i < 100000; i++)
Math.from0To1(0.5, p1);
}
{
.profile(" - skew factor with JSON");
for(i = 0; i < 100000; i++)
Math.from0To1(0.5, p2);
}
{
.profile(" - mid point with fix object");
for(i = 0; i < 100000; i++)
Math.from0To1(0.5, o1);
}
{
.profile(" - skew factor with fix object");
for(i = 0; i < 100000; i++)
Math.from0To1(0.5, o2);
}
/* Results:
- mid point with JSON: 83.185 ms
- skew factor with JSON: 29.896 ms
- mid point with fix object: 27.032 ms
- skew factor with fix object: 24.955 ms
*/
As you can see, the performance can be drastically improved from 83ms to 25ms by using both the skew()
function and a fix object.
smoothstep
Calculates a smooth transition between the lower and the upper value.
Math.smoothstep(var input, var lower, var upper)
Math.smoothstep(x,0,2);
This function is very popular in graphics programming because it allows a seemless transition between two values, but there are certainly a few interesting use cases for DSP scripting / MIDI processing too. A good explanation of this function can be found here .
sqr
Calculates the square (xx) of the value.
Math.sqr(var value)
sqrt
Calculates the square root of the value.
Math.sqrt(var value)
tan
Calculates the tan value (radian based).
Math.tan(var value)
tanh
Calculates the tanh value (radian based).
Math.tanh(var value)
to0To1
Converts a value inside a range defined by the JSON data in range obj to a normalised value.
Math.to0To1(var value, var rangeObj)
This function will take a range defined by a JSON object and convert values back and to the normalized range of 0...1
.
Take a look at the Math.from0To1()
function for a detailed description on how to use this method.
toDegrees
Converts radian (0...2PI) to degree (0...3600).
Math.toDegrees(var value)
Console.print(Math.toDegrees(Math.PI*2)); // 360.0
toRadians
Converts degree (0...3600) to radian (0...2PI).
Math.toRadians(var value)
Console.print(Math.toRadians(360)); // 6.2831.. // PI*2
wrap
Wraps the value around the limit (always positive).
Math.wrap(var value, var limit)
Unlike its sibling fmod() , this function will not behave weird with negative values, so if you rely on it to loop around correctly with negative numbers, use this instead.
// fmod will not wrap around zero
Console.print(Math.fmod(-1.0, 19.0)); // -> -1.0
// wrap will... wrap around zero
Console.print(Math.wrap(-1.0, 19.0)); // -> 18.0