Ryle Radio 1.0.0
An open-source "radio" system for Unity, allowing tracks, tuning, broadcasters, and more!
Loading...
Searching...
No Matches
RadioDataEditor.cs
1using UnityEngine;
2
3namespace RyleRadio.Editor
4{
5 using RyleRadio.Tracks;
6
7#if UNITY_EDITOR
8 using UnityEditor;
9
10 /// <summary>
11 /// A custom editor for \ref RadioData
12 /// <br><br> This mainly exists so that we can reset tracks when they're newly added to the RadioData and prevent them from being linked- I don't think it actually does its job for that, though
13 /// <br><br><b>See: </b>\ref RadioData
14 /// </summary>
15 [CustomEditor(typeof(RadioData))]
16 public class RadioDataEditor : Editor
17 {
18 /// The tracks contained in this radio
19 private SerializedProperty trackWs;
20 /// The last recorded number of tracks contained in this radio
21 private int lastTrackWSize;
22
23 /// The primary colour of gizmos on components referencing this radio
24 private SerializedProperty gizmoColor;
25 /// The secondary colour of gizmos on components referencing this radio
26 private SerializedProperty gizmoColorSecondary;
27
28 /// Toggles whether or not we should force the sample rate on AudioClips used in this radio
29 private SerializedProperty forceClipSampleRate;
30 /// The sample rate we're forcing on AudioClips used in this radio- if left at 0, picks the project's default sample rate
31 private SerializedProperty forcedSampleRate;
32
33 /// Toggle drawing of advanced settings
34 private bool showAdvanced = false;
35
36
37 /// <summary>
38 /// Initializes this object on inspector init
39 /// </summary>
40 private void OnEnable()
41 {
42 // store gizmo colours
43 gizmoColor = serializedObject.FindProperty("gizmoColor");
44 gizmoColorSecondary = serializedObject.FindProperty("gizmoColorSecondary");
45
46 forceClipSampleRate = serializedObject.FindProperty("forceClipSampleRate");
47 forcedSampleRate = serializedObject.FindProperty("forcedSampleRate");
48
49 // store tracks
50 trackWs = serializedObject.FindProperty("trackWs");
51 lastTrackWSize = trackWs.arraySize;
52
53 // for every track,
54 for (int i = 0; i < trackWs.arraySize; i++)
55 {
56 // cache it
57 SerializedProperty track = trackWs.GetArrayElementAtIndex(i);
58
59 // get the internal track class and the string eventType
60 SerializedProperty radioTrack = track.FindPropertyRelative("track");
61 SerializedProperty trackType = track.FindPropertyRelative("trackType");
62
63 // if the track itself is null somehow, (e.g it's the first track added when the data is created)
64 if (radioTrack.managedReferenceValue == null)
65 {
66 // set a default track class based on the listed track eventType string
67 radioTrack.managedReferenceValue = RadioTrackWrapper.CreateTrackEditor(trackType.stringValue);
68 }
69 else
70 {
71 // set the track eventType string to whatever the internal track class is
72 trackType.stringValue = RadioTrackWrapper.GetTrackType(radioTrack.managedReferenceValue.ToString());
73 }
74 }
75
76 // apply the changes
77 serializedObject.ApplyModifiedProperties();
78 }
79
80 /// <summary>
81 /// Draws variables, buttons, etc
82 /// </summary>
83 public override void OnInspectorGUI()
84 {
85 // update the rest of the inspector
86 serializedObject.Update();
87
88 // show the foldout that hides advanced vars
89 showAdvanced = EditorGUILayout.Foldout(showAdvanced, new GUIContent("Advanced Settings"));
90
91 // if the foldout is open,
92 if (showAdvanced)
93 {
94 DrawAdvancedOptions();
95 }
96
97 // display the tracks
98 EditorGUILayout.PropertyField(trackWs, new GUIContent("Tracks", "These are actually RadioTrackWrappers, not RadioTracks"));
99
100 // if something has been changed
101 if (GUI.changed)
102 {
103 // if a track has been added,
104 if (trackWs.arraySize > lastTrackWSize)
105 {
106 InitNewTrack();
107 }
108 // if a track has been removed
109 else if (trackWs.arraySize < lastTrackWSize)
110 {
111 // store the new track list size
112 lastTrackWSize--;
113 }
114 }
115
116 // apply inspector changes
117 serializedObject.ApplyModifiedProperties();
118 }
119
120 /// <summary>
121 /// Draws the advanced options (gizmo colours, sample rate forcing, cache clear)
122 /// </summary>
123 private void DrawAdvancedOptions()
124 {
125 // display the gizmo colour vars
126 EditorGUILayout.PropertyField(gizmoColor, new GUIContent("Gizmo Colour"));
127 EditorGUILayout.PropertyField(gizmoColorSecondary, new GUIContent("Secondary Gizmo Colour"));
128
129 // toggle for whether or not the user wants to force a sample rate on clips referenced in this radio
130 forceClipSampleRate.boolValue = EditorGUILayout.BeginToggleGroup("Force sample rate on Clips", forceClipSampleRate.boolValue);
131
132 // the sample rate to force on the clips
133 EditorGUILayout.PropertyField(forcedSampleRate, new GUIContent("Forced sample rate"));
134
135 // a button to manually perform the sample rate forcing
136 if (GUILayout.Button(new GUIContent("Force Clips to sample rate")))
137 ForceClipsToSampleRate();
138
139 // finish the toggled area
140 EditorGUILayout.EndToggleGroup();
141
142 // button to manually clear the name and ID caches of the radio
143 if (GUILayout.Button(new GUIContent("Clear Cache")))
144 ((RadioData)serializedObject.targetObject).ClearCache();
145 }
146
147 /// <summary>
148 /// Initializes a newly created track
149 /// </summary>
150 private void InitNewTrack()
151 {
152 // cache it
153 SerializedProperty newElement = trackWs.GetArrayElementAtIndex(trackWs.arraySize - 1);
154
155 // get the internal class and eventType
156 SerializedProperty radioTrack = newElement.FindPropertyRelative("track");
157 SerializedProperty trackType = newElement.FindPropertyRelative("trackType");
158
159 // get the gain
160 SerializedProperty gain = newElement.FindPropertyRelative("gain");
161
162 // get the gain curve
163 SerializedProperty rangeCurve = newElement.FindPropertyRelative("rangeCurve");
164
165 // reset the internal track class
166 radioTrack.managedReferenceValue = RadioTrackWrapper.CreateTrackEditor(trackType.stringValue);
167
168 // reset the gain and the gain curve
169 gain.floatValue = 100;
170 rangeCurve.animationCurveValue = new(RadioTrackWrapper.DefaultRangeCurve.keys);
171
172 // store the new track list size
173 lastTrackWSize++;
174 }
175
176 /// <summary>
177 /// Get all AudioClips used in this radio, and override their sample rates all at once. This is done to reduce distortion when converting between sample rates at runtime- if you're okay with the distortion there's no issue
178 /// </summary>
179 private void ForceClipsToSampleRate()
180 {
181 // for every track in this radio,
182 for (int i = 0; i < trackWs.arraySize; i++)
183 {
184 // get its wrapper
185 SerializedProperty wrapper = trackWs.GetArrayElementAtIndex(i);
186
187 // if the wrapper is a clip,
188 if (wrapper.FindPropertyRelative("track").managedReferenceValue is ClipRadioTrack clipTrack)
189 {
190 // force the clip's sample rate
191 ForceSingleClipToSampleRate(clipTrack.clip);
192 }
193 // otherwise if the wrapper is a station (and therefore could contain a clip)
194 else if (wrapper.FindPropertyRelative("track").managedReferenceValue is StationRadioTrack stationTrack)
195 {
196 // for every track in this station
197 foreach (StationRadioTrackWrapper sTrackW in stationTrack.stationTrackWs)
198 {
199 // if the track has a referenced clip (is a ClipRadioTrack)
200 if (sTrackW.EditorChildClip != null)
201 ForceSingleClipToSampleRate(sTrackW.EditorChildClip); // force its sample rate
202 }
203 }
204 }
205 }
206
207 /// <summary>
208 /// Override the sample rate of a specific AudioClip
209 /// </summary>
210 /// <param name="_clip">The clip to override the sample rate on</param>
211 private void ForceSingleClipToSampleRate(AudioClip _clip)
212 {
213 // get the import settings for the clip
214 AudioImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(_clip)) as AudioImporter;
215
216 // get the current build target of the game
217 string buildTarget = BuildPipeline.GetBuildTargetName(EditorUserBuildSettings.activeBuildTarget);
218
219 // get the custom sample settings of the clip
220 var sampleSettings = importer.GetOverrideSampleSettings(buildTarget);
221
222 // enable the sample rate override
223 sampleSettings.sampleRateSetting = AudioSampleRateSetting.OverrideSampleRate;
224
225 // save whatever the sample rate is now
226 uint lastSampleRate = sampleSettings.sampleRateOverride;
227
228 // if a chosen sample rate has been provided,
229 if (forceClipSampleRate.intValue > 0)
230 sampleSettings.sampleRateOverride = (uint)forcedSampleRate.intValue; // set it to that
231 else // otherwise if it's set to 0 or less,
232 sampleSettings.sampleRateOverride = (uint)AudioSettings.outputSampleRate; // set it to the game's default
233
234 // if the sample rate was changed, let the user know
235 if (sampleSettings.sampleRateOverride != lastSampleRate)
236 Debug.Log("Changed clip {_clip} sample rate to {sampleSettings.sampleRateOverride} for platform {buildTarget}.");
237
238 // apply the sample rate override
239 importer.SetOverrideSampleSettings(buildTarget, sampleSettings);
240 }
241 }
242#endif
243
244}
Editor scripts for classes and attributes, notably excluding MultiselectAttribute.