Auto-assign custom speech audio

The "Auto-name speech audio files?" option in the Speech Manager lets you toggle between having speech audio referred to manually, or automatically through naming convention.

When unchecked, audio file fields are exposed in the Speech Manager for each line, and the user can manually assign an AudioClip.  When checked, the audio is pulled at runtime from the Resources folder, provided that its location and filename matches its expected value.

For example, the Demo game's Player lines are audio files of the format:

/Resources/Speech/Brain39

This script lets you toggle between the two modes more easily, should audio files have already been assigned.  If your audio is currently manually-set, this script will rename and move the files into a Resources folder.  If automatically-set, it can manually link clips to each entry in the Speech Manager so that they can be moved out of the Resources folder.

To use, paste the code below into a C# script named CustomAudioManagement.cs, and place the file in a folder named Editor somewhere in your Project window.

You can then use the new links under "Adventure Creator -> Speech audio management" in the top toolbar.

```
using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEditor;

using AC;

public class CustomAudioManagement : MonoBehaviour

{

	[MenuItem ("Adventure Creator/Speech audio management/Assign Resources audio manually", false, 39)]

	static void AutoAssignAudio ()

	{

		if (EditorUtility.DisplayDialog ("Auto-assign audio", "This script will locate all 'Resources' speech audio files and assign them manually to their associated entry in the Speech Manager. It is recommended to backup your project beforehand. Continue?", "OK", "Cancel"))

		{

			bool overwrite = UnityEditor.EditorUtility.DisplayDialog ("Overwrite fields?", "If a line entry is found to already have audio manually assigned, should this process overwrite it?", "Yes", "No");

			if (AdvGame.GetReferences ().speechManager)

			{

				SpeechManager speechManager = AdvGame.GetReferences ().speechManager;

				speechManager.autoNameSpeechFiles = false;

				int numAssigned = 0;

				for (int i=0; i<speechManager.lines.Count; i++)

				{

					EditorUtility.DisplayProgressBar ("Renaming files..", "Please wait while the operation completes.", (float) (i) / (float) speechManager.lines.Count);

					SpeechLine line = speechManager.lines[i];

					if (line.textType == AC_TextType.Speech)

					{

						int lineNumUpdated = AssignAudioManually (speechManager, line, overwrite);

						numAssigned += lineNumUpdated;

					}

				}

				EditorUtility.ClearProgressBar ();

				EditorUtility.DisplayDialog ("Auto-assign audio", "Process complete. " + numAssigned + " lines were updated. The linked audio files can now be moved out of the Resources folder.", "OK");

			}

			else

			{

				Debug.LogWarning ("No Speech Manager assigned");

			}

		}

	}

	private static int AssignAudioManually (SpeechManager speechManager, SpeechLine line, bool overwrite)

	{

		int numUpdated = 0;

		if (AssignAudioManually (speechManager, line, 0, overwrite))

		{

			numUpdated ++;

		}

		if (speechManager.languages != null && speechManager.languages.Count > 1 && speechManager.translateAudio)

		{

			for (int i=1; i<speechManager.languages.Count; i++)

			{

				if (AssignAudioManually (speechManager, line, i, overwrite))

				{

					numUpdated ++;

				}

			}

		}

		return numUpdated;

	}

	private static bool AssignAudioManually (SpeechManager speechManager, SpeechLine line, int languageIndex, bool overwrite)

	{

		string languageName = (languageIndex <= 0) ? string.Empty : speechManager.languages[languageIndex];

		string fullFilename = KickStarter.speechManager.GetAutoAssetPathAndName (line.lineID, null, languageName, false);

		AudioClip clipObj = Resources.Load (fullFilename) as AudioClip;

		if (clipObj != null)

		{

			if (languageIndex > 0)

			{

				if (line.customTranslationAudioClips != null && line.customTranslationAudioClips.Count > (languageIndex-1))

				{

					if (line.customTranslationAudioClips[languageIndex-1] == null || overwrite)

					{

						line.customTranslationAudioClips[languageIndex-1] = clipObj;

					}

				}

			}

			else

			{

				if (line.customAudioClip == null || overwrite)

				{

					line.customAudioClip = clipObj;

				}

			}

			return true;

		}

		return false;

	}

	[MenuItem ("Adventure Creator/Speech audio management/Rename manual audio to automatic", false, 40)]

	static void RenameManualAudio ()

	{

		if (EditorUtility.DisplayDialog ("Rename manual audio", "This script will locate all audio files manually assigned in the Speech Manager, and rename them to the convention expected when 'Auto-name audio files?' is checked. The files will not be moved, so must still be placed in the appropriate Resources/Speech subfolder.  Continue?", "OK", "Cancel"))

		{

			bool move = UnityEditor.EditorUtility.DisplayDialog ("Move files?", "When complete, audio files will need to be located in a Resources/Speech subfolder.  Do you want renamed files to be moved automatically?", "Yes", "No");

			if (AdvGame.GetReferences ().speechManager)

			{

				SpeechManager speechManager = AdvGame.GetReferences ().speechManager;

				if (string.IsNullOrEmpty (speechManager.autoSpeechFolder))

				{

					speechManager.autoSpeechFolder = "Speech";

				}

				if (move)

				{

					if (!AssetDatabase.IsValidFolder ("Assets/Resources"))

					{

						AssetDatabase.CreateFolder ("Assets", "Resources");

					}

					if (!AssetDatabase.IsValidFolder ("Assets/Resources/" + speechManager.autoSpeechFolder))

					{

						AssetDatabase.CreateFolder ("Assets/Resources", speechManager.autoSpeechFolder);

					}

				}

				speechManager.autoNameSpeechFiles = true;

				speechManager.placeAudioInSubfolders = true;

				int numAssigned = 0;

				for (int i=0; i<speechManager.lines.Count; i++)

				{

					EditorUtility.DisplayProgressBar ("Renaming files..", "Please wait while the operation completes.", (float) (i) / (float) speechManager.lines.Count);

					SpeechLine line = speechManager.lines[i];

					if (line.textType == AC_TextType.Speech)

					{

						int lineNumUpdated = RenameAudio (speechManager, line, move);

						numAssigned += lineNumUpdated;

					}

				}

				AssetDatabase.SaveAssets ();

				EditorUtility.ClearProgressBar ();

				EditorUtility.DisplayDialog ("Renaming files", "Process complete. " + numAssigned + " lines were updated. The audio files should now be moved into a Resources folder.", "OK");

			}

			else

			{

				Debug.LogWarning ("No Speech Manager assigned");

			}

		}

	}

	private static int RenameAudio (SpeechManager speechManager, SpeechLine line, bool move)

	{

		int numUpdated = 0;

		if (RenameAudio (speechManager, line, 0, move))

		{

			numUpdated ++;

		}

		if (speechManager.languages != null && speechManager.languages.Count > 1 && speechManager.translateAudio)

		{

			for (int i=1; i<speechManager.languages.Count; i++)

			{

				if (RenameAudio (speechManager, line, i, move))

				{

					numUpdated ++;

				}

			}

		}

		return numUpdated;

	}

	private static bool RenameAudio (SpeechManager speechManager, SpeechLine line, int languageIndex, bool move)

	{

		AudioClip audioClip = (languageIndex <= 0) ? line.customAudioClip : line.customTranslationAudioClips [languageIndex-1];

		if (audioClip == null)

		{

			return false;

		}

		string fullFilenameAndPath = AssetDatabase.GetAssetPath (audioClip);

		if (string.IsNullOrEmpty (fullFilenameAndPath))

		{

			return false;;

		}

		int lastSlashIndex = fullFilenameAndPath.LastIndexOf ("/") + 1;

		int lastDotIndex = fullFilenameAndPath.LastIndexOf (".");

		if (lastSlashIndex <= 1 || lastDotIndex <= lastSlashIndex)

		{

			return false;

		}

		string newFilename = line.GetFilename () + line.lineID.ToString ();

		string error = AssetDatabase.RenameAsset (fullFilenameAndPath, newFilename);

		if (!string.IsNullOrEmpty (error))

		{

			Debug.LogWarning ("Error renaming '" + fullFilenameAndPath + "' - " + error);

			return false;

		}

		if (move)

		{

			fullFilenameAndPath = AssetDatabase.GetAssetPath (audioClip);

			string baseFolder = "Assets/Resources/" + speechManager.autoSpeechFolder;

			if (speechManager.placeAudioInSubfolders)

			{

				if (!AssetDatabase.IsValidFolder (baseFolder + "/" + line.GetFilename ()))

				{

					AssetDatabase.CreateFolder (baseFolder, line.GetFilename ());

				}

				baseFolder += "/" + line.GetFilename ();

			}

			if (languageIndex > 0)

			{

				string languageName = speechManager.languages[languageIndex];

				if (!AssetDatabase.IsValidFolder (baseFolder + "/" + languageName))

				{

					AssetDatabase.CreateFolder (baseFolder, languageName);

				}

				baseFolder += "/" + languageName;

			}

			baseFolder += "/" + newFilename;

			error = AssetDatabase.MoveAsset (fullFilenameAndPath, baseFolder);

			if (!string.IsNullOrEmpty (error))

			{

				Debug.LogWarning ("Error moving '" + fullFilenameAndPath + "' to '" + baseFolder + "' - " + error);

				return false;

			}

		}

		if (languageIndex <= 0)

		{

			line.customAudioClip = null;

		}

		else

		{

			line.customTranslationAudioClips[languageIndex-1] = null;

		}

		return true;

	}

}

```