/ src / library / av_processing / SpeechShapeTables.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
 *
 * The tables in this file are the ones the standard for compressing
 * speech fixes. They are taken from the reference implementation
 * published by Xiph.Org, Skype Limited and others, which is offered
 * under a three clause licence allowing use in other software so long as
 * its notice is carried along:
 *
 *   Copyright 2001-2023 Xiph.Org, Skype Limited, Octasic, Jean-Marc
 *   Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark
 *   Borgerding, Erik de Castro Lopo, Mozilla, Amazon.
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the copyright notice,
 *   this list of conditions and the disclaimer are retained. This
 *   software is provided by the copyright holders as is, and any
 *   warranty is disclaimed.
 *
 * @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;

/**
 * SpeechShapeTables holds the tables that say what shape a stretch of
 * speech has: the mouth and throat that made it, written as a set of
 * frequencies that rise in order.
 *
 * A stretch does not carry those frequencies outright. It carries the
 * number of a guess from a fixed book, and then a small mending for each
 * frequency of that guess. This file holds the book, the likelihoods
 * used to read a guess and its mendings, how much each frequency leans
 * on the one before it, and the least gap two frequencies may sit apart.
 *
 * The numbers cover sound kept up to eight thousand cycles a second,
 * which is what a browser records speech at, and are written with
 * sixteen frequencies to a stretch.
 *
 * @author Chris Pollett
 */
