Esempio n. 1
0
        public bool Start(SoundSource music, int startTick)
        {
            if (Playing)
            {
                throw new InvalidOperationException();
            }
            if (music == null)
            {
                throw new ArgumentNullException("music");
            }
            SoundManager.Register(ClapSource.FilePath);
            SoundManager.Register(music.FilePath);
            EndTick = IsStopAtLastNote ? NoteView.Notes.GetLastTick() : GetTickFromTime(SoundManager.GetDuration(music.FilePath), NoteView.ScoreEvents.BPMChangeEvents);
            if (EndTick < startTick)
            {
                return(false);
            }

            var tickSet        = new HashSet <int>();
            var notes          = NoteView.Notes;
            var shortNotesTick = notes.Taps.Cast <TappableBase>().Concat(notes.ExTaps).Concat(notes.Flicks).Concat(notes.Damages).Select(p => p.Tick);
            var holdsTick      = notes.Holds.SelectMany(p => new int[] { p.StartTick, p.StartTick + p.Duration });
            var slidesTick     = notes.Slides.SelectMany(p => new int[] { p.StartTick }.Concat(p.StepNotes.Where(q => q.IsVisible).Select(q => q.Tick)));
            var airActionsTick = notes.AirActions.SelectMany(p => p.ActionNotes.Select(q => p.StartTick + q.Offset));

            foreach (int tick in shortNotesTick.Concat(holdsTick).Concat(slidesTick).Concat(airActionsTick))
            {
                tickSet.Add(tick);
            }
            TickElement = new LinkedList <int?>(tickSet.Where(p => p >= startTick).OrderBy(p => p).Select(p => new int?(p))).First;

            BPMElement = new LinkedList <BPMChangeEvent>(NoteView.ScoreEvents.BPMChangeEvents.OrderBy(p => p.Tick)).First;

            // スタート時まで進める
            while (TickElement != null && TickElement.Value < startTick)
            {
                TickElement = TickElement.Next;
            }
            while (BPMElement.Next != null && BPMElement.Next.Value.Tick <= startTick)
            {
                BPMElement = BPMElement.Next;
            }

            int clapLatencyTick = GetLatencyTick(ClapSource.Latency, (double)BPMElement.Value.BPM);

            InitialTick = startTick - clapLatencyTick;
            CurrentTick = InitialTick;
            StartTick   = startTick;

            TimeSpan startTime = GetTimeFromTick(startTick, NoteView.ScoreEvents.BPMChangeEvents);
            TimeSpan headGap   = TimeSpan.FromSeconds(-music.Latency) - startTime;

            elapsedTick = 0;
            Task.Run(() =>
            {
                LastSystemTick = Environment.TickCount;
                NoteView.Invoke((MethodInvoker)(() => Timer.Start()));

                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(Math.Max(ClapSource.Latency, 0)));
                if (headGap.TotalSeconds > 0)
                {
                    System.Threading.Thread.Sleep(headGap);
                }
                if (!Playing)
                {
                    return;
                }
                SoundManager.Play(music.FilePath, startTime + TimeSpan.FromSeconds(music.Latency));
            })
            .ContinueWith(p =>
            {
                if (p.Exception != null)
                {
                    Program.DumpExceptionTo(p.Exception, "sound_exception.json");
                    ExceptionThrown?.Invoke(this, EventArgs.Empty);
                }
            });

            Playing = true;
            return(true);
        }