public void AddThemes(params AreaTheme[] themes)
    {
        _themes.Clear();
        _alreadyPlayingThemes.Clear();
        ActiveTheme = null;
        foreach (var theme in themes)
        {
#if UNITY_EDITOR
            if (theme == null || !theme.AmbientSound.IsNotEmpty())
            {
                Debug.LogError("AddTheme caused: theme is null or empty");
                return;
            }
            if (_themes.Any(t => t.Name == theme.Name))
            {
                Debug.LogError("AddTheme caused: Theme with name " + theme.Name + " already exists");
                return;
            }
#endif

            _themes.Add(theme);
        }
    }
    private IEnumerator ActivateTheme(string themeName)
    {
        yield return(null);

        // If null then fade all themes
        if (string.IsNullOrEmpty(themeName))
        {
            ActiveTheme = null;
            yield break;
        }

        AreaTheme theme = _themes.FirstOrDefault(t => t.Name == themeName);

        // If there is no such theme - do nothing
        if (theme == null)
        {
            yield break;
        }

        // If this theme is already active - do nothing
        if (ActiveTheme != null && theme.Name == ActiveTheme.Name)
        {
            yield break;
        }

        // Make this theme active
        ActiveTheme = theme;

        // If theme is already playing - do nothing
        if (!_alreadyPlayingThemes.Add(theme))
        {
            yield break;
        }

        // Sarting theme playing
        AudioClip clip = GetClipFromSound(theme.AmbientSound);

        var         listener = FindObjectOfType <AudioListener>().transform;
        AudioSource source   = GetAudioSource(listener, listener.position);

        source.clip   = clip;
        source.loop   = true;
        source.volume = 0;
        source.Play();


        Dictionary <RandomSound, float> randomSoundDelays =
            theme.RandomSounds
            .Where(r => r.Sound.IsNotEmpty())
            .ToDictionary(k => k, v => Random.Range(5f, v.MaxSecondsDelay));

        float activeRaito = theme.Name == ActiveTheme.Name ? 1 : 0;

        // Store all currently playing theme sounds to be able change their volume
        var activeAudioSources = new HashSet <AudioSource>(new[] { source });

        while (true)
        {
            yield return(null);

            bool isActive = ActiveTheme.Name == theme.Name;
            activeRaito = Mathf.Lerp(activeRaito, isActive ? 1 : 0, Time.deltaTime * ThemeFadeFactor);

            float actualVolume = theme.BaseVolume * activeRaito * CurrentAmbientVolume;

            // Remove all sounds that are already finished playing
            activeAudioSources.RemoveWhere(a => a != source && !a.isPlaying);

            // Change all sounds volume depending to the actual one
            foreach (AudioSource audioSource in activeAudioSources)
            {
                audioSource.volume = actualVolume;
            }

            // Play random sounds
            foreach (RandomSound sound in randomSoundDelays.Keys.ToArray())
            {
                randomSoundDelays[sound] -= Time.deltaTime;

                if (randomSoundDelays[sound] <= 0)
                {
                    AudioSource audioSource = Play(sound.Sound, actualVolume);

                    // Store sound source for later use
                    activeAudioSources.Add(audioSource);

                    randomSoundDelays[sound] = Random.Range(sound.MinSecondsDelay, sound.MaxSecondsDelay);
                }
            }
        }
    }