Beispiel #1
0
        /// <summary>
        /// Section 재생 준비
        /// </summary>
        public void StartSection(Data.Section section, BeatSyncClock clock, TransitionType ttype, double startTime = 0)
        {
            EndSection();                                                                                                       // 이전에 재생중이었을 수도 있는 섹션을 강제 종료


            // 초기화

            m_sectionData = section;
            m_clock       = clock;

            m_startTransition = ttype;
            m_endTransition   = TransitionType.None;
            isOnTransition    = false;


            // 텐션 관련 설정
            for (int i = 0; i < Data.Section.c_maxLayerPerSection; i++)
            {
                var layer = section.GetLayer(i);
                if (layer != null)
                {
                    layer.SetAutomationTarget(m_tensionAutomationTargets[i]);
                }
            }
            section.tension = m_tension;


            if (startTime == 0)                                                                                                 // 시작 시간이 지정되지 않은 경우 다음 안전한 비트를 시작 시간으로
            {
                startTime = m_clock.CalcNextSafeBeatTime();
            }

            m_updateCo = m_context.StartCoroutine(UpdateStateCo(startTime));                    // 코루틴 시작
        }
Beispiel #2
0
        /// <summary>
        /// Track을 새로 지정
        /// </summary>
        /// <param name="track"></param>
        /// <param name="clockToSync">기존에 존재하는 clock과 싱크를 맞춰야할 경우 지정</param>
        public void SetTrack(Track track, BeatSyncClock clockToSync = null)
        {
            m_track            = track;
            m_sectionIdx       = -1;
            m_suppressProgress = false;

            if (clockToSync == null)                                                                            // 클럭이 지정되지 않은 경우, 새로 생성
            {
                m_clock = new BeatSyncClock(track.BPM);
            }
            else if (clockToSync.BPM != track.BPM)                                              // 기존 클럭과 bpm이 다른 경우, 기존 클럭의 다음번 비트와 동기화하여 새로 클럭 생성
            {
                m_clock = new BeatSyncClock(track.BPM, clockToSync.CalcNextSafeBeatTime());
            }
            else
            {                                                                                                                           // 아니면 기존 클럭 그대로 사용
                m_clock = clockToSync;
            }
        }
