Rendering waveform in PHP - How to produce a more compressed render?
With no math skills (and probably useful to have a speedy display):
You have 256 possible values. Create an array that contains the "dynamic" value for each of these values:
$dynamic = array(
0 => 0,
1 => 2,
...
);
That done, you can easily get the dynamic value:
$v = (int) ($dynamic[(int) $data / 255] * $height);
You might lose some precision, but it's probably useful.
Natural dynamic values are generated by the math sine and cosine functions, in PHP this sin
Docs (and others linked there).
You can use a loop and that function to prefill the array as well and re-use the array so you have pre-computed values:
$sine = function($v)
{
return sin($v * 0.5 * M_PI);
};
$dynamic = array();
$base = 255;
for ($i = 0; $i <= $base; $i++)
{
$dynamic[$i] = $i/$base;
}
$dynamic = array_map($sine, $dynamic);
I use a variable function here, so you can write multiple and can easily test which one matches your needs.
You need something similar to gamma correction.
For input values x in the range 0.0 -> 1.0, take y = pow(x, n)
when n
should be in the range 0.2 - 0.7 (ish). Just pick a number that gives the desired curve.
As your values are in the range 0 -> 255 you will need to divide by 255.0, apply the pow
function, and then multiply by 255 again, e.g.
$y = 255 * pow($x / 255.0, 0.4);
The pow
formula satisfies the criteria that 0 and 1 map to themselves, and smaller values are "amplified" more than larger values.
Here's a graph showing gamma curves for n = 1 / 1.6, 1 / 2, 1 / 2.4 and 1 / 2.8, vs the sin
curve (in red):
The lower the value of n
, the more "compression" is applied to the low end, so the light blue line is the one with n = 1 / 2.8.
Note how the sin
curve is almost linear in the range 0 to 0.5, so provides almost no low end compression at all.
If as I suspect your values are actually centered around 128, then you need to modify the formula somewhat:
$v = ($x - 128.0) / 128.0;
$y = 128 + 127 * sign($v) * pow(abs($v), 0.4);
although I see that the PHP developers have not included a sign
function in the PHP library.