/ src / library / av_processing / AacDecoder.php
<?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
 *
 * AacDecoder turns compressed AAC frames back into samples of sound.
 */
namespace seekquarry\yioop\library\av_processing;

/**
 * AacDecoder turns the compressed frames of an AAC sound track back
 * into samples. A frame carries the strengths of the tones a stretch of
 * sound is made of, rounded coarsely where the ear would not notice, so
 * decoding one means reading those strengths, scaling them back up, and
 * turning them from tones into sound again.
 *
 * Frames overlap: each covers twice as much sound as it advances by,
 * and neighboring frames are faded into one another, so a decoder holds
 * the tail of one frame until the next arrives.
 *
 * What this reads so far is the AAC that AacEncoder writes: one channel
 * to a part, long windows, and the table of codes the standard numbers
 * eleven. Parts that pad a frame out or carry a writer's own notes are
 * stepped over, since a real file begins with one.
 *
 * A file from another encoder decodes: all eleven tables of codes are
 * read, bands of noise are made rather than read, and a pair of
 * channels written as a sum and a difference is put back and averaged
 * into one. Measured against ffmpeg's own decoding of a stereo song at
 * a hundred and fifty thousand bits a second, the samples differ by six
 * thousandths on average.
 *
 * A frame written as eight short stretches is read as well. A stream
 * writes one where the sound changes quickly, such as at the start of a
 * word or a drum beat, because one long stretch would smear that change
 * across the whole frame. Every frame of the tone ffmpeg wrote now
 * decodes.
 *
 * One kind of frame is still refused, with a sentence naming what it
 * met: a pair of channels that each carry their own settings rather
 * than sharing one set. In that song those are eight frames in four
 * hundred and seventy.
 *
 * @author Chris Pollett
 */
