using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; namespace OCES.Audio { public static class AudioImportTool { const string k_audioResourcePath = "Audios"; const string k_audioConfigPath = "AudioData"; static string AudioAbsolutePath { get { return Path.Combine(Application.dataPath, "Resources", k_audioResourcePath); } } static string ConfigAbsolutePath { get { return Path.Combine(Application.dataPath, "Resources", k_audioConfigPath); } } [MenuItem("Tools/Audio/Apply Audio Import Settings")] public static void RunFromMenu() { if (EditorUtility.DisplayDialog( "Apply Audio Import Settings", $"将对 {AudioAbsolutePath} 下所有文件重新应用导入设置,确认继续?", "确认", "取消")) { Run(); } } /// /// Executes the audio import tool from the command line in batch mode. /// This method is designed to be called via Unity's -executeMethod command line argument /// and serves as the entry point for automated audio import workflows. /// It initializes the process and delegates to the main Run method to apply /// audio import settings to all supported audio files in the configured directory. /// public static void RunCli() { Debug.Log("[AudioImportTool] CLI 模式启动"); Run(); } public static void Run() { // 1. 加载配置表 var audioObjectConfig = AudioConfigLoader.Load(ConfigAbsolutePath, "AudioObject.bytes"); var musicSegmentConfig = AudioConfigLoader.Load(ConfigAbsolutePath, "MusicSegment.bytes"); if (audioObjectConfig == null || musicSegmentConfig == null) { Debug.LogError("[AudioImportTool] 配置表加载失败,终止"); return; } // 2. 扫描文件 List supportedExtensions = new() { ".wav", ".ogg" }; DirectoryInfo dir = new(AudioAbsolutePath); FileInfo[] files = dir.GetFiles().Where(f => supportedExtensions.Contains(f.Extension.ToLower())).ToArray(); int total = files.Length, processed = 0, failed = 0; AssetDatabase.StartAssetEditing(); // 批量操作,暂停自动刷新 try { foreach (FileInfo file in files) { // 转成 Assets/... 相对路径供 AssetDatabase 使用 string assetPath = "Assets" + file.FullName .Replace(Application.dataPath, "") .Replace("\\", "/"); EditorUtility.DisplayProgressBar( "Audio Import Tool", $"处理: {file.Name} ({processed}/{total})", (float)processed / total); bool ok = ProcessFile(assetPath, file.Name, audioObjectConfig, musicSegmentConfig); if (ok) processed++; else failed++; } } finally { EditorUtility.ClearProgressBar(); AssetDatabase.StopAssetEditing(); AssetDatabase.SaveAssets(); } Debug.Log($"[AudioImportTool] 完成:{processed} 成功,{failed} 失败,共 {total} 个文件"); } static bool ProcessFile( string assetPath, string fileName, AudioObjectConfig audioObjectConfig, MusicSegmentConfig musicSegmentConfig) { AudioImporter importer = AssetImporter.GetAtPath(assetPath) as AudioImporter; if (!importer) { Debug.LogWarning($"[AudioImportTool] 无法获取 AudioImporter: {assetPath}"); return false; } AudioClip clip = AssetDatabase.LoadAssetAtPath(assetPath); if (!clip) { Debug.LogWarning($"[AudioImportTool] 无法加载 AudioClip: {assetPath}"); return false; } float duration = clip.length; string fileNameNoExt = Path.GetFileNameWithoutExtension(fileName); AudioCategory category = ClassifyAudio(fileNameNoExt, audioObjectConfig, musicSegmentConfig, out AudioObject audioObject); importer.ClearSampleSettingOverride("Android"); importer.ClearSampleSettingOverride("iOS"); AudioImporterSampleSettings settings = importer.defaultSampleSettings; settings.compressionFormat = AudioCompressionFormat.Vorbis; settings.sampleRateSetting = AudioSampleRateSetting.OverrideSampleRate; settings.preloadAudioData = audioObject?.Haptic != 0; switch (category) { case AudioCategory.Music: settings.sampleRateOverride = 44100; settings.quality = 0.13f; settings.loadType = duration switch { <= 5 => AudioClipLoadType.DecompressOnLoad, >= 15 => AudioClipLoadType.Streaming, _ => AudioClipLoadType.CompressedInMemory, }; break; case AudioCategory.Voice: case AudioCategory.SFX: default: settings.sampleRateOverride = 22050; // 音效2022.3.62f3没有32kHz这一档,要是有的话这一档其实最合适 settings.quality = 0.5f; settings.loadType = duration switch { >= 15 => AudioClipLoadType.Streaming, _ => AudioClipLoadType.DecompressOnLoad, }; break; } importer.defaultSampleSettings = settings; importer.forceToMono = false; importer.SaveAndReimport(); return true; } enum AudioCategory { Music, SFX, Voice } static AudioCategory ClassifyAudio( string fileName, // 不含扩展名 AudioObjectConfig audioObjectConfig, MusicSegmentConfig musicSegmentConfig, out AudioObject matchedObject) { matchedObject = null; // 1. MusicSegment 表命中 → Music MusicSegment segment = musicSegmentConfig.MusicSegmentList() .FirstOrDefault(musicSegment => musicSegment.Name == fileName); if (segment != null) return AudioCategory.Music; // 2. AudioObject 表命中 → 按 MixingType AudioObject audioObject = audioObjectConfig.AudioObjectList() .FirstOrDefault(audioObject => audioObject.Name != null && audioObject.Name.Contains(fileName)); if (audioObject != null) { matchedObject = audioObject; return audioObject.MixingType == MixingType.Voice ? AudioCategory.Voice : AudioCategory.SFX; // SFX + Accent 都走 SFX 分支 } // 3. 文件名 fallback string lower = fileName.ToLowerInvariant(); if (lower.Contains("music") || lower.Contains("bgm")) return AudioCategory.Music; if (lower.Contains("sfx")) return AudioCategory.SFX; if (lower.Contains("voice")) return AudioCategory.Voice; // 4. 完全兜底 Debug.LogWarning($"[AudioImportTool] 无法分类: {fileName},默认当作 SFX 处理"); return AudioCategory.SFX; } } }