Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F bgm loop #127

Draft
wants to merge 2 commits into
base: mod
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Assembly-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@
<Compile Include="LTSpline.cs" />
<Compile Include="MenuUIController.cs" />
<Compile Include="MOD.Scripts.Core.Audio\MODBGMInfo.cs" />
<Compile Include="MOD.Scripts.Core.Audio\MODPreLoopAudio.cs" />
<Compile Include="MOD.Scripts.Core.Config\MODConfig.cs" />
<Compile Include="MOD.Scripts.Core.Config\MODConfigManager.cs" />
<Compile Include="MOD.Scripts.Core.Movie\AVProMovieRenderer.cs" />
Expand Down
26 changes: 21 additions & 5 deletions Assets.Scripts.Core.Audio/AudioLayerUnity.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Assets.Scripts.Core.AssetManagement;
using Assets.Scripts.Core.Audio;
using MOD.Scripts.Core.Audio;
using System;
using System.Collections;
using UnityEngine;
Expand All @@ -14,6 +15,8 @@ internal class AudioLayerUnity : MonoBehaviour

private AudioClip audioClip;

private MODPreLoopAudio preLoopAudio = new MODPreLoopAudio();

private AudioFinishCallback finishCallback;

private OnFinishLoad onFinishLoad;
Expand Down Expand Up @@ -102,6 +105,7 @@ public void StopAudio()
{
Destroy(audioClip);
}
preLoopAudio.StopAudio();
loadedName = string.Empty;
audioClip = null;
iTween.Stop(base.gameObject);
Expand All @@ -118,7 +122,7 @@ public bool IsPlaying()
{
return false;
}
return audioSource.isPlaying;
return preLoopAudio.IsPlaying() || audioSource.isPlaying;
}

public float GetRemainingPlayTime()
Expand All @@ -127,17 +131,23 @@ public float GetRemainingPlayTime()
{
return -1f;
}
return audioSource.clip.length - audioSource.time;
return preLoopAudio.GetRemainingPlayTime() + audioSource.clip.length - audioSource.time;
}

public int GetPlayTimeSamples() => audioSource.timeSamples;
public int GetPlayTimeSamples() => preLoopAudio.GetPlayTimeSamples() + audioSource.timeSamples;

private IEnumerator WaitForLoad(string filename, AudioType type, Action<string, AudioType, AudioClip> onAudioDataLoaded = null)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
string path = AssetManager.Instance.GetAudioFilePath(filename, type);
WWW audioLoader = new WWW("file://" + path);
yield return audioLoader;

if(isLoop)
{
yield return StartCoroutine(preLoopAudio.LoadAudioClips(filename, type));
}

loadedName = filename;
audioClip = audioLoader.audioClip;

Expand Down Expand Up @@ -199,7 +209,12 @@ private void OnFinishLoading()
audioSource.loop = isLoop;
audioSource.priority = audioController.GetPriorityByType(audioType);
volume = audioController.GetVolumeByType(audioType) * subVolume;
audioSource.Play();

LoopPlaybackInformation info = preLoopAudio.OnFinishLoad(base.gameObject, audioSource.priority);

audioSource.volume = volume;
audioSource.time = info.loopFirstStartTime;
audioSource.PlayDelayed(info.loopStartDelay);
isReady = true;
if (onFinishLoad != null)
{
Expand Down Expand Up @@ -233,7 +248,8 @@ private void Update()
}
volume = audioController.GetVolumeByType(audioType);
audioSource.volume = volume * subVolume;
if (!audioSource.isPlaying && !isLoop && !isLoading && isReady && isLoaded)
preLoopAudio.Update(audioSource.volume);
if (!preLoopAudio.IsPlaying() && !audioSource.isPlaying && !isLoop && !isLoading && isReady && isLoaded)
{
OnAudioEnd();
}
Expand Down
183 changes: 183 additions & 0 deletions MOD.Scripts.Core.Audio/MODPreLoopAudio.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using Assets.Scripts.Core.AssetManagement;
using Assets.Scripts.Core.Audio;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