class AacDecoder
{
    /**
     * NAME_BITS is how many bits name the kind of part a frame begins
     * with, such as a channel of sound or the end of the frame.
     * @var int
     */
    const NAME_BITS = 3;
    /**
     * ONE_CHANNEL is the number naming a part that carries a single
     * channel of sound.
     * @var int
     */
    const ONE_CHANNEL = 0;
    /**
     * END_OF_FRAME is the number naming the part that closes a frame.
     * @var int
     */
    const END_OF_FRAME = 7;
    /**
     * TWO_CHANNELS is the number naming a part that carries a pair of
     * channels coded together.
     * @var int
     */
    const TWO_CHANNELS = 1;
    /**
     * FILL_PART is the number naming a part that carries no sound. An
     * encoder writes one to pad a frame out to the length it aimed at,
     * or to carry a note about the sound that a player may ignore.
     * @var int
     */
    const FILL_PART = 6;
    /**
     * SPARE_PART is the number naming a part that carries data of the
     * writer's own rather than sound.
     * @var int
     */
    const SPARE_PART = 4;
    /**
     * SETTINGS_PART is the number naming the part in which a stream
     * describes how its channels are laid out.
     * @var int
     */
    const SETTINGS_PART = 5;
    /**
     * FILL_LENGTH_BITS is how many bits say how long a fill part is.
     * Where the length is as large as those bits can hold, another
     * eight bits follow saying how much longer.
     * @var int
     */
    const FILL_LENGTH_BITS = 4;
    /**
     * FILL_LENGTH_CARRIES_ON is the length that says a fill part is
     * longer than its first count can hold.
     * @var int
     */
    const FILL_LENGTH_CARRIES_ON = 15;
    /**
     * SPARE_TAG_BITS is how many bits name which of the writer's own
     * parts this is.
     * @var int
     */
    const SPARE_TAG_BITS = 4;
    /**
     * BASE_BITS is how many bits the loudness a frame counts from
     * takes.
     * @var int
     */
    const BASE_BITS = 8;
    /**
     * TABLE_BITS is how many bits name which table of codes a run of
     * bands was written with.
     * @var int
     */
    const TABLE_BITS = 4;
    /**
     * RUN_BITS is how many bits say how many bands a run covers.
     * @var int
     */
    const RUN_BITS = 5;
    /**
     * RUN_CARRIES_ON is the count that says a run is longer than one
     * number can hold and carries on into the next.
     * @var int
     */
    const RUN_CARRIES_ON = 31;
    /**
     * EMPTY_TABLE is the number naming the table used for a run of
     * bands that carry nothing at all.
     * @var int
     */
    const EMPTY_TABLE = 0;
    /**
     * NOISE_TABLE is the number a band names instead of a table where
     * it carries noise rather than coded values. Sound that is close to
     * noise costs many bits to write out and sounds the same when made
     * afresh, so a stream says how loud that noise is and leaves the
     * decoder to make it.
     * @var int
     */
    const NOISE_TABLE = 13;
    /**
     * INTENSITY_TABLES are the numbers a band names where its sound is
     * taken from the other channel of a pair rather than written out.
     * A single channel never carries these.
     * @var array
     */
    const INTENSITY_TABLES = [14, 15];
    /**
     * SHORT_RUN_BITS is how many bits say how many bands a run covers
     * in a frame of short stretches. A short stretch has fewer bands
     * than a long one, so fewer bits are needed to count them.
     * @var int
     */
    const SHORT_RUN_BITS = 3;
    /**
     * SHORT_RUN_CARRIES_ON is the count that says such a run is longer
     * than one number can hold and carries on into the next.
     * @var int
     */
    const SHORT_RUN_CARRIES_ON = 7;
    /**
     * NOISE_START_BITS is how many bits the first noise loudness of a
     * frame takes. The ones after it are written as steps from the one
     * before, like any other loudness.
     * @var int
     */
    const NOISE_START_BITS = 9;
    /**
     * ESCAPE_AT is the size at which a code stops carrying the number
     * itself and the rest of it is written separately.
     * @var int
     */
    const ESCAPE_AT = 16;
    /**
     * DECODER_SCALE is what the encoder multiplied every sample by
     * before compressing it, so the decoder divides by the same to give
     * back sound at the loudness it arrived at.
     * @var float
     */
    const DECODER_SCALE = 32768.0;
    /**
     * OVERLAP_SHARE is what each frame's sound is multiplied by before
     * neighboring frames are added together. The transform hands back a
     * whole frame's worth, and two frames overlap over every sample, so
     * each carries half the weight. Measured by encoding a tone and
     * decoding it: at this share the sound comes back within a
     * thousandth of what went in, and at twice it comes back twice as
     * loud.
     * @var float
     */
    const OVERLAP_SHARE = 0.5;
    /**
     * $carried stores the tail of the frame decoded before this one.
     * Frames overlap by half their length, so the second half of one
     * frame is added to the first half of the next.
     * @var array
     */
    public $carried = [];
    /**
     * $transform stores the transform that turns tone strengths back
     * into sound, made once and used for every frame.
     * @var Mdct
     */
    public $transform = null;
    /**
     * $fade stores the curve each frame is faded in and out with. Two
     * neighboring frames fade into one another, and their fades add to
     * one so that steady sound comes back unchanged.
     * @var array
     */
    public $fade = [];
    /**
     * __construct builds the transform and the fade a decoder needs,
     * which are the same for every frame.
     */
    public function __construct()
    {
        $this->transform = Mdct::forSize(AacEncoder::HOP);
        $this->fade = AacBands::fadeFor(AacBands::LONG);
        $this->carried = array_fill(0, AacEncoder::HOP, 0.0);
    }
    /**
     * decodeFrame turns one compressed frame into samples: it reads the
     * tone strengths, scales them back up, turns them into sound, fades
     * that sound in, and adds the tail the frame before it left.
     *
     * @param string $frame One compressed frame.
     * @return array The samples this frame gives, as fractions of one.
     */
    public function decodeFrame($frame)
    {
        $tones = $this->readTones($frame);
        $sound = $this->transform->inverse($tones);
        $span = AacEncoder::SPAN;
        $hop = AacEncoder::HOP;
        $faded = [];
        for ($at = 0; $at < $span; $at++) {
            $faded[$at] = $sound[$at] * $this->fade[$at];
        }
        $given = [];
        for ($at = 0; $at < $hop; $at++) {
            $given[$at] = ($faded[$at] + $this->carried[$at]) *
                self::OVERLAP_SHARE / self::DECODER_SCALE;
        }
        $tail = [];
        for ($at = 0; $at < $hop; $at++) {
            $tail[$at] = $faded[$hop + $at];
        }
        $this->carried = $tail;
        return $given;
    }
    /**
     * readTones reads the strengths of the tones out of one frame and
     * scales each back to its own size. A frame writes those strengths
     * as small whole numbers together with a step for each band, and
     * the strength is the number raised to four thirds and multiplied
     * by the step.
     *
     * @param string $frame One compressed frame.
     * @return array One strength for each tone the frame covers.
     */
    public function readTones($frame)
    {
        $reader = new BitReader($frame);
        /* A frame is built of parts, each named by three bits. Only the
           part carrying one channel of sound is read here; the parts
           that pad a frame out or carry a writer's own notes are
           stepped over, and the rest are refused by name. */
        while (true) {
            if ($reader->bitsLeft() < AacFrame::NAME_BITS) {
                throw new \RuntimeException("this frame ends before it "
                    . "carries any sound");
            }
            $named = $reader->readBits(AacFrame::NAME_BITS);
            if ($named === AacFrame::ONE_CHANNEL) {
                break;
            }
            if ($named === self::FILL_PART) {
                self::skipFill($reader);
                continue;
            }
            if ($named === self::SPARE_PART) {
                self::skipSpare($reader);
                continue;
            }
            if ($named === self::TWO_CHANNELS) {
                return $this->readPairedChannels($reader);
            }
            if ($named === AacFrame::END_OF_FRAME) {
                throw new \RuntimeException("this frame closes before "
                    . "it carries any sound");
            }
            throw new \RuntimeException("this frame carries a part "
                . "named $named, which is not read yet");
        }
        $reader->readBits(4);
        $base = $reader->readBits(AacFrame::BASE_BITS);
        $said = $this->readShape($reader);
        if ($said["shape"] === AacBands::SHORT) {
            return $this->readShortFrame($reader, $said, $base);
        }
        $bands = $said["bands"];
        if ($bands <= 0 || $bands > AacBands::longBandCount()) {
            $bands = AacBands::longBandCount();
        }
        $tables = $this->readRuns($reader, $bands);
        $steps = $this->readSteps($reader, $bands, $tables, $base);
        /* Three flags say whether the frame carries the extra
           settings this encoder never writes: added pulses, a filter
           over the tones, and a gain that changes within the frame. */
        for ($at = 0; $at < 3; $at++) {
            if ($reader->readBit() !== 0) {
                throw new \RuntimeException("this frame carries extra "
                    . "settings that are not read yet");
            }
        }
        return $this->readBands($reader, $bands, $tables, $steps);
    }
    /**
     * readPairedChannels reads a part carrying two channels coded
     * together and hands back one run of tone strengths. Two channels
     * often hold nearly the same sound, so a stream may write their sum
     * and their difference rather than each on its own; those are put
     * back into a left and a right channel, which are then averaged,
     * since what this folder writes carries a single channel.
     *
     * @param BitReader $reader The frame's bits.
     * @return array One strength for each tone the frame covers.
     */
    public function readPairedChannels($reader)
    {
        $reader->readBits(4);
        $shared = $reader->readBit();
        if ($shared !== 1) {
            throw new \RuntimeException("this pair of channels each "
                . "carry their own settings, which is not decoded yet");
        }
        $said = $this->readShape($reader);
        if ($said["shape"] === AacBands::SHORT) {
            throw new \RuntimeException("this frame uses the shorter "
                . "windows, which are not decoded yet");
        }
        $bands = $said["bands"];
        if ($bands <= 0 || $bands > AacBands::longBandCount()) {
            $bands = AacBands::longBandCount();
        }
        /* A pair may say, band by band, that it wrote the sum and the
           difference of its two channels rather than each channel. */
        $joined = $reader->readBits(2);
        $summed = array_fill(0, $bands, false);
        if ($joined === 1) {
            for ($band = 0; $band < $bands; $band++) {
                $summed[$band] = ($reader->readBit() === 1);
            }
        } elseif ($joined === 2) {
            $summed = array_fill(0, $bands, true);
        }
        $left = $this->readChannel($reader, $bands);
        $right = $this->readChannel($reader, $bands);
        return self::joinChannels($left, $right, $summed, $bands);
    }
    /**
     * joinChannels turns the two runs of strengths a pair carries into
     * one. Where a band holds a sum and a difference, the two channels
     * are worked back out of them first, and the two are then averaged
     * into the single channel this folder writes.
     *
     * @param array $left The first channel's strengths.
     * @param array $right The second channel's strengths.
     * @param array $summed Whether each band holds a sum and a
     *     difference rather than two channels.
     * @param int $bands How many bands the frame covers.
     * @return array One strength for each tone.
     */
    public static function joinChannels($left, $right, $summed, $bands)
    {
        $joined = [];
        for ($band = 0; $band < $bands; $band++) {
            $from = AacBands::LONG_EDGES[$band];
            $past = AacBands::LONG_EDGES[$band + 1];
            for ($at = $from; $at < $past; $at++) {
                $one = $left[$at] ?? 0.0;
                $two = $right[$at] ?? 0.0;
                if ($summed[$band]) {
                    $joined[$at] = $one;
                } else {
                    $joined[$at] = ($one + $two) / 2.0;
                }
            }
        }
        for ($at = 0; $at < AacEncoder::HOP; $at++) {
            if (!isset($joined[$at])) {
                $joined[$at] = 0.0;
            }
        }
        ksort($joined);
        return array_values($joined);
    }
    /**
     * readChannel reads one channel of a pair: the loudness it counts
     * from, which table each band was written with, the step for each
     * band, and the values themselves.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands the frame covers.
     * @return array One strength for each tone of that channel.
     */
    public function readChannel($reader, $bands)
    {
        $base = $reader->readBits(AacFrame::BASE_BITS);
        $tables = $this->readRuns($reader, $bands);
        $steps = $this->readSteps($reader, $bands, $tables, $base);
        for ($at = 0; $at < 3; $at++) {
            if ($reader->readBit() !== 0) {
                throw new \RuntimeException("this frame carries extra "
                    . "settings that are not read yet");
            }
        }
        return $this->readBands($reader, $bands, $tables, $steps);
    }
    /**
     * skipFill steps over a part that carries no sound. Such a part
     * says how long it is, and where it is longer than that count can
     * hold, a further count follows.
     *
     * @param BitReader $reader The frame's bits.
     */
    public static function skipFill($reader)
    {
        $length = $reader->readBits(self::FILL_LENGTH_BITS);
        if ($length === self::FILL_LENGTH_CARRIES_ON) {
            $length += $reader->readBits(8) - 1;
        }
        $reader->skipBits($length * 8);
    }
    /**
     * skipSpare steps over a part carrying data of the writer's own
     * rather than sound. Such a part names itself, says whether its
     * length is counted in bytes, then gives that length.
     *
     * @param BitReader $reader The frame's bits.
     */
    public static function skipSpare($reader)
    {
        $reader->readBits(self::SPARE_TAG_BITS);
        $aligned = $reader->readBit();
        $length = $reader->readBits(8);
        if ($length === 255) {
            $length += $reader->readBits(8);
        }
        if ($aligned === 1) {
            $reader->skipBits((8 - ($reader->position % 8)) % 8);
        }
        $reader->skipBits($length * 8);
    }
    /**
     * readShortFrame reads a frame written as eight short stretches
     * rather than one long one. A long stretch would smear a sudden
     * change across the whole frame, so a stream splits the frame into
     * eight where the sound changes quickly, such as at the start of a
     * word or a drum beat.
     *
     * @param BitReader $reader The frame's bits.
     * @param array $said What readShape read: the shape, how many bands
     *     one short stretch covers, and how the eight are grouped.
     * @param int $base The loudness the frame counts from, already read.
     * @return array The eight stretches of strengths, one after
     *     another.
     */
    public function readShortFrame($reader, $said, $base)
    {
        $bands = $said["bands"];
        if ($bands <= 0 ||
            $bands > count(AacBands::SHORT_EDGES) - 1) {
            $bands = count(AacBands::SHORT_EDGES) - 1;
        }
        $groups = self::groupsWithin($said["grouping"]);
        $tables = $this->readShortRuns($reader, $bands, count($groups));
        $steps = $this->readShortSteps($reader, $bands, $tables, $base);
        for ($at = 0; $at < 3; $at++) {
            if ($reader->readBit() !== 0) {
                throw new \RuntimeException("this frame carries extra "
                    . "settings that are not read yet");
            }
        }
        return $this->readShortBands($reader, $bands, $tables, $steps,
            $groups);
    }
    /**
     * groupsWithin works out how the eight short stretches of a frame
     * are grouped. Stretches that sound alike share one set of steps
     * and one set of tables, and the frame marks where each group
     * begins with seven bits, one for each stretch after the first.
     *
     * @param int $grouping The seven bits the frame wrote.
     * @return array How many stretches each group holds.
     */
    public static function groupsWithin($grouping)
    {
        $groups = [];
        $held = 1;
        for ($at = 6; $at >= 0; $at--) {
            if ((($grouping >> $at) & 1) === 1) {
                $held++;
            } else {
                $groups[] = $held;
                $held = 1;
            }
        }
        $groups[] = $held;
        return $groups;
    }
    /**
     * readShortRuns reads which table of codes each band of each group
     * was written with. A short frame says its runs with fewer bits
     * than a long one, since a short stretch has fewer bands.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands one short stretch covers.
     * @param int $groups How many groups the eight stretches make.
     * @return array Which table each band of each group uses.
     */
    public function readShortRuns($reader, $bands, $groups)
    {
        $tables = [];
        for ($group = 0; $group < $groups; $group++) {
            $at = 0;
            while ($at < $bands) {
                $table = $reader->readBits(AacFrame::TABLE_BITS);
                $length = 0;
                do {
                    $piece = $reader->readBits(self::SHORT_RUN_BITS);
                    $length += $piece;
                } while ($piece === self::SHORT_RUN_CARRIES_ON);
                if ($length <= 0) {
                    throw new \RuntimeException("this frame names a run "
                        . "of no bands, so it cannot be read");
                }
                for ($seen = 0; $seen < $length && $at < $bands;
                    $seen++) {
                    $tables[$group][$at] = $table;
                    $at++;
                }
            }
        }
        return $tables;
    }
    /**
     * readShortSteps reads the step each band of each group is scaled
     * by. The steps run on from group to group as they do from band to
     * band, each written as how far it sits from the one before.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands one short stretch covers.
     * @param array $tables Which table each band of each group uses.
     * @param int $base The loudness the frame counts from.
     * @return array The step for each band of each group.
     */
    public function readShortSteps($reader, $bands, $tables, $base)
    {
        $steps = [];
        $last = $base;
        $noise_last = 0;
        $noise_started = false;
        foreach ($tables as $group => $row) {
            for ($band = 0; $band < $bands; $band++) {
                $table = $row[$band] ?? AacFrame::EMPTY_TABLE;
                if ($table === AacFrame::EMPTY_TABLE) {
                    $steps[$group][$band] = 0;
                    continue;
                }
                if (in_array($table, self::INTENSITY_TABLES, true)) {
                    self::readLoudnessCode($reader);
                    $steps[$group][$band] = 0;
                    continue;
                }
                if ($table === self::NOISE_TABLE) {
                    if (!$noise_started) {
                        $noise_last = $base - 256 +
                            $reader->readBits(self::NOISE_START_BITS);
                        $noise_started = true;
                    } else {
                        $noise_last += self::readLoudnessCode($reader) -
                            AacTables::LOUDNESS_SPAN;
                    }
                    $steps[$group][$band] = $noise_last;
                    continue;
                }
                $last += self::readLoudnessCode($reader) -
                    AacTables::LOUDNESS_SPAN;
                $steps[$group][$band] = $last;
            }
        }
        return $steps;
    }
    /**
     * readShortBands reads the values of every band of every stretch.
     * A group's values are written once for the whole group, stretch by
     * stretch within it, and the eight stretches are laid end to end in
     * what this hands back.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands one short stretch covers.
     * @param array $tables Which table each band of each group uses.
     * @param array $steps The step each band of each group is scaled
     *     by.
     * @param array $groups How many stretches each group holds.
     * @return array The eight stretches of strengths, one after
     *     another.
     */
    public function readShortBands($reader, $bands, $tables, $steps,
        $groups)
    {
        $short = AacBands::SHORT_TONES;
        $tones = array_fill(0, AacEncoder::HOP, 0.0);
        $stretch = 0;
        foreach ($groups as $group => $holds) {
            $held = [];
            for ($band = 0; $band < $bands; $band++) {
                $table = $tables[$group][$band] ?? AacFrame::EMPTY_TABLE;
                $from = AacBands::SHORT_EDGES[$band];
                $past = AacBands::SHORT_EDGES[$band + 1];
                for ($within = 0; $within < $holds; $within++) {
                    if ($table === AacFrame::EMPTY_TABLE) {
                        continue;
                    }
                    if ($table === self::NOISE_TABLE) {
                        continue;
                    }
                    if (in_array($table, self::INTENSITY_TABLES, true)) {
                        throw new \RuntimeException("this band takes "
                            . "its sound from the other channel of a "
                            . "pair, which is not decoded yet");
                    }
                    $code_table = self::tableFor($table);
                    $escapes = ($table === AacTables::SOUND_TABLE);
                    $scale = pow(2.0, AacQuantizer::SQUASHED_STEP *
                        ($steps[$group][$band] -
                        AacQuantizer::MIDDLE_STEP) /
                        AacQuantizer::SQUASH);
                    for ($at = $from; $at < $past;
                        $at += $code_table["holds"]) {
                        $values = self::readGroup($reader, $code_table,
                            $escapes);
                        foreach ($values as $which => $value) {
                            if ($at + $which >= $past) {
                                break;
                            }
                            $held[$within][$at + $which] =
                                self::sizeOfNumber($value) * $scale;
                        }
                    }
                }
            }
            for ($within = 0; $within < $holds; $within++) {
                $start = ($stretch + $within) * $short;
                for ($at = 0; $at < $short; $at++) {
                    $tones[$start + $at] = $held[$within][$at] ?? 0.0;
                }
            }
            $stretch += $holds;
        }
        return $tones;
    }
    /**
     * readShape reads how the frame was faded. This decoder reads the
     * one fade the encoder writes, so a frame saying it used the softer
     * fade is refused rather than decoded with the wrong curve.
     *
     * @param BitReader $reader The frame's bits.
     * @return array Which shape the frame used under the key shape, how
     *     many bands it covers under the key bands, and how its
     *     stretches are grouped under the key grouping.
     */
    public function readShape($reader)
    {
        $reader->readBit();
        $shape = $reader->readBits(AacFrame::SHAPE_BITS);
        $reader->readBit();
        if ($shape === AacBands::SHORT) {
            /* A frame of short windows counts its bands over one short
               stretch and says how its eight stretches are grouped, so
               both are read before anything else. */
            $bands = $reader->readBits(4);
            $grouping = $reader->readBits(7);
            return ["shape" => $shape, "bands" => $bands,
                "grouping" => $grouping];
        }
        $bands = $reader->readBits(AacFrame::BAND_COUNT_BITS);
        $reader->readBit();
        return ["shape" => $shape, "bands" => $bands, "grouping" => 0];
    }
    /**
     * readRuns reads which table of codes each band was written with.
     * The frame says it once for a run of bands rather than for each,
     * and a run longer than one number can hold carries on into the
     * next.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands the frame covers.
     * @return array Which table each band uses.
     */
    public function readRuns($reader, $bands)
    {
        $tables = [];
        $at = 0;
        while ($at < $bands) {
            $table = $reader->readBits(AacFrame::TABLE_BITS);
            $length = 0;
            do {
                $piece = $reader->readBits(AacFrame::RUN_BITS);
                $length += $piece;
            } while ($piece === AacFrame::RUN_CARRIES_ON);
            if ($length <= 0) {
                throw new \RuntimeException("this frame names a run of "
                    . "no bands, so it cannot be read");
            }
            for ($seen = 0; $seen < $length && $at < $bands; $seen++) {
                $tables[$at] = $table;
                $at++;
            }
        }
        return $tables;
    }
    /**
     * readSteps reads the step each band's numbers are scaled by. A
     * step is written as how far it sits from the step before, so they
     * are added up as they are read, starting from the loudness the
     * frame counts from.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands the frame covers.
     * @param array $tables Which table each band uses.
     * @param int $base The loudness the frame counts from.
     * @return array The step for each band.
     */
    public function readSteps($reader, $bands, $tables, $base)
    {
        $steps = [];
        $last = $base;
        $noise_last = 0;
        $noise_started = false;
        for ($band = 0; $band < $bands; $band++) {
            $table = $tables[$band] ?? AacFrame::EMPTY_TABLE;
            if ($table === AacFrame::EMPTY_TABLE) {
                $steps[$band] = 0;
                continue;
            }
            if (in_array($table, self::INTENSITY_TABLES, true)) {
                $steps[$band] = 0;
                self::readLoudnessCode($reader);
                continue;
            }
            if ($table === self::NOISE_TABLE) {
                /* The first noise loudness of a frame is written out in
                   full; each one after it is a step from the last. */
                if (!$noise_started) {
                    $noise_last = $base - 256 +
                        $reader->readBits(self::NOISE_START_BITS);
                    $noise_started = true;
                } else {
                    $noise_last += self::readLoudnessCode($reader) -
                        AacTables::LOUDNESS_SPAN;
                }
                $steps[$band] = $noise_last;
                continue;
            }
            $which = self::readLoudnessCode($reader);
            $last += $which - AacTables::LOUDNESS_SPAN;
            $steps[$band] = $last;
        }
        return $steps;
    }
    /**
     * readLoudnessCode reads one of the codes that say how far a step
     * sits from the step before it. The codes are of different lengths,
     * so bits are taken one at a time until they spell one out.
     *
     * @param BitReader $reader The frame's bits.
     * @return int Which of the codes was read, counting from zero.
     */
    public static function readLoudnessCode($reader)
    {
        $held = 0;
        $length = 0;
        while ($length < 20) {
            $held = ($held << 1) | $reader->readBit();
            $length++;
            foreach (AacTables::LOUDNESS_CODE_BITS as $which => $bits) {
                if ($bits === $length
                    && AacTables::LOUDNESS_CODES[$which] === $held) {
                    return $which;
                }
            }
        }
        throw new \RuntimeException("a step in this frame is written "
            . "with a code that is not in the table");
    }
    /**
     * tableFor hands back the table of codes a band was written with,
     * along with how many values each of its codes stands for and
     * whether the code carries their signs.
     *
     * @param int $table Which table, as the frame named it.
     * @return array The rows of the table under the key rows, how many
     *     values a code stands for under the key holds, and whether
     *     signs follow under the key signed.
     */
    public static function tableFor($table)
    {
        $held = [
            1 => [AacCodeTables::VALUE_CODES_ONE, 4, false],
            2 => [AacCodeTables::VALUE_CODES_TWO, 4, false],
            3 => [AacCodeTables::VALUE_CODES_THREE, 4, true],
            4 => [AacCodeTables::VALUE_CODES_FOUR, 4, true],
            5 => [AacCodeTables::VALUE_CODES_FIVE, 2, false],
            6 => [AacCodeTables::VALUE_CODES_SIX, 2, false],
            7 => [AacCodeTables::VALUE_CODES_SEVEN, 2, true],
            8 => [AacCodeTables::VALUE_CODES_EIGHT, 2, true],
            9 => [AacCodeTables::VALUE_CODES_NINE, 2, true],
            10 => [AacCodeTables::VALUE_CODES_TEN, 2, true],
            11 => [AacCodeTables::VALUE_CODES_ELEVEN, 2, true],
        ];
        if (!isset($held[$table])) {
            throw new \RuntimeException("this frame names table $table "
                . "of codes, which the standard does not fix");
        }
        return ["rows" => $held[$table][0], "holds" => $held[$table][1],
            "signed" => $held[$table][2]];
    }
    /**
     * rowFor takes bits until they spell out one of a table's codes,
     * and hands back the row that code names. A code may be anywhere
     * from one to nineteen bits long, so the reading grows a bit at a
     * time until it matches.
     *
     * @param BitReader $reader The frame's bits.
     * @param array $rows The rows of the table being read.
     * @return array The row the bits spelled out.
     */
    public static function rowFor($reader, $rows)
    {
        $at = 0;
        $length = $rows[0][0];
        $held = $reader->readBits($length);
        while ($held !== $rows[$at][1]) {
            $at++;
            if (!isset($rows[$at])) {
                throw new \RuntimeException("a code in this frame is "
                    . "not in the table it was written with");
            }
            $wider = $rows[$at][0] - $length;
            $length = $rows[$at][0];
            $held = ($held << $wider) | $reader->readBits($wider);
        }
        return $rows[$at];
    }
    /**
     * readGroup reads one group of values written with a given table:
     * either a pair or four at a time, with the signs following where
     * the table does not carry them, and the rest of any value too
     * large for the table to hold.
     *
     * @param BitReader $reader The frame's bits.
     * @param array $table The table, as tableFor gave it.
     * @param bool $escapes Whether values too large for the table are
     *     written with the rest following.
     * @return array The values of this group, with their signs.
     */
    public static function readGroup($reader, $table, $escapes)
    {
        $row = self::rowFor($reader, $table["rows"]);
        $values = array_slice($row, 2, $table["holds"]);
        if ($table["signed"]) {
            foreach ($values as $at => $value) {
                if ($value !== 0 && $reader->readBit() === 1) {
                    $values[$at] = -$value;
                }
            }
        }
        if ($escapes) {
            foreach ($values as $at => $value) {
                if (abs($value) === self::ESCAPE_AT) {
                    $rest = self::readRest($reader);
                    $values[$at] = ($value < 0) ? -$rest : $rest;
                }
            }
        }
        return $values;
    }
    /**
     * readBands reads the rounded numbers of every band and turns each
     * back into the strength of a tone. A band that carries nothing
     * gives silence, and a band that carries something is read a pair
     * of numbers at a time.
     *
     * @param BitReader $reader The frame's bits.
     * @param int $bands How many bands the frame covers.
     * @param array $tables Which table each band uses.
     * @param array $steps The step each band is scaled by.
     * @return array One strength for each tone the frame covers.
     */
    public function readBands($reader, $bands, $tables, $steps)
    {
        $tones = array_fill(0, AacEncoder::HOP, 0.0);
        for ($band = 0; $band < $bands; $band++) {
            $table = $tables[$band] ?? AacFrame::EMPTY_TABLE;
            if ($table === AacFrame::EMPTY_TABLE) {
                continue;
            }
            if ($table === self::NOISE_TABLE) {
                self::fillWithNoise($tones, $band, $steps[$band]);
                continue;
            }
            if (in_array($table, self::INTENSITY_TABLES, true)) {
                throw new \RuntimeException("this band takes its sound "
                    . "from the other channel of a pair, which is not "
                    . "decoded yet");
            }
            $held = self::tableFor($table);
            $escapes = ($table === AacTables::SOUND_TABLE);
            $from = AacBands::LONG_EDGES[$band];
            $past = AacBands::LONG_EDGES[$band + 1];
            $scale = pow(2.0, AacQuantizer::SQUASHED_STEP *
                ($steps[$band] - AacQuantizer::MIDDLE_STEP) /
                AacQuantizer::SQUASH);
            for ($at = $from; $at < $past; $at += $held["holds"]) {
                $values = self::readGroup($reader, $held, $escapes);
                foreach ($values as $which => $value) {
                    if ($at + $which >= $past) {
                        break;
                    }
                    $tones[$at + $which] = self::sizeOfNumber($value) *
                        $scale;
                }
            }
        }
        return $tones;
    }
    /**
     * fillWithNoise fills one band with noise at the loudness the frame
     * asked for. A band whose sound is close to noise is not written
     * out: the stream says how loud it should be, and any noise of that
     * loudness sounds the same to a listener.
     *
     * @param array $tones The strengths being built, changed in place.
     * @param int $band Which band to fill.
     * @param int $loudness How loud that noise should be.
     */
    public static function fillWithNoise(&$tones, $band, $loudness)
    {
        $from = AacBands::LONG_EDGES[$band];
        $past = AacBands::LONG_EDGES[$band + 1];
        $made = [];
        $total = 0.0;
        for ($at = $from; $at < $past; $at++) {
            $made[$at] = mt_rand(-1000, 1000) / 1000.0;
            $total += $made[$at] * $made[$at];
        }
        $wanted = pow(2.0, ($loudness - AacQuantizer::MIDDLE_STEP) / 4.0);
        $fit = ($total > 0.0) ?
            $wanted * sqrt(($past - $from) / $total) : 0.0;
        for ($at = $from; $at < $past; $at++) {
            $tones[$at] = $made[$at] * $fit;
        }
    }
    /**
     * readPair reads one pair of rounded numbers. The pair is written
     * as a single code saying how large each of the two is, followed by
     * a sign for each that is not zero, and by the rest of any number
     * too large for the code to carry.
     *
     * @param BitReader $reader The frame's bits.
     * @return array The two numbers, with their signs.
     */
    public static function readPair($reader)
    {
        $where = self::readSoundCode($reader);
        $first = intdiv($where, AacTables::PAIR_RANGE);
        $second = $where % AacTables::PAIR_RANGE;
        if ($first !== 0 && $reader->readBit() === 1) {
            $first = -$first;
        }
        if ($second !== 0 && $reader->readBit() === 1) {
            $second = -$second;
        }
        if (abs($first) >= self::ESCAPE_AT) {
            $first = self::readRest($reader) * ($first < 0 ? -1 : 1);
        }
        if (abs($second) >= self::ESCAPE_AT) {
            $second = self::readRest($reader) * ($second < 0 ? -1 : 1);
        }
        return [$first, $second];
    }
    /**
     * readSoundCode reads one of the codes that stand for a pair of
     * rounded numbers. The codes are of different lengths, so bits are
     * taken one at a time until they spell one out.
     *
     * @param BitReader $reader The frame's bits.
     * @return int Which of the codes was read, counting from zero.
     */
    public static function readSoundCode($reader)
    {
        $held = 0;
        $length = 0;
        while ($length < 20) {
            $held = ($held << 1) | $reader->readBit();
            $length++;
            foreach (AacTables::SOUND_CODE_BITS as $where => $bits) {
                if ($bits === $length
                    && AacTables::SOUND_CODES[$where] === $held) {
                    return $where;
                }
            }
        }
        throw new \RuntimeException("a pair in this frame is written "
            . "with a code that is not in the table");
    }
    /**
     * readRest reads a number too large for its code to carry. Such a
     * number is written as a run of ones saying how many bits follow,
     * then a zero, then the bits themselves.
     *
     * @param BitReader $reader The frame's bits.
     * @return int The number those bits spell out.
     */
    public static function readRest($reader)
    {
        $length = 4;
        while ($reader->readBit() === 1) {
            $length++;
            if ($length > 24) {
                throw new \RuntimeException("a number in this frame is "
                    . "written as longer than any number can be");
            }
        }
        return $reader->readBits($length) + (1 << $length);
    }
    /**
     * sizeOfNumber turns a rounded number back into the strength it
     * stands for. The encoder took each strength to the power of three
     * quarters before rounding it, so the decoder raises the rounded
     * number to four thirds.
     *
     * @param int $number The rounded number, with its sign.
     * @return float The strength it stands for.
     */
    public static function sizeOfNumber($number)
    {
        if ($number === 0) {
            return 0.0;
        }
        $size = pow(abs($number), AacQuantizer::UNSQUASH);
        return ($number < 0) ? -$size : $size;
    }
}
X