feat: SyncPoint.SameAsCurrentSegment music transition

- Add SameAsCurrentSegment mode to align new container's timeSamples with the old container's playback position, accounting for FadeInOffset
- Fix BeatClock callback burst when Restart is called with a past dspTime
- Add GetFirstLeafSource() for resolving playback position across nested containers
- Manual BeatClock.Restart replaces OnContainerEntered subscription for accurate timing with SyncPoint
This commit is contained in:
2026-04-16 20:50:34 +08:00
parent e2c9c53aa3
commit 2b34d0bf94
13 changed files with 182 additions and 44 deletions
@@ -65,15 +65,16 @@ namespace OCES.Audio
IEnumerator BeatCoroutine()
{
long index = 0; // 从第 1 拍开始,第 0 拍是起始点本身
double elapsed = AudioSettings.dspTime - this.m_startDspTime;
long index = elapsed > 0.05 ? (long)(elapsed / this.m_secondsPerBeat) : 0;
while (true)
{
double nextTime = this.m_startDspTime + index * this.m_secondsPerBeat;
yield return new WaitUntil(() => AudioSettings.dspTime >= nextTime - 0.02);
while (AudioSettings.dspTime < nextTime)
yield return null;
if (this.m_blendError || this.m_stopped){
yield break;
}
@@ -84,12 +85,14 @@ namespace OCES.Audio
IEnumerator BarCoroutine()
{
long index = 0;
double elapsed = AudioSettings.dspTime - this.m_startDspTime;
double secondsPerBar = this.m_secondsPerBeat * this.m_beatsPerBar;
long index = elapsed > 0.05 ? (long)(elapsed / secondsPerBar) : 0;
while (true)
{
double nextTime = this.m_startDspTime + index * this.m_secondsPerBeat * this.m_beatsPerBar;
double nextTime = this.m_startDspTime + index * secondsPerBar;
yield return new WaitUntil(() => AudioSettings.dspTime >= nextTime - 0.02);
while (AudioSettings.dspTime < nextTime)
yield return null;
if (this.m_blendError || this.m_stopped){
@@ -102,12 +105,14 @@ namespace OCES.Audio
IEnumerator GridCoroutine()
{
long index = 0;
double elapsed = AudioSettings.dspTime - this.m_startDspTime;
double secondsPerGrid = this.m_secondsPerBeat * this.m_beatsPerBar * this.m_barsPerGrid;
long index = elapsed > 0.05 ? (long)(elapsed / secondsPerGrid) : 0;
while (true)
{
double nextTime = this.m_startDspTime + index * this.m_secondsPerBeat * this.m_beatsPerBar * this.m_barsPerGrid;
double nextTime = this.m_startDspTime + index * secondsPerGrid;
yield return new WaitUntil(() => AudioSettings.dspTime >= nextTime - 0.02);
while (AudioSettings.dspTime < nextTime)
yield return null;
if (this.m_blendError || this.m_stopped){