<?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\library\av_processing;
/**
* BitWriter builds up a run of bits that do not fall on byte boundaries.
* Compressed sound is written as codes of uneven length, so a code starts
* wherever the one before it ended rather than at the start of a byte. This
* gathers those codes and hands back whole bytes at the end, padding the last
* one out with nothing.
*/
class BitWriter
{
/**
* BYTE_BITS is how many bits make one byte, which is when the writer
* moves what it holds into the finished bytes.
*/
const BYTE_BITS = 8;
/**
* settled stores the bytes already finished, which nothing will
* change again.
* @var string
*/
public $settled;
/**
* holding stores bits written but not yet part of a whole byte.
* @var int
*/
public $holding;
/**
* held stores how many bits are waiting in $holding for the rest of
* their byte.
* @var int
*/
public $held;
/**
* written stores how many bits have gone in altogether, counting the
* ones still waiting for the rest of their byte
* @var int
*/
public $written;
/**
* __construct starts a writer with nothing written yet. A caller adds
* values a few bits at a time and asks for the bytes at the end
*/
public function __construct()
{
$this->settled = "";
$this->holding = 0;
$this->held = 0;
$this->written = 0;
}
/**
* add adds a value of a given width to the run
*
* @param int $value the value to add
* @param int $bits how many bits wide it is
*/
public function add($value, $bits)
{
/* The bits go in as one piece, and whole bytes come off the
top as they fill, which is much quicker than moving the
bits across one at a time. */
$this->holding = ($this->holding << $bits) |
($value & ((1 << $bits) - 1));
$held = $this->held + $bits;
while ($held >= self::BYTE_BITS) {
$held -= self::BYTE_BITS;
$this->settled .= chr(($this->holding >> $held) & 0xFF);
}
$this->holding &= (1 << $held) - 1;
$this->held = $held;
$this->written += $bits;
}
/**
* length how many bits the run holds so far
*
* @return int how many bits
*/
public function length()
{
return $this->written;
}
/**
* finish closes the run off, padding the last byte with nothing
*
* @return string the whole run as bytes
*/
public function finish()
{
if ($this->held > 0) {
$this->settled .= chr($this->holding <<
(self::BYTE_BITS - $this->held));
$this->holding = 0;
$this->held = 0;
}
return $this->settled;
}
}