class SpeechShapeTables
{
    /**
     * FREQUENCIES_IN_SHAPE is how many frequencies describe the shape of
     * one stretch of wide sound.
     */
    const FREQUENCIES_IN_SHAPE = 16;
    /**
     * GUESSES_IN_BOOK is how many guesses the fixed book holds. A
     * stretch names one of them and then mends it.
     */
    const GUESSES_IN_BOOK = 32;
    /**
     * WHOLE_BITS is how many bits the likelihoods in this file add up
     * to, as in the rest of the speech decoding.
     */
    const WHOLE_BITS = 8;
    /**
     * MENDING_STEPS is how many different mendings may be written for
     * one frequency, counting from the largest downward step to the
     * largest upward one.
     */
    const MENDING_STEPS = 10;
    /**
     * MENDING_STEP_SIZE is how far one step of mending moves a
     * frequency before the weight beside it is taken into account,
     * written out of 65536.
     */
    const MENDING_STEP_SIZE = 9830;
    /**
     * MENDING_LEVEL_ADJUST is taken off the size of a mending that is
     * not zero, since the writer rounds toward zero and the reader has
     * to undo that.
     */
    const MENDING_LEVEL_ADJUST = 102;
    /**
     * MENDING_BEYOND_CHANCES is how likely each further step was where a
     * mending sits at either end of its range. The writer may have
     * wanted to move further than the range allows, and says how much
     * further with these.
     */
    const MENDING_BEYOND_CHANCES = [100, 40, 16, 7, 3, 1, 0];
    /**
     * SHAPE_BLEND_CHANCES is how likely each degree of blending with the
     * stretch before was. A stretch of four quarters blends its shape
     * with the one before it, and says how much here.
     */
    const SHAPE_BLEND_CHANCES = [243, 221, 192, 181, 0];
    /**
     * SHAPE_FIRST_GUESSES is the book of guesses at the shape of a
     * stretch. Each guess holds sixteen frequencies, so the book is read
     * sixteen numbers at a time. A frequency is written as a fraction of
     * the highest one the sound can hold.
     */
    const SHAPE_FIRST_GUESSES = [
        7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208,
        223, 239, 13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171,
        187, 203, 220, 236, 15, 21, 34, 51, 61, 78, 92, 106, 126, 136,
        152, 167, 185, 205, 225, 240, 10, 21, 36, 50, 63, 79, 95, 110,
        126, 141, 157, 173, 189, 205, 221, 237, 17, 20, 37, 51, 59, 78,
        89, 107, 123, 134, 150, 164, 184, 205, 224, 240, 10, 15, 32, 51,
        67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236, 8, 21,
        37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, 218,
        12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203,
        219, 236, 16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171,
        186, 204, 220, 237, 11, 28, 43, 58, 74, 89, 105, 120, 135, 150,
        165, 180, 196, 211, 226, 241, 6, 16, 33, 46, 60, 75, 92, 107,
        123, 137, 156, 169, 185, 199, 214, 225, 11, 19, 30, 44, 57, 74,
        89, 105, 121, 135, 152, 169, 186, 202, 218, 234, 12, 19, 29, 46,
        57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233, 17, 23,
        35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, 222, 237,
        14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206,
        221, 240, 9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171,
        189, 205, 222, 237, 16, 19, 36, 48, 57, 76, 87, 105, 118, 132,
        150, 167, 185, 202, 218, 236, 12, 17, 29, 54, 71, 81, 94, 104,
        126, 136, 149, 164, 182, 201, 221, 237, 15, 28, 47, 62, 79, 97,
        115, 129, 142, 155, 168, 180, 194, 208, 223, 238, 8, 14, 30, 45,
        62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239, 17, 30,
        49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, 204, 220,
        235, 14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189,
        205, 222, 238, 12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154,
        171, 187, 204, 221, 236, 13, 17, 31, 43, 53, 70, 83, 103, 114,
        131, 149, 167, 185, 203, 220, 237, 17, 22, 35, 42, 58, 78, 93,
        110, 125, 139, 155, 170, 188, 206, 224, 240, 8, 15, 34, 50, 67,
        83, 99, 115, 131, 146, 162, 178, 193, 209, 224, 239, 13, 16, 41,
        66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241, 17,
        25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, 175, 191, 212,
        231, 19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200,
        213, 227, 242, 18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163,
        177, 192, 207, 223, 239, 16, 29, 47, 61, 76, 90, 106, 119, 133,
        147, 161, 176, 193, 209, 224, 240, 15, 21, 35, 50, 61, 73, 86,
        97, 110, 119, 129, 141, 175, 198, 218, 237];
    /**
     * SHAPE_GUESS_CHANCES is how likely each guess in the book was, for
     * each of the two kinds of speech. The first thirty-two entries are
     * for speech made without the voice and the rest for speech made
     * with it.
     */
    const SHAPE_GUESS_CHANCES = [
        225, 204, 201, 184, 183, 175, 158, 154, 153, 135, 119, 115, 113,
        110, 109, 99, 98, 95, 79, 68, 52, 50, 48, 45, 43, 32, 31, 27,
        18, 10, 3, 0, 255, 251, 235, 230, 212, 201, 196, 182, 167, 166,
        163, 151, 138, 124, 110, 104, 90, 78, 76, 70, 69, 57, 45, 34,
        24, 21, 11, 6, 5, 4, 3, 0];
    /**
     * SHAPE_MEND_TABLE_FOR says which set of likelihoods to read a
     * mending with, for each frequency of each guess in the book. A
     * frequency near a crowded part of the book is mended more finely
     * than one standing on its own.
     */
    /**
     * SHAPE_GUESS_WEIGHTS says how tightly each frequency of each guess
     * in the book is held. A frequency the book pins down closely takes
     * a smaller mending than one it leaves loose, so a mending is
     * divided by the weight beside it.
     */
    const SHAPE_GUESS_WEIGHTS = [
        3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925,
        2925, 2925, 2963, 2963, 2925, 2846, 3216, 3085, 2972, 3056,
        3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846,
        2846, 2726, 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846,
        3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, 3516, 3197,
        3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888,
        2888, 2888, 2888, 2753, 5054, 5054, 2934, 3573, 3385, 3056,
        3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888,
        4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019,
        2925, 2925, 2925, 2925, 2888, 2726, 3620, 3019, 2972, 3056,
        3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981,
        3310, 2991, 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094,
        3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, 5081, 5174,
        4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888,
        2846, 2793, 2846, 2700, 3122, 2888, 2963, 2925, 2925, 2925,
        2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963,
        4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873,
        2916, 3019, 2972, 3010, 3197, 2873, 3760, 3760, 3244, 3103,
        2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888,
        2888, 2660, 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963,
        2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, 3845, 4080,
        3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846,
        2647, 2647, 2846, 2806, 5147, 4894, 3225, 3845, 3441, 3169,
        2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753,
        4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740,
        2793, 2740, 2793, 2846, 2888, 2806, 5081, 5054, 3047, 3545,
        3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846,
        2793, 2620, 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075,
        3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, 3056, 2916,
        2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169,
        3056, 3010, 2963, 2846, 4375, 3882, 2925, 2888, 2846, 2888,
        2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846,
        2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056,
        3010, 2972, 2972, 2972, 2925, 2740, 4229, 4149, 3310, 3347,
        2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846,
        2846, 2793, 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888,
        2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, 4615, 4575,
        3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687,
        2687, 2740, 2793, 2700, 4149, 4269, 3789, 3657, 2726, 2780,
        2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888,
        4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925,
        2888, 2925, 2925, 2925, 2963, 2888, 5174, 4921, 2261, 3432,
        3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487,
        2753, 2925, 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207,
        2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, 2981, 3010,
        2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150,
        3150, 3103, 3010, 3010, 2944, 2873, 2687, 2726, 2780, 3010,
        3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846,
        3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056,
        3010, 2888, 2846, 2925, 2925, 2888, 3920, 3967, 3010, 3197,
        3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460,
        2580, 2607];
    const SHAPE_MEND_TABLE_FOR = [
        0, 0, 0, 0, 0, 0, 0, 1, 100, 102, 102, 68, 68, 36, 34, 96, 164,
        107, 158, 185, 180, 185, 139, 102, 64, 66, 36, 34, 34, 0, 1, 32,
        208, 139, 141, 191, 152, 185, 155, 104, 96, 171, 104, 166, 102,
        102, 102, 132, 1, 0, 0, 0, 0, 16, 16, 0, 80, 109, 78, 107, 185,
        139, 103, 101, 208, 212, 141, 139, 173, 153, 123, 103, 36, 0, 0,
        0, 0, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 32, 68, 135, 123, 119, 119,
        103, 69, 98, 68, 103, 120, 118, 118, 102, 71, 98, 134, 136, 157,
        184, 182, 153, 139, 134, 208, 168, 248, 75, 189, 143, 121, 107,
        32, 49, 34, 34, 34, 0, 17, 2, 210, 235, 139, 123, 185, 137, 105,
        134, 98, 135, 104, 182, 100, 183, 171, 134, 100, 70, 68, 70, 66,
        66, 34, 131, 64, 166, 102, 68, 36, 2, 1, 0, 134, 166, 102, 68,
        34, 34, 66, 132, 212, 246, 158, 139, 107, 107, 87, 102, 100,
        219, 125, 122, 137, 118, 103, 132, 114, 135, 137, 105, 171, 106,
        50, 34, 164, 214, 141, 143, 185, 151, 121, 103, 192, 34, 0, 0,
        0, 0, 0, 1, 208, 109, 74, 187, 134, 249, 159, 137, 102, 110,
        154, 118, 87, 101, 119, 101, 0, 2, 0, 36, 36, 66, 68, 35, 96,
        164, 102, 100, 36, 0, 2, 33, 167, 138, 174, 102, 100, 84, 2, 2,
        100, 107, 120, 119, 36, 197, 24, 0];
    /**
     * SHAPE_MEND_CHANCES is how likely each mending was, in sets of
     * nine, one set for each degree of fineness.
     */
    const SHAPE_MEND_CHANCES = [
        255, 254, 253, 244, 12, 3, 2, 1, 0, 255, 254, 252, 224, 38, 3,
        2, 1, 0, 255, 254, 251, 209, 57, 4, 2, 1, 0, 255, 254, 244, 195,
        69, 4, 2, 1, 0, 255, 251, 232, 184, 84, 7, 2, 1, 0, 255, 254,
        240, 186, 86, 14, 2, 1, 0, 255, 254, 239, 178, 91, 30, 5, 1, 0,
        255, 248, 227, 177, 100, 19, 2, 1, 0];
    /**
     * SHAPE_LEAN_ON_NEIGHBOUR is how much of a frequency's mending is
     * carried into the next one, for each of the two kinds of speech.
     * Neighboring frequencies move together, so a mending is worth
     * writing once and leaning on.
     */
    const SHAPE_LEAN_ON_NEIGHBOUR = [
        175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198,
        192, 182, 68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142,
        160, 142, 155];
    /**
     * SHAPE_LEAST_GAP is the smallest gap allowed between one frequency
     * and the next, with the first entry the gap from zero and the last
     * the gap to the top. Frequencies that crossed would describe a
     * shape no mouth can make.
     */
    /**
     * COSINE_TABLE holds twice the cosine of each of a hundred and
     * twenty-nine evenly spaced angles, written out of 4096. Turning a
     * frequency into a filter term needs that cosine, and reading it
     * from a table with a straight line drawn between two entries is
     * what every decoder does, so the answers agree to the last digit.
     */
    const COSINE_TABLE = [
        8192, 8190, 8182, 8170, 8152, 8130, 8104, 8072, 8034, 7994,
        7946, 7896, 7840, 7778, 7714, 7644, 7568, 7490, 7406, 7318,
        7226, 7128, 7026, 6922, 6812, 6698, 6580, 6458, 6332, 6204,
        6070, 5934, 5792, 5648, 5502, 5352, 5198, 5040, 4880, 4718,
        4552, 4382, 4212, 4038, 3862, 3684, 3502, 3320, 3136, 2948,
        2760, 2570, 2378, 2186, 1990, 1794, 1598, 1400, 1202, 1002, 802,
        602, 402, 202, 0, -202, -402, -602, -802, -1002, -1202, -1400,
        -1598, -1794, -1990, -2186, -2378, -2570, -2760, -2948, -3136,
        -3320, -3502, -3684, -3862, -4038, -4212, -4382, -4552, -4718,
        -4880, -5040, -5198, -5352, -5502, -5648, -5792, -5934, -6070,
        -6204, -6332, -6458, -6580, -6698, -6812, -6922, -7026, -7128,
        -7226, -7318, -7406, -7490, -7568, -7644, -7714, -7778, -7840,
        -7896, -7946, -7994, -8034, -8072, -8104, -8130, -8152, -8170,
        -8182, -8190, -8192];
    const SHAPE_LEAST_GAP = [
        100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347];
}
X