Hi,
I’m working on a dialog/subtitle playable and everything is working like a charm, my only problem is that I can’t figure out how to set the playable duration in the code.
I have an AudioClip and I would like to set playable duration the same of AudioClip lenght.
This is a known issue, and something we want to address. You can override the duration property in your PlayableAsset representing your clip, and set it to the the audio clip length.
As an example, here is how we do the duration for the audio clip track (the extra math keeps better frame alignment):
public override double duration
{
get
{
if (m_Clip == null)
return base.duration;
// use this instead of length to avoid rounding precision errors,
return (double)m_Clip.samples / (double)m_Clip.frequency;
}
}
The problem is typically you create the clip prior to assigning the audio clip, so you need to pick a default when nothing is assigned. Once the audio clip is assigned, if you right click on the clip and go to Editing → Reset Editing it will change the length to the audio clip in that case.
Some of the customization improvements on our backlog is to better support drag and drop for custom types. That would allow drag and drop of an audio clip to your custom track to assign the audio clip before determining a default length.
Hi and thank you so much for your answer. In which one of the various scripts which compose the playable should I write that code?
Is there any API to invoke this “Reset Editing” functionality by code? Would be great to auto-size clips that are generated by code.
Reset Editing doesn’t have an API call, but if you create the clip via code, you should be able to something like
var clip = track.CreateDefaultClip();
clip.duration = (double) audioClip.sample / audioClip.frequency;
That totally works, thanks!
If you want the duration to update when you’re changing the audio clip you can do it by creating a custom property drawer for your behaviour and implementing the following code.
Taking @Mars91 's example of dialog/subtitle track assuming you have a clip with a behaviour “template” similar to created by the playables wizard and an ExposedReference variable on the clip.
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(SubtitleBehaviour))]
public class SubtitleBehaviourDrawer : PropertyDrawer
{
public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, true);
}
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
// Draw the behaviours properties
EditorGUI.PropertyField(position, property, true);
// Find the clip this behaviour is associated with a grab the audio clip
SubtitleClip clip = property.serializedObject.targetObject as SubtitleClip;
AudioClip audioClip = clip._Audio.Resolve(property.serializedObject.context as IExposedPropertyTable);
if(audioClip)
{
// Assume that the currently selected object is the internal class UnityEditor.Timeline.EditorClip
// this gives you access to the clip start, duration etc.
SerializedObject editorGUI = new SerializedObject(Selection.activeObject);
// Grab the duration, set and apply modified properties
SerializedProperty duration = editorGUI.FindProperty("m_Clip.m_Duration");
duration.doubleValue = (double) audioClip.samples / audioClip.frequency;
editorGUI.ApplyModifiedProperties();
}
}
}
You can then change the audio clip and see the clip duration update.
Thanks, this helped me a bit closer to finding a solution my (unrelated) problem.
I’m trying to select specific UnityEditor.Timeline.EditorClip’s in a timeline from another script.
Basically what I want to do is to set Selection.activeObject = Some Editorclip.
My problem is that I cant figure out how to locate the references to editorclips, do you know where I can find the editorclips relative to a specific Timeline track?
Any bright ideas?
How would I go about getting the bound GO from the track so I could set the duration based on its data?
The GO passed to CreatePlayable or CreateTrackMixer is the game object that contains the playing playable director. From the playable director you can use GetGenericBinding, passing the track as the key, to get the binding for that track. You will need to cast it to your specific type.
Note: FindProperty root is “m_Item” vice “m_Clip” in Unity 2017.2+.
Has this gotten any easier over the last couple years?
I have a GO in the editor scene that has a custom MB on it. That MB has frame data including its duration. When creating a CLIP from this Object in Timeline, artists want the clip to be auto set to the correct duration of the underlying object but I’m getting super confused trying to unravel all these pieces involved.
I know I posted 2 years ago asking how to get the bound object from the tack, but what I really need is to get the bound object from the clip. I think?
I need the clip to be created with the proper duration set from the data in the bound object.
If you are using 2019.2, you can make a clip editor for your type. It gets a callback on create, so you can set a default duration for your clip.
[CustomTimelineEditor(typeof(MyClip))]
public class MyClipEditor : ClipEditor
{
public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom)
{
var myClip = (MyClip) clip.asset;
var obj = TimelineEditor.inspectedDirector.GetReferenceValue(myClip.exposedProperty.exposedName, out _) as MyBindingType;
if (obj != null)
myClip.defaultDuration = obj.duration;
base.OnCreate(clip, track, clonedFrom);
}
}
public class MyClip : PlayableAsset
{
public ExposedReference<MyBindingType> exposedProperty;
public double defaultDuration = 5;
// this is used as the default duration of the clip when created
public override double duration { get { return defaultDuration; } }
}
It sets the default duration instead of just the clip duration, so actions like Reset to default length work.
Wow that looks a LOT easier than in the past. Thanks! I’ll tackle this today but looks simple enough with that new ClipEditor class.
Another question, if we change the Clip duration in Inspector, how can we receive this message from Code? I had try TrackAsset.UpdateDuration and it should work, but it get invoked many times and I can’t get ExposedReference data inside UpdateDuration.
If it’s your own track type, you should put the code in the inspector and use this API to check for changes.
But if you want to do this for a built-in track, it might be a lot harder. Timeline doesn’t typically react to clip content changes except for start time, duration and blends. It only reacts to the content changes to recreate the graph.
Since what you are authoring are timings, it’s generally a bad idea to automatically change the timing of a clip when the contents change, as it will throw off all your edits.
What are you attempting to react to?
@DavidGeoffroy ClipEditor doesn’t seem to have a serializedObject property… how do we get the serialized object to use? Sorry if I’m missing something obvious.