Beispiel #3
0
        /// <summary>
        /// 업데이트 코루틴
        /// </summary>
        /// <returns></returns>
        IEnumerator UpdateStateCo(double startTime)
        {
            var curplayer = currentPlayerComponent;
            var beatTime  = m_clock.SecondPerBeat;


            // *** 재생하기 전

            m_state = State.BeforePlay;

            SetSectionToCurrentPlayer();                                                                        // 각 layer정보 세팅
            //m_sectionAudioLength	= curplayer.fullAudioLength;		// 전체 오디오 길이 구하기
            while (!curplayer.readyToPlay)                                                                      // 로딩 대기
            {
                yield return(null);
            }

            // 각종 시간값 계산
            var timePlay      = startTime;
            var timeFillIn    = timePlay + beatTime * m_sectionData.beatFillIn;
            var timeLoopStart = timePlay + beatTime * m_sectionData.beatStart;

            m_loopLengthDspTime = beatTime * m_sectionData.beatLoopLength;
            var timeNextLoopEnd = timeLoopStart + m_loopLengthDspTime;


            // 현재 재생 종류, section 세팅값을 보고 음원의 어느 지점부터 재생할지 정한다.
            double offset = 0;

            if (m_startTransition == TransitionType.Manual)                     // 강제 전환 시작시에는 fill-in 앞부분은 스킵한다.
            {
                offset = timeFillIn - timePlay;

                timeFillIn      -= offset;                                                                      // 시간값들 조정
                timeLoopStart   -= offset;
                timeNextLoopEnd -= offset;
            }
            else if (m_startTransition == TransitionType.Instant)
            {
                offset = timeLoopStart - timePlay;

                timeFillIn      -= offset;                                                                      // 시간값들 조정
                timeLoopStart   -= offset;
                timeNextLoopEnd -= offset;
            }
            //Debug.Log("PlayScheduled time : " + timePlay + ", offset : " + offset);
            curplayer.PlayScheduled(timePlay, offset);                                  // 다음번 비트에 음원 재생


            // 필요한 시간값은 멤버로 보관
            //m_timePlayStart		= timePlay;
            firstLoopStartDspTime = timeLoopStart;
            nextLoopEndDspTime    = timeNextLoopEnd;

            // 전환 오토메이션을 미리 앞부분으로 적용해둔다.
            var auto = GetAutomation(m_startTransition == TransitionType.Manual? m_sectionData.inTypeManual : m_sectionData.inTypeNatural);

            if (auto != null)
            {
                m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue(0));
            }



            while (AudioSettings.dspTime < timePlay)                                    // 재생될 때까지 대기
            {
                yield return(null);
            }


            // *** 재생 후, Fill-in 이전

            m_state = State.BeforeFillIn;
            //Debug.Log(m_state.ToString() + " ... dspTime : " + AudioSettings.dspTime);

            if (m_startTransition == TransitionType.Natural)                    // 자연 전환일 경우 여기에서 트랜지션
            {
                while (AudioSettings.dspTime < timeFillIn)
                {
                    if (auto != null)
                    {
                        var t = (AudioSettings.dspTime - timePlay) / (timeLoopStart - timePlay);
                        m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue((float)t));
                        //Debug.LogFormat("t = {0}, value = {1}", t, auto.GetValue((float)t));
                    }
                    yield return(null);
                }
            }
            else
            {
                while (AudioSettings.dspTime < timeFillIn)                              // Fill-in 지점까지 대기
                {
                    yield return(null);
                }
            }


            // *** Fill - in

            m_state = State.FillIn;
            //Debug.Log(m_state.ToString() + " ... dspTime : " + AudioSettings.dspTime);


            if (m_startTransition == TransitionType.Natural)                    // 자연 전환일 경우, 루프 시작까지 남은 부분에 대해서 전환
            {
                while (AudioSettings.dspTime < timeLoopStart)
                {
                    if (auto != null)
                    {
                        var t = (AudioSettings.dspTime - timePlay) / (timeLoopStart - timePlay);
                        m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue((float)t));
                        //Debug.LogFormat("t = {0}, value = {1}", t, auto.GetValue((float)t));
                    }
                    yield return(null);
                }
                m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue(1));                   // 마지막 값으로 보정
            }
            else
            {                                                                                                                   // 강제 전환
                while (AudioSettings.dspTime < timeLoopStart)
                {
                    if (auto != null)
                    {
                        var t = (AudioSettings.dspTime - timeFillIn) / (timeLoopStart - timeFillIn);
                        m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue((float)t));
                        //Debug.LogFormat("t = {0}, value = {1}", t, auto.GetValue((float)t));
                    }
                    yield return(null);
                }
                m_transitionAutomationTarget.Set(auto.targetParam, auto.GetValue(1));                   // 마지막 값으로 보정
            }


            // *** Looping

            m_state           = State.Looping;
            m_loopReserved    = false;                                                                                  // 루핑 예약을 했는지 여부
            m_suppressLooping = false;                                                                                  // 루프 억제 여부
            while (true)                                                                                                // fadeout 설정이 되지 않는다면 계속 루프한다.
            {
                var nextSafeBeat = m_clock.CalcNextSafeBeatTime();
                if (System.Math.Abs(nextSafeBeat - nextLoopEndDspTime) < beatTime &&
                    !m_loopReserved && !m_suppressLooping)                                                                                      // 다음번 비트에 루프를 해야하는 경우
                {
                    var loopStartOffset = beatTime * m_sectionData.beatStart;

                    // 다른쪽 플레이어에 섹션 정보 세팅, 루프 시작 위치로 재생 예약
                    SwitchPlayerComponent();
                    SetSectionToCurrentPlayer();

                    while (!currentPlayerComponent.readyToPlay)                                                                 // 로딩될 때까지 대기
                    {
                        yield return(null);
                    }

                    if (!m_suppressLooping)                                                                                                     // 로딩 대기 중에 이 플래그값이 true가 될 수도 있다. 그렇지 않을 때만 실제 재생
                    {
                        currentPlayerComponent.PlayScheduled(nextLoopEndDspTime, loopStartOffset);

                        //Debug.Log("Loop reserved");
                        m_loopReserved = true;                                                                                                  // 루프 예약 지정
                    }
                }

                yield return(null);


                if (AudioSettings.dspTime >= nextLoopEndDspTime)                                                        // 루프 시간을 넘을 때마다
                {
                    m_loopReserved      = false;                                                                        // 루프 예약 여부 해제
                    nextLoopEndDspTime += m_loopLengthDspTime;                                                          // 다음 루프 시간 지정
                }
            }
        }
