<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\tests;
use seekquarry\yioop\library\av_processing\Laplace;
/**
* Writes numbers the way band loudnesses are stored, so that what the
* reader gets back can be checked against what went in.
*
* Only reading is needed to play a recording, so this sits here rather
* than in the library.
*
* The writer may not be able to store a number exactly as given. Very
* far from zero the shape runs out of room, and the writer settles for
* the nearest it can hold, saying which value that was. A check has to
* compare against that rather than against what it asked for, which is
* why the writing method hands the settled value back.
*/
class LaplaceWriter
{
/**
* Writes one number and says which value was actually stored
*
* @param object $writer the writer partway through a piece
* @param int $value the number to store
* @param int $zero_chance how much of the whole the value zero
* takes
* @param int $fall how fast the chance falls away per step
* @return int the value actually stored, which may differ where
* the number was too far from zero to hold exactly
*/
public static function writeTo($writer, $value, $zero_chance, $fall)
{
$below = 0;
$chance = $zero_chance;
$stored = $value;
if ($value != 0) {
$negative = ($value < 0);
$size = abs($value);
$below = $chance;
$chance = Laplace::firstStepChance($chance, $fall);
$steps = 1;
while ($chance > 0 && $steps < $size) {
$chance *= 2;
$below += $chance + 2 * Laplace::SMALLEST_CHANCE;
$chance = ($chance * $fall) >> 15;
$steps++;
}
if ($chance == 0) {
$room = (Laplace::WHOLE - $below + Laplace::SMALLEST_CHANCE
- 1) >> 0;
$room = ($room - ($negative ? -1 : 0)) >> 1;
$further = min($size - $steps, $room - 1);
$below += (2 * $further + 1 + ($negative ? -1 : 0)) *
Laplace::SMALLEST_CHANCE;
$chance = min(Laplace::SMALLEST_CHANCE,
Laplace::WHOLE - $below);
$settled = $steps + $further;
$stored = $negative ? -$settled : $settled;
} else {
$chance += Laplace::SMALLEST_CHANCE;
if (!$negative) {
$below += $chance;
}
}
}
$writer->encodeBinary($below, $below + $chance, Laplace::WHOLE_BITS);
return $stored;
}
}