├── Documentation~
├── Example.gif
├── Generated Code Files.png
└── Github Header.jpg
├── Editor.meta
├── Editor
├── AudioReferenceDropdown.cs
├── AudioReferenceDropdown.cs.meta
├── AudioReferencePropertyDrawer.cs
├── AudioReferencePropertyDrawer.cs.meta
├── CodeGenerator.cs
├── CodeGenerator.cs.meta
├── Extensions.meta
├── Extensions
│ ├── BankEditorExtensions.cs
│ ├── BankEditorExtensions.cs.meta
│ ├── BusEditorExtensions.cs
│ ├── BusEditorExtensions.cs.meta
│ ├── EditorEventRefExtensions.cs
│ ├── EditorEventRefExtensions.cs.meta
│ ├── EditorParamRefExtensions.cs
│ ├── EditorParamRefExtensions.cs.meta
│ ├── MemberInfoExtensions.cs
│ ├── MemberInfoExtensions.cs.meta
│ ├── SerializedPropertyExtensions.cs
│ ├── SerializedPropertyExtensions.cs.meta
│ ├── TypeExtensions.cs
│ ├── TypeExtensions.cs.meta
│ ├── VCAEditorExtensions.cs
│ └── VCAEditorExtensions.cs.meta
├── FmodCodeGenerator.cs
├── FmodCodeGenerator.cs.meta
├── FmodSettingsProvider.cs
├── FmodSettingsProvider.cs.meta
├── FmodSyntaxSettingsEditor.cs
├── FmodSyntaxSettingsEditor.cs.meta
├── FmodSyntaxUtilities.cs
├── FmodSyntaxUtilities.cs.meta
├── Resources.meta
├── Resources
│ ├── Templates.meta
│ └── Templates
│ │ ├── Fmod.meta
│ │ └── Fmod
│ │ ├── Banks.meta
│ │ ├── Banks
│ │ ├── FmodBankField.cs.txt
│ │ ├── FmodBankField.cs.txt.meta
│ │ ├── FmodBanks.cs.txt
│ │ └── FmodBanks.cs.txt.meta
│ │ ├── Buses.meta
│ │ ├── Buses
│ │ ├── FmodBusField.cs.txt
│ │ ├── FmodBusField.cs.txt.meta
│ │ ├── FmodBuses.cs.txt
│ │ └── FmodBuses.cs.txt.meta
│ │ ├── Events.meta
│ │ ├── Events
│ │ ├── FmodEnum.cs.txt
│ │ ├── FmodEnum.cs.txt.meta
│ │ ├── FmodEventConfigPlayMethodWithParameters.cs.txt
│ │ ├── FmodEventConfigPlayMethodWithParameters.cs.txt.meta
│ │ ├── FmodEventField.cs.txt
│ │ ├── FmodEventField.cs.txt.meta
│ │ ├── FmodEventFolder.cs.txt
│ │ ├── FmodEventFolder.cs.txt.meta
│ │ ├── FmodEventParameter.cs.txt
│ │ ├── FmodEventParameter.cs.txt.meta
│ │ ├── FmodEventParametersInitialization.cs.txt
│ │ ├── FmodEventParametersInitialization.cs.txt.meta
│ │ ├── FmodEventPlaybackPlayMethodWithParameters.cs.txt
│ │ ├── FmodEventPlaybackPlayMethodWithParameters.cs.txt.meta
│ │ ├── FmodEventType.cs.txt
│ │ ├── FmodEventType.cs.txt.meta
│ │ ├── FmodEventTypes.cs.txt
│ │ ├── FmodEventTypes.cs.txt.meta
│ │ ├── FmodEvents.cs.txt
│ │ ├── FmodEvents.cs.txt.meta
│ │ ├── FmodGlobalParameter.cs.txt
│ │ ├── FmodGlobalParameter.cs.txt.meta
│ │ ├── FmodGlobalParameters.cs.txt
│ │ └── FmodGlobalParameters.cs.txt.meta
│ │ ├── FMOD-Syntax.asmdef.txt
│ │ ├── FMOD-Syntax.asmdef.txt.meta
│ │ ├── Snapshots.meta
│ │ ├── Snapshots
│ │ ├── FmodSnapshotFields.cs.txt
│ │ ├── FmodSnapshotFields.cs.txt.meta
│ │ ├── FmodSnapshotType.cs.txt
│ │ ├── FmodSnapshotType.cs.txt.meta
│ │ ├── FmodSnapshotTypes.cs.txt
│ │ ├── FmodSnapshotTypes.cs.txt.meta
│ │ ├── FmodSnapshots.cs.txt
│ │ └── FmodSnapshots.cs.txt.meta
│ │ ├── VCAs.meta
│ │ └── VCAs
│ │ ├── FmodVCAField.cs.txt
│ │ ├── FmodVCAField.cs.txt.meta
│ │ ├── FmodVCAs.cs.txt
│ │ └── FmodVCAs.cs.txt.meta
├── RoyTheunissen.FMODSyntax.Editor.asmdef
├── RoyTheunissen.FMODSyntax.Editor.asmdef.meta
├── SetupWizard.cs
├── SetupWizard.cs.meta
├── SnapshotReferenceDropdown.cs
├── SnapshotReferenceDropdown.cs.meta
├── SnapshotReferencePropertyDrawer.cs
├── SnapshotReferencePropertyDrawer.cs.meta
├── Utilities.meta
└── Utilities
│ ├── EditorAssetReference.cs
│ ├── EditorAssetReference.cs.meta
│ ├── EditorPreference.cs
│ └── EditorPreference.cs.meta
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── AudioReference.cs
├── AudioReference.cs.meta
├── Banks.meta
├── Banks
│ ├── BankExtensions.cs
│ └── BankExtensions.cs.meta
├── Buses.meta
├── Buses
│ ├── Bus.cs
│ ├── Bus.cs.meta
│ ├── BusExtensions.cs
│ └── BusExtensions.cs.meta
├── Callbacks.meta
├── Callbacks
│ ├── IOnFmodPlayback.cs
│ └── IOnFmodPlayback.cs.meta
├── Events.meta
├── Events
│ ├── FmodAudioConfig.cs
│ ├── FmodAudioConfig.cs.meta
│ ├── FmodAudioFolder.cs
│ ├── FmodAudioFolder.cs.meta
│ ├── FmodAudioPlayback.cs
│ ├── FmodAudioPlayback.cs.meta
│ ├── FmodParameterlessAudio.cs
│ ├── FmodParameterlessAudio.cs.meta
│ ├── FmodPlayableConfig.cs
│ ├── FmodPlayableConfig.cs.meta
│ ├── FmodPlayablePlaybackBase.cs
│ ├── FmodPlayablePlaybackBase.cs.meta
│ ├── Parameter.cs
│ └── Parameter.cs.meta
├── Extensions.meta
├── Extensions
│ ├── StringExtensions.cs
│ └── StringExtensions.cs.meta
├── FmodLabelEnum.cs
├── FmodLabelEnum.cs.meta
├── FmodSyntaxSettings.cs
├── FmodSyntaxSettings.cs.meta
├── FmodSyntaxSystem.cs
├── FmodSyntaxSystem.cs.meta
├── IAudioConfig.cs
├── IAudioConfig.cs.meta
├── IAudioPlayback.cs
├── IAudioPlayback.cs.meta
├── RoyTheunissen.FMODSyntax.asmdef
├── RoyTheunissen.FMODSyntax.asmdef.meta
├── Snapshots.meta
├── Snapshots
│ ├── FmodSnapshotConfig.cs
│ ├── FmodSnapshotConfig.cs.meta
│ ├── FmodSnapshotPlayback.cs
│ ├── FmodSnapshotPlayback.cs.meta
│ ├── SnapshotReference.cs
│ └── SnapshotReference.cs.meta
├── VCAs.meta
└── VCAs
│ ├── VCA.cs
│ ├── VCA.cs.meta
│ ├── VCAExtensions.cs
│ └── VCAExtensions.cs.meta
├── package.json
└── package.json.meta
/Documentation~/Example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RoyTheunissen/FMOD-Syntax/1543a6bd00242d364ec3307a7b969726f6b815f1/Documentation~/Example.gif
--------------------------------------------------------------------------------
/Documentation~/Generated Code Files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RoyTheunissen/FMOD-Syntax/1543a6bd00242d364ec3307a7b969726f6b815f1/Documentation~/Generated Code Files.png
--------------------------------------------------------------------------------
/Documentation~/Github Header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RoyTheunissen/FMOD-Syntax/1543a6bd00242d364ec3307a7b969726f6b815f1/Documentation~/Github Header.jpg
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 19a3ff78dd603fc4fa288a82d52ddaf1
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/AudioReferenceDropdown.cs:
--------------------------------------------------------------------------------
1 | using UnityEditor;
2 | using UnityEditor.IMGUI.Controls;
3 | using FMODUnity;
4 | using System.Linq;
5 |
6 | namespace RoyTheunissen.FMODSyntax
7 | {
8 | ///
9 | /// Dropdown to pick audio references from a list in a searchable way / with subfolders.
10 | ///
11 | public sealed class AudioReferenceDropdown : AdvancedDropdown
12 | {
13 | private readonly SerializedProperty serializedProperty;
14 |
15 | public AudioReferenceDropdown(AdvancedDropdownState state, SerializedProperty serializedProperty)
16 | : base(state)
17 | {
18 | this.serializedProperty = serializedProperty;
19 | }
20 |
21 | protected override AdvancedDropdownItem BuildRoot()
22 | {
23 | AudioConfigDropdownItem root = new AudioConfigDropdownItem(
24 | this, string.Empty, "Audio Configs", string.Empty);
25 |
26 | EditorEventRef[] parameterlessEvents = EventManager.Events
27 | .Where(e => e.Path.StartsWith(EditorEventRefExtensions.EventPrefix) && e.LocalParameters.Count == 0)
28 | .OrderBy(e => e.Path)
29 | .ToArray();
30 | string[] paths = new string[parameterlessEvents.Length];
31 | string[] guids = new string[parameterlessEvents.Length];
32 |
33 | root.AddChildByPath("None", "None");
34 |
35 | for (int i = 0; i < parameterlessEvents.Length; i++)
36 | {
37 | // Remove the event prefix otherwise it gets treated as a folder.
38 | string path = parameterlessEvents[i].Path;
39 | path = path.RemovePrefix(EditorEventRefExtensions.EventPrefix);
40 | paths[i] = path;
41 |
42 | guids[i] = parameterlessEvents[i].Guid.ToString();
43 | }
44 |
45 | for (int i = 0; i < paths.Length; i++)
46 | {
47 | root.AddChildByPath(guids[i], paths[i]);
48 | }
49 |
50 | return root;
51 | }
52 |
53 | protected override void ItemSelected(AdvancedDropdownItem item)
54 | {
55 | base.ItemSelected(item);
56 |
57 | AudioConfigDropdownItem dropdownItem = (AudioConfigDropdownItem)item;
58 |
59 | serializedProperty.serializedObject.Update();
60 | serializedProperty.stringValue = dropdownItem.Guid == "None" ? string.Empty : dropdownItem.Guid;
61 | serializedProperty.serializedObject.ApplyModifiedProperties();
62 | }
63 | }
64 |
65 | public sealed class AudioConfigDropdownItem : AdvancedDropdownItem
66 | {
67 | private const char Separator = '/';
68 |
69 | private readonly AudioReferenceDropdown dropdown;
70 |
71 | private string path;
72 |
73 | private string guid;
74 | public string Guid => guid;
75 |
76 | public AudioConfigDropdownItem(
77 | AudioReferenceDropdown dropdown, string guid, string name, string path) : base(name)
78 | {
79 | this.dropdown = dropdown;
80 | this.guid = guid;
81 | this.path = path;
82 | }
83 |
84 | private AudioConfigDropdownItem AddChild(string guid, string name)
85 | {
86 | string newPath = string.IsNullOrEmpty(path) ? name : path + Separator + name;
87 |
88 | AudioConfigDropdownItem child = new AudioConfigDropdownItem(dropdown, guid, name, newPath);
89 |
90 | AddChild(child);
91 |
92 | return child;
93 | }
94 |
95 | private AudioConfigDropdownItem GetOrCreateChild(string guid, string name)
96 | {
97 | // Find a child with the specified name.
98 | foreach (AdvancedDropdownItem child in children)
99 | {
100 | if (child.name == name)
101 | return (AudioConfigDropdownItem)child;
102 | }
103 |
104 | // Add a new one if it didn't exist yet.
105 | return AddChild(guid, name);
106 | }
107 |
108 | public void AddChildByPath(string guid, string relativePath)
109 | {
110 | // Leaf node, add the event there.
111 | if (!relativePath.Contains(Separator))
112 | {
113 | AddChild(guid, relativePath);
114 | return;
115 | }
116 |
117 | string[] sections = relativePath.Split(Separator);
118 |
119 | // Ensure a child exists for the first section of the path.
120 | // This acts as a folder and and does not have a key itself.
121 | AudioConfigDropdownItem firstSection = GetOrCreateChild(string.Empty, sections[0]);
122 |
123 | // Determine the path relative to this first child.
124 | string pathRemaining = string.Empty;
125 | for (int i = 1; i < sections.Length; i++)
126 | {
127 | pathRemaining += sections[i];
128 |
129 | if (i < sections.Length - 1)
130 | pathRemaining += Separator;
131 | }
132 |
133 | // Continue recursively from the first section.
134 | firstSection.AddChildByPath(guid, pathRemaining);
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/Editor/AudioReferenceDropdown.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 79dc00952e9106c4ba77ca8b6d55e3f7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/AudioReferencePropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | using FMODUnity;
2 | using UnityEditor;
3 | using UnityEditor.IMGUI.Controls;
4 | using UnityEngine;
5 | using GUID = FMOD.GUID;
6 |
7 | namespace RoyTheunissen.FMODSyntax
8 | {
9 | ///
10 | /// Draws dropdowns for selecting an audio config.
11 | ///
12 | [CustomPropertyDrawer(typeof(AudioReference))]
13 | public class AudioReferencePropertyDrawer : PropertyDrawer
14 | {
15 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
16 | {
17 | // If this is an array, it would just show "Element 0" as the label which takes up a lot of space and is
18 | // useless. Even more useless is that it actually sees that the first property of AudioReference is a string
19 | // and shows that as the name instead for an array. That just means that it shows the GUID as the label.
20 | // HOW USEFUL. How about we don't show a label at all and just have a wider field that's easier to read?
21 | if (property.IsInArray())
22 | label = GUIContent.none;
23 |
24 | SerializedProperty audioConfigProperty = property.FindPropertyRelative("fmodEventGuid");
25 |
26 | // Figure out the display text and the content property.
27 | string displayedText;
28 | string guid = audioConfigProperty.stringValue;
29 | if (string.IsNullOrEmpty(guid))
30 | {
31 | displayedText = "";
32 | }
33 | else
34 | {
35 | GUID id = GUID.Parse(guid);
36 | EditorEventRef eventRef = EventManager.EventFromGUID(id);
37 | displayedText = eventRef.GetDisplayName();
38 | }
39 |
40 | // Draw a dropdown button to select the audio config.
41 | EditorGUI.BeginProperty(position, label, audioConfigProperty);
42 | Rect valueRect = EditorGUI.PrefixLabel(position, label);
43 | bool didPress = EditorGUI.DropdownButton(
44 | valueRect, new GUIContent(displayedText), FocusType.Keyboard);
45 | if (didPress)
46 | {
47 | Rect dropDownRect = position;
48 | dropDownRect.xMax += 200;
49 |
50 | AudioReferenceDropdown menu = new AudioReferenceDropdown(new AdvancedDropdownState(), audioConfigProperty);
51 | menu.Show(dropDownRect);
52 | }
53 | EditorGUI.EndProperty();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Editor/AudioReferencePropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d5afffc01088ad74cbb240d67ba72d56
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/CodeGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using UnityEditor;
5 | using UnityEngine;
6 | using UnityEngine.Assertions;
7 |
8 | namespace RoyTheunissen.FMODSyntax
9 | {
10 | ///
11 | /// Utility for generating code from a template .txt file.
12 | ///
13 | public sealed class CodeGenerator
14 | {
15 | private const string TemplateSuffix = ".txt";
16 |
17 | private const string KeywordStart = "##";
18 | private const string KeywordEnd = "##";
19 |
20 | private const string Nl = "\r\n";
21 |
22 | private string defaultPath;
23 | private string contents;
24 |
25 | private readonly EditorAssetReference textAsset;
26 |
27 | private bool isInitialized;
28 |
29 | public CodeGenerator(string templateFileName)
30 | {
31 | textAsset = new EditorAssetReference(templateFileName);
32 |
33 | // By default, just write to the folder where the template is.
34 | defaultPath = templateFileName.RemoveSuffix(TemplateSuffix);
35 | }
36 |
37 | private void Initialize()
38 | {
39 | if (isInitialized)
40 | return;
41 |
42 | isInitialized = true;
43 |
44 | Assert.IsNotNull(textAsset.Asset, $"Tried to load code template '{textAsset.Path}' which didn't exist.");
45 |
46 | Reset();
47 | }
48 |
49 | public void Reset()
50 | {
51 | contents = textAsset.Asset.text;
52 | }
53 |
54 | private string GetKeywordFormatted(string keyword)
55 | {
56 | return KeywordStart + keyword + KeywordEnd;
57 | }
58 |
59 | public bool HasKeyword(string keyword)
60 | {
61 | keyword = GetKeywordFormatted(keyword);
62 | return contents.Contains(keyword);
63 | }
64 |
65 | public void ReplaceKeyword(string keyword, string code, bool removeLineIfCodeIsEmpty = false)
66 | {
67 | Initialize();
68 |
69 | if (string.IsNullOrEmpty(keyword))
70 | return;
71 |
72 | bool isCodeEmpty = string.IsNullOrEmpty(code);
73 |
74 | if (isCodeEmpty && removeLineIfCodeIsEmpty)
75 | {
76 | RemoveKeywordLines(keyword);
77 | return;
78 | }
79 |
80 | keyword = GetKeywordFormatted(keyword);
81 |
82 | if (isCodeEmpty)
83 | {
84 | contents = contents.Replace(keyword, code);
85 | return;
86 | }
87 |
88 | // Make indentation consistent...
89 | code = code.Replace("\t", " ");
90 |
91 | int indexOfKeyword = contents.IndexOf(keyword, StringComparison.Ordinal);
92 | while (indexOfKeyword != -1)
93 | {
94 | // Determine the whitespace immediately preceding the keyword.
95 | string whitespacePreceding = contents.GetWhitespacePreceding(indexOfKeyword, false);
96 |
97 | // Remove the keyword.
98 | contents = contents.Remove(indexOfKeyword, keyword.Length);
99 |
100 | // Now apply the correct indentation to every line of the code.
101 | string codeWithIndentation = string.Empty;
102 | string[] codeLines = code.TrimEnd().Split("\n");
103 | for (int i = 0; i < codeLines.Length; i++)
104 | {
105 | // The first line doesn't need extra indentation because it already has it.
106 | if (i > 0)
107 | codeWithIndentation += whitespacePreceding;
108 | codeWithIndentation += codeLines[i];
109 |
110 | if (i < codeLines.Length - 1)
111 | codeWithIndentation += "\n";
112 | }
113 |
114 | // Now add the correctly formatted code at the specified position.
115 | contents = contents.Insert(indexOfKeyword, codeWithIndentation);
116 |
117 | // See if there's another keyword that should be replaced.
118 | indexOfKeyword = contents.IndexOf(keyword, StringComparison.Ordinal);
119 | }
120 | }
121 |
122 | public void RemoveKeywordLines(string keyword)
123 | {
124 | Initialize();
125 |
126 | if (string.IsNullOrEmpty(keyword))
127 | return;
128 |
129 | keyword = GetKeywordFormatted(keyword);
130 |
131 | List lines = new List(contents.Split("\n"));
132 | for (int i = lines.Count - 1; i >= 0; i--)
133 | {
134 | if (lines[i].Contains(keyword))
135 | lines.RemoveAt(i);
136 | }
137 |
138 | contents = string.Join("\n", lines);
139 | }
140 |
141 | public string GetCode()
142 | {
143 | Initialize();
144 |
145 | return contents;
146 | }
147 |
148 | public void GenerateFile(string path = null)
149 | {
150 | Initialize();
151 |
152 | string pathAbsolute =
153 | string.IsNullOrEmpty(path) ? defaultPath.GetAbsolutePath() : path.GetAbsolutePath();
154 |
155 | if (!File.Exists(pathAbsolute))
156 | {
157 | Directory.CreateDirectory(Path.GetDirectoryName(pathAbsolute));
158 | StreamWriter writeStream = File.CreateText(pathAbsolute);
159 | writeStream.Write(GetCode());
160 | writeStream.Flush();
161 | writeStream.Close();
162 | }
163 | else
164 | File.WriteAllText(pathAbsolute, GetCode());
165 |
166 | AssetDatabase.Refresh();
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/Editor/CodeGenerator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4a72ba2bd2680e24b85a3a3ea76d6de1
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4e03ebd0ed0f28c46a7e0bc37582201d
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Extensions/BankEditorExtensions.cs:
--------------------------------------------------------------------------------
1 | using RoyTheunissen.FMODSyntax;
2 |
3 | namespace FMOD.Studio
4 | {
5 | ///
6 | /// Extensions for bank to get the path without an out parameter because to make lambda functions easy to write.
7 | ///
8 | public static class BankEditorExtensions
9 | {
10 | public static string GetName(this Bank bank)
11 | {
12 | return FmodSyntaxUtilities.GetFilteredNameFromPath(bank.getPath());
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Editor/Extensions/BankEditorExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2e8e09e9174c82d4ea69845b9e6b1305
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/BusEditorExtensions.cs:
--------------------------------------------------------------------------------
1 | using RoyTheunissen.FMODSyntax;
2 |
3 | namespace FMOD.Studio
4 | {
5 | ///
6 | /// Extensions for bus to get the path without an out parameter because to make lambda functions easy to write.
7 | ///
8 | public static class BusEditorExtensions
9 | {
10 | public static string GetName(this Bus bus)
11 | {
12 | return FmodSyntaxUtilities.GetFilteredNameFromPath(bus.getPath());
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Editor/Extensions/BusEditorExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fa1facdb911386e42bf43466f016d8de
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/EditorEventRefExtensions.cs:
--------------------------------------------------------------------------------
1 | using FMODUnity;
2 |
3 | namespace RoyTheunissen.FMODSyntax
4 | {
5 | ///
6 | /// Useful extension methods for EditorEventRef.
7 | ///
8 | public static class EditorEventRefExtensions
9 | {
10 | public const string EventPrefix = "event:/";
11 | public const string SnapshotPrefix = "snapshot:/";
12 |
13 | public static string GetDisplayName(this EditorEventRef @event)
14 | {
15 | return FmodSyntaxUtilities.GetDisplayNameFromPath(@event.name);
16 | }
17 |
18 | public static string GetFilteredName(this EditorEventRef @event)
19 | {
20 | return FmodSyntaxUtilities.GetFilteredNameFromPath(@event.name);
21 | }
22 |
23 | public static string GetFieldName(this EditorEventRef @event)
24 | {
25 | return FmodSyntaxUtilities.GetFilteredNameFromPathLowerCase(@event.name);
26 | }
27 |
28 | public static string GetFilteredPath(this EditorEventRef @event, bool stripSpecialCharacters = false)
29 | {
30 | return FmodSyntaxUtilities.GetFilteredPath(@event.Path, stripSpecialCharacters);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Editor/Extensions/EditorEventRefExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2b0f5b1d8012caf4a81416d63f736d2d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/EditorParamRefExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FMODUnity;
3 | using UnityEngine;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Useful extension methods for EditorParamRef.
9 | ///
10 | public static class EditorParamRefExtensions
11 | {
12 | public static string GetFilteredName(this EditorParamRef parameter)
13 | {
14 | return FmodSyntaxUtilities.GetFilteredNameFromPath(parameter.Name);
15 | }
16 |
17 | public static string GetArgumentName(this EditorParamRef parameter)
18 | {
19 | return FmodSyntaxUtilities.GetFilteredNameFromPathLowerCase(parameter.Name);
20 | }
21 |
22 | public static bool HasNormalizedRange(this EditorParamRef parameter) =>
23 | Mathf.Approximately(parameter.Min, 0.0f) && Mathf.Approximately(parameter.Max, 1.0f);
24 |
25 | private static string GetLabelParameterTypeName(
26 | this EditorParamRef parameter, bool fullyQualified, EditorEventRef @event)
27 | {
28 | string name = parameter.GetFilteredName();
29 | bool hasUserEnum = FmodCodeGenerator.GetUserSpecifiedLabelParameterType(name, out Type userEnum);
30 | if (hasUserEnum)
31 | return userEnum.FullName;
32 |
33 | string type = $"{name}Values";
34 |
35 | if (fullyQualified)
36 | type = $"{@event.GetFilteredName()}Playback." + type;
37 |
38 | return type;
39 | }
40 |
41 | public static string GetWrapperType(this EditorParamRef parameter)
42 | {
43 | switch (parameter.Type)
44 | {
45 | default:
46 | return "ParameterFloat";
47 | case ParameterType.Discrete:
48 | return parameter.HasNormalizedRange() ? "ParameterBool" : "ParameterInt";
49 | case ParameterType.Labeled:
50 | {
51 | #if SCRIPTABLE_OBJECT_COLLECTION
52 | string name = parameter.GetFilteredName();
53 | bool hasUserType = FmodCodeGenerator.GetUserSpecifiedLabelParameterType(name, out Type userType);
54 | if (hasUserType && !typeof(Enum).IsAssignableFrom(userType))
55 | return $"ParameterScriptableObjectCollectionItem<{parameter.GetLabelParameterTypeName(false, null)}>";
56 | #endif // SCRIPTABLE_OBJECT_COLLECTION
57 |
58 | return $"ParameterEnum<{parameter.GetLabelParameterTypeName(false, null)}>";
59 | }
60 | }
61 | }
62 |
63 | public static string GetArgumentType(this EditorParamRef parameter)
64 | {
65 | switch (parameter.Type)
66 | {
67 | default:
68 | return "float";
69 | case ParameterType.Discrete:
70 | return parameter.HasNormalizedRange() ? "bool" : "int";
71 | case ParameterType.Labeled:
72 | return $"{parameter.GetLabelParameterTypeName(false, null)}";
73 | }
74 | }
75 |
76 | public static string GetArgumentTypeFullyQualified(this EditorParamRef parameter, EditorEventRef @event)
77 | {
78 | string type = parameter.GetArgumentType();
79 | if (parameter.Type == ParameterType.Labeled)
80 | type = parameter.GetLabelParameterTypeName(true, @event);
81 | return type;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Editor/Extensions/EditorParamRefExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 068ee796b2dd5d04480e943b36fbc692
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/MemberInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace RoyTheunissen.FMODSyntax
7 | {
8 | public static class MemberInfoExtensions
9 | {
10 | public static T GetAttribute(this MemberInfo memberInfo, bool inherit = true)
11 | where T : Attribute
12 | {
13 | object[] attributes = memberInfo.GetCustomAttributes(inherit);
14 | return attributes.OfType().FirstOrDefault();
15 | }
16 |
17 | public static bool HasAttribute(this MemberInfo memberInfo, bool inherit = true)
18 | where T : Attribute
19 | {
20 | object[] attributes = memberInfo.GetCustomAttributes(inherit);
21 | return attributes.OfType().Any();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Editor/Extensions/MemberInfoExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 81ec3cf01af8bf343a61d77ead7b597a
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/SerializedPropertyExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text.RegularExpressions;
3 | using UnityEditor;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Useful extension methods for EditorParamRef.
9 | ///
10 | public static class SerializedPropertyExtensions
11 | {
12 | ///
13 | /// From: https://gist.github.com/monry/9de7009689cbc5050c652bcaaaa11daa
14 | ///
15 | public static SerializedProperty GetParent(this SerializedProperty serializedProperty)
16 | {
17 | string[] propertyPaths = serializedProperty.propertyPath.Split('.');
18 | if (propertyPaths.Length <= 1)
19 | return default;
20 |
21 | SerializedProperty parentSerializedProperty =
22 | serializedProperty.serializedObject.FindProperty(propertyPaths.First());
23 | for (int index = 1; index < propertyPaths.Length - 1; index++)
24 | {
25 | if (propertyPaths[index] == "Array")
26 | {
27 | if (index + 1 == propertyPaths.Length - 1)
28 | {
29 | // reached the end
30 | break;
31 | }
32 | if (propertyPaths.Length > index + 1 && Regex.IsMatch(propertyPaths[index + 1], "^data\\[\\d+\\]$"))
33 | {
34 | Match match = Regex.Match(propertyPaths[index + 1], "^data\\[(\\d+)\\]$");
35 | int arrayIndex = int.Parse(match.Groups[1].Value);
36 | parentSerializedProperty = parentSerializedProperty.GetArrayElementAtIndex(arrayIndex);
37 | index++;
38 | }
39 | }
40 | else
41 | {
42 | parentSerializedProperty = parentSerializedProperty.FindPropertyRelative(propertyPaths[index]);
43 | }
44 | }
45 |
46 | return parentSerializedProperty;
47 | }
48 |
49 | public static bool IsInArray(this SerializedProperty serializedProperty)
50 | {
51 | SerializedProperty parent = serializedProperty.GetParent();
52 |
53 | if (parent == null)
54 | return false;
55 |
56 | return parent.isArray;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Editor/Extensions/SerializedPropertyExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a4bc8b960164ed04eb3c52ebe5d03071
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/TypeExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace RoyTheunissen.FMODSyntax
5 | {
6 | ///
7 | /// Useful extension methods for EditorParamRef.
8 | ///
9 | public static class TypeExtensions
10 | {
11 | public static Type[] GetAllTypesWithAttribute(bool includeAbstract = true)
12 | where T : Attribute
13 | {
14 | return AppDomain.CurrentDomain.GetAssemblies()
15 | .SelectMany(a => a.GetTypes())
16 | .Where(t => t.HasAttribute() && (includeAbstract || !t.IsAbstract)).ToArray();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Editor/Extensions/TypeExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: eaff6c4f01ccb5347aeded551238c288
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Extensions/VCAEditorExtensions.cs:
--------------------------------------------------------------------------------
1 | using RoyTheunissen.FMODSyntax;
2 |
3 | namespace FMOD.Studio
4 | {
5 | ///
6 | /// Extensions for bus to get the path without an out parameter because to make lambda functions easy to write.
7 | ///
8 | public static class VCAEditorExtensions
9 | {
10 | public static string GetName(this VCA vca)
11 | {
12 | return FmodSyntaxUtilities.GetFilteredNameFromPath(vca.getPath());
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Editor/Extensions/VCAEditorExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9e813911a175d7e40aafd2411a769586
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/FmodCodeGenerator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 63207498fd557844a9a89bd4f843df8b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/FmodSettingsProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEditor;
3 |
4 | #if FMOD_AUTO_REGENERATE_CODE
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Exposes serialized editor-time FMOD preferences.
9 | ///
10 | public static class FmodPreferences
11 | {
12 | public static readonly EditorPreferenceBool GenerateCodeAutomaticallyPreference =
13 | new EditorPreferenceBool("FMOD/Generate Code Automatically", true);
14 | }
15 |
16 | ///
17 | /// Provides a window with which to tweak FMOD preferences such as whether to generate code automatically or not.
18 | ///
19 | public class FmodSettingsProvider : SettingsProvider
20 | {
21 | public FmodSettingsProvider(string path, SettingsScope scopes, IEnumerable keywords = null)
22 | : base(path, scopes, keywords)
23 | {
24 | }
25 |
26 | public override void OnGUI(string searchContext)
27 | {
28 | base.OnGUI(searchContext);
29 |
30 | EditorGUILayout.Space();
31 | FmodPreferences.GenerateCodeAutomaticallyPreference.DrawGUILayoutLeft();
32 | }
33 |
34 | [SettingsProvider]
35 | public static SettingsProvider CreateFMODSettingsProvider()
36 | {
37 | var provider = new FmodSettingsProvider("Preferences/FMOD", SettingsScope.User)
38 | {
39 | label = "FMOD",
40 | keywords = new HashSet(new[] { "FMOD", "Audio" })
41 | };
42 |
43 | return provider;
44 | }
45 | }
46 | }
47 | #endif // FMOD_AUTO_REGENERATE_CODE
48 |
--------------------------------------------------------------------------------
/Editor/FmodSettingsProvider.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 488576f2fa669c24ebb57dbf0ed12c8b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/FmodSyntaxSettingsEditor.cs:
--------------------------------------------------------------------------------
1 | using UnityEditor;
2 | using UnityEngine;
3 |
4 | namespace RoyTheunissen.FMODSyntax
5 | {
6 | ///
7 | /// Draws a button for re-generating FMOD code.
8 | ///
9 | [CustomEditor(typeof(FmodSyntaxSettings))]
10 | public class FmodSyntaxSettingsEditor : Editor
11 | {
12 | public override void OnInspectorGUI()
13 | {
14 | serializedObject.Update();
15 | base.OnInspectorGUI();
16 | serializedObject.ApplyModifiedProperties();
17 |
18 | // Draw a button to generate FMOD code. This is particularly useful to have here because once you are done
19 | // tweaking the settings, you are likely to want to re-generate code anyway.
20 | EditorGUILayout.Space();
21 | bool shouldGenerateCode = GUILayout.Button("Generate Code", GUILayout.Height(40));
22 | if (shouldGenerateCode)
23 | FmodCodeGenerator.GenerateCode();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Editor/FmodSyntaxSettingsEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 931a0c2a865530e40aea0b4f88b99b42
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/FmodSyntaxUtilities.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Useful utility methods for the FMOD Syntax.
9 | ///
10 | public static class FmodSyntaxUtilities
11 | {
12 | private static readonly Dictionary replacements = new Dictionary()
13 | {
14 | { "base", "@base" },
15 | };
16 |
17 | private static readonly Dictionary substitutions = new Dictionary()
18 | {
19 | { "-", "_" },
20 | { " ", "" },
21 | { ".", "" },
22 | { "(", "" },
23 | { ")", "" },
24 | { "&", "And" },
25 | };
26 |
27 | public static string Filter(string name, bool performReplacements = true)
28 | {
29 | if (performReplacements)
30 | {
31 | foreach (KeyValuePair replacement in replacements)
32 | {
33 | if (name == replacement.Key)
34 | return replacement.Value;
35 | }
36 | }
37 |
38 | foreach (KeyValuePair substitution in substitutions)
39 | {
40 | name = name.Replace(substitution.Key, substitution.Value);
41 | }
42 |
43 | return name;
44 | }
45 |
46 | public static string GetDisplayNameFromPath(string path)
47 | {
48 | return Path.GetFileName(path);
49 | }
50 |
51 | public static string GetFilteredNameFromPath(string path)
52 | {
53 | string name = Path.GetFileName(path).ToPascalCasing();
54 | name = Filter(name);
55 | return name;
56 | }
57 |
58 | public static string GetFilteredNameFromPathLowerCase(string path)
59 | {
60 | string name = GetFilteredNameFromPath(path).ToCamelCasing();
61 | name = Filter(name);
62 | return name;
63 | }
64 |
65 | public static string GetFilteredPath(string path, bool stripSpecialCharacters)
66 | {
67 | if (string.IsNullOrEmpty(path))
68 | return string.Empty;
69 |
70 | const char separator = '/';
71 |
72 | // Events start with something like event:/ , so get rid of that first.
73 | path = path.Substring(path.IndexOf(separator, StringComparison.Ordinal) + 1);
74 |
75 | if (stripSpecialCharacters)
76 | {
77 | // Clean up every section a bit.
78 | string[] pathSections = path.Split(separator);
79 | for (int i = 0; i < pathSections.Length; i++)
80 | {
81 | pathSections[i] = pathSections[i].ToPascalCasing();
82 | pathSections[i] = Filter(pathSections[i], false);
83 | }
84 |
85 | path = string.Join(separator, pathSections);
86 | }
87 |
88 | return path;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Editor/FmodSyntaxUtilities.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fc901f3ea6389004bb35433168a2a3e4
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Resources.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 71925b42d3892a3499dcbf63879d1d31
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1a686c0c3d6f2a44fbb4b7ccfa06856c
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 54f74ae49e1b4bb478c1551717844e6c
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Banks.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 66358b99ce7ac824baef31d437999f40
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Banks/FmodBankField.cs.txt:
--------------------------------------------------------------------------------
1 | public static readonly string ##BankName## = "##BankPath##";
2 |
3 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Banks/FmodBankField.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 174f5f9b8db97714fa68ae70dd3ebac4
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Banks/FmodBanks.cs.txt:
--------------------------------------------------------------------------------
1 | namespace ##Namespace##
2 | {
3 | ///
4 | /// GENERATED: Contains FMOD banks so they can be accessed in a strongly-typed manner.
5 | ///
6 | public static class AudioBanks
7 | {
8 | ##Banks##
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Banks/FmodBanks.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 38c472dd142c8a34bb565a31740da9d8
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Buses.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6f8850eaaa5c0b14787b4fd2a739a50c
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Buses/FmodBusField.cs.txt:
--------------------------------------------------------------------------------
1 | public static readonly Bus ##BusName## = new Bus("##BusPath##");
2 |
3 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Buses/FmodBusField.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: af8bfc2375c239b49965fe664792d165
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Buses/FmodBuses.cs.txt:
--------------------------------------------------------------------------------
1 | using RoyTheunissen.FMODSyntax;
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains FMOD buses so they can be accessed in a strongly-typed manner.
7 | ///
8 | public static class AudioBuses
9 | {
10 | ##Buses##
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Buses/FmodBuses.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c2a391e0c6b479f4b88f7ac9c81e5b5e
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3e8149d83d8cc514881405f86b99be62
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEnum.cs.txt:
--------------------------------------------------------------------------------
1 | public enum ##Name##
2 | {
3 | ##Values##
4 | }
5 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEnum.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 34235fc742135d04ba0c67fbbd548265
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventConfigPlayMethodWithParameters.cs.txt:
--------------------------------------------------------------------------------
1 |
2 | public ##EventName##Playback Play(Transform source, ##ParameterArgumentsWithType##)
3 | {
4 | ##EventName##Playback instance = new ##EventName##Playback();
5 | instance.Play(EventDescription, source, ##ParameterArguments##);
6 | return instance;
7 | }
8 |
9 | public ##EventName##Playback Play(##ParameterArgumentsWithType##)
10 | {
11 | return Play(null, ##ParameterArguments##);
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventConfigPlayMethodWithParameters.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 01d00435ae4ef734bbc2016a51c46279
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventField.cs.txt:
--------------------------------------------------------------------------------
1 | ##Attributes##
2 | public static readonly ##EventName##Config ##EventName## = new ##EventName##Config("##GUID##");
3 |
4 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventField.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 062ef2aacc2d8e349bce13d62a4ec33c
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventFolder.cs.txt:
--------------------------------------------------------------------------------
1 | public sealed partial class ##FolderName####BaseType##
2 | {
3 | ##Subfolders##
4 | ##EventTypes##
5 | ##EventTypeAliases##
6 | ##Events##
7 | ##EventAliases##
8 | }
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventFolder.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d9f4d72b6dbc00341a6243e35ba786ac
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventParameter.cs.txt:
--------------------------------------------------------------------------------
1 | ##ParameterEnum##
2 | public readonly ##ParameterType## ##ParameterName## = new ##ParameterType##(new PARAMETER_ID { data1 = ##ID1##, data2 = ##ID2## }, false);
3 |
4 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventParameter.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d10121bab27a9d74e87ce1baac4bd3ff
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventParametersInitialization.cs.txt:
--------------------------------------------------------------------------------
1 | protected override void InitializeParameters()
2 | {
3 | base.InitializeParameters();
4 |
5 | ##EventParametersInitialization##
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventParametersInitialization.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f92cedd8d9d9d8546afff76b27155f7e
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventPlaybackPlayMethodWithParameters.cs.txt:
--------------------------------------------------------------------------------
1 | public void Play(EventDescription eventDescription, Transform source, ##ParameterArgumentsWithType##)
2 | {
3 | Play(eventDescription, source);
4 |
5 | ##ParameterInitializationsFromArguments##
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventPlaybackPlayMethodWithParameters.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 467afe0517051a74c84ede82e3de9d3a
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventType.cs.txt:
--------------------------------------------------------------------------------
1 | public sealed class ##EventName##Config : FmodAudioConfig<##EventName##Playback>
2 | {
3 | public ##EventName##Config(string guid) : base(guid) { }
4 |
5 | public override ##EventName##Playback Play(Transform source = null)
6 | {
7 | ##EventName##Playback instance = new ##EventName##Playback();
8 | instance.Play(EventDescription, source);
9 | return instance;
10 | }
11 | ##ConfigPlayMethodWithParameters##
12 | }
13 | ##Attributes##
14 | public sealed class ##EventName##Playback : FmodAudioPlayback
15 | {
16 | ##EventParameters##
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventType.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a43b1a605d41e2149a82070129407bc4
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventTypes.cs.txt:
--------------------------------------------------------------------------------
1 | ##UsingDirectives##
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains definition of FMOD events which is separated out from the declaration for readability.
7 | /// To get an overview of which folders and events exist see 'FmodEvents.cs'
8 | ///
9 | ##Events##
10 | }
11 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEventTypes.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0d3dedbaef1b8d547b1dae92da4d6099
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEvents.cs.txt:
--------------------------------------------------------------------------------
1 | ##UsingDirectives##
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains FMOD event configs so they can be called in a strongly-typed manner to produce instances.
7 | /// For readability's sake we only define the folders and fields in this file so you can easily get an overview of
8 | /// the events that exist. The definitions of the classes in question can be found in 'FmodEventTypes.cs'
9 | ///
10 | ##Events##
11 |
12 | [Preserve]
13 | public static class AudioParameterlessEvents
14 | {
15 | public static readonly Dictionary EventsByGuid =
16 | new Dictionary
17 | {
18 | ##ParameterlessEventIds##
19 | };
20 | }
21 |
22 | /* ---------------------------------------------- METADATA ------------------------------------------------------
23 | ##MetaData##
24 | ------------------------------------------------- METADATA --------------------------------------------------- */
25 | }
26 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodEvents.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 653d81bbd1daae54eaf97bbc9eafd6fb
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodGlobalParameter.cs.txt:
--------------------------------------------------------------------------------
1 | ##ParameterEnum##
2 | public static readonly ##ParameterType## ##ParameterName## = new ##ParameterType##(new PARAMETER_ID { data1 = ##ID1##, data2 = ##ID2## }, true);
3 |
4 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodGlobalParameter.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6ac439fa414cd474a96c63fbb7f5ec73
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodGlobalParameters.cs.txt:
--------------------------------------------------------------------------------
1 | ##UsingDirectives##
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains FMOD global parameters so they can be called in a strongly-typed manner.
7 | ///
8 | public static class AudioGlobalParameters
9 | {
10 | ##GlobalParameters##
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Events/FmodGlobalParameters.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 00e848c62e78c384fb4abbc0030c2fad
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/FMOD-Syntax.asmdef.txt:
--------------------------------------------------------------------------------
1 | {
2 | "name": "##Name##",
3 | "rootNamespace": "##Namespace##",
4 | "references": [
5 | "GUID:f28b76e6ba53ea24ca2daf55c1581312",
6 | "GUID:0c752da273b17c547ae705acf0f2adf2"
7 | ],
8 | "includePlatforms": [],
9 | "excludePlatforms": [],
10 | "allowUnsafeCode": false,
11 | "overrideReferences": false,
12 | "precompiledReferences": [],
13 | "autoReferenced": true,
14 | "defineConstraints": [],
15 | "versionDefines": [],
16 | "noEngineReferences": false
17 | }
18 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/FMOD-Syntax.asmdef.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dc252742681cda740a3873db3abc60a9
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3f745a8789110df4bb572289e12f6cd4
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotFields.cs.txt:
--------------------------------------------------------------------------------
1 | public static readonly FmodSnapshotConfig ##SnapshotName## = new FmodSnapshotConfig("##GUID##");
2 |
3 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotFields.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d107c8fa0fb4db94aa93a7719cb16972
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotType.cs.txt:
--------------------------------------------------------------------------------
1 | public sealed class ##EventName##Config : FmodSnapshotConfig<##EventName##Playback>
2 | {
3 | public ##EventName##Config(string guid) : base(guid) { }
4 |
5 | public override ##EventName##Playback Play()
6 | {
7 | ##EventName##Playback instance = new ##EventName##Playback();
8 | instance.Play(EventDescription);
9 | return instance;
10 | }
11 | ##ConfigPlayMethodWithParameters##
12 | }
13 | ##Attributes##
14 | public sealed class ##EventName##Playback : FmodSnapshotPlayback
15 | {
16 | ##EventParameters##
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotType.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4319304daf4bd3842be3426174e00b41
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotTypes.cs.txt:
--------------------------------------------------------------------------------
1 | ##UsingDirectives##
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains definition of FMOD snapshots which is separated out from the declaration for readability.
7 | /// To get an overview of which folders and events exist see 'FmodSnapshots.cs'
8 | ///
9 | ##Events##
10 | }
11 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshotTypes.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 14ee39780660f2d43ac1edc8a3ffecaa
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshots.cs.txt:
--------------------------------------------------------------------------------
1 | ##UsingDirectives##
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains FMOD snapshot configs so they can be called in a strongly-typed manner to produce instances.
7 | /// For readability's sake we only define the folders and fields in this file so you can easily get an overview of
8 | /// the events that exist. The definitions of the classes in question can be found in 'FmodSnapshotTypes.cs'
9 | ///
10 | ##Events##
11 |
12 | /* ---------------------------------------------- METADATA ------------------------------------------------------
13 | ##MetaData##
14 | ------------------------------------------------- METADATA --------------------------------------------------- */
15 | }
16 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/Snapshots/FmodSnapshots.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 78a1bcab036d63a4c841b79a54119bb9
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/VCAs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c1ad4bf92acaa4a429e524795017102e
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/VCAs/FmodVCAField.cs.txt:
--------------------------------------------------------------------------------
1 | public static readonly VCA ##VCAName## = new VCA("##VCAPath##");
2 |
3 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/VCAs/FmodVCAField.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f549756ff96b2c741898d8afbc821adf
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/VCAs/FmodVCAs.cs.txt:
--------------------------------------------------------------------------------
1 | using RoyTheunissen.FMODSyntax;
2 |
3 | namespace ##Namespace##
4 | {
5 | ///
6 | /// GENERATED: Contains FMOD VCAs so they can be accessed in a strongly-typed manner.
7 | ///
8 | public static class AudioVCAs
9 | {
10 | ##VCAs##
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Editor/Resources/Templates/Fmod/VCAs/FmodVCAs.cs.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7760576ded9f70347abb205d8bcadfbe
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/RoyTheunissen.FMODSyntax.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RoyTheunissen.FMODSyntax.Editor",
3 | "rootNamespace": "RoyTheunissen.FMODSyntax",
4 | "references": [
5 | "GUID:f28b76e6ba53ea24ca2daf55c1581312",
6 | "GUID:0c752da273b17c547ae705acf0f2adf2",
7 | "GUID:aab3caaf43456d6449a3e035348ff798"
8 | ],
9 | "includePlatforms": [
10 | "Editor"
11 | ],
12 | "excludePlatforms": [],
13 | "allowUnsafeCode": false,
14 | "overrideReferences": false,
15 | "precompiledReferences": [],
16 | "autoReferenced": true,
17 | "defineConstraints": [],
18 | "versionDefines": [
19 | {
20 | "name": "com.brunomikoski.scriptableobjectcollection",
21 | "expression": "2.2.1",
22 | "define": "SCRIPTABLE_OBJECT_COLLECTION"
23 | }
24 | ],
25 | "noEngineReferences": false
26 | }
--------------------------------------------------------------------------------
/Editor/RoyTheunissen.FMODSyntax.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 908a1ca5dca0e3a428aedca6231395e4
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/SetupWizard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using UnityEditor;
4 | using System.IO;
5 |
6 | namespace RoyTheunissen.FMODSyntax
7 | {
8 | ///
9 | /// Window to show to users when they haven't set up the FMOD Syntax system yet to let them conveniently
10 | /// initialize it with appropriate settings.
11 | ///
12 | public class SetupWizard : EditorWindow
13 | {
14 | private string settingsFolderPath = string.Empty;
15 | private string generatedScriptsFolderPath = "Generated/Scripts/FMOD";
16 |
17 | private string namespaceForGeneratedCode;
18 | private bool shouldGenerateAssemblyDefinition = true;
19 |
20 | [NonSerialized] private GUIContent cachedFolderIcon;
21 | [NonSerialized] private bool didCacheFolderIcon;
22 | private GUIContent FolderIcon
23 | {
24 | get
25 | {
26 | if (!didCacheFolderIcon)
27 | {
28 | didCacheFolderIcon = true;
29 | string path = "Folder Icon";
30 | if (EditorGUIUtility.isProSkin)
31 | path = "d_" + path;
32 |
33 | cachedFolderIcon = EditorGUIUtility.IconContent(path, string.Empty);
34 | }
35 | return cachedFolderIcon;
36 | }
37 | }
38 |
39 | [InitializeOnLoadMethod]
40 | private static void Initialize()
41 | {
42 | string[] settingsAsset = AssetDatabase.FindAssets($"t:{nameof(FmodSyntaxSettings)}");
43 | if (settingsAsset.Length > 0)
44 | return;
45 |
46 | EditorApplication.delayCall += () =>
47 | {
48 | SetupWizard setupWizard = GetWindow(true, "FMOD Syntax Setup Wizard");
49 | setupWizard.minSize = setupWizard.maxSize = new Vector2(500, 270);
50 | setupWizard.namespaceForGeneratedCode =
51 | $"{SanitizeNamespace(Application.companyName)}.{SanitizeNamespace(Application.productName)}.FMOD";
52 | };
53 | }
54 |
55 | private static string SanitizeNamespace(string @namespace)
56 | {
57 | return FmodSyntaxUtilities.Filter(@namespace, false);
58 | }
59 |
60 | private void OnGUI()
61 | {
62 | EditorGUILayout.BeginHorizontal();
63 | EditorGUILayout.Space();
64 | EditorGUILayout.BeginVertical();
65 |
66 | EditorGUILayout.Space();
67 |
68 | EditorGUILayout.LabelField("Welcome! You've installed the FMOD Syntax package.");
69 |
70 | EditorGUILayout.Space();
71 | EditorGUILayout.LabelField("Let's initialize the system with some default settings.");
72 | EditorGUILayout.Space();
73 |
74 | EditorGUILayout.BeginVertical("Box");
75 | EditorGUILayout.LabelField("Folders", EditorStyles.boldLabel);
76 |
77 | settingsFolderPath = DrawFolderPathField(settingsFolderPath, "Settings Config",
78 | "Where to create the config file that has all the settings in it.");
79 |
80 | generatedScriptsFolderPath = DrawFolderPathField(generatedScriptsFolderPath, "Generated Scripts",
81 | "Where to place the generated scripts for events and such.");
82 |
83 | EditorGUILayout.Space();
84 |
85 | EditorGUILayout.LabelField("Code Formatting", EditorStyles.boldLabel);
86 | namespaceForGeneratedCode = EditorGUILayout.TextField(
87 | new GUIContent("Namespace", "The namespace to use for all generated code."), namespaceForGeneratedCode);
88 |
89 | GUIContent generateAsmdefLabel = new GUIContent(
90 | "Make Assembly Definition",
91 | "Whether to generate an assembly definition file for the generated FMOD code. " +
92 | "If the code is to be generated within one central runtime assembly definition for your game, " +
93 | "you may want to turn this off.");
94 | shouldGenerateAssemblyDefinition = EditorGUILayout.Toggle(
95 | generateAsmdefLabel, shouldGenerateAssemblyDefinition);
96 |
97 | EditorGUILayout.Space();
98 | EditorGUILayout.EndVertical();
99 |
100 | EditorGUILayout.Space();
101 |
102 | bool shouldInitialize = GUILayout.Button("Initialize", GUILayout.Height(40));
103 | if (shouldInitialize)
104 | InitializeFmodSyntaxSystem();
105 |
106 | EditorGUILayout.Space();
107 |
108 | EditorGUILayout.EndVertical();
109 |
110 | EditorGUILayout.Space();
111 |
112 | EditorGUILayout.EndHorizontal();
113 | }
114 |
115 | private void InitializeFmodSyntaxSystem()
116 | {
117 | FmodSyntaxSettings settings = CreateScriptableObject(
118 | settingsFolderPath, nameof(FmodSyntaxSettings));
119 |
120 | settings.InitializeFromWizard(
121 | generatedScriptsFolderPath, namespaceForGeneratedCode, shouldGenerateAssemblyDefinition);
122 |
123 | EditorUtility.SetDirty(settings);
124 | AssetDatabase.SaveAssets();
125 |
126 | Close();
127 | }
128 |
129 | private static void EnsureFolderExists(string path)
130 | {
131 | string absolutePath = Path.Combine(Application.dataPath, path);
132 |
133 | if (Directory.Exists(absolutePath))
134 | return;
135 |
136 | Directory.CreateDirectory(absolutePath);
137 | AssetDatabase.Refresh();
138 | }
139 |
140 | private static Type CreateScriptableObject(string path, string name)
141 | where Type : ScriptableObject
142 | {
143 | ScriptableObject scriptableObject = CreateInstance(typeof(Type));
144 | scriptableObject.name = name;
145 |
146 | EnsureFolderExists(path);
147 |
148 | path = Path.Combine(path, name + ".asset");
149 | AssetDatabase.CreateAsset(scriptableObject, Path.Combine("Assets", path));
150 |
151 | return (Type)scriptableObject;
152 | }
153 |
154 | private string DrawFolderPathField(string currentPath, string label, string tooltip = null)
155 | {
156 | EditorGUILayout.BeginHorizontal();
157 | EditorGUILayout.LabelField(new GUIContent(label, tooltip), GUILayout.Width(EditorGUIUtility.labelWidth));
158 | currentPath = EditorGUILayout.TextField(currentPath);
159 | float height = EditorGUIUtility.singleLineHeight;
160 | bool shouldPick = GUILayout.Button(FolderIcon, GUILayout.Width(1.5f * height), GUILayout.Height(height));
161 | if (shouldPick)
162 | {
163 | string selectedFolder = EditorUtility.OpenFolderPanel(
164 | $"Pick {label} Folder", Path.Combine(Application.dataPath, currentPath), string.Empty);
165 | if (!string.IsNullOrEmpty(selectedFolder) && selectedFolder.StartsWith(Application.dataPath))
166 | {
167 | selectedFolder = selectedFolder.Substring(Application.dataPath.Length);
168 |
169 | if (selectedFolder.StartsWith(Path.DirectorySeparatorChar) ||
170 | selectedFolder.StartsWith(Path.AltDirectorySeparatorChar))
171 | {
172 | selectedFolder = selectedFolder.Substring(1);
173 | }
174 |
175 | currentPath = selectedFolder;
176 |
177 | EditorApplication.delayCall += Repaint;
178 | }
179 | }
180 |
181 | EditorGUILayout.EndHorizontal();
182 |
183 | return currentPath;
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/Editor/SetupWizard.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8d24ea029abd0f24e9a188f63fe7fc12
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/SnapshotReferenceDropdown.cs:
--------------------------------------------------------------------------------
1 | using UnityEditor;
2 | using UnityEditor.IMGUI.Controls;
3 | using FMODUnity;
4 | using System.Linq;
5 |
6 | namespace RoyTheunissen.FMODSyntax
7 | {
8 | ///
9 | /// Dropdown to pick snapshot references from a list in a searchable way / with subfolders.
10 | ///
11 | public sealed class SnapshotReferenceDropdown : AdvancedDropdown
12 | {
13 | private readonly SerializedProperty serializedProperty;
14 |
15 | public SnapshotReferenceDropdown(AdvancedDropdownState state, SerializedProperty serializedProperty)
16 | : base(state)
17 | {
18 | this.serializedProperty = serializedProperty;
19 | }
20 |
21 | protected override AdvancedDropdownItem BuildRoot()
22 | {
23 | SnapshotConfigDropdownItem root = new SnapshotConfigDropdownItem(
24 | this, string.Empty, "Snapshots", string.Empty);
25 |
26 | EditorEventRef[] snapshots = EventManager.Events
27 | .Where(e => e.Path.StartsWith(EditorEventRefExtensions.SnapshotPrefix))
28 | .OrderBy(e => e.Path)
29 | .ToArray();
30 | string[] paths = new string[snapshots.Length];
31 | string[] guids = new string[snapshots.Length];
32 |
33 | root.AddChildByPath("None", "None");
34 |
35 | for (int i = 0; i < snapshots.Length; i++)
36 | {
37 | // Remove the event prefix otherwise it gets treated as a folder.
38 | string path = snapshots[i].Path;
39 | path = path.RemovePrefix(EditorEventRefExtensions.SnapshotPrefix);
40 | paths[i] = path;
41 |
42 | guids[i] = snapshots[i].Guid.ToString();
43 | }
44 |
45 | for (int i = 0; i < paths.Length; i++)
46 | {
47 | root.AddChildByPath(guids[i], paths[i]);
48 | }
49 |
50 | return root;
51 | }
52 |
53 | protected override void ItemSelected(AdvancedDropdownItem item)
54 | {
55 | base.ItemSelected(item);
56 |
57 | SnapshotConfigDropdownItem dropdownItem = (SnapshotConfigDropdownItem)item;
58 |
59 | serializedProperty.serializedObject.Update();
60 | serializedProperty.stringValue = dropdownItem.Guid == "None" ? string.Empty : dropdownItem.Guid;
61 | serializedProperty.serializedObject.ApplyModifiedProperties();
62 | }
63 | }
64 |
65 | public sealed class SnapshotConfigDropdownItem : AdvancedDropdownItem
66 | {
67 | private const char Separator = '/';
68 |
69 | private readonly SnapshotReferenceDropdown dropdown;
70 |
71 | private string path;
72 |
73 | private string guid;
74 | public string Guid => guid;
75 |
76 | public SnapshotConfigDropdownItem(
77 | SnapshotReferenceDropdown dropdown, string guid, string name, string path) : base(name)
78 | {
79 | this.dropdown = dropdown;
80 | this.guid = guid;
81 | this.path = path;
82 | }
83 |
84 | private SnapshotConfigDropdownItem AddChild(string guid, string name)
85 | {
86 | string newPath = string.IsNullOrEmpty(path) ? name : path + Separator + name;
87 |
88 | SnapshotConfigDropdownItem child = new SnapshotConfigDropdownItem(dropdown, guid, name, newPath);
89 |
90 | AddChild(child);
91 |
92 | return child;
93 | }
94 |
95 | private SnapshotConfigDropdownItem GetOrCreateChild(string guid, string name)
96 | {
97 | // Find a child with the specified name.
98 | foreach (AdvancedDropdownItem child in children)
99 | {
100 | if (child.name == name)
101 | return (SnapshotConfigDropdownItem)child;
102 | }
103 |
104 | // Add a new one if it didn't exist yet.
105 | return AddChild(guid, name);
106 | }
107 |
108 | public void AddChildByPath(string guid, string relativePath)
109 | {
110 | // Leaf node, add the event there.
111 | if (!relativePath.Contains(Separator))
112 | {
113 | AddChild(guid, relativePath);
114 | return;
115 | }
116 |
117 | string[] sections = relativePath.Split(Separator);
118 |
119 | // Ensure a child exists for the first section of the path.
120 | // This acts as a folder and and does not have a key itself.
121 | SnapshotConfigDropdownItem firstSection = GetOrCreateChild(string.Empty, sections[0]);
122 |
123 | // Determine the path relative to this first child.
124 | string pathRemaining = string.Empty;
125 | for (int i = 1; i < sections.Length; i++)
126 | {
127 | pathRemaining += sections[i];
128 |
129 | if (i < sections.Length - 1)
130 | pathRemaining += Separator;
131 | }
132 |
133 | // Continue recursively from the first section.
134 | firstSection.AddChildByPath(guid, pathRemaining);
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/Editor/SnapshotReferenceDropdown.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a6143441a05599143be8bb6880fb7d14
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/SnapshotReferencePropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | using FMODUnity;
2 | using UnityEditor;
3 | using UnityEditor.IMGUI.Controls;
4 | using UnityEngine;
5 | using GUID = FMOD.GUID;
6 |
7 | namespace RoyTheunissen.FMODSyntax
8 | {
9 | ///
10 | /// Draws dropdowns for selecting a snapshot config.
11 | ///
12 | [CustomPropertyDrawer(typeof(SnapshotReference))]
13 | public class SnapshotReferencePropertyDrawer : PropertyDrawer
14 | {
15 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
16 | {
17 | // If this is an array, it would just show "Element 0" as the label which takes up a lot of space and is
18 | // useless. Even more useless is that it actually sees that the first property of AudioReference is a string
19 | // and shows that as the name instead for an array. That just means that it shows the GUID as the label.
20 | // HOW USEFUL. How about we don't show a label at all and just have a wider field that's easier to read?
21 | if (property.IsInArray())
22 | label = GUIContent.none;
23 |
24 | SerializedProperty snapshotConfigProperty = property.FindPropertyRelative("fmodSnapshotGuid");
25 |
26 | // Figure out the display text and the content property.
27 | string displayedText;
28 | string guid = snapshotConfigProperty.stringValue;
29 | if (string.IsNullOrEmpty(guid))
30 | {
31 | displayedText = string.Empty;
32 | }
33 | else
34 | {
35 | GUID id = GUID.Parse(guid);
36 | EditorEventRef eventRef = EventManager.EventFromGUID(id);
37 | displayedText = eventRef == null ? string.Empty : eventRef.GetDisplayName();
38 | }
39 |
40 | // Draw a dropdown button to select the snapshot config.
41 | EditorGUI.BeginProperty(position, label, snapshotConfigProperty);
42 | Rect valueRect = EditorGUI.PrefixLabel(position, label);
43 | bool didPress = EditorGUI.DropdownButton(
44 | valueRect, new GUIContent(displayedText), FocusType.Keyboard);
45 | if (didPress)
46 | {
47 | Rect dropDownRect = position;
48 | dropDownRect.xMax += 200;
49 |
50 | SnapshotReferenceDropdown menu = new SnapshotReferenceDropdown(
51 | new AdvancedDropdownState(), snapshotConfigProperty);
52 | menu.Show(dropDownRect);
53 | }
54 | EditorGUI.EndProperty();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Editor/SnapshotReferencePropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 041e64241708b274b9aa64dfd2f28da3
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 27cdfa7b0bb6fdd44855b024da538980
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Utilities/EditorAssetReference.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using Object = UnityEngine.Object;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Helps you access an asset at editor time. Useful for finding code templates, for example.
9 | ///
10 | public class EditorAssetReference where T : Object
11 | {
12 | [NonSerialized] private T cachedAsset;
13 | public T Asset
14 | {
15 | get
16 | {
17 | if (cachedAsset == null)
18 | cachedAsset = Resources.Load(path);
19 | return cachedAsset;
20 | }
21 | }
22 |
23 | [NonSerialized] private readonly string path;
24 | public string Path => path;
25 |
26 | public EditorAssetReference(string path)
27 | {
28 | this.path = path;
29 | }
30 |
31 | public static implicit operator T(EditorAssetReference editorAssetReference)
32 | {
33 | return editorAssetReference.Asset;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Editor/Utilities/EditorAssetReference.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2ada72029bb66614d96e6b6231018552
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities/EditorPreference.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using Object = UnityEngine.Object;
3 |
4 | #if !UNITY_EDITOR
5 | using System;
6 | #endif // UNITY_EDITOR
7 |
8 | namespace RoyTheunissen.FMODSyntax
9 | {
10 | ///
11 | /// Utility class to simplify the workflow of using EditorPrefs-serialized fields.
12 | ///
13 | /// Now you can specify a field that is to be serialized in EditorPrefs as follows:
14 | ///
15 | /// private EditorPreferenceBool skipIntro = new EditorPreferenceBool("ProjectName/Skip Intro");
16 | ///
17 | /// then you can get or set its value as follows:
18 | /// skipIntro.Value
19 | ///
20 | /// You can also draw the default editor field associated with it like so:
21 | /// skipIntro.DrawGUILayout();
22 | ///
23 | public abstract class EditorPreference
24 | {
25 | #if !UNITY_EDITOR
26 | protected const string EditorOnlyExceptionMessage = "Can only be called in the Editor.";
27 | #endif // !UNITY_EDITOR
28 |
29 | private string path;
30 | public string Path => IsProjectSpecific ? ProjectPrefix + path : path;
31 |
32 | private bool isProjectSpecific = true;
33 | public bool IsProjectSpecific
34 | {
35 | get => isProjectSpecific;
36 | set => isProjectSpecific = value;
37 | }
38 |
39 | private static string cachedProjectPrefix;
40 |
41 | private static string ProjectPrefix
42 | {
43 | get
44 | {
45 | if (cachedProjectPrefix == null)
46 | {
47 | string assetsFolder = Application.dataPath;
48 | string projectsFolder = assetsFolder.Substring(0, assetsFolder.Length - "/Assets".Length);
49 |
50 | // NOTE: If you only want the name of the project checkout, you can do that here. That would
51 | // conflate save data from checkouts in different drives/parent folders with the same name though,
52 | // so I'm choosing to include the path up until the project name too.
53 | //string projectName = System.IO.Path.GetFileName(projectsFolder);
54 |
55 | // Prefix ends up something like C:/Git/YourProjectName/ so it's unique to your checkout.
56 | cachedProjectPrefix = projectsFolder + "/";
57 | }
58 | return cachedProjectPrefix;
59 | }
60 | }
61 |
62 | private GUIContent label;
63 | protected GUIContent Label => label;
64 |
65 | public abstract object ObjectValue { get; }
66 |
67 | protected EditorPreference(string path)
68 | {
69 | this.path = path;
70 |
71 | string name = System.IO.Path.GetFileName(path).ToHumanReadable();
72 | label = new GUIContent(name);
73 | }
74 |
75 | public abstract void DrawGUILayout(GUIContent label, params GUILayoutOption[] options);
76 |
77 | public void DrawGUILayout(params GUILayoutOption[] layoutOptions)
78 | {
79 | DrawGUILayout(Label, layoutOptions);
80 | }
81 |
82 | public void DrawGUILayout(string label, params GUILayoutOption[] options)
83 | {
84 | DrawGUILayout(new GUIContent(label), options);
85 | }
86 |
87 | public abstract void DrawGUI(Rect position, GUIContent label);
88 |
89 | public void DrawGUI(Rect position)
90 | {
91 | DrawGUI(position, Label);
92 | }
93 |
94 | public void DrawGUI(Rect position, string label)
95 | {
96 | DrawGUI(position, new GUIContent(label));
97 | }
98 | }
99 |
100 | public abstract class EditorPreferenceGeneric
101 | : EditorPreference
102 | {
103 | public virtual ValueType Value
104 | {
105 | get => ValueRaw;
106 | set => ValueRaw = value;
107 | }
108 |
109 | protected ValueType ValueRaw
110 | {
111 | get
112 | {
113 | #if !UNITY_EDITOR
114 | return ValueRuntime;
115 | #else
116 | return !UnityEditor.EditorPrefs.HasKey(Path) ? defaultValue : UnityPrefsValue;
117 | #endif // UNITY_EDITOR
118 | }
119 | set
120 | {
121 | #if !UNITY_EDITOR
122 | // No need to set anything because we can't access the unity prefs anyway.
123 | #else
124 | UnityPrefsValue = value;
125 | #endif // UNITY_EDITOR
126 | }
127 | }
128 |
129 | protected virtual ValueType ValueRuntime => defaultValue;
130 |
131 | public override object ObjectValue => Value;
132 |
133 | protected abstract ValueType UnityPrefsValue { get; set; }
134 |
135 | private ValueType defaultValue;
136 |
137 | protected EditorPreferenceGeneric(string path, ValueType defaultValue = default(ValueType)) : base(path)
138 | {
139 | this.defaultValue = defaultValue;
140 | }
141 | }
142 |
143 | public class EditorPreferenceBool : EditorPreferenceGeneric
144 | {
145 | protected override bool UnityPrefsValue
146 | {
147 | get
148 | {
149 | #if UNITY_EDITOR
150 | return UnityEditor.EditorPrefs.GetBool(Path);
151 | #else
152 | throw new Exception(EditorOnlyExceptionMessage);
153 | #endif // !UNITY_EDITOR
154 | }
155 | set
156 | {
157 | #if UNITY_EDITOR
158 | UnityEditor.EditorPrefs.SetBool(Path, value);
159 | #else
160 | throw new Exception(EditorOnlyExceptionMessage);
161 | #endif // !UNITY_EDITOR
162 | }
163 | }
164 |
165 | public EditorPreferenceBool(string path, bool defaultValue = default(bool)) : base(path, defaultValue)
166 | {
167 | }
168 |
169 | public override void DrawGUILayout(GUIContent label, params GUILayoutOption[] options)
170 | {
171 | #if UNITY_EDITOR
172 | Value = UnityEditor.EditorGUILayout.Toggle(label, Value, options);
173 | #endif // UNITY_EDITOR
174 | }
175 |
176 | public void DrawGUILayoutLeft(params GUILayoutOption[] options)
177 | {
178 | DrawGUILayoutLeft(Label, options);
179 | }
180 |
181 | public void DrawGUILayoutLeft(GUIContent label, params GUILayoutOption[] options)
182 | {
183 | #if UNITY_EDITOR
184 | Value = UnityEditor.EditorGUILayout.ToggleLeft(label, Value, options);
185 | #endif // UNITY_EDITOR
186 | }
187 |
188 | public void DrawGUILayoutLeft(string label, params GUILayoutOption[] options)
189 | {
190 | DrawGUILayoutLeft(new GUIContent(label), options);
191 | }
192 |
193 | public override void DrawGUI(Rect position, GUIContent label)
194 | {
195 | #if UNITY_EDITOR
196 | Value = UnityEditor.EditorGUI.Toggle(position, label, Value);
197 | #endif // UNITY_EDITOR
198 | }
199 |
200 | public void DrawGUILeft(Rect position)
201 | {
202 | DrawGUILeft(position, Label);
203 | }
204 |
205 | public void DrawGUILeft(Rect position, GUIContent label)
206 | {
207 | #if UNITY_EDITOR
208 | Value = UnityEditor.EditorGUI.ToggleLeft(position, label, Value);
209 | #endif // UNITY_EDITOR
210 | }
211 |
212 | public void DrawGUILeft(Rect position, string label)
213 | {
214 | DrawGUILeft(position, new GUIContent(label));
215 | }
216 | }
217 |
218 | public class EditorPreferenceString : EditorPreferenceGeneric
219 | {
220 | protected override string UnityPrefsValue
221 | {
222 | get
223 | {
224 | #if UNITY_EDITOR
225 | return UnityEditor.EditorPrefs.GetString(Path);
226 | #else
227 | throw new Exception(EditorOnlyExceptionMessage);
228 | #endif // !UNITY_EDITOR
229 | }
230 | set
231 | {
232 | #if UNITY_EDITOR
233 | UnityEditor.EditorPrefs.SetString(Path, value);
234 | #else
235 | throw new Exception(EditorOnlyExceptionMessage);
236 | #endif // !UNITY_EDITOR
237 | }
238 | }
239 |
240 | public EditorPreferenceString(string path, string defaultValue = default(string)) : base(path, defaultValue)
241 | {
242 | }
243 |
244 | public override void DrawGUILayout(GUIContent label, params GUILayoutOption[] options)
245 | {
246 | #if UNITY_EDITOR
247 | Value = UnityEditor.EditorGUILayout.TextField(label, Value, options);
248 | #endif // UNITY_EDITOR
249 | }
250 |
251 | public override void DrawGUI(Rect position, GUIContent label)
252 | {
253 | #if UNITY_EDITOR
254 | Value = UnityEditor.EditorGUI.TextField(position, label, Value);
255 | #endif // UNITY_EDITOR
256 | }
257 | }
258 |
259 | public class EditorPreferenceInt : EditorPreferenceGeneric
260 | {
261 | protected override int UnityPrefsValue
262 | {
263 | get
264 | {
265 | #if UNITY_EDITOR
266 | return UnityEditor.EditorPrefs.GetInt(Path);
267 | #else
268 | throw new Exception(EditorOnlyExceptionMessage);
269 | #endif // !UNITY_EDITOR
270 | }
271 | set
272 | {
273 | #if UNITY_EDITOR
274 | UnityEditor.EditorPrefs.SetInt(Path, value);
275 | #else
276 | throw new Exception(EditorOnlyExceptionMessage);
277 | #endif // !UNITY_EDITOR
278 | }
279 | }
280 |
281 | public EditorPreferenceInt(string path, int defaultValue = default(int)) : base(path, defaultValue)
282 | {
283 | }
284 |
285 | public override void DrawGUILayout(GUIContent label, params GUILayoutOption[] options)
286 | {
287 | #if UNITY_EDITOR
288 | Value = UnityEditor.EditorGUILayout.IntField(label, Value, options);
289 | #endif // UNITY_EDITOR
290 | }
291 |
292 | public override void DrawGUI(Rect position, GUIContent label)
293 | {
294 | #if UNITY_EDITOR
295 | Value = UnityEditor.EditorGUI.IntField(position, label, Value);
296 | #endif // UNITY_EDITOR
297 | }
298 | }
299 |
300 | public class EditorPreferenceFloat : EditorPreferenceGeneric
301 | {
302 | protected override float UnityPrefsValue
303 | {
304 | get
305 | {
306 | #if UNITY_EDITOR
307 | return UnityEditor.EditorPrefs.GetFloat(Path);
308 | #else
309 | throw new Exception(EditorOnlyExceptionMessage);
310 | #endif // !UNITY_EDITOR
311 | }
312 | set
313 | {
314 | #if UNITY_EDITOR
315 | UnityEditor.EditorPrefs.SetFloat(Path, value);
316 | #else
317 | throw new Exception(EditorOnlyExceptionMessage);
318 | #endif // !UNITY_EDITOR
319 | }
320 | }
321 |
322 | public EditorPreferenceFloat(string path, float defaultValue = default(float)) : base(path, defaultValue)
323 | {
324 | }
325 |
326 | public override void DrawGUILayout(GUIContent label, params GUILayoutOption[] options)
327 | {
328 | #if UNITY_EDITOR
329 | Value = UnityEditor.EditorGUILayout.FloatField(label, Value, options);
330 | #endif // UNITY_EDITOR
331 | }
332 |
333 | public override void DrawGUI(Rect position, GUIContent label)
334 | {
335 | #if UNITY_EDITOR
336 | Value = UnityEditor.EditorGUI.FloatField(position, label, Value);
337 | #endif // UNITY_EDITOR
338 | }
339 | }
340 |
341 | public class EditorPreferenceObject : EditorPreferenceGeneric
342 | where T : Object
343 | {
344 | private T cachedAsset;
345 |
346 | protected override T UnityPrefsValue
347 | {
348 | get
349 | {
350 | #if UNITY_EDITOR
351 | if (cachedAsset == null)
352 | {
353 | string assetPath = UnityEditor.EditorPrefs.GetString(Path);
354 |
355 | if (string.IsNullOrEmpty(assetPath))
356 | return null;
357 |
358 | cachedAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath);
359 | }
360 |
361 | return cachedAsset;
362 | #else
363 | throw new Exception(EditorOnlyExceptionMessage);
364 | #endif // !UNITY_EDITOR
365 | }
366 | set
367 | {
368 | #if UNITY_EDITOR
369 | T previousValue = UnityPrefsValue;
370 | if (previousValue != value)
371 | {
372 | // Store the new asset's path.
373 | string path = value == null ? null : UnityEditor.AssetDatabase.GetAssetPath(value);
374 | UnityEditor.EditorPrefs.SetString(Path, path);
375 |
376 | // Invalidate the cached asset.
377 | cachedAsset = null;
378 | }
379 | #else
380 | throw new Exception(EditorOnlyExceptionMessage);
381 | #endif // !UNITY_EDITOR
382 | }
383 | }
384 |
385 | public EditorPreferenceObject(string path, T defaultValue = default(T)) : base(path, defaultValue)
386 | {
387 | }
388 |
389 | public override void DrawGUILayout(GUIContent label, params GUILayoutOption[] options)
390 | {
391 | #if UNITY_EDITOR
392 | Value = (T)UnityEditor.EditorGUILayout.ObjectField(label, Value, typeof(T), false, options);
393 | #endif // UNITY_EDITOR
394 | }
395 |
396 | public override void DrawGUI(Rect position, GUIContent label)
397 | {
398 | #if UNITY_EDITOR
399 | Value = (T)UnityEditor.EditorGUI.ObjectField(position, label, Value, typeof(T), false);
400 | #endif // UNITY_EDITOR
401 | }
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/Editor/Utilities/EditorPreference.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 59c760fd241e131429d20eba823e8f8c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Roy Theunissen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8fd535d4937796b4da4b1648c12eed22
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://roytheunissen.com)
2 | [](LICENSE.md)
3 | 
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | _Generates code to allow invoking FMOD events with a strongly-typed syntax._
26 |
27 | ## About the Project
28 |
29 | Out-of-the-box FMOD requires you to access events and parameters via inspector references or by name.
30 | Neither of these setups is ideal.
31 |
32 | Dispatching an event this way requires you to define a bunch of fields, assign things in the inspector, and then the syntax for setting parameters is weakly-typed.
33 | You can skip some of this by dispatching events/setting parameters by name but that has the drawback that you need to look up what the name is and it's very hard and error-prone to rename anything as it'll break references.
34 |
35 | For ease of use it's preferable if FMOD events and parameters are accessed in a strongly-typed way such that they're known at compile-time. Maybe something like this:
36 |
37 | ```cs
38 | AudioEvents.PlayerJump.Play(transform);
39 | ```
40 |
41 | This would require a little bit of code generation, and that's where `FMOD-Syntax` comes in. With a simple setup wizard and one line of code in your audio service for culling expired events you can start dispatching FMOD events with parameters in as little as one line of code.
42 |
43 | 
44 |
45 | This setup allows events and parameters to be renamed gracefully as you can do it via your IDE, update your banks accordingly and then re-generate the code. If events are renamed in the banks and you still reference those events by their old names, warnings will be thrown to give you a chance to refactor without immediately getting compile errors.
46 |
47 | Overall this system significantly speeds up your audio implementation workflow and makes it more robust, at the expense of a little bit of boilerplate code that you won't even have to maintain yourself.
48 |
49 | ## Getting Started
50 |
51 | - Install the package to your Unity project
52 | - The Setup Wizard will pop up and allow you to specify where and how to create the settings file & save generated code files
53 | - Configure the system as desired and press Initialize
54 | - Use `FMOD > Generate FMOD Code` or `CTRL+ALT+G` to generate the FMOD code
55 | - Cull expired FMOD playback instances by calling `FmodSyntaxSystem.CullPlaybacks();` in an `Update` loop somewhere. I recommend putting this in your audio service.
56 | - You can now fire your FMOD events in a strongly typed way
57 |
58 | ## How to use
59 |
60 | ### One-offs
61 | ```cs
62 | // Parameterless one-off sound (global)
63 | AudioEvents.TestOneOff.Play();
64 |
65 | // Parameterless one-off sound (spatialized)
66 | AudioEvents.TestOneOff.Play(transform);
67 |
68 | // Spatialized one-off with parameters
69 | AudioEvents.Footstep.Play(transform, FootstepPlayback.SurfaceValues.Generic);
70 | ```
71 |
72 | ### Loops
73 | ```cs
74 | // Start a looping sound
75 | TestContinuousPlayback testContinuousPlayback = AudioEvents.TestContinuous.Play(transform);
76 |
77 | // Set the parameter on a looping sound
78 | float value = Mathf.Sin(Time.time * Mathf.PI * 1.0f).Map(-1, 1);
79 | testContinuousPlayback.Strength.Value = value;
80 |
81 | // Stop a looping sound
82 | testContinuousPlayback?.Stop();
83 |
84 | // Cancel a looping sound in OnDestroy
85 | testContinuousPlayback?.Cleanup();
86 | ```
87 |
88 | ### Global Parameters
89 | ```cs
90 | // Setting global parameters
91 | AudioGlobalParameters.PlayerSpeed.Value = value;
92 | ```
93 |
94 | ### Dispatching a parameterless event that is chosen via the inspector
95 | ```cs
96 | // Get a reference to the event that you can assign via the inspector
97 | [SerializeField] private AudioConfigReference parameterlessAudio;
98 |
99 | // Dispatch as per usual
100 | parameterlessAudio.Play(transform);
101 | ```
102 |
103 | ### Labeled parameter enums
104 | In FMOD there are three types of parameters: "Continuous" (`int`), "Discrete" (`float`) and "Labeled" (`enum`).
105 |
106 | Labeled parameters are sent and received as integers, but they are associated with a name for convenience, exactly like enums in C#.
107 |
108 | 
109 |
110 | For convenience, FMOD Syntax generates an enum for every event with a labeled parameter, so auto-complete conveniently suggests all valid values when you are invoking the event.
111 |
112 | ```cs
113 | AudioEvents.Footstep.Play(transform, FootstepPlayback.SurfaceValues.Generic);
114 | ```
115 |
116 | But let's say you have several events that share the same "Surface" parameter, for instance a Jump and a Footstep event.
117 | It could be inconvenient if you just want to determine the current surface type, and then fire jump and footstep events with that type,
118 | because you would have to cast it to the appropriate event-specific enum.
119 |
120 | ```cs
121 | AudioEvents.Footstep.Play(transform, FootstepPlayback.SurfaceValues.Generic);
122 | AudioEvents.Jump.Play(transform, JumpPlayback.SurfaceValues.Generic);
123 | ```
124 |
125 | Furthermore, the enums in FMOD may actually represent an enum in your game. So it's inconvenient to have to map from that game enum to the FMOD enum. But there's a solution for that: **User-specified labeled parameter enums**.
126 |
127 | Simply tag your game enum with `[FmodLabelType]` and specify the names of the labeled parameters that it represents, and then when code is generated instead of generating event-specific enums, it uses the game enum you specified for those events.
128 |
129 | No more duplication, no more mapping.
130 |
131 | ```cs
132 | [FmodLabelType("Surface")]
133 | public enum SurfaceTypes
134 | {
135 | Generic,
136 | Dirt,
137 | Rock,
138 | }
139 | ```
140 | ```cs
141 | AudioEvents.Footstep.Play(transform, SurfaceTypes.Generic);
142 | AudioEvents.Jump.Play(transform, SurfaceTypes.Generic);
143 | ```
144 | #### Scriptable Object Collection Support
145 |
146 | The above 'Labeled parameter enums' feature now also works for the [Scriptable Object Collection](https://github.com/brunomikoski/ScriptableObjectCollection). Simply add the `[FmodLabelType]` attribute to the Scriptable Object Collection Item the same way you would with an enum.
147 |
148 | > [!IMPORTANT]
149 | > If you installed FMOD-Syntax or ScriptableObjectCollection to the `Assets` folder instead of via the Package Manager / in the Packages folder, a `SCRIPTABLE_OBJECT_COLLECTION` scripting define symbol will not be defined automatically and you will have to manually add this to the project settings for this feature to work._
150 |
151 |
152 |
153 | ### Moving/renaming Events
154 | FMOD-Syntax has a two-tiered solution for allowing you to move/rename events in FMOD and update your code accordingly:
155 | - **Alias Generation** - When an event is detected as having been moved or renamed, 'aliases' are generated under the old name, tagged with an `[Obsolete]` attribute that informs you what the event is currently called. This causes the game to throw a compile warning everywhere that the old incorrect syntax is used, and you can copy/paste the correct name from the warning. This lets you manually migrate your event code without compile errors and with reminders for what the new syntax is.
156 | - **Auto-Refactoring** - When an event is detected has having been moved or renamed, you are also presented with the option to Auto-Refactor. If chosen, FMOD-Syntax will look through your .cs files, find any references to the old events and automatically refactor them to use the new event syntax.
157 |
158 | ### Syntax Formats
159 | FMOD-Syntax provides three syntax formats for defining events:
160 | - **Flat**: All events are defined in `AudioEvents`. Simplest / shortest syntax, but event names have to be unique.
161 | An event called `Player/Footstep` is invoked via `AudioEvents.Footstep.Play();`
162 | - **Flat (With Path Included In Name)**: Slightly longer names, but event names don't have to be unique. Requested by @AldeRoberge
163 | An event called `Player/Footstep` is invoked via `AudioEvents.Player_Footstep.Play();`
164 | - **Subclasses Per Folder**: Subclasses are generated inside the `AudioEvents` class for every folder holding their events. Longer syntax, but events are neatly organized and names don't have to be unique.
165 | An event called `Player/Footstep` is invoked via `AudioEvents.Player.Footstep.Play();`
166 |
167 | The default syntax is `Flat`, and you are recommended to use that and give unique names to your events.
168 |
169 | For example, you can use the following naming convention: `Object_Event`. That way you can have a footstep event for both a player and a monster without getting a name clash, and it doesn't matter if the event is in a folder called `Core/World1/Gameplay/Characters/Enemies/Monster/Monster_Footstep`, because including all those folders in the name is cumbersome.
170 |
171 | However, as you may be integrating FMOD-Syntax into an existing project and may not have the ability to affect the naming convention of events much, we recognize that different projects have different structures and you are free to choose whatever syntax suits your project best.
172 |
173 | Switching syntax formats supports all the same migration features as renaming or moving events.
174 |
175 | #### Miscellaneous Features
176 |
177 | - Code is also generated for playing Snapshots. Basically treated like events, though it's separated in its own `AudioSnapshots` class.
178 | - Code is also generated for Buses and VCA's, which can be accessed via an `AudioBuses` and `AudioVCAs` class respectively.
179 |
180 | ## Compatibility
181 |
182 | This system was developed for Unity 2021 and upwards, it's recommended that you use it for these versions.
183 |
184 | If you use an older version of Unity and are running into trouble, feel free to reach out and I'll see what I can do.
185 |
186 | ## Known Issues
187 | - There is a setup for automatically regenerating the code when the FMOD banks update, but this would require you to modify the FMOD Unity plugin so that feature is currently disabled.
188 |
189 |
190 | ## Installation
191 |
192 | ### Package Manager
193 |
194 | Go to `Edit > Project Settings > Package Manager`. Under 'Scoped Registries' make sure there is an OpenUPM entry.
195 |
196 | If you don't have one: click the `+` button and enter the following values:
197 |
198 | - Name: `OpenUPM`
199 | - URL: `https://package.openupm.com`
200 |
201 | Then under 'Scope(s)' press the `+` button and add `com.roytheunissen`.
202 |
203 | It should look something like this:
204 | 
205 |
206 |
207 | All of my packages will now be available to you in the Package Manager in the 'My Registries' section and can be installed from there.
208 |
209 |
210 |
211 | ### Git Submodule
212 |
213 | You can check out this repository as a submodule into your project's Assets folder. This is recommended if you intend to contribute to the repository yourself.
214 |
215 | ### OpenUPM
216 | The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
217 |
218 | ```
219 | openupm add com.roytheunissen.fmod-syntax
220 | ```
221 |
222 | ### Manifest
223 | You can also install via git URL by adding this entry in your **manifest.json** (make sure to end with a comma if you're adding this at the top)
224 |
225 | ```
226 | "com.roytheunissen.fmod-syntax": "https://github.com/RoyTheunissen/FMOD-Syntax.git"
227 | ```
228 |
229 | ### Unity Package Manager
230 | From Window->Package Manager, click on the + sign and Add from git:
231 | ```
232 | https://github.com/RoyTheunissen/FMOD-Syntax.git
233 | ```
234 |
235 |
236 | ## Contact
237 | [Roy Theunissen](https://roytheunissen.com)
238 |
239 | [roy.theunissen@live.nl](mailto:roy.theunissen@live.nl)
240 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: def502edc086a9d4cb2032786c011b8f
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 15afd043ffab31b4e8f5ca59b9202fb4
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/AudioReference.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using UnityEngine;
6 |
7 | namespace RoyTheunissen.FMODSyntax
8 | {
9 | ///
10 | /// Inspector reference to FMOD audio config. Can be used to get a simple parameterless audio config.
11 | ///
12 | [Serializable]
13 | public class AudioReference : IAudioConfig
14 | {
15 | [SerializeField] private string fmodEventGuid;
16 |
17 | [NonSerialized] private FmodParameterlessAudioConfig cachedFmodAudioConfig;
18 | [NonSerialized] private string guidFmodAudioConfigIsCachedFor;
19 | private FmodParameterlessAudioConfig FmodAudioConfig
20 | {
21 | get
22 | {
23 | if (guidFmodAudioConfigIsCachedFor != fmodEventGuid)
24 | {
25 | guidFmodAudioConfigIsCachedFor = fmodEventGuid;
26 | cachedFmodAudioConfig = GetParameterlessEventConfig(fmodEventGuid);
27 | if (!string.IsNullOrEmpty(fmodEventGuid) && cachedFmodAudioConfig == null)
28 | {
29 | Debug.LogError($"FMOD event was assigned to audio reference but its corresponding config could " +
30 | $"not be found at runtime. Did you forget to compile FMOD code?");
31 | }
32 | }
33 | return cachedFmodAudioConfig;
34 | }
35 | }
36 |
37 | public bool IsAssigned => FmodAudioConfig != null;
38 |
39 | public string Name => IsAssigned ? FmodAudioConfig.Name : "";
40 | public string Path => IsAssigned ? FmodAudioConfig.Path : "";
41 |
42 | [NonSerialized] private static bool didCacheParameterlessEvents;
43 | private static readonly Dictionary parameterlessEventsByGuid =
44 | new Dictionary();
45 |
46 | public FmodParameterlessAudioPlayback Play(Transform source = null)
47 | {
48 | return FmodAudioConfig.Play(source);
49 | }
50 |
51 | IAudioPlayback IAudioConfig.Play(Transform source)
52 | {
53 | return Play(source);
54 | }
55 |
56 | #if UNITY_EDITOR
57 | [UnityEditor.InitializeOnLoadMethod]
58 | private static void Initialize()
59 | {
60 | parameterlessEventsByGuid.Clear();
61 | didCacheParameterlessEvents = false;
62 | }
63 | #endif // UNITY_EDITOR
64 |
65 |
66 | public static FmodParameterlessAudioConfig GetParameterlessEventConfig(string guid)
67 | {
68 | CacheParameterlessEventConfigs();
69 |
70 | if (parameterlessEventsByGuid.TryGetValue(guid, out FmodParameterlessAudioConfig result))
71 | return result;
72 |
73 | return null;
74 | }
75 |
76 | private static void CacheParameterlessEventConfigs()
77 | {
78 | if (didCacheParameterlessEvents)
79 | return;
80 |
81 | didCacheParameterlessEvents = true;
82 |
83 | parameterlessEventsByGuid.Clear();
84 |
85 | const string containerClassName = "AudioParameterlessEvents";
86 | IEnumerable containerTypes = AppDomain.CurrentDomain.GetAssemblies()
87 | .SelectMany(assembly => assembly.GetTypes()).Where(t => t.Name == containerClassName);
88 |
89 | foreach (Type containerType in containerTypes)
90 | {
91 | // Get the dictionary of parameter events by GUID.
92 | FieldInfo eventsByGuidDictionaryField = containerType.GetField(
93 | "EventsByGuid", BindingFlags.Public | BindingFlags.Static);
94 | Dictionary eventsByGuidDictionary =
95 | (Dictionary)eventsByGuidDictionaryField.GetValue(null);
96 |
97 | // Compile them all into one big dictionary.
98 | foreach (KeyValuePair kvp in eventsByGuidDictionary)
99 | {
100 | parameterlessEventsByGuid.Add(kvp.Key, kvp.Value);
101 | }
102 | }
103 | }
104 |
105 | public override string ToString()
106 | {
107 | FmodParameterlessAudioConfig config = FmodAudioConfig;
108 | return config == null ? "" : config.ToString();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Runtime/AudioReference.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: acdf7a8fe1d11dd4ba6217bde9680583
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Banks.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e12dd6d432c7de64b9deaa6c46bda6c0
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Banks/BankExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace FMOD.Studio
2 | {
3 | ///
4 | /// Extensions for bank to get the path without an out parameter because to make lambda functions easy to write.
5 | ///
6 | public static class BankExtensions
7 | {
8 | public static string getPath(this Bank bank)
9 | {
10 | bank.getPath(out string path);
11 | return path;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Runtime/Banks/BankExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 366b7beedb50c3c46b71596470091e65
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Buses.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 05bab732c1d23ab4f90737d2b8a5225d
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Buses/Bus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FMODUnity;
3 |
4 | namespace RoyTheunissen.FMODSyntax
5 | {
6 | ///
7 | /// Utility for accessing the buses more conveniently.
8 | ///
9 | public class Bus
10 | {
11 | private readonly string path;
12 |
13 | [NonSerialized] private FMOD.Studio.Bus cachedFmodBus;
14 | [NonSerialized] private bool didCacheFmodBus;
15 |
16 | public FMOD.Studio.Bus FmodBus
17 | {
18 | get
19 | {
20 | if (!didCacheFmodBus)
21 | {
22 | didCacheFmodBus = true;
23 | cachedFmodBus = RuntimeManager.GetBus(path);
24 | }
25 | return cachedFmodBus;
26 | }
27 | }
28 |
29 | public float VolumeLinear
30 | {
31 | get => FMOD.Studio.BusExtensions.getVolume(FmodBus);
32 | set => FmodBus.setVolume(value);
33 | }
34 |
35 | public Bus(string path)
36 | {
37 | this.path = path;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Runtime/Buses/Bus.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4019062cc94a9b0478efbc97ad0b873b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Buses/BusExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace FMOD.Studio
2 | {
3 | ///
4 | /// Extensions for bus to get the path without an out parameter to make lambda functions easy to write.
5 | ///
6 | public static class BusExtensions
7 | {
8 | public static string getPath(this FMOD.Studio.Bus bus)
9 | {
10 | bus.getPath(out string path);
11 | return path;
12 | }
13 |
14 | public static float getVolume(this FMOD.Studio.Bus bus)
15 | {
16 | bus.getVolume(out float volume);
17 | return volume;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Runtime/Buses/BusExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c6a849f795dac694780ce3a344ee4c73
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Callbacks.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6bfbaaba73d1e6f4e8cef65a6ef7c1de
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Callbacks/IOnFmodPlayback.cs:
--------------------------------------------------------------------------------
1 | namespace RoyTheunissen.FMODSyntax.Callbacks
2 | {
3 | ///
4 | /// Interface to use when you want a callback whenever an FMOD event playback is (un)registered.
5 | ///
6 | public interface IOnFmodPlayback
7 | {
8 | void OnFmodPlaybackRegistered(FmodAudioPlayback playback);
9 | void OnFmodPlaybackUnregistered(FmodAudioPlayback playback);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Runtime/Callbacks/IOnFmodPlayback.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ffe122c1a3f97764aa253a59b3602381
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ac1fadd7a67f8d24697e4b016458d0e5
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioConfig.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace RoyTheunissen.FMODSyntax
4 | {
5 | ///
6 | /// Non-generic base class for FmodAudioConfig to apply as a type constraint.
7 | ///
8 | public abstract class FmodAudioConfigBase : FmodPlayableConfig
9 | {
10 | protected FmodAudioConfigBase(string guid) : base(guid)
11 | {
12 | }
13 | }
14 |
15 | ///
16 | /// Config for a playable FMOD audio event. Returns an instance of the specified AudioFmodPlayback type so you can
17 | /// modify its parameters. Configs are specified in FmodEvents.AudioEvents
18 | ///
19 | public abstract class FmodAudioConfig : FmodAudioConfigBase, IAudioConfig
20 | where PlaybackType : FmodAudioPlayback
21 | {
22 | public FmodAudioConfig(string guid) : base(guid)
23 | {
24 | }
25 |
26 | public abstract PlaybackType Play(Transform source = null);
27 |
28 | IAudioPlayback IAudioConfig.Play(Transform source)
29 | {
30 | return Play(source);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioConfig.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d6c822bf45292ed48b64d0ee86832454
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioFolder.cs:
--------------------------------------------------------------------------------
1 | namespace RoyTheunissen.FMODSyntax
2 | {
3 | ///
4 | /// Represents a folder in the FMOD bank. Helps organize events and prevent name conflicts.
5 | ///
6 | public abstract class FmodAudioFolder
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioFolder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4d8770b2da4ab6849a12b4325f20a026
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioPlayback.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FMOD;
4 | using FMOD.Studio;
5 | using FMODUnity;
6 | using RoyTheunissen.FMODSyntax.Callbacks;
7 | using UnityEngine;
8 | using Debug = UnityEngine.Debug;
9 | using STOP_MODE = FMOD.Studio.STOP_MODE;
10 |
11 | namespace RoyTheunissen.FMODSyntax
12 | {
13 | ///
14 | /// Non-generic base class for AudioFmodPlayback to apply as a type constraint.
15 | ///
16 | public abstract class FmodAudioPlaybackBase : FmodPlayablePlaybackBase
17 | {
18 | private bool isOneshot = false;
19 | public bool IsOneshot
20 | {
21 | get => isOneshot;
22 | protected set => isOneshot = value;
23 | }
24 | }
25 |
26 | ///
27 | /// Playback for a playable FMOD audio event. Allows you to update its parameters.
28 | /// Produced by calling Play() on an AudioFmodConfig, which are specified in FmodEvents.AudioEvents
29 | ///
30 | public abstract class FmodAudioPlayback : FmodAudioPlaybackBase, IAudioPlayback
31 | {
32 | public void Play(EventDescription eventDescription, Transform source)
33 | {
34 | eventDescription.getPath(out string path);
35 |
36 | if (!eventDescription.isValid())
37 | {
38 | eventDescription.getID(out GUID guid);
39 | Debug.LogError($"Trying to play invalid FMOD Event guid: '{guid}' path:'{path}'");
40 | return;
41 | }
42 |
43 | // Events are called something like event:/ but we want to get rid of any prefix like that.
44 | // Also every 'folder' along the way will be treated like a sort of 'tag'
45 | SearchKeywords = path.Substring(path.IndexOf("/", StringComparison.Ordinal) + 1).Replace('/', ',');
46 |
47 | Name = Path.GetFileName(path);
48 |
49 | EventDescription = eventDescription;
50 | eventDescription.createInstance(out EventInstance newInstance);
51 | Instance = newInstance;
52 |
53 | if (source != null)
54 | {
55 | Instance.set3DAttributes(RuntimeUtils.To3DAttributes(source));
56 | RuntimeManager.AttachInstanceToGameObject(Instance, source);
57 | }
58 |
59 | // Cache properties.
60 | eventDescription.isOneshot(out bool isOneshotResult);
61 | IsOneshot = isOneshotResult;
62 |
63 | InitializeParameters();
64 |
65 | Instance.start();
66 |
67 | FmodSyntaxSystem.RegisterActiveEventPlayback(this);
68 | }
69 |
70 | public void Stop()
71 | {
72 | if (Instance.isValid())
73 | Instance.stop(STOP_MODE.ALLOWFADEOUT);
74 | }
75 |
76 | public override void Cleanup()
77 | {
78 | if (Instance.isValid())
79 | {
80 | Instance.stop(STOP_MODE.IMMEDIATE);
81 |
82 | RuntimeManager.DetachInstanceFromGameObject(Instance);
83 | if (EventDescription.isValid())
84 | {
85 | Instance.release();
86 | Instance.clearHandle();
87 | }
88 | }
89 |
90 | FmodSyntaxSystem.UnregisterActiveEventPlayback(this);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodAudioPlayback.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9f9422358271b6f47808272ac35a22c8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodParameterlessAudio.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace RoyTheunissen.FMODSyntax
4 | {
5 | ///
6 | /// Playback of a simple FMOD event without any parameters.
7 | ///
8 | public sealed class FmodParameterlessAudioPlayback : FmodAudioPlayback
9 | {
10 | }
11 |
12 | ///
13 | /// Config of a simple FMOD event without any parameters.
14 | ///
15 | public sealed class FmodParameterlessAudioConfig : FmodAudioConfig, IAudioConfig
16 | {
17 | public FmodParameterlessAudioConfig(string guid) : base(guid)
18 | {
19 | }
20 |
21 | public override FmodParameterlessAudioPlayback Play(Transform source = null)
22 | {
23 | FmodParameterlessAudioPlayback instance = new FmodParameterlessAudioPlayback();
24 | instance.Play(EventDescription, source);
25 | return instance;
26 | }
27 |
28 | IAudioPlayback IAudioConfig.Play(Transform source)
29 | {
30 | FmodParameterlessAudioPlayback instance = new FmodParameterlessAudioPlayback();
31 | instance.Play(EventDescription, source);
32 | return instance;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodParameterlessAudio.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a38ea1c1583aa5a429a776f66e4d26e7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodPlayableConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FMOD;
3 | using FMOD.Studio;
4 | using FMODUnity;
5 |
6 | namespace RoyTheunissen.FMODSyntax
7 | {
8 | ///
9 | /// Base class for configs of Playables (Events and Snapshots).
10 | ///
11 | public abstract class FmodPlayableConfig
12 | {
13 | [NonSerialized] private GUID id;
14 | public string Id => id.ToString();
15 |
16 | ///
17 | /// NOTE: Seems like we can't cache this for some reason that's related to domain reloading. Not sure yet why.
18 | ///
19 | protected EventDescription EventDescription => RuntimeManager.GetEventDescription(id);
20 |
21 | public string Path
22 | {
23 | get
24 | {
25 | EventDescription.getPath(out string path);
26 | return path;
27 | }
28 | }
29 |
30 | public string Name => System.IO.Path.GetFileNameWithoutExtension(Path);
31 |
32 | public bool IsAssigned => !id.IsNull;
33 |
34 | public FmodPlayableConfig(string guid)
35 | {
36 | id = GUID.Parse(guid);
37 | }
38 |
39 | public void Preload()
40 | {
41 | EventDescription.loadSampleData();
42 | }
43 |
44 | public void Unload()
45 | {
46 | EventDescription.unloadSampleData();
47 | }
48 |
49 | public override string ToString()
50 | {
51 | return Name;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/Runtime/Events/FmodPlayableConfig.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ee08425065d285c46a355a7cc6e94246
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodPlayablePlaybackBase.cs:
--------------------------------------------------------------------------------
1 | using FMOD.Studio;
2 | using UnityEngine;
3 |
4 | namespace RoyTheunissen.FMODSyntax
5 | {
6 | ///
7 | /// Non-generic base class for the playback of Playables (Events / Snapshots).
8 | ///
9 | public abstract class FmodPlayablePlaybackBase
10 | {
11 | private EventInstance instance;
12 | protected EventInstance Instance
13 | {
14 | get => instance;
15 | set => instance = value;
16 | }
17 |
18 | private EventDescription eventDescription;
19 | protected EventDescription EventDescription
20 | {
21 | get => eventDescription;
22 | set => eventDescription = value;
23 | }
24 |
25 | public bool CanBeCleanedUp
26 | {
27 | get
28 | {
29 | if (!Instance.isValid())
30 | return true;
31 |
32 | Instance.getPlaybackState(out PLAYBACK_STATE playbackState);
33 | return playbackState == PLAYBACK_STATE.STOPPED;
34 | }
35 | }
36 |
37 | private string name;
38 | public string Name
39 | {
40 | get => name;
41 | protected set => name = value;
42 | }
43 |
44 | private string searchKeywords;
45 | public string SearchKeywords
46 | {
47 | get => searchKeywords;
48 | protected set => searchKeywords = value;
49 | }
50 |
51 | public float NormalizedProgress
52 | {
53 | get
54 | {
55 | if (!eventDescription.isValid() || !instance.isValid())
56 | return 0.0f;
57 |
58 | eventDescription.getLength(out int timelineDurationInMilliseconds);
59 | instance.getTimelinePosition(out int timelinePositionInMilliSeconds);
60 | return (float)(timelinePositionInMilliSeconds / (double)timelineDurationInMilliseconds);
61 | }
62 | }
63 |
64 | public float Volume
65 | {
66 | get
67 | {
68 | if (!eventDescription.isValid() || !instance.isValid())
69 | return 1.0f;
70 | instance.getVolume(out float volume);
71 | return volume;
72 | }
73 | set
74 | {
75 | if (!eventDescription.isValid() || !instance.isValid())
76 | return;
77 |
78 | instance.setVolume(Mathf.Max(value, 0.0f));
79 | }
80 | }
81 |
82 | private float smoothDampVolumeVelocity;
83 |
84 | protected virtual void InitializeParameters()
85 | {
86 | // We need to pass our instance on to our parameters so we can set its values correctly.
87 | }
88 |
89 | public void MoveTowardsVolume(float target, float maxDelta)
90 | {
91 | Volume = Mathf.MoveTowards(Volume, target, maxDelta);
92 | }
93 |
94 | public void SmoothDampTowardsVolume(float target, float duration)
95 | {
96 | // Need to explicitly check for this or it can return NaN if Time.timeScale is 0. Yes, really.
97 | // https://discussions.unity.com/t/mathf-smoothdamp-assigns-nan/383635/13
98 | if (!Mathf.Approximately(Time.deltaTime, 0.0f))
99 | Volume = Mathf.SmoothDamp(Volume, target, ref smoothDampVolumeVelocity, duration);
100 | }
101 |
102 | public abstract void Cleanup();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Runtime/Events/FmodPlayablePlaybackBase.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 92e9b5b4828aad546b9464a2d2ad9fe2
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Events/Parameter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FMOD.Studio;
3 | using FMODUnity;
4 |
5 | #if SCRIPTABLE_OBJECT_COLLECTION
6 | using BrunoMikoski.ScriptableObjectCollections;
7 | #endif // SCRIPTABLE_OBJECT_COLLECTION
8 |
9 | namespace RoyTheunissen.FMODSyntax
10 | {
11 | ///
12 | /// Utility for setting FMOD parameters from code.
13 | ///
14 | public abstract class Parameter
15 | {
16 | protected PARAMETER_ID id;
17 | protected bool isGlobal;
18 |
19 | protected EventInstance instance;
20 |
21 | public Parameter(PARAMETER_ID id, bool isGlobal)
22 | {
23 | this.id = id;
24 | this.isGlobal = isGlobal;
25 | }
26 |
27 | public void InitializeAsEventParameter(EventInstance instance)
28 | {
29 | this.instance = instance;
30 | }
31 | }
32 |
33 | public abstract class ParameterGeneric : Parameter
34 | {
35 | private float floatValue;
36 | public ValueType Value
37 | {
38 | get
39 | {
40 | if (isGlobal)
41 | RuntimeManager.StudioSystem.getParameterByID(id, out floatValue);
42 | else if (instance.isValid())
43 | instance.getParameterByID(id, out floatValue);
44 | return GetValueFromFloat(floatValue);
45 | }
46 | set
47 | {
48 | floatValue = GetFloatFromValue(value);
49 | if (isGlobal)
50 | RuntimeManager.StudioSystem.setParameterByID(id, floatValue);
51 | else if (instance.isValid())
52 | instance.setParameterByID(id, floatValue);
53 | }
54 | }
55 |
56 | protected abstract ValueType GetValueFromFloat(float value);
57 | protected abstract float GetFloatFromValue(ValueType value);
58 |
59 | protected ParameterGeneric(PARAMETER_ID id, bool isGlobal)
60 | : base(id, isGlobal)
61 | {
62 | }
63 | }
64 |
65 | public sealed class ParameterFloat : ParameterGeneric
66 | {
67 | public ParameterFloat(PARAMETER_ID id, bool isGlobal) : base(id, isGlobal)
68 | {
69 | }
70 |
71 | protected override float GetValueFromFloat(float value)
72 | {
73 | return value;
74 | }
75 |
76 | protected override float GetFloatFromValue(float value)
77 | {
78 | return value;
79 | }
80 | }
81 |
82 | public sealed class ParameterInt : ParameterGeneric
83 | {
84 | public ParameterInt(PARAMETER_ID id, bool isGlobal) : base(id, isGlobal)
85 | {
86 | }
87 |
88 | protected override int GetValueFromFloat(float value)
89 | {
90 | return (int)value;
91 | }
92 |
93 | protected override float GetFloatFromValue(int value)
94 | {
95 | return value;
96 | }
97 | }
98 |
99 | public sealed class ParameterEnum : ParameterGeneric
100 | where EnumType : Enum
101 | {
102 | public ParameterEnum(PARAMETER_ID id, bool isGlobal) : base(id, isGlobal)
103 | {
104 | }
105 |
106 | protected override EnumType GetValueFromFloat(float value)
107 | {
108 | return (EnumType)(object)(int)value;
109 | }
110 |
111 | protected override float GetFloatFromValue(EnumType value)
112 | {
113 | return (int)(object)value;
114 | }
115 | }
116 |
117 | #if SCRIPTABLE_OBJECT_COLLECTION
118 | public sealed class ParameterScriptableObjectCollectionItem : ParameterGeneric
119 | where ItemType : ScriptableObjectCollectionItem
120 | {
121 | public ParameterScriptableObjectCollectionItem(PARAMETER_ID id, bool isGlobal) : base(id, isGlobal)
122 | {
123 | }
124 |
125 | protected override ItemType GetValueFromFloat(float value)
126 | {
127 | return ScriptableObjectCollection.Values[(int)value];
128 | }
129 |
130 | protected override float GetFloatFromValue(ItemType value)
131 | {
132 | return value.Index;
133 | }
134 | }
135 | #endif // SCRIPTABLE_OBJECT_COLLECTION
136 |
137 | public sealed class ParameterBool : ParameterGeneric
138 | {
139 | public ParameterBool(PARAMETER_ID id, bool isGlobal) : base(id, isGlobal)
140 | {
141 | }
142 |
143 | protected override bool GetValueFromFloat(float value)
144 | {
145 | return value > 0.5f;
146 | }
147 |
148 | protected override float GetFloatFromValue(bool value)
149 | {
150 | return value ? 1 : 0;
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Runtime/Events/Parameter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dd2d20f1cd1724448aaf3daed853352b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: eb33782e752ffb146a80df7c52b47528
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Extensions/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using UnityEngine;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | public static class StringExtensions
8 | {
9 | private const string HungarianPrefix = "m_";
10 | private const char Underscore = '_';
11 | public const char DefaultSeparator = ' ';
12 |
13 | private static readonly char[] DirectorySeparators = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
14 |
15 | private static bool IsExcludedSymbol(char symbol, char wordSeparator = DefaultSeparator)
16 | {
17 | return char.IsWhiteSpace(symbol) || char.IsPunctuation(symbol) || symbol == wordSeparator;
18 | }
19 |
20 | public static string ToCamelCasing(this string text, char wordSeparator = DefaultSeparator)
21 | {
22 | if (string.IsNullOrEmpty(text))
23 | return text;
24 |
25 | // Split the text up into separate words first then fix spaces and change captialization.
26 | text = text.ToHumanReadable(wordSeparator);
27 |
28 | string camelText = string.Empty;
29 | for (int i = 0; i < text.Length; i++)
30 | {
31 | // Separators cause the next character to be capitalized.
32 | if (char.IsWhiteSpace(text[i]) || text[i] == wordSeparator)
33 | {
34 | // Non-whitespace separators are allowed through.
35 | if (!char.IsWhiteSpace(text[i]))
36 | camelText += text[i];
37 |
38 | // If there is a character after the whitespace, add that as capitalized.
39 | if (i + 1 < text.Length)
40 | {
41 | i++;
42 | camelText += char.ToUpper(text[i]);
43 | }
44 |
45 | continue;
46 | }
47 |
48 | camelText += char.ToLower(text[i]);
49 | }
50 |
51 | return camelText;
52 | }
53 |
54 | public static string ToPascalCasing(this string text, char wordSeparator = DefaultSeparator)
55 | {
56 | if (string.IsNullOrEmpty(text))
57 | return text;
58 |
59 | // Capitalize the first letter.
60 | string camelCasingText = text.ToCamelCasing(wordSeparator);
61 | if (camelCasingText.Length == 1)
62 | return camelCasingText.ToUpper();
63 |
64 | return char.ToUpper(camelCasingText[0]) + camelCasingText.Substring(1);
65 | }
66 |
67 | ///
68 | /// Gets the human readable version of programmer text, like a variable name.
69 | ///
70 | /// The programmer text.
71 | /// The human readable equivalent of the programmer text.
72 | public static string ToHumanReadable(
73 | this string programmerText,
74 | char wordSeparator = DefaultSeparator)
75 | {
76 | if (string.IsNullOrEmpty(programmerText))
77 | return programmerText;
78 |
79 | bool wasLetter = false;
80 | bool wasUpperCase = false;
81 | bool addedSpace = false;
82 | string result = "";
83 |
84 | // First remove the m_ prefix if it exists.
85 | if (programmerText.StartsWith(HungarianPrefix))
86 | programmerText = programmerText.Substring(HungarianPrefix.Length);
87 |
88 | // Deal with any miscellanneous spaces.
89 | if (wordSeparator != DefaultSeparator)
90 | programmerText = programmerText.Replace(DefaultSeparator, wordSeparator);
91 |
92 | // Deal with any miscellanneous underscores.
93 | if (wordSeparator != Underscore)
94 | programmerText = programmerText.Replace(Underscore, wordSeparator);
95 |
96 | // Go through the original string and copy it with some modifications.
97 | for (int i = 0; i < programmerText.Length; i++)
98 | {
99 | // If there was a change in caps add spaces.
100 | if ((wasUpperCase != char.IsUpper(programmerText[i])
101 | || (wasLetter != char.IsLetter(programmerText[i])))
102 | && i > 0 && !addedSpace
103 | && !(IsExcludedSymbol(programmerText[i], wordSeparator) ||
104 | IsExcludedSymbol(programmerText[i - 1], wordSeparator)))
105 | {
106 | // Upper case to lower case.
107 | // I added this so that something like 'GUIItem' turns into 'GUI Item', but that
108 | // means we have to make sure that no symbols are involved. Also check that there
109 | // isn't already a space where we want to add a space. Don't want to double space.
110 | if (wasUpperCase && i > 1 && !IsExcludedSymbol(programmerText[i - 1], wordSeparator)
111 | && !IsExcludedSymbol(result[result.Length - 2], wordSeparator))
112 | {
113 | // From letter to letter means we have to insert a space one character back.
114 | // Otherwise it's going from a letter to a symbol and we can just add a space.
115 | if (wasLetter && char.IsLetter(programmerText[i]))
116 | result = result.Insert(result.Length - 1, wordSeparator.ToString());
117 | else
118 | result += wordSeparator;
119 | addedSpace = true;
120 | }
121 |
122 | // Lower case to upper case.
123 | if (!wasUpperCase)
124 | {
125 | result += wordSeparator;
126 | addedSpace = true;
127 | }
128 | }
129 | else
130 | {
131 | // No case change.
132 | addedSpace = false;
133 | }
134 |
135 | // Add the character.
136 | result += programmerText[i];
137 |
138 | // Capitalize the first character.
139 | if (i == 0)
140 | result = result.ToUpper();
141 |
142 | // Remember things about the previous letter.
143 | wasLetter = char.IsLetter(programmerText[i]);
144 | wasUpperCase = char.IsUpper(programmerText[i]);
145 | }
146 |
147 | return result;
148 | }
149 |
150 | public static string RemovePrefix(this string name, string prefix)
151 | {
152 | if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(prefix))
153 | return name;
154 |
155 | if (!name.StartsWith(prefix))
156 | return name;
157 |
158 | return name.Substring(prefix.Length);
159 | }
160 |
161 | public static string RemoveSuffix(this string name, string suffix)
162 | {
163 | if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(suffix))
164 | return name;
165 |
166 | if (!name.EndsWith(suffix))
167 | return name;
168 |
169 | return name.Substring(0, name.Length - suffix.Length);
170 | }
171 |
172 | ///
173 | /// Converts the slashes to be consistent.
174 | ///
175 | public static string ToUnityPath(this string name)
176 | {
177 | return name.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
178 | }
179 |
180 | private const string AssetsFolder = "Assets";
181 |
182 | public static string RemoveAssetsPrefix(this string path)
183 | {
184 | return path.RemovePrefix(AssetsFolder + Path.AltDirectorySeparatorChar);
185 | }
186 |
187 | public static string GetAbsolutePath(this string projectPath)
188 | {
189 | string absolutePath = projectPath.ToUnityPath().RemoveAssetsPrefix();
190 | return Application.dataPath + Path.AltDirectorySeparatorChar + absolutePath;
191 | }
192 |
193 | public static string GetWhitespacePreceding(this string text, int index, bool includingNewLines)
194 | {
195 | string whitespacePreceding = string.Empty;
196 | if (index > 0)
197 | {
198 | for (int i = index - 1; i >= 0; i--)
199 | {
200 | char c = text[i];
201 | if (c == '\n' && !includingNewLines)
202 | break;
203 | if (char.IsWhiteSpace(c))
204 | whitespacePreceding = text[i] + whitespacePreceding;
205 | else
206 | break;
207 | }
208 | }
209 |
210 | return whitespacePreceding;
211 | }
212 |
213 | public static string GetSection(this string text, string from, string to)
214 | {
215 | if (string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to))
216 | return string.Empty;
217 |
218 | int fromIndex = text.IndexOf(from, StringComparison.Ordinal);
219 | if (fromIndex == -1)
220 | return string.Empty;
221 | fromIndex += from.Length;
222 |
223 | int toIndex = text.IndexOf(to, fromIndex, StringComparison.Ordinal);
224 | if (toIndex == -1)
225 | return string.Empty;
226 |
227 | return text.Substring(fromIndex, toIndex - fromIndex);
228 | }
229 |
230 | public static string GetParentDirectory(this string path)
231 | {
232 | int lastDirectorySeparator = path.LastIndexOfAny(DirectorySeparators);
233 | if (lastDirectorySeparator == -1)
234 | return path;
235 |
236 | return path.Substring(0, lastDirectorySeparator);
237 | }
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/Runtime/Extensions/StringExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 647e8bc42dcac1a49ae16fbef3701d1f
3 | timeCreated: 1470404105
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Runtime/FmodLabelEnum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RoyTheunissen.FMODSyntax
4 | {
5 | ///
6 | /// Attribute to let the FMOD Syntax system know that a custom type is used to represent a labelled parameter.
7 | /// This is useful if for example you have a labelled parameter that is shared between various events, and you want
8 | /// to have only one enum represent it instead of having to map enums back-and-forth. Instead of an enum you can now
9 | /// also use a Scriptable Object Collection item.
10 | ///
11 | public class FmodLabelTypeAttribute : Attribute
12 | {
13 | private string[] labelledParameterNames;
14 | public string[] LabelledParameterNames => labelledParameterNames;
15 |
16 | public FmodLabelTypeAttribute(params string[] labelledParameterNames)
17 | {
18 | this.labelledParameterNames = labelledParameterNames;
19 | }
20 | }
21 |
22 | ///
23 | /// Basically here for backwards compatibility. FmodLabelTypeAttribute is a better name because these days it also
24 | /// supports linking Scriptable Object Collection item types to an FMOD Label parameter. I find it a bit harsh
25 | /// to mark this one as obsolete though, seems harmless to make this one just redirect to FmodLabelTypeAttribute.
26 | ///
27 | public sealed class FmodLabelEnumAttribute : FmodLabelTypeAttribute
28 | {
29 | public FmodLabelEnumAttribute(params string[] labelledParameterNames)
30 | : base(labelledParameterNames)
31 | {
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Runtime/FmodLabelEnum.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b11e62610b60a1440bfabab2cb9b4fdd
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/FmodSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using UnityEngine;
4 | using UnityEngine.Serialization;
5 |
6 | #if UNITY_EDITOR
7 | using UnityEditor;
8 | #endif // UNITY_EDITOR
9 |
10 | namespace RoyTheunissen.FMODSyntax
11 | {
12 | ///
13 | /// Scriptable object that holds all the settings for the FMOD Syntax system.
14 | ///
15 | public sealed class FmodSyntaxSettings : ScriptableObject
16 | {
17 | public enum SyntaxFormats
18 | {
19 | Flat = 0,
20 | FlatWithPathIncludedInName = 1,
21 | SubclassesPerFolder = 2,
22 | }
23 |
24 | [SerializeField] private string generatedScriptsFolderPath;
25 | public string GeneratedScriptsFolderPath => generatedScriptsFolderPath;
26 |
27 | [SerializeField] private string namespaceForGeneratedCode;
28 | public string NamespaceForGeneratedCode => namespaceForGeneratedCode;
29 |
30 | [SerializeField] private bool shouldGenerateAssemblyDefinition;
31 | public bool ShouldGenerateAssemblyDefinition => shouldGenerateAssemblyDefinition;
32 |
33 | [FormerlySerializedAs("generateFallbacksForMissingEvents")]
34 | [Tooltip("If specified, renamed or moved events will first generate an 'alias' so that any existing " +
35 | "references so you can update the references without getting compile errors.")]
36 | [SerializeField] private bool generateFallbacksForChangedEvents = true;
37 | public bool GenerateFallbacksForChangedEvents => generateFallbacksForChangedEvents;
38 |
39 | [Space]
40 | [Tooltip("How to format the events syntax. Different formats suit different use cases:\n\n" +
41 | "Flat - Simplest syntax. All events are inside a class called AudioEvents. Event names have to be unique.\n\n" +
42 | "Flat (With Path Included In Name) - Like Flat but an event called 'Player/Footstep' would generate " +
43 | "a field called 'Player_Footstep'. Keeps things very simple but does prevent name conflicts.\n\n" +
44 | "Subclasses Per Folder - Generates subclasses inside AudioEvents to represent the " +
45 | "folders in the FMOD project. An event called 'Player/Footstep' would be accessed via " +
46 | "'AudioEvents.Player.Footstep'. A very clear and organized way to prevent name clashes but does " +
47 | "require more typing.")]
48 | [SerializeField] private SyntaxFormats syntaxFormat = SyntaxFormats.Flat;
49 | public SyntaxFormats SyntaxFormat => syntaxFormat;
50 |
51 | [NonSerialized] private static FmodSyntaxSettings cachedInstance;
52 | [NonSerialized] private static bool didCacheInstance;
53 | public static FmodSyntaxSettings Instance
54 | {
55 | get
56 | {
57 | #if UNITY_EDITOR
58 | if (!didCacheInstance)
59 | {
60 | string[] guids = AssetDatabase.FindAssets($"t:{nameof(FmodSyntaxSettings)}");
61 | if (guids.Length > 0)
62 | {
63 | string path = AssetDatabase.GUIDToAssetPath(guids[0]);
64 | cachedInstance = AssetDatabase.LoadAssetAtPath(path);
65 | didCacheInstance = cachedInstance != null;
66 | }
67 | }
68 | #endif // UNITY_EDITOR
69 | return cachedInstance;
70 | }
71 | }
72 |
73 | public void InitializeFromWizard(
74 | string generatedScriptsFolderPath, string namespaceForGeneratedCode, bool shouldGenerateAssemblyDefinition)
75 | {
76 | // Sanitize the generated scripts folder path.
77 | this.generatedScriptsFolderPath = generatedScriptsFolderPath.Replace(
78 | Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
79 | if (!this.generatedScriptsFolderPath.EndsWith(Path.AltDirectorySeparatorChar))
80 | this.generatedScriptsFolderPath += Path.AltDirectorySeparatorChar;
81 |
82 | this.namespaceForGeneratedCode = namespaceForGeneratedCode;
83 |
84 | this.shouldGenerateAssemblyDefinition = shouldGenerateAssemblyDefinition;
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Runtime/FmodSyntaxSettings.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b66f732db3a804e4eb5ef4765f45f02f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/FmodSyntaxSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using RoyTheunissen.FMODSyntax.Callbacks;
4 |
5 | namespace RoyTheunissen.FMODSyntax
6 | {
7 | ///
8 | /// Class to use to expose information, help manage playback instances, that sort of thing.
9 | ///
10 | public static class FmodSyntaxSystem
11 | {
12 | private static readonly List activeEventPlaybacks = new List();
13 | public static List ActiveEventPlaybacks => activeEventPlaybacks;
14 |
15 | private static readonly List onEventPlaybackCallbackReceivers = new List();
16 |
17 | private static readonly List activeSnapshotPlaybacks = new List();
18 | public static List ActiveSnapshotPlaybacks => activeSnapshotPlaybacks;
19 |
20 | #if UNITY_EDITOR
21 | [UnityEditor.InitializeOnLoadMethod]
22 | private static void Initialize()
23 | {
24 | activeEventPlaybacks.Clear();
25 | onEventPlaybackCallbackReceivers.Clear();
26 | }
27 | #endif // UNITY_EDITOR
28 |
29 | public static void StopAllActivePlaybacks()
30 | {
31 | StopAllActiveEventPlaybacks();
32 | StopAllActiveSnapshotPlaybacks();
33 | }
34 |
35 | public static void RegisterActiveEventPlayback(FmodAudioPlayback playback)
36 | {
37 | activeEventPlaybacks.Add(playback);
38 |
39 | for (int i = 0; i < onEventPlaybackCallbackReceivers.Count; i++)
40 | {
41 | onEventPlaybackCallbackReceivers[i].OnFmodPlaybackRegistered(playback);
42 | }
43 | }
44 |
45 | public static void UnregisterActiveEventPlayback(FmodAudioPlayback playback)
46 | {
47 | activeEventPlaybacks.Remove(playback);
48 |
49 | for (int i = 0; i < onEventPlaybackCallbackReceivers.Count; i++)
50 | {
51 | onEventPlaybackCallbackReceivers[i].OnFmodPlaybackUnregistered(playback);
52 | }
53 | }
54 |
55 | public static void StopAllActiveEventPlaybacks()
56 | {
57 | for (int i = activeEventPlaybacks.Count - 1; i >= 0; i--)
58 | {
59 | activeEventPlaybacks[i].Stop();
60 | }
61 | }
62 |
63 | public static void RegisterActiveSnapshotPlayback(FmodSnapshotPlayback playback)
64 | {
65 | activeSnapshotPlaybacks.Add(playback);
66 | }
67 |
68 | public static void UnregisterActiveSnapshotPlayback(FmodSnapshotPlayback playback)
69 | {
70 | activeSnapshotPlaybacks.Remove(playback);
71 | }
72 |
73 | ///
74 | /// Culls playbacks that are no longer necessary. You should perform this logic continuously.
75 | /// You can either call this or use the ActivePlaybacks list / playback callbacks to do it in your own system.
76 | ///
77 | public static void CullPlaybacks()
78 | {
79 | // Cull any events that are ready to be cleaned up.
80 | for (int i = activeEventPlaybacks.Count - 1; i >= 0; i--)
81 | {
82 | IFmodPlayback activeEvent = activeEventPlaybacks[i];
83 | if (activeEvent.CanBeCleanedUp)
84 | activeEvent.Cleanup();
85 | }
86 |
87 | // Cull any snapshots that are ready to be cleaned up.
88 | for (int i = activeSnapshotPlaybacks.Count - 1; i >= 0; i--)
89 | {
90 | IFmodPlayback activeSnapshot = activeSnapshotPlaybacks[i];
91 | if (activeSnapshot.CanBeCleanedUp)
92 | activeSnapshot.Cleanup();
93 | }
94 | }
95 |
96 | public static void StopAllActiveSnapshotPlaybacks()
97 | {
98 | for (int i = activeSnapshotPlaybacks.Count - 1; i >= 0; i--)
99 | {
100 | activeSnapshotPlaybacks[i].Stop();
101 | }
102 | }
103 |
104 | [Obsolete("This method is being renamed for disambiguation. " +
105 | "Please use RegisterEventPlaybackCallbackReceiver instead.")]
106 | public static void RegisterPlaybackCallbackReceiver(IOnFmodPlayback callbackReceiver)
107 | {
108 | RegisterEventPlaybackCallbackReceiver(callbackReceiver);
109 | }
110 |
111 | [Obsolete("This method is being renamed for disambiguation. " +
112 | "Please use UnregisterEventPlaybackCallbackReceiver instead.")]
113 | public static void UnregisterPlaybackCallbackReceiver(IOnFmodPlayback callbackReceiver)
114 | {
115 | UnregisterEventPlaybackCallbackReceiver(callbackReceiver);
116 | }
117 |
118 | public static void RegisterEventPlaybackCallbackReceiver(IOnFmodPlayback callbackReceiver)
119 | {
120 | onEventPlaybackCallbackReceivers.Add(callbackReceiver);
121 | }
122 |
123 | public static void UnregisterEventPlaybackCallbackReceiver(IOnFmodPlayback callbackReceiver)
124 | {
125 | onEventPlaybackCallbackReceivers.Remove(callbackReceiver);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Runtime/FmodSyntaxSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 57fd282cadc18f040afa9b8c86cfc243
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/IAudioConfig.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace RoyTheunissen.FMODSyntax
4 | {
5 | public interface IAudioConfig
6 | {
7 | bool IsAssigned { get; }
8 |
9 | IAudioPlayback Play(Transform source = null);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Runtime/IAudioConfig.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 70052d8a0d09c444899a37521f7bcd67
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/IAudioPlayback.cs:
--------------------------------------------------------------------------------
1 | namespace RoyTheunissen.FMODSyntax
2 | {
3 | public interface IFmodPlayback
4 | {
5 | bool CanBeCleanedUp { get; }
6 |
7 | ///
8 | /// Cleanup is responsible for finalizing playback and de-allocating whatever resources were used.
9 | ///
10 | void Cleanup();
11 |
12 | void Stop();
13 | }
14 |
15 | public interface IAudioPlayback : IFmodPlayback
16 | {
17 | string Name { get; }
18 | string SearchKeywords { get; }
19 | bool IsOneshot { get; }
20 | float NormalizedProgress { get; }
21 | float Volume { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Runtime/IAudioPlayback.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3c99c6911d5e40db9dac78b9afcb37c2
3 | timeCreated: 1694637524
--------------------------------------------------------------------------------
/Runtime/RoyTheunissen.FMODSyntax.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RoyTheunissen.FMODSyntax",
3 | "rootNamespace": "RoyTheunissen.FMODSyntax",
4 | "references": [
5 | "FMODUnity",
6 | "BrunoMikoski.ScriptableObjectCollection"
7 | ],
8 | "includePlatforms": [],
9 | "excludePlatforms": [],
10 | "allowUnsafeCode": false,
11 | "overrideReferences": false,
12 | "precompiledReferences": [],
13 | "autoReferenced": true,
14 | "defineConstraints": [],
15 | "versionDefines": [
16 | {
17 | "name": "com.brunomikoski.scriptableobjectcollection",
18 | "expression": "2.2.1",
19 | "define": "SCRIPTABLE_OBJECT_COLLECTION"
20 | }
21 | ],
22 | "noEngineReferences": false
23 | }
--------------------------------------------------------------------------------
/Runtime/RoyTheunissen.FMODSyntax.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f28b76e6ba53ea24ca2daf55c1581312
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime/Snapshots.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 636121fa99ff68b4fbba0031ca936e24
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Snapshots/FmodSnapshotConfig.cs:
--------------------------------------------------------------------------------
1 | namespace RoyTheunissen.FMODSyntax
2 | {
3 | ///
4 | /// Non-generic base class for FmodSnapshotConfig to apply as a type constraint.
5 | ///
6 | public abstract class FmodSnapshotConfigBase : FmodPlayableConfig
7 | {
8 | protected FmodSnapshotConfigBase(string guid) : base(guid)
9 | {
10 | }
11 |
12 | public abstract FmodSnapshotPlayback PlayGeneric();
13 | }
14 |
15 | ///
16 | /// Config for a playable FMOD snapshot. Returns a playback instance of the specified snapshot so you can stop it
17 | /// from there. Very similar to an FMOD event, but represents a certain set of mixer property values. Note that
18 | /// unlike events, snapshots do not have any parameters. As such, we do not need to generate new types of snapshots,
19 | /// we just need to generate snapshots with the appropriate GUIDs.
20 | ///
21 | public abstract class FmodSnapshotConfig : FmodSnapshotConfigBase
22 | where PlaybackType : FmodSnapshotPlayback
23 | {
24 | public FmodSnapshotConfig(string guid) : base(guid)
25 | {
26 | }
27 |
28 | public abstract PlaybackType Play();
29 |
30 | public override FmodSnapshotPlayback PlayGeneric() => Play();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Runtime/Snapshots/FmodSnapshotConfig.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bc7499d217b85de4989fe3be17581408
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Snapshots/FmodSnapshotPlayback.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FMOD;
4 | using FMOD.Studio;
5 | using Debug = UnityEngine.Debug;
6 |
7 | namespace RoyTheunissen.FMODSyntax
8 | {
9 | ///
10 | /// Non-generic base class for FmodSnapshotPlayback to apply as a type constraint.
11 | ///
12 | public abstract class FmodSnapshotPlaybackBase : FmodPlayablePlaybackBase
13 | {
14 | private const string IntensityParameterName = "Intensity";
15 | private const float IntensityParameterRange = 100;
16 |
17 | ///
18 | /// For snapshots it's very useful to define a parameter to control the Intensity setting of the snapshot and
19 | /// thus blend it in and out. This can easily be created by right-clicking the Intensity control in the right
20 | /// of the snapshot editor and choosing Expose As Parameter.
21 | /// NOTE: By default the intensity parameter's values go from 0 - 100 so we respect that.
22 | /// Use IntensityNormalized if you prefer to set it as number between 0 and 1.
23 | ///
24 | public float Intensity
25 | {
26 | get
27 | {
28 | RESULT result = Instance.getParameterByName(IntensityParameterName, out float value);
29 | if (result != RESULT.OK)
30 | {
31 | Debug.LogWarning($"Tried to get {IntensityParameterName} parameter of snapshot '{Name}' but no " +
32 | $"such parameter was found. Did you forget to set up an " +
33 | $"{IntensityParameterName} parameter in FMOD?");
34 | }
35 | return value;
36 | }
37 | set
38 | {
39 | RESULT result = Instance.setParameterByName(IntensityParameterName, value);
40 | if (result != RESULT.OK)
41 | {
42 | Debug.LogWarning($"Tried to set {IntensityParameterName} parameter of snapshot '{Name}' but no " +
43 | $"such parameter was found. Did you forget to set up an " +
44 | $"{IntensityParameterName} parameter in FMOD?");
45 | }
46 | }
47 | }
48 |
49 | public float IntensityNormalized
50 | {
51 | get => Intensity / IntensityParameterRange;
52 | set => Intensity = value * IntensityParameterRange;
53 | }
54 | }
55 |
56 | ///
57 | /// Playback of a snapshot. Sort of like an event, but simpler.
58 | ///
59 | public abstract class FmodSnapshotPlayback : FmodSnapshotPlaybackBase, IFmodPlayback
60 | {
61 | public void Play(EventDescription eventDescription)
62 | {
63 | eventDescription.getPath(out string path);
64 |
65 | if (!eventDescription.isValid())
66 | {
67 | eventDescription.getID(out GUID guid);
68 | Debug.LogError($"Trying to play invalid FMOD Snapshot guid: '{guid}' path:'{path}'");
69 | return;
70 | }
71 |
72 | // Events are called something like event:/ but we want to get rid of any prefix like that.
73 | // Also every 'folder' along the way will be treated like a sort of 'tag'
74 | SearchKeywords = path.Substring(path.IndexOf("/", StringComparison.Ordinal) + 1).Replace('/', ',');
75 |
76 | Name = Path.GetFileName(path);
77 |
78 | EventDescription = eventDescription;
79 | eventDescription.createInstance(out EventInstance newInstance);
80 | Instance = newInstance;
81 |
82 | InitializeParameters();
83 |
84 | Instance.start();
85 |
86 | FmodSyntaxSystem.RegisterActiveSnapshotPlayback(this);
87 | }
88 |
89 | public void Stop()
90 | {
91 | if (Instance.isValid())
92 | Instance.stop(STOP_MODE.ALLOWFADEOUT);
93 | }
94 |
95 | public override void Cleanup()
96 | {
97 | if (Instance.isValid())
98 | {
99 | Instance.stop(STOP_MODE.IMMEDIATE);
100 |
101 | if (EventDescription.isValid())
102 | {
103 | Instance.release();
104 | Instance.clearHandle();
105 | }
106 | }
107 |
108 | FmodSyntaxSystem.UnregisterActiveSnapshotPlayback(this);
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Runtime/Snapshots/FmodSnapshotPlayback.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7c7fbd29f2e74e1193881d2778de30ad
3 | timeCreated: 1698868389
--------------------------------------------------------------------------------
/Runtime/Snapshots/SnapshotReference.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using UnityEngine;
6 |
7 | namespace RoyTheunissen.FMODSyntax
8 | {
9 | ///
10 | /// Inspector reference to FMOD snapshot config. Can be used to specify via the inspector which snapshot to play.
11 | ///
12 | [Serializable]
13 | public class SnapshotReference
14 | {
15 | [SerializeField] private string fmodSnapshotGuid;
16 |
17 | [NonSerialized] private FmodSnapshotConfigBase cachedFmodSnapshotConfig;
18 | [NonSerialized] private string guidFmodSnapshotConfigIsCachedFor;
19 | private FmodSnapshotConfigBase FmodSnapshotConfig
20 | {
21 | get
22 | {
23 | if (guidFmodSnapshotConfigIsCachedFor != fmodSnapshotGuid)
24 | {
25 | guidFmodSnapshotConfigIsCachedFor = fmodSnapshotGuid;
26 | cachedFmodSnapshotConfig = GetSnapshotConfig(fmodSnapshotGuid);
27 | if (!string.IsNullOrEmpty(fmodSnapshotGuid) && cachedFmodSnapshotConfig == null)
28 | {
29 | Debug.LogError($"FMOD event was assigned to snapshot reference but its corresponding config " +
30 | $"could not be found at runtime. Did you forget to compile FMOD code?");
31 | }
32 | }
33 | return cachedFmodSnapshotConfig;
34 | }
35 | }
36 |
37 | public bool IsAssigned => FmodSnapshotConfig != null;
38 |
39 | public string Name => IsAssigned ? FmodSnapshotConfig.Name : "";
40 | public string Path => IsAssigned ? FmodSnapshotConfig.Path : "";
41 |
42 | [NonSerialized] private static bool didCacheSnapshots;
43 | private static readonly Dictionary snapshotsByGuid =
44 | new Dictionary();
45 |
46 | public FmodSnapshotPlayback Play()
47 | {
48 | return FmodSnapshotConfig.PlayGeneric();
49 | }
50 |
51 | #if UNITY_EDITOR
52 | [UnityEditor.InitializeOnLoadMethod]
53 | private static void Initialize()
54 | {
55 | snapshotsByGuid.Clear();
56 | didCacheSnapshots = false;
57 | }
58 | #endif // UNITY_EDITOR
59 |
60 |
61 | public static FmodSnapshotConfigBase GetSnapshotConfig(string guid)
62 | {
63 | CacheSnapshotConfigs();
64 |
65 | if (snapshotsByGuid.TryGetValue(guid, out FmodSnapshotConfigBase result))
66 | return result;
67 |
68 | return null;
69 | }
70 |
71 | private static void CacheSnapshotConfigs()
72 | {
73 | if (didCacheSnapshots)
74 | return;
75 |
76 | didCacheSnapshots = true;
77 |
78 | snapshotsByGuid.Clear();
79 |
80 | // Find every class with name AudioSnapshots.
81 | const string containerClassName = "AudioSnapshots";
82 | IEnumerable containerTypes = AppDomain.CurrentDomain.GetAssemblies()
83 | .SelectMany(assembly => assembly.GetTypes()).Where(t => t.Name == containerClassName);
84 |
85 | foreach (Type containerType in containerTypes)
86 | {
87 | // Find all the fields declared in those container classes.
88 | FieldInfo[] fields = containerType.GetFields(BindingFlags.Public | BindingFlags.Static);
89 | for (int i = 0; i < fields.Length; i++)
90 | {
91 | if (!typeof(FmodSnapshotConfigBase).IsAssignableFrom(fields[i].FieldType))
92 | continue;
93 |
94 | // If the field is a valid snapshot config, add it to the dictionary.
95 | if (fields[i].GetValue(null) is FmodSnapshotConfigBase snapshotConfig)
96 | snapshotsByGuid.Add(snapshotConfig.Id, snapshotConfig);
97 | }
98 | }
99 | }
100 |
101 | public override string ToString()
102 | {
103 | FmodSnapshotConfigBase config = FmodSnapshotConfig;
104 | return config == null ? "" : config.ToString();
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Runtime/Snapshots/SnapshotReference.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 609dd020242bedf43af1d71f0b213971
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/VCAs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 50f6273335e30624ba2c1b20db22a65b
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/VCAs/VCA.cs:
--------------------------------------------------------------------------------
1 | using FMOD.Studio;
2 | using FMODUnity;
3 |
4 | namespace RoyTheunissen.FMODSyntax
5 | {
6 | ///
7 | /// Utility for accessing the VCAs more conveniently.
8 | ///
9 | public class VCA
10 | {
11 | private readonly string path;
12 |
13 | ///
14 | /// NOTE: Seems like we can't cache this for some reason that's related to domain reloading. Not sure yet why.
15 | ///
16 | private FMOD.Studio.VCA FmodVca => RuntimeManager.GetVCA(path);
17 |
18 | public float VolumeLinear
19 | {
20 | get => FmodVca.getVolume();
21 | set => FmodVca.setVolume(value);
22 | }
23 |
24 | public VCA(string path)
25 | {
26 | this.path = path;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Runtime/VCAs/VCA.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4aec168eb379b7b40877c98385434dbe
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/VCAs/VCAExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace FMOD.Studio
2 | {
3 | ///
4 | /// Extensions for VCA to get the path without an out parameter to make lambda functions easy to write.
5 | ///
6 | public static class VCAExtensions
7 | {
8 | public static string getPath(this FMOD.Studio.VCA vca)
9 | {
10 | vca.getPath(out string path);
11 | return path;
12 | }
13 |
14 | public static float getVolume(this FMOD.Studio.VCA vca)
15 | {
16 | vca.getVolume(out float volume);
17 | return volume;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Runtime/VCAs/VCAExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 12322f111decb53458fa73a921bd3197
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.roytheunissen.fmod-syntax",
3 | "displayName": "FMOD Syntax",
4 | "version": "0.2.3",
5 | "unity": "2021.3",
6 | "description": "Generates code to allow invoking FMOD events with a strongly-typed syntax.",
7 | "keywords": [
8 | "FMOD",
9 | "Audio",
10 | "Code Generation"
11 | ],
12 | "author": {
13 | "name": "Roy Theunissen",
14 | "url": "https://www.roytheunissen.com"
15 | },
16 | "category": "audio",
17 | "homepage": "https://github.com/RoyTheunissen/FMOD-Syntax",
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/RoyTheunissen/FMOD-Syntax"
21 | },
22 | "bugs": "https://github.com/RoyTheunissen/FMOD-Syntax/issues"
23 | }
24 |
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9381d3b6ee2b4dc47a6dccb6aacaed4a
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------