EN

Slave Rift

by tueb2024 · Shooting
5.0 (1)
▶ Play 💬 Feedback Source 🕘 Versions Edit GitHub
games/slave-rift / src / Audio / RiftSfx.php · commit 9ea6094
<?phpnamespace App\Audio;use JumPHP\Audio\SoundManager;/** Small original 44.1 kHz sound bank: no external audio dependency. */final class RiftSfx{    private const RATE = 44100;    public static function register(SoundManager $sound): void    {        if ($sound->hasSfx('colt_fire')) return;        $sound->synth('rift_kick', self::kick());        $sound->synth('rift_snare', self::snare());        $sound->synth('rift_clap', self::clap());        $sound->synth('rift_hat', self::hat());        $sound->synth('colt_fire', self::gun(0.22, 0.62, 0.52));        $sound->synth('sten_fire', self::gun(0.12, 0.42, 0.50));        $sound->synth('heavy_fire', self::gun(0.16, 0.72, 0.46));        $sound->synth('pulse_sfx', self::sweepFx(0.42, 140.0, 760.0));        $sound->synth('special_sfx', self::special());        $sound->synth('pickup_xp', self::pickup());        $sound->synth('level_up', self::levelUp());    }    private static function kick(): string    {        return self::wav(0.24, static function (float $t, int $i): float {            $f = 48.0 + 92.0 * exp(-20.0 * $t);            return self::env($t, 0.24) * (0.90 * sin(2 * M_PI * $f * $t) + ($i % 11 === 0 ? 0.05 : 0.0));        });    }    private static function snare(): string    {        $seed = 0x13579b;        return self::wav(0.20, static function (float $t, int $i) use (&$seed): float {            $noise = self::noise($seed);            return self::env($t, 0.20) * (0.62 * $noise + 0.26 * sin(2 * M_PI * 185.0 * $t));        });    }    private static function clap(): string    {        $seed = 0x61ac3d; $last = 0.0;        return self::wav(0.14, static function (float $t, int $i) use (&$seed, &$last): float {            $x = self::noise($seed); $hp = $x - $last * 0.88; $last = $x;            $burst = 0.0;            foreach ([0.0, 0.018, 0.036] as $offset) {                if ($t >= $offset) $burst += exp(-92.0 * ($t - $offset));            }            return 0.28 * $burst * $hp;        });    }    private static function hat(): string    {        $seed = 0x2468ac; $last = 0.0;        return self::wav(0.065, static function (float $t, int $i) use (&$seed, &$last): float {            $x = self::noise($seed); $hp = $x - $last * 0.92; $last = $x;            return self::env($t, 0.065, 0.001) * 0.42 * $hp;        });    }    private static function gun(float $duration, float $body, float $noiseAmount): string    {        $seed = (int)round($duration * 100000) ^ 0x5a17;        return self::wav($duration, static function (float $t, int $i) use ($duration, $body, $noiseAmount, &$seed): float {            $f = 90.0 + 40.0 * exp(-18.0 * $t);            return self::env($t, $duration, 0.0015) * ($noiseAmount * self::noise($seed) + $body * sin(2 * M_PI * $f * $t));        });    }    private static function sweepFx(float $duration, float $from, float $to): string    {        return self::wav($duration, static function (float $t) use ($duration, $from, $to): float {            $u = min(1.0, $t / $duration); $f = $from + ($to - $from) * $u;            return self::env($t, $duration, 0.008) * (0.55 * sin(2 * M_PI * $f * $t) + 0.18 * sin(2 * M_PI * $f * 2.03 * $t));        });    }    private static function special(): string    {        return self::wav(0.52, static function (float $t): float {            $u = $t / 0.52; $f = 520.0 - 260.0 * $u;            return self::env($t, 0.52, 0.006) * (0.52 * sin(2 * M_PI * $f * $t) + 0.34 * sin(2 * M_PI * $f * 2.0 * $t));        });    }    private static function pickup(): string    {        return self::wav(0.16, static fn(float $t): float => self::env($t, 0.16, 0.003) *            (0.50 * sin(2 * M_PI * 880.0 * $t) + 0.28 * sin(2 * M_PI * 1320.0 * $t)));    }    private static function levelUp(): string    {        $notes = [523.25, 659.25, 783.99];        return self::wav(0.42, static function (float $t) use ($notes): float {            $part = min(2, (int)floor($t / 0.14)); $local = $t - $part * 0.14;            return 0.46 * exp(-28.0 * $local) * sin(2 * M_PI * $notes[$part] * $t);        });    }    private static function env(float $t, float $duration, float $attack = 0.003): float    {        return min(1.0, $t / max(0.0001, $attack)) * exp(-6.0 * $t / max(0.001, $duration));    }    private static function noise(int &$seed): float    {        $seed ^= ($seed << 13) & 0x7fffffff;        $seed ^= ($seed >> 17);        $seed ^= ($seed << 5) & 0x7fffffff;        $seed &= 0x7fffffff;        return ($seed / 1073741824.0) - 1.0;    }    private static function wav(float $duration, callable $sample): string    {        $count = max(1, (int)round(self::RATE * $duration));        $pcm = '';        for ($i = 0; $i < $count; $i++) {            $v = max(-1.0, min(1.0, (float)$sample($i / self::RATE, $i)));            $pcm .= pack('v', ((int)round($v * 32767.0)) & 0xffff);        }        $bytes = strlen($pcm);        return 'RIFF' . pack('V', 36 + $bytes) . 'WAVEfmt ' . pack('VvvVVvv', 16, 1, 1, self::RATE, self::RATE * 2, 2, 16) .            'data' . pack('V', $bytes) . $pcm;    }}