namespace MOD.Scripts.Core.Audio
{
public class LoopPlaybackInformation
{
public float loopStartDelay;
public float loopFirstStartTime;

public LoopPlaybackInformation(float loopStartDelay, float loopInitialTime)
{
this.loopStartDelay = loopStartDelay;
this.loopFirstStartTime = loopInitialTime;
}
}

public class MODPreLoopAudio
{
List<AudioClip> AudioClips = new List<AudioClip>();
List<AudioSource> AudioSources = new List<AudioSource>();
bool LastTrackOverlaps = true;
LoopPlaybackInformation playbackInformation = null;

public IEnumerator LoadAudioClips(string filename, Assets.Scripts.Core.Audio.AudioType type)
{
for (int i = 0; i < 10; i++)
{
string preLoopFilename = Path.GetFileNameWithoutExtension(filename) + $"_{i}" + Path.GetExtension(filename);
string preLoopPath = AssetManager.Instance.GetAudioFilePath(preLoopFilename, type);

bool fileExists = false;

if (File.Exists(preLoopPath))
{
fileExists = true;
}
else
{
// If file not found, try checking same path suffixed with 'f' - this means that the audio
// file is a 'full audio' and should not overlap with the main audio loop
preLoopFilename = Path.GetFileNameWithoutExtension(filename) + $"_{i}f" + Path.GetExtension(filename);
preLoopPath = AssetManager.Instance.GetAudioFilePath(preLoopFilename, type);

if (File.Exists(preLoopPath))
{
LastTrackOverlaps = false;
fileExists = true;
}
}

if (fileExists)
{
WWW audioLoaderIntro = new WWW("file://" + preLoopPath);
yield return audioLoaderIntro;
AudioClips.Add(audioLoaderIntro.audioClip);
}
else
{
break;
}
}
}

public LoopPlaybackInformation OnFinishLoad(GameObject gameObjectToAttach, int priority)
{
// Probably unnecessary, but there was a guard here in the original code to prevent creating extra AudioSource objects unecessarily
if (playbackInformation != null)
{
return playbackInformation;
}

// First, generate an audio source for each audio clip
foreach (AudioClip audioClip in AudioClips)
{
AudioSource audioSource = gameObjectToAttach.AddComponent<AudioSource>();

audioSource.clip = audioClip;
audioSource.loop = false;
audioSource.priority = priority;

AudioSources.Add(audioSource);
}

// Then, determine when each audio should start playing
float overlapAmount = 0;
float playHead = 0;
foreach(AudioSource audioSource in AudioSources)
{
// Handle overlap by moving playhead back slightly (but never less than 0)
playHead = Math.Max(0, playHead - overlapAmount);

audioSource.PlayDelayed(playHead);

// Increment playhead equal to length of played track
playHead += audioSource.clip.length;
}

playbackInformation = new LoopPlaybackInformation(playHead, GetLoopInitialStartTime());
return playbackInformation;
}

private float GetLoopInitialStartTime()
{
// Return the length of the last audio, if the last audio track overlaps the main loop
if(LastTrackOverlaps && AudioClips.Count > 0)
{
return AudioClips[AudioClips.Count - 1].length;
}

// Otherwise, the main loop plays from the start
return 0;
}

public void StopAudio()
{
foreach (AudioSource audioSource in AudioSources)
{
audioSource.Stop();
}

foreach(AudioClip audioClip in AudioClips)
{
UnityEngine.Object.Destroy(audioClip);
}
}

public bool IsPlaying()
{
foreach(AudioSource audioSource in AudioSources)
{
if(audioSource.isPlaying)
{
return true;
}
}

return false;
}

public float GetRemainingPlayTime()
{
float remainingPlayTime = 0;

foreach (AudioSource audioSource in AudioSources)
{
if(audioSource.time != audioSource.clip.length)
{
remainingPlayTime = audioSource.clip.length - audioSource.time;
}
}

return remainingPlayTime;
}

public int GetPlayTimeSamples()
{
int playTimeSamples = 0;

foreach (AudioSource audioSource in AudioSources)
{
playTimeSamples += audioSource.timeSamples;
}

return playTimeSamples;
}

// To be called from AudioLayerUnity.cs's Update() function
public void Update(float volume)
{
foreach (AudioSource audioSource in AudioSources)
{
audioSource.volume = volume;
}
}
}
}
Loading