Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Seeking Example Project

This example demonstrates seeking for scriptable processors: repositioning a playing generator to a new point on its timeline, either immediately or scheduled to fire sample-accurately when playback reaches a chosen position.

The project targets Unity 6.7 and is built on the Scriptable audio pipeline APIs. Seeking is delivered to a live generator instance with SeekMessage.

Run the demo

Open the project in Unity 6.7, open Assets/Scenes/Seeking.unity, and enter Play Mode.

The scene contains a single Seek Tester GameObject (a SeekTester, a ClipPlayerGenerator with Count1To10.wav assigned, and an AudioSource) and a Main Camera that provides the AudioListener. A GUI panel appears in Play Mode:

  • Playback starts stopped. Use the Play/Stop button.
  • Pick when a seek should fire (the clip second at which it triggers) with the slider, then click a number button to enqueue "when the clip reaches that second, jump so I hear number N".
  • Enable Fire immediately to ignore when and seek at the next process block instead.
  • You can build a queue while stopped; it is delivered when you press Play, so several seeks end up queued on the generator at once.
  • The panel schedules on whole-second boundaries for legibility; SeekMessage itself accepts any DiscreteTime.

The clip counts "one" through "ten" over roughly ten seconds, so the audible result makes each seek easy to verify by ear.

How seeking works

A seek is a message sent to a live generator instance. There are two forms:

Call Effect
new SeekMessage(destination) Immediate seek: jump to destination at the next process block.
new SeekMessage(destination, when) Scheduled seek: jump to destination when the timeline reaches when.

Both destination and when are DiscreteTime values; DiscreteTime(int) is interpreted as whole seconds here. The message is delivered with:

var msg = new SeekMessage(destination, when);
var response = ControlContext.builtIn.SendMessage(instance, ref msg);

The instance only exists a frame or so after AudioSource.Play(), so SeekTester waits until ControlContext.builtIn.Exists(source.generatorInstance) is true before flushing its queued seeks.

The generator applies seeks in the order you send them. It never reorders them by when. A scheduled seek that isn't due yet holds back every seek sent after it, including immediate ones, so send seeks in the order you want them to happen.

Each seek moves the playback position to its destination, and the remaining seeks' when values are compared against that new position. If playback has already passed a seek's when by the time it's next in line, for example because an earlier seek jumped past it, the generator drops it and logs a warning.

If you seek while the clip is still loading, only the most recent seek is kept, and the earlier ones are dropped with a warning.

The scripts

The implementation is two small MonoBehaviours in Assets/Scripts/.

File Role
ClipPlayerGenerator.cs An IAudioGenerator that wraps the clip's own generator instance (clip.CreateInstance), which is what handles seeks. Its realtime side forwards each Process call to that nested instance and watches the returned Result; SeekMessages arriving at the wrapper are forwarded down unchanged. When the nested instance reports isFinished(), the realtime side sends a datum over the pipe and the control side relays it to ClipPlaybackState on the main thread.
SeekTester.cs A manual seek playground. Wires the generator onto an AudioSource, draws the GUI transport, sends SeekMessages to the live instance, and stops the source when ClipPlaybackState reports the clip has finished.