HKI Core
SimpleAudioPlayer.cs
Go to the documentation of this file.
1 using UnityEngine;
2 using System.Text;
3 using System.Collections;
4 using System.Collections.Generic;
5 using HKI.Core.Loc;
6 
7 namespace HKI.Core.Audio
8 {
14  public class SimpleAudioPlayer : MonoBehaviour
15  {
16  // Subclass
17  [System.Serializable]
18  public class AudioPlayerSettings
19  {
20  // Public enums
21  public enum Playmodes
22  {
23  SingleOutput,
24  SingleOutputWithCrossfade,
25  MultiOutput
26  }
27 
28  // Public variables
29  [SerializeField] Playmodes Playmode = Playmodes.SingleOutputWithCrossfade;
30  [SerializeField] float FadingTimeInSeconds = 5.0f;
31  [SerializeField] bool AtSetupStartPlayingPlaylist = true;
32  [SerializeField] Playlist StartPlaylist = null;
33 
34  [SerializeField] UnityEngine.Audio.AudioMixerGroup AudioMixerGroup = null;
35  [SerializeField] Language LocalizationLanguage = null;
36 
37  [SerializeField] bool DontGetDestroyedOnLoad = false;
38 
39  // Getter
40  public Playmodes GetPlaymode { get { return Playmode; } }
41  public float GetFadingTimeInSeconds { get { return FadingTimeInSeconds; } }
42  public bool GetAtSetupStartPlayingPlaylist { get { return AtSetupStartPlayingPlaylist; } }
43  public Playlist GetStartPlaylist { get { return StartPlaylist; } }
44 
45  public UnityEngine.Audio.AudioMixerGroup GetAudioMixerGroup { get { return AudioMixerGroup; } }
46  public Language GetLocalizationLanguage { get { return LocalizationLanguage; } }
47 
48  public bool GetDontGetDestroyedOnLoad { get { return DontGetDestroyedOnLoad; } }
49 
50  // Interface functions
51  public string GetInfoString()
52  {
53  StringBuilder infoString = new StringBuilder();
54  infoString.AppendLine("Audio Player Settings:");
55 
56  infoString.Append("Playmode: ");
57  infoString.AppendLine(Playmode.ToString());
58 
59  infoString.Append("FadingTimeInSeconds: ");
60  infoString.AppendLine(FadingTimeInSeconds.ToString());
61 
62  infoString.Append("AtSetupStartPlayingPlaylist: ");
63  infoString.AppendLine(AtSetupStartPlayingPlaylist.ToString());
64 
65  infoString.Append("StartPlaylist: ");
66  infoString.AppendLine(StartPlaylist != null ? StartPlaylist.name : "null");
67 
68  infoString.Append("AudioMixerGroup: ");
69  infoString.AppendLine(AudioMixerGroup != null ? AudioMixerGroup.name : "null");
70 
71  infoString.Append("LocalizationLanguage: ");
72  infoString.AppendLine(LocalizationLanguage != null ? LocalizationLanguage.name : "null");
73 
74  infoString.Append("DontGetDestroyedOnLoad: ");
75  infoString.AppendLine(DontGetDestroyedOnLoad.ToString());
76 
77  return infoString.ToString();
78  }
79  }
80 
81  // Private variables
82  AudioPlayerSettings currentSettings = null;
83 
84  List<AudioSource> audioSources = new List<AudioSource>();
85  int currentMainAudioSourceId = 0;
86 
87  bool isPlayingPlaylist = false;
88  Playlist currentPlaylist = null;
89 
90  Coroutine crossfadeCoroutine = null;
91  Coroutine playNextSoundClipOfPlaylistCoroutine = null;
92 
93  // Getter
94  public AudioPlayerSettings GetSettings { get { return currentSettings; } }
95 
96  public bool IsPlayingPlaylist { get { return isPlayingPlaylist; } }
97  public Playlist GetCurrentPlaylist { get { return currentPlaylist; } }
98 
99  // Interface function
100  public void Setup(AudioPlayerSettings settings)
101  {
102  if(settings == null)
103  {
104  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to setup the (AudioPlayer) but the new (AudioPlayerSettings) settings is null!");
105  return;
106  }
107 
108  StopPlayingAllClips();
109 
110  if(audioSources != null && audioSources.Count > 0)
111  {
112  for (int i = 0; i < audioSources.Count; i++)
113  Destroy(audioSources[i]);
114 
115  audioSources.Clear();
116  }
117 
118  currentSettings = settings;
119  currentPlaylist = currentSettings.GetStartPlaylist;
120 
121  switch(currentSettings.GetPlaymode)
122  {
123  case AudioPlayerSettings.Playmodes.SingleOutput:
124  case AudioPlayerSettings.Playmodes.MultiOutput:
125  audioSources.Add(CreateAudioSource());
126  break;
127 
128  case AudioPlayerSettings.Playmodes.SingleOutputWithCrossfade:
129  audioSources.Add(CreateAudioSource());
130  audioSources.Add(CreateAudioSource());
131  break;
132  }
133 
134  if(currentSettings.GetDontGetDestroyedOnLoad)
135  DontDestroyOnLoad(gameObject);
136 
137  if(currentSettings.GetAtSetupStartPlayingPlaylist)
138  PlayPlaylist(true);
139  }
140 
141  public void PlayPlaylist(bool playPlaylist, bool debugLog = true)
142  {
143  if(playPlaylist && currentPlaylist == null && debugLog)
144  {
145  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a clip from the current playlist but the current playlist is null!");
146  return;
147  }
148 
149  if(playPlaylist && currentPlaylist.GetNumberOfClips == 0 && debugLog)
150  {
151  Debug.LogWarning("(SimpleAudioPlayer)" + gameObject.name + " you try to play a clip from the current playlist " + currentPlaylist.name + " but the current playlist has no sound clips in it!");
152  return;
153  }
154 
155  if (!isPlayingPlaylist && playPlaylist)
156  {
157  isPlayingPlaylist = playPlaylist;
158  PlaySoundClip(currentPlaylist.GetNextClip());
159  }
160  else if(isPlayingPlaylist && !playPlaylist)
161  {
162  isPlayingPlaylist = playPlaylist;
163  StopPlayingAllClips();
164  }
165  }
166 
167  public void ChangePlaylist(Playlist playlist)
168  {
169  if(playlist == null)
170  {
171  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to change the (Playlist) but the new playlist is null!");
172  return;
173  }
174 
175  currentPlaylist = playlist;
176 
177  if(isPlayingPlaylist)
178  PlaySoundClip(currentPlaylist.GetNextClip());
179  }
180 
181  public void ChangePlaylist(Playlist playlist, bool playPlaylist)
182  {
183  PlayPlaylist(playPlaylist);
184  ChangePlaylist(playlist);
185  }
186 
187  public void PlaySoundClip(SoundClip clip)
188  {
189  if(clip == null)
190  {
191  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (SoundClip) but the clip is null!");
192  return;
193  }
194 
195  if(currentSettings == null || audioSources.Count == 0)
196  {
197  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (SoundClip) but the AudioPlayer isn't setuped!");
198  return;
199  }
200 
201 
202  PlayAudioClip(clip.GetClip, clip.GetVolume, clip.GetPitch.GetRandomValue());
203  }
204 
205  public void PlayAudioLocalization(AudioLocalization audioLocalization)
206  {
207  if(audioLocalization == null)
208  {
209  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (AudioLocalization) but the audioLocalization is null!");
210  return;
211  }
212 
213  if(currentSettings == null || audioSources.Count == 0)
214  {
215  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (AudioLocalization) but the audio player isn't setuped!");
216  return;
217  }
218 
219  if(currentSettings.GetLocalizationLanguage == null)
220  {
221  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (AudioLocalization) but the audio player setting has no localization language!");
222  return;
223  }
224 
225  AudioLocalization.AudioLocalizationElement audioLocalizationElement = audioLocalization.GetAudioLocalizationElement(currentSettings.GetLocalizationLanguage.Value);
226 
227  if(audioLocalizationElement != null)
228  PlayAudioClip(audioLocalizationElement.GetClip, audioLocalizationElement.GetVolume, audioLocalizationElement.GetPitch.GetRandomValue());
229  }
230 
231  public void PlayAudioClip(AudioClip clip, float volume, float pitch)
232  {
233  if(clip == null)
234  {
235  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (AudioClip) but the clip is null!");
236  return;
237  }
238 
239  if(currentSettings == null || audioSources.Count == 0)
240  {
241  Debug.LogError("(SimpleAudioPlayer)" + gameObject.name + " you try to play a (AudioClip) but the audio player isn't setuped!");
242  return;
243  }
244 
245  switch(currentSettings.GetPlaymode)
246  {
247  case AudioPlayerSettings.Playmodes.SingleOutput:
248  if(playNextSoundClipOfPlaylistCoroutine != null)
249  StopCoroutine(playNextSoundClipOfPlaylistCoroutine);
250 
251  audioSources[0].clip = clip;
252  audioSources[0].volume = volume;
253  audioSources[0].pitch = pitch;
254 
255  audioSources[0].Play();
256 
257  if(isPlayingPlaylist)
258  playNextSoundClipOfPlaylistCoroutine = StartCoroutine(PlayNextSoundClipOfPlaylist(clip.length));
259  break;
260 
261  case AudioPlayerSettings.Playmodes.SingleOutputWithCrossfade:
262  if(crossfadeCoroutine != null)
263  StopCoroutine(crossfadeCoroutine);
264 
265  if(playNextSoundClipOfPlaylistCoroutine != null)
266  StopCoroutine(playNextSoundClipOfPlaylistCoroutine);
267 
268  crossfadeCoroutine = StartCoroutine(PlayClipWithCrossfade(clip, volume, pitch));
269 
270  if(isPlayingPlaylist)
271  playNextSoundClipOfPlaylistCoroutine = StartCoroutine(PlayNextSoundClipOfPlaylist(clip.length - currentSettings.GetFadingTimeInSeconds));
272  break;
273 
274  case AudioPlayerSettings.Playmodes.MultiOutput:
275  AudioSource freeAudioSource = null;
276 
277  for(int i = 0; i < audioSources.Count; i++)
278  {
279  if (!audioSources[i].isPlaying)
280  freeAudioSource = audioSources[i];
281  }
282 
283  if(freeAudioSource == null)
284  {
285  freeAudioSource = CreateAudioSource();
286  audioSources.Add(freeAudioSource);
287  }
288 
289  freeAudioSource.clip = clip;
290  freeAudioSource.volume = volume;
291  freeAudioSource.pitch = pitch;
292 
293  freeAudioSource.Play();
294 
295  break;
296  }
297  }
298 
299  public void StopPlayingAllClips()
300  {
301  isPlayingPlaylist = false;
302 
303  if(playNextSoundClipOfPlaylistCoroutine != null)
304  StopCoroutine(playNextSoundClipOfPlaylistCoroutine);
305 
306  for (int i = 0; i < audioSources.Count; i++)
307  {
308  audioSources[i].Stop();
309  audioSources[i].clip = null;
310  audioSources[i].volume = 0.0f;
311  audioSources[i].pitch = 1.0f;
312  }
313  }
314 
315  // Helper function
316  AudioSource CreateAudioSource()
317  {
318  AudioSource audioSource = gameObject.AddComponent<AudioSource>();
319  audioSource.outputAudioMixerGroup = currentSettings.GetAudioMixerGroup;
320  audioSource.playOnAwake = false;
321  audioSource.loop = false;
322  audioSource.clip = null;
323  audioSource.volume = 0.0f;
324  audioSource.pitch = 1.0f;
325 
326  return audioSource;
327  }
328 
329  IEnumerator PlayClipWithCrossfade(AudioClip clip, float volume, float pitch)
330  {
331  AudioSource oldAudioSource = audioSources[currentMainAudioSourceId];
332  currentMainAudioSourceId = (currentMainAudioSourceId + 1) % 2;
333  AudioSource newAudioSource = audioSources[currentMainAudioSourceId];
334 
335  newAudioSource.clip = clip;
336  newAudioSource.volume = 0.0f;
337  newAudioSource.pitch = pitch;
338 
339  newAudioSource.Play();
340 
341  float remainingFadeTime = currentSettings.GetFadingTimeInSeconds;
342 
343  float oldVolumeChangePerSecond = oldAudioSource.volume / currentSettings.GetFadingTimeInSeconds;
344  float newVolumeChangePerSecond = volume / currentSettings.GetFadingTimeInSeconds;
345 
346  while (remainingFadeTime > 0.0f)
347  {
348  oldAudioSource.volume -= Time.unscaledDeltaTime * oldVolumeChangePerSecond;
349  newAudioSource.volume += Time.unscaledDeltaTime * newVolumeChangePerSecond;
350 
351  remainingFadeTime -= Time.unscaledDeltaTime;
352  yield return null;
353  }
354 
355  newAudioSource.volume = volume;
356 
357  oldAudioSource.Stop();
358  oldAudioSource.clip = null;
359  oldAudioSource.volume = 0.0f;
360  oldAudioSource.pitch = 1.0f;
361  }
362 
363  IEnumerator PlayNextSoundClipOfPlaylist(float waitTime)
364  {
365  yield return new WaitForSecondsRealtime(waitTime);
366 
367  if(isPlayingPlaylist)
368  PlaySoundClip(currentPlaylist.GetNextClip());
369  }
370  }
371 }
This ScriptableObject contains the data of a playlist for the AudioPlayer.
Definition: Playlist.cs:19
void PlayPlaylist(bool playPlaylist, bool debugLog=true)
void ChangePlaylist(Playlist playlist)
void PlayAudioLocalization(AudioLocalization audioLocalization)
void Setup(AudioPlayerSettings settings)
void PlayAudioClip(AudioClip clip, float volume, float pitch)
MinMaxRange GetPitch
Definition: SoundClip.cs:23
This subclass holds the data for a audio localization in a specific language.
This MonoBehaviour allows playing of a SoundClip on one of the general purpose AudioPlayers.
Definition: PlaySoundClip.cs:8
This is a AudioPlayer that can play playlist or SoundClips. It allows to play multiple clips at once ...
SoundClip GetNextClip()
Definition: Playlist.cs:56
Special Variable enables the use of the SystemLanguage data type as a variable of the settings system...
Definition: Language.cs:13
This MonoBehaviour allows the changing of the playlist on one of the general purpose AudioPlayers...
IEnumerator PlayClipWithCrossfade(AudioClip clip, float volume, float pitch)
AudioLocalizationElement GetAudioLocalizationElement(Language language)
This function returns the AudioLocalizationElement in a specific language. If there is no localizatio...
This is a container ScriptableObject that holds all data required to play a AudioClip.
Definition: SoundClip.cs:11
UnityEngine.Audio.AudioMixerGroup GetAudioMixerGroup
void ChangePlaylist(Playlist playlist, bool playPlaylist)
IEnumerator PlayNextSoundClipOfPlaylist(float waitTime)
This ScriptableObject contains as a container for all audio localization information.