Beispiel #4
0
        TransitionTimeInfo DoProgress(SectionPlayer.TransitionType ttype, bool reverse, int sectionIdxOverride = int.MinValue)
        {
            // 트랜지션을 해도 괜찮은 상황인지 체크

            if (sidePlayer.isReadyOrFinished)                   // 다른쪽 플레이어가 재생중이 아니거나 루프 종료된 경우 스위칭. 새로 재생할 플레이어가 currentPlayer가 된다
            {
                SwitchPlayer();

                if (sectionIdxOverride == int.MinValue)                         // 다음 섹션 idx를 오버라이드하지 않은 경우엔 자동으로 +1
                {
                    m_sectionIdx++;
                }
                else
                {                                                                                                       // 오버라이드한 경우
                    m_sectionIdx = sectionIdxOverride;
                }

                //Debug.Log("switch player. section idx : " + m_sectionIdx);
            }


            // 트랜지션 시간 구하기

            double transitionTime = CalcSectionTransitionTimeLength(m_sectionIdx, ttype);



            // 여기서부터는 sidePlayer => 기존에 재생중이던 플레이어가 됨

            TransitionTimeInfo tinfo = new TransitionTimeInfo();

            tinfo.transitionStart = -1;
            tinfo.transitionEnd   = -1;

            // 기존 재생중이던 플레이어가 트랜지션 진행중이지 않고, 좀더 상위의 트랜지션을 걸 때
            if (!sidePlayer.isOnTransition &&
                (int)ttype > (int)sidePlayer.currentEndTransition)
            {
                //Debug.LogWarningFormat("transition check - m_sectionIdx : {0}, m_suppressProgress : {1}", m_sectionIdx, m_suppressProgress);
                if (((!reverse && m_sectionIdx > 0) || (reverse && m_sectionIdx < m_track.sectionCount - 1)) &&
                    !m_suppressProgress && !sidePlayer.isReadyOrFinished)                               // 처음 섹션이 아니고 재생을 끝내는 경우도 아닐 때만
                {
                    tinfo.transitionStart = sidePlayer.FadeoutSection(ttype, transitionTime);
                    //Debug.LogWarning("fadeout triggered");
                }
                else
                {                                                                                                       // 그 외의 경우엔 전부 다음 비트에 트랜지션 시작하는 것으로
                    tinfo.transitionStart = m_clock.CalcNextSafeBeatTime();
                }


                if ((!reverse && m_sectionIdx < m_track.sectionCount) || (reverse && m_sectionIdx >= 0))                        // 더 진행할 섹션이 있는 경우에만
                {
                    //Debug.LogWarning("start : " + ttype);
                    currentPlayer.StartSection(m_track.GetSection(m_sectionIdx), m_clock, ttype, tinfo.transitionStart);
                    tinfo.transitionEnd = currentPlayer.firstLoopStartDspTime;
                }
                else
                {
                    // TODO : 필요할지는 모르겠는데, 새 섹션이 시작되지 않는 경우에도 올바른 트랜지션 종료 타이밍을 계산해서 집어넣게 수정해야 할지도...
                    tinfo.transitionEnd = tinfo.transitionStart;
                }

                // 트랜지션 추적 (step을 올바르게 업데이트하기 위해서)
                m_curTransition = ttype;
                StartTransitionMonitor(tinfo);
            }
            else
            {
                Debug.Log(string.Format("sidePlayer.isOnTransition : {0}, sidePlayer.currentEndTransition : {1}", sidePlayer.isOnTransition, sidePlayer.currentEndTransition));
            }

            return(tinfo);
        }