// this method fades the volume of a player with playerId in (start == true) or out (start == false)
        // it also starts playing a track with currentTrack id if start == true
        // and stops playing a current track otherwise
        IEnumerator FadeMusicTrack(int playerId, bool up, bool loop = false)
        {
            MusicPlayer currentPlayer = musicPlayers[playerId];

            currentPlayer.fading  = true;
            currentPlayer.trackId = currentTrack;
            AudioSource actualPlayer = currentPlayer.actualPlayer;

            if (up || currentPlayer.trackId != AudioTrackEnum.Unknown)
            {
                AudioTrackControl track = MusicTracks[currentTrack];
                if (up)
                {
                    if (currentPlayer.playerCouroutine != null)
                    {
                        StopCoroutine(currentPlayer.playerCouroutine);
                    }
                    if (actualPlayer.isPlaying)
                    {
                        actualPlayer.Stop();
                    }
                }
                if (up)
                {
                    ResetMusicMusicPlayer(currentPlayer, track);
                    // set the track and play
                    currentPlayer.loop = loop;
                    actualPlayer.clip  = track.clip;
                    actualPlayer.Play();
                    currentPlayer.playerCouroutine = StartCoroutine(SubclipMusicPlayer());
                }
                // now fade the volume
                float startVolume = actualPlayer.volume;
                float endVolume   = up ? track.volume * MaxMusicVolume : 0;
                float currentTime = 0;
                while (currentTime < Parameters.MusicCrossFadeTime)
                {
                    currentTime        += Time.deltaTime;
                    actualPlayer.volume = Mathf.Lerp(startVolume, endVolume, currentTime / Parameters.MusicCrossFadeTime);
                    yield return(null);
                }
                actualPlayer.volume = endVolume;
                if (!up)
                {
                    if (currentPlayer.playerCouroutine != null)
                    {
                        StopCoroutine(currentPlayer.playerCouroutine);
                    }
                    currentPlayer.playerCouroutine = null;
                    actualPlayer.Stop();
                    GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.MusicTrackPlayed, this, currentPlayer.trackId);
                }
                currentPlayer.fading = false;
            }
        }
 void PromoteToNextMusicSubclip(MusicPlayer currentMusicPlayer, AudioTrackControl track)
 {
     if (track.subclips.Length > 0)
     {
         if (track.subclipOrder.Length > 0)
         {
             currentMusicPlayer.order   = (currentMusicPlayer.order + 1) % track.subclipOrder.Length;
             currentMusicPlayer.subclip = track.subclipOrder[currentMusicPlayer.order];
         }
         else
         {
             currentMusicPlayer.order   = 0;
             currentMusicPlayer.subclip = 0;
         }
         currentMusicPlayer.startTime = track.subclips[currentMusicPlayer.subclip].min;
         currentMusicPlayer.endTime   = track.subclips[currentMusicPlayer.subclip].max;
     }
     else
     {
         currentMusicPlayer.order     = 0;
         currentMusicPlayer.startTime = 0;
         currentMusicPlayer.endTime   = track.clip.length;
     }
 }
        // this method plays subclips of the currentTrack with currentPlayer using specified subclip order
        // if no subclips or their order defined it plays the full track from its beginning to the end
        // the underlying AudioSource is already playing
        IEnumerator SubclipMusicPlayer()
        {
            if (Parameters.Tracks.Count > 0)
            {
                int               startPlayerId      = currentMusicPlayerId;
                MusicPlayer       currentMusicPlayer = musicPlayers[currentMusicPlayerId];
                AudioSource       actualPlayer       = currentMusicPlayer.actualPlayer;
                AudioTrackControl track = MusicTracks[currentTrack];
                do
                {
                    // prepare subclip play parameters
                    float startTime = currentMusicPlayer.startTime;
                    float waitTime  = currentMusicPlayer.endTime - startTime;
                    //Debug.Log("Playing subclip " + currentMusicPlayer.subclip.ToString() + " from " + startTime.ToString() + ", waiting for " + waitTime.ToString());
                    // do the actual play
                    actualPlayer.time = startTime;
                    // ensure that actual player is really playing
                    if (!actualPlayer.isPlaying)
                    {
                        actualPlayer.Play();
                    }
                    yield return(new WaitForSeconds(waitTime));

                    // move to the next subclip
                    PromoteToNextMusicSubclip(currentMusicPlayer, track);
                    //Debug.Log("Subclip order " + currentMusicPlayer.order.ToString() + "/" + track.subclipOrder.Length.ToString());
                }while (currentMusicPlayer.loop || currentMusicPlayer.order < track.subclipOrder.Length);
                // forcibly stop playing
                actualPlayer.Stop();
                if (startPlayerId == currentMusicPlayerId)
                {
                    currentMusicPlayerId = -1;
                }
                GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.MusicTrackPlayed, this, track.id);
            }
        }
 void ResetMusicMusicPlayer(MusicPlayer currentMusicPlayer, AudioTrackControl track)
 {
     currentMusicPlayer.order   = -1;
     currentMusicPlayer.subclip = -1;
     PromoteToNextMusicSubclip(currentMusicPlayer, track);
 }