public bool Start(ISoundPreviewContext context, int startTick)
        {
            if (Playing)
            {
                throw new InvalidOperationException();
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            PreviewContext = context;
            SoundManager.Register(context.ClapSource.FilePath);
            SoundManager.Register(context.MusicSource.FilePath);

            var timeCalculator = new TimeCalculator(context.TicksPerBeat, context.BpmDefinitions);
            var ticks          = new SortedSet <int>(context.GetGuideTicks()).ToList();

            TickElement = new LinkedList <int?>(ticks.Where(p => p >= startTick).OrderBy(p => p).Select(p => new int?(p))).First;
            BpmElement  = new LinkedList <BpmChangeEvent>(context.BpmDefinitions.OrderBy(p => p.Tick)).First;

            EndTick = IsStopAtLastNote ? ticks[ticks.Count - 1] : timeCalculator.GetTickFromTime(SoundManager.GetDuration(context.MusicSource.FilePath));
            if (EndTick < startTick)
            {
                return(false);
            }

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

            int clapLatencyTick = GetLatencyTick(context.ClapSource.Latency, BpmElement.Value.Bpm);

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

            double startTime = timeCalculator.GetTimeFromTick(startTick);
            double headGap   = Math.Max(-context.MusicSource.Latency - startTime, 0);

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

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

            Playing = true;
            Started?.Invoke(this, EventArgs.Empty);
            return(true);
        }