public sealed class MusicPlayerMusic that reacts, without gameplay knowing what a bar is.
No guide page documents this yet — the page shows what the code says about itself.
Remarks
The problem this solves is timing, not sequencing. Playing one piece of music after another is a queue and needs nothing; the hard part is that gameplay decides to change the music at an arbitrary instant and music cannot change at an arbitrary instant. Everything here is arranged around separating "a fight started" from "the music changes at the top of the next bar".
The incoming segment is scheduled to the sample. Its start is an absolute frame on the device's own clock, so it lands where it was asked to whatever the frame rate is doing. The outgoing one is faded over CrossfadeSeconds rather than cut, because a hard cut between two unrelated pieces of music is a click at worst and a seam at best, while a fortieth of a second of overlap is inaudible and standard. The join that matters musically is where the new material begins, and that one is exact.
Looping is the provider's, not a rescheduling. A looping segment is one voice with Loop set, so the wrap is seamless by construction — restarting the clip each time round would put a block boundary at every loop point, which is the seam every naive music system has.
Game thread only, and Update must be called each frame. Nothing here runs on the audio thread; what reaches it is a StartFrame and the ordinary voice fields.
Fields and properties (8)
public MusicTransport TransportWhere the music is, in samples the device actually produced.
public int BusWhich bus the music plays on.
public float CrossfadeSecondsHow long the outgoing segment takes to get out of the way.
public MusicSegment? CurrentWhat is playing.
public MusicSegment? QueuedWhat is scheduled to play next, if anything.
public long QueuedAtFrameThe device frame Queued begins at.
public bool IsPlayingWhether anything is playing or scheduled.
public bool IsSustainingWhether the music is holding at a sustain point, waiting to be let go.
Events (4)
public Action<long>? BeatPassedRaised as the playhead crosses a beat, with its number from the segment's start.
public Action<long>? BarPassedRaised as the playhead crosses a bar line.
public Action<string>? MarkerPassedRaised as the playhead crosses a named marker.
public Action<MusicSegment>? SegmentStartedRaised when a segment actually begins, rather than when it was scheduled.
Methods (10)
public MusicPlayer(AudioEngine engine, int bus = 0)A player on an engine.
public bool Release()Lets a sustaining segment move on.
public void Add(MusicSegment segment)Adds a segment it can play.
public void AddTransition(MusicTransition transition)Adds a rule about when the music may change on its own.
public MusicSegment? Find(string name)Finds a segment by name.
public bool Play(string name)Starts a segment now, cutting off whatever was playing.
public bool TransitionTo(string name, MusicQuantize quantize = Bar)Asks for a segment, to land where it is allowed to.
public VoiceHandle PlayStinger(AudioClip clip, MusicQuantize quantize = Beat, float gainDb = 0)Fires a one-shot over the top of whatever is playing.
public void Stop(MusicQuantize quantize = Immediate)Stops the music.
public void Update()Advances the music. Once a frame, on the game thread.
Used by (2)
- MusicBuilderVixen.Audio
- MusicPlayerTestsVixen.Audio.Tests