using UnityEngine; using UnityEditor; using System.IO; /// /// 生成与 SpriteNoiseGlitch shader 三阶段对应的程序化音效。 /// 菜单: Tools > Generate Glitch Noise Audio /// public static class GlitchNoiseAudioGenerator { private const int SampleRate = 44100; private const float Duration = 4f; // 每段音效时长(秒),便于循环使用 private const string OutputFolder = "Assets/RawResources/Audio/GlitchNoise"; [MenuItem("Tools/Generate Glitch Noise Audio")] public static void Generate() { string dir = Path.Combine(Application.dataPath, "RawResources", "Audio", "GlitchNoise"); Directory.CreateDirectory(dir); GenerateStage1(dir); GenerateStage2(dir); GenerateStage3(dir); AssetDatabase.Refresh(); Debug.Log($"[GlitchNoise] 已生成三阶段音效至 Assets/RawResources/Audio/GlitchNoise"); } /// Stage 1: 轻微静态噪点 - 柔和白噪声 private static void GenerateStage1(string dir) { int samples = (int)(SampleRate * Duration); float[] data = new float[samples]; var rnd = new System.Random(12345); float gain = 0.12f; for (int i = 0; i < samples; i++) { data[i] = ((float)rnd.NextDouble() * 2f - 1f) * gain; } SaveWav(dir, "GlitchNoise_Stage1_Light.wav", data); } /// Stage 2: 中等 - 更多噪点 + 偶尔 glitch 爆音 private static void GenerateStage2(string dir) { int samples = (int)(SampleRate * Duration); float[] data = new float[samples]; var rnd = new System.Random(23456); float noiseGain = 0.22f; int glitchInterval = SampleRate / 4; // 约每 0.25 秒一次 glitch 爆音 for (int i = 0; i < samples; i++) { float n = ((float)rnd.NextDouble() * 2f - 1f) * noiseGain; // 随机 glitch 爆音 if (i > 0 && i % glitchInterval < 120) { float burst = ((float)rnd.NextDouble() * 2f - 1f) * 0.5f; n += burst * (1f - (i % glitchInterval) / 120f); } data[i] = Mathf.Clamp(n, -1f, 1f); } SaveWav(dir, "GlitchNoise_Stage2_Medium.wav", data); } /// Stage 3: 严重 - 强烈噪点 + 频繁 glitch + 数字故障感 private static void GenerateStage3(string dir) { int samples = (int)(SampleRate * Duration); float[] data = new float[samples]; var rnd = new System.Random(34567); float noiseGain = 0.4f; int blockSize = 2205; // 约 0.05 秒一块 int glitchBlockEvery = 4; for (int i = 0; i < samples; i++) { int block = i / blockSize; float n = ((float)rnd.NextDouble() * 2f - 1f) * noiseGain; // 块状 glitch:整块随机反转/爆音 if (block % glitchBlockEvery == 0) { int posInBlock = i % blockSize; float t = (float)posInBlock / blockSize; n += ((float)rnd.NextDouble() * 2f - 1f) * 0.6f * (1f - t); } // 随机“卡顿”短静音后爆音 if (rnd.NextDouble() < 0.0003) { int silenceLen = 100 + rnd.Next(300); int end = Mathf.Min(i + silenceLen, samples); for (int j = i; j < end; j++) { data[j] = j == end - 1 ? ((float)rnd.NextDouble() * 2f - 1f) * 0.8f : 0f; } i = end - 1; } else { data[i] = Mathf.Clamp(n, -1f, 1f); } } SaveWav(dir, "GlitchNoise_Stage3_Heavy.wav", data); } private static void SaveWav(string dir, string filename, float[] samples) { string path = Path.Combine(dir, filename); using (var fs = new FileStream(path, FileMode.Create)) using (var bw = new BinaryWriter(fs)) { // RIFF header bw.Write(new[] { 'R', 'I', 'F', 'F' }); int dataSize = samples.Length * 2; // 16-bit bw.Write(36 + dataSize); bw.Write(new[] { 'W', 'A', 'V', 'E' }); // fmt chunk bw.Write(new[] { 'f', 'm', 't', ' ' }); bw.Write(16); // chunk size bw.Write((short)1); // PCM bw.Write((short)1); // mono bw.Write(SampleRate); bw.Write(SampleRate * 2); bw.Write((short)2); bw.Write((short)16); // data chunk bw.Write(new[] { 'd', 'a', 't', 'a' }); bw.Write(dataSize); foreach (float s in samples) { short sample = (short)Mathf.Clamp((int)(s * 32767), -32768, 32767); bw.Write(sample); } } } }