using UnityEngine; /// /// Процедурный генератор звуковых эффектов и атмосферы для вступительной кат-сцены «Синтезия». /// Все звуки генерируются программно в памяти (AudioClip.Create) и не требуют внешних файлов. /// public static class IntroCutsceneAudio { private static int sampleRate = 44100; /// /// Низкий давящий гул заброшенного подземного бункера (зацикленный) /// 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; } /// /// Глухой ритмичный стук сердца (двойной удар тук-тук) /// 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; } /// /// Пиканье кардиомонитора (медицинский зуммер) /// 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; } /// /// Скрежет ногтей по стене и искаженный стон безумия /// 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; } /// /// Скрип сжатого в руке металла /// 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; } /// /// Гортанный хищный рык мутанта вдалеке /// 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; } /// /// Оглушительный удар металла о стену /// 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; } /// /// Яростный визг мутанта при броске /// 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; } /// /// Низкий басовый кинематографичный удар (Cinematic Boom) под появление логотипа SYNTHESIA /// 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; } }