Once I received such a demand: to display the length of a character's voice on the interface and count down when playing. When I saw this demand at that time, I thought I would directly call the function provided by the official to obtain the event length, but when I did it, I found that I was naive.
In the function interface provided by the government (aksoundeengine class), I have searched over and over for functions that do not get the duration of an event. I can only find ways to get the information by myself. Where can I get it?
At that time, our project will use the Wwise event to configure the audio in the Timeline. In the Timeline, the length of the event can be seen. (the name of the event is smeared out and the leaked project information is placed, although I don't know why I should be so cautious.)
Find the corresponding script and see how to get the event length.
Search for the AkTimelineEventPlayable script in the project, and you can find it through akutilities Geteventdurations delegate. The final delegate is:
eureka? Don't worry. Look at the top of the script file. The script content can only be used under UnityEditor and cannot be called after final packaging, including AkWwiseProjectInfo script.
But since it can be obtained under the unitydeditor, I can get it myself and copy it in the project.
So here comes the solution~
Solution
Direct code
- WwiseInfoCollector.cs, menu script under editor
[MenuItem("WWISE/Collect Event Duration")] private static void GenerateCharacterVoiceInfo() { // NOTE the classes and methods for reading resources here are encapsulated by our project and must be replaced by ourselves. // Read to determine whether there is asset resource, if not, create ScriptWwiseInfo wwiseInfo = AssetLibrary.LoadAsset<ScriptWwiseInfo>(WwiseInfoHolder.WwiseInfoDataPath, true); if (wwiseInfo == null) { wwiseInfo = ScriptableObject.CreateInstance<ScriptWwiseInfo>(); AssetDatabase.CreateAsset(wwiseInfo, WwiseInfoHolder.WwiseInfoDataPath); } var wwiseProjectData = AkWwiseProjectInfo.GetData(); // Redeposit information wwiseInfo.EventInfos = new List<WwiseEvent>(); foreach (var wwu in wwiseProjectData.EventWwu) { // Here, only the voice part of the character is transferred according to the path rule of the event, and the rule is replaced or the judgment is deleted for all events. if (wwu.ParentPath.Contains("Character")) { foreach (var wwuEvent in wwu.List) { wwiseInfo.EventInfos.Add(new WwiseEvent() { Id = wwuEvent.Id, Name = wwuEvent.Name, DurationMin = wwuEvent.minDuration, DurationMax = wwuEvent.maxDuration, }); } break; } } // preservation. asset file EditorUtility.SetDirty(wwiseInfo); AssetDatabase.SaveAssets(); }
- WwiseInfoHolder.cs, the script used by the runtime to get the event length. There is a variable called PlayNormalPrefix, which is a unified prefix for playing audio events in our project. It is not necessary (there may be other events with Stop_ prefix, etc.). Realize the query method of using string (event name) and uint (event id, which can be obtained from Wwise_IDs script. See article 1 in the corner below for details).
public class WwiseInfoHolder { public const string WwiseInfoDataName = "WwiseEventDurations.asset"; public static readonly string WwiseInfoDataPath = "Assets/Wwise/ScriptableObjects/" + WwiseInfoDataName; private readonly ScriptWwiseInfo _wwiseInfo; private const string PlayNormalPrefix = "Play_"; public WwiseInfoHolder() { // NOTE the classes and methods for reading resources here are encapsulated by our project and must be replaced by ourselves. _wwiseInfo = AssetLibrary.LoadAsset<ScriptWwiseInfo>(WwiseInfoDataPath, true); if (_wwiseInfo == null) WwiseLogger.LogMessage(WwiseLogger.LogLevel.Warning, "WwiseInfoData load failed."); } /// <summary> /// Get sound duration.Only for character voice currently. /// </summary> /// <param name="soundName"></param> /// <param name="durationMin"></param> /// <param name="durationMax"></param> public bool TryGetCharacterVoiceDuration(string soundName, out float durationMin, out float durationMax) { durationMin = -1; durationMax = -1; if (_wwiseInfo == null) { WwiseLogger.LogMessage(WwiseLogger.LogLevel.Warning, "WwiseInfoData was not loaded."); return false; } var eventName = PlayNormalPrefix + soundName; var result = _wwiseInfo.EventInfos.Find((wwiseEvent) => wwiseEvent.Name.ToLower() == eventName.ToLower()); if (result == null) { WwiseLogger.LogMessage(WwiseLogger.LogLevel.Warning, string.Format("Didn't find duration of event named <{0}>", eventName)); return false; } durationMin = result.DurationMin; durationMax = result.DurationMax; return true; } /// <summary> /// Get sound duration.Only for character voice currently. /// </summary> /// <param name="eventId">Wwise event id, defined in <see cref="AK.EVENTS"/></param> /// <param name="durationMin"></param> /// <param name="durationMax"></param> public bool TryGetCharacterVoiceDuration(uint eventId, out float durationMin, out float durationMax) { durationMin = -1; durationMax = -1; if (_wwiseInfo == null) { WwiseLogger.LogMessage(WwiseLogger.LogLevel.Warning, "WwiseInfoData was not loaded."); return false; } var result = _wwiseInfo.EventInfos.Find((wwiseEvent) => wwiseEvent.Id == eventId); if (result == null) { WwiseLogger.LogMessage(WwiseLogger.LogLevel.Warning, string.Format("Didn't find event duration with id <{0}>", eventId)); return false; } durationMin = result.DurationMin; durationMax = result.DurationMax; return true; } }
- ScriptWwiseInfo.cs, used to generate The data structure script of the asset file.
[Serializable] public class ScriptWwiseInfo : ScriptableObject { public List<WwiseEvent> EventInfos; } [Serializable] public class WwiseEvent { public uint Id; public string Name; public float DurationMin; public float DurationMax; }
matters needing attention
- Some events are of circular playback type, and the above methods cannot be used for circular playback type
- Event duration of non playback type is 0
- It is necessary to call the above menu script once every time or every time the audio content is updated or packaged to keep the latest length information.
Corner
-
uint type event ID
According to the official methods (such as AkSoundEngine.Post()), there are overloaded methods with uint type parameters, and the uint type ID identifying the event is Wwise stored in the exported content_ IDs. H script, which can be used for the illusory engine. If you want to use it for Unity, you need to convert it.
In the Unity menu bar, assets > Wwise > Convert Wwise soundbank IDS, but this method always needs to manually select the directory and then put the generated script into the project. So search the name of his menu item directly in the IDE, find the conversion script AkWwiseIDConverter, copy the conversion function and write one to read directly according to the path c file conversion to cs coexists in the function of the project.
private static readonly string s_converterScript = Path.Combine( Path.Combine(Path.Combine(Application.dataPath, "Wwise"), "Tools"), "WwiseIDConverter.py"); private static readonly string s_progTitle = "WwiseUnity: Converting SoundBank IDs"; [MenuItem("WWISE/Convert Wwise_Ids.h into C# and replace")] public static void ConvertWwiseId() { var wwiseAssetsPath = Path.Combine(Application.streamingAssetsPath, AkWwiseEditorSettings.Instance.SoundbankPath); var bankIdHeaderPath = Path.Combine(wwiseAssetsPath, "Wwise_IDs.h"); if (string.IsNullOrEmpty(bankIdHeaderPath)) { Debug.Log("WwiseUnity: User canceled the action."); return; } var start = new System.Diagnostics.ProcessStartInfo(); start.FileName = "python"; start.Arguments = string.Format("\"{0}\" \"{1}\"", s_converterScript, bankIdHeaderPath); start.UseShellExecute = false; start.RedirectStandardOutput = true; var progMsg = "WwiseUnity: Converting C++ SoundBank IDs into C# ..."; EditorUtility.DisplayProgressBar(s_progTitle, progMsg, 0.5f); using (var process = System.Diagnostics.Process.Start(start)) { process.WaitForExit(); try { //ExitCode throws InvalidOperationException if the process is hanging if (process.ExitCode == 0) { EditorUtility.DisplayProgressBar(s_progTitle, progMsg, 1.0f); Debug.Log(string.Format( "WwiseUnity: SoundBank ID conversion succeeded. Find generated Unity script under {0}.", bankIdHeaderPath)); ReplaceOldWwiseIDsFile(wwiseAssetsPath); } else Debug.LogError("WwiseUnity: Conversion failed."); AssetDatabase.Refresh(); } catch (Exception ex) { AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); Debug.LogError(string.Format( "WwiseUnity: SoundBank ID conversion process failed with exception: {0}. Check detailed logs under the folder: Assets/Wwise/Logs.", ex)); } EditorUtility.ClearProgressBar(); } } private static void ReplaceOldWwiseIDsFile(string wwiseAssetsPath) { var bankIdCsharp = "Wwise_IDs.cs"; var bankIdCSharpPath = Path.Combine(wwiseAssetsPath, bankIdCsharp); var wwisePackagePath = Path.Combine(Path.Combine(Application.dataPath, "Wwise"), bankIdCsharp); File.Replace(bankIdCSharpPath, wwisePackagePath, null); }