Kursach_StealthAction/Assets/Scripts/IntroCutsceneAudio.cs

288 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
/// <summary>
/// Процедурный генератор звуковых эффектов и атмосферы для вступительной кат-сцены «Синтезия».
/// Все звуки генерируются программно в памяти (AudioClip.Create) и не требуют внешних файлов.
/// </summary>
public static class IntroCutsceneAudio
{
private static int sampleRate = 44100;
/// <summary>
/// Низкий давящий гул заброшенного подземного бункера (зацикленный)
/// </summary>
public static AudioClip CreateBunkerHumClip(float duration = 6f)
{
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
System.Random rnd = new System.Random(1337);
float lastNoise = 0f;
for (int i = 0; i < samples; i++)
{
float t = (float)i / sampleRate;
// Низкочастотный рокот бункера: 45 Гц + 68 Гц с биениями
float sub = Mathf.Sin(2f * Mathf.PI * 45f * t) * 0.45f;
float drone = Mathf.Sin(2f * Mathf.PI * 68f * t + Mathf.Sin(2f * Mathf.PI * 0.4f * t)) * 0.25f;
// Фильтрованный низкочастотный шум воздуха в вентиляции
float white = ((float)rnd.NextDouble() * 2f - 1f) * 0.15f;
lastNoise = Mathf.Lerp(lastNoise, white, 0.04f);
// Бесшовное зацикливание по краям
float edgeEnv = 1f;
float edgeTime = 0.5f;
if (t < edgeTime) edgeEnv = t / edgeTime;
else if (t > duration - edgeTime) edgeEnv = (duration - t) / edgeTime;
data[i] = (sub + drone + lastNoise) * edgeEnv * 0.7f;
}
AudioClip clip = AudioClip.Create("BunkerHum", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Глухой ритмичный стук сердца (двойной удар тук-тук)
/// </summary>
public static AudioClip CreateHeartbeatClip(float bpm = 65f)
{
float period = 60f / bpm;
int samples = (int)(sampleRate * period);
float[] data = new float[samples];
for (int i = 0; i < samples; i++)
{
float t = (float)i / sampleRate;
float val = 0f;
// Первый удар (Систола, 0.0с - 0.18с)
if (t < 0.20f)
{
float localT = t / 0.20f;
float env = Mathf.Sin(localT * Mathf.PI) * Mathf.Exp(-localT * 3.5f);
float freq = Mathf.Lerp(65f, 38f, localT);
val += Mathf.Sin(2f * Mathf.PI * freq * t) * env * 0.85f;
}
// Второй удар (Диастола, 0.24с - 0.44с)
float t2 = t - 0.24f;
if (t2 >= 0f && t2 < 0.20f)
{
float localT = t2 / 0.20f;
float env = Mathf.Sin(localT * Mathf.PI) * Mathf.Exp(-localT * 4.0f);
float freq = Mathf.Lerp(55f, 34f, localT);
val += Mathf.Sin(2f * Mathf.PI * freq * t2) * env * 0.65f;
}
data[i] = Mathf.Clamp(val, -1f, 1f);
}
AudioClip clip = AudioClip.Create("Heartbeat", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Пиканье кардиомонитора (медицинский зуммер)
/// </summary>
public static AudioClip CreateHeartMonitorBeepClip()
{
float duration = 0.14f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
float env = Mathf.Sin(t * Mathf.PI);
// Чистый чирп частоты 940 Гц
float tone = Mathf.Sin(2f * Mathf.PI * 940f * ((float)i / sampleRate));
data[i] = tone * env * 0.35f;
}
AudioClip clip = AudioClip.Create("HeartMonitorBeep", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Скрежет ногтей по стене и искаженный стон безумия
/// </summary>
public static AudioClip CreateScratchAndGroanClip()
{
float duration = 3.2f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
System.Random rnd = new System.Random(42);
float lastVal = 0f;
for (int i = 0; i < samples; i++)
{
float t = (float)i / sampleRate;
// Скрежет ногтей по бетону (высокочастотный фрикционный скрежет)
float scratchNoise = ((float)rnd.NextDouble() * 2f - 1f);
float scratchFilt = scratchNoise - lastVal;
lastVal = scratchNoise * 0.45f;
float scratchMod = Mathf.Sin(2f * Mathf.PI * 7.5f * t) * 0.5f + 0.5f;
float scratch = scratchFilt * scratchMod * 0.22f;
// Заглушенный утробный стон
float groanEnv = Mathf.Sin(Mathf.Clamp01(t / 2.8f) * Mathf.PI);
float groanFreq = Mathf.Lerp(140f, 90f, t / 3.2f) + Mathf.Sin(2f * Mathf.PI * 5f * t) * 12f;
float groan = Mathf.Sin(2f * Mathf.PI * groanFreq * t) * groanEnv * 0.35f;
data[i] = (scratch + groan) * 0.75f;
}
AudioClip clip = AudioClip.Create("ScratchGroan", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Скрип сжатого в руке металла
/// </summary>
public static AudioClip CreateMetalGripClip()
{
float duration = 1.4f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
float env = Mathf.Sin(t * Mathf.PI) * Mathf.Exp(-t * 2.2f);
// Высокий металлический скрип напряжения
float creak = Mathf.Sin(2f * Mathf.PI * (1450f + Mathf.Sin(t * 40f) * 350f) * ((float)i / sampleRate));
float lowClank = Mathf.Sin(2f * Mathf.PI * 220f * ((float)i / sampleRate)) * Mathf.Exp(-t * 8f);
data[i] = (creak * 0.25f + lowClank * 0.45f) * env;
}
AudioClip clip = AudioClip.Create("MetalGrip", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Гортанный хищный рык мутанта вдалеке
/// </summary>
public static AudioClip CreateDistantGrowlClip()
{
float duration = 2.4f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
System.Random rnd = new System.Random(999);
for (int i = 0; i < samples; i++)
{
float t = (float)i / sampleRate;
float env = Mathf.Sin(Mathf.Clamp01(t / 2.4f) * Mathf.PI);
// Вибрирующий гортанный рык
float am = Mathf.Sin(2f * Mathf.PI * 28f * t) * 0.5f + 0.5f;
float freq = Mathf.Lerp(110f, 65f, t / 2.4f);
float tone = Mathf.Sin(2f * Mathf.PI * freq * t) * am;
float noise = ((float)rnd.NextDouble() * 2f - 1f) * 0.35f * am;
data[i] = (tone * 0.6f + noise * 0.4f) * env * 0.65f;
}
AudioClip clip = AudioClip.Create("DistantGrowl", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Оглушительный удар металла о стену
/// </summary>
public static AudioClip CreateMetalClangClip()
{
float duration = 1.8f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
System.Random rnd = new System.Random(555);
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
// Ударный импульс
float impEnv = Mathf.Exp(-t * 22f);
float ringEnv = Mathf.Exp(-t * 3.5f);
float noise = ((float)rnd.NextDouble() * 2f - 1f) * impEnv * 0.8f;
// Металлические гармоники гаечного ключа (звон 440, 880, 1320, 2400 Гц)
float tone1 = Mathf.Sin(2f * Mathf.PI * 520f * ((float)i / sampleRate));
float tone2 = Mathf.Sin(2f * Mathf.PI * 1150f * ((float)i / sampleRate));
float tone3 = Mathf.Sin(2f * Mathf.PI * 2350f * ((float)i / sampleRate));
float harmonics = (tone1 * 0.45f + tone2 * 0.35f + tone3 * 0.2f) * ringEnv;
data[i] = (noise + harmonics) * 0.9f;
}
AudioClip clip = AudioClip.Create("MetalClang", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Яростный визг мутанта при броске
/// </summary>
public static AudioClip CreateFuriousScreechClip()
{
float duration = 1.6f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
System.Random rnd = new System.Random(777);
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
float env = Mathf.Sin(t * Mathf.PI) * Mathf.Exp(-t * 1.8f);
// Резкий частотный спад от 1600 Гц до 450 Гц с жестким дисторшном
float freq = Mathf.Lerp(1600f, 450f, t);
float tone = Mathf.Sin(2f * Mathf.PI * freq * ((float)i / sampleRate));
float noise = ((float)rnd.NextDouble() * 2f - 1f) * 0.4f;
float raw = (tone + noise) * env * 1.5f;
data[i] = Mathf.Clamp(raw, -0.9f, 0.9f); // Сатурация
}
AudioClip clip = AudioClip.Create("FuriousScreech", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
/// <summary>
/// Низкий басовый кинематографичный удар (Cinematic Boom) под появление логотипа SYNTHESIA
/// </summary>
public static AudioClip CreateCinematicBoomClip()
{
float duration = 3.5f;
int samples = (int)(sampleRate * duration);
float[] data = new float[samples];
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
// Ударный спад
float subEnv = Mathf.Exp(-t * 1.6f);
// Скольжение частоты саб-баса: 110 Гц -> 36 Гц
float freq = Mathf.Lerp(110f, 36f, Mathf.Pow(t, 0.6f));
float sub = Mathf.Sin(2f * Mathf.PI * freq * ((float)i / sampleRate));
// Теплый обертон
float harmonic = Mathf.Sin(2f * Mathf.PI * (freq * 2.05f) * ((float)i / sampleRate)) * 0.35f;
data[i] = (sub + harmonic) * subEnv * 0.95f;
}
AudioClip clip = AudioClip.Create("CinematicBoom", samples, 1, sampleRate, false);
clip.SetData(data, 0);
return clip;
}
}