<?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\SpeechLoudness;
use seekquarry\yioop\library\UnitTest;
/**
* SpeechLoudnessTest checks that SpeechLoudness turns the loudness
* numbers a stretch of speech carries into the scales its four quarters
* are played at.
*
* The scales this works out were compared against the reference decoder
* for the Opus audio codec, built here and made to print the scales it
* uses: on ten seconds of speech, 198 packets, all four scales of every
* packet agree. The cases below hold the rules that comparison relies
* on, so a later change cannot quietly break them.
*
* @author Chris Pollett
*/
class SpeechLoudnessTest extends UnitTest
{
/**
* A_REAL_STRETCH is the four numbers the forty-third packet of the
* test speech wrote for its quarters.
* @var array
*/
const A_REAL_STRETCH = [40, 7, 5, 2];
/**
* ITS_SCALES is what the reference decoder works out from those four
* numbers, each written out of 65536.
* @var array
*/
const ITS_SCALES = [44826624, 71827456, 83886080, 61603840];
/**
* setUp does nothing; every case works from numbers it holds itself.
*/
public function setUp()
{
}
/**
* tearDown does nothing, since no case here writes a file.
*/
public function tearDown()
{
}
/**
* realStretchGivesTheScalesTheReferenceGivesTestCase checks the
* four numbers of a stretch taken from the test speech against the
* four scales the reference decoder works out for it. This is the
* whole of the arithmetic in one case.
*/
public function realStretchGivesTheScalesTheReferenceGivesTestCase()
{
$found = SpeechLoudness::scalesFor(self::A_REAL_STRETCH);
$this->assertEqual(self::ITS_SCALES, $found["scales"],
"the four scales are the ones the reference works out");
}
/**
* louderStepGivesALargerScaleTestCase checks that naming a higher
* step gives a larger scale. Loudness is written on a scale of
* decibels, so the answer rises with the step throughout.
*/
public function louderStepGivesALargerScaleTestCase()
{
$last = -1;
for ($step = 0; $step < SpeechLoudness::LEVELS; $step += 4) {
$found = SpeechLoudness::scalesFor([$step]);
$scale = $found["scales"][0];
$this->assertTrue($scale > $last,
"a step of $step gives a larger scale than the step " .
"below it, and gave $scale");
$last = $scale;
}
}
/**
* stepIsHeldWithinTheRangeTestCase checks that a run of rises
* cannot carry a stretch past the loudest step, and a run of falls
* cannot take it below the quietest.
*/
public function stepIsHeldWithinTheRangeTestCase()
{
$rising = SpeechLoudness::scalesFor([63, 40, 40, 40]);
$this->assertTrue($rising["ended_at"] <=
SpeechLoudness::LEVELS - 1,
"a run of rises stops at the loudest step, and stopped at " .
$rising["ended_at"]);
$falling = SpeechLoudness::scalesFor([0, 0, 0, 0]);
$this->assertTrue($falling["ended_at"] >= 0,
"a run of falls stops at the quietest step, and stopped at " .
$falling["ended_at"]);
}
/**
* stretchLeaningOnItsNeighborCountsFromItTestCase checks that a
* stretch which does not name its first step outright counts from
* the step the stretch before it ended at.
*/
public function stretchLeaningOnItsNeighborCountsFromItTestCase()
{
$alone = SpeechLoudness::scalesFor([4, 4, 4, 4], true, 0);
$leaning = SpeechLoudness::scalesFor([4, 4, 4, 4], false, 20);
$this->assertTrue($leaning["scales"][0] > $alone["scales"][0],
"a stretch counting from a louder neighbor starts louder");
}
}