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):

Gamma Curves vs Sin

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.

Tags:

Php

Math

